DEADSOFTWARE

sdlmixer: added hidden config options to setup sampling rate and buffer size
[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 rfreq: Integer;
159 rformat: UInt16;
160 rchans: Integer;
161 begin
162 if SoundInitialized then begin Result := true; Exit end;
164 Result := False;
165 SoundInitialized := False;
167 // wow, this is actually MIDI player!
168 // we need module player
169 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);
170 e_WriteLog(Format('SDL: res=0x%x', [res]), MSG_NOTIFY);
171 if (res and MIX_INIT_FLAC) <> 0 then e_WriteLog('SDL: FLAC playback is active', MSG_NOTIFY);
172 if (res and MIX_INIT_MOD) <> 0 then e_WriteLog('SDL: MOD playback is active', MSG_NOTIFY);
173 if (res and MIX_INIT_MODPLUG) <> 0 then e_WriteLog('SDL: MODPLUG playback is active', MSG_NOTIFY);
174 if (res and MIX_INIT_MP3) <> 0 then e_WriteLog('SDL: MP3 playback is active', MSG_NOTIFY);
175 if (res and MIX_INIT_OGG) <> 0 then e_WriteLog('SDL: OGG playback is active', MSG_NOTIFY);
176 if (res and MIX_INIT_FLUIDSYNTH) <> 0 then e_WriteLog('SDL: FLUIDSYNTH playback is active', MSG_NOTIFY);
178 e_WriteLog(Format('SDL: initializing mixer at %d with buffer %d', [gsSDLSampleRate, gsSDLBufferSize]), MSG_NOTIFY);
179 res := Mix_OpenAudio(gsSDLSampleRate, AUDIO_S16LSB, 2, gsSDLBufferSize);
180 if res = -1 then
181 begin
182 e_WriteLog('Error initializing SDL mixer:', MSG_FATALERROR);
183 e_WriteLog(Mix_GetError(), MSG_FATALERROR);
184 Exit;
185 end;
187 if Mix_QuerySpec(@rfreq, @rformat, @rchans) > 0 then
188 begin
189 e_WriteLog(Format('SDL: frequency=%d; format=%u; channels=%d', [rfreq, rformat, rchans]), MSG_NOTIFY);
190 end;
192 for i := 0 to Mix_GetNumChunkDecoders()-1 do
193 begin
194 e_WriteLog(Format('SDL: chunk decoder %s is avalable', [Mix_GetChunkDecoder(i)]), MSG_NOTIFY);
195 end;
196 for i := 0 to Mix_GetNumMusicDecoders()-1 do
197 begin
198 e_WriteLog(Format('SDL: music decoder %s is avalable', [Mix_GetMusicDecoder(i)]), MSG_NOTIFY);
199 end;
201 Mix_AllocateChannels(N_CHANNELS);
202 Mix_ChannelFinished(chanFinished);
204 for i := 0 to N_CHANNELS-1 do
205 begin
206 ChanSIds[i].id := NO_SOUND_ID;
207 ChanSIds[i].muted := SoundMuted;
208 ChanSIds[i].oldvol := MIX_MAX_VOLUME;
209 ChanSIds[i].pan := 1.0;
210 end;
211 MusVolume := MIX_MAX_VOLUME;
213 SoundInitialized := True;
214 Result := True;
215 end;
217 function e_isMusic (id: DWORD): Boolean;
218 begin
219 Result := False;
220 if (e_SoundsArray <> nil) and (id <= High(e_SoundsArray)) then
221 begin
222 Result := (e_SoundsArray[id].Music <> nil);
223 end;
224 end;
226 function e_isSound (id: DWORD): Boolean;
227 begin
228 Result := False;
229 if (e_SoundsArray <> nil) and (id <= High(e_SoundsArray)) then
230 begin
231 Result := (e_SoundsArray[id].Sound <> nil);
232 end;
233 end;
235 function FindESound(): DWORD;
236 var
237 i: Integer;
238 begin
239 if e_SoundsArray <> nil then
240 begin
241 for i := 0 to High(e_SoundsArray) do
242 if (e_SoundsArray[i].Sound = nil) and (e_SoundsArray[i].Music = nil) then
243 begin
244 Result := i;
245 Exit;
246 end;
247 end;
248 if e_SoundsArray = nil then
249 begin
250 SetLength(e_SoundsArray, 16);
251 Result := 0;
252 end
253 else
254 begin
255 Result := High(e_SoundsArray) + 1;
256 SetLength(e_SoundsArray, Length(e_SoundsArray) + 16);
257 end;
258 for i := Result to High(e_SoundsArray) do
259 begin
260 e_SoundsArray[i].Sound := nil;
261 e_SoundsArray[i].Music := nil;
262 e_SoundsArray[i].Data := nil;
263 e_SoundsArray[i].isMusic := False;
264 e_SoundsArray[i].nRefs := 0;
265 end;
266 end;
268 function e_LoadSound(FileName: String; var ID: DWORD; isMusic: Boolean): Boolean;
269 var
270 find_id: DWORD;
271 begin
272 ID := NO_SOUND_ID;
273 Result := False;
274 if not SoundInitialized then Exit;
276 if isMusic then e_WriteLog('Loading music '+FileName+'...', MSG_NOTIFY)
277 else e_WriteLog('Loading sound '+FileName+'...', MSG_NOTIFY);
280 if isMusic then
281 begin
282 e_WriteLog('IGNORING MUSIC FROM FILE', MSG_WARNING);
283 Exit;
284 end;
287 find_id := FindESound();
289 e_SoundsArray[find_id].Data := nil;
290 e_SoundsArray[find_id].isMusic := isMusic;
291 e_SoundsArray[find_id].nRefs := 0;
293 if isMusic then
294 begin
295 e_WriteLog(Format(' MUSIC SLOT: %u', [find_id]), MSG_NOTIFY);
296 e_SoundsArray[find_id].Music := Mix_LoadMUS(PAnsiChar(FileName));
297 if e_SoundsArray[find_id].Music = nil then
298 begin
299 e_WriteLog(Format('ERROR LOADING MUSIC:', [find_id]), MSG_WARNING);
300 e_WriteLog(Mix_GetError(), MSG_WARNING);
301 Exit;
302 end;
303 dumpMusicType(e_SoundsArray[find_id].Music);
304 end
305 else
306 begin
307 e_SoundsArray[find_id].Sound := Mix_LoadWAV(PAnsiChar(FileName));
308 if e_SoundsArray[find_id].Sound = nil then Exit;
309 end;
311 ID := find_id;
313 Result := True;
314 end;
316 function e_LoadSoundMem(pData: Pointer; Length: Integer; var ID: DWORD; isMusic: Boolean): Boolean;
317 var
318 find_id: DWORD;
319 rw: PSDL_RWops;
320 //pc: PChar;
321 isid3: Boolean;
322 begin
323 ID := NO_SOUND_ID;
324 Result := False;
325 if not SoundInitialized then Exit;
326 isid3 := False;
329 if isMusic then
330 begin
331 e_WriteLog('IGNORING MUSIC FROM MEMORY', MSG_WARNING);
332 Exit;
333 end;
336 //FIXME: correctly skip ID3
338 pc := PChar(pData);
339 if (Length > $400) and (pc[0] = 'I') and (pc[1] = 'D') and (pc[2] = '3') then
340 begin
341 isid3 := True;
342 Inc(pc, $400);
343 pData := Pointer(pc);
344 Dec(Length, $400);
345 e_WriteLog('MUSIC: MP3 ID3 WORKAROUND APPLIED!', MSG_WARNING);
346 end;
349 rw := SDL_RWFromConstMem(pData, Length);
350 if rw = nil then Exit;
352 find_id := FindESound();
354 e_SoundsArray[find_id].Data := pData;
355 if isid3 then e_SoundsArray[find_id].Data := nil;
356 e_SoundsArray[find_id].isMusic := isMusic;
357 e_SoundsArray[find_id].nRefs := 0;
359 if isMusic then
360 begin
361 e_WriteLog(Format(' MUSIC SLOT: %u', [find_id]), MSG_NOTIFY);
362 e_SoundsArray[find_id].Music := Mix_LoadMUS_RW(rw, 0);
363 if e_SoundsArray[find_id].Music = nil then
364 begin
365 e_WriteLog(Format('ERROR LOADING MUSIC:', [find_id]), MSG_WARNING);
366 e_WriteLog(Mix_GetError(), MSG_WARNING);
367 end
368 else
369 begin
370 dumpMusicType(e_SoundsArray[find_id].Music);
371 end;
372 //SDL_FreeRW(rw);
374 if e_SoundsArray[find_id].Music <> nil then
375 begin
376 Mix_FreeMusic(e_SoundsArray[find_id].Music);
377 end;
378 e_SoundsArray[find_id].Music := nil;
379 Exit;
381 end
382 else
383 begin
384 e_SoundsArray[find_id].Sound := Mix_LoadWAV_RW(rw, 0);
385 end;
386 //SDL_FreeRW(rw); // somehow it segfaults...
387 if (e_SoundsArray[find_id].Sound = nil) and (e_SoundsArray[find_id].Music = nil) then
388 begin
389 e_SoundsArray[find_id].Data := nil;
390 Exit;
391 end;
393 ID := find_id;
395 Result := True;
396 end;
398 function e_PlaySound (ID: DWORD): Integer;
399 var
400 res: Integer = -1;
401 begin
402 Result := -1;
403 if not SoundInitialized then Exit;
405 if e_isSound(ID) then
406 begin
407 if e_SoundsArray[ID].nRefs >= gMaxSimSounds then Exit;
408 Inc(e_SoundsArray[ID].nRefs);
409 res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, 0);
410 if res >= 0 then
411 begin
412 ChanSIds[res].id := ID;
413 ChanSIds[res].muted := SoundMuted;
414 if SoundMuted then Mix_Volume(res, 0) else Mix_Volume(res, ChanSIds[res].oldvol);
416 if e_SoundsArray[ID].isMusic then
417 res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, -1)
418 else
419 res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, 0);
421 end;
422 end
423 else
424 begin
425 if not e_isMusic(ID) then Exit;
426 Mix_HaltMusic();
427 res := Mix_PlayMusic(e_SoundsArray[ID].Music, -1);
428 if res >= 0 then res := N_MUSCHAN;
429 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
430 Result := res;
431 end;
433 Result := res;
434 end;
436 function e_chanSetPan (chan: Integer; Pan: Single): Boolean;
437 var
438 l, r: UInt8;
439 begin
440 Result := True;
441 if chan = N_MUSCHAN then
442 begin
443 // no panning for music
444 end
445 else if chan >= 0 then
446 begin
447 if Pan < -1.0 then Pan := -1.0 else if Pan > 1.0 then Pan := 1.0;
448 Pan := Pan+1.0; // 0..2
449 l := trunc(127.0*(2.0-Pan));
450 r := trunc(127.0*Pan);
451 Mix_SetPanning(chan, l, r);
452 ChanSIds[chan].pan := Pan;
453 end
454 else
455 begin
456 Result := False;
457 end;
458 end;
460 function e_chanSetVol (chan: Integer; Volume: Single): Boolean;
461 var
462 vol: Integer;
463 begin
464 Result := True;
465 if Volume < 0 then Volume := 0 else if Volume > 1 then Volume := 1;
466 vol := trunc(Volume*MIX_MAX_VOLUME);
467 if chan = N_MUSCHAN then
468 begin
469 MusVolume := vol;
470 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(vol);
471 end
472 else if chan >= 0 then
473 begin
474 ChanSIds[chan].oldvol := vol;
475 if ChanSIds[chan].muted then Mix_Volume(chan, 0) else Mix_Volume(chan, vol);
476 end
477 else
478 begin
479 Result := False;
480 end;
481 end;
483 function e_PlaySoundPan(ID: DWORD; Pan: Single): Integer;
484 var
485 chan: Integer;
486 begin
487 Result := -1;
488 chan := e_PlaySound(ID);
489 e_chanSetPan(chan, Pan);
490 Result := chan;
491 end;
493 function e_PlaySoundVolume(ID: DWORD; Volume: Single): Integer;
494 var
495 chan: Integer;
496 begin
497 Result := -1;
498 chan := e_PlaySound(ID);
499 e_chanSetVol(chan, Volume);
500 Result := chan;
501 end;
503 function e_PlaySoundPanVolume(ID: DWORD; Pan, Volume: Single): Integer;
504 var
505 chan: Integer;
506 begin
507 Result := -1;
508 chan := e_PlaySound(ID);
509 e_chanSetPan(chan, Pan);
510 e_chanSetVol(chan, Volume);
511 Result := chan;
512 end;
514 procedure e_DeleteSound(ID: DWORD);
515 var
516 i: Integer;
517 begin
518 if ID > High(e_SoundsArray) then Exit;
519 if (e_SoundsArray[ID].Sound = nil) and (e_SoundsArray[ID].Music = nil) then Exit;
521 for i := 0 to N_CHANNELS-1 do
522 begin
523 if ChanSIds[i].id = ID then
524 begin
525 ChanSIds[i].id := NO_SOUND_ID;
526 Mix_HaltChannel(i);
527 end;
528 end;
530 if e_SoundsArray[ID].Sound <> nil then Mix_FreeChunk(e_SoundsArray[ID].Sound);
531 if e_SoundsArray[ID].Music <> nil then Mix_FreeMusic(e_SoundsArray[ID].Music);
532 if e_SoundsArray[ID].Data <> nil then FreeMem(e_SoundsArray[ID].Data);
534 e_SoundsArray[ID].Sound := nil;
535 e_SoundsArray[ID].Music := nil;
536 e_SoundsArray[ID].Data := nil;
537 e_SoundsArray[ID].nRefs := 0;
538 end;
540 procedure e_ModifyChannelsVolumes(SoundMod: Single; setMode: Boolean);
541 var
542 i: Integer;
543 vol: Single;
544 ovol: Integer;
545 begin
546 for i := 0 to N_CHANNELS-1 do
547 begin
548 ovol := ChanSIds[i].oldvol;
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 ChanSIds[i].oldvol := trunc(vol*MIX_MAX_VOLUME);
560 //if i = 0 then e_WriteLog(Format('modifying volumes: vol=%f; newvol=%d', [vol, ChanSIds[i].oldvol]), MSG_WARNING);
561 if ChanSIds[i].muted then Mix_Volume(i, 0) else Mix_Volume(i, ChanSIds[i].oldvol);
562 end;
563 ovol := Mix_VolumeMusic(-1);
564 if ovol >= 0 then
565 begin
566 if setMode then
567 begin
568 vol := SoundMod;
569 end
570 else
571 begin
572 vol := (MIX_MAX_VOLUME+0.0)/ovol;
573 vol := vol * SoundMod;
574 end;
575 if vol < 0 then vol := 0 else if vol > 1 then vol := 1;
576 MusVolume := trunc(vol*MIX_MAX_VOLUME);
577 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
578 end;
579 end;
581 procedure e_MuteChannels(Enable: Boolean);
582 var
583 i: Integer;
584 begin
585 //if Enable = SoundMuted then Exit;
586 SoundMuted := Enable;
587 for i := 0 to N_CHANNELS-1 do
588 begin
589 if ChanSIds[i].muted <> SoundMuted then
590 begin
591 ChanSIds[i].muted := SoundMuted;
592 //e_WriteLog(Format('gmuting sound for channel %d', [i]), MSG_WARNING);
593 if ChanSIds[i].muted then Mix_Volume(i, 0) else Mix_Volume(i, ChanSIds[i].oldvol);
594 end;
595 end;
596 //if SoundMuted then e_WriteLog('muting music', MSG_NOTIFY) else e_WriteLog(Format('unmuting music (%d)', [MusVolume]), MSG_NOTIFY);
597 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
598 end;
600 procedure e_StopChannels();
601 var
602 i: Integer;
603 begin
604 Mix_HaltChannel(-1);
605 Mix_HaltMusic();
606 for i := 0 to High(e_SoundsArray) do e_SoundsArray[i].nRefs := 0;
607 for i := 0 to N_CHANNELS-1 do ChanSIds[i].id := NO_SOUND_ID;
608 end;
610 procedure e_RemoveAllSounds();
611 var
612 i: Integer;
613 begin
614 if SoundInitialized then e_StopChannels();
615 for i := 0 to High(e_SoundsArray) do e_DeleteSound(i);
616 SetLength(e_SoundsArray, 0);
617 e_SoundsArray := nil;
618 end;
620 procedure e_ReleaseSoundSystem();
621 begin
622 e_RemoveAllSounds();
623 if SoundInitialized then
624 begin
625 Mix_CloseAudio();
626 SoundInitialized := False;
627 end;
628 end;
630 procedure e_SoundUpdate();
631 begin
632 //FMOD_System_Update(F_System);
633 end;
636 { TBasicSound: }
638 constructor TBasicSound.Create();
639 begin
640 FID := NO_SOUND_ID;
641 FMusic := False;
642 FChanNum := -1;
643 FPosition := 0;
644 FPriority := 128;
645 end;
647 destructor TBasicSound.Destroy();
648 begin
649 FreeSound();
650 inherited;
651 end;
653 function TBasicSound.GetChan (): Integer;
654 begin
655 if (FID <> NO_SOUND_ID) and (FChanNum >= 0) and (FChanNum < N_CHANNELS) then
656 begin
657 if ChanSIds[FChanNum].id <> FID then FChanNum := -1;
658 end
659 else if e_isMusic(FID) then
660 begin
661 FChanNum := N_MUSCHAN;
662 end;
663 Result := FChanNum;
664 end;
666 procedure TBasicSound.FreeSound();
667 begin
668 if FID = NO_SOUND_ID then Exit;
669 Stop();
670 FID := NO_SOUND_ID;
671 FMusic := False;
672 FPosition := 0;
673 FChanNum := -1;
674 end;
676 // aPos: msecs
677 function TBasicSound.RawPlay(Pan: Single; Volume: Single; aPos: DWORD): Boolean;
678 begin
679 Result := False;
680 if (FID = NO_SOUND_ID) or not SoundInitialized then Exit;
681 FChanNum := e_PlaySoundPanVolume(FID, Pan, Volume);
682 Result := (FChanNum >= 0);
683 //if e_isMusic(FID) then e_WriteLog(Format('playing music (%u)', [FID]), MSG_NOTIFY);
684 //TODO: aPos
685 end;
687 procedure TBasicSound.SetID(ID: DWORD);
688 begin
689 FreeSound();
690 FID := ID;
691 if ID <> NO_SOUND_ID then
692 begin
693 FMusic := e_SoundsArray[ID].isMusic;
694 end;
695 FChanNum := -1;
696 end;
698 function TBasicSound.IsPlaying(): Boolean;
699 var
700 chan: Integer;
701 begin
702 Result := False;
703 if e_isSound(FID) then
704 begin
705 //e_WriteLog(Format('IsPlaying: FID=%u; FChanNum=%d', [FID, FChanNum]), MSG_WARNING);
706 chan := Channel;
707 if chan < 0 then
708 begin
709 //e_WriteLog(Format('IsPlaying: FID=%u; ONA', [FID]), MSG_WARNING);
710 Exit;
711 end;
712 //Result := (Mix_Playing(chan) > 0)
713 //e_WriteLog(Format('IsPlaying: FID=%u; TAN', [FID]), MSG_WARNING);
714 Result := True;
715 end
716 else if e_isMusic(FID) then
717 begin
718 Result := (Mix_PlayingMusic() > 0);
719 end;
720 end;
722 procedure TBasicSound.Stop();
723 var
724 chan: Integer;
725 begin
726 if e_isSound(FID) then
727 begin
728 chan := Channel;
729 if chan >= 0 then
730 begin
731 //GetPosition();
732 Mix_HaltChannel(chan);
733 end;
734 end
735 else if e_isMusic(FID) then
736 begin
737 Mix_HaltMusic();
738 end;
739 FChanNum := -1;
740 end;
742 function TBasicSound.IsPaused(): Boolean;
743 var
744 chan: Integer;
745 begin
746 Result := False;
747 if e_isSound(FID) then
748 begin
749 chan := Channel;
750 if chan < 0 then Exit;
751 Result := (Mix_Paused(chan) > 0);
752 end
753 else if e_isMusic(FID) then
754 begin
755 Result := (Mix_PausedMusic() > 0);
756 end;
757 end;
759 procedure TBasicSound.Pause(Enable: Boolean);
760 var
761 chan: Integer;
762 pl: Boolean;
763 begin
764 Enable := not Enable; // fuckin' double negation
765 if e_isSound(FID) then
766 begin
767 chan := Channel;
768 if chan < 0 then Exit;
769 pl := not (Mix_Paused(chan) > 0);
770 if pl <> Enable then
771 begin
772 if Enable then Mix_Resume(chan) else Mix_Pause(chan);
773 end;
774 end
775 else if e_isMusic(FID) then
776 begin
777 pl := not (Mix_PausedMusic() > 0);
778 if pl <> Enable then
779 begin
780 if Enable then Mix_ResumeMusic() else Mix_PauseMusic();
781 end;
782 end;
784 if Enable then
785 begin
786 res := FMOD_Channel_GetPosition(FChanNum, FPosition, FMOD_TIMEUNIT_MS);
787 if res <> FMOD_OK then
788 begin
789 end;
790 end;
792 end;
794 function TBasicSound.GetVolume(): Single;
795 var
796 chan: Integer;
797 begin
798 Result := 0.0;
799 if e_isSound(FID) then
800 begin
801 chan := Channel;
802 if chan < 0 then Exit;
803 Result := (ChanSIds[chan].oldvol+0.0)/(MIX_MAX_VOLUME+0.0);
804 end
805 else if e_isMusic(FID) then
806 begin
807 Result := (MusVolume+0.0)/(MIX_MAX_VOLUME+0.0);
808 end;
809 end;
811 procedure TBasicSound.SetVolume(Volume: Single);
812 var
813 chan: Integer;
814 begin
815 if e_isSound(FID) then
816 begin
817 chan := Channel;
818 if chan < 0 then Exit;
819 //e_WriteLog(Format('SetVolume: chan=%d; Volume=%f', [chan, Volume]), MSG_WARNING);
820 e_chanSetVol(chan, Volume);
821 end
822 else if e_isMusic(FID) then
823 begin
824 //e_WriteLog(Format('SetVolume: chan=MUSIC; Volume=%f', [Volume]), MSG_WARNING);
825 e_chanSetVol(N_MUSCHAN, Volume);
826 end;
827 end;
829 function TBasicSound.GetPan(): Single;
830 var
831 chan: Integer;
832 begin
833 Result := 1.0;
834 if e_isSound(FID) then
835 begin
836 chan := Channel;
837 if chan < 0 then Exit;
838 Result := ChanSIds[chan].pan;
839 end;
840 end;
842 procedure TBasicSound.SetPan(Pan: Single);
843 var
844 chan: Integer;
845 begin
846 if e_isSound(FID) then
847 begin
848 chan := Channel;
849 if chan < 0 then Exit;
850 e_chanSetPan(chan, Pan);
851 end;
852 end;
854 function TBasicSound.IsMuted(): Boolean;
855 var
856 chan: Integer;
857 begin
858 Result := False;
859 if e_isSound(FID) then
860 begin
861 chan := Channel;
862 if chan < 0 then Exit;
863 Result := ChanSIds[chan].muted;
864 end
865 else if e_isMusic(FID) then
866 begin
867 Result := SoundMuted;
868 end;
869 end;
871 procedure TBasicSound.Mute(Enable: Boolean);
872 var
873 chan: Integer;
874 begin
875 if e_isSound(FID) then
876 begin
877 chan := Channel;
878 if chan < 0 then Exit;
879 if ChanSIds[chan].muted <> Enable then
880 begin
881 //e_WriteLog(Format('muting sound for channel %d', [cnan]), MSG_WARNING);
882 ChanSIds[chan].muted := Enable;
883 if ChanSIds[chan].muted then Mix_Volume(chan, 0) else Mix_Volume(chan, ChanSIds[chan].oldvol);
884 end;
885 end
886 else if e_isMusic(FID) then
887 begin
888 if Enable then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
889 end;
890 end;
892 //TODO
893 function TBasicSound.GetPosition(): DWORD;
894 begin
895 Result := 0;
897 if FChanNum < 0 then Exit;
898 res := FMOD_Channel_GetPosition(FChanNum, FPosition, FMOD_TIMEUNIT_MS);
899 if res <> FMOD_OK then
900 begin
901 Exit;
902 end;
903 Result := FPosition;
905 end;
907 //TODO
908 procedure TBasicSound.SetPosition(aPos: DWORD);
909 begin
910 FPosition := aPos;
912 if FChanNum < 0 then Exit;
913 res := FMOD_Channel_SetPosition(FChanNum, FPosition, FMOD_TIMEUNIT_MS);
914 if res <> FMOD_OK then
915 begin
916 end;
918 end;
920 //TODO
921 procedure TBasicSound.SetPriority(priority: Integer);
922 begin
924 if (FChanNum <> nil) and (FPriority <> priority) and
925 (priority >= 0) and (priority <= 256) then
926 begin
927 FPriority := priority;
928 res := FMOD_Channel_SetPriority(FChanNum, priority);
929 if res <> FMOD_OK then
930 begin
931 end;
932 end;
934 end;
936 end.