From 489c3771e648d412cab283c660996c880149315d Mon Sep 17 00:00:00 2001 From: sanine Date: Tue, 30 Aug 2022 22:25:43 -0500 Subject: refactor: use stereo panning model --- include/mossrose.h | 2 + src/channel.c | 31 ++++++++--- src/channel.h | 11 ++-- src/channel.test.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 162 insertions(+), 33 deletions(-) diff --git a/include/mossrose.h b/include/mossrose.h index 5ca454a..44d5477 100644 --- a/include/mossrose.h +++ b/include/mossrose.h @@ -2,10 +2,12 @@ #define MOSSROSE_H #include +#include struct mossrose_sound_t { float *left; float *right; + bool mono; size_t len; }; diff --git a/src/channel.c b/src/channel.c index 603a980..2fd0324 100644 --- a/src/channel.c +++ b/src/channel.c @@ -9,7 +9,8 @@ void channel_init(struct channel_t *chan) chan->active = false; chan->paused = false; chan->volume = 255; - chan->pan = 0; + chan->pan_left = -128; + chan->pan_right = 128; chan->sound_mutex = p_mutex_new(); chan->sound.left = NULL; @@ -22,7 +23,8 @@ 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), 0); + 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); } @@ -49,12 +51,16 @@ void channel_set_volume(struct channel_t *chan, float volume) } -void channel_set_pan(struct channel_t *chan, float pan) +void channel_set_pan(struct channel_t *chan, float pan_left, float pan_right) { - if (pan > 1.0f) pan = 1.0f; - if (pan < -1.0f) pan = -1.0f; + if (pan_left > 1.0f) pan_left = 1.0f; + if (pan_left < -1.0f) pan_left = -1.0f; - p_atomic_int_set(&(chan->pan), 128*pan); + if (pan_right > 1.0f) pan_right = 1.0f; + if (pan_right < -1.0f) pan_right = -1.0f; + + p_atomic_int_set(&(chan->pan_left), 128*pan_left); + p_atomic_int_set(&(chan->pan_right), 128*pan_right); } @@ -76,8 +82,17 @@ void channel_get_next_sample(float *left, float *right, struct channel_t *chan) return; } - *left = chan->sound.left[chan->pos]; - *right = chan->sound.right[chan->pos]; + float l, r; + + l = chan->sound.left[chan->pos]; + if (chan->sound.mono) + r = l; + else + r = chan->sound.right[chan->pos]; + + float volume = ((float)p_atomic_int_get(&(chan->active)))/255; + *left = volume * l; + *right = volume * r; chan->pos += 1; if (chan->pos >= chan->sound.len) { diff --git a/src/channel.h b/src/channel.h index 6f06803..ec1f645 100644 --- a/src/channel.h +++ b/src/channel.h @@ -8,10 +8,11 @@ struct channel_t { - volatile pint active; /* boolean */ - volatile pint paused; /* boolean */ - volatile pint volume; /* 0-255 */ - volatile pint pan; /* -128-128 */ + volatile pint active; /* boolean */ + volatile pint paused; /* boolean */ + volatile pint volume; /* 0-255 */ + volatile pint pan_left; /* -128-128 */ + volatile pint pan_right; /* -128-128 */ PMutex *sound_mutex; struct mossrose_sound_t sound; @@ -24,7 +25,7 @@ void channel_reset(struct channel_t *chan); 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); +void channel_set_pan(struct channel_t *chan, float pan_left, float pan_right); 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 2c5cdad..427fd63 100644 --- a/src/channel.test.c +++ b/src/channel.test.c @@ -54,7 +54,8 @@ void test_channel_init() 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, 0); + lily_assert_int_equal(chan.pan_left, -128); + lily_assert_int_equal(chan.pan_right, 128); lily_assert_null(chan.sound.left); lily_assert_null(chan.sound.right); @@ -69,7 +70,8 @@ void test_channel_reset() chan.active = true; chan.paused = true; chan.volume = 5; - chan.pan = 30; + chan.pan_left = 30; + chan.pan_right = 30; channel_reset(&chan); @@ -77,7 +79,8 @@ void test_channel_reset() 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, 0); + lily_assert_int_equal(chan.pan_left, -128); + lily_assert_int_equal(chan.pan_right, 128); } @@ -126,24 +129,32 @@ void test_channel_set_volume() void test_channel_set_pan() { struct channel_t chan; - chan.pan = 255; - - channel_set_pan(&chan, -1.0f); - lily_assert_int_equal(chan.pan, -128); - channel_set_pan(&chan, -0.5f); - lily_assert_int_equal(chan.pan, -64); - channel_set_pan(&chan, 0.0f); - lily_assert_int_equal(chan.pan, 0); - channel_set_pan(&chan, 0.5f); - lily_assert_int_equal(chan.pan, 64); - channel_set_pan(&chan, 1.0f); - lily_assert_int_equal(chan.pan, 128); + chan.pan_left = 255; + chan.pan_right = 255; + + channel_set_pan(&chan, -1.0f, 1.0f); + lily_assert_int_equal(chan.pan_left, -128); + lily_assert_int_equal(chan.pan_right, 128); + channel_set_pan(&chan, -0.5f, 0.5f); + lily_assert_int_equal(chan.pan_left, -64); + lily_assert_int_equal(chan.pan_right, 64); + channel_set_pan(&chan, 0.0f, 0.0f); + lily_assert_int_equal(chan.pan_left, 0); + lily_assert_int_equal(chan.pan_right, 0); + channel_set_pan(&chan, 0.5f, -0.5f); + lily_assert_int_equal(chan.pan_left, 64); + lily_assert_int_equal(chan.pan_right, -64); + channel_set_pan(&chan, 1.0f, -1.0f); + lily_assert_int_equal(chan.pan_left, 128); + lily_assert_int_equal(chan.pan_right, -128); /* oob */ - channel_set_pan(&chan, -10.0f); - lily_assert_int_equal(chan.pan, -128); - channel_set_pan(&chan, 2.0f); - lily_assert_int_equal(chan.pan, 128); + channel_set_pan(&chan, -10.0f, 2.0f); + lily_assert_int_equal(chan.pan_left, -128); + lily_assert_int_equal(chan.pan_right, 128); + channel_set_pan(&chan, 2.0f, -10.0f); + lily_assert_int_equal(chan.pan_left, 128); + lily_assert_int_equal(chan.pan_right, -128); } @@ -218,11 +229,13 @@ void test_channel_get_next_sample_normal() chan.active = true; chan.paused = false; chan.volume = 255; - chan.pan = 0; + chan.pan_left = -128; + chan.pan_right = 128; float audio_left[] = { 0.0, 0.5, 1.0 }; float audio_right[] = { 1.0, 0.5, 0.0 }; chan.sound.left = audio_left; chan.sound.right = audio_right; + chan.sound.mono = false; chan.sound.len = 3; chan.pos = 0; @@ -255,6 +268,102 @@ void test_channel_get_next_sample_normal() } +void test_channel_get_next_sample_volume_0() +{ + lily_mock_use(&mock_p_mutex_trylock); + lily_mock_use(&mock_p_mutex_unlock); + + struct channel_t chan; + chan.active = true; + chan.paused = false; + chan.volume = 0; + chan.pan_left = -128; + chan.pan_right = 128; + float audio_left[] = { 0.0, 0.5, 1.0 }; + float audio_right[] = { 1.0, 0.5, 0.0 }; + chan.sound.left = audio_left; + chan.sound.right = audio_right; + chan.sound.mono = false; + chan.sound.len = 3; + chan.pos = 0; + + float l, r; + + lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); + channel_get_next_sample(&l, &r, &chan); + lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 1); + lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); + lily_assert_int_equal(chan.pos, 1); + lily_assert_float_equal(l, 0.0f, 0.1f); + lily_assert_float_equal(r, 0.0f, 0.1f); + + lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); + channel_get_next_sample(&l, &r, &chan); + lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 2); + lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 2); + lily_assert_int_equal(chan.pos, 2); + lily_assert_float_equal(l, 0.0f, 0.1f); + lily_assert_float_equal(r, 0.0f, 0.1f); + + lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); + channel_get_next_sample(&l, &r, &chan); + lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 3); + lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 3); + lily_assert_int_equal(chan.pos, 0); + lily_assert_int_equal(chan.active, false); + lily_assert_float_equal(l, 0.0f, 0.1f); + lily_assert_float_equal(r, 0.0f, 0.1f); +} + + +void test_channel_get_next_sample_mono() +{ + lily_mock_use(&mock_p_mutex_trylock); + lily_mock_use(&mock_p_mutex_unlock); + + struct channel_t chan; + chan.active = true; + chan.paused = false; + chan.volume = 255; + chan.pan_left = 0; + chan.pan_right = 128; + float audio[] = { 0.0, 0.5, 1.0 }; + chan.sound.left = audio; + chan.sound.right = NULL; + chan.sound.mono = true; + chan.sound.len = 3; + chan.pos = 0; + + float l, r; + + lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); + channel_get_next_sample(&l, &r, &chan); + lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 1); + lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); + lily_assert_int_equal(chan.pos, 1); + lily_assert_float_equal(l, 0.0f, 0.1f); + lily_assert_float_equal(r, 0.0f, 0.1f); + + lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); + channel_get_next_sample(&l, &r, &chan); + lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 2); + lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 2); + lily_assert_int_equal(chan.pos, 2); + lily_assert_float_equal(l, 0.0f, 0.1f); + lily_assert_float_equal(r, 0.0f, 0.1f); + + lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); + channel_get_next_sample(&l, &r, &chan); + lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 3); + lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 3); + lily_assert_int_equal(chan.pos, 0); + lily_assert_int_equal(chan.active, false); + lily_assert_float_equal(l, 0.0f, 0.1f); + lily_assert_float_equal(r, 0.0f, 0.1f); +} + + + void suite_channel() { lily_run_test(test_channel_init); @@ -268,6 +377,8 @@ void suite_channel() lily_run_test(test_channel_get_next_sample_paused); lily_run_test(test_channel_get_next_sample_normal); lily_run_test(test_channel_get_next_sample_nolock); + lily_run_test(test_channel_get_next_sample_volume_0); + lily_run_test(test_channel_get_next_sample_mono); lily_mock_destroy(mock_p_mutex_new); } -- cgit v1.2.1