Autor Beitrag
Manina
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 44

Win 7 Pro
RAD Studio 2010 Pro
BeitragVerfasst: Di 21.11.06 15:48 
ich nerve schon wieder...

Ich glaube, wir kommen nicht um ein Typecasting herum, um Laufzeitfehler auszuschließen.
Allerdings können die Variablendefinitionen so bleiben, wie sie sind. :wink:

Ich hab mir mal folgendes überlegt und getestet und es scheint wirklich so zu sein :roll:

Angenommen, FTagSize (LongWord !) ist 77824 (dec), also 13000 (hex). Dann bedeutet Stream.Seek(-FTagSize, ...) also
(-77824) (dec) bzw. FFFED000 (hex). Da aber LongWord, wird das als vorzeichenlos interpretiert, macht also 4.294.889.472 (dec).
Das sprengt beim Seeken sicher jeden Rahmen :wink:

Ich hab jetzt nur mal bei RemoveFromStream so gecastet:

Stream.Seek(-Int64(FTagSize), soFromEnd);

Damit klappts, egal wie die Prüfoptionen gesetzt sind, weil die 64-Bit-Variante der Seek-Procedure aus TStream benutzt wird. :)
Nur war ich zu faul, die komplette Unit nach solchen Stellen zu durchforsten; das ist Dein Job, Gausi... :D

Ich hoffe, auf diese Art sind wir alle zufrieden...

Gruß, Bernd.
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8535
Erhaltene Danke: 473

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Di 21.11.06 16:19 
Ich hab mir die Datei (die aus der Mail) mal angeschaut. Der Tag scheint soweit in Ordnung zu sein, wenn auch diverse leere Frames drin sind. Aber das macht ja nix. Es liegt also nicht an einem fehlerhaften Tag, an dem sich die Unit verschluckt.

Ich kann den Fehler bei mir aber nicht reproduzieren. :nixweiss: Ich hab jetzt auch ein bissel in den Debugger-Optionen rumgespielt, aber immer dasselbe Ergebnis: Es funktioniert ohne Fehlermeldung. Den v1-tag löschen ist sinnfrei, weil der gar nicht da ist. Und der v2-Tag wird anstandslos und korrekt entfernt.

Erläuter mal bitte Schritt für Schritt, was du wo für Optionen in der IDE gesetzt hast. So wie ich das sehe, sollte eigentlich bei etwas wie seek(-MyLongWordVar) der Parameter als negativer Wert aufgefasst werden. Wenn ich allerdings soetwas mache: Stream.Seek(LongWord(-FTagSize), soFromEnd);, dann bekomme auch ich einen Integerüberlauf...

_________________
We are, we were and will not be.
Manina
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 44

Win 7 Pro
RAD Studio 2010 Pro
BeitragVerfasst: Di 21.11.06 17:05 
es geht nur um die Compilerschalter {$R} (Bereichsüberprüfung) und {$Q} (Überlaufprüfung), die ich unter

Projekt / Optionen / Compiler

an- oder ausschalte. Der Konstrukt

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
        try
          TmpStream.Seek(0, soFromBeginning);
          if StreamToStream(Stream, TmpStream, Stream.Size -
                                Stream.Position) <> MP3ERR_None then
          begin
            result := ID3ERR_Cache;
            Exit;
          end;

          // shorten the file by the size of the tag
          Stream.Seek(-FTagSize, soFromEnd);
          SetEndOfFile((Stream as TFileStream).Handle);

          // return the audio data to the stream
          Stream.Seek(0, soFromBeginning);
          TmpStream.Seek(0, soFromBeginning);
          if StreamToStream(TmpStream, Stream, TmpStream.Size) <> MP3ERR_None then
          begin
            result := ID3ERR_Cache;
            Exit;
          end;
        except
          on EWriteError do result := MP3ERR_SWrite;
          on E: Exception do
          begin                              // hier lande ich .....
            result := ID3ERR_Unclassified;
            MessageBox(0, PChar(E.Message), PChar('Error'), MB_OK or MB_ICONERROR or MB_TASKMODAL or MB_SETFOREGROUND);
          end;
        end;


in TID3v2Tag.RemoveFromStream landet immer in Zeile 24, außer ich setze beide Schalter auf aus.

