DEADSOFTWARE

restored fmod sound driver
[d2df-sdl.git] / src / engine / e_sound_sdl.inc
1 interface
3 uses
4 sdl2,
5 SDL2_mixer,
6 e_log,
7 SysUtils;
9 type
10 TSoundRec = record
11 Data: Pointer;
12 Sound: PMix_Chunk;
13 Music: PMix_Music;
14 isMusic: Boolean;
15 nRefs: Integer;
16 end;
18 TBasicSound = class (TObject)
19 private
20 FChanNum: Integer; // <0: no channel allocated
22 protected
23 FID: DWORD;
24 FMusic: Boolean;
25 FPosition: DWORD;
26 FPriority: Integer;
28 function RawPlay(Pan: Single; Volume: Single; aPos: DWORD): Boolean;
29 function GetChan (): Integer;
31 property Channel: Integer read GetChan;
33 public
34 constructor Create();
35 destructor Destroy(); override;
36 procedure SetID(ID: DWORD);
37 procedure FreeSound();
38 function IsPlaying(): Boolean;
39 procedure Stop();
40 function IsPaused(): Boolean;
41 procedure Pause(Enable: Boolean);
42 function GetVolume(): Single;
43 procedure SetVolume(Volume: Single);
44 function GetPan(): Single;
45 procedure SetPan(Pan: Single);
46 function IsMuted(): Boolean;
47 procedure Mute(Enable: Boolean);
48 function GetPosition(): DWORD;
49 procedure SetPosition(aPos: DWORD);
50 procedure SetPriority(priority: Integer);
51 end;
53 const
54 NO_SOUND_ID = DWORD(-1);
56 function e_InitSoundSystem(): Boolean;
58 function e_LoadSound(FileName: string; var ID: DWORD; isMusic: Boolean): Boolean;
59 function e_LoadSoundMem(pData: Pointer; Length: Integer; var ID: DWORD; isMusic: Boolean): Boolean;
61 // returns channel number or -1
62 function e_PlaySound(ID: DWORD): Integer;
63 function e_PlaySoundPan(ID: DWORD; Pan: Single): Integer;
64 function e_PlaySoundVolume(ID: DWORD; Volume: Single): Integer;
65 function e_PlaySoundPanVolume(ID: DWORD; Pan, Volume: Single): Integer;
67 procedure e_ModifyChannelsVolumes(SoundMod: Single; setMode: Boolean);
68 procedure e_MuteChannels(Enable: Boolean);
69 procedure e_StopChannels();
71 procedure e_DeleteSound(ID: DWORD);
72 procedure e_RemoveAllSounds();
73 procedure e_ReleaseSoundSystem();
74 procedure e_SoundUpdate();
76 var
77 e_SoundsArray: array of TSoundRec = nil;
79 implementation
81 uses
82 g_window, g_options, BinEditor;
84 const
85 N_CHANNELS = 512;
86 N_MUSCHAN = N_CHANNELS+42;
88 type
89 TChanInfo = record
90 id: DWORD; // sound id
91 muted: Boolean;
92 oldvol: Integer; // for muted
93 pan: Single;
94 end;
96 var
97 SoundMuted: Boolean = False;
98 SoundInitialized: Boolean = False;
99 ChanSIds: array[0..N_CHANNELS] of TChanInfo;
100 MusVolume: Integer = MIX_MAX_VOLUME;
103 procedure chanFinished (chan: Integer); cdecl;
104 begin
105 //e_WriteLog(Format('chanFinished: %d', [chan]), MSG_NOTIFY);
106 if (chan >= 0) and (chan < N_CHANNELS) then
107 begin
108 if ChanSIds[chan].id <> NO_SOUND_ID then
109 begin
110 if (ChanSIds[chan].id <= High(e_SoundsArray)) and (e_SoundsArray[ChanSIds[chan].id].nRefs > 0) then
111 begin
112 Dec(e_SoundsArray[ChanSIds[chan].id].nRefs);
113 end;
114 ChanSIds[chan].id := NO_SOUND_ID;
115 end;
116 end;
117 end;
120 procedure dumpMusicType (ms: PMix_Music);
121 begin
122 if ms = nil then
123 begin
124 e_WriteLog('MUSIC FORMAT: NONE', MSG_NOTIFY);
125 end
126 else
127 begin
128 case Mix_GetMusicType(ms^) of
129 TMix_MusicType.MUS_NONE:
130 e_WriteLog('MUSIC FORMAT: NONE', MSG_NOTIFY);
131 TMix_MusicType.MUS_CMD:
132 e_WriteLog('MUSIC FORMAT: CMD', MSG_NOTIFY);
133 TMix_MusicType.MUS_WAV:
134 e_WriteLog('MUSIC FORMAT: WAV', MSG_NOTIFY);
135 TMix_MusicType.MUS_MOD:
136 e_WriteLog('MUSIC FORMAT: MOD', MSG_NOTIFY);
137 TMix_MusicType.MUS_MID:
138 e_WriteLog('MUSIC FORMAT: MID', MSG_NOTIFY);
139 TMix_MusicType.MUS_OGG:
140 e_WriteLog('MUSIC FORMAT: OGG', MSG_NOTIFY);
141 TMix_MusicType.MUS_MP3:
142 e_WriteLog('MUSIC FORMAT: MP3', MSG_NOTIFY);
143 TMix_MusicType.MUS_MP3_MAD:
144 e_WriteLog('MUSIC FORMAT: MP3_MAD', MSG_NOTIFY);
145 TMix_MusicType.MUS_FLAC:
146 e_WriteLog('MUSIC FORMAT: FLAC', MSG_NOTIFY);
147 TMix_MusicType.MUS_MODPLUG:
148 e_WriteLog('MUSIC FORMAT: MODPLUG', MSG_NOTIFY);
149 otherwise
150 e_WriteLog('MUSIC FORMAT: UNKNOWN', MSG_NOTIFY);
151 end;
152 end;
153 end;
155 function e_InitSoundSystem(): Boolean;
156 var
157 res, i: Integer;
158 begin
159 if SoundInitialized then begin Result := true; Exit end;
161 Result := False;
162 SoundInitialized := False;
164 // wow, this is actually MIDI player!
165 // we need module player
166 res := Mix_Init(MIX_INIT_FLAC or MIX_INIT_MOD or MIX_INIT_MODPLUG or MIX_INIT_MP3 or MIX_INIT_OGG or MIX_INIT_FLUIDSYNTH);
167 e_WriteLog(Format('SDL: res=0x%x', [res]), MSG_NOTIFY);
168 if (res and MIX_INIT_FLAC) <> 0 then e_WriteLog('SDL: FLAC playback is active', MSG_NOTIFY);
169 if (res and MIX_INIT_MOD) <> 0 then e_WriteLog('SDL: MOD playback is active', MSG_NOTIFY);
170 if (res and MIX_INIT_MODPLUG) <> 0 then e_WriteLog('SDL: MODPLUG playback is active', MSG_NOTIFY);
171 if (res and MIX_INIT_MP3) <> 0 then e_WriteLog('SDL: MP3 playback is active', MSG_NOTIFY);
172 if (res and MIX_INIT_OGG) <> 0 then e_WriteLog('SDL: OGG playback is active', MSG_NOTIFY);
173 if (res and MIX_INIT_FLUIDSYNTH) <> 0 then e_WriteLog('SDL: FLUIDSYNTH playback is active', MSG_NOTIFY);
175 res := Mix_OpenAudio(48000, AUDIO_S16LSB, 2, 2048);
176 if res = -1 then res := Mix_OpenAudio(44100, AUDIO_S16LSB, 2, 2048);
177 if res = -1 then
178 begin
179 e_WriteLog('Error initializing SDL mixer:', MSG_FATALERROR);
180 e_WriteLog(Mix_GetError(), MSG_FATALERROR);
181 Exit;
182 end;
184 Mix_AllocateChannels(N_CHANNELS);
185 Mix_ChannelFinished(chanFinished);
187 for i := 0 to N_CHANNELS-1 do
188 begin
189 ChanSIds[i].id := NO_SOUND_ID;
190 ChanSIds[i].muted := SoundMuted;
191 ChanSIds[i].oldvol := MIX_MAX_VOLUME;
192 ChanSIds[i].pan := 1.0;
193 end;
194 MusVolume := MIX_MAX_VOLUME;
196 SoundInitialized := True;
197 Result := True;
198 end;
200 function e_isMusic (id: DWORD): Boolean;
201 begin
202 Result := False;
203 if (e_SoundsArray <> nil) and (id <= High(e_SoundsArray)) then
204 begin
205 Result := (e_SoundsArray[id].Music <> nil);
206 end;
207 end;
209 function e_isSound (id: DWORD): Boolean;
210 begin
211 Result := False;
212 if (e_SoundsArray <> nil) and (id <= High(e_SoundsArray)) then
213 begin
214 Result := (e_SoundsArray[id].Sound <> nil);
215 end;
216 end;
218 function FindESound(): DWORD;
219 var
220 i: Integer;
221 begin
222 if e_SoundsArray <> nil then
223 begin
224 for i := 0 to High(e_SoundsArray) do
225 if (e_SoundsArray[i].Sound = nil) and (e_SoundsArray[i].Music = nil) then
226 begin
227 Result := i;
228 Exit;
229 end;
230 end;
231 if e_SoundsArray = nil then
232 begin
233 SetLength(e_SoundsArray, 16);
234 Result := 0;
235 end
236 else
237 begin
238 Result := High(e_SoundsArray) + 1;
239 SetLength(e_SoundsArray, Length(e_SoundsArray) + 16);
240 end;
241 for i := Result to High(e_SoundsArray) do
242 begin
243 e_SoundsArray[i].Sound := nil;
244 e_SoundsArray[i].Music := nil;
245 e_SoundsArray[i].Data := nil;
246 e_SoundsArray[i].isMusic := False;
247 e_SoundsArray[i].nRefs := 0;
248 end;
249 end;
251 function e_LoadSound(FileName: String; var ID: DWORD; isMusic: Boolean): Boolean;
252 var
253 find_id: DWORD;
254 begin
255 ID := NO_SOUND_ID;
256 Result := False;
257 if not SoundInitialized then Exit;
259 if isMusic then e_WriteLog('Loading music '+FileName+'...', MSG_NOTIFY)
260 else e_WriteLog('Loading sound '+FileName+'...', MSG_NOTIFY);
263 if isMusic then
264 begin
265 e_WriteLog('IGNORING MUSIC FROM FILE', MSG_WARNING);
266 Exit;
267 end;
270 find_id := FindESound();
272 e_SoundsArray[find_id].Data := nil;
273 e_SoundsArray[find_id].isMusic := isMusic;
274 e_SoundsArray[find_id].nRefs := 0;
276 if isMusic then
277 begin
278 e_WriteLog(Format(' MUSIC SLOT: %u', [find_id]), MSG_NOTIFY);
279 e_SoundsArray[find_id].Music := Mix_LoadMUS(PAnsiChar(FileName));
280 if e_SoundsArray[find_id].Music = nil then
281 begin
282 e_WriteLog(Format('ERROR LOADING MUSIC:', [find_id]), MSG_WARNING);
283 e_WriteLog(Mix_GetError(), MSG_WARNING);
284 Exit;
285 end;
286 dumpMusicType(e_SoundsArray[find_id].Music);
287 end
288 else
289 begin
290 e_SoundsArray[find_id].Sound := Mix_LoadWAV(PAnsiChar(FileName));
291 if e_SoundsArray[find_id].Sound = nil then Exit;
292 end;
294 ID := find_id;
296 Result := True;
297 end;
299 function e_LoadSoundMem(pData: Pointer; Length: Integer; var ID: DWORD; isMusic: Boolean): Boolean;
300 var
301 find_id: DWORD;
302 rw: PSDL_RWops;
303 //pc: PChar;
304 isid3: Boolean;
305 begin
306 ID := NO_SOUND_ID;
307 Result := False;
308 if not SoundInitialized then Exit;
309 isid3 := False;
312 if isMusic then
313 begin
314 e_WriteLog('IGNORING MUSIC FROM MEMORY', MSG_WARNING);
315 Exit;
316 end;
319 //FIXME: correctly skip ID3
321 pc := PChar(pData);
322 if (Length > $400) and (pc[0] = 'I') and (pc[1] = 'D') and (pc[2] = '3') then
323 begin
324 isid3 := True;
325 Inc(pc, $400);
326 pData := Pointer(pc);
327 Dec(Length, $400);
328 e_WriteLog('MUSIC: MP3 ID3 WORKAROUND APPLIED!', MSG_WARNING);
329 end;
332 rw := SDL_RWFromConstMem(pData, Length);
333 if rw = nil then Exit;
335 find_id := FindESound();
337 e_SoundsArray[find_id].Data := pData;
338 if isid3 then e_SoundsArray[find_id].Data := nil;
339 e_SoundsArray[find_id].isMusic := isMusic;
340 e_SoundsArray[find_id].nRefs := 0;
342 if isMusic then
343 begin
344 e_WriteLog(Format(' MUSIC SLOT: %u', [find_id]), MSG_NOTIFY);
345 e_SoundsArray[find_id].Music := Mix_LoadMUS_RW(rw, 0);
346 if e_SoundsArray[find_id].Music = nil then
347 begin
348 e_WriteLog(Format('ERROR LOADING MUSIC:', [find_id]), MSG_WARNING);
349 e_WriteLog(Mix_GetError(), MSG_WARNING);
350 end
351 else
352 begin
353 dumpMusicType(e_SoundsArray[find_id].Music);
354 end;
355 //SDL_FreeRW(rw);
357 if e_SoundsArray[find_id].Music <> nil then
358 begin
359 Mix_FreeMusic(e_SoundsArray[find_id].Music);
360 end;
361 e_SoundsArray[find_id].Music := nil;
362 Exit;
364 end
365 else
366 begin
367 e_SoundsArray[find_id].Sound := Mix_LoadWAV_RW(rw, 0);
368 end;
369 //SDL_FreeRW(rw); // somehow it segfaults...
370 if (e_SoundsArray[find_id].Sound = nil) and (e_SoundsArray[find_id].Music = nil) then
371 begin
372 e_SoundsArray[find_id].Data := nil;
373 Exit;
374 end;
376 ID := find_id;
378 Result := True;
379 end;
381 function e_PlaySound (ID: DWORD): Integer;
382 var
383 res: Integer = -1;
384 begin
385 Result := -1;
386 if not SoundInitialized then Exit;
388 if e_isSound(ID) then
389 begin
390 if e_SoundsArray[ID].nRefs >= gMaxSimSounds then Exit;
391 Inc(e_SoundsArray[ID].nRefs);
392 res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, 0);
393 if res >= 0 then
394 begin
395 ChanSIds[res].id := ID;
396 ChanSIds[res].muted := SoundMuted;
397 if SoundMuted then Mix_Volume(res, 0) else Mix_Volume(res, ChanSIds[res].oldvol);
399 if e_SoundsArray[ID].isMusic then
400 res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, -1)
401 else
402 res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, 0);
404 end;
405 end
406 else
407 begin
408 if not e_isMusic(ID) then Exit;
409 Mix_HaltMusic();
410 res := Mix_PlayMusic(e_SoundsArray[ID].Music, -1);
411 if res >= 0 then res := N_MUSCHAN;
412 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
413 Result := res;
414 end;
416 Result := res;
417 end;
419 function e_chanSetPan (chan: Integer; Pan: Single): Boolean;
420 var
421 l, r: UInt8;
422 begin
423 Result := True;
424 if chan = N_MUSCHAN then
425 begin
426 // no panning for music
427 end
428 else if chan >= 0 then
429 begin
430 if Pan < -1.0 then Pan := -1.0 else if Pan > 1.0 then Pan := 1.0;
431 Pan := Pan+1.0; // 0..2
432 l := trunc(127.0*(2.0-Pan));
433 r := trunc(127.0*Pan);
434 Mix_SetPanning(chan, l, r);
435 ChanSIds[chan].pan := Pan;
436 end
437 else
438 begin
439 Result := False;
440 end;
441 end;
443 function e_chanSetVol (chan: Integer; Volume: Single): Boolean;
444 var
445 vol: Integer;
446 begin
447 Result := True;
448 if Volume < 0 then Volume := 0 else if Volume > 1 then Volume := 1;
449 vol := trunc(Volume*MIX_MAX_VOLUME);
450 if chan = N_MUSCHAN then
451 begin
452 MusVolume := vol;
453 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(vol);
454 end
455 else if chan >= 0 then
456 begin
457 ChanSIds[chan].oldvol := vol;
458 if ChanSIds[chan].muted then Mix_Volume(chan, 0) else Mix_Volume(chan, vol);
459 end
460 else
461 begin
462 Result := False;
463 end;
464 end;
466 function e_PlaySoundPan(ID: DWORD; Pan: Single): Integer;
467 var
468 chan: Integer;
469 begin
470 Result := -1;
471 chan := e_PlaySound(ID);
472 e_chanSetPan(chan, Pan);
473 Result := chan;
474 end;
476 function e_PlaySoundVolume(ID: DWORD; Volume: Single): Integer;
477 var
478 chan: Integer;
479 begin
480 Result := -1;
481 chan := e_PlaySound(ID);
482 e_chanSetVol(chan, Volume);
483 Result := chan;
484 end;
486 function e_PlaySoundPanVolume(ID: DWORD; Pan, Volume: Single): Integer;
487 var
488 chan: Integer;
489 begin
490 Result := -1;
491 chan := e_PlaySound(ID);
492 e_chanSetPan(chan, Pan);
493 e_chanSetVol(chan, Volume);
494 Result := chan;
495 end;
497 procedure e_DeleteSound(ID: DWORD);
498 var
499 i: Integer;
500 begin
501 if ID > High(e_SoundsArray) then Exit;
502 if (e_SoundsArray[ID].Sound = nil) and (e_SoundsArray[ID].Music = nil) then Exit;
504 for i := 0 to N_CHANNELS-1 do
505 begin
506 if ChanSIds[i].id = ID then
507 begin
508 ChanSIds[i].id := NO_SOUND_ID;
509 Mix_HaltChannel(i);
510 end;
511 end;
513 if e_SoundsArray[ID].Sound <> nil then Mix_FreeChunk(e_SoundsArray[ID].Sound);
514 if e_SoundsArray[ID].Music <> nil then Mix_FreeMusic(e_SoundsArray[ID].Music);
515 if e_SoundsArray[ID].Data <> nil then FreeMem(e_SoundsArray[ID].Data);
517 e_SoundsArray[ID].Sound := nil;
518 e_SoundsArray[ID].Music := nil;
519 e_SoundsArray[ID].Data := nil;
520 e_SoundsArray[ID].nRefs := 0;
521 end;
523 procedure e_ModifyChannelsVolumes(SoundMod: Single; setMode: Boolean);
524 var
525 i: Integer;
526 vol: Single;
527 ovol: Integer;
528 begin
529 for i := 0 to N_CHANNELS-1 do
530 begin
531 ovol := ChanSIds[i].oldvol;
532 if setMode then
533 begin
534 vol := SoundMod;
535 end
536 else
537 begin
538 vol := (MIX_MAX_VOLUME+0.0)/ovol;
539 vol := vol*SoundMod;
540 end;
541 if vol < 0 then vol := 0 else if vol > 1 then vol := 1;
542 ChanSIds[i].oldvol := trunc(vol*MIX_MAX_VOLUME);
543 //if i = 0 then e_WriteLog(Format('modifying volumes: vol=%f; newvol=%d', [vol, ChanSIds[i].oldvol]), MSG_WARNING);
544 if ChanSIds[i].muted then Mix_Volume(i, 0) else Mix_Volume(i, ChanSIds[i].oldvol);
545 end;
546 ovol := Mix_VolumeMusic(-1);
547 if ovol >= 0 then
548 begin
549 if setMode then
550 begin
551 vol := SoundMod;
552 end
553 else
554 begin
555 vol := (MIX_MAX_VOLUME+0.0)/ovol;
556 vol := vol * SoundMod;
557 end;
558 if vol < 0 then vol := 0 else if vol > 1 then vol := 1;
559 MusVolume := trunc(vol*MIX_MAX_VOLUME);
560 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
561 end;
562 end;
564 procedure e_MuteChannels(Enable: Boolean);
565 var
566 i: Integer;
567 begin
568 //if Enable = SoundMuted then Exit;
569 SoundMuted := Enable;
570 for i := 0 to N_CHANNELS-1 do
571 begin
572 if ChanSIds[i].muted <> SoundMuted then
573 begin
574 ChanSIds[i].muted := SoundMuted;
575 //e_WriteLog(Format('gmuting sound for channel %d', [i]), MSG_WARNING);
576 if ChanSIds[i].muted then Mix_Volume(i, 0) else Mix_Volume(i, ChanSIds[i].oldvol);
577 end;
578 end;
579 //if SoundMuted then e_WriteLog('muting music', MSG_NOTIFY) else e_WriteLog(Format('unmuting music (%d)', [MusVolume]), MSG_NOTIFY);
580 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
581 end;
583 procedure e_StopChannels();
584 var
585 i: Integer;
586 begin
587 Mix_HaltChannel(-1);
588 Mix_HaltMusic();
589 for i := 0 to High(e_SoundsArray) do e_SoundsArray[i].nRefs := 0;
590 for i := 0 to N_CHANNELS-1 do ChanSIds[i].id := NO_SOUND_ID;
591 end;
593 procedure e_RemoveAllSounds();
594 var
595 i: Integer;
596 begin
597 if SoundInitialized then e_StopChannels();
598 for i := 0 to High(e_SoundsArray) do e_DeleteSound(i);
599 SetLength(e_SoundsArray, 0);
600 e_SoundsArray := nil;
601 end;
603 procedure e_ReleaseSoundSystem();
604 begin
605 e_RemoveAllSounds();
606 if SoundInitialized then
607 begin
608 Mix_CloseAudio();
609 SoundInitialized := False;
610 end;
611 end;
613 procedure e_SoundUpdate();
614 begin
615 //FMOD_System_Update(F_System);
616 end;
619 { TBasicSound: }
621 constructor TBasicSound.Create();
622 begin
623 FID := NO_SOUND_ID;
624 FMusic := False;
625 FChanNum := -1;
626 FPosition := 0;
627 FPriority := 128;
628 end;
630 destructor TBasicSound.Destroy();
631 begin
632 FreeSound();
633 inherited;
634 end;
636 function TBasicSound.GetChan (): Integer;
637 begin
638 if (FID <> NO_SOUND_ID) and (FChanNum >= 0) and (FChanNum < N_CHANNELS) then
639 begin
640 if ChanSIds[FChanNum].id <> FID then FChanNum := -1;
641 end
642 else if e_isMusic(FID) then
643 begin
644 FChanNum := N_MUSCHAN;
645 end;
646 Result := FChanNum;
647 end;
649 procedure TBasicSound.FreeSound();
650 begin
651 if FID = NO_SOUND_ID then Exit;
652 Stop();
653 FID := NO_SOUND_ID;
654 FMusic := False;
655 FPosition := 0;
656 FChanNum := -1;
657 end;
659 // aPos: msecs
660 function TBasicSound.RawPlay(Pan: Single; Volume: Single; aPos: DWORD): Boolean;
661 begin
662 Result := False;
663 if (FID = NO_SOUND_ID) or not SoundInitialized then Exit;
664 FChanNum := e_PlaySoundPanVolume(FID, Pan, Volume);
665 Result := (FChanNum >= 0);
666 //if e_isMusic(FID) then e_WriteLog(Format('playing music (%u)', [FID]), MSG_NOTIFY);
667 //TODO: aPos
668 end;
670 procedure TBasicSound.SetID(ID: DWORD);
671 begin
672 FreeSound();
673 FID := ID;
674 if ID <> NO_SOUND_ID then
675 begin
676 FMusic := e_SoundsArray[ID].isMusic;
677 end;
678 FChanNum := -1;
679 end;
681 function TBasicSound.IsPlaying(): Boolean;
682 var
683 chan: Integer;
684 begin
685 Result := False;
686 if e_isSound(FID) then
687 begin
688 //e_WriteLog(Format('IsPlaying: FID=%u; FChanNum=%d', [FID, FChanNum]), MSG_WARNING);
689 chan := Channel;
690 if chan < 0 then
691 begin
692 //e_WriteLog(Format('IsPlaying: FID=%u; ONA', [FID]), MSG_WARNING);
693 Exit;
694 end;
695 //Result := (Mix_Playing(chan) > 0)
696 //e_WriteLog(Format('IsPlaying: FID=%u; TAN', [FID]), MSG_WARNING);
697 Result := True;
698 end
699 else if e_isMusic(FID) then
700 begin
701 Result := (Mix_PlayingMusic() > 0);
702 end;
703 end;
705 procedure TBasicSound.Stop();
706 var
707 chan: Integer;
708 begin
709 if e_isSound(FID) then
710 begin
711 chan := Channel;
712 if chan >= 0 then
713 begin
714 //GetPosition();
715 Mix_HaltChannel(chan);
716 end;
717 end
718 else if e_isMusic(FID) then
719 begin
720 Mix_HaltMusic();
721 end;
722 FChanNum := -1;
723 end;
725 function TBasicSound.IsPaused(): Boolean;
726 var
727 chan: Integer;
728 begin
729 Result := False;
730 if e_isSound(FID) then
731 begin
732 chan := Channel;
733 if chan < 0 then Exit;
734 Result := (Mix_Paused(chan) > 0);
735 end
736 else if e_isMusic(FID) then
737 begin
738 Result := (Mix_PausedMusic() > 0);
739 end;
740 end;
742 procedure TBasicSound.Pause(Enable: Boolean);
743 var
744 chan: Integer;
745 pl: Boolean;
746 begin
747 Enable := not Enable; // fuckin' double negation
748 if e_isSound(FID) then
749 begin
750 chan := Channel;
751 if chan < 0 then Exit;
752 pl := not (Mix_Paused(chan) > 0);
753 if pl <> Enable then
754 begin
755 if Enable then Mix_Resume(chan) else Mix_Pause(chan);
756 end;
757 end
758 else if e_isMusic(FID) then
759 begin
760 pl := not (Mix_PausedMusic() > 0);
761 if pl <> Enable then
762 begin
763 if Enable then Mix_ResumeMusic() else Mix_PauseMusic();
764 end;
765 end;
767 if Enable then
768 begin
769 res := FMOD_Channel_GetPosition(FChanNum, FPosition, FMOD_TIMEUNIT_MS);
770 if res <> FMOD_OK then
771 begin
772 end;
773 end;
775 end;
777 function TBasicSound.GetVolume(): Single;
778 var
779 chan: Integer;
780 begin
781 Result := 0.0;
782 if e_isSound(FID) then
783 begin
784 chan := Channel;
785 if chan < 0 then Exit;
786 Result := (ChanSIds[chan].oldvol+0.0)/(MIX_MAX_VOLUME+0.0);
787 end
788 else if e_isMusic(FID) then
789 begin
790 Result := (MusVolume+0.0)/(MIX_MAX_VOLUME+0.0);
791 end;
792 end;
794 procedure TBasicSound.SetVolume(Volume: Single);
795 var
796 chan: Integer;
797 begin
798 if e_isSound(FID) then
799 begin
800 chan := Channel;
801 if chan < 0 then Exit;
802 //e_WriteLog(Format('SetVolume: chan=%d; Volume=%f', [chan, Volume]), MSG_WARNING);
803 e_chanSetVol(chan, Volume);
804 end
805 else if e_isMusic(FID) then
806 begin
807 //e_WriteLog(Format('SetVolume: chan=MUSIC; Volume=%f', [Volume]), MSG_WARNING);
808 e_chanSetVol(N_MUSCHAN, Volume);
809 end;
810 end;
812 function TBasicSound.GetPan(): Single;
813 var
814 chan: Integer;
815 begin
816 Result := 1.0;
817 if e_isSound(FID) then
818 begin
819 chan := Channel;
820 if chan < 0 then Exit;
821 Result := ChanSIds[chan].pan;
822 end;
823 end;
825 procedure TBasicSound.SetPan(Pan: Single);
826 var
827 chan: Integer;
828 begin
829 if e_isSound(FID) then
830 begin
831 chan := Channel;
832 if chan < 0 then Exit;
833 e_chanSetPan(chan, Pan);
834 end;
835 end;
837 function TBasicSound.IsMuted(): Boolean;
838 var
839 chan: Integer;
840 begin
841 Result := False;
842 if e_isSound(FID) then
843 begin
844 chan := Channel;
845 if chan < 0 then Exit;
846 Result := ChanSIds[chan].muted;
847 end
848 else if e_isMusic(FID) then
849 begin
850 Result := SoundMuted;
851 end;
852 end;
854 procedure TBasicSound.Mute(Enable: Boolean);
855 var
856 chan: Integer;
857 begin
858 if e_isSound(FID) then
859 begin
860 chan := Channel;
861 if chan < 0 then Exit;
862 if ChanSIds[chan].muted <> Enable then
863 begin
864 //e_WriteLog(Format('muting sound for channel %d', [cnan]), MSG_WARNING);
865 ChanSIds[chan].muted := Enable;
866 if ChanSIds[chan].muted then Mix_Volume(chan, 0) else Mix_Volume(chan, ChanSIds[chan].oldvol);
867 end;
868 end
869 else if e_isMusic(FID) then
870 begin
871 if Enable then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
872 end;
873 end;
875 //TODO
876 function TBasicSound.GetPosition(): DWORD;
877 begin
878 Result := 0;
880 if FChanNum < 0 then Exit;
881 res := FMOD_Channel_GetPosition(FChanNum, FPosition, FMOD_TIMEUNIT_MS);
882 if res <> FMOD_OK then
883 begin
884 Exit;
885 end;
886 Result := FPosition;
888 end;
890 //TODO
891 procedure TBasicSound.SetPosition(aPos: DWORD);
892 begin
893 FPosition := aPos;
895 if FChanNum < 0 then Exit;
896 res := FMOD_Channel_SetPosition(FChanNum, FPosition, FMOD_TIMEUNIT_MS);
897 if res <> FMOD_OK then
898 begin
899 end;
901 end;
903 //TODO
904 procedure TBasicSound.SetPriority(priority: Integer);
905 begin
907 if (FChanNum <> nil) and (FPriority <> priority) and
908 (priority >= 0) and (priority <= 256) then
909 begin
910 FPriority := priority;
911 res := FMOD_Channel_SetPriority(FChanNum, priority);
912 if res <> FMOD_OK then
913 begin
914 end;
915 end;
917 end;
919 end.