mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 19:50:12 +01:00
Update audio.c
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
|
|
||||||
//WARNING: This is ported code from raylib's rAudio. It's also been mangled
|
// Thank you raysan for data structures
|
||||||
// with claude. I need a professional review. Thank you raysan for most of the code
|
|
||||||
// https://github.com/raysan5/raylib/blob/master/src/raudio.c
|
// https://github.com/raysan5/raylib/blob/master/src/raudio.c
|
||||||
|
// This could be cleaned up significantly. I do not think
|
||||||
|
// the audio stream structure is necessary after converting the music
|
||||||
|
// stream to portaudio
|
||||||
|
|
||||||
#include "portaudio.h"
|
#include "portaudio.h"
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
@@ -14,7 +16,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
// Logging macros
|
|
||||||
#define LOG_INFO 0
|
#define LOG_INFO 0
|
||||||
#define LOG_WARNING 1
|
#define LOG_WARNING 1
|
||||||
#define LOG_ERROR 2
|
#define LOG_ERROR 2
|
||||||
@@ -28,15 +29,12 @@
|
|||||||
fflush(stdout); \
|
fflush(stdout); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
// Memory management macros
|
|
||||||
#define FREE(ptr) do { if (ptr) { free(ptr); (ptr) = NULL; } } while(0)
|
#define FREE(ptr) do { if (ptr) { free(ptr); (ptr) = NULL; } } while(0)
|
||||||
|
|
||||||
#define AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo
|
#define AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo
|
||||||
|
|
||||||
// Forward declarations of structures
|
|
||||||
struct audio_buffer;
|
struct audio_buffer;
|
||||||
|
|
||||||
// Type definitions
|
|
||||||
typedef struct wave {
|
typedef struct wave {
|
||||||
unsigned int frameCount; // Total number of frames (considering channels)
|
unsigned int frameCount; // Total number of frames (considering channels)
|
||||||
unsigned int sampleRate; // Frequency (samples per second)
|
unsigned int sampleRate; // Frequency (samples per second)
|
||||||
@@ -45,7 +43,6 @@ typedef struct wave {
|
|||||||
void *data; // Buffer data pointer
|
void *data; // Buffer data pointer
|
||||||
} wave;
|
} wave;
|
||||||
|
|
||||||
// AudioStream, custom audio stream
|
|
||||||
typedef struct audio_stream {
|
typedef struct audio_stream {
|
||||||
struct audio_buffer *buffer; // Pointer to internal data used by the audio system
|
struct audio_buffer *buffer; // Pointer to internal data used by the audio system
|
||||||
|
|
||||||
@@ -54,13 +51,12 @@ typedef struct audio_stream {
|
|||||||
unsigned int channels; // Number of channels (1-mono, 2-stereo, ...)
|
unsigned int channels; // Number of channels (1-mono, 2-stereo, ...)
|
||||||
} audio_stream;
|
} audio_stream;
|
||||||
|
|
||||||
// Sound
|
|
||||||
typedef struct sound {
|
typedef struct sound {
|
||||||
audio_stream stream; // Audio stream
|
audio_stream stream; // Audio stream
|
||||||
unsigned int frameCount; // Total number of frames (considering channels)
|
unsigned int frameCount; // Total number of frames (considering channels)
|
||||||
} sound;
|
} sound;
|
||||||
|
|
||||||
// Music, audio stream, anything longer than ~10 seconds should be streamed
|
//anything longer than ~10 seconds should be streamed
|
||||||
typedef struct music {
|
typedef struct music {
|
||||||
audio_stream stream; // Audio stream
|
audio_stream stream; // Audio stream
|
||||||
unsigned int frameCount; // Total number of frames (considering channels)
|
unsigned int frameCount; // Total number of frames (considering channels)
|
||||||
@@ -74,7 +70,6 @@ typedef struct music_ctx {
|
|||||||
double src_ratio;
|
double src_ratio;
|
||||||
} music_ctx;
|
} music_ctx;
|
||||||
|
|
||||||
// Audio buffer structure
|
|
||||||
struct audio_buffer {
|
struct audio_buffer {
|
||||||
float volume; // Audio buffer volume
|
float volume; // Audio buffer volume
|
||||||
float pitch; // Audio buffer pitch
|
float pitch; // Audio buffer pitch
|
||||||
@@ -91,9 +86,6 @@ struct audio_buffer {
|
|||||||
struct audio_buffer *prev; // Previous audio buffer on the list
|
struct audio_buffer *prev; // Previous audio buffer on the list
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Audio data context
|
|
||||||
typedef struct AudioData {
|
typedef struct AudioData {
|
||||||
struct {
|
struct {
|
||||||
PaStream *stream; // PortAudio stream
|
PaStream *stream; // PortAudio stream
|
||||||
@@ -111,8 +103,6 @@ typedef struct AudioData {
|
|||||||
} Buffer;
|
} Buffer;
|
||||||
} AudioData;
|
} AudioData;
|
||||||
|
|
||||||
// Function declarations
|
|
||||||
// Device management
|
|
||||||
void list_host_apis(void);
|
void list_host_apis(void);
|
||||||
void init_audio_device(PaHostApiIndex host_api, double sample_rate, unsigned long buffer_size);
|
void init_audio_device(PaHostApiIndex host_api, double sample_rate, unsigned long buffer_size);
|
||||||
void close_audio_device(void);
|
void close_audio_device(void);
|
||||||
@@ -120,7 +110,6 @@ bool is_audio_device_ready(void);
|
|||||||
void set_master_volume(float volume);
|
void set_master_volume(float volume);
|
||||||
float get_master_volume(void);
|
float get_master_volume(void);
|
||||||
|
|
||||||
// Audio buffer management
|
|
||||||
struct audio_buffer *load_audio_buffer(uint32_t channels, uint32_t size_in_frames, int usage);
|
struct audio_buffer *load_audio_buffer(uint32_t channels, uint32_t size_in_frames, int usage);
|
||||||
void unload_audio_buffer(struct audio_buffer *buffer);
|
void unload_audio_buffer(struct audio_buffer *buffer);
|
||||||
bool is_audio_buffer_playing(struct audio_buffer *buffer);
|
bool is_audio_buffer_playing(struct audio_buffer *buffer);
|
||||||
@@ -134,12 +123,10 @@ void set_audio_buffer_pan(struct audio_buffer *buffer, float pan);
|
|||||||
void track_audio_buffer(struct audio_buffer *buffer);
|
void track_audio_buffer(struct audio_buffer *buffer);
|
||||||
void untrack_audio_buffer(struct audio_buffer *buffer);
|
void untrack_audio_buffer(struct audio_buffer *buffer);
|
||||||
|
|
||||||
// Wave management
|
|
||||||
wave load_wave(const char* filename);
|
wave load_wave(const char* filename);
|
||||||
bool is_wave_valid(wave wave);
|
bool is_wave_valid(wave wave);
|
||||||
void unload_wave(wave wave);
|
void unload_wave(wave wave);
|
||||||
|
|
||||||
// Sound management
|
|
||||||
sound load_sound_from_wave(wave wave);
|
sound load_sound_from_wave(wave wave);
|
||||||
sound load_sound(const char* filename);
|
sound load_sound(const char* filename);
|
||||||
bool is_sound_valid(sound sound);
|
bool is_sound_valid(sound sound);
|
||||||
@@ -153,7 +140,6 @@ void set_sound_volume(sound sound, float volume);
|
|||||||
void set_sound_pitch(sound sound, float pitch);
|
void set_sound_pitch(sound sound, float pitch);
|
||||||
void set_sound_pan(sound sound, float pan);
|
void set_sound_pan(sound sound, float pan);
|
||||||
|
|
||||||
// Audio stream management
|
|
||||||
audio_stream load_audio_stream(unsigned int sample_rate, unsigned int sample_size, unsigned int channels);
|
audio_stream load_audio_stream(unsigned int sample_rate, unsigned int sample_size, unsigned int channels);
|
||||||
void unload_audio_stream(audio_stream stream);
|
void unload_audio_stream(audio_stream stream);
|
||||||
void play_audio_stream(audio_stream stream);
|
void play_audio_stream(audio_stream stream);
|
||||||
@@ -166,7 +152,6 @@ void set_audio_stream_pitch(audio_stream stream, float pitch);
|
|||||||
void set_audio_stream_pan(audio_stream stream, float pan);
|
void set_audio_stream_pan(audio_stream stream, float pan);
|
||||||
void update_audio_stream(audio_stream stream, const void *data, int frame_count);
|
void update_audio_stream(audio_stream stream, const void *data, int frame_count);
|
||||||
|
|
||||||
// Music management
|
|
||||||
music load_music_stream(const char* filename);
|
music load_music_stream(const char* filename);
|
||||||
bool is_music_valid(music music);
|
bool is_music_valid(music music);
|
||||||
void unload_music_stream(music music);
|
void unload_music_stream(music music);
|
||||||
@@ -183,7 +168,6 @@ void set_music_pan(music music, float pan);
|
|||||||
float get_music_time_length(music music);
|
float get_music_time_length(music music);
|
||||||
float get_music_time_played(music music);
|
float get_music_time_played(music music);
|
||||||
|
|
||||||
// Internal callback
|
|
||||||
static int port_audio_callback(const void *inputBuffer, void *outputBuffer,
|
static int port_audio_callback(const void *inputBuffer, void *outputBuffer,
|
||||||
unsigned long framesPerBuffer,
|
unsigned long framesPerBuffer,
|
||||||
const PaStreamCallbackTimeInfo* timeInfo,
|
const PaStreamCallbackTimeInfo* timeInfo,
|
||||||
@@ -195,7 +179,6 @@ static AudioData AUDIO = {
|
|||||||
.System.masterVolume = 1.0f
|
.System.masterVolume = 1.0f
|
||||||
};
|
};
|
||||||
|
|
||||||
// PortAudio callback implementation
|
|
||||||
static int port_audio_callback(const void *inputBuffer, void *outputBuffer,
|
static int port_audio_callback(const void *inputBuffer, void *outputBuffer,
|
||||||
unsigned long framesPerBuffer,
|
unsigned long framesPerBuffer,
|
||||||
const PaStreamCallbackTimeInfo* timeInfo,
|
const PaStreamCallbackTimeInfo* timeInfo,
|
||||||
@@ -234,7 +217,6 @@ static int port_audio_callback(const void *inputBuffer, void *outputBuffer,
|
|||||||
if (audio_buffer->isSubBufferProcessed[currentSubBufferIndex]) {
|
if (audio_buffer->isSubBufferProcessed[currentSubBufferIndex]) {
|
||||||
// This part of the buffer is not ready, output silence
|
// This part of the buffer is not ready, output silence
|
||||||
} else {
|
} else {
|
||||||
// Mix the audio data
|
|
||||||
for (unsigned long i = 0; i < framesThisPass; i++) {
|
for (unsigned long i = 0; i < framesThisPass; i++) {
|
||||||
unsigned long buffer_pos = ((audio_buffer->frameCursorPos + i) % audio_buffer->sizeInFrames) * AUDIO_DEVICE_CHANNELS;
|
unsigned long buffer_pos = ((audio_buffer->frameCursorPos + i) % audio_buffer->sizeInFrames) * AUDIO_DEVICE_CHANNELS;
|
||||||
unsigned long output_pos = (framesPerBuffer - framesToMix + i) * AUDIO_DEVICE_CHANNELS;
|
unsigned long output_pos = (framesPerBuffer - framesToMix + i) * AUDIO_DEVICE_CHANNELS;
|
||||||
@@ -255,20 +237,15 @@ static int port_audio_callback(const void *inputBuffer, void *outputBuffer,
|
|||||||
audio_buffer->isSubBufferProcessed[currentSubBufferIndex] = true;
|
audio_buffer->isSubBufferProcessed[currentSubBufferIndex] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXED: Only stop non-streaming buffers when they reach the end
|
|
||||||
if (!audio_buffer->isStreaming && audio_buffer->frameCursorPos >= audio_buffer->sizeInFrames) {
|
if (!audio_buffer->isStreaming && audio_buffer->frameCursorPos >= audio_buffer->sizeInFrames) {
|
||||||
audio_buffer->playing = false;
|
audio_buffer->playing = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For streaming buffers, frameCursorPos can exceed sizeInFrames and that's OK
|
|
||||||
// The modulo operation handles the circular buffer access
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
audio_buffer = audio_buffer->next;
|
audio_buffer = audio_buffer->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply master volume
|
|
||||||
for (unsigned long i = 0; i < framesPerBuffer * AUDIO_DEVICE_CHANNELS; i++) {
|
for (unsigned long i = 0; i < framesPerBuffer * AUDIO_DEVICE_CHANNELS; i++) {
|
||||||
out[i] *= AUDIO.System.masterVolume;
|
out[i] *= AUDIO.System.masterVolume;
|
||||||
}
|
}
|
||||||
@@ -302,12 +279,10 @@ PaDeviceIndex get_best_output_device_for_host_api(PaHostApiIndex hostApi)
|
|||||||
return paNoDevice;
|
return paNoDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First try the default output device for this host API
|
|
||||||
if (hostApiInfo->defaultOutputDevice != paNoDevice) {
|
if (hostApiInfo->defaultOutputDevice != paNoDevice) {
|
||||||
return hostApiInfo->defaultOutputDevice;
|
return hostApiInfo->defaultOutputDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no default, find the first available output device for this host API
|
|
||||||
for (int i = 0; i < hostApiInfo->deviceCount; i++) {
|
for (int i = 0; i < hostApiInfo->deviceCount; i++) {
|
||||||
PaDeviceIndex deviceIndex = Pa_HostApiDeviceIndexToDeviceIndex(hostApi, i);
|
PaDeviceIndex deviceIndex = Pa_HostApiDeviceIndexToDeviceIndex(hostApi, i);
|
||||||
if (deviceIndex >= 0) {
|
if (deviceIndex >= 0) {
|
||||||
@@ -321,24 +296,20 @@ PaDeviceIndex get_best_output_device_for_host_api(PaHostApiIndex hostApi)
|
|||||||
return paNoDevice;
|
return paNoDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device management implementations
|
|
||||||
void init_audio_device(PaHostApiIndex host_api, double sample_rate, unsigned long buffer_size)
|
void init_audio_device(PaHostApiIndex host_api, double sample_rate, unsigned long buffer_size)
|
||||||
{
|
{
|
||||||
// Initialize PortAudio
|
|
||||||
PaError err = Pa_Initialize();
|
PaError err = Pa_Initialize();
|
||||||
if (err != paNoError) {
|
if (err != paNoError) {
|
||||||
TRACELOG(LOG_WARNING, "AUDIO: Failed to initialize PortAudio: %s", Pa_GetErrorText(err));
|
TRACELOG(LOG_WARNING, "AUDIO: Failed to initialize PortAudio: %s", Pa_GetErrorText(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize mutex for thread synchronization
|
|
||||||
if (pthread_mutex_init(&AUDIO.System.lock, NULL) != 0) {
|
if (pthread_mutex_init(&AUDIO.System.lock, NULL) != 0) {
|
||||||
TRACELOG(LOG_WARNING, "AUDIO: Failed to create mutex for mixing");
|
TRACELOG(LOG_WARNING, "AUDIO: Failed to create mutex for mixing");
|
||||||
Pa_Terminate();
|
Pa_Terminate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up output parameters
|
|
||||||
AUDIO.System.outputParameters.device = get_best_output_device_for_host_api(host_api);
|
AUDIO.System.outputParameters.device = get_best_output_device_for_host_api(host_api);
|
||||||
if (AUDIO.System.outputParameters.device == paNoDevice) {
|
if (AUDIO.System.outputParameters.device == paNoDevice) {
|
||||||
TRACELOG(LOG_WARNING, "AUDIO: No usable output device found");
|
TRACELOG(LOG_WARNING, "AUDIO: No usable output device found");
|
||||||
@@ -353,12 +324,11 @@ void init_audio_device(PaHostApiIndex host_api, double sample_rate, unsigned lon
|
|||||||
AUDIO.System.outputParameters.hostApiSpecificStreamInfo = NULL;
|
AUDIO.System.outputParameters.hostApiSpecificStreamInfo = NULL;
|
||||||
AUDIO.System.sampleRate = sample_rate;
|
AUDIO.System.sampleRate = sample_rate;
|
||||||
|
|
||||||
// Open the audio stream
|
|
||||||
err = Pa_OpenStream(&AUDIO.System.stream,
|
err = Pa_OpenStream(&AUDIO.System.stream,
|
||||||
NULL, // No input
|
NULL, // No input
|
||||||
&AUDIO.System.outputParameters, // Output parameters
|
&AUDIO.System.outputParameters, // Output parameters
|
||||||
sample_rate, // Sample rate
|
sample_rate, // Sample rate
|
||||||
buffer_size, // Frames per buffer (let PortAudio decide)
|
buffer_size, // Frames per buffer
|
||||||
paClipOff, // No clipping
|
paClipOff, // No clipping
|
||||||
port_audio_callback, // Callback function
|
port_audio_callback, // Callback function
|
||||||
NULL); // User data
|
NULL); // User data
|
||||||
@@ -370,7 +340,6 @@ void init_audio_device(PaHostApiIndex host_api, double sample_rate, unsigned lon
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the audio stream
|
|
||||||
err = Pa_StartStream(AUDIO.System.stream);
|
err = Pa_StartStream(AUDIO.System.stream);
|
||||||
if (err != paNoError) {
|
if (err != paNoError) {
|
||||||
TRACELOG(LOG_WARNING, "AUDIO: Failed to start audio stream: %s", Pa_GetErrorText(err));
|
TRACELOG(LOG_WARNING, "AUDIO: Failed to start audio stream: %s", Pa_GetErrorText(err));
|
||||||
@@ -382,7 +351,6 @@ void init_audio_device(PaHostApiIndex host_api, double sample_rate, unsigned lon
|
|||||||
|
|
||||||
AUDIO.System.isReady = true;
|
AUDIO.System.isReady = true;
|
||||||
|
|
||||||
// Log device information
|
|
||||||
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(AUDIO.System.outputParameters.device);
|
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(AUDIO.System.outputParameters.device);
|
||||||
const PaHostApiInfo *hostApiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
|
const PaHostApiInfo *hostApiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
|
||||||
|
|
||||||
@@ -398,19 +366,16 @@ void init_audio_device(PaHostApiIndex host_api, double sample_rate, unsigned lon
|
|||||||
void close_audio_device(void)
|
void close_audio_device(void)
|
||||||
{
|
{
|
||||||
if (AUDIO.System.isReady) {
|
if (AUDIO.System.isReady) {
|
||||||
// Stop the stream
|
|
||||||
PaError err = Pa_StopStream(AUDIO.System.stream);
|
PaError err = Pa_StopStream(AUDIO.System.stream);
|
||||||
if (err != paNoError) {
|
if (err != paNoError) {
|
||||||
TRACELOG(LOG_WARNING, "AUDIO: Error stopping stream: %s", Pa_GetErrorText(err));
|
TRACELOG(LOG_WARNING, "AUDIO: Error stopping stream: %s", Pa_GetErrorText(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the stream
|
|
||||||
err = Pa_CloseStream(AUDIO.System.stream);
|
err = Pa_CloseStream(AUDIO.System.stream);
|
||||||
if (err != paNoError) {
|
if (err != paNoError) {
|
||||||
TRACELOG(LOG_WARNING, "AUDIO: Error closing stream: %s", Pa_GetErrorText(err));
|
TRACELOG(LOG_WARNING, "AUDIO: Error closing stream: %s", Pa_GetErrorText(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
pthread_mutex_destroy(&AUDIO.System.lock);
|
pthread_mutex_destroy(&AUDIO.System.lock);
|
||||||
Pa_Terminate();
|
Pa_Terminate();
|
||||||
|
|
||||||
@@ -446,7 +411,6 @@ float get_master_volume(void)
|
|||||||
return volume;
|
return volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Audio buffer management implementations
|
|
||||||
struct audio_buffer *load_audio_buffer(uint32_t channels, uint32_t size_in_frames, int usage)
|
struct audio_buffer *load_audio_buffer(uint32_t channels, uint32_t size_in_frames, int usage)
|
||||||
{
|
{
|
||||||
struct audio_buffer *buffer = (struct audio_buffer*)calloc(1, sizeof(struct audio_buffer));
|
struct audio_buffer *buffer = (struct audio_buffer*)calloc(1, sizeof(struct audio_buffer));
|
||||||
@@ -479,9 +443,7 @@ struct audio_buffer *load_audio_buffer(uint32_t channels, uint32_t size_in_frame
|
|||||||
buffer->isSubBufferProcessed[1] = true;
|
buffer->isSubBufferProcessed[1] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set streaming flag based on usage parameter
|
buffer->isStreaming = (usage == 1); //1 means streaming
|
||||||
// You can define constants like: #define AUDIO_BUFFER_USAGE_STATIC 0, #define AUDIO_BUFFER_USAGE_STREAM 1
|
|
||||||
buffer->isStreaming = (usage == 1); // Assuming 1 means streaming
|
|
||||||
|
|
||||||
track_audio_buffer(buffer);
|
track_audio_buffer(buffer);
|
||||||
|
|
||||||
@@ -606,7 +568,6 @@ void untrack_audio_buffer(struct audio_buffer* buffer) {
|
|||||||
pthread_mutex_unlock(&AUDIO.System.lock);
|
pthread_mutex_unlock(&AUDIO.System.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wave management implementations
|
|
||||||
wave load_wave(const char* filename) {
|
wave load_wave(const char* filename) {
|
||||||
wave wave = { 0 };
|
wave wave = { 0 };
|
||||||
SNDFILE *snd_file;
|
SNDFILE *snd_file;
|
||||||
@@ -650,7 +611,6 @@ void unload_wave(wave wave) {
|
|||||||
FREE(wave.data);
|
FREE(wave.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sound management implementations
|
|
||||||
sound load_sound_from_wave(wave wave) {
|
sound load_sound_from_wave(wave wave) {
|
||||||
sound sound = { 0 };
|
sound sound = { 0 };
|
||||||
if (wave.data == NULL) return sound;
|
if (wave.data == NULL) return sound;
|
||||||
@@ -781,7 +741,6 @@ void set_sound_pan(sound sound, float pan) {
|
|||||||
set_audio_buffer_pan(sound.stream.buffer, pan);
|
set_audio_buffer_pan(sound.stream.buffer, pan);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Audio stream management implementations
|
|
||||||
audio_stream load_audio_stream(unsigned int sample_rate, unsigned int sample_size, unsigned int channels)
|
audio_stream load_audio_stream(unsigned int sample_rate, unsigned int sample_size, unsigned int channels)
|
||||||
{
|
{
|
||||||
audio_stream stream = { 0 };
|
audio_stream stream = { 0 };
|
||||||
@@ -790,7 +749,6 @@ audio_stream load_audio_stream(unsigned int sample_rate, unsigned int sample_siz
|
|||||||
stream.sampleSize = sample_size;
|
stream.sampleSize = sample_size;
|
||||||
stream.channels = channels;
|
stream.channels = channels;
|
||||||
|
|
||||||
// Pass 1 to indicate this is a streaming buffer
|
|
||||||
stream.buffer = load_audio_buffer(AUDIO_DEVICE_CHANNELS, AUDIO.System.sampleRate, 1);
|
stream.buffer = load_audio_buffer(AUDIO_DEVICE_CHANNELS, AUDIO.System.sampleRate, 1);
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
@@ -846,7 +804,6 @@ void update_audio_stream(audio_stream stream, const void *data, int frame_count)
|
|||||||
|
|
||||||
pthread_mutex_lock(&AUDIO.System.lock);
|
pthread_mutex_lock(&AUDIO.System.lock);
|
||||||
|
|
||||||
// For streaming, we directly update the buffer data
|
|
||||||
if (stream.buffer->data != NULL) {
|
if (stream.buffer->data != NULL) {
|
||||||
float *buffer_data = (float *)stream.buffer->data;
|
float *buffer_data = (float *)stream.buffer->data;
|
||||||
const float *input_data = (const float *)data;
|
const float *input_data = (const float *)data;
|
||||||
@@ -858,18 +815,14 @@ void update_audio_stream(audio_stream stream, const void *data, int frame_count)
|
|||||||
samples_to_copy = max_samples;
|
samples_to_copy = max_samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the data to the buffer
|
|
||||||
memcpy(buffer_data, input_data, samples_to_copy * sizeof(float));
|
memcpy(buffer_data, input_data, samples_to_copy * sizeof(float));
|
||||||
|
|
||||||
// Update the buffer size to match actual data
|
|
||||||
stream.buffer->sizeInFrames = frame_count;
|
stream.buffer->sizeInFrames = frame_count;
|
||||||
// Don't reset cursor - let the callback manage it
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&AUDIO.System.lock);
|
pthread_mutex_unlock(&AUDIO.System.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Music management implementations
|
|
||||||
music load_music_stream(const char* filename) {
|
music load_music_stream(const char* filename) {
|
||||||
music music = { 0 };
|
music music = { 0 };
|
||||||
bool music_loaded = false;
|
bool music_loaded = false;
|
||||||
@@ -902,7 +855,7 @@ music load_music_stream(const char* filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
music.ctxData = ctx;
|
music.ctxData = ctx;
|
||||||
int sample_size = 32; // We will work with floats internally
|
int sample_size = 32;
|
||||||
music.stream = load_audio_stream(AUDIO.System.sampleRate, sample_size, sf_info.channels);
|
music.stream = load_audio_stream(AUDIO.System.sampleRate, sample_size, sf_info.channels);
|
||||||
music.frameCount = (unsigned int)(sf_info.frames * ctx->src_ratio);
|
music.frameCount = (unsigned int)(sf_info.frames * ctx->src_ratio);
|
||||||
music_loaded = true;
|
music_loaded = true;
|
||||||
@@ -964,10 +917,8 @@ void seek_music_stream(music music, float position) {
|
|||||||
|
|
||||||
music_ctx *ctx = (music_ctx *)music.ctxData;
|
music_ctx *ctx = (music_ctx *)music.ctxData;
|
||||||
SNDFILE *sndFile = ctx->snd_file;
|
SNDFILE *sndFile = ctx->snd_file;
|
||||||
// Position is in output samples, so we need to convert back to input samples for seeking
|
|
||||||
unsigned int position_in_frames = (unsigned int)(position * music.stream.sampleRate / ctx->src_ratio);
|
unsigned int position_in_frames = (unsigned int)(position * music.stream.sampleRate / ctx->src_ratio);
|
||||||
|
|
||||||
// Seek the file to the new position
|
|
||||||
sf_count_t seek_result = sf_seek(sndFile, position_in_frames, SEEK_SET);
|
sf_count_t seek_result = sf_seek(sndFile, position_in_frames, SEEK_SET);
|
||||||
if (seek_result < 0) return; // Seek failed
|
if (seek_result < 0) return; // Seek failed
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user