| 
| Autor | Beitrag |  
| mimi 
          Beiträge: 3458
 
 Ubuntu, Win XP
 Lazarus
 
 | 
Verfasst: Mi 28.07.04 12:53 
 
Hallo,
 ich habe heute mal eine sound Klasse geschrieben, mit deren hilfe man sehr einfach viele verschiedne formate abspielen kann.
 die verwendung ist sehr einfach:
 Beispiel:
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 
 | Form1.Create:Sound:=TSound(Handle);
 Sound.add(Dateinamen);
 Sound.Play(DateiNamen);
 Timer1.invervall:=1;
 
 Timer1.OnTimer:
 Sound.CheckPlay;
 |  Upgedatete Version, vorschläge von Nightmare_82 habe ich übernommen
 Unit:
 												| 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:
 77:
 78:
 79:
 80:
 81:
 82:
 83:
 84:
 85:
 86:
 87:
 88:
 89:
 90:
 91:
 92:
 93:
 94:
 95:
 96:
 97:
 98:
 99:
 100:
 101:
 102:
 103:
 104:
 105:
 106:
 107:
 108:
 109:
 110:
 111:
 112:
 113:
 114:
 115:
 116:
 117:
 118:
 119:
 120:
 121:
 122:
 123:
 124:
 125:
 126:
 127:
 128:
 129:
 130:
 131:
 132:
 133:
 134:
 135:
 136:
 137:
 138:
 139:
 140:
 141:
 142:
 143:
 144:
 145:
 146:
 147:
 148:
 149:
 150:
 151:
 152:
 153:
 154:
 155:
 156:
 157:
 158:
 159:
 160:
 161:
 162:
 163:
 164:
 165:
 166:
 167:
 168:
 169:
 170:
 171:
 172:
 173:
 174:
 175:
 176:
 177:
 178:
 179:
 180:
 181:
 182:
 183:
 184:
 185:
 186:
 187:
 188:
 189:
 190:
 191:
 192:
 193:
 194:
 195:
 196:
 197:
 198:
 199:
 200:
 201:
 202:
 203:
 204:
 205:
 206:
 207:
 208:
 209:
 210:
 211:
 212:
 213:
 214:
 215:
 216:
 217:
 218:
 219:
 220:
 221:
 222:
 223:
 224:
 225:
 226:
 227:
 228:
 229:
 230:
 231:
 232:
 233:
 234:
 235:
 236:
 237:
 238:
 239:
 240:
 241:
 242:
 243:
 244:
 245:
 246:
 247:
 248:
 249:
 250:
 251:
 252:
 253:
 254:
 255:
 256:
 257:
 258:
 259:
 260:
 261:
 262:
 263:
 264:
 265:
 266:
 267:
 268:
 269:
 270:
 271:
 272:
 273:
 274:
 275:
 276:
 277:
 278:
 279:
 280:
 281:
 282:
 283:
 284:
 285:
 286:
 287:
 288:
 289:
 290:
 291:
 292:
 293:
 294:
 295:
 296:
 297:
 298:
 299:
 300:
 301:
 302:
 303:
 304:
 305:
 306:
 307:
 308:
 309:
 310:
 311:
 312:
 313:
 314:
 315:
 316:
 317:
 318:
 319:
 320:
 321:
 322:
 323:
 324:
 325:
 326:
 327:
 328:
 329:
 330:
 331:
 332:
 333:
 334:
 335:
 336:
 337:
 338:
 339:
 340:
 341:
 342:
 343:
 344:
 345:
 346:
 347:
 348:
 349:
 350:
 351:
 352:
 353:
 354:
 355:
 356:
 357:
 358:
 359:
 360:
 361:
 362:
 363:
 364:
 365:
 366:
 367:
 368:
 369:
 370:
 371:
 372:
 373:
 374:
 375:
 376:
 377:
 378:
 379:
 380:
 381:
 382:
 383:
 
 | 
 unit usound;
 
 interface
 
 uses fmodtypes,SysUtils,dialogs,ExtCtrls,wihle,Classes;
 
 type
 
 TSongType = record
 Module: PFMusicModule;
 Stream: PFSoundStream;
 Channel,f: Integer;
 isLoad: Boolean;
 FileName:String;
 end;
 
 TSound = class
 private
 Timer:TTimer;
 Musik: array of TSongType;     Sound: array of TSongType;     PlayMusikIndex:Integer;     isRandom:Boolean;     t:TSoundWihle;     function OpenSong(FileName:TFileName):TSongType;     function GetListenIndex(Song: array of TSongType; FileName:TFileName): Integer;     procedure RandomMusik;     procedure onE;
 procedure DeleteSong(Liste:array of TSongType; index:Integer);
 public
 dFileName:String;
 constructor Create(Handle:Cardinal);     procedure AddSound(FileName:String);     procedure AddMusik(FileName:String);
 procedure ClearSound;     procedure ClearMusik;
 procedure PlayMusik(FileName:String; F:Integer);     procedure PlaySound(FileName:String; F:Integer);     procedure StopSong;     procedure CheckPlay;     procedure TInit;
 
 end;
 
 implementation
 
 uses fmod, fmoderrors;
 
 
 
 constructor TSound.Create(Handle:Cardinal);
 begin
 if FMOD_VERSION > FSOUND_GetVersion then
 begin
 ShowMessage(PChar(Format('API version %3.2f is newer than DLL version %3.2f', [FMOD_VERSION, FSOUND_GetVersion])));
 Halt;
 end;
 
 
 try
 if not FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND) then
 raise Exception.Create('FSOUND_SetOutput failed');
 if not FSOUND_SetDriver(0) then
 raise Exception.Create('FSOUND_SetDriver failed');
 if not FSOUND_SetMixer(FSOUND_MIXER_QUALITY_AUTODETECT) then
 raise Exception.Create('FSOUND_SetMixer failed');
 if not FSOUND_SetHWND(Handle) then
 raise Exception.Create('FSOUND_SetHWND failed');
 except
 ShowMessage(FMOD_ErrorString(FSOUND_GetError));
 raise;
 end;
 
 if not FSOUND_Init(22050, 128, FSOUND_Init_GlobalFocus) then
 begin
 Showmessage(FMOD_ErrorString(FSOUND_GetError));
 Halt;
 end;
 
 PlayMusikIndex:=-1; isRandom:=False;
 
 end;
 
 procedure TSound.ClearSound; begin
 SetLength(Sound,0);
 end;
 
 procedure TSound.ClearMusik; begin
 SetLength(Musik,0);
 end;
 
 procedure TSound.TInit;
 begin
 t:=TSoundWihle.Create(True);
 t.onE:=onE;
 t.Priority := tpLower;
 t.FreeOnTerminate:=True;
 t.Resume;
 end;
 
 
 
 procedure TSound.DeleteSong(Liste:array of TSongType;index:Integer);
 var
 i:Integer;
 begin
 if Length(Liste) -1 >= 1 then begin
 for i:=index to HIGH(Liste) do
 Liste[i]:=Liste[i+1];
 end;
 end;
 
 
 
 procedure TSound.onE;
 begin
 CheckPlay;
 end;
 
 
 
 procedure TSound.StopSong;
 begin
 if Musik[PlayMusikIndex].Module <> NIL then FMUSIC_StopSong(Musik[PlayMusikIndex].Module);
 if Musik[PlayMusikIndex].Channel > -1 then FSOUND_StopSound(Musik[PlayMusikIndex].Channel);
 end;
 
 
 
 procedure TSound.randomMusik;
 var
 r:Integer;
 begin
 t.Suspend;
 isRandom:=True;
 try
 Randomize;
 r:=random(length(musik));
 PlayMusik(Musik[r].FileName,Musik[r].f)
 finally
 isRandom:=False;
 t.Resume;
 end;
 end;
 
 
 
 procedure TSound.CheckPlay;
 begin
 
 if (PlayMusikIndex > -1) and (isRandom = False)  then begin
 
 if (Musik[PlayMusikIndex].Module <> NIL) and (FMUSIC_IsFinished(Musik[PlayMusikIndex].Module) = True) then
 randomMusik;
 
 if (Musik[PlayMusikIndex].Stream <> NIL) and ( FSOUND_IsPlaying(Musik[PlayMusikIndex].Channel) = False) then
 randomMusik;
 end;
 
 end;
 
 
 
 
 function TSound.GetListenIndex(Song: array of TSongType; FileName:TFileName): Integer;
 var
 i:Integer;
 begin
 for i:=0 to High(Song) do begin
 if Song[i].FileName = FileName then begin
 result:=i;
 exit;
 end;
 end;
 
 result:=-1;
 end;
 
 
 
 
 
 function TSound.OpenSong(FileName:TFileName):TSongType;
 var
 Module: PFMusicModule;
 Stream: PFSoundStream;
 SongCount: Integer;
 begin
 Stream := nil;
 Module := nil;
 
 Module := FMUSIC_LoadSong(PChar(FileName));
 
 
 if Module = nil then
 Stream := FSOUND_Stream_Open(PChar(FileName), FSOUND_NORMAL, 0, 0);
 
 if (Module = nil) and (Stream = nil) then begin
 Showmessage(FMOD_ErrorString(FSOUND_GetError));
 exit;
 end;
 
 if Module <> nil then  FMUSIC_SetMasterVolume(Module, 255);
 
 result.Module := Module;
 result.Stream := Stream;
 result.isLoad:=True;
 end;
 
 
 
 procedure TSound.PlaySound(FileName:String; f:Integer);
 var
 Index:Integer;
 Test:TSongType;
 begin
 if (f = 1) and (PlayMusikIndex > -1) then begin
 DeleteSong(Sound,PlayMusikIndex);
 SetLength(Sound,Length(Sound)-1);
 end;
 
 Index:=GetListenIndex(Sound,FileName);
 
 if index > -1 then begin
 if Sound[index].isLoad = False then begin
 Test:=OpenSong(Filename);
 Sound[index].Module:=Test.Module;
 Sound[index].Stream:=Test.Stream;
 Sound[index].Channel:=Test.Channel;
 end;
 
 if Sound[Index].Module <> nil then begin
 FMUSIC_PlaySong(Sound[Index].Module);
 if Sound[Index].Module = nil then
 ShowmEssage(FMOD_ErrorString(FSOUND_GetError));
 end
 else begin
 if Sound[Index].Stream <> nil then begin
 Sound[Index].Channel := FSOUND_Stream_Play(FSOUND_FREE, Sound[Index].Stream);
 
 if Sound[Index].Channel = -1 then begin
 ShowMessage(FMOD_ErrorString(FSOUND_GetError));
 end
 end;
 end;
 end;
 
 
 end;
 
 
 
 procedure TSound.PlayMusik(FileName:String; f:Integer);
 var
 Index:Integer;
 Test:TSongType;
 begin
 if (f = 1) and (PlayMusikIndex > -1) then begin
 DeleteSong(Musik,PlayMusikIndex);
 SetLength(Musik,Length(Musik)-1);
 end;
 
 Index:=GetListenIndex(Musik,FileName);
 
 if index > -1 then begin
 if Musik[index].isLoad = False then begin
 Test:=OpenSong(Filename);
 dFileName:=FileName;
 Musik[index].Module:=Test.Module;
 Musik[index].Stream:=Test.Stream;
 Musik[index].Channel:=Test.Channel;
 
 end;
 
 
 if Musik[Index].Module <> nil then begin
 FMUSIC_PlaySong(Musik[Index].Module);
 if Musik[Index].Module = nil then
 ShowmEssage(FMOD_ErrorString(FSOUND_GetError));
 end
 else begin
 
 if Musik[Index].Stream <> nil then begin
 Musik[Index].Channel := FSOUND_Stream_Play(FSOUND_FREE, Musik[Index].Stream);
 
 if Musik[Index].Channel = -1 then begin
 ShowMessage(FMOD_ErrorString(FSOUND_GetError));
 end
 end;
 end;
 end;
 PlayMusikIndex:=Index;
 end;
 
 
 
 procedure TSound.AddSound(FileName:String);
 begin
 if GetListenIndex(Sound,FileName) = -1 then begin
 SetLength(Sound,high(Sound)+2);
 
 Sound[high(Sound)].FileName:=FileName;
 Sound[high(Sound)].Module:=NIL;
 Sound[high(Sound)].Stream:=NIL;
 Sound[high(Sound)].Channel:=-1;
 Sound[high(Sound)].isLoad:=False;
 end;
 end;
 
 
 
 procedure TSound.AddMusik(FileName:String);
 begin
 if GetListenIndex(musik,FileName) = -1 then begin
 SetLength(Musik,high(Musik)+2);
 Musik[high(Musik)].FileName:=FileName;
 
 Musik[high(Musik)].Module:=NIL;
 Musik[high(Musik)].Stream:=NIL;
 Musik[high(Musik)].Channel:=-1;
 Musik[high(Musik)].isLoad:=False;
 end;
 end;
 
 end.
 | _________________ MFG
   Michael Springwald, "kann kein englisch...."
 
 Zuletzt bearbeitet von mimi am Fr 30.07.04 14:06, insgesamt 2-mal bearbeitet
 |  |  |  
