Make a separate demo for audio effect processors. Return information about the system audio in InitAudioDevice()

This commit is contained in:
ptarabbia 2021-12-16 09:18:59 -05:00
parent 0bfa877d9d
commit 1267eafe1f
6 changed files with 212 additions and 41 deletions

View 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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -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();
//----------------------------------------------------------------------------------

View File

@ -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;
}

View File

@ -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

View File

@ -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)