{$R+}, {$Q+} --> "Fehler bei Bereichsprüfung"
{$R+}, {$Q-} --> dito, {$R} hat also scheinbar Vorrang
{$R-}, {$Q+} --> "Integerüberlauf"
{$R-}, {$Q-} --> alles i.O.

:nixweiss:

Das hier sind die Standardeinstellungen in meiner IDE:
Einloggen, um Attachments anzusehen!
jakobwenzel
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1889
Erhaltene Danke: 1

XP home, ubuntu
BDS 2006 Prof
BeitragVerfasst: Do 01.02.07 17:44 
Ich nutze deine Unit auch, und finde, dass die wirklich "das beste auf dem Markt" ist.

Ich hab nur ein Problem: Bei meinem aktuellen Projekt versuche ich, die Angewohnheit von iTunes, Coverbilder in allen möglichen (für MP3-Player nicht lesbaren) Formaten abzuspeichern, auszubügeln. Das klappt schon ganz gut, jedoch wird am Schluss der Lieder immer ein Stück wiederholt, ich vermute mal, es liegt daran, dass die Bilder vorher BMP waren und jetzt kleiner geworden sind und da irgendwas durcheinanderkommt. :nixweiss:

Hier mein (ziemlich wirrer) Code:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
procedure ConvertPic(stream:TMemoryStream; delete:Boolean=false);
var
  tag:TID3v2Tag;
  PictureDescriptions: TPictureFrameDescriptionArray;
  i:Integer;
  sList:TSTringList;
  jpg:TJPEGImage;
  picture:TPicture;
  picStream:TMemoryStream;
begin
  picture:=TPicture.Create;
  tag:=TID3v2Tag.Create;
  sList:=TStringList.Create;
  try
    stream.Position:=0;
    tag.ReadFromstream(stream);
    if tag.exists then
    begin
      //Load Picture
      PictureDescriptions := Tag.GetAllPictureFrameDescriptions;
      sList.Clear;
      for i:=0 to length(PictureDescriptions)-1 do
        try
          sList.Add(Picture_Types[PictureDescriptions[i].bildtyp] +  ' [' + PictureDescriptions[i].Description + '] ');
        except
          sList.Add(Picture_Types[0] +  ' [' + PictureDescriptions[i].Description + '] ');
        end;
      if sList.Count > 0 then
      begin
        PicStream := TMemoryStream.Create;
        try
          Tag.GetPicture(PicStream, PictureDescriptions[0]);
          PicStream.Seek(0, soFromBeginning);
          try
            LoadPic(PicStream,Picture);
          except
            Picture.Assign(NIL);
          end;
        finally
          PicStream.Free;
        end;

        //Delete pic?
        if delete then
        begin
          for I := 0 to sList.Count do
            Tag.DeletePicture(PictureDescriptions[i]);
          Stream.Position:=0;
          Tag.WriteToStream(stream);
        end
        else
        begin
          PicStream:=TMemoryStream.Create;
          //Convert raw data to JPEG
          jpg:=TJPEGImage.Create;
          jpg.Assign(Picture.Bitmap);
          jpg.SaveToStream(PicStream);
          PicStream.Position:=0;
          Tag.SetPicture(PicStream,PictureDescriptions[0]);
          Stream.Position:=0;
          Tag.WriteToStreaM(Stream);
          jpg.Free;
          PicStream.Free;
        end;
      end
      else begin
        Picture.Assign(NIL);
      end;
    end;
  finally
    tag.Free;
    sList.Free;
    picture.Free;
  end;
  stream.Position:=0;
end;

LoadPic ist ne selbstgeschriebene Prozedur, die alle möglichen Grafikformate in ein TPicture lädt. (Ich glaub nich, dass da der Fehler liegt, deshalb hab ich den Code jetz nich gepostet)

_________________
I thought what I'd do was, I'd pretend I was one of those deaf-mutes.
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8535
Erhaltene Danke: 473

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Do 01.02.07 18:04 
Hmm... da habe ich eine ganz böse Befürchtung :gruebel:

Du bearbeitest also die Tags so, dass sie (signifikant) kleiner werden, und wenn du speicherst, dann ist das mp3-File insofern beschädigt, dass hinterher beim abspielen am Ende was doppelt abgespielt wird?

