DEADSOFTWARE

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