DEADSOFTWARE

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