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_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)
|
||||
{
|
||||
// Initialization
|
||||
|
|
@ -33,9 +60,11 @@ int main(void)
|
|||
|
||||
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);
|
||||
|
||||
SetAudioStreamCallback(stream, &audioCallback, NULL);
|
||||
|
||||
// Buffer for the single cycle waveform we are synthesizing
|
||||
short *data = (short *)malloc(sizeof(short)*MAX_SAMPLES);
|
||||
|
||||
|
|
@ -47,15 +76,6 @@ int main(void)
|
|||
// Position read in to determine next frequency
|
||||
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
|
||||
int waveLength = 1;
|
||||
|
||||
|
|
@ -78,56 +98,23 @@ int main(void)
|
|||
float fp = (float)(mousePosition.y);
|
||||
frequency = 40.0f + (float)(fp);
|
||||
}
|
||||
|
||||
// Rewrite the sine wave.
|
||||
// Compute two cycles to allow the buffer padding, simplifying any modulation, resampling, etc.
|
||||
if (frequency != oldFrequency)
|
||||
{
|
||||
// Compute wavelength. Limit size in both directions.
|
||||
int oldWavelength = waveLength;
|
||||
waveLength = (int)(22050/frequency);
|
||||
if (waveLength > MAX_SAMPLES/2) waveLength = MAX_SAMPLES/2;
|
||||
waveLength = (int)(22050 / frequency);
|
||||
if (waveLength > MAX_SAMPLES / 2) waveLength = MAX_SAMPLES / 2;
|
||||
if (waveLength < 1) waveLength = 1;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
@ -147,7 +134,6 @@ int main(void)
|
|||
|
||||
DrawPixelV(position, RED);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
|
|
|||
34
src/raudio.c
34
src/raudio.c
|
|
@ -315,6 +315,9 @@ typedef enum {
|
|||
struct rAudioBuffer {
|
||||
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 pitch; // Audio buffer pitch
|
||||
|
||||
|
|
@ -396,6 +399,7 @@ void PlayAudioBuffer(AudioBuffer *buffer);
|
|||
void StopAudioBuffer(AudioBuffer *buffer);
|
||||
void PauseAudioBuffer(AudioBuffer *buffer);
|
||||
void ResumeAudioBuffer(AudioBuffer *buffer);
|
||||
void SetAudioBufferCallback(AudioBuffer* buffer, int callback(void*));
|
||||
void SetAudioBufferVolume(AudioBuffer *buffer, float volume);
|
||||
void SetAudioBufferPitch(AudioBuffer *buffer, float pitch);
|
||||
void TrackAudioBuffer(AudioBuffer *buffer);
|
||||
|
|
@ -553,6 +557,8 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
|
|||
// Init audio buffer values
|
||||
audioBuffer->volume = 1.0f;
|
||||
audioBuffer->pitch = 1.0f;
|
||||
audioBuffer->audioCallback = NULL;
|
||||
audioBuffer->audioCallbackData = NULL;
|
||||
audioBuffer->playing = false;
|
||||
audioBuffer->paused = false;
|
||||
audioBuffer->looping = false;
|
||||
|
|
@ -635,6 +641,16 @@ void ResumeAudioBuffer(AudioBuffer *buffer)
|
|||
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
|
||||
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]->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]->usage = sound.stream.buffer->usage;
|
||||
AUDIO.MultiChannel.pool[index]->isSubBufferProcessed[0] = false;
|
||||
|
|
@ -1987,6 +2006,12 @@ void SetAudioStreamBufferSizeDefault(int 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
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -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.
|
||||
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 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames;
|
||||
|
||||
|
|
@ -2030,7 +2061,8 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
|
|||
}
|
||||
else
|
||||
{
|
||||
if (isSubBufferProcessed[currentSubBufferIndex]) break;
|
||||
if (isSubBufferProcessed[currentSubBufferIndex])
|
||||
break;
|
||||
}
|
||||
|
||||
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 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 SetAudioStreamCallback(AudioStream stream, void callback(void*, unsigned int, void*), void* callbackData); // Audio thread callback to request new data
|
||||
|
||||
#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 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 SetAudioStreamCallback(AudioStream stream, void callback(void*, unsigned int, void*), void* callbackData); // Audio thread callback to request new data
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user