Würdest du mir evtl. ein Beispiel-Lied mailen, und am besten auch eine kompilierfähige Version deines Projektes (ggf. auf diesen Code/dieses spezielle File beschränkt), damit ich mich mal dahintersetzen kann, was da schiefläuft?
Das mit dem Projekt muss nicht unbedingt sein, aber eine fehlerhafte Datei (und ein passendes Original) wäre schon hilfreich.

Edit: Was schiefläuft, weiß ich jetzt. Dürfte ne Kleinigkeit im Code sein, aber da muss ich mal etwas genauer drüber nachdenken. Da fehlt einfach ein SetStreamEnd oder so ähnlich. In den vorhandenen Datenstrom wird der Tag geschrieben, dann die Audiodaten. Wenn der Tag wesentlich kürzer geworden ist, dann stehen am Ende noch Audiodaten vom alten Stream, die aber wieder mit gespeichert werden.

Sorry: :oops: Ein böser Fehler, ganz wie ich vermutet hatte. Wird so schnell wie möglich gefixed.

_________________
We are, we were and will not be.
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8535
Erhaltene Danke: 473

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Mo 12.02.07 21:33 
So, Fehler behoben und ne neue Version mit ein paar anderen Änderungen hochgeladen. Die Anmerkungen von Manina sind aber noch nicht drin (die hab ich grade beim posten erst wieder entdeckt :oops:) - im Zweifelsfall die angesprochenen Copmilerschalter abschalten, wie es auch Vorgabe ist. Ich guck da aber nochmal drüber.
Da Seek auf jeden Fall einen Typ mit Vorzeichen erwartet, funktioniert das auch so. Intern wird richtig rumgecastet, so dass der Integerüberlauf/Bereichsüberschreitung hier nicht schlimm ist, bzw. das richtige Ergebnis liefert.

_________________
We are, we were and will not be.
Manina
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 44

Win 7 Pro
RAD Studio 2010 Pro
BeitragVerfasst: Mo 02.04.07 23:48 
Mal wieder was von mir :D

diesmal nur ein klitzeklitzeklitzeklitzekleiner Schönheitsfehler in den Definitionen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
  // Beschreibung für Bild-Frames
  TPictureFrameDesription = record
    Description: String;
    Bildtyp: Byte;
  end;


soll doch (hoffentlich) wohl heißen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
  // Beschreibung für Bild-Frames
  TPictureFrameDescription = record 
    Description: String;
    Bildtyp: Byte;
  end;


Oder war das Absicht von Dir ? Wenn ja, dann sorry ... :roll:

_________________
Gates, oder Gates nicht ?
MrSaint
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1033
Erhaltene Danke: 1

WinXP Pro SP2
Delphi 6 Prof.
BeitragVerfasst: Mi 13.06.07 08:42 
Hallo!
Bin auch grad am rumexperimentieren mit deiner Komponente und mi ID3v2Tag funktionierrt bisher eigentlich alles toll. Leider hab ich etwas Probleme mit dem ID3V1Tag. Du Speicehrst hier Titel etc. intern als String30 ab und castest das bei einer Abfrage auf id3v1.Title auf WideString (ich hab den TNT-Compilerschalter an). Wenn ich jetzt sowas mache:
ausblenden Delphi-Quelltext
1:
shwomessage('Titel: ' + id3v1.Titel + ' blabla');					

wird das 'blabla' abgeschnitten, weil er die #0-Zeichen aus dem String30 bei der Konvertierung zu WideString mitnimmt :( Was helfen würde wäre u.U. folendes "rumgecaste":
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
function TID3v1Tag.GetTitle: WideString;
begin
  {$IFDEF USE_DIConverters}
  result := GetConvertedUnicodeText(FTitle);
  {$ELSE}
  result := WideString(PChar(string(FTitle)));
  {$ENDIF}
end;

Dann wird alles korrekt zurückgegeben (leider kann man FTitle nicht direkt in PChar casten, das mag er nicht...). Jetzt habe ich nur nicht allzu viel Ahnung von Unicode und weiß deshalb nicht, ob bei so einer Methode hier irgendwas verloren geht...
Gleiches gilt für Artist, Album & Comment...




MrSaint

_________________
"people knew how to write small, efficient programs [...], a skill that has subsequently been lost"
Andrew S. Tanenbaum - Modern Operating Systems
Chatfix
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1583
Erhaltene Danke: 10

