From eb4e4cab2d3f24ee7f8d0be7149162084fe98392 Mon Sep 17 00:00:00 2001 From: sanine Date: Tue, 30 Aug 2022 23:46:40 -0500 Subject: add mono panning --- CMakeLists.txt | 4 ++-- src/channel.c | 33 ++++++++++++++++++++++-------- src/channel.test.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++--- src/test/lily-test.c | 5 +++-- 4 files changed, 85 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 76ef10d..16b27d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ set_target_properties(mossrose PROPERTIES VERSION ${PROJECT_VERSION} PUBLIC_HEADER src/mossrose.h ) -target_link_libraries(mossrose portaudio plibsys) +target_link_libraries(mossrose portaudio plibsys m) if (MOSSROSE_BUILD_EXAMPLES) @@ -32,7 +32,7 @@ endif() if (MOSSROSE_BUILD_TESTS) add_executable(test) - target_link_libraries(test plibsys) + target_link_libraries(test plibsys m) endif() diff --git a/src/channel.c b/src/channel.c index 2fd0324..a29e7f7 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1,5 +1,6 @@ #include #include +#include #include #include "channel.h" @@ -64,6 +65,15 @@ void channel_set_pan(struct channel_t *chan, float pan_left, float pan_right) } +#define QUARTER_PI 0.785397 +static void pan_gain(float *gain_l, float *gain_r, float pan) +{ + float theta = (QUARTER_PI * pan) + QUARTER_PI; /* 0-PI/2 */ + *gain_l = cos(theta); + *gain_r = sin(theta); +} + + void channel_get_next_sample(float *left, float *right, struct channel_t *chan) { bool active = p_atomic_int_get(&(chan->active)); @@ -82,17 +92,24 @@ void channel_get_next_sample(float *left, float *right, struct channel_t *chan) return; } - float l, r; + float volume = ((float)p_atomic_int_get(&(chan->volume)))/255; - l = chan->sound.left[chan->pos]; - if (chan->sound.mono) - r = l; - else + if (chan->sound.mono) { + float x = chan->sound.left[chan->pos]; + float pan = ((float)p_atomic_int_get(&(chan->pan_left)))/128; + float gain_l, gain_r; + pan_gain(&gain_l, &gain_r, pan); + *left = volume * gain_l * x; + *right = volume * gain_r * x; + } + else { + float l, r; + l = chan->sound.left[chan->pos]; r = chan->sound.right[chan->pos]; + *left = volume * l; + *right = volume * r; + } - 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.test.c b/src/channel.test.c index 427fd63..150adb9 100644 --- a/src/channel.test.c +++ b/src/channel.test.c @@ -336,20 +336,71 @@ void test_channel_get_next_sample_mono() float l, r; + const float gain = 0.7071; /* constant-power panning center gain */ + 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_assert_float_equal(l, gain * 0.0f, 0.1f); + lily_assert_float_equal(r, gain * 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, gain * 0.5f, 0.1f); + lily_assert_float_equal(r, gain * 0.5f, 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, gain * 1.0f, 0.1f); + lily_assert_float_equal(r, gain * 1.0f, 0.1f); +} + + +void test_channel_get_next_sample_mono_panned() +{ + 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 = -128; + 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; + + const float gain = 0.7071; /* constant-power panning center gain */ + + 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, gain * 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.5f, 0.1f); lily_assert_float_equal(r, 0.0f, 0.1f); lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); @@ -358,7 +409,7 @@ void test_channel_get_next_sample_mono() 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(l, 1.0f, 0.1f); lily_assert_float_equal(r, 0.0f, 0.1f); } @@ -379,6 +430,7 @@ void suite_channel() 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_run_test(test_channel_get_next_sample_mono_panned); lily_mock_destroy(mock_p_mutex_new); } diff --git a/src/test/lily-test.c b/src/test/lily-test.c index a8381d0..30f96d5 100644 --- a/src/test/lily-test.c +++ b/src/test/lily-test.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "lily-test.h" struct lily_globals_t _lily_globals = { {0}, 0, NULL, "" }; @@ -209,7 +210,7 @@ void _lily_assert_int_not_equal(const char *name_a, const char *name_b, void _lily_assert_float_equal(const char *name_a, const char *name_b, double a, double b, double epsilon, const char *location) { - lily_assert_msg(abs(a - b) <= epsilon, location, + lily_assert_msg(fabs(a - b) <= epsilon, location, "%s (%f) is not equal to %s (%f) (epsilon: %f)", name_a, a, name_b, b, epsilon); } @@ -218,7 +219,7 @@ void _lily_assert_float_equal(const char *name_a, const char *name_b, void _lily_assert_float_not_equal(const char *name_a, const char *name_b, double a, double b, double epsilon, const char *location) { - lily_assert_msg(abs(a - b) > epsilon, location, + lily_assert_msg(fabs(a - b) > epsilon, location, "%s (%f) is equal to %s (%f) (epsilon: %f)", name_a, a, name_b, b, epsilon); } -- cgit v1.2.1