Autor |
Beitrag |
mimi
Beiträge: 3458
Ubuntu, Win XP
Lazarus
|
Verfasst: Mi 28.07.04 13: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 15:06, insgesamt 2-mal bearbeitet
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 28.07.04 15: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:
| type ESoundSetOutputError = 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:
| try Sound := 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 18: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 12: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 12: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 14: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 14: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...."
|
|
|