From 48e6520f6517f196a0a8f39bf86159075ad44c6b Mon Sep 17 00:00:00 2001
From: sanine <sanine.not@pm.me>
Date: Wed, 31 Aug 2022 14:34:22 -0500
Subject: finish basic implementation

---
 src/CMakeLists.txt |   1 +
 src/mossrose.c     | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 101 insertions(+), 1 deletion(-)

(limited to 'src')

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index cca9610..0453c34 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -3,6 +3,7 @@ project(mossrose)
 target_sources(mossrose PUBLIC
 	${CMAKE_CURRENT_LIST_DIR}/mossrose.c
 	${CMAKE_CURRENT_LIST_DIR}/channel.c
+	${CMAKE_CURRENT_LIST_DIR}/sound.c
 )
 
 
diff --git a/src/mossrose.c b/src/mossrose.c
index 4babfd7..fb017cd 100644
--- a/src/mossrose.c
+++ b/src/mossrose.c
@@ -13,26 +13,125 @@ struct mossrose_global_t {
 } mossrose_global;
 
 
+static int callback(
+	const void *input,
+	void *output,
+	unsigned long frame_count,
+	const PaStreamCallbackTimeInfo* time_info,
+	PaStreamCallbackFlags status_flags,
+	void *user_data)
+{
+	float *out = output;
+	float *left, *right;
+	float l, r;
+	
+	for (int i=0; i<frame_count; i++) {
+		left = out + 2*i;
+		right = left + 1;
+		*left = 0;
+		*right = 0;
+		for (int j=0; j<mossrose_global.n_channels; j++) {
+			struct channel_t *chan = mossrose_global.channels + j;
+			channel_get_next_sample(&l, &r, chan);
+			*left += l;
+			*right += r;
+		}
+	}
+	return 0;
+}
+
+
 int mossrose_init(double sample_rate, int n_channels, bool init_plibsys)
 {
+	/* optionally initialze plibsys */
+	if (init_plibsys)
+		p_libsys_init();
+
 	/* initialize channels */
 	mossrose_global.n_channels = n_channels;
 	mossrose_global.channels = malloc(n_channels * sizeof(struct channel_t));
 	if (mossrose_global.channels == NULL) {
-		fprintf("failed to allocate memory for %d channels\n", n_channels);
+		fprintf(stderr, "failed to allocate memory for %d channels\n", n_channels);
 		return 1;
 	}
 	for (int i=0; i<n_channels; i++)
 		channel_init(mossrose_global.channels + i);
 
+	PaError err;
+	/* initialize portaudio */
+	err = Pa_Initialize();
+	if (err != paNoError) {
+		fprintf(stderr, "failed to initialize portaudio\n");
+		return 2;
+	}
+
+	/* initialize stream */
+	err = Pa_OpenDefaultStream(&(mossrose_global.stream), 0, 2, paFloat32, sample_rate, 0, callback, NULL);
+	if (err != paNoError) {
+		fprintf(stderr, "failed to open audio stream!\n");
+		return 3;
+	}
+
+
+	/* start stream */
+	err = Pa_StartStream(mossrose_global.stream);
+	if (err != paNoError) {
+		fprintf(stderr, "failed to start audio stream\n");
+		return 4;
+	}
+
+	return 0;
 };
 
 
 int mossrose_play(struct mossrose_sound_t *sound, int channel)
 {
+	if (channel >= 0) {
+		/* play on specified channel */
+		if (channel_sound_load(mossrose_global.channels + channel, sound, true) == 0)
+			return channel;
+		else
+			return -1;
+	}
+	else {
+		/* 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;
+		}
+		return -1;
+	}
+}
+
+
+void mossrose_channel_set_volume(int channel, float volume) {
+	struct channel_t *chan = mossrose_global.channels + channel;
+	channel_set_volume(chan, volume);
+}
+
+
+void mossrose_channel_set_pan(int channel, float left, float right) {
+	struct channel_t *chan = mossrose_global.channels + channel;
+	channel_set_pan(chan, left, right);
+}
+
+
+void mossrose_channel_pause(int channel) {
+	struct channel_t *chan = mossrose_global.channels + channel;
+	channel_pause(chan);
+}
+
+
+void mossrose_channel_resume(int channel) {
+	struct channel_t *chan = mossrose_global.channels + channel;
+	channel_resume(chan);
 }
 
 
 int mossrose_terminate()
 {
+	Pa_AbortStream(mossrose_global.stream);
+	Pa_CloseStream(mossrose_global.stream);
+	Pa_Terminate();
+	return 0;
 }
-- 
cgit v1.2.1