summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2022-09-03 21:32:25 -0500
committersanine <sanine.not@pm.me>2022-09-03 21:32:25 -0500
commit2cf000fb7cbe653c2e96e0b3b8f3c1425401d3fc (patch)
treee172ef67b253d1eaa0fb22186b5901edd4de793a
parenta416cfb6881b8ff99c29ba87c1d940d6143e44b1 (diff)
add looping
-rw-r--r--examples/CMakeLists.txt5
-rw-r--r--examples/example.c6
-rw-r--r--examples/loop.c40
-rw-r--r--examples/panning.c2
-rw-r--r--include/mossrose.h2
-rw-r--r--src/channel.c10
-rw-r--r--src/channel.h3
-rw-r--r--src/channel.test.c56
-rw-r--r--src/mossrose.c7
9 files changed, 108 insertions, 23 deletions
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 <stdio.h>
+#include <math.h>
+#include <mossrose.h>
+#include <portaudio.h>
+
+#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; i<SAMPLE_RATE; i++) {
+ float time = ((float)i)/SAMPLE_RATE;
+ data[i] = sin(2*PI*f(time)*time);
+ }
+
+ struct mossrose_sound_t sound = {
+ .left = data, .right = NULL, .mono = true, .len = SAMPLE_RATE
+ };
+
+ int err = mossrose_init(SAMPLE_RATE, N_CHANNELS, true);
+ if (err != 0)
+ fprintf(stderr, "FAILED TO INITIALIZE MOSSROSE\n");
+
+ int chan = mossrose_play(&sound, -1, 5);
+ Pa_Sleep(5000);
+
+ mossrose_terminate();
+ return 0;
+}
diff --git a/examples/panning.c b/examples/panning.c
index 485833a..b63727b 100644
--- a/examples/panning.c
+++ b/examples/panning.c
@@ -28,7 +28,7 @@ int main()
Pa_Sleep(500);
- int chan = mossrose_play(&sound, -1);
+ int chan = mossrose_play(&sound, -1, 1);
for (int i=0; i<8000; i++) {
float time = ((float)i)/1000;
diff --git a/include/mossrose.h b/include/mossrose.h
index 81f71db..72f7b99 100644
--- a/include/mossrose.h
+++ b/include/mossrose.h
@@ -15,7 +15,7 @@ int mossrose_init(double sample_rate, int n_channels, bool init_plibsys);
int mossrose_terminate();
-int mossrose_play(struct mossrose_sound_t *sound, int channel);
+int mossrose_play(struct mossrose_sound_t *sound, int channel, int loops);
void mossrose_channel_set_volume(int channel, float volume);
void mossrose_channel_set_pan(int channel, float left, float right);
void mossrose_channel_pause(int channel);
diff --git a/src/channel.c b/src/channel.c
index 1d0b63b..8615265 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -25,7 +25,12 @@ void channel_init(struct channel_t *chan)
void channel_reset(struct channel_t *chan)
{
- p_atomic_int_set(&(chan->shared.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<mossrose_global.n_channels; i++) {
struct channel_t *chan = mossrose_global.channels + i;
- if (channel_sound_load(chan, sound, false) == 0) return i;
+ if (channel_sound_load(chan, sound, false, loops) == 0) return i;
}
return -1;
}