diff --git a/examples/audio/audio_raw_stream.c b/examples/audio/audio_raw_stream.c index c9ec7a9d..9b2d1022 100644 --- a/examples/audio/audio_raw_stream.c +++ b/examples/audio/audio_raw_stream.c @@ -77,6 +77,9 @@ int main(void) { float fp = (float)(mousePosition.y); frequency = 40.0f + (float)(fp); + + float pan = (float)(mousePosition.x) / (float)screenWidth; + SetAudioStreamPan(stream, pan); } // Rewrite the sine wave. @@ -137,7 +140,7 @@ int main(void) ClearBackground(RAYWHITE); DrawText(TextFormat("sine frequency: %i",(int)frequency), GetScreenWidth() - 220, 10, 20, RED); - DrawText("click mouse button to change frequency", 10, 10, 20, DARKGRAY); + DrawText("click mouse button to change frequency or pan", 10, 10, 20, DARKGRAY); // Draw the current buffer state proportionate to the screen for (int i = 0; i < screenWidth; i++) diff --git a/src/raudio.c b/src/raudio.c index 67510dc2..57f4294f 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -317,6 +317,7 @@ struct rAudioBuffer { float volume; // Audio buffer volume float pitch; // Audio buffer pitch + float pan; // Audio buffer pan (0 to 1) bool playing; // Audio buffer state: AUDIO_PLAYING bool paused; // Audio buffer state: AUDIO_PAUSED @@ -373,7 +374,7 @@ static AudioData AUDIO = { // Global AUDIO context //---------------------------------------------------------------------------------- static void OnLog(ma_context *pContext, ma_device *pDevice, ma_uint32 logLevel, const char *message); static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const void *pFramesInput, ma_uint32 frameCount); -static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, float localVolume); +static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, AudioBuffer *buffer); #if defined(RAUDIO_STANDALONE) static bool IsFileExtension(const char *fileName, const char *ext); // Check file extension @@ -397,6 +398,7 @@ void StopAudioBuffer(AudioBuffer *buffer); void PauseAudioBuffer(AudioBuffer *buffer); void ResumeAudioBuffer(AudioBuffer *buffer); void SetAudioBufferVolume(AudioBuffer *buffer, float volume); +void SetAudioBufferPan(AudioBuffer *buffer, float pan); void SetAudioBufferPitch(AudioBuffer *buffer, float pitch); void TrackAudioBuffer(AudioBuffer *buffer); void UntrackAudioBuffer(AudioBuffer *buffer); @@ -553,6 +555,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->pan = 0.5f; + audioBuffer->playing = false; audioBuffer->paused = false; audioBuffer->looping = false; @@ -641,6 +645,12 @@ void SetAudioBufferVolume(AudioBuffer *buffer, float volume) if (buffer != NULL) buffer->volume = volume; } +// Set pan for an audio buffer +void SetAudioBufferPan(AudioBuffer *buffer, float pan) +{ + if (buffer != NULL) buffer->pan = pan; +} + // Set pitch for an audio buffer void SetAudioBufferPitch(AudioBuffer *buffer, float pitch) { @@ -1048,6 +1058,8 @@ void PlaySoundMulti(Sound sound) SetAudioBufferVolume(AUDIO.MultiChannel.pool[index], sound.stream.buffer->volume); SetAudioBufferPitch(AUDIO.MultiChannel.pool[index], sound.stream.buffer->pitch); + SetAudioBufferPan(AUDIO.MultiChannel.pool[index], sound.stream.buffer->pan); + 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; @@ -1113,6 +1125,12 @@ void SetSoundPitch(Sound sound, float pitch) SetAudioBufferPitch(sound.stream.buffer, pitch); } +// Set pan for a sound +void SetSoundPan(Sound sound, float pan) +{ + SetAudioBufferPan(sound.stream.buffer, pan); +} + // Convert wave data to desired format void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) { @@ -1809,6 +1827,12 @@ void SetMusicPitch(Music music, float pitch) SetAudioBufferPitch(music.stream.buffer, pitch); } +// Set pan for a music +void SetMusicPan(Music music, float pan) +{ + SetAudioBufferPan(music.stream.buffer, pan); +} + // Get music time length (in seconds) float GetMusicTimeLength(Music music) { @@ -1989,6 +2013,14 @@ void SetAudioStreamPitch(AudioStream stream, float pitch) SetAudioBufferPitch(stream.buffer, pitch); } +// Set pan for audio stream +void SetAudioStreamPan(AudioStream stream, float pan) +{ + if (pan < 0.0f) pan = 0.0f; else if (pan > 1.0f) pan = 1.0f; + SetAudioBufferPan(stream.buffer, pan); +} + + // Default size for new audio streams void SetAudioStreamBufferSizeDefault(int size) { @@ -2184,7 +2216,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const float *framesOut = (float *)pFramesOut + (framesRead*AUDIO.System.device.playback.channels); float *framesIn = tempBuffer; - MixAudioFrames(framesOut, framesIn, framesJustRead, audioBuffer->volume); + MixAudioFrames(framesOut, framesIn, framesJustRead, audioBuffer); framesToRead -= framesJustRead; framesRead += framesJustRead; @@ -2226,16 +2258,40 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const // This is the main mixing function. Mixing is pretty simple in this project - it's just an accumulation. // NOTE: framesOut is both an input and an output. It will be initially filled with zeros outside of this function. -static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, float localVolume) +static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, AudioBuffer *buffer) { - for (ma_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) - { - for (ma_uint32 iChannel = 0; iChannel < AUDIO.System.device.playback.channels; ++iChannel) - { - float *frameOut = framesOut + (iFrame*AUDIO.System.device.playback.channels); - const float *frameIn = framesIn + (iFrame*AUDIO.System.device.playback.channels); + const float localVolume = buffer->volume; - frameOut[iChannel] += (frameIn[iChannel]*localVolume); + const ma_uint32 nChannels = AUDIO.System.device.playback.channels; + if (nChannels == 2) + { + const float left = buffer->pan; + const float right = 1.0f - left; + + // fast sine approximation in [0..1] for pan law: y = 0.5f * x * (3 - x * x); + const float levels[2] = { localVolume*0.5f*left*(3.0f-left*left), localVolume*0.5f*right*(3.0f-right*right) }; + + float *frameOut = framesOut; + const float *frameIn = framesIn; + for (ma_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) + { + frameOut[0] += (frameIn[0]*levels[0]); + frameOut[1] += (frameIn[1]*levels[1]); + frameOut += 2; + frameIn += 2; + } + } + else // pan is kinda meaningless + { + for (ma_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) + { + for (ma_uint32 iChannel = 0; iChannel < nChannels; ++iChannel) + { + float *frameOut = framesOut + (iFrame * nChannels); + const float *frameIn = framesIn + (iFrame * nChannels); + + frameOut[iChannel] += (frameIn[iChannel] * localVolume); + } } } } diff --git a/src/raudio.h b/src/raudio.h index dbcfbd69..35c850bd 100644 --- a/src/raudio.h +++ b/src/raudio.h @@ -155,6 +155,7 @@ int GetSoundsPlaying(void); // Get number of bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) +void SetSoundPan(Sound sound, float pan); // Set pan for a sound (0.0 to 1.0, 0.5=center) void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format Wave WaveCopy(Wave wave); // Copy a wave to a new wave void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range @@ -173,6 +174,7 @@ void PauseMusicStream(Music music); // Pause music p void ResumeMusicStream(Music music); // Resume playing paused music void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds) void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) +void SetMusicPan(Music sound, float pan); // Set pan for a music (0.0 to 1.0, 0.5=center) void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) float GetMusicTimeLength(Music music); // Get music time length (in seconds) float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) @@ -189,6 +191,7 @@ bool IsAudioStreamPlaying(AudioStream stream); // Check if audi void StopAudioStream(AudioStream stream); // Stop audio stream 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 SetAudioStreamPan(AudioStream strean, float pan); // Set pan for audio stream (0.0 to 1.0, 0.5=center) void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams #ifdef __cplusplus diff --git a/src/raylib.h b/src/raylib.h index a2e3ea9c..74df758b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1498,6 +1498,7 @@ RLAPI void StopSoundMulti(void); // Stop an RLAPI int GetSoundsPlaying(void); // Get number of sounds playing in the multichannel RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) +RLAPI void SetSoundPan(Sound sound, float pan); // Set pan for a sound (0.5 = center) RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave @@ -1517,6 +1518,7 @@ RLAPI void PauseMusicStream(Music music); // Pause m RLAPI void ResumeMusicStream(Music music); // Resume playing paused music RLAPI void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds) RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) +RLAPI void SetMusicPan(Music music, float pan); // Set pan for a music (0.5 = center) RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds) RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) @@ -1533,6 +1535,7 @@ RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check i RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream 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 SetAudioStreamPan(AudioStream stream, float pan); // Set pan for audio stream (0.5 = centered) RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams #if defined(__cplusplus)