| Luckie Ehemaliges Mitglied
 Erhaltene Danke: 1
 
 
 
 
 | 
Verfasst: Mi 28.07.04 14:52 
 
Das ist schlecht:
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 
 |   if FMOD_VERSION > FSOUND_GetVersion then  begin
 ShowMessage(PChar(Format('API version %3.2f is newer than DLL version %3.2f', [FMOD_VERSION, FSOUND_GetVersion])));
 Halt;
 end;
 |  Nehmen wir an ich habe ein Spiel mit Sound programmiert. Wenn jetzt was bei der Initialisierung deiner Sound Klasse fehlschläg, dann wird gleich das ganze Programm beendet. Ich hab also noch nicht mal die Chance mein "Vier gewinnt" ohne Sound zu spielen. Und der Programmierer hat noch nicht mal die Möglichkeit eine eigenen Fehlermeldung auszugeben.
 Du solltest eine Exception werfen, die dann der Programmierer geielt abfangen kann.
 Ebendso hier:
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 
 |   try  if not FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND) then
 raise Exception.Create('FSOUND_SetOutput failed');
 if not FSOUND_SetDriver(0) then
 raise Exception.Create('FSOUND_SetDriver failed');
 if not FSOUND_SetMixer(FSOUND_MIXER_QUALITY_AUTODETECT) then
 raise Exception.Create('FSOUND_SetMixer failed');
 if not FSOUND_SetHWND(Handle) then
 raise Exception.Create('FSOUND_SetHWND failed');
 except
 |  Spezifische Exceptions würde es den Programmierer einfachher machen Fehler abzufangen. Also zum Beispiel so was:
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 
 | typeESoundSetOutputError = class(Exception);
 ESoundSetDriverError = class(Exception);
 ...;
 ...;
 |  Undd ann im Code:
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 
 | constructor TSound.Create....;resourcestring
 rsSetOutputError = 'Output konnte nicht initialisiert werden';
 ...;
 begin
 ...;
 ...;
 if not FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND) then
 raise ESoundSetOutputError.Create(rsSetOutputError);
 ...;
 end;
 |  Aufruf:
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 
 | trySound := TSound.Create....;
 try
 Sound. ...;
 finally
 FreeAndNil(Sound);
 end;
 except
 on e: ESoundSetOutputError do ShowMessage(e.Message);
 on e: ESoundSetDriverError do ...
 end;
 |  Was die Exceptions angeht kannst du dir mal hier mein Demo dazu ankucken: www.luckie-online.de/Downloads/Demos/ |  |  |  
