summaryrefslogtreecommitdiff
path: root/src/mossrose.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mossrose.c')
-rw-r--r--src/mossrose.c110
1 files changed, 93 insertions, 17 deletions
diff --git a/src/mossrose.c b/src/mossrose.c
index fdaa10c..02f063a 100644
--- a/src/mossrose.c
+++ b/src/mossrose.c
@@ -1,17 +1,67 @@
#include <stdio.h>
+#include <stdlib.h>
#include <portaudio.h>
#include "mossrose.h"
+#include "mossrose-mutex.h"
+#include "mossrose-channel.h"
-PaStream *stream;
-
+/* ~~~~~~~~~~~~~~~~ type definitions ~~~~~~~~~~~~~~~~ */
+/* audio output */
struct audio_output_t {
float l;
float r;
};
+
+/* ~~~~~~~~~~~~~~~~ globals ~~~~~~~~~~~~~~~~ */
+
+struct mossrose_globals_t {
+ PaStream *stream;
+ struct mossrose_channel_t *channels;
+ int n_channels;
+} mossrose_global;
+
+
+struct audio_output_t build_sample()
+{
+ struct audio_output_t out;
+ out.l = 0; out.r = 0;
+
+ /* loop variables */
+ struct mossrose_channel_t *chan;
+ float chan_l, chan_r;
+
+ for (int i=0; i<mossrose_global.n_channels; i++) {
+ chan = mossrose_global.channels + i;
+ if (mossrose_mutex_trylock(&(chan->mutex)) != 0) {
+ /* can't lock the mutex, this channel is being modified */
+ printf("can't lock channel %d\n", i);
+ continue;
+ }
+
+ if (chan->n_samples == 0) {
+ /* channel is not currently in use, skip */
+ }
+ else {
+ if (mossrose_channel_advance(&chan_l, &chan_r, chan) != 0)
+ /* channel is done playing, reset */
+ mossrose_channel_reset(chan);
+ else {
+ out.l += chan_l;
+ out.r += chan_r;
+ }
+ }
+
+ mossrose_mutex_unlock(&(chan->mutex));
+ }
+
+ return out;
+}
+
+
static int callback(
const void *input,
void *output,
@@ -19,39 +69,49 @@ static int callback(
const PaStreamCallbackTimeInfo *time_info,
void *userdata)
{
- static float left = 0;
- static float right = 0;
-
struct audio_output_t *out = output;
+ struct audio_output_t sample;
+
for (int i=0; i<frame_count; i++) {
- out[i].l = left;
- out[i].r = right;
- left += 0.01;
- right += 0.03;
- if (left > 1) left -= 2;
- if (right > 1) right -= 2;
+ sample = build_sample();
+ out[i].l = sample.l;
+ out[i].r = sample.r;
}
return 0;
}
-int mr_init(double sample_rate, int n_channels)
+int mossrose_init(double sample_rate, int n_channels)
{
+ /* initialize channels */
+ mossrose_global.n_channels = n_channels;
+ mossrose_global.channels = malloc(n_channels * sizeof(struct mossrose_channel_t));
+ if (mossrose_global.channels == NULL) {
+ fprintf(stderr, "failed to allocate memory for %d channels", n_channels);
+ return 1;
+ }
+ for (int i=0; i<n_channels; i++) {
+ mossrose_channel_init(mossrose_global.channels + i);
+ }
+
PaError err;
+ /* initialize portaudio */
err = Pa_Initialize();
if (err != paNoError) {
fprintf(stderr, "failed to initialize PortAudio!\n");
return 1;
}
- err = Pa_OpenDefaultStream(&stream, 0, 2, paFloat32, sample_rate, 0, callback, NULL);
+ /* open 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 1;
}
- err = Pa_StartStream(stream);
+ /* start stream */
+ err = Pa_StartStream(mossrose_global.stream);
if (err != paNoError) {
fprintf(stderr, "failed to start audio stream!\n");
return 1;
@@ -61,10 +121,26 @@ int mr_init(double sample_rate, int n_channels)
};
-int mr_terminate(double sample_rate, int n_channels)
+int mossrose_play(float *left, float *right, size_t len, int channel)
+{
+ if (channel > 0) {
+ return mossrose_channel_set(mossrose_global.channels+channel, left, right, len, 1);
+ }
+ else {
+ struct mossrose_channel_t *chan;
+ for (int i=0; i<mossrose_global.n_channels; i++) {
+ chan = mossrose_global.channels + i;
+ if (mossrose_channel_set(chan, left, right, len, 0) == 0) return 0;
+ }
+ return 1;
+ }
+}
+
+
+int mossrose_terminate(double sample_rate, int n_channels)
{
- Pa_AbortStream(stream);
- Pa_CloseStream(stream);
+ Pa_AbortStream(mossrose_global.stream);
+ Pa_CloseStream(mossrose_global.stream);
Pa_Terminate();
return 0;
}