DEADSOFTWARE

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