| mimi  
          Beiträge: 3458
 
 Ubuntu, Win XP
 Lazarus
 
 | 
Verfasst: Mi 28.07.04 17:49 
 
Danke für dein vorschlag... kennst du tutors über sowas ? also was die laufzeit fehler angehet ?? _________________ MFG
   Michael Springwald, "kann kein englisch...."
 |  |  |  
| Luckie Ehemaliges Mitglied
 Erhaltene Danke: 1
 
 
 
 
 | 
Verfasst: Fr 30.07.04 11:23 
 
hast du schon mal auf den Link geklickt? da findest zu mindest erstmal eine Demo. Ansonsten arbeite / plane ich gerade ein Exception Tutorial - kann aber noch etwas dauern. |  |  |  
| mimi  
          Beiträge: 3458
 
 Ubuntu, Win XP
 Lazarus
 
 | 
Verfasst: Fr 30.07.04 11:28 
 
ja habe ich*G*
 und sonst, was könnte ich noch verbessern, einbauen ??
 _________________ MFG
   Michael Springwald, "kann kein englisch...."
 |  |  |  
| Nightmare_82 
          Beiträge: 260
 
 
 
 
 | 
Verfasst: Fr 30.07.04 13:32 
 
Ich habe mir die Unit mal angeschaut und habe ein paar Verbesserungsvorschläge:
 	  | mimi hat folgendes geschrieben: |  	  | 
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 
 | procedure TSound.randomMusik;begin
 isRandom:=True;
 try
 Randomize;
 PlayMusik(Musik[random(high(musik))].FileName)
 finally
 isRandom:=False;
 end;
 end;
 |  
 | 
 hier muß es length(musik) oder high(musik)+1 sein, sonst wird das letzte Lied nie abgespielt.
 Ansonsten sollte man Randomize nur einmal aufrufen am Anfang. 
 Was auch noch gut wäre, wäre die Möglichkeit, die Sounds auch wieder freizugeben. Wenn ich damit einen MP3-Player programmieren würde, wären irgendwann alle Lieder im Speicher.Am besten über ein Flag, das regelt, ob die Lieder, nachdem sie gespielt wurden, freigegeben werden(was man beim Laden jedes Lieds/Sounds mitangibt).
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 
 | procedure TSound.StopSong;  begin
 if Musik[PlayMusikIndex].Module <> NIL then FMUSIC_StopSong(Musik[PlayMusikIndex].Module);
 if Musik[PlayMusikIndex].Channel > -1 then FSOUND_StopSound(Musik[PlayMusikIndex].Channel);
 end;
 |  Hier solltest du noch prüfen, ob PlayMusikIndex > -1 ist, sonst gibts eine Zugriffsverletzung.
 Ansonsten wäre es nicht schlecht, wenn er bei AddSong und AddMusik prüfen würde, ob die Datei schon geladen wurde. Sonst lädt man leicht Lieder doppelt.
 Aber die Klasse sieht ansonsten ziemlich brauchbar aus. |  |  |  
| mimi  
          Beiträge: 3458
 
 Ubuntu, Win XP
 Lazarus
 
 | 
Verfasst: Fr 30.07.04 13:43 
 
randomMusik wird ja nur aufgerufen, wenn ein lied zu ände ist, und so macht es wohl nichts *G*
 danke für deine vorschläge, werde ich gleich umsetzen  _________________ MFG
   Michael Springwald, "kann kein englisch...."
 |  |  |  |