From 54351358e17b36212872313f4a820d59f14fdf12 Mon Sep 17 00:00:00 2001 From: sanine Date: Wed, 31 Aug 2022 11:51:54 -0500 Subject: add channel sound loading --- src/channel.c | 36 ++++++++++- src/channel.h | 1 + src/channel.test.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/mossrose.c | 21 ++++++- src/sound.c | 1 + 5 files changed, 223 insertions(+), 8 deletions(-) diff --git a/src/channel.c b/src/channel.c index d039701..62e32fc 100644 --- a/src/channel.c +++ b/src/channel.c @@ -3,6 +3,7 @@ #include #include #include "channel.h" +#include "sound.h" void channel_init(struct channel_t *chan) @@ -23,9 +24,6 @@ void channel_init(struct channel_t *chan) void channel_reset(struct channel_t *chan) { p_atomic_int_set(&(chan->paused), false); - p_atomic_int_set(&(chan->volume), 255); - p_atomic_int_set(&(chan->pan_left), -128); - p_atomic_int_set(&(chan->pan_right), 128); chan->pos = 0; p_atomic_int_set(&(chan->active), false); } @@ -65,6 +63,38 @@ void channel_set_pan(struct channel_t *chan, float pan_left, float pan_right) } +int channel_sound_load(struct channel_t *chan, struct mossrose_sound_t *sound, bool force) +{ + if (!force && p_atomic_int_get(&(chan->active))) + /* active, fail! */ + return 1; + + p_mutex_lock(chan->sound_mutex); + sound_copy(&(chan->sound), sound); + chan->pos = 0; + + p_atomic_int_set(&(chan->paused), false); + + if (!force) { + /* overwrite channel settings */ + p_atomic_int_set(&(chan->volume), 255); + if (sound->mono) { + p_atomic_int_set(&(chan->pan_left), 0); + p_atomic_int_set(&(chan->pan_right), 0); + } + else { + /* stereo */ + p_atomic_int_set(&(chan->pan_left), -128); + p_atomic_int_set(&(chan->pan_right), 128); + } + } + p_mutex_unlock(chan->sound_mutex); + + p_atomic_int_set(&(chan->active), true); + return 0; +} + + #define QUARTER_PI 0.785397 static void pan_gain(float *gain_l, float *gain_r, float pan) { diff --git a/src/channel.h b/src/channel.h index ec1f645..d4ff6ee 100644 --- a/src/channel.h +++ b/src/channel.h @@ -26,6 +26,7 @@ void channel_pause(struct channel_t *chan); void channel_resume(struct channel_t *chan); void channel_set_volume(struct channel_t *chan, float volume); void channel_set_pan(struct channel_t *chan, float pan_left, float pan_right); +int channel_sound_load(struct channel_t *chan, struct mossrose_sound_t *sound, bool force); void channel_get_next_sample(float *left, float *right, struct channel_t *chan); diff --git a/src/channel.test.c b/src/channel.test.c index c0a7e73..cab741b 100644 --- a/src/channel.test.c +++ b/src/channel.test.c @@ -3,10 +3,12 @@ PMutex * mock_p_mutex_new_(); pboolean mock_p_mutex_trylock_(); +pboolean mock_p_mutex_lock_(); pboolean mock_p_mutex_unlock_(); #define p_mutex_new mock_p_mutex_new_ #define p_mutex_trylock mock_p_mutex_trylock_ +#define p_mutex_lock mock_p_mutex_lock_ #define p_mutex_unlock mock_p_mutex_unlock_ #include "channel.c" #undef p_mutex_new @@ -31,6 +33,12 @@ pboolean mock_p_mutex_trylock_(PMutex *m) return result; } +lily_mock_t *mock_p_mutex_lock = NULL; +pboolean mock_p_mutex_lock_(PMutex *m) +{ + mock_p_mutex_lock->n_calls += 1; + return TRUE; +} lily_mock_t *mock_p_mutex_unlock = NULL; pboolean mock_p_mutex_unlock_(PMutex *m) @@ -78,9 +86,6 @@ void test_channel_reset() lily_assert_int_equal(chan.pos, 0); lily_assert_int_equal(chan.active, false); lily_assert_int_equal(chan.paused, false); - lily_assert_int_equal(chan.volume, 255); - lily_assert_int_equal(chan.pan_left, -128); - lily_assert_int_equal(chan.pan_right, 128); } @@ -158,6 +163,162 @@ void test_channel_set_pan() } +void test_channel_sound_load() +{ + lily_mock_use(&mock_p_mutex_lock); + lily_mock_use(&mock_p_mutex_unlock); + + float audio_left[] = { 0.2, 0.5, 1.0 }; + float audio_right[] = { 1.0, 0.5, 0.2 }; + struct mossrose_sound_t sound; + sound.left = audio_left; + sound.right = audio_right; + sound.mono = false; + sound.len = 3; + + struct channel_t chan; + chan.active = false; + chan.sound.left = NULL; + chan.sound.right = NULL; + + int result = channel_sound_load(&chan, &sound, false); + + lily_assert_int_equal(mock_p_mutex_lock->n_calls, 1); + lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); + lily_assert_int_equal(result, 0); + + lily_assert_int_equal(chan.active, true); + lily_assert_int_equal(chan.paused, false); + lily_assert_int_equal(chan.volume, 255); + lily_assert_int_equal(chan.pan_left, -128); + lily_assert_int_equal(chan.pan_right, 128); + + lily_assert_memory_equal(chan.sound.left, audio_left, sizeof(audio_left)); + lily_assert_memory_equal(chan.sound.right, audio_right, sizeof(audio_right)); + lily_assert_int_equal(chan.sound.mono, false); + lily_assert_int_equal(chan.pos, 0); +} + + +void test_channel_sound_load_mono() +{ + lily_mock_use(&mock_p_mutex_lock); + lily_mock_use(&mock_p_mutex_unlock); + + float audio[] = { 0.2, 0.5, 1.0 }; + struct mossrose_sound_t sound; + sound.left = audio; + sound.right = NULL; + sound.mono = true; + sound.len = 3; + + struct channel_t chan; + chan.active = false; + chan.sound.left = NULL; + chan.sound.right = NULL; + + int result = channel_sound_load(&chan, &sound, false); + + lily_assert_int_equal(mock_p_mutex_lock->n_calls, 1); + lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); + lily_assert_int_equal(result, 0); + + lily_assert_int_equal(chan.active, true); + lily_assert_int_equal(chan.paused, false); + lily_assert_int_equal(chan.volume, 255); + lily_assert_int_equal(chan.pan_left, 0); + lily_assert_int_equal(chan.pan_right, 0); + + lily_assert_memory_equal(chan.sound.left, audio, sizeof(audio)); + lily_assert_null(chan.sound.right); + lily_assert_int_equal(chan.sound.mono, true); + lily_assert_int_equal(chan.pos, 0); +} + + +void test_channel_sound_load_preserve() +{ + lily_mock_use(&mock_p_mutex_lock); + lily_mock_use(&mock_p_mutex_unlock); + + float audio_left[] = { 0.2, 0.5, 1.0 }; + float audio_right[] = { 1.0, 0.5, 0.2 }; + struct mossrose_sound_t sound; + sound.left = audio_left; + sound.right = audio_right; + sound.mono = false; + sound.len = 3; + + struct channel_t chan; + chan.active = false; + chan.sound.left = NULL; + chan.sound.right = NULL; + chan.volume = 127; + chan.pan_left = 0; + chan.pan_right = 64; + + int result = channel_sound_load(&chan, &sound, true); + + lily_assert_int_equal(mock_p_mutex_lock->n_calls, 1); + lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); + lily_assert_int_equal(result, 0); + + lily_assert_int_equal(chan.active, true); + lily_assert_int_equal(chan.paused, false); + lily_assert_int_equal(chan.volume, 127); + lily_assert_int_equal(chan.pan_left, 0); + lily_assert_int_equal(chan.pan_right, 64); + + lily_assert_memory_equal(chan.sound.left, audio_left, sizeof(audio_left)); + lily_assert_memory_equal(chan.sound.right, audio_right, sizeof(audio_right)); + lily_assert_int_equal(chan.sound.mono, false); + lily_assert_int_equal(chan.pos, 0); +} + + +void test_channel_sound_fail() +{ + lily_mock_use(&mock_p_mutex_lock); + lily_mock_use(&mock_p_mutex_unlock); + + float audio_left[] = { 0.2, 0.5, 1.0 }; + float audio_right[] = { 1.0, 0.5, 0.2 }; + struct mossrose_sound_t sound; + sound.left = audio_left; + sound.right = audio_right; + sound.mono = false; + sound.len = 3; + + struct channel_t chan; + chan.active = true; + chan.paused = true; + chan.volume = 2; + chan.pan_left = 4; + chan.pan_right = 4; + chan.sound.left = NULL; + chan.sound.right = NULL; + chan.sound.mono = true; + chan.pos = 6; + + int result = channel_sound_load(&chan, &sound, false); + + lily_assert_int_equal(mock_p_mutex_lock->n_calls, 0); + lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 0); + lily_assert_int_equal(result, 1); + + lily_assert_int_equal(chan.active, true); + lily_assert_int_equal(chan.paused, true); + lily_assert_int_equal(chan.volume, 2); + lily_assert_int_equal(chan.pan_left, 4); + lily_assert_int_equal(chan.pan_right, 4); + + lily_assert_null(chan.sound.left); + lily_assert_null(chan.sound.right); + lily_assert_int_equal(chan.sound.mono, true); + lily_assert_int_equal(chan.pos, 6); +} + + /* get_next_sample tests */ void test_channel_get_next_sample_inactive() { @@ -471,6 +632,11 @@ void suite_channel() lily_run_test(test_channel_set_volume); lily_run_test(test_channel_set_pan); + lily_run_test(test_channel_sound_load); + lily_run_test(test_channel_sound_load_mono); + lily_run_test(test_channel_sound_load_preserve); + lily_run_test(test_channel_sound_fail); + lily_run_test(test_channel_get_next_sample_inactive); lily_run_test(test_channel_get_next_sample_paused); lily_run_test(test_channel_get_next_sample_normal); diff --git a/src/mossrose.c b/src/mossrose.c index 40f4393..4babfd7 100644 --- a/src/mossrose.c +++ b/src/mossrose.c @@ -6,8 +6,25 @@ #include "channel.h" -int mossrose_init(double sample_rate, int n_channels) +struct mossrose_global_t { + PaStream *stream; + struct channel_t *channels; + int n_channels; +} mossrose_global; + + +int mossrose_init(double sample_rate, int n_channels, bool init_plibsys) { + /* initialize channels */ + mossrose_global.n_channels = n_channels; + mossrose_global.channels = malloc(n_channels * sizeof(struct channel_t)); + if (mossrose_global.channels == NULL) { + fprintf("failed to allocate memory for %d channels\n", n_channels); + return 1; + } + for (int i=0; ilen = src->len; + dest->mono = src->mono; /* left channel */ if (src->left != NULL) { -- cgit v1.2.1