DEADSOFTWARE

sdl mixer: initializing all possible engines
[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 if (chan >= 0) and (chan < N_CHANNELS) then
108 begin
109 if ChanSIds[chan].id <> NO_SOUND_ID then
110 begin
111 Dec(e_SoundsArray[ChanSIds[chan].id].nRefs);
112 ChanSIds[chan].id := NO_SOUND_ID;
113 end;
114 end;
115 end;
118 function e_InitSoundSystem(): Boolean;
119 var
120 res, i: Integer;
121 begin
122 if SoundInitialized then begin Result := true; Exit end;
124 Result := False;
125 SoundInitialized := False;
127 // wow, this is actually MIDI player!
128 // we need module player
129 res := Mix_Init(MIX_INIT_MOD or MIX_INIT_MP3 or MIX_INIT_OGG or MIX_INIT_FLAC);
130 if (res and MIX_INIT_FLAC) <> 0 then e_WriteLog('SDL: FLAC playback is active', MSG_NOTIFY);
131 if (res and MIX_INIT_MOD) <> 0 then e_WriteLog('SDL: MOD/MIDI playback is active', MSG_NOTIFY);
132 if (res and MIX_INIT_MP3) <> 0 then e_WriteLog('SDL: MP3 playback is active', MSG_NOTIFY);
133 if (res and MIX_INIT_OGG) <> 0 then e_WriteLog('SDL: OGG playback is active', MSG_NOTIFY);
135 res := Mix_OpenAudio(48000, AUDIO_S16LSB, 2, 2048);
136 if res = -1 then res := Mix_OpenAudio(44100, AUDIO_S16LSB, 2, 2048);
137 if res = -1 then
138 begin
139 e_WriteLog('Error initializing SDL mixer:', MSG_FATALERROR);
140 e_WriteLog(Mix_GetError(), MSG_FATALERROR);
141 Exit;
142 end;
144 Mix_AllocateChannels(N_CHANNELS);
145 Mix_ChannelFinished(chanFinished);
147 for i := 0 to N_CHANNELS-1 do
148 begin
149 ChanSIds[i].id := NO_SOUND_ID;
150 ChanSIds[i].muted := SoundMuted;
151 ChanSIds[i].oldvol := MIX_MAX_VOLUME;
152 ChanSIds[i].pan := 1.0;
153 end;
154 MusVolume := MIX_MAX_VOLUME;
156 SoundInitialized := True;
157 Result := True;
158 end;
160 function e_isMusic (id: DWORD): Boolean;
161 begin
162 Result := False;
163 if (e_SoundsArray <> nil) and (id <= High(e_SoundsArray)) then
164 begin
165 Result := (e_SoundsArray[id].Music <> nil);
166 end;
167 end;
169 function e_isSound (id: DWORD): Boolean;
170 begin
171 Result := False;
172 if (e_SoundsArray <> nil) and (id <= High(e_SoundsArray)) then
173 begin
174 Result := (e_SoundsArray[id].Sound <> nil);
175 end;
176 end;
178 function FindESound(): DWORD;
179 var
180 i: Integer;
181 begin
182 if e_SoundsArray <> nil then
183 begin
184 for i := 0 to High(e_SoundsArray) do
185 if (e_SoundsArray[i].Sound = nil) and (e_SoundsArray[i].Music = nil) then
186 begin
187 Result := i;
188 Exit;
189 end;
190 end;
191 if e_SoundsArray = nil then
192 begin
193 SetLength(e_SoundsArray, 16);
194 Result := 0;
195 end
196 else
197 begin
198 Result := High(e_SoundsArray) + 1;
199 SetLength(e_SoundsArray, Length(e_SoundsArray) + 16);
200 end;
201 end;
203 function e_LoadSound(FileName: String; var ID: DWORD; isMusic: Boolean): Boolean;
204 var
205 find_id: DWORD;
206 begin
207 Result := False;
208 if not SoundInitialized then Exit;
210 if isMusic then e_WriteLog('Loading music '+FileName+'...', MSG_NOTIFY)
211 else e_WriteLog('Loading sound '+FileName+'...', MSG_NOTIFY);
213 find_id := FindESound();
215 e_SoundsArray[find_id].Data := nil;
216 e_SoundsArray[find_id].isMusic := isMusic;
217 e_SoundsArray[find_id].nRefs := 0;
219 if isMusic then
220 begin
221 e_SoundsArray[find_id].Music := Mix_LoadMUS(PAnsiChar(FileName));
222 if e_SoundsArray[find_id].Music = nil then Exit;
223 end
224 else
225 begin
226 e_SoundsArray[find_id].Sound := Mix_LoadWAV(PAnsiChar(FileName));
227 if e_SoundsArray[find_id].Sound = nil then Exit;
228 end;
230 ID := find_id;
232 Result := True;
233 end;
235 function e_LoadSoundMem(pData: Pointer; Length: Integer; var ID: DWORD; isMusic: Boolean): Boolean;
236 var
237 find_id: DWORD;
238 rw: PSDL_RWops;
239 begin
240 Result := False;
241 if not SoundInitialized then Exit;
243 rw := SDL_RWFromConstMem(pData, Length);
244 if rw = nil then Exit;
246 find_id := FindESound();
248 e_SoundsArray[find_id].Data := pData;
249 e_SoundsArray[find_id].isMusic := isMusic;
250 e_SoundsArray[find_id].nRefs := 0;
252 if isMusic then
253 begin
254 e_SoundsArray[find_id].Music := Mix_LoadMUS_RW(rw, 0);
255 end
256 else
257 begin
258 e_SoundsArray[find_id].Sound := Mix_LoadWAV_RW(rw, 0);
259 end;
260 SDL_FreeRW(rw);
261 if (e_SoundsArray[find_id].Sound = nil) and (e_SoundsArray[find_id].Music = nil) then Exit;
263 ID := find_id;
265 Result := True;
266 end;
268 function e_PlaySound (ID: DWORD): Integer;
269 var
270 res: Integer = -1;
271 begin
272 Result := -1;
273 if not SoundInitialized then Exit;
275 if e_isSound(ID) then
276 begin
277 if e_SoundsArray[ID].nRefs >= gMaxSimSounds then Exit;
278 Inc(e_SoundsArray[ID].nRefs);
279 res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, 0);
280 if res >= 0 then
281 begin
282 ChanSIds[res].id := ID;
283 ChanSIds[res].muted := SoundMuted;
284 if SoundMuted then Mix_Volume(res, 0) else Mix_Volume(res, ChanSIds[res].oldvol);
286 if e_SoundsArray[ID].isMusic then
287 res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, -1)
288 else
289 res := Mix_PlayChannel(-1, e_SoundsArray[ID].Sound, 0);
291 end;
292 end
293 else
294 begin
295 if not e_isMusic(ID) then Exit;
296 res := Mix_PlayMusic(e_SoundsArray[ID].Music, -1);
297 if res >= 0 then res := N_MUSCHAN;
298 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
299 Result := res;
300 end;
302 Result := res;
303 end;
305 function e_chanSetPan (chan: Integer; Pan: Single): Boolean;
306 var
307 l, r: UInt8;
308 begin
309 Result := True;
310 if chan = N_MUSCHAN then
311 begin
312 // no panning for music
313 end
314 else if chan >= 0 then
315 begin
316 if Pan < -1.0 then Pan := -1.0 else if Pan > 1.0 then Pan := 1.0;
317 Pan := Pan+1.0; // 0..2
318 l := trunc(127.0*(2.0-Pan));
319 r := trunc(127.0*Pan);
320 Mix_SetPanning(chan, l, r);
321 ChanSIds[chan].pan := Pan;
322 end
323 else
324 begin
325 Result := False;
326 end;
327 end;
329 function e_chanSetVol (chan: Integer; Volume: Single): Boolean;
330 var
331 vol: Integer;
332 begin
333 Result := True;
334 if Volume < 0 then Volume := 0 else if Volume > 1 then Volume := 1;
335 vol := trunc(Volume*MIX_MAX_VOLUME);
336 if chan = N_MUSCHAN then
337 begin
338 MusVolume := vol;
339 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(vol);
340 end
341 else if chan >= 0 then
342 begin
343 ChanSIds[chan].oldvol := vol;
344 if ChanSIds[chan].muted then Mix_Volume(chan, 0) else Mix_Volume(chan, vol);
345 end
346 else
347 begin
348 Result := False;
349 end;
350 end;
352 function e_PlaySoundPan(ID: DWORD; Pan: Single): Integer;
353 var
354 chan: Integer;
355 begin
356 Result := -1;
357 chan := e_PlaySound(ID);
358 e_chanSetPan(chan, Pan);
359 Result := chan;
360 end;
362 function e_PlaySoundVolume(ID: DWORD; Volume: Single): Integer;
363 var
364 chan: Integer;
365 begin
366 Result := -1;
367 chan := e_PlaySound(ID);
368 e_chanSetVol(chan, Volume);
369 Result := chan;
370 end;
372 function e_PlaySoundPanVolume(ID: DWORD; Pan, Volume: Single): Integer;
373 var
374 chan: Integer;
375 begin
376 Result := -1;
377 chan := e_PlaySound(ID);
378 e_chanSetPan(chan, Pan);
379 e_chanSetVol(chan, Volume);
380 Result := chan;
381 end;
383 procedure e_DeleteSound(ID: DWORD);
384 var
385 i: Integer;
386 begin
387 if (e_SoundsArray[ID].Sound = nil) and (e_SoundsArray[ID].Music = nil) then Exit;
389 for i := 0 to N_CHANNELS-1 do
390 begin
391 if ChanSIds[i].id = ID then
392 begin
393 ChanSIds[i].id := NO_SOUND_ID;
394 Mix_HaltChannel(i);
395 end;
396 end;
398 if e_SoundsArray[ID].Data <> nil then FreeMem(e_SoundsArray[ID].Data);
399 if e_SoundsArray[ID].Sound <> nil then Mix_FreeChunk(e_SoundsArray[ID].Sound);
400 if e_SoundsArray[ID].Music <> nil then Mix_FreeMusic(e_SoundsArray[ID].Music);
402 e_SoundsArray[ID].Sound := nil;
403 e_SoundsArray[ID].Music := nil;
404 e_SoundsArray[ID].Data := nil;
405 e_SoundsArray[ID].nRefs := 0;
406 end;
408 procedure e_ModifyChannelsVolumes(SoundMod: Single; setMode: Boolean);
409 var
410 i: Integer;
411 vol: Single;
412 ovol: Integer;
413 begin
414 for i := 0 to N_CHANNELS-1 do
415 begin
416 ovol := ChanSIds[i].oldvol;
417 if setMode then
418 begin
419 vol := SoundMod;
420 end
421 else
422 begin
423 vol := (MIX_MAX_VOLUME+0.0)/ovol;
424 vol := vol*SoundMod;
425 end;
426 if vol < 0 then vol := 0 else if vol > 1 then vol := 1;
427 ChanSIds[i].oldvol := trunc(vol*MIX_MAX_VOLUME);
428 //if i = 0 then e_WriteLog(Format('modifying volumes: vol=%f; newvol=%d', [vol, ChanSIds[i].oldvol]), MSG_WARNING);
429 if ChanSIds[i].muted then Mix_Volume(i, 0) else Mix_Volume(i, ChanSIds[i].oldvol);
430 end;
431 ovol := Mix_VolumeMusic(-1);
432 if ovol >= 0 then
433 begin
434 if setMode then
435 begin
436 vol := SoundMod;
437 end
438 else
439 begin
440 vol := (MIX_MAX_VOLUME+0.0)/ovol;
441 vol := vol * SoundMod;
442 end;
443 if vol < 0 then vol := 0 else if vol > 1 then vol := 1;
444 MusVolume := trunc(vol*MIX_MAX_VOLUME);
445 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
446 end;
447 end;
449 procedure e_MuteChannels(Enable: Boolean);
450 var
451 i: Integer;
452 begin
453 //if Enable = SoundMuted then Exit;
454 SoundMuted := Enable;
455 for i := 0 to N_CHANNELS-1 do
456 begin
457 if ChanSIds[i].muted <> SoundMuted then
458 begin
459 ChanSIds[i].muted := SoundMuted;
460 //e_WriteLog(Format('gmuting sound for channel %d', [i]), MSG_WARNING);
461 if ChanSIds[i].muted then Mix_Volume(i, 0) else Mix_Volume(i, ChanSIds[i].oldvol);
462 end;
463 end;
464 if SoundMuted then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
465 end;
467 procedure e_StopChannels();
468 var
469 i: Integer;
470 begin
471 Mix_HaltChannel(-1);
472 Mix_HaltMusic();
473 for i := 0 to High(e_SoundsArray) do e_SoundsArray[i].nRefs := 0;
474 for i := 0 to N_CHANNELS-1 do ChanSIds[i].id := NO_SOUND_ID;
475 end;
477 procedure e_RemoveAllSounds();
478 var
479 i: Integer;
480 begin
481 if SoundInitialized then e_StopChannels();
482 for i := 0 to High(e_SoundsArray) do e_DeleteSound(i);
483 SetLength(e_SoundsArray, 0);
484 e_SoundsArray := nil;
485 end;
487 procedure e_ReleaseSoundSystem();
488 begin
489 e_RemoveAllSounds();
490 if SoundInitialized then
491 begin
492 Mix_CloseAudio();
493 SoundInitialized := False;
494 end;
495 end;
497 procedure e_SoundUpdate();
498 begin
499 //FMOD_System_Update(F_System);
500 end;
503 { TBasicSound: }
505 constructor TBasicSound.Create();
506 begin
507 FID := NO_SOUND_ID;
508 FMusic := False;
509 FChanNum := -1;
510 FPosition := 0;
511 FPriority := 128;
512 end;
514 destructor TBasicSound.Destroy();
515 begin
516 FreeSound();
517 inherited;
518 end;
520 function TBasicSound.GetChan (): Integer;
521 begin
522 if (FID <> NO_SOUND_ID) and (FChanNum >= 0) and (FChanNum < N_CHANNELS) then
523 begin
524 if ChanSIds[FChanNum].id <> FID then FChanNum := -1;
525 end
526 else if e_isMusic(FID) then
527 begin
528 FChanNum := N_MUSCHAN;
529 end;
530 Result := FChanNum;
531 end;
533 procedure TBasicSound.FreeSound();
534 begin
535 if FID = NO_SOUND_ID then Exit;
536 Stop();
537 FID := NO_SOUND_ID;
538 FMusic := False;
539 FPosition := 0;
540 FChanNum := -1;
541 end;
543 // aPos: msecs
544 function TBasicSound.RawPlay(Pan: Single; Volume: Single; aPos: DWORD): Boolean;
545 begin
546 Result := False;
547 if (FID = NO_SOUND_ID) or not SoundInitialized then Exit;
548 FChanNum := e_PlaySoundPanVolume(FID, Pan, Volume);
549 Result := (FChanNum >= 0);
550 //TODO: aPos
551 end;
553 procedure TBasicSound.SetID(ID: DWORD);
554 begin
555 FreeSound();
556 FID := ID;
557 FMusic := e_SoundsArray[ID].isMusic;
558 FChanNum := -1;
559 end;
561 function TBasicSound.IsPlaying(): Boolean;
562 var
563 chan: Integer;
564 begin
565 Result := False;
566 if e_isSound(FID) then
567 begin
568 //e_WriteLog(Format('IsPlaying: FID=%u; FChanNum=%d', [FID, FChanNum]), MSG_WARNING);
569 chan := Channel;
570 if chan < 0 then
571 begin
572 //e_WriteLog(Format('IsPlaying: FID=%u; ONA', [FID]), MSG_WARNING);
573 Exit;
574 end;
575 //Result := (Mix_Playing(chan) > 0)
576 //e_WriteLog(Format('IsPlaying: FID=%u; TAN', [FID]), MSG_WARNING);
577 Result := True;
578 end
579 else if e_isMusic(FID) then
580 begin
581 Result := (Mix_PlayingMusic() > 0);
582 end;
583 end;
585 procedure TBasicSound.Stop();
586 var
587 chan: Integer;
588 begin
589 if e_isSound(FID) then
590 begin
591 chan := Channel;
592 if chan >= 0 then
593 begin
594 //GetPosition();
595 Mix_HaltChannel(chan);
596 end;
597 end
598 else if e_isMusic(FID) then
599 begin
600 Mix_HaltMusic();
601 end;
602 FChanNum := -1;
603 end;
605 function TBasicSound.IsPaused(): Boolean;
606 var
607 chan: Integer;
608 begin
609 Result := False;
610 if e_isSound(FID) then
611 begin
612 chan := Channel;
613 if chan < 0 then Exit;
614 Result := (Mix_Paused(chan) > 0);
615 end
616 else if e_isMusic(FID) then
617 begin
618 Result := (Mix_PausedMusic() > 0);
619 end;
620 end;
622 procedure TBasicSound.Pause(Enable: Boolean);
623 var
624 chan: Integer;
625 pl: Boolean;
626 begin
627 if e_isSound(FID) then
628 begin
629 chan := Channel;
630 if chan < 0 then Exit;
631 pl := not (Mix_Paused(chan) > 0);
632 if pl <> Enable then
633 begin
634 if Enable then Mix_Resume(chan) else Mix_Pause(chan);
635 end;
636 end
637 else if e_isMusic(FID) then
638 begin
639 pl := not (Mix_PausedMusic() > 0);
640 if pl <> Enable then
641 begin
642 if Enable then Mix_ResumeMusic() else Mix_PauseMusic();
643 end;
644 end;
646 if Enable then
647 begin
648 res := FMOD_Channel_GetPosition(FChanNum, FPosition, FMOD_TIMEUNIT_MS);
649 if res <> FMOD_OK then
650 begin
651 end;
652 end;
654 end;
656 function TBasicSound.GetVolume(): Single;
657 var
658 chan: Integer;
659 begin
660 Result := 0.0;
661 if e_isSound(FID) then
662 begin
663 chan := Channel;
664 if chan < 0 then Exit;
665 Result := (ChanSIds[chan].oldvol+0.0)/(MIX_MAX_VOLUME+0.0);
666 end
667 else if e_isMusic(FID) then
668 begin
669 Result := (MusVolume+0.0)/(MIX_MAX_VOLUME+0.0);
670 end;
671 end;
673 procedure TBasicSound.SetVolume(Volume: Single);
674 var
675 chan: Integer;
676 begin
677 if e_isSound(FID) then
678 begin
679 chan := Channel;
680 if chan < 0 then Exit;
681 //e_WriteLog(Format('SetVolume: chan=%d; Volume=%f', [chan, Volume]), MSG_WARNING);
682 e_chanSetVol(chan, Volume);
683 end
684 else if e_isMusic(FID) then
685 begin
686 //e_WriteLog(Format('SetVolume: chan=MUSIC; Volume=%f', [Volume]), MSG_WARNING);
687 e_chanSetVol(N_MUSCHAN, Volume);
688 end;
689 end;
691 function TBasicSound.GetPan(): Single;
692 var
693 chan: Integer;
694 begin
695 Result := 1.0;
696 if e_isSound(FID) then
697 begin
698 chan := Channel;
699 if chan < 0 then Exit;
700 Result := ChanSIds[chan].pan;
701 end;
702 end;
704 procedure TBasicSound.SetPan(Pan: Single);
705 var
706 chan: Integer;
707 begin
708 if e_isSound(FID) then
709 begin
710 chan := Channel;
711 if chan < 0 then Exit;
712 e_chanSetPan(chan, Pan);
713 end;
714 end;
716 function TBasicSound.IsMuted(): Boolean;
717 var
718 chan: Integer;
719 begin
720 Result := False;
721 if e_isSound(FID) then
722 begin
723 chan := Channel;
724 if chan < 0 then Exit;
725 Result := ChanSIds[chan].muted;
726 end
727 else if e_isMusic(FID) then
728 begin
729 Result := SoundMuted;
730 end;
731 end;
733 procedure TBasicSound.Mute(Enable: Boolean);
734 var
735 chan: Integer;
736 begin
737 if e_isSound(FID) then
738 begin
739 chan := Channel;
740 if chan < 0 then Exit;
741 if ChanSIds[chan].muted <> Enable then
742 begin
743 //e_WriteLog(Format('muting sound for channel %d', [cnan]), MSG_WARNING);
744 ChanSIds[chan].muted := Enable;
745 if ChanSIds[chan].muted then Mix_Volume(chan, 0) else Mix_Volume(chan, ChanSIds[chan].oldvol);
746 end;
747 end
748 else if e_isMusic(FID) then
749 begin
750 if Enable then Mix_VolumeMusic(0) else Mix_VolumeMusic(MusVolume);
751 end;
752 end;
754 //TODO
755 function TBasicSound.GetPosition(): DWORD;
756 begin
757 Result := 0;
759 if FChanNum < 0 then Exit;
760 res := FMOD_Channel_GetPosition(FChanNum, FPosition, FMOD_TIMEUNIT_MS);
761 if res <> FMOD_OK then
762 begin
763 Exit;
764 end;
765 Result := FPosition;
767 end;
769 //TODO
770 procedure TBasicSound.SetPosition(aPos: DWORD);
771 begin
772 FPosition := aPos;
774 if FChanNum < 0 then Exit;
775 res := FMOD_Channel_SetPosition(FChanNum, FPosition, FMOD_TIMEUNIT_MS);
776 if res <> FMOD_OK then
777 begin
778 end;
780 end;
782 //TODO
783 procedure TBasicSound.SetPriority(priority: Integer);
784 begin
786 if (FChanNum <> nil) and (FPriority <> priority) and
787 (priority >= 0) and (priority <= 256) then
788 begin
789 FPriority := priority;
790 res := FMOD_Channel_SetPriority(FChanNum, priority);
791 if res <> FMOD_OK then
792 begin
793 end;
794 end;
796 end;
798 end.