Add SetAudioStreamCallback method to fill audio streams on the audio thread.
This commit is contained in:
parent
20f4d8c147
commit
9238d8e656
|
|
@ -20,6 +20,33 @@
|
||||||
#define MAX_SAMPLES 512
|
#define MAX_SAMPLES 512
|
||||||
#define MAX_SAMPLES_PER_UPDATE 4096
|
#define MAX_SAMPLES_PER_UPDATE 4096
|
||||||
|
|
||||||
|
// Cycles per second (hz)
|
||||||
|
float frequency = 440.0f;
|
||||||
|
|
||||||
|
// Audio frequency, for smoothing
|
||||||
|
float audioFrequency = 440.0f;
|
||||||
|
|
||||||
|
// Previous value, used to test if sine needs to be rewritten, and to smoothly modulate frequency
|
||||||
|
float oldFrequency = 1.0f;
|
||||||
|
|
||||||
|
// index for audio rendering
|
||||||
|
float sineIdx = 0.0f;
|
||||||
|
|
||||||
|
void audioCallback(void* buffer, unsigned int nFrames, void* callbackData)
|
||||||
|
{
|
||||||
|
audioFrequency = frequency + (audioFrequency - frequency) * 0.95f;
|
||||||
|
audioFrequency += 1.0f;
|
||||||
|
audioFrequency -= 1.0f;
|
||||||
|
float incr = audioFrequency / 44100.0f;
|
||||||
|
short* d = (short*)buffer;
|
||||||
|
for (int i = 0; i < nFrames; i++)
|
||||||
|
{
|
||||||
|
d[i] = (short)(32000.0f * sinf(2 * PI * sineIdx));
|
||||||
|
sineIdx += incr;
|
||||||
|
if (sineIdx > 1.0f) sineIdx -= 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
// Initialization
|
// Initialization
|
||||||
|
|
@ -33,9 +60,11 @@ int main(void)
|
||||||
|
|
||||||
SetAudioStreamBufferSizeDefault(MAX_SAMPLES_PER_UPDATE);
|
SetAudioStreamBufferSizeDefault(MAX_SAMPLES_PER_UPDATE);
|
||||||
|
|
||||||
// Init raw audio stream (sample rate: 22050, sample size: 16bit-short, channels: 1-mono)
|
// Init raw audio stream (sample rate: 44100, sample size: 16bit-short, channels: 1-mono)
|
||||||
AudioStream stream = LoadAudioStream(44100, 16, 1);
|
AudioStream stream = LoadAudioStream(44100, 16, 1);
|
||||||
|
|
||||||
|
SetAudioStreamCallback(stream, &audioCallback, NULL);
|
||||||
|
|
||||||
// Buffer for the single cycle waveform we are synthesizing
|
// Buffer for the single cycle waveform we are synthesizing
|
||||||
short *data = (short *)malloc(sizeof(short)*MAX_SAMPLES);
|
short *data = (short *)malloc(sizeof(short)*MAX_SAMPLES);
|
||||||
|
|
||||||
|
|
@ -47,15 +76,6 @@ int main(void)
|
||||||
// Position read in to determine next frequency
|
// Position read in to determine next frequency
|
||||||
Vector2 mousePosition = { -100.0f, -100.0f };
|
Vector2 mousePosition = { -100.0f, -100.0f };
|
||||||
|
|
||||||
// Cycles per second (hz)
|
|
||||||
float frequency = 440.0f;
|
|
||||||
|
|
||||||
// Previous value, used to test if sine needs to be rewritten, and to smoothly modulate frequency
|
|
||||||
float oldFrequency = 1.0f;
|
|
||||||
|
|
||||||
// Cursor to read and copy the samples of the sine wave buffer
|
|
||||||
int readCursor = 0;
|
|
||||||
|
|
||||||
// Computed size in samples of the sine wave
|
// Computed size in samples of the sine wave
|
||||||
int waveLength = 1;
|
int waveLength = 1;
|
||||||
|
|
||||||
|
|
@ -78,56 +98,23 @@ int main(void)
|
||||||
float fp = (float)(mousePosition.y);
|
float fp = (float)(mousePosition.y);
|
||||||
frequency = 40.0f + (float)(fp);
|
frequency = 40.0f + (float)(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite the sine wave.
|
// Rewrite the sine wave.
|
||||||
// Compute two cycles to allow the buffer padding, simplifying any modulation, resampling, etc.
|
|
||||||
if (frequency != oldFrequency)
|
if (frequency != oldFrequency)
|
||||||
{
|
{
|
||||||
// Compute wavelength. Limit size in both directions.
|
// Compute wavelength. Limit size in both directions.
|
||||||
int oldWavelength = waveLength;
|
int oldWavelength = waveLength;
|
||||||
waveLength = (int)(22050/frequency);
|
waveLength = (int)(22050 / frequency);
|
||||||
if (waveLength > MAX_SAMPLES/2) waveLength = MAX_SAMPLES/2;
|
if (waveLength > MAX_SAMPLES / 2) waveLength = MAX_SAMPLES / 2;
|
||||||
if (waveLength < 1) waveLength = 1;
|
if (waveLength < 1) waveLength = 1;
|
||||||
|
|
||||||
// Write sine wave.
|
// Write sine wave.
|
||||||
for (int i = 0; i < waveLength*2; i++)
|
for (int i = 0; i < waveLength * 2; i++)
|
||||||
{
|
{
|
||||||
data[i] = (short)(sinf(((2*PI*(float)i/waveLength)))*32000);
|
data[i] = (short)(sinf(((2 * PI * (float)i / waveLength))) * 32000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale read cursor's position to minimize transition artifacts
|
|
||||||
readCursor = (int)(readCursor * ((float)waveLength / (float)oldWavelength));
|
|
||||||
oldFrequency = frequency;
|
oldFrequency = frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refill audio stream if required
|
|
||||||
if (IsAudioStreamProcessed(stream))
|
|
||||||
{
|
|
||||||
// Synthesize a buffer that is exactly the requested size
|
|
||||||
int writeCursor = 0;
|
|
||||||
|
|
||||||
while (writeCursor < MAX_SAMPLES_PER_UPDATE)
|
|
||||||
{
|
|
||||||
// Start by trying to write the whole chunk at once
|
|
||||||
int writeLength = MAX_SAMPLES_PER_UPDATE-writeCursor;
|
|
||||||
|
|
||||||
// Limit to the maximum readable size
|
|
||||||
int readLength = waveLength-readCursor;
|
|
||||||
|
|
||||||
if (writeLength > readLength) writeLength = readLength;
|
|
||||||
|
|
||||||
// Write the slice
|
|
||||||
memcpy(writeBuf + writeCursor, data + readCursor, writeLength*sizeof(short));
|
|
||||||
|
|
||||||
// Update cursors and loop audio
|
|
||||||
readCursor = (readCursor + writeLength) % waveLength;
|
|
||||||
|
|
||||||
writeCursor += writeLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy finished frame to audio stream
|
|
||||||
UpdateAudioStream(stream, writeBuf, MAX_SAMPLES_PER_UPDATE);
|
|
||||||
}
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
|
|
@ -147,7 +134,6 @@ int main(void)
|
||||||
|
|
||||||
DrawPixelV(position, RED);
|
DrawPixelV(position, RED);
|
||||||
}
|
}
|
||||||
|
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
}
|
}
|
||||||
|
|
|
||||||
34
src/raudio.c
34
src/raudio.c
|
|
@ -315,6 +315,9 @@ typedef enum {
|
||||||
struct rAudioBuffer {
|
struct rAudioBuffer {
|
||||||
ma_data_converter converter; // Audio data converter
|
ma_data_converter converter; // Audio data converter
|
||||||
|
|
||||||
|
void (*audioCallback)(void*, unsigned int); // optional callback for filling in buffer on audio threads
|
||||||
|
void* audioCallbackData; // optional data passed to callback
|
||||||
|
|
||||||
float volume; // Audio buffer volume
|
float volume; // Audio buffer volume
|
||||||
float pitch; // Audio buffer pitch
|
float pitch; // Audio buffer pitch
|
||||||
|
|
||||||
|
|
@ -396,6 +399,7 @@ void PlayAudioBuffer(AudioBuffer *buffer);
|
||||||
void StopAudioBuffer(AudioBuffer *buffer);
|
void StopAudioBuffer(AudioBuffer *buffer);
|
||||||
void PauseAudioBuffer(AudioBuffer *buffer);
|
void PauseAudioBuffer(AudioBuffer *buffer);
|
||||||
void ResumeAudioBuffer(AudioBuffer *buffer);
|
void ResumeAudioBuffer(AudioBuffer *buffer);
|
||||||
|
void SetAudioBufferCallback(AudioBuffer* buffer, int callback(void*));
|
||||||
void SetAudioBufferVolume(AudioBuffer *buffer, float volume);
|
void SetAudioBufferVolume(AudioBuffer *buffer, float volume);
|
||||||
void SetAudioBufferPitch(AudioBuffer *buffer, float pitch);
|
void SetAudioBufferPitch(AudioBuffer *buffer, float pitch);
|
||||||
void TrackAudioBuffer(AudioBuffer *buffer);
|
void TrackAudioBuffer(AudioBuffer *buffer);
|
||||||
|
|
@ -553,6 +557,8 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
|
||||||
// Init audio buffer values
|
// Init audio buffer values
|
||||||
audioBuffer->volume = 1.0f;
|
audioBuffer->volume = 1.0f;
|
||||||
audioBuffer->pitch = 1.0f;
|
audioBuffer->pitch = 1.0f;
|
||||||
|
audioBuffer->audioCallback = NULL;
|
||||||
|
audioBuffer->audioCallbackData = NULL;
|
||||||
audioBuffer->playing = false;
|
audioBuffer->playing = false;
|
||||||
audioBuffer->paused = false;
|
audioBuffer->paused = false;
|
||||||
audioBuffer->looping = false;
|
audioBuffer->looping = false;
|
||||||
|
|
@ -635,6 +641,16 @@ void ResumeAudioBuffer(AudioBuffer *buffer)
|
||||||
if (buffer != NULL) buffer->paused = false;
|
if (buffer != NULL) buffer->paused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Audio thread callback to request new data
|
||||||
|
void SetAudioBufferCallback(AudioBuffer* buffer, void callback(void*, unsigned int, void*), void* callbackData)
|
||||||
|
{
|
||||||
|
if (buffer != NULL)
|
||||||
|
{
|
||||||
|
buffer->audioCallback = callback;
|
||||||
|
buffer->audioCallbackData = callbackData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set volume for an audio buffer
|
// Set volume for an audio buffer
|
||||||
void SetAudioBufferVolume(AudioBuffer *buffer, float volume)
|
void SetAudioBufferVolume(AudioBuffer *buffer, float volume)
|
||||||
{
|
{
|
||||||
|
|
@ -1040,6 +1056,9 @@ void PlaySoundMulti(Sound sound)
|
||||||
|
|
||||||
AUDIO.MultiChannel.pool[index]->volume = sound.stream.buffer->volume;
|
AUDIO.MultiChannel.pool[index]->volume = sound.stream.buffer->volume;
|
||||||
AUDIO.MultiChannel.pool[index]->pitch = sound.stream.buffer->pitch;
|
AUDIO.MultiChannel.pool[index]->pitch = sound.stream.buffer->pitch;
|
||||||
|
AUDIO.MultiChannel.pool[index]->audioCallback = sound.stream.buffer->audioCallback;
|
||||||
|
AUDIO.MultiChannel.pool[index]->audioCallbackData = sound.stream.buffer->audioCallbackData;
|
||||||
|
|
||||||
AUDIO.MultiChannel.pool[index]->looping = sound.stream.buffer->looping;
|
AUDIO.MultiChannel.pool[index]->looping = sound.stream.buffer->looping;
|
||||||
AUDIO.MultiChannel.pool[index]->usage = sound.stream.buffer->usage;
|
AUDIO.MultiChannel.pool[index]->usage = sound.stream.buffer->usage;
|
||||||
AUDIO.MultiChannel.pool[index]->isSubBufferProcessed[0] = false;
|
AUDIO.MultiChannel.pool[index]->isSubBufferProcessed[0] = false;
|
||||||
|
|
@ -1987,6 +2006,12 @@ void SetAudioStreamBufferSizeDefault(int size)
|
||||||
AUDIO.Buffer.defaultSize = size;
|
AUDIO.Buffer.defaultSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Audio thread callback to request new data
|
||||||
|
void SetAudioStreamCallback(AudioStream stream, void callback(void*, unsigned int, void*), void* callbackData)
|
||||||
|
{
|
||||||
|
SetAudioBufferCallback(stream.buffer, callback, callbackData);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module specific Functions Definition
|
// Module specific Functions Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -2003,6 +2028,12 @@ static void OnLog(ma_context *pContext, ma_device *pDevice, ma_uint32 logLevel,
|
||||||
// Reads audio data from an AudioBuffer object in internal format.
|
// Reads audio data from an AudioBuffer object in internal format.
|
||||||
static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, void *framesOut, ma_uint32 frameCount)
|
static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, void *framesOut, ma_uint32 frameCount)
|
||||||
{
|
{
|
||||||
|
if (audioBuffer->audioCallback)
|
||||||
|
{
|
||||||
|
audioBuffer->audioCallback(framesOut, frameCount, audioBuffer->audioCallbackData);
|
||||||
|
return frameCount;
|
||||||
|
}
|
||||||
|
|
||||||
ma_uint32 subBufferSizeInFrames = (audioBuffer->sizeInFrames > 1)? audioBuffer->sizeInFrames/2 : audioBuffer->sizeInFrames;
|
ma_uint32 subBufferSizeInFrames = (audioBuffer->sizeInFrames > 1)? audioBuffer->sizeInFrames/2 : audioBuffer->sizeInFrames;
|
||||||
ma_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames;
|
ma_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames;
|
||||||
|
|
||||||
|
|
@ -2030,7 +2061,8 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (isSubBufferProcessed[currentSubBufferIndex]) break;
|
if (isSubBufferProcessed[currentSubBufferIndex])
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ma_uint32 totalFramesRemaining = (frameCount - framesRead);
|
ma_uint32 totalFramesRemaining = (frameCount - framesRead);
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,7 @@ void StopAudioStream(AudioStream stream); // Stop audio st
|
||||||
void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
|
void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
|
||||||
void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
|
void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
|
||||||
void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams
|
void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams
|
||||||
|
void SetAudioStreamCallback(AudioStream stream, void callback(void*, unsigned int, void*), void* callbackData); // Audio thread callback to request new data
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1530,6 +1530,7 @@ RLAPI void StopAudioStream(AudioStream stream); // Stop au
|
||||||
RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
|
RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
|
||||||
RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
|
RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
|
||||||
RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams
|
RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams
|
||||||
|
RLAPI void SetAudioStreamCallback(AudioStream stream, void callback(void*, unsigned int, void*), void* callbackData); // Audio thread callback to request new data
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user