From d232fd1b3add3a93b81fc040d8b7e165590930cf Mon Sep 17 00:00:00 2001
From: sanine <sanine.not@pm.me>
Date: Sun, 28 Aug 2022 14:21:42 -0500
Subject: add channel_get_next_sample()

---
 src/channel.c        |  30 +++++++++++
 src/channel.h        |   1 +
 src/channel.test.c   | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/test/lily-test.c |  12 ++---
 4 files changed, 174 insertions(+), 6 deletions(-)

diff --git a/src/channel.c b/src/channel.c
index e6e6c3f..b9242c4 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -26,3 +26,33 @@ void channel_reset(struct channel_t *chan)
 	chan->pos = 0;
 	p_atomic_int_set(&(chan->active), false);
 }
+
+
+void channel_get_next_sample(float *left, float *right, struct channel_t *chan)
+{
+	bool active = p_atomic_int_get(&(chan->active));
+	bool paused = p_atomic_int_get(&(chan->paused));
+	if (!active || paused) {
+		/* skip this channel */
+		*left = 0;
+		*right = 0;
+		return;
+	}
+
+	if (!p_mutex_trylock(chan->sound_mutex)) {
+		/* can't lock mutex, skip */
+		*left = 0;
+		*right = 0;
+		return;
+	}
+
+	*left = chan->sound.left[chan->pos];
+	*right = chan->sound.right[chan->pos];
+	chan->pos += 1;
+
+	if (chan->pos >= chan->sound.len) {
+		channel_reset(chan);
+	}
+
+	p_mutex_unlock(chan->sound_mutex);
+}
diff --git a/src/channel.h b/src/channel.h
index 4d0800b..2bc45d2 100644
--- a/src/channel.h
+++ b/src/channel.h
@@ -21,6 +21,7 @@ struct channel_t {
 
 void channel_init(struct channel_t *chan);
 void channel_reset(struct channel_t *chan);
+void channel_get_next_sample(float *left, float *right, struct channel_t *chan);
 
 
 #endif
diff --git a/src/channel.test.c b/src/channel.test.c
index e7f7e06..532d153 100644
--- a/src/channel.test.c
+++ b/src/channel.test.c
@@ -2,12 +2,18 @@
 #include <plibsys.h>
 
 PMutex * mock_p_mutex_new_();
+pboolean mock_p_mutex_trylock_();
+pboolean mock_p_mutex_unlock_();
 
 #define p_mutex_new mock_p_mutex_new_
+#define p_mutex_trylock mock_p_mutex_trylock_
+#define p_mutex_unlock mock_p_mutex_unlock_
 #include "channel.c"
 #undef p_mutex_new
 
 
+/* ~~~~~~~~ mocks ~~~~~~~~ */
+
 lily_mock_t *mock_p_mutex_new = NULL;
 PMutex * mock_p_mutex_new_()
 {
@@ -16,6 +22,26 @@ PMutex * mock_p_mutex_new_()
 }
 
 
+lily_mock_t *mock_p_mutex_trylock = NULL;
+pboolean mock_p_mutex_trylock_(PMutex *m)
+{
+	mock_p_mutex_trylock->n_calls += 1;
+	pboolean result;
+	lily_get_value(mock_p_mutex_trylock, pboolean, &result);
+	return result;
+}
+
+
+lily_mock_t *mock_p_mutex_unlock = NULL;
+pboolean mock_p_mutex_unlock_(PMutex *m)
+{
+	mock_p_mutex_unlock->n_calls += 1;
+	return TRUE;
+}
+
+
+/* ~~~~~~~~ tests ~~~~~~~~ */
+
 void test_channel_init()
 {
 	lily_mock_use(&mock_p_mutex_new);
@@ -55,10 +81,121 @@ void test_channel_reset()
 }
 
 
+void test_channel_get_next_sample_inactive()
+{
+	lily_mock_use(&mock_p_mutex_trylock);
+	lily_mock_use(&mock_p_mutex_unlock);
+
+	struct channel_t chan;
+	chan.active = false;
+	chan.pos = 0;
+	float l = 22; float r = 22;
+	channel_get_next_sample(&l, &r, &chan);
+
+	lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 0);
+	lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 0);
+	lily_assert_int_equal(chan.pos, 0);
+	lily_assert_float_equal(l, 0.0f, 0.1f);
+	lily_assert_float_equal(r, 0.0f, 0.1f);
+}
+
+
+void test_channel_get_next_sample_paused()
+{
+	lily_mock_use(&mock_p_mutex_trylock);
+	lily_mock_use(&mock_p_mutex_unlock);
+
+	struct channel_t chan;
+	chan.active = true;
+	chan.paused = true;
+	chan.pos = 0;
+	float l = 22; float r = 22;
+	channel_get_next_sample(&l, &r, &chan);
+
+	lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 0);
+	lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 0);
+	lily_assert_int_equal(chan.pos, 0);
+	lily_assert_float_equal(l, 0.0f, 0.1f);
+	lily_assert_float_equal(r, 0.0f, 0.1f);
+}
+
+
+void test_channel_get_next_sample_nolock()
+{
+	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.pos = 0;
+	float l = 22; float r = 22;
+
+	lily_store_value(mock_p_mutex_trylock, pboolean, FALSE);
+	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, 0);
+
+	lily_assert_int_equal(chan.pos, 0);
+	lily_assert_float_equal(l, 0.0f, 0.1f);
+	lily_assert_float_equal(r, 0.0f, 0.1f);
+}
+
+
+void test_channel_get_next_sample_normal()
+{
+	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 = 0;
+	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.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, 1.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.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, 1.0f, 0.1f);
+	lily_assert_float_equal(r, 0.0f, 0.1f);
+}
+
+
 void suite_channel()
 {
 	lily_run_test(test_channel_init);
 	lily_run_test(test_channel_reset);
+	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);
+	lily_run_test(test_channel_get_next_sample_nolock);
 
 	lily_mock_destroy(mock_p_mutex_new);
 }
diff --git a/src/test/lily-test.c b/src/test/lily-test.c
index 2f43a28..a8381d0 100644
--- a/src/test/lily-test.c
+++ b/src/test/lily-test.c
@@ -209,7 +209,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,
+	lily_assert_msg(abs(a - b) <= epsilon, location,
 			"%s (%f) is not equal to %s (%f) (epsilon: %f)",
 			name_a, a, name_b, b, epsilon);
 }
@@ -218,7 +218,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,
+	lily_assert_msg(abs(a - b) > epsilon, location,
 			"%s (%f) is equal to %s (%f) (epsilon: %f)",
 			name_a, a, name_b, b, epsilon);
 }
@@ -227,7 +227,7 @@ void _lily_assert_float_not_equal(const char *name_a, const char *name_b,
 void _lily_assert_string_equal(const char *name_a, const char *name_b,
 					 char *a, char *b, const char *location)
 {
-	lily_assert_msg(strcmp(a, b) == 0,
+	lily_assert_msg(strcmp(a, b) == 0, location,
 			"%s ('%s') is not equal to %s ('%s')",
 			name_a, a, name_b, b);
 }
@@ -236,7 +236,7 @@ void _lily_assert_string_equal(const char *name_a, const char *name_b,
 void _lily_assert_string_not_equal(const char *name_a, const char *name_b,
 					char *a, char *b, const char *location)
 {
-	lily_assert_msg(strcmp(a, b) != 0,
+	lily_assert_msg(strcmp(a, b) != 0, location,
 			"%s ('%s') is equal to %s",
 			name_a, a, name_b);
 }
@@ -245,7 +245,7 @@ void _lily_assert_string_not_equal(const char *name_a, const char *name_b,
 void _lily_assert_memory_equal(const char *name_a, const char *name_b,
 					 void *a, void *b, size_t size, const char *location)
 {
-	lily_assert_msg(memcmp(a, b, size) == 0,
+	lily_assert_msg(memcmp(a, b, size) == 0, location,
 			"%s and %s contain different data", name_a, name_b);
 }
 
@@ -253,7 +253,7 @@ void _lily_assert_memory_equal(const char *name_a, const char *name_b,
 void _lily_assert_memory_not_equal(const char *name_a, const char *name_b,
 					void *a, void *b, size_t size, const char *location)
 {
-	lily_assert_msg(memcmp(a, b, size) == 0,
+	lily_assert_msg(memcmp(a, b, size) == 0, location,
 			"%s contains the same data s %s", name_a, name_b);
 }
 
-- 
cgit v1.2.1