X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fengine%2Fe_sound_al.inc;h=ac64ad41d7f8e2d6d83ce7a5c92070270c80d671;hb=367241f47cc2babef77538b6a58c7c500add44e7;hp=dfe5919ea8ef52f374a57939a80ecc6ce474ca7e;hpb=d194bf7d765aa5eb39a57892f6e5c4e66eeae5e5;p=d2df-sdl.git diff --git a/src/engine/e_sound_al.inc b/src/engine/e_sound_al.inc index dfe5919..ac64ad4 100644 --- a/src/engine/e_sound_al.inc +++ b/src/engine/e_sound_al.inc @@ -2,8 +2,7 @@ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * the Free Software Foundation, version 3 of the License ONLY. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -91,13 +90,15 @@ procedure e_SoundUpdate(); var e_SoundFormat: TSoundFormat; // desired sound format e_SoundsArray: array of TSoundRec = nil; - e_ZeroPosition: array [0..2] of ALfloat; + e_ZeroPosition: array [0..2] of ALfloat = (0, 0, 0); e_ALError: ALenum = 0; + e_SoundFont: string = ''; + e_MusicLerp: Boolean = True; implementation uses - g_window, g_options, utils; + g_options, utils; const NUM_SOURCES = 255; // + 1 stereo @@ -119,6 +120,28 @@ var alStreamData: array [0..STREAM_BUFSIZE-1] of Byte; alStreamAvail: Integer = NUM_STREAM_BUFFERS; +{$IFNDEF OPENAL_SINGLETHREADED} +var + StreamThread: TThreadID = NilThreadId; + StreamThreadRunning: Boolean = False; + StreamLock: TRTLCriticalSection; + StreamBufTime: Integer = 100; // time to sleep between buffer checks + +procedure UpdateStreamSource(Src: Integer); forward; + +function StreamThreadProc(Param: Pointer): PtrInt; +begin + while StreamThreadRunning do + begin + EnterCriticalSection(StreamLock); + UpdateStreamSource(MUSIC_SOURCE); + LeaveCriticalSection(StreamLock); + Sleep(StreamBufTime); + end; + Result := 0; +end; +{$ENDIF} + function CheckALError(): Boolean; begin e_ALError := alGetError(); @@ -213,6 +236,12 @@ begin else alStreamAvail := NUM_STREAM_BUFFERS; + {$IFNDEF OPENAL_SINGLETHREADED} + InitCriticalSection(StreamLock); + StreamThreadRunning := True; + StreamThread := BeginThread(Addr(StreamThreadProc)); + {$ENDIF} + Result := True; end; @@ -264,12 +293,70 @@ begin alGetSourcei(S, AL_SOURCE_STATE, Result); end; +function LoadEntireSound(var Snd: TSoundRec; Loader: TSoundLoader): Boolean; +var + Frame: Pointer; + Data: Pointer; + Rx: LongWord; + DataLen, OldLen: LongWord; +const + CHUNK_SIZE = 65536 * 2 * 2; +begin + Result := False; + + Frame := GetMem(CHUNK_SIZE); + if Frame = nil then exit; + + Data := nil; + DataLen := 0; + + repeat + Rx := Loader.FillBuffer(Frame, CHUNK_SIZE); + if Rx = 0 then break; + + OldLen := DataLen; + DataLen := DataLen + Rx; + Data := ReAllocMem(Data, DataLen); + if Data = nil then begin FreeMem(Frame); exit; end; + + Move(Frame^, (Data + OldLen)^, Rx); + until Loader.Finished(); + + FreeMem(Frame); + + alGenBuffers(1, Addr(Snd.alBuffer)); + if CheckALError() then + begin + e_LogWritefln('AL: Could not create AL buffer: %s', [GetALError()]); + FreeMem(Data); + exit; + end; + + alBufferData( + Snd.alBuffer, + GetALSoundFormat(Loader.Format), + Data, + DataLen, + Loader.Format.SampleRate + ); + + FreeMem(Data); + + if CheckALError() then + begin + e_LogWriteln('AL: Could not fill AL buffer: ' + GetALError()); + alDeleteBuffers(1, Addr(Snd.alBuffer)); + Snd.alBuffer := 0; + exit; + end; + + Result := True; +end; + function e_LoadSound(FileName: String; var ID: DWORD; isMusic: Boolean; ForceNoLoop: Boolean = False): Boolean; var find_id: DWORD; Loader: TSoundLoader; - OutData: Pointer; - OutLen: LongWord; begin ID := NO_SOUND_ID; Result := False; @@ -288,7 +375,7 @@ begin exit; end; - if not Loader.Load(FileName, e_SoundsArray[find_id].isMusic) then + if not Loader.Load(FileName, e_SoundsArray[find_id].Loops) then begin e_LogWritefln('Could not load sound `%s`', [FileName]); exit; @@ -296,36 +383,13 @@ begin alGetError(); // reset error state, god damn it - if not Loader.Streaming then + if not isMusic then begin - alGenBuffers(1, Addr(e_SoundsArray[find_id].alBuffer)); - if CheckALError() then - begin - e_LogWritefln('Could not create AL buffer for `%s`: %s', [FileName, GetALError()]); - Loader.Free(); - exit; - end; - - OutLen := Loader.GetAll(OutData); - alBufferData( - e_SoundsArray[find_id].alBuffer, - GetALSoundFormat(Loader.Format), - OutData, - OutLen, - Loader.Format.SampleRate - ); - + if not LoadEntireSound(e_SoundsArray[find_id], Loader) then + e_LogWritefln('AL: Could not buffer sound effect `%s`', [FileName]); // don't need this anymore Loader.Free(); Loader := nil; - - if CheckALError() then - begin - e_LogWriteln('AL: what the fuck: ' + GetALError()); - alDeleteBuffers(1, Addr(e_SoundsArray[find_id].alBuffer)); - e_SoundsArray[find_id].alBuffer := 0; - exit; - end; end else begin @@ -341,8 +405,6 @@ function e_LoadSoundMem(pData: Pointer; Length: Integer; var ID: DWORD; isMusic: var find_id: DWORD; Loader: TSoundLoader; - OutData: Pointer; - OutLen: LongWord; begin ID := NO_SOUND_ID; Result := False; @@ -361,7 +423,7 @@ begin exit; end; - if not Loader.Load(pData, LongWord(Length), e_SoundsArray[find_id].isMusic) then + if not Loader.Load(pData, LongWord(Length), e_SoundsArray[find_id].Loops) then begin e_LogWritefln('Could not load sound `%p`', [pData]); exit; @@ -369,36 +431,13 @@ begin alGetError(); // reset error state, god damn it - if not Loader.Streaming then + if not isMusic then begin - alGenBuffers(1, Addr(e_SoundsArray[find_id].alBuffer)); - if CheckALError() then - begin - e_LogWritefln('Could not create AL buffer for `%p`: %s', [pData, GetALError()]); - Loader.Free(); - exit; - end; - - OutLen := Loader.GetAll(OutData); - alBufferData( - e_SoundsArray[find_id].alBuffer, - GetALSoundFormat(Loader.Format), - OutData, - OutLen, - Loader.Format.SampleRate - ); - + if not LoadEntireSound(e_SoundsArray[find_id], Loader) then + e_LogWritefln('AL: Could not buffer sound effect `%p`', [pData]); // don't need this anymore Loader.Free(); Loader := nil; - - if CheckALError() then - begin - e_LogWriteln('AL: what the fuck: ' + GetALError()); - alDeleteBuffers(1, Addr(e_SoundsArray[find_id].alBuffer)); - e_SoundsArray[find_id].alBuffer := 0; - exit; - end; end else begin @@ -406,6 +445,8 @@ begin e_SoundsArray[find_id].Loader := Loader; end; + // the calling side won't free this, the loader will get a copy, so fuck it + FreeMem(pData); ID := find_id; Result := True; end; @@ -447,18 +488,44 @@ begin end; procedure AssignSound(ID: DWORD; Src: ALuint); inline; +var + S: ALint; begin alGetError(); // reset error state if e_SoundsArray[ID].Loader <> nil then begin // this is a stream + {$IFNDEF OPENAL_SINGLETHREADED} + // lock the stream so the stream thread doesn't shit itself + EnterCriticalSection(StreamLock); + // number of stereo samples / samplerate = + // time until buffer runs out + StreamBufTime := + (STREAM_BUFSIZE div (2 * e_SoundsArray[ID].Loader.Format.SampleBits div 8)) div + (e_SoundsArray[ID].Loader.Format.SampleRate div 1000) - 1; + if StreamBufTime < 1 then StreamBufTime := 1; + e_LogWritefln('sleep time = %d', [StreamBufTime]); + {$ENDIF} // reset position - e_SoundsArray[ID].Loader.SetPosition(0); - if CurStream <> ID then // changing streams, stop the thing just in case - alSourceStop(Src); + e_SoundsArray[ID].Loader.Restart(); + if CurStream <> ID then // changing streams + begin + alSourceStop(Src); // this should mark all buffers as processed + alGetSourcei(Src, AL_BUFFERS_PROCESSED, S); + // unqueue all buffers + if S > 0 then + begin + alSourceUnqueueBuffers(Src, S, @alStreamBufs[alStreamAvail]); + alStreamAvail := NUM_STREAM_BUFFERS; + end; + end; // this shit is playing now CurStream := ID; + {$IFNDEF OPENAL_SINGLETHREADED} + // unlock the stream + LeaveCriticalSection(StreamLock); + {$ENDIF} end else begin @@ -494,6 +561,8 @@ begin if Result >= 0 then begin Pos[0] := Pan; + Pos[1] := 0; + Pos[2] := 0; AssignSound(ID, alSources[Result]); alSourcef(alSources[Result], AL_GAIN, 1); alSourcefv(alSources[Result], AL_POSITION, Pos); @@ -521,6 +590,8 @@ begin if Result >= 0 then begin Pos[0] := Pan; + Pos[1] := 0; + Pos[2] := 0; AssignSound(ID, alSources[Result]); alSourcefv(alSources[Result], AL_POSITION, Pos); alSourcef(alSources[Result], AL_GAIN, Volume); @@ -606,6 +677,16 @@ end; procedure e_ReleaseSoundSystem(); begin + {$IFNDEF OPENAL_SINGLETHREADED} + if StreamThread <> NilThreadId then + begin + StreamThreadRunning := False; + WaitForThreadTerminate(StreamThread, 66666); + StreamThread := NilThreadId; + DoneCriticalSection(StreamLock); + end; + {$ENDIF} + e_RemoveAllSounds(); alcMakeContextCurrent(nil); @@ -675,8 +756,10 @@ begin alOwners[S] := nil; end; + {$IFDEF OPENAL_SINGLETHREADED} // update the stream sources UpdateStreamSource(MUSIC_SOURCE); + {$ENDIF} end; { TBasicSound: } @@ -796,7 +879,7 @@ end; function TBasicSound.GetPan(): Single; var - Pos: array [0..2] of ALfloat; + Pos: array [0..2] of ALfloat = (0, 0, 0); begin Result := 0.0; if InvalidSource() then @@ -812,6 +895,8 @@ begin if InvalidSource() then Exit; Pos[0] := Pan; + Pos[1] := 0; + Pos[2] := 0; alSourcefv(alSources[FSource], AL_POSITION, Pos); end;