Win 10, Win 8, Win 7, Win Vista, Win XP
VB.net (VS 2015), MsSQL (T-SQL), HTML, CSS, PHP, MySQL
BeitragVerfasst: Mi 13.06.07 08:51 
Wenn ich mich recht erinnere hatte ich das selbe Problem.
Versuchs mal mit Trim. Damit sollten die #0-Zeichen verschwinden :)

_________________
Gehirn: ein Organ, mit dem wir denken, daß wir denken. - Ambrose Bierce
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8535
Erhaltene Danke: 473

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Mi 13.06.07 09:31 
Ja, ein Trim in den Gettern sollte helfen, also result := Trim(WideString(FArtist));. Wichtig wäre möglicherweise auch, für die Eigenschaft Year auch einen Getter zu bauen, der mit Trim arbeitet. Werde wohl die Tage (oder schon heut nachmittag) mal was daran ändern - dann kann ich auch endlich die ganzen PNs löschen :lol:.

_________________
We are, we were and will not be.
MrSaint
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1033
Erhaltene Danke: 1

WinXP Pro SP2
Delphi 6 Prof.
BeitragVerfasst: Mi 13.06.07 11:13 
Hmm.. Trim... da war was ;) Oh man, man kann's sich ja auch kompliziert machen.. lol ;)

_________________
"people knew how to write small, efficient programs [...], a skill that has subsequently been lost"
Andrew S. Tanenbaum - Modern Operating Systems
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8535
Erhaltene Danke: 473

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Mi 13.06.07 15:36 
Die neue Version 0.3a ist da. Ich hoffe, ich hab auf die Schnelle nichts falsch gemacht.

Für die, die damit schon Bilder auslesen: TPictureFrameDesription heißt jetzt TPictureFrameDescription - da also ggf. bei der Variablen-Deklaration ein c einfügen.

_________________
We are, we were and will not be.
Chatfix
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1583
Erhaltene Danke: 10

Win 10, Win 8, Win 7, Win Vista, Win XP
VB.net (VS 2015), MsSQL (T-SQL), HTML, CSS, PHP, MySQL
BeitragVerfasst: Do 14.06.07 10:30 
Leider kommt beim ID3v1.Year immernoch "#0#0#0#0" wenn kein Jahr drin steht.


EDIT: Habs grad nochmal mit den anderen Probiert. Leider ist der Fehler mit dem RightTrim nicht behoben.

Hat es einen bestimmten Grund das du nicht Trim verwendet hast?

_________________
Gehirn: ein Organ, mit dem wir denken, daß wir denken. - Ambrose Bierce
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8535
Erhaltene Danke: 473

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Do 14.06.07 16:29 
Hmm... Ich kann das nicht nachvollziehen. :nixweiss: Beim Auswerten des RawTags nutze ich TrimRight, ja, und beim Setzen auch. Nen bestimmten Grund hat das iirc nicht. Aber beim Getter für Jahr ist ein Trim zusätzlich mit drin. Und Konstrukte wie
ausblenden Delphi-Quelltext
1:
2:
tmp := Id3v1Tag.year;
showmessage(PChar('@' + tmp + '@'));
zeigen brav zwei @ an, wenn das Jahr nur aus #0 besteht. Auch wenn tmp ein WideString ist (dann muss man aber das PChar weglassen, aber das ist ne andere Geschichte). Kannst du mir mal ein Minimal-Projekt schicken, wo sich dieser Fehler bemerkbar macht?

_________________
We are, we were and will not be.
Chatfix
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1583
Erhaltene Danke: 10

Win 10, Win 8, Win 7, Win Vista, Win XP
VB.net (VS 2015), MsSQL (T-SQL), HTML, CSS, PHP, MySQL
BeitragVerfasst: Do 14.06.07 22:03 
Ok, ich schau mir das morgen mal an und versuch mal aus meinem Colde ein Testprogramm zu schreiben.
Vielleicht hab ich ja auch einen Fehler drin.

Ich nutze auf jedenfall die Unicode-Variante mit den TNT-Komponenten.

PS: Du kannst aber morgen ruhig in Ruhe feiern. Sooo dringend ist das Problem nicht, da die Version 0.3 mit Trim ja vorerst funktioniert.

