Make a separate demo for audio effect processors. Return information about the system audio in InitAudioDevice()
This commit is contained in:
parent
0bfa877d9d
commit
1267eafe1f
179
examples/audio/audio_effect_processor.c
Normal file
179
examples/audio/audio_effect_processor.c
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - Audio effects (streaming)
|
||||
*
|
||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define AUDIO_THREAD_MUSIC_UPDATE true
|
||||
|
||||
// a simple lowpass filter applied to the music stream
|
||||
static void processFilterEffect(float* buffer, unsigned int nframes)
|
||||
{
|
||||
static float low[2] = { 0.0f, 0.0f };
|
||||
static const float cutoff = 70.0f / 44100.0f; // 70 Hz lowpass filter
|
||||
const float k = cutoff / (cutoff + 0.1591549431f); // RC filter formula
|
||||
|
||||
for (unsigned int i = 0; i < nframes*2; i+=2)
|
||||
{
|
||||
float l = buffer[i], r = buffer[i + 1];
|
||||
low[0] += k * (l - low[0]);
|
||||
low[1] += k * (r - low[1]);
|
||||
buffer[i] = low[0];
|
||||
buffer[i + 1] = low[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float* delayBuffer = NULL;
|
||||
unsigned int delayBufferSize = 0;
|
||||
unsigned int delayReadIndex = 2;
|
||||
unsigned int delayWriteIndex = 0;
|
||||
static void processDelayEffect(float* buffer, unsigned int nframes)
|
||||
{
|
||||
for (unsigned int i = 0; i < nframes*2; i+=2)
|
||||
{
|
||||
float leftDelay = delayBuffer[delayReadIndex++];
|
||||
float rightDelay = delayBuffer[delayReadIndex++];
|
||||
if (delayReadIndex == delayBufferSize) delayReadIndex = 0;
|
||||
|
||||
buffer[i] = 0.5f * buffer[i] + 0.5f * leftDelay;
|
||||
buffer[i+1] = 0.5f * buffer[i+1] + 0.5f * rightDelay;
|
||||
|
||||
delayBuffer[delayWriteIndex++] = buffer[i];
|
||||
delayBuffer[delayWriteIndex++] = buffer[i+1];
|
||||
if (delayWriteIndex == delayBufferSize) delayWriteIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - audio effects");
|
||||
|
||||
AudioDeviceInfo audioDevice = InitAudioDevice(); // Initialize audio device
|
||||
if (!audioDevice.channels) return -1;
|
||||
|
||||
// allocate buffer for the delay effect
|
||||
delayBufferSize = audioDevice.channels * audioDevice.sampleRate; // 1s delay
|
||||
delayBuffer = (float*)RL_CALLOC(delayBufferSize, sizeof(float));
|
||||
|
||||
Music music = LoadMusicStream("resources/country.mp3");
|
||||
music.background = AUDIO_THREAD_MUSIC_UPDATE;
|
||||
|
||||
PlayMusicStream(music);
|
||||
|
||||
float timePlayed = 0.0f;
|
||||
bool pause = false;
|
||||
bool hasFilter = false;
|
||||
bool hasDelay = false;
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (!AUDIO_THREAD_MUSIC_UPDATE)
|
||||
{
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
}
|
||||
|
||||
// Restart music playing (stop and play)
|
||||
if (IsKeyPressed(KEY_SPACE))
|
||||
{
|
||||
StopMusicStream(music);
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
// Pause/Resume music playing
|
||||
if (IsKeyPressed(KEY_P))
|
||||
{
|
||||
pause = !pause;
|
||||
|
||||
if (pause) PauseMusicStream(music);
|
||||
else ResumeMusicStream(music);
|
||||
}
|
||||
|
||||
// Add/Remove effects
|
||||
if (IsKeyPressed(KEY_F))
|
||||
{
|
||||
hasFilter = !hasFilter;
|
||||
if (hasFilter)
|
||||
{
|
||||
AddAudioStreamProcessor(music.stream, &processFilterEffect);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveAudioStreamProcessor(music.stream, &processFilterEffect);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KEY_D))
|
||||
{
|
||||
hasDelay = !hasDelay;
|
||||
if (hasDelay)
|
||||
{
|
||||
AddAudioStreamProcessor(music.stream, &processDelayEffect);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveAudioStreamProcessor(music.stream, &processDelayEffect);
|
||||
}
|
||||
}
|
||||
|
||||
// Get timePlayed scaled to bar dimensions (400 pixels)
|
||||
timePlayed = GetMusicTimePlayed(music)/GetMusicTimeLength(music)*400;
|
||||
|
||||
if (timePlayed > 400) StopMusicStream(music);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, LIGHTGRAY);
|
||||
|
||||
DrawRectangle(200, 200, 400, 12, LIGHTGRAY);
|
||||
DrawRectangle(200, 200, (int)timePlayed, 12, MAROON);
|
||||
DrawRectangleLines(200, 200, 400, 12, GRAY);
|
||||
DrawRectangleLines(200, 200, 400, 12, GRAY);
|
||||
|
||||
DrawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, LIGHTGRAY);
|
||||
DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 280, 20, LIGHTGRAY);
|
||||
DrawText("PRESS F TO ADD/REMOVE FILTER EFFECT", 180, 310, 20, LIGHTGRAY);
|
||||
DrawText("PRESS D TO ADD/REMOVE DELAY EFFECT", 180, 340, 20, LIGHTGRAY);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
UnloadMusicStream(music); // Unload music stream buffers from RAM
|
||||
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
|
||||
RL_FREE(delayBuffer); // Free delay buffer
|
||||
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
examples/audio/audio_effect_processor.png
Normal file
BIN
examples/audio/audio_effect_processor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
|
|
@ -14,23 +14,6 @@
|
|||
|
||||
#define AUDIO_THREAD_MUSIC_UPDATE true
|
||||
|
||||
// a simple lowpass filter applied to the music stream
|
||||
static void audioEffectDemo(float* buffer, unsigned int nframes)
|
||||
{
|
||||
static float low[2] = { 0.0f, 0.0f };
|
||||
static const float cutoff = 70.0f / 44100.0f; // 70 Hz lowpass filter
|
||||
const float k = cutoff / (cutoff + 0.1591549431f); // RC filter formula
|
||||
|
||||
for (unsigned int i = 0; i < nframes*2; i+=2)
|
||||
{
|
||||
float l = buffer[i], r = buffer[i + 1];
|
||||
low[0] += k * (l - low[0]);
|
||||
low[1] += k * (r - low[1]);
|
||||
buffer[i] = low[0];
|
||||
buffer[i + 1] = low[1];
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Initialization
|
||||
|
|
@ -49,7 +32,6 @@ int main(void)
|
|||
|
||||
float timePlayed = 0.0f;
|
||||
bool pause = false;
|
||||
bool hasfx = false;
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
|
@ -80,20 +62,6 @@ int main(void)
|
|||
else ResumeMusicStream(music);
|
||||
}
|
||||
|
||||
// Add/Remove effect
|
||||
if (IsKeyPressed(KEY_F))
|
||||
{
|
||||
hasfx = !hasfx;
|
||||
if (hasfx)
|
||||
{
|
||||
AddAudioStreamProcessor(music.stream, &audioEffectDemo);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveAudioStreamProcessor(music.stream, &audioEffectDemo);
|
||||
}
|
||||
}
|
||||
|
||||
// Get timePlayed scaled to bar dimensions (400 pixels)
|
||||
timePlayed = GetMusicTimePlayed(music)/GetMusicTimeLength(music)*400;
|
||||
|
||||
|
|
@ -111,11 +79,9 @@ int main(void)
|
|||
DrawRectangle(200, 200, 400, 12, LIGHTGRAY);
|
||||
DrawRectangle(200, 200, (int)timePlayed, 12, MAROON);
|
||||
DrawRectangleLines(200, 200, 400, 12, GRAY);
|
||||
DrawRectangleLines(200, 200, 400, 12, GRAY);
|
||||
|
||||
DrawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, LIGHTGRAY);
|
||||
DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 280, 20, LIGHTGRAY);
|
||||
DrawText("PRESS F TO ADD/REMOVE EFFECT", 208, 310, 20, LIGHTGRAY);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
|
|||
21
src/raudio.c
21
src/raudio.c
|
|
@ -418,8 +418,13 @@ void UntrackAudioBuffer(AudioBuffer *buffer);
|
|||
// Module Functions Definition - Audio Device initialization and Closing
|
||||
//----------------------------------------------------------------------------------
|
||||
// Initialize audio device
|
||||
void InitAudioDevice(void)
|
||||
AudioDeviceInfo InitAudioDevice(void)
|
||||
{
|
||||
AudioDeviceInfo deviceInfo;
|
||||
deviceInfo.sampleRate = 0;
|
||||
deviceInfo.channels = 0;
|
||||
deviceInfo.bufferSize = 0;
|
||||
|
||||
// Init audio context
|
||||
ma_context_config ctxConfig = ma_context_config_init();
|
||||
ctxConfig.logCallback = OnLog;
|
||||
|
|
@ -428,7 +433,7 @@ void InitAudioDevice(void)
|
|||
if (result != MA_SUCCESS)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "AUDIO: Failed to initialize context");
|
||||
return;
|
||||
return deviceInfo;
|
||||
}
|
||||
|
||||
// Init audio device
|
||||
|
|
@ -449,7 +454,7 @@ void InitAudioDevice(void)
|
|||
{
|
||||
TRACELOG(LOG_WARNING, "AUDIO: Failed to initialize playback device");
|
||||
ma_context_uninit(&AUDIO.System.context);
|
||||
return;
|
||||
return deviceInfo;
|
||||
}
|
||||
|
||||
// Keep the device running the whole time. May want to consider doing something a bit smarter and only have the device running
|
||||
|
|
@ -460,7 +465,7 @@ void InitAudioDevice(void)
|
|||
TRACELOG(LOG_WARNING, "AUDIO: Failed to start playback device");
|
||||
ma_device_uninit(&AUDIO.System.device);
|
||||
ma_context_uninit(&AUDIO.System.context);
|
||||
return;
|
||||
return deviceInfo;
|
||||
}
|
||||
|
||||
// Mixing happens on a seperate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may
|
||||
|
|
@ -470,7 +475,7 @@ void InitAudioDevice(void)
|
|||
TRACELOG(LOG_WARNING, "AUDIO: Failed to create mutex for mixing");
|
||||
ma_device_uninit(&AUDIO.System.device);
|
||||
ma_context_uninit(&AUDIO.System.context);
|
||||
return;
|
||||
return deviceInfo;
|
||||
}
|
||||
|
||||
// Init dummy audio buffers pool for multichannel sound playing
|
||||
|
|
@ -489,6 +494,11 @@ void InitAudioDevice(void)
|
|||
TRACELOG(LOG_INFO, " > Periods size: %d", AUDIO.System.device.playback.internalPeriodSizeInFrames*AUDIO.System.device.playback.internalPeriods);
|
||||
|
||||
AUDIO.System.isReady = true;
|
||||
|
||||
deviceInfo.sampleRate = AUDIO.System.device.playback.internalSampleRate;
|
||||
deviceInfo.channels = AUDIO.System.device.playback.channels;
|
||||
deviceInfo.bufferSize = AUDIO.System.device.playback.internalPeriodSizeInFrames;
|
||||
return deviceInfo;
|
||||
}
|
||||
|
||||
// Close the audio device for all contexts
|
||||
|
|
@ -2195,6 +2205,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
|
|||
if (audioBuffer->audioCallback)
|
||||
{
|
||||
audioBuffer->audioCallback(framesOut, frameCount, audioBuffer->audioCallbackData);
|
||||
audioBuffer->framesProcessed += frameCount;
|
||||
return frameCount;
|
||||
}
|
||||
|
||||
|
|
|
|||
10
src/raudio.h
10
src/raudio.h
|
|
@ -114,6 +114,13 @@ typedef struct Music {
|
|||
void *ctxData; // Audio context data, depends on type
|
||||
} Music;
|
||||
|
||||
typedef struct AudioDeviceInfo
|
||||
{
|
||||
unsigned int sampleRate;
|
||||
unsigned int channels;
|
||||
unsigned int bufferSize;
|
||||
} AudioDeviceInfo;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -128,7 +135,7 @@ extern "C" { // Prevents name mangling of functions
|
|||
#endif
|
||||
|
||||
// Audio device management functions
|
||||
void InitAudioDevice(void); // Initialize audio device and context
|
||||
AudioDeviceInfo InitAudioDevice(void); // Initialize audio device and context
|
||||
void CloseAudioDevice(void); // Close the audio device and context
|
||||
bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully
|
||||
void SetMasterVolume(float volume); // Set master volume (listener)
|
||||
|
|
@ -193,6 +200,7 @@ void SetAudioStreamBufferSizeDefault(int size); // Default size
|
|||
void SetAudioStreamCallback(AudioStream stream, void callback(void*, unsigned int, void*), void* callbackData); // Audio thread callback to request new data
|
||||
void AddAudioStreamProcessor(AudioStream stream, void (*process)(float*, unsigned int));
|
||||
void RemoveAudioStreamProcessor(AudioStream stream, void (*process)(float*, unsigned int));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -453,6 +453,13 @@ typedef struct Music {
|
|||
void *ctxData; // Audio context data, depends on type
|
||||
} Music;
|
||||
|
||||
typedef struct AudioDeviceInfo
|
||||
{
|
||||
unsigned int sampleRate;
|
||||
unsigned int channels;
|
||||
unsigned int bufferSize;
|
||||
} AudioDeviceInfo;
|
||||
|
||||
// VrDeviceInfo, Head-Mounted-Display device parameters
|
||||
typedef struct VrDeviceInfo {
|
||||
int hResolution; // Horizontal resolution in pixels
|
||||
|
|
@ -1469,7 +1476,7 @@ RLAPI RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3
|
|||
//------------------------------------------------------------------------------------
|
||||
|
||||
// Audio device management functions
|
||||
RLAPI void InitAudioDevice(void); // Initialize audio device and context
|
||||
RLAPI AudioDeviceInfo InitAudioDevice(void); // Initialize audio device and context
|
||||
RLAPI void CloseAudioDevice(void); // Close the audio device and context
|
||||
RLAPI bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully
|
||||
RLAPI void SetMasterVolume(float volume); // Set master volume (listener)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user