diff options
Diffstat (limited to 'src/audio')
| -rw-r--r-- | src/audio/audio.cc | 30 | ||||
| -rw-r--r-- | src/audio/audio.cpp | 28 | ||||
| -rw-r--r-- | src/audio/fdct.cc | 17 | ||||
| -rw-r--r-- | src/audio/fdct.cpp | 17 | ||||
| -rw-r--r-- | src/audio/idct.cc | 17 | ||||
| -rw-r--r-- | src/audio/idct.cpp | 17 | ||||
| -rw-r--r-- | src/audio/synth.cc | 179 | ||||
| -rw-r--r-- | src/audio/synth.cpp | 167 | ||||
| -rw-r--r-- | src/audio/synth.h | 12 | ||||
| -rw-r--r-- | src/audio/window.cc | 9 | ||||
| -rw-r--r-- | src/audio/window.cpp | 9 |
11 files changed, 258 insertions, 244 deletions
diff --git a/src/audio/audio.cc b/src/audio/audio.cc new file mode 100644 index 0000000..0eceed5 --- /dev/null +++ b/src/audio/audio.cc @@ -0,0 +1,30 @@ +#define MINIAUDIO_IMPLEMENTATION +#include "miniaudio.h" +#include "synth.h" +#include <math.h> + +static ma_device device; + +static void audio_callback(ma_device *, void *output, const void *, + ma_uint32 frames) { + synth_render((float *)output, frames); +} + +void audio_init() { + synth_init(); + ma_device_config cfg = ma_device_config_init(ma_device_type_playback); + cfg.playback.format = ma_format_f32; + cfg.playback.channels = 2; + cfg.sampleRate = 32000; + cfg.dataCallback = audio_callback; + + ma_device_init(nullptr, &cfg, &device); + ma_device_start(&device); +} + +void audio_update() { +} +void audio_shutdown() { + synth_shutdown(); + ma_device_uninit(&device); +} diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp deleted file mode 100644 index 318ccb8..0000000 --- a/src/audio/audio.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#define MINIAUDIO_IMPLEMENTATION -#include "miniaudio.h" -#include "synth.h" -#include <math.h> - -static ma_device device; - -static void audio_callback(ma_device*, void* output, const void*, ma_uint32 frames) { - synth_render((float*)output, frames); -} - -void audio_init() { - synth_init(); - ma_device_config cfg = ma_device_config_init(ma_device_type_playback); - cfg.playback.format = ma_format_f32; - cfg.playback.channels = 2; - cfg.sampleRate = 32000; - cfg.dataCallback = audio_callback; - - ma_device_init(nullptr, &cfg, &device); - ma_device_start(&device); -} - -void audio_update() {} -void audio_shutdown() { - synth_shutdown(); - ma_device_uninit(&device); -} diff --git a/src/audio/fdct.cc b/src/audio/fdct.cc new file mode 100644 index 0000000..5cf0211 --- /dev/null +++ b/src/audio/fdct.cc @@ -0,0 +1,17 @@ +#include "dct.h" +#include "util/math.h" +#include <math.h> + +void fdct_512(const float input[DCT_SIZE], float output[DCT_SIZE]) { + float scale_k0 = sqrtf(1.0f / DCT_SIZE); + float scale_kn = sqrtf(2.0f / DCT_SIZE); + + for (int k = 0; k < DCT_SIZE; ++k) { + float sum = 0.0f; + for (int n = 0; n < DCT_SIZE; ++n) { + sum += input[n] * cosf((PI / DCT_SIZE) * (n + 0.5f) * k); + } + float scale = (k == 0) ? scale_k0 : scale_kn; + output[k] = sum * scale; + } +} diff --git a/src/audio/fdct.cpp b/src/audio/fdct.cpp deleted file mode 100644 index 50ab458..0000000 --- a/src/audio/fdct.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "dct.h" -#include "util/math.h" -#include <math.h> - -void fdct_512(const float input[DCT_SIZE], float output[DCT_SIZE]) { - float scale_k0 = sqrtf(1.0f / DCT_SIZE); - float scale_kn = sqrtf(2.0f / DCT_SIZE); - - for (int k = 0; k < DCT_SIZE; ++k) { - float sum = 0.0f; - for (int n = 0; n < DCT_SIZE; ++n) { - sum += input[n] * cosf((PI / DCT_SIZE) * (n + 0.5f) * k); - } - float scale = (k == 0) ? scale_k0 : scale_kn; - output[k] = sum * scale; - } -} diff --git a/src/audio/idct.cc b/src/audio/idct.cc new file mode 100644 index 0000000..5d6bde0 --- /dev/null +++ b/src/audio/idct.cc @@ -0,0 +1,17 @@ +#include "dct.h" +#include "util/math.h" +#include <math.h> + +void idct_512(const float input[DCT_SIZE], float output[DCT_SIZE]) { + float scale_k0 = sqrtf(1.0f / DCT_SIZE); + float scale_kn = sqrtf(2.0f / DCT_SIZE); + + for (int n = 0; n < DCT_SIZE; ++n) { + float sum = 0.0f; + for (int k = 0; k < DCT_SIZE; ++k) { + float scale = (k == 0) ? scale_k0 : scale_kn; + sum += scale * input[k] * cosf((PI / DCT_SIZE) * (n + 0.5f) * k); + } + output[n] = sum; + } +} diff --git a/src/audio/idct.cpp b/src/audio/idct.cpp deleted file mode 100644 index a32f92e..0000000 --- a/src/audio/idct.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "dct.h" -#include "util/math.h" -#include <math.h> - -void idct_512(const float input[DCT_SIZE], float output[DCT_SIZE]) { - float scale_k0 = sqrtf(1.0f / DCT_SIZE); - float scale_kn = sqrtf(2.0f / DCT_SIZE); - - for (int n = 0; n < DCT_SIZE; ++n) { - float sum = 0.0f; - for (int k = 0; k < DCT_SIZE; ++k) { - float scale = (k == 0) ? scale_k0 : scale_kn; - sum += scale * input[k] * cosf((PI / DCT_SIZE) * (n + 0.5f) * k); - } - output[n] = sum; - } -} diff --git a/src/audio/synth.cc b/src/audio/synth.cc new file mode 100644 index 0000000..451fcdb --- /dev/null +++ b/src/audio/synth.cc @@ -0,0 +1,179 @@ +#include "synth.h" +#include "audio/window.h" +#include <atomic> +#include <string.h> // For memset + +struct Voice { + bool active; + int spectrogram_id; + float volume; + float pan_left; + float pan_right; + + int current_spectral_frame; + int total_spectral_frames; + + float time_domain_buffer[DCT_SIZE]; + int buffer_pos; + + const volatile float *active_spectral_data; +}; + +static struct { + Spectrogram spectrograms[MAX_SPECTROGRAMS]; + const volatile float *active_spectrogram_data[MAX_SPECTROGRAMS]; + bool spectrogram_registered[MAX_SPECTROGRAMS]; +} g_synth_data; + +static Voice g_voices[MAX_VOICES]; + +void synth_init() { + memset(&g_synth_data, 0, sizeof(g_synth_data)); + memset(g_voices, 0, sizeof(g_voices)); +} + +void synth_shutdown() { + // Nothing to do here since we are not allocating memory +} + +int synth_register_spectrogram(const Spectrogram *spec) { + for (int i = 0; i < MAX_SPECTROGRAMS; ++i) { + if (!g_synth_data.spectrogram_registered[i]) { + g_synth_data.spectrograms[i] = *spec; + g_synth_data.active_spectrogram_data[i] = spec->spectral_data_a; + g_synth_data.spectrogram_registered[i] = true; + return i; + } + } + return -1; // No free slots +} + +void synth_unregister_spectrogram(int spectrogram_id) { + if (spectrogram_id >= 0 && spectrogram_id < MAX_SPECTROGRAMS) { + g_synth_data.spectrogram_registered[spectrogram_id] = false; + } +} + +float *synth_begin_update(int spectrogram_id) { + if (spectrogram_id < 0 || spectrogram_id >= MAX_SPECTROGRAMS || + !g_synth_data.spectrogram_registered[spectrogram_id]) { + return nullptr; + } + + const volatile float *active_ptr = + g_synth_data.active_spectrogram_data[spectrogram_id]; + + if (active_ptr == g_synth_data.spectrograms[spectrogram_id].spectral_data_a) { + return g_synth_data.spectrograms[spectrogram_id].spectral_data_b; + } else { + return g_synth_data.spectrograms[spectrogram_id].spectral_data_a; + } +} + +void synth_commit_update(int spectrogram_id) { + if (spectrogram_id < 0 || spectrogram_id >= MAX_SPECTROGRAMS || + !g_synth_data.spectrogram_registered[spectrogram_id]) { + return; + } + + const volatile float *old_active_ptr = + g_synth_data.active_spectrogram_data[spectrogram_id]; + const float *new_active_ptr = + (old_active_ptr == + g_synth_data.spectrograms[spectrogram_id].spectral_data_a) + ? g_synth_data.spectrograms[spectrogram_id].spectral_data_b + : g_synth_data.spectrograms[spectrogram_id].spectral_data_a; + + // Atomic swap using GCC/Clang builtins for thread safety + __atomic_store_n( + (const float **)&g_synth_data.active_spectrogram_data[spectrogram_id], + new_active_ptr, __ATOMIC_RELEASE); +} + +void synth_trigger_voice(int spectrogram_id, float volume, float pan) { + if (spectrogram_id < 0 || spectrogram_id >= MAX_SPECTROGRAMS || + !g_synth_data.spectrogram_registered[spectrogram_id]) { + return; + } + + for (int i = 0; i < MAX_VOICES; ++i) { + if (!g_voices[i].active) { + Voice &v = g_voices[i]; + v.active = true; + v.spectrogram_id = spectrogram_id; + v.volume = volume; + + // Simple linear panning + v.pan_left = (pan > 0.0f) ? (1.0f - pan) : 1.0f; + v.pan_right = (pan < 0.0f) ? (1.0f + pan) : 1.0f; + + v.current_spectral_frame = 0; + v.total_spectral_frames = + g_synth_data.spectrograms[spectrogram_id].num_frames; + v.buffer_pos = DCT_SIZE; // Force IDCT on first render + v.active_spectral_data = + g_synth_data.active_spectrogram_data[spectrogram_id]; + + return; // Voice triggered + } + } +} + +void synth_render(float *output_buffer, int num_frames) { + float window[WINDOW_SIZE]; + hamming_window_512(window); + + for (int i = 0; i < num_frames; ++i) { + float left_sample = 0.0f; + float right_sample = 0.0f; + + for (int v_idx = 0; v_idx < MAX_VOICES; ++v_idx) { + Voice &v = g_voices[v_idx]; + if (!v.active) + continue; + + if (v.buffer_pos >= DCT_SIZE) { + if (v.current_spectral_frame >= v.total_spectral_frames) { + v.active = false; + continue; + } + + // Fetch the latest active spectrogram pointer for this voice + v.active_spectral_data = + g_synth_data.active_spectrogram_data[v.spectrogram_id]; + + const float *spectral_frame = (const float *)v.active_spectral_data + + (v.current_spectral_frame * DCT_SIZE); + + float windowed_frame[DCT_SIZE]; + for (int j = 0; j < DCT_SIZE; ++j) { + windowed_frame[j] = spectral_frame[j] * window[j]; + } + + idct_512(windowed_frame, v.time_domain_buffer); + + v.buffer_pos = 0; + v.current_spectral_frame++; + } + + float voice_sample = v.time_domain_buffer[v.buffer_pos] * v.volume; + left_sample += voice_sample * v.pan_left; + right_sample += voice_sample * v.pan_right; + + v.buffer_pos++; + } + + output_buffer[i * 2] = left_sample; + output_buffer[i * 2 + 1] = right_sample; + } +} + +int synth_get_active_voice_count() { + int count = 0; + for (int i = 0; i < MAX_VOICES; ++i) { + if (g_voices[i].active) { + count++; + } + } + return count; +} diff --git a/src/audio/synth.cpp b/src/audio/synth.cpp deleted file mode 100644 index 3c20b0b..0000000 --- a/src/audio/synth.cpp +++ /dev/null @@ -1,167 +0,0 @@ -#include "synth.h" -#include "audio/window.h" -#include <string.h> // For memset -#include <atomic> - -struct Voice { - bool active; - int spectrogram_id; - float volume; - float pan_left; - float pan_right; - - int current_spectral_frame; - int total_spectral_frames; - - float time_domain_buffer[DCT_SIZE]; - int buffer_pos; - - const volatile float* active_spectral_data; -}; - -static struct { - Spectrogram spectrograms[MAX_SPECTROGRAMS]; - const volatile float* active_spectrogram_data[MAX_SPECTROGRAMS]; - bool spectrogram_registered[MAX_SPECTROGRAMS]; -} g_synth_data; - -static Voice g_voices[MAX_VOICES]; - -void synth_init() { - memset(&g_synth_data, 0, sizeof(g_synth_data)); - memset(g_voices, 0, sizeof(g_voices)); -} - -void synth_shutdown() { - // Nothing to do here since we are not allocating memory -} - -int synth_register_spectrogram(const Spectrogram* spec) { - for (int i = 0; i < MAX_SPECTROGRAMS; ++i) { - if (!g_synth_data.spectrogram_registered[i]) { - g_synth_data.spectrograms[i] = *spec; - g_synth_data.active_spectrogram_data[i] = spec->spectral_data_a; - g_synth_data.spectrogram_registered[i] = true; - return i; - } - } - return -1; // No free slots -} - -void synth_unregister_spectrogram(int spectrogram_id) { - if (spectrogram_id >= 0 && spectrogram_id < MAX_SPECTROGRAMS) { - g_synth_data.spectrogram_registered[spectrogram_id] = false; - } -} - -float* synth_begin_update(int spectrogram_id) { - if (spectrogram_id < 0 || spectrogram_id >= MAX_SPECTROGRAMS || !g_synth_data.spectrogram_registered[spectrogram_id]) { - return nullptr; - } - - const volatile float* active_ptr = g_synth_data.active_spectrogram_data[spectrogram_id]; - - if (active_ptr == g_synth_data.spectrograms[spectrogram_id].spectral_data_a) { - return g_synth_data.spectrograms[spectrogram_id].spectral_data_b; - } else { - return g_synth_data.spectrograms[spectrogram_id].spectral_data_a; - } -} - -void synth_commit_update(int spectrogram_id) { - if (spectrogram_id < 0 || spectrogram_id >= MAX_SPECTROGRAMS || !g_synth_data.spectrogram_registered[spectrogram_id]) { - return; - } - - const volatile float* old_active_ptr = g_synth_data.active_spectrogram_data[spectrogram_id]; - const float* new_active_ptr = (old_active_ptr == g_synth_data.spectrograms[spectrogram_id].spectral_data_a) - ? g_synth_data.spectrograms[spectrogram_id].spectral_data_b - : g_synth_data.spectrograms[spectrogram_id].spectral_data_a; - - // Atomic swap using GCC/Clang builtins for thread safety - __atomic_store_n((const float**)&g_synth_data.active_spectrogram_data[spectrogram_id], new_active_ptr, __ATOMIC_RELEASE); -} - - -void synth_trigger_voice(int spectrogram_id, float volume, float pan) { - if (spectrogram_id < 0 || spectrogram_id >= MAX_SPECTROGRAMS || !g_synth_data.spectrogram_registered[spectrogram_id]) { - return; - } - - for (int i = 0; i < MAX_VOICES; ++i) { - if (!g_voices[i].active) { - Voice& v = g_voices[i]; - v.active = true; - v.spectrogram_id = spectrogram_id; - v.volume = volume; - - // Simple linear panning - v.pan_left = (pan > 0.0f) ? (1.0f - pan) : 1.0f; - v.pan_right = (pan < 0.0f) ? (1.0f + pan) : 1.0f; - - v.current_spectral_frame = 0; - v.total_spectral_frames = g_synth_data.spectrograms[spectrogram_id].num_frames; - v.buffer_pos = DCT_SIZE; // Force IDCT on first render - v.active_spectral_data = g_synth_data.active_spectrogram_data[spectrogram_id]; - - return; // Voice triggered - } - } -} - - -void synth_render(float* output_buffer, int num_frames) { - float window[WINDOW_SIZE]; - hamming_window_512(window); - - for (int i = 0; i < num_frames; ++i) { - float left_sample = 0.0f; - float right_sample = 0.0f; - - for (int v_idx = 0; v_idx < MAX_VOICES; ++v_idx) { - Voice& v = g_voices[v_idx]; - if (!v.active) continue; - - if (v.buffer_pos >= DCT_SIZE) { - if (v.current_spectral_frame >= v.total_spectral_frames) { - v.active = false; - continue; - } - - // Fetch the latest active spectrogram pointer for this voice - v.active_spectral_data = g_synth_data.active_spectrogram_data[v.spectrogram_id]; - - const float* spectral_frame = (const float*)v.active_spectral_data + (v.current_spectral_frame * DCT_SIZE); - - float windowed_frame[DCT_SIZE]; - for(int j=0; j<DCT_SIZE; ++j) { - windowed_frame[j] = spectral_frame[j] * window[j]; - } - - idct_512(windowed_frame, v.time_domain_buffer); - - v.buffer_pos = 0; - v.current_spectral_frame++; - } - - float voice_sample = v.time_domain_buffer[v.buffer_pos] * v.volume; - left_sample += voice_sample * v.pan_left; - right_sample += voice_sample * v.pan_right; - - v.buffer_pos++; - } - - output_buffer[i * 2] = left_sample; - output_buffer[i * 2 + 1] = right_sample; - } -} - -int synth_get_active_voice_count() { - int count = 0; - for (int i = 0; i < MAX_VOICES; ++i) { - if (g_voices[i].active) { - count++; - } - } - return count; -} diff --git a/src/audio/synth.h b/src/audio/synth.h index 17770a7..eadde10 100644 --- a/src/audio/synth.h +++ b/src/audio/synth.h @@ -6,20 +6,20 @@ #define MAX_VOICES 16 struct Spectrogram { - float* spectral_data_a; - float* spectral_data_b; - int num_frames; + float *spectral_data_a; + float *spectral_data_b; + int num_frames; }; void synth_init(); void synth_shutdown(); -int synth_register_spectrogram(const Spectrogram* spec); +int synth_register_spectrogram(const Spectrogram *spec); void synth_unregister_spectrogram(int spectrogram_id); -float* synth_begin_update(int spectrogram_id); +float *synth_begin_update(int spectrogram_id); void synth_commit_update(int spectrogram_id); void synth_trigger_voice(int spectrogram_id, float volume, float pan); -void synth_render(float* output_buffer, int num_frames); +void synth_render(float *output_buffer, int num_frames); int synth_get_active_voice_count(); diff --git a/src/audio/window.cc b/src/audio/window.cc new file mode 100644 index 0000000..d92f371 --- /dev/null +++ b/src/audio/window.cc @@ -0,0 +1,9 @@ +#include "window.h" +#include "util/math.h" +#include <math.h> + +void hamming_window_512(float window[WINDOW_SIZE]) { + for (int i = 0; i < WINDOW_SIZE; ++i) { + window[i] = 0.54f - 0.46f * cosf(2.0f * PI * i / (WINDOW_SIZE - 1)); + } +} diff --git a/src/audio/window.cpp b/src/audio/window.cpp deleted file mode 100644 index 3f36480..0000000 --- a/src/audio/window.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "window.h" -#include "util/math.h" -#include <math.h> - -void hamming_window_512(float window[WINDOW_SIZE]) { - for (int i = 0; i < WINDOW_SIZE; ++i) { - window[i] = 0.54f - 0.46f * cosf(2.0f * PI * i / (WINDOW_SIZE - 1)); - } -} |