_________________
Gehirn: ein Organ, mit dem wir denken, daß wir denken. - Ambrose Bierce
Chatfix
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1583
Erhaltene Danke: 10

Win 10, Win 8, Win 7, Win Vista, Win XP
VB.net (VS 2015), MsSQL (T-SQL), HTML, CSS, PHP, MySQL
BeitragVerfasst: Fr 15.06.07 09:03 
[schlechte Singstimme]
Weil Du heut Geburtstag hast da hab ich mir gedacht,
ich probier es einfach nochmal aus und siehe da: es klappt.
[/schlechte Singstimme]

:party: Erstmal alles Gute zum Geburtstag! Vorallem viel Gesundheit! :party:

Nun wieder zum Thema:
Ich habe mich heute gleich an ein Beispielprogramm gemacht und dort trat der Fehler nicht auf.
Ich habe also nochmal im eigentlichen Projekt die Mp3FileUtils ausgetauscht. Und nun funktionierts auch hier.

Ich weis nicht warum es vorher nicht ging. Vielleicht hab ich die DCU nicht gelöscht, aber die hätte ja Delphi neu kompilieren müssen, da ich in der neuen Unit ja die Tnt's eingeschaltet habe. Nunja jetzt scheints zu funktionieren.

Danke trotzdem für deine Mühen!

_________________
Gehirn: ein Organ, mit dem wir denken, daß wir denken. - Ambrose Bierce
Lazarus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 33



BeitragVerfasst: Mi 11.07.07 18:06 
Gausi, RESPEKT für deine Arbeit. Funzt ja auch soweit hganz gut.
Beim Bilder auslesen und bei Unicode baut das Programm bei mir dann mist. Letzteres, weil ich die anderen Komponenten (TNT) nicht habe. Bei mir sind in iTunes alle Bilder da und auch alle Titel etc. Bei deinen Routinen fällt mein programm manchmal auf die Nase... Wenn ich geneueres weiß, sag ich dir bescheid...
Schade das die TNT Kompos kommerziell sind, kennt da jemand ne alternative ???
Chatfix
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1583
Erhaltene Danke: 10

Win 10, Win 8, Win 7, Win Vista, Win XP
VB.net (VS 2015), MsSQL (T-SQL), HTML, CSS, PHP, MySQL
BeitragVerfasst: Mi 11.07.07 18:11 
Weis nich obs legal is aber ich habe noch die alten kostenlosen TNT-Kompos, die könnte ich dir zukommen lassen, wenn mal jemand klärt ob das zulässig ist.

_________________
Gehirn: ein Organ, mit dem wir denken, daß wir denken. - Ambrose Bierce
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8535
Erhaltene Danke: 473

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Mi 11.07.07 18:32 
@iTunes und Bilder: Ich habe keine Ahnung, wo iTunes die Bilder hinpackt. Wahrscheinlich gibts da irgendwo auf der Platte ne Datenbank, in der die gespeichert sind, oder der ruft die direkt aus dem Netz ab. Diese Unit sucht nur im ID3v2Tag nach den PICTURE-Frames. Ich kann mir aber gerne mal ein mp3-File ansehen, wo iTunes Bilder anzeigt. Schicks per Mail, dann schau ich mal drüber. Wenn eins drin ist, dann werde ich das wahrscheinlich erkennen, und ggf. den Fehler in der Unit ausbügeln. Allerdings glaube ich, dass iTunes da was anderes verwendet. ;-)

@TNTs: Bei mir steht in der License.txt so etwas:
Zitat:
Redistribution and use in binary forms, with or without modification, are permitted.
Redistribution and use in source forms, with or without modification, are permitted provided that the redistributions of source code retain the above copyright.

Meiner Meinung nach dürfte ein Kopieren und Weiterverteilen kein Problem sein.

_________________
We are, we were and will not be.
jakobwenzel
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1889
Erhaltene Danke: 1

XP home, ubuntu
BDS 2006 Prof
BeitragVerfasst: Mi 11.07.07 18:50 
Zumindest in ver. 7.3.0.54 speichert iTunes die Bilder im Tag (wobei ich auch alle Bilder manuell eigefügt hab), wenn auch nicht unbedingt im JPG-Format (was ja laut Spezifikation das einzige zulässige Format ist)

_________________
I thought what I'd do was, I'd pretend I was one of those deaf-mutes.