From 2cf000fb7cbe653c2e96e0b3b8f3c1425401d3fc Mon Sep 17 00:00:00 2001 From: sanine Date: Sat, 3 Sep 2022 21:32:25 -0500 Subject: add looping --- examples/CMakeLists.txt | 5 +++++ examples/example.c | 6 +++--- examples/loop.c | 40 +++++++++++++++++++++++++++++++++++ examples/panning.c | 2 +- include/mossrose.h | 2 +- src/channel.c | 10 +++++++-- src/channel.h | 3 ++- src/channel.test.c | 56 +++++++++++++++++++++++++++++++++++++++---------- src/mossrose.c | 7 +++---- 9 files changed, 108 insertions(+), 23 deletions(-) create mode 100644 examples/loop.c diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 46e02d4..7fe2030 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,3 +8,8 @@ add_dependencies(examples example) add_executable(panning ${CMAKE_CURRENT_LIST_DIR}/panning.c) target_link_libraries(panning mossrose) add_dependencies(examples panning) + + +add_executable(loop ${CMAKE_CURRENT_LIST_DIR}/loop.c) +target_link_libraries(loop mossrose) +add_dependencies(examples loop) diff --git a/examples/example.c b/examples/example.c index 5e65d82..eefc41d 100644 --- a/examples/example.c +++ b/examples/example.c @@ -35,17 +35,17 @@ int main() Pa_Sleep(500); printf("play 1\n"); - mossrose_play(&sound_512, -1); + mossrose_play(&sound_512, -1, 1); printf("wait\n"); Pa_Sleep(1000); printf("play 2\n"); - mossrose_play(&sound_440, -1); + mossrose_play(&sound_440, -1, 1); printf("wait\n"); Pa_Sleep(500); printf("play 3\n"); - mossrose_play(&sound_512, -1); + mossrose_play(&sound_512, -1, 1); printf("wait\n"); Pa_Sleep(1000); diff --git a/examples/loop.c b/examples/loop.c new file mode 100644 index 0000000..1be04a9 --- /dev/null +++ b/examples/loop.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include + +#define PI 3.14159 + + +#define SAMPLE_RATE 44100 +#define N_CHANNELS 8 + +float f(float t) +{ + const int f0 = 440; + const int f1 = 880; + return ( t*f1 ) + ( (1-t)*f0 ); +} + +int main() +{ + float data[SAMPLE_RATE]; + for (long i=0; ishared.active), false); + chan->pos = 0; + int loops = channel_atomic_get(chan->shared.loops); + if (loops) { + if (p_atomic_int_dec_and_test(&(chan->shared.loops))) + channel_atomic_set(chan->shared.active, false); + } } @@ -63,7 +68,7 @@ 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) +int channel_sound_load(struct channel_t *chan, struct mossrose_sound_t *sound, bool force, int loops) { if (!force && channel_atomic_get(chan->shared.active)) /* active, fail! */ @@ -74,6 +79,7 @@ int channel_sound_load(struct channel_t *chan, struct mossrose_sound_t *sound, b chan->pos = 0; p_atomic_int_set(&(chan->shared.paused), false); + p_atomic_int_set(&(chan->shared.loops), loops); if (!force) { /* overwrite channel settings */ diff --git a/src/channel.h b/src/channel.h index ae9c24b..5be42a2 100644 --- a/src/channel.h +++ b/src/channel.h @@ -13,6 +13,7 @@ struct channel_shared_t { volatile pint volume; /* 0-255 */ volatile pint pan_left; /* -255-255 */ volatile pint pan_right; /* -255-255 */ + volatile pint loops; }; @@ -34,7 +35,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); +int channel_sound_load(struct channel_t *chan, struct mossrose_sound_t *sound, bool force, int loops); 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 4591b43..067879f 100644 --- a/src/channel.test.c +++ b/src/channel.test.c @@ -71,15 +71,11 @@ void test_channel_init() } -void test_channel_reset() +void test_channel_reset_last_loop() { struct channel_t chan; - chan.pos = 255; chan.shared.active = true; - chan.shared.paused = true; - chan.shared.volume = 5; - chan.shared.pan_left = 30; - chan.shared.pan_right = 30; + chan.shared.loops = 1; channel_reset(&chan); @@ -87,6 +83,36 @@ void test_channel_reset() } +void test_channel_reset_penultimate_loop() +{ + struct channel_t chan; + chan.shared.active = true; + chan.shared.loops = 2; + chan.pos = 98; + + channel_reset(&chan); + + lily_assert_int_equal(chan.shared.active, true); + lily_assert_int_equal(chan.shared.loops, 1); + lily_assert_int_equal(chan.pos, 0); +} + + +void test_channel_reset_infinite_loop() +{ + struct channel_t chan; + chan.shared.active = true; + chan.shared.loops = 0; + chan.pos = 17; + + channel_reset(&chan); + + lily_assert_int_equal(chan.shared.active, true); + lily_assert_int_equal(chan.shared.loops, 0); + lily_assert_int_equal(chan.pos, 0); +} + + void test_channel_pause() { struct channel_t chan; @@ -180,7 +206,7 @@ void test_channel_sound_load() chan.sound.right = NULL; chan.pos = 5; - int result = channel_sound_load(&chan, &sound, false); + int result = channel_sound_load(&chan, &sound, false, 1); lily_assert_int_equal(mock_p_mutex_lock->n_calls, 1); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); @@ -216,7 +242,7 @@ void test_channel_sound_load_mono() chan.sound.left = NULL; chan.sound.right = NULL; - int result = channel_sound_load(&chan, &sound, false); + int result = channel_sound_load(&chan, &sound, false, 1); lily_assert_int_equal(mock_p_mutex_lock->n_calls, 1); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); @@ -256,7 +282,7 @@ void test_channel_sound_load_preserve() chan.shared.pan_left = 0; chan.shared.pan_right = 64; - int result = channel_sound_load(&chan, &sound, true); + int result = channel_sound_load(&chan, &sound, true, 1); lily_assert_int_equal(mock_p_mutex_lock->n_calls, 1); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); @@ -299,7 +325,7 @@ void test_channel_sound_fail() chan.sound.mono = true; chan.pos = 6; - int result = channel_sound_load(&chan, &sound, false); + int result = channel_sound_load(&chan, &sound, false, 1); lily_assert_int_equal(mock_p_mutex_lock->n_calls, 0); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 0); @@ -391,6 +417,7 @@ void test_channel_get_next_sample_normal() struct channel_t chan; chan.shared.active = true; chan.shared.paused = false; + chan.shared.loops = 1; chan.shared.volume = 255; chan.shared.pan_left = -128; chan.shared.pan_right = 128; @@ -441,6 +468,7 @@ void test_channel_get_next_sample_volume_0() struct channel_t chan; chan.shared.active = true; chan.shared.paused = false; + chan.shared.loops = 1; chan.shared.volume = 0; chan.shared.pan_left = -128; chan.shared.pan_right = 128; @@ -491,6 +519,7 @@ void test_channel_get_next_sample_mono() struct channel_t chan; chan.shared.active = true; chan.shared.paused = false; + chan.shared.loops = 1; chan.shared.volume = 255; chan.shared.pan_left = 0; chan.shared.pan_right = 128; @@ -542,6 +571,7 @@ void test_channel_get_next_sample_mono_panned() struct channel_t chan; chan.shared.active = true; chan.shared.paused = false; + chan.shared.loops = 1; chan.shared.volume = 255; chan.shared.pan_left = -128; chan.shared.pan_right = 128; @@ -591,6 +621,7 @@ void test_channel_get_next_sample_panned() struct channel_t chan; chan.shared.active = true; chan.shared.paused = false; + chan.shared.loops = 1; chan.shared.volume = 255; chan.shared.pan_left = 128; chan.shared.pan_right = 0; @@ -638,12 +669,15 @@ void test_channel_get_next_sample_panned() void suite_channel() { lily_run_test(test_channel_init); - lily_run_test(test_channel_reset); lily_run_test(test_channel_pause); lily_run_test(test_channel_resume); lily_run_test(test_channel_set_volume); lily_run_test(test_channel_set_pan); + lily_run_test(test_channel_reset_last_loop); + lily_run_test(test_channel_reset_penultimate_loop); + lily_run_test(test_channel_reset_infinite_loop); + lily_run_test(test_channel_sound_load); lily_run_test(test_channel_sound_load_mono); lily_run_test(test_channel_sound_load_preserve); diff --git a/src/mossrose.c b/src/mossrose.c index 04770f5..cd1b98d 100644 --- a/src/mossrose.c +++ b/src/mossrose.c @@ -21,7 +21,6 @@ static int callback( PaStreamCallbackFlags status_flags, void *user_data) { - printf("frame count: %d\n", frame_count); float *out = output; float *left, *right; float l, r; @@ -88,11 +87,11 @@ int mossrose_init(double sample_rate, int n_channels, bool init_plibsys) }; -int mossrose_play(struct mossrose_sound_t *sound, int channel) +int mossrose_play(struct mossrose_sound_t *sound, int channel, int loops) { if (channel >= 0) { /* play on specified channel */ - if (channel_sound_load(mossrose_global.channels + channel, sound, true) == 0) + if (channel_sound_load(mossrose_global.channels + channel, sound, true, loops) == 0) return channel; else return -1; @@ -101,7 +100,7 @@ int mossrose_play(struct mossrose_sound_t *sound, int channel) /* play on first available channel */ for (int i=0; i