Hi, I’ve been working on getting volume and panning working using SDL audio. This example has it working. I can set the volume/pan and it will work,however I am unable to change it in real-time. Well, any change will only be reflected after SDL_GetAudioStreamAvailable returns 0. Can you give me some insight on how to rework this code to make this happen? Also, I can call SDL_ClearAudioStream after a volume/pan change, it will happen right away, but there are gaps in the audio.
procedure Test05;
const
CChunkSize = 1024;
var
LVorbisStream: Pstb_vorbis;
LInAudioSpec, LOutAudioSpec: SDL_AudioSpec;
LAudioDevice: SDL_AudioDeviceID;
LAudioStream: PSDL_AudioStream;
LInBuffer: array [0..CChunkSize] of Smallint;
LOutBuffer: array [0..CChunkSize*2] of Smallint;
BytesToWrite: Integer;
LInfo: stb_vorbis_info;
Loop, Done: Boolean;
LRWops: PSDL_Rwops;
LError: Integer;
//LSamples: Cardinal;
LFilename: string;
I: Integer;
LVolume: Single;
LCalVolume: Integer;
LPan: Single;
LLeftVolume: Single;
LRightVolume: Single;
LCount: Integer;
begin
// try to init SDL audio subsystem
if SDL_Init(SDL_INIT_AUDIO) <> 0 then
Exit;
// open OGG from zip file
LFilename := 'arc/music/song02.ogg';
//LFilename := 'arc/sfx/samp0.ogg';
LRWops := SDL_RWFromZipFile(CZipPassword, CZipFilename, LFilename);
if not Assigned(LRWops) then
begin
SDL_Quit;
Exit;
end;
// open OGG stream
LVorbisStream := stb_vorbis_open_rwops(LRWops, 0, @LError, nil);
if not Assigned(LVorbisStream) then
begin
SDL_RWclose(LRWops);
SDL_Quit;
Exit;
end;
// get size in samples
//LSamples := stb_vorbis_stream_length_in_samples(LVorbisStream);
// get OGG info
LInfo := stb_vorbis_get_info(LVorbisStream);
// error if ogg does not have two channels for this example
if LInfo.channels > 2 then
begin
stb_vorbis_close(LVorbisStream);
SDL_RWclose(LRWops);
SDL_Quit;
Exit;
end;
// Set input audio specs
LInAudioSpec.format := SDL_AUDIO_S16;
//LInAudioSpec.channels := LInfo.channels;
LInAudioSpec.channels := 2;
LInAudioSpec.freq := LInfo.sample_rate;
// set ouput audio specs
LOutAudioSpec.format := SDL_AUDIO_S16;
LOutAudioSpec.channels := 2;
LOutAudioSpec.freq := 44100;
// open audio device
LAudioDevice := SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT,
@LInAudioSpec);
// check if audio device is open
if LAudioDevice = 0 then
begin
stb_vorbis_close(LVorbisStream);
SDL_RWclose(LRWops);
SDL_Quit;
Exit;
end;
// Create audio stream
LAudioStream := SDL_CreateAudioStream(@LInAudioSpec, @LOutAudioSpec);
// check if audio stream was create
if not Assigned(LAudioStream) then
begin
SDL_CloseAudioDevice(LAudioDevice);
stb_vorbis_close(LVorbisStream);
SDL_RWclose(LRWops);
SDL_Quit;
Exit;
end;
// bind audio stream to the audio device
SDL_BindAudioStream(LAudioDevice, LAudioStream);
// start playing audio
SDL_ResumeAudioDevice(LAudioDevice);
Loop := True;
Done := FAlse;
LVolume := 1.0;
LPan := 0.0;
LCount := 0;
//PrintLn('Samples: %d', [LSamples]);
PrintLn('Channels: %d', [LInfo.channels]);
PrintLn('SampleRate: %d', [LInfo.sample_rate]);
Print(CRLF+'Press ESC to quit...');
// update audio
repeat
// decode more audio
BytesToWrite := stb_vorbis_get_samples_short_interleaved(LVorbisStream, LInfo.channels, @LInBuffer[0], CChunkSize);
if BytesToWrite > 0 then
begin
if LInfo.channels = 1 then
begin
for i := 0 to CChunkSize - 1 do
begin
LOutBuffer[i * 2] := EnsureRange(Round(LInBuffer[i] * UnitToScalarValue( (1.0 - (Lpan / 2.0 + 0.5)) * LVolume, 1)), -32768, 32767);
LOutBuffer[i * 2 + 1] :=EnsureRange(Round(LInBuffer[i] * UnitToScalarValue((Lpan / 2.0 + 0.5) * LVolume, 1)), -32768, 32767);
end;
end
else
begin
Move(LInBuffer, LOutBuffer, SizeOf(LInBuffer));
for i := 0 to CChunkSize - 1 do
begin
LOutBuffer[i * 2] := EnsureRange(Round(LOutBuffer[i * 2] * UnitToScalarValue( (1.0 - (Lpan / 2.0 + 0.5)) * LVolume, 1)), -32768, 32767);
LOutBuffer[i * 2 + 1] := EnsureRange(Round(LOutBuffer[i * 2 + 1] * UnitToScalarValue((Lpan / 2.0 + 0.5) * LVolume, 1)), -32768, 32767);
end;
end;
SDL_PutAudioStreamData(LAudioStream, @LOutBuffer[0], (BytesToWrite*(LOutAudioSpec.channels*SizeOf(SmallInt))));
end
else
begin
// prevent 100 CPU usage
Sleep(10);
if SDL_GetAudioStreamAvailable(LAudioStream) = 0 then
begin
if Loop then
begin
// seek to start of ogg
stb_vorbis_seek_start(LVorbisStream);
end
else
Done := True;
end;
end;
if WasKeyPressed(VK_ESCAPE) then
Done := True;
if WasKeyPressed(VK_RIGHT) then
begin
LPan := LPan + 0.1;
if LPan > 1.0 then LPan := 1.0;
writeln(LPan:3:2);
end
else
if WasKeyPressed(VK_LEFT) then
begin
LPan := LPan - 0.1;
if LPan < -1.0 then LPan := -1.0;
writeln(LPan:3:2);
end;
if WasKeyPressed(VK_UP) then
begin
LVolume := LVolume + 0.1;
LVolume := EnsureRange(LVolume, 0, 1);
writeln(LVolume:3:2);
end
else
if WasKeyPressed(VK_DOWN) then
begin
LVolume := LVolume - 0.1;
LVolume := EnsureRange(LVolume, 0, 1);
writeln(LVolume:3:2);
end;
until Done;
// clear audio stream
SDL_ClearAudioStream(LAudioStream);
// unbind and destroy the audio stream
SDL_UnbindAudioStream(LAudioStream);
SDL_DestroyAudioStream(LAudioStream);
// close audio device
SDL_CloseAudioDevice(LAudioDevice);
// clean up OGG stream
stb_vorbis_close(LVorbisStream);
// close RWops
SDL_RWclose(LRWops);
// quit SDL
SDL_Quit;
end;