DEADSOFTWARE

sdlmixer: use 44100, and let mixer decide
[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 res := Mix_OpenAudio(44100, AUDIO_S16LSB, 2, 2048);
179 if res = -1 then
180 begin
181 e_WriteLog('Error initializing SDL mixer:', MSG_FATALERROR);
182 e_WriteLog(Mix_GetError(), MSG_FATALERROR);
183 Exit;
184 end;
186 if Mix_QuerySpec(@rfreq, @rformat, @rchans) > 0 then
187 begin
188 e_WriteLog(Format('SDL: frequency=%d; format=%u; channels=%d', [rfreq, rformat, rchans]), MSG_NOTIFY);
189 end;
191 Mix_AllocateChannels(N_CHANNELS);
192 Mix_ChannelFinished(chanFinished);
194 for i := 0 to N_CHANNELS-1 do
195 begin
196 ChanSIds[i].id := NO_SOUND_ID;
197 ChanSIds[i].muted := SoundMuted;
198 ChanSIds[i].oldvol := MIX_MAX_VOLUME;
199 ChanSIds[i].pan := 1.0;
200 end;
201 MusVolume := MIX_MAX_VOLUME;
203 SoundInitialized := True;
204 Result := True;
205 end;
207 function e_isMusic (id: DWORD): Boolean;
208 begin
209 Result := False;
210 if (e_SoundsArray <> nil) and (id <= High(e_SoundsArray)) then
211 begin
212 Result := (e_SoundsArray[id].Music <> nil);
213 end;
214 end;
216 function e_isSound (id: DWORD): Boolean;
217 begin
218 Result := False;
219 if (e_SoundsArray <> nil) and (id <= High(e_SoundsArray)) then
220 begin
221 Result := (e_SoundsArray[id].Sound <> nil);
222 end;
223 end;
225 function FindESound(): DWORD;
226 var
227 i: Integer;
228 begin
229 if e_SoundsArray <> nil then
230 begin
231 for i := 0 to High(e_SoundsArray) do
232 if (e_SoundsArray[i].Sound = nil) and (e_SoundsArray[i].Music = nil) then
233 begin
234 Result := i;
235 Exit;
236 end;
237 end;
238 if e_SoundsArray = nil then
239 begin
240 SetLength(e_SoundsArray, 16);
241 Result := 0;
242 end
243 else
244 begin
245 Result := High(e_SoundsArray) + 1;
246 SetLength(e_SoundsArray, Length(e_SoundsArray) + 16);
247 end;
248 for i := Result to High(e_SoundsArray) do
249 begin
250 e_SoundsArray[i].Sound := nil;
251 e_SoundsArray[i].Music := nil;
252 e_SoundsArray[i].Data := nil;
253 e_SoundsArray[i].isMusic := False;
254 e_SoundsArray[i].nRefs := 0;
255 end;
256 end;
258 function e_LoadSound(FileName: String; var ID: DWORD; isMusic: Boolean): Boolean;
259 var
260 find_id: DWORD;
261 begin
262 ID := NO_SOUND_ID;
263 Result := False;
264 if not SoundInitialized then Exit;
266 if isMusic then e_WriteLog('Loading music '+FileName+'...', MSG_NOTIFY)
267 else e_WriteLog('Loading sound '+FileName+'...', MSG_NOTIFY);
270 if isMusic then
271 begin
272 e_WriteLog('IGNORING MUSIC FROM FILE', MSG_WARNING);
273 Exit;
274 end;
277 find_id := FindESound();
279 e_SoundsArray[find_id].Data := nil;
280 e_SoundsArray[find_id].isMusic := isMusic;
281 e_SoundsArray[find_id].nRefs := 0;
283 if isMusic then
284 begin
285 e_WriteLog(Format(' MUSIC SLOT: %u', [find_id]), MSG_NOTIFY);
286 e_SoundsArray[find_id].Music := Mix_LoadMUS(PAnsiChar(FileName));
287 if e_SoundsArray[find_id].Music = nil then
288 begin
289 e_WriteLog(Format('ERROR LOADING MUSIC:', [find_id]), MSG_WARNING);
290 e_WriteLog(Mix_GetError(), MSG_WARNING);
291 Exit;
292 end;
293 dumpMusicType(e_SoundsArray[find_id].Music);
294 end
295 else
296 begin
297 e_SoundsArray[find_id].Sound := Mix_LoadWAV(PAnsiChar(FileName));
298 if e_SoundsArray[find_id].Sound = nil then Exit;
299 end;
301 ID := find_id;
303 Result := True;
304 end;
306 function e_LoadSoundMem(pData: Pointer; Length: Integer; var ID: DWORD; isMusic: Boolean): Boolean;
307 var
308 find_id: DWORD;
309 rw: PSDL_RWops;
310 //pc: PChar;
311 isid3: Boolean;
312 begin
313 ID := NO_SOUND_ID;
314 Result := False;
315 if not SoundInitialized then Exit;
316 isid3 := False;
319 if isMusic then
320 begin
321 e_WriteLog('IGNORING MUSIC FROM MEMORY', MSG_WARNING);
322 Exit;
323 end;
326 //FIXME: correctly skip ID3
328 pc := PChar(pData);
329 if (Length > $400) and (pc[0] = 'I') and (pc[1] = 'D') and (pc[2] = '3') then
330 begin
331 isid3 := True;
332 Inc(pc, $400);
333 pData := Pointer(pc);
334 Dec(Length, $400);
335 e_WriteLog('MUSIC: MP3 ID3 WORKAROUND APPLIED!', MSG_WARNING);
336 end;
339 rw := SDL_RWFromConstMem(pData, Length);
340 if rw = nil then Exit;
342 find_id := FindESound();
344 e_SoundsArray[find_id].Data := pData;
345 if isid3 then e_SoundsArray[find_id].Data := nil;
346 e_SoundsArray[find_id].isMusic := isMusic;
347 e_SoundsArray[find_id].nRefs := 0;
349 if isMusic then
350 begin
351 e_WriteLog(Format(' MUSIC SLOT: %u', [find_id]), MSG_NOTIFY);
352 e_SoundsArray[find_id].Music := Mix_LoadMUS_RW(rw, 0);
353 if e_SoundsArray[find_id].Music = nil then
354 begin
355 e_WriteLog(Format('ERROR LOADING MUSIC:', [find_id]), MSG_WARNING);
356 e_WriteLog(Mix_GetError(), MSG_WARNING);
357 end
358 else
359 begin
360 dumpMusicType(e_SoundsArray[find_id].Music);
361 end;
362 //SDL_FreeRW(rw);
364 if e_SoundsArray[find_id].Music <> nil then
365 begin
366 Mix_FreeMusic(e_SoundsArray[find_id].Music);
367 end;
368 e_SoundsArray[find_id].Music := nil;
369 Exit;
371 end
372 else
373 begin
374 e_SoundsArray[find_id].Sound := Mix_LoadWAV_RW(rw, 0);
375 end;
376 //SDL_FreeRW(rw); // somehow it segfaults...
377 if (e_SoundsArray[find_id].Sound = nil) and (e_SoundsArray[find_id].Music = nil) then
378 begin
379 e_SoundsArray[find_id].Data := nil;
380 Exit;
381 end;
383 ID := find_id;
385 Result := True;
386 end;
388 function e_PlaySound (ID: DWORD): Integer;
389 var
390 res: Integer = -1;
391 begin
392 Result := -1;
393 if not SoundInitialized then Exit;
395 if e_isSound(ID) then
396 begin
397 if e_SoundsArray[ID].nRefs >= gMaxSimSounds then Exit;
398 Inc(e_SoundsArray[ID].nRefs);
399 res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, 0);
400 if res >= 0 then
401 begin
402 ChanSIds[res].id := ID;
403 ChanSIds[res].muted := SoundMuted;
404 if SoundMuted then Mix_Volume(res, 0) else Mix_Volume(res, ChanSIds[res].oldvol);
406 if e_SoundsArray[ID].isMusic then
407 res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, -1)
408 else
409 res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, 0);
411 end;
412 end
413 else
414 begin
415 if not e_isMusic(ID) then Exit;
416 Mix_HaltMusic();
417 res := Mix_PlayMusic(e_SoundsArray[ID].Music, -1);
418 if res >= 0 then res := N_MUSCHAN;
419 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
420 Result := res;
421 end;
423 Result := res;
424 end;
426 function e_chanSetPan (chan: Integer; Pan: Single): Boolean;
427 var
428 l, r: UInt8;
429 begin
430 Result := True;
431 if chan = N_MUSCHAN then
432 begin
433 // no panning for music
434 end
435 else if chan >= 0 then
436 begin
437 if Pan < -1.0 then Pan := -1.0 else if Pan > 1.0 then Pan := 1.0;
438 Pan := Pan+1.0; // 0..2
439 l := trunc(127.0*(2.0-Pan));
440 r := trunc(127.0*Pan);
441 Mix_SetPanning(chan, l, r);
442 ChanSIds[chan].pan := Pan;
443 end
444 else
445 begin
446 Result := False;
447 end;
448 end;
450 function e_chanSetVol (chan: Integer; Volume: Single): Boolean;
451 var
452 vol: Integer;
453 begin
454 Result := True;
455 if Volume < 0 then Volume := 0 else if Volume > 1 then Volume := 1;
456 vol := trunc(Volume*MIX_MAX_VOLUME);
457 if chan = N_MUSCHAN then
458 begin
459 MusVolume := vol;
460 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(vol);
461 end
462 else if chan >= 0 then
463 begin
464 ChanSIds[chan].oldvol := vol;
465 if ChanSIds[chan].muted then Mix_Volume(chan, 0) else Mix_Volume(chan, vol);
466 end
467 else
468 begin
469 Result := False;
470 end;
471 end;
473 function e_PlaySoundPan(ID: DWORD; Pan: Single): Integer;
474 var
475 chan: Integer;
476 begin
477 Result := -1;
478 chan := e_PlaySound(ID);
479 e_chanSetPan(chan, Pan);
480 Result := chan;
481 end;
483 function e_PlaySoundVolume(ID: DWORD; Volume: Single): Integer;
484 var
485 chan: Integer;
486 begin
487 Result := -1;
488 chan := e_PlaySound(ID);
489 e_chanSetVol(chan, Volume);
490 Result := chan;
491 end;
493 function e_PlaySoundPanVolume(ID: DWORD; Pan, Volume: Single): Integer;
494 var
495 chan: Integer;
496 begin
497 Result := -1;
498 chan := e_PlaySound(ID);
499 e_chanSetPan(chan, Pan);
500 e_chanSetVol(chan, Volume);
501 Result := chan;
502 end;
504 procedure e_DeleteSound(ID: DWORD);
505 var
506 i: Integer;
507 begin
508 if ID > High(e_SoundsArray) then Exit;
509 if (e_SoundsArray[ID].Sound = nil) and (e_SoundsArray[ID].Music = nil) then Exit;
511 for i := 0 to N_CHANNELS-1 do
512 begin
513 if ChanSIds[i].id = ID then
514 begin
515 ChanSIds[i].id := NO_SOUND_ID;
516 Mix_HaltChannel(i);
517 end;
518 end;
520 if e_SoundsArray[ID].Sound <> nil then Mix_FreeChunk(e_SoundsArray[ID].Sound);
521 if e_SoundsArray[ID].Music <> nil then Mix_FreeMusic(e_SoundsArray[ID].Music);
522 if e_SoundsArray[ID].Data <> nil then FreeMem(e_SoundsArray[ID].Data);
524 e_SoundsArray[ID].Sound := nil;
525 e_SoundsArray[ID].Music := nil;
526 e_SoundsArray[ID].Data := nil;
527 e_SoundsArray[ID].nRefs := 0;
528 end;
530 procedure e_ModifyChannelsVolumes(SoundMod: Single; setMode: Boolean);
531 var
532 i: Integer;
533 vol: Single;
534 ovol: Integer;
535 begin
536 for i := 0 to N_CHANNELS-1 do
537 begin
538 ovol := ChanSIds[i].oldvol;
539 if setMode then
540 begin
541 vol := SoundMod;
542 end
543 else
544 begin
545 vol := (MIX_MAX_VOLUME+0.0)/ovol;
546 vol := vol*SoundMod;
547 end;
548 if vol < 0 then vol := 0 else if vol > 1 then vol := 1;
549 ChanSIds[i].oldvol := trunc(vol*MIX_MAX_VOLUME);
550 //if i = 0 then e_WriteLog(Format('modifying volumes: vol=%f; newvol=%d', [vol, ChanSIds[i].oldvol]), MSG_WARNING);
551 if ChanSIds[i].muted then Mix_Volume(i, 0) else Mix_Volume(i, ChanSIds[i].oldvol);
552 end;
553 ovol := Mix_VolumeMusic(-1);
554 if ovol >= 0 then
555 begin
556 if setMode then
557 begin
558 vol := SoundMod;
559 end
560 else
561 begin
562 vol := (MIX_MAX_VOLUME+0.0)/ovol;
563 vol := vol * SoundMod;
564 end;
565 if vol < 0 then vol := 0 else if vol > 1 then vol := 1;
566 MusVolume := trunc(vol*MIX_MAX_VOLUME);
567 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
568 end;
569 end;
571 procedure e_MuteChannels(Enable: Boolean);
572 var
573 i: Integer;
574 begin
575 //if Enable = SoundMuted then Exit;
576 SoundMuted := Enable;
577 for i := 0 to N_CHANNELS-1 do
578 begin
579 if ChanSIds[i].muted <> SoundMuted then
580 begin
581 ChanSIds[i].muted := SoundMuted;
582 //e_WriteLog(Format('gmuting sound for channel %d', [i]), MSG_WARNING);
583 if ChanSIds[i].muted then Mix_Volume(i, 0) else Mix_Volume(i, ChanSIds[i].oldvol);
584 end;
585 end;
586 //if SoundMuted then e_WriteLog('muting music', MSG_NOTIFY) else e_WriteLog(Format('unmuting music (%d)', [MusVolume]), MSG_NOTIFY);
587 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
588 end;
590 procedure e_StopChannels();
591 var
592 i: Integer;
593 begin
594 Mix_HaltChannel(-1);
595 Mix_HaltMusic();
596 for i := 0 to High(e_SoundsArray) do e_SoundsArray[i].nRefs := 0;
597 for i := 0 to N_CHANNELS-1 do ChanSIds[i].id := NO_SOUND_ID;
598 end;
600 procedure e_RemoveAllSounds();
601 var
602 i: Integer;
603 begin
604 if SoundInitialized then e_StopChannels();
605 for i := 0 to High(e_SoundsArray) do e_DeleteSound(i);
606 SetLength(e_SoundsArray, 0);
607 e_SoundsArray := nil;
608 end;
610 procedure e_ReleaseSoundSystem();
611 begin
612 e_RemoveAllSounds();
613 if SoundInitialized then
614 begin
615 Mix_CloseAudio();
616 SoundInitialized := False;
617 end;
618 end;
620 procedure e_SoundUpdate();
621 begin
622 //FMOD_System_Update(F_System);
623 end;
626 { TBasicSound: }
628 constructor TBasicSound.Create();
629 begin
630 FID := NO_SOUND_ID;
631 FMusic := False;
632 FChanNum := -1;
633 FPosition := 0;
634 FPriority := 128;
635 end;
637 destructor TBasicSound.Destroy();
638 begin
639 FreeSound();
640 inherited;
641 end;
643 function TBasicSound.GetChan (): Integer;
644 begin
645 if (FID <> NO_SOUND_ID) and (FChanNum >= 0) and (FChanNum < N_CHANNELS) then
646 begin
647 if ChanSIds[FChanNum].id <> FID then FChanNum := -1;
648 end
649 else if e_isMusic(FID) then
650 begin
651 FChanNum := N_MUSCHAN;
652 end;
653 Result := FChanNum;
654 end;
656 procedure TBasicSound.FreeSound();
657 begin
658 if FID = NO_SOUND_ID then Exit;
659 Stop();
660 FID := NO_SOUND_ID;
661 FMusic := False;
662 FPosition := 0;
663 FChanNum := -1;
664 end;
666 // aPos: msecs
667 function TBasicSound.RawPlay(Pan: Single; Volume: Single; aPos: DWORD): Boolean;
668 begin
669 Result := False;
670 if (FID = NO_SOUND_ID) or not SoundInitialized then Exit;
671 FChanNum := e_PlaySoundPanVolume(FID, Pan, Volume);
672 Result := (FChanNum >= 0);
673 //if e_isMusic(FID) then e_WriteLog(Format('playing music (%u)', [FID]), MSG_NOTIFY);
674 //TODO: aPos
675 end;
677 procedure TBasicSound.SetID(ID: DWORD);
678 begin
679 FreeSound();
680 FID := ID;
681 if ID <> NO_SOUND_ID then
682 begin
683 FMusic := e_SoundsArray[ID].isMusic;
684 end;
685 FChanNum := -1;
686 end;
688 function TBasicSound.IsPlaying(): Boolean;
689 var
690 chan: Integer;
691 begin
692 Result := False;
693 if e_isSound(FID) then
694 begin
695 //e_WriteLog(Format('IsPlaying: FID=%u; FChanNum=%d', [FID, FChanNum]), MSG_WARNING);
696 chan := Channel;
697 if chan < 0 then
698 begin
699 //e_WriteLog(Format('IsPlaying: FID=%u; ONA', [FID]), MSG_WARNING);
700 Exit;
701 end;
702 //Result := (Mix_Playing(chan) > 0)
703 //e_WriteLog(Format('IsPlaying: FID=%u; TAN', [FID]), MSG_WARNING);
704 Result := True;
705 end
706 else if e_isMusic(FID) then
707 begin
708 Result := (Mix_PlayingMusic() > 0);
709 end;
710 end;
712 procedure TBasicSound.Stop();
713 var
714 chan: Integer;
715 begin
716 if e_isSound(FID) then
717 begin
718 chan := Channel;
719 if chan >= 0 then
720 begin
721 //GetPosition();
722 Mix_HaltChannel(chan);
723 end;
724 end
725 else if e_isMusic(FID) then
726 begin
727 Mix_HaltMusic();
728 end;
729 FChanNum := -1;
730 end;
732 function TBasicSound.IsPaused(): Boolean;
733 var
734 chan: Integer;
735 begin
736 Result := False;
737 if e_isSound(FID) then
738 begin
739 chan := Channel;
740 if chan < 0 then Exit;
741 Result := (Mix_Paused(chan) > 0);
742 end
743 else if e_isMusic(FID) then
744 begin
745 Result := (Mix_PausedMusic() > 0);
746 end;
747 end;
749 procedure TBasicSound.Pause(Enable: Boolean);
750 var
751 chan: Integer;
752 pl: Boolean;
753 begin
754 Enable := not Enable; // fuckin' double negation
755 if e_isSound(FID) then
756 begin
757 chan := Channel;
758 if chan < 0 then Exit;
759 pl := not (Mix_Paused(chan) > 0);
760 if pl <> Enable then
761 begin
762 if Enable then Mix_Resume(chan) else Mix_Pause(chan);
763 end;
764 end
765 else if e_isMusic(FID) then
766 begin
767 pl := not (Mix_PausedMusic() > 0);
768 if pl <> Enable then
769 begin
770 if Enable then Mix_ResumeMusic() else Mix_PauseMusic();
771 end;
772 end;
774 if Enable then
775 begin
776 res := FMOD_Channel_GetPosition(FChanNum, FPosition, FMOD_TIMEUNIT_MS);
777 if res <> FMOD_OK then
778 begin
779 end;
780 end;
782 end;
784 function TBasicSound.GetVolume(): Single;
785 var
786 chan: Integer;
787 begin
788 Result := 0.0;
789 if e_isSound(FID) then
790 begin
791 chan := Channel;
792 if chan < 0 then Exit;
793 Result := (ChanSIds[chan].oldvol+0.0)/(MIX_MAX_VOLUME+0.0);
794 end
795 else if e_isMusic(FID) then
796 begin
797 Result := (MusVolume+0.0)/(MIX_MAX_VOLUME+0.0);
798 end;
799 end;
801 procedure TBasicSound.SetVolume(Volume: Single);
802 var
803 chan: Integer;
804 begin
805 if e_isSound(FID) then
806 begin
807 chan := Channel;
808 if chan < 0 then Exit;
809 //e_WriteLog(Format('SetVolume: chan=%d; Volume=%f', [chan, Volume]), MSG_WARNING);
810 e_chanSetVol(chan, Volume);
811 end
812 else if e_isMusic(FID) then
813 begin
814 //e_WriteLog(Format('SetVolume: chan=MUSIC; Volume=%f', [Volume]), MSG_WARNING);
815 e_chanSetVol(N_MUSCHAN, Volume);
816 end;
817 end;
819 function TBasicSound.GetPan(): Single;
820 var
821 chan: Integer;
822 begin
823 Result := 1.0;
824 if e_isSound(FID) then
825 begin
826 chan := Channel;
827 if chan < 0 then Exit;
828 Result := ChanSIds[chan].pan;
829 end;
830 end;
832 procedure TBasicSound.SetPan(Pan: Single);
833 var
834 chan: Integer;
835 begin
836 if e_isSound(FID) then
837 begin
838 chan := Channel;
839 if chan < 0 then Exit;
840 e_chanSetPan(chan, Pan);
841 end;
842 end;
844 function TBasicSound.IsMuted(): Boolean;
845 var
846 chan: Integer;
847 begin
848 Result := False;
849 if e_isSound(FID) then
850 begin
851 chan := Channel;
852 if chan < 0 then Exit;
853 Result := ChanSIds[chan].muted;
854 end
855 else if e_isMusic(FID) then
856 begin
857 Result := SoundMuted;
858 end;
859 end;
861 procedure TBasicSound.Mute(Enable: Boolean);
862 var
863 chan: Integer;
864 begin
865 if e_isSound(FID) then
866 begin
867 chan := Channel;
868 if chan < 0 then Exit;
869 if ChanSIds[chan].muted <> Enable then
870 begin
871 //e_WriteLog(Format('muting sound for channel %d', [cnan]), MSG_WARNING);
872 ChanSIds[chan].muted := Enable;
873 if ChanSIds[chan].muted then Mix_Volume(chan, 0) else Mix_Volume(chan, ChanSIds[chan].oldvol);
874 end;
875 end
876 else if e_isMusic(FID) then
877 begin
878 if Enable then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
879 end;
880 end;
882 //TODO
883 function TBasicSound.GetPosition(): DWORD;
884 begin
885 Result := 0;
887 if FChanNum < 0 then Exit;
888 res := FMOD_Channel_GetPosition(FChanNum, FPosition, FMOD_TIMEUNIT_MS);
889 if res <> FMOD_OK then
890 begin
891 Exit;
892 end;
893 Result := FPosition;
895 end;
897 //TODO
898 procedure TBasicSound.SetPosition(aPos: DWORD);
899 begin
900 FPosition := aPos;
902 if FChanNum < 0 then Exit;
903 res := FMOD_Channel_SetPosition(FChanNum, FPosition, FMOD_TIMEUNIT_MS);
904 if res <> FMOD_OK then
905 begin
906 end;
908 end;
910 //TODO
911 procedure TBasicSound.SetPriority(priority: Integer);
912 begin
914 if (FChanNum <> nil) and (FPriority <> priority) and
915 (priority >= 0) and (priority <= 256) then
916 begin
917 FPriority := priority;
918 res := FMOD_Channel_SetPriority(FChanNum, priority);
919 if res <> FMOD_OK then
920 begin
921 end;
922 end;
924 end;
926 end.