diff --git a/build/rtbuf_signal/Makefile b/build/rtbuf_signal/Makefile
index 4bbd92d..c11dba1 100644
--- a/build/rtbuf_signal/Makefile
+++ b/build/rtbuf_signal/Makefile
@@ -7,9 +7,10 @@ CFLAGS = -O0 -ggdb -W -Wall -Werror -fpic
LDFLAGS = -fPIC -shared
LIBS = -lm
-HEADERS = rtbuf_defs.h rtbuf_type.h rtbuf_fun.h rtbuf.h rtbuf_lib.h \
- rtbuf_music.h rtbuf_signal.h
-OBJECTS = rtbuf_signal.o rtbuf_signal_sinus.o rtbuf_signal_square.o
+HEADERS = symbol.h rtbuf_defs.h rtbuf_type.h rtbuf_fun.h rtbuf.h \
+ rtbuf_lib.h rtbuf_music.h rtbuf_signal.h
+OBJECTS = symbol.o rtbuf_signal.o rtbuf_signal_sinus.o \
+ rtbuf_signal_square.o rtbuf_signal_synth.o
SRC = ${HEADERS} ${OBJECTS:%.o=%.c}
diff --git a/build/rtbuf_sndio/Makefile b/build/rtbuf_sndio/Makefile
index 39b87c0..d743ee0 100644
--- a/build/rtbuf_sndio/Makefile
+++ b/build/rtbuf_sndio/Makefile
@@ -7,8 +7,8 @@ CFLAGS = -O0 -ggdb -W -Wall -Werror -fpic
LDFLAGS = -fPIC -shared
LIBS = -lsndio
-HEADERS = rtbuf_defs.h rtbuf_type.h rtbuf_fun.h rtbuf.h rtbuf_lib.h \
- rtbuf_music.h rtbuf_signal.h rtbuf_sndio.h
+HEADERS = symbol.h rtbuf_defs.h rtbuf_type.h rtbuf_fun.h rtbuf.h \
+ rtbuf_lib.h rtbuf_music.h rtbuf_signal.h rtbuf_sndio.h
OBJECTS = rtbuf_sndio.o rtbuf_sndio_input.o rtbuf_sndio_output.o
SRC = ${HEADERS} ${OBJECTS:%.o=%.c}
diff --git a/rtbuf.c b/rtbuf.c
index a5ca52d..093d849 100644
--- a/rtbuf.c
+++ b/rtbuf.c
@@ -2,6 +2,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <strings.h>
#include "rtbuf.h"
#include "rtbuf_lib.h"
@@ -76,6 +77,20 @@ void rtbuf_delete (s_rtbuf *rtb)
g_rtbuf_sort = 1;
}
+int rtbuf_clone (s_rtbuf *rtb)
+{
+ int i = rtbuf_new(rtb->fun);
+ unsigned int j = 0;
+ if (i < 0)
+ return -1;
+ while (j < rtb->fun->var_n) {
+ g_rtbuf[i].var[j] = rtb->var[j];
+ j++;
+ }
+ g_rtbuf[i].var_n = rtb->var_n;
+ return i;
+}
+
void rtbuf_var_unbind (s_rtbuf *rtb, unsigned int var)
{
s_rtbuf_binding *rb = &rtb->var[var];
@@ -107,6 +122,18 @@ void rtbuf_unbind (s_rtbuf *rtb)
rtbuf_var_unbind(rtb, i);
}
+int rtbuf_data_set (s_rtbuf *rtb, symbol name, void *value,
+ unsigned int size)
+{
+ s_rtbuf_fun_out *out = rtbuf_fun_out_find(rtb->fun, name);
+ if (out && out->type->size == size) {
+ void *data = rtb->data + out->offset;
+ memcpy(data, value, size);
+ return size;
+ }
+ return 0;
+}
+
typedef struct rtbuf_var_ptr {
unsigned int rtb;
unsigned int var;
diff --git a/rtbuf.h b/rtbuf.h
index 0f2bca5..6f401bf 100644
--- a/rtbuf.h
+++ b/rtbuf.h
@@ -34,20 +34,23 @@ extern unsigned int g_rtbuf_sort;
extern int g_rtbuf_sorted[];
extern unsigned int g_rtbuf_sorted_n;
-int rtbuf_init ();
-void rtbuf_delete (s_rtbuf *rtb);
int rtbuf_err (const char *msg);
-int rtbuf_find (const char *x);
-int rtbuf_out_find (s_rtbuf *rtb, const char *x);
+int rtbuf_init ();
int rtbuf_new (s_rtbuf_fun *rf);
-void rtbuf_run ();
-void rtbuf_sort ();
-void rtbuf_start();
-void rtbuf_stop();
+void rtbuf_delete (s_rtbuf *rtb);
+int rtbuf_clone (s_rtbuf *rtb);
+int rtbuf_find (symbol sym);
+int rtbuf_out_find (s_rtbuf *rtb, symbol sym);
void rtbuf_unbind (s_rtbuf *rtb);
void rtbuf_var_unbind (s_rtbuf *rtb, unsigned int var);
void rtbuf_var_bind (s_rtbuf *rtb, unsigned int var,
unsigned int target, unsigned int target_out);
+int rtbuf_data_set (s_rtbuf *rtb, symbol name, void *value,
+ unsigned int size);
+void rtbuf_sort ();
+void rtbuf_start();
+void rtbuf_run ();
+void rtbuf_stop();
static inline double min (double a, double b)
{
diff --git a/rtbuf_fun.c b/rtbuf_fun.c
index f613caf..e9c32f4 100644
--- a/rtbuf_fun.c
+++ b/rtbuf_fun.c
@@ -98,3 +98,15 @@ s_rtbuf_fun * rtbuf_fun_find (const char *x)
}
return 0;
}
+
+s_rtbuf_fun_out * rtbuf_fun_out_find (s_rtbuf_fun *fun,
+ symbol name)
+{
+ unsigned int i = 0;
+ while (i < fun->out_n) {
+ if (name == fun->out[i].name)
+ return &fun->out[i];
+ i++;
+ }
+ return 0;
+}
diff --git a/rtbuf_fun.h b/rtbuf_fun.h
index 19254b8..fb20f97 100644
--- a/rtbuf_fun.h
+++ b/rtbuf_fun.h
@@ -2,14 +2,15 @@
#define RTBUF_FUN_H
#include "rtbuf_defs.h"
+#include "symbol.h"
struct rtbuf_fun_var {
- const char *name; /* symbol */
+ symbol name;
s_rtbuf_type *type;
};
struct rtbuf_fun_out {
- const char *name; /* symbol */
+ symbol name;
s_rtbuf_type *type;
unsigned int offset;
};
@@ -18,7 +19,7 @@ struct rtbuf_fun_out {
#define RTBUF_FUN_OUT_MAX 32
struct rtbuf_fun {
- const char *name; /* symbol */
+ symbol name;
f_rtbuf_fun *f;
f_rtbuf_fun *start;
f_rtbuf_fun *stop;
@@ -35,10 +36,12 @@ struct rtbuf_fun {
extern s_rtbuf_fun g_rtbuf_fun[RTBUF_FUN_MAX];
extern unsigned int g_rtbuf_fun_n;
-extern void rtbuf_fun_init ();
-extern int rtbuf_fun_p (s_rtbuf_fun *fun);
-extern s_rtbuf_fun * rtbuf_fun_new (s_rtbuf_lib_fun *x);
-extern void rtbuf_fun_delete (s_rtbuf_fun *fun);
-extern s_rtbuf_fun * rtbuf_fun_find (const char *x);
+extern void rtbuf_fun_init ();
+extern int rtbuf_fun_p (s_rtbuf_fun *fun);
+extern s_rtbuf_fun * rtbuf_fun_new (s_rtbuf_lib_fun *x);
+extern void rtbuf_fun_delete (s_rtbuf_fun *fun);
+extern s_rtbuf_fun * rtbuf_fun_find (const char *x);
+extern s_rtbuf_fun_out * rtbuf_fun_out_find (s_rtbuf_fun *fun,
+ symbol name);
#endif
diff --git a/rtbuf_music.c b/rtbuf_music.c
index a2e7c87..ae58317 100644
--- a/rtbuf_music.c
+++ b/rtbuf_music.c
@@ -53,3 +53,23 @@ void rtbuf_music_notes_dt (s_rtbuf_music_notes *notes, double dt)
}
}
}
+
+s_rtbuf_music_notes * rtbuf_music_notes (s_rtbuf *rtb,
+ unsigned int var)
+{
+ s_rtbuf_binding *v = &rtb->var[var];
+ s_rtbuf *target;
+ void *data;
+ if (v->rtb < 0)
+ return 0;
+ target = &g_rtbuf[v->rtb];
+ //if (v->out >= target->fun->out_n)
+ data = target->data + target->fun->out[v->out].offset;
+ return (s_rtbuf_music_notes*) data;
+}
+
+int rtbuf_music_note_p (s_rtbuf_music_note *note)
+{
+ return (note && note->freq > 0.0 && note->velocity > 0.0 &&
+ note->start >= 0.0);
+}
diff --git a/rtbuf_music.h b/rtbuf_music.h
index 45b611e..cd55445 100644
--- a/rtbuf_music.h
+++ b/rtbuf_music.h
@@ -19,8 +19,13 @@ typedef struct rtbuf_music_notes {
void rtbuf_music_notes_init (s_rtbuf_music_notes *notes);
int rtbuf_music_notes_new (s_rtbuf_music_notes *notes);
-void rtbuf_music_notes_delete (s_rtbuf_music_notes *notes, unsigned int i);
+void rtbuf_music_notes_delete (s_rtbuf_music_notes *notes,
+ unsigned int i);
void rtbuf_music_notes_dt (s_rtbuf_music_notes *notes, double dt);
+int rtbuf_music_note_p (s_rtbuf_music_note *note);
void rtbuf_music_note_dt (s_rtbuf_music_note *note, double dt);
+s_rtbuf_music_notes * rtbuf_music_notes (s_rtbuf *rtb,
+ unsigned int var);
+
#endif
diff --git a/rtbuf_signal.c b/rtbuf_signal.c
index 05be336..0813268 100644
--- a/rtbuf_signal.c
+++ b/rtbuf_signal.c
@@ -27,6 +27,19 @@ s_rtbuf_lib_fun_out g_rtbuf_signal_square_out[] = {
{ "phase", "double" },
{ 0, 0 } };
+s_rtbuf_lib_fun_var g_rtbuf_signal_adsr_var[] = {
+ { "attack", RTBUF_SIGNAL_TYPE },
+ { "decay", RTBUF_SIGNAL_TYPE },
+ { "sustain", RTBUF_SIGNAL_TYPE },
+ { "release", RTBUF_SIGNAL_TYPE },
+ { 0, 0 } };
+
+s_rtbuf_lib_fun_out g_rtbuf_signal_adsr_out[] = {
+ { "signal", RTBUF_SIGNAL_TYPE },
+ { "start", "double" },
+ { "stop", "double" },
+ { 0, 0 } };
+
s_rtbuf_lib_fun_var g_rtbuf_signal_synth_var[] = {
{ "keyboard", RTBUF_MUSIC_NOTES_TYPE },
{ "envelope", RTBUF_SIGNAL_TYPE },
@@ -45,6 +58,8 @@ s_rtbuf_lib_fun rtbuf_lib_fun[] = {
g_rtbuf_signal_sinus_var, g_rtbuf_signal_sinus_out },
{ "square", rtbuf_signal_square, rtbuf_signal_square_start, 0,
g_rtbuf_signal_square_var, g_rtbuf_signal_square_out },
+ { "adsr", rtbuf_signal_adsr, rtbuf_signal_adsr_start, 0,
+ g_rtbuf_signal_adsr_var, g_rtbuf_signal_adsr_out },
{ "synth", rtbuf_signal_synth, rtbuf_signal_synth_start, 0,
g_rtbuf_signal_synth_var, g_rtbuf_signal_synth_out },
{ 0, 0, 0, 0, 0, 0 } };
diff --git a/rtbuf_signal.h b/rtbuf_signal.h
index db08937..5f0e87e 100644
--- a/rtbuf_signal.h
+++ b/rtbuf_signal.h
@@ -6,7 +6,9 @@
#define RTBUF_SIGNAL_SAMPLES 256
#define RTBUF_SIGNAL_SAMPLERATE 44100
-#define RTBUF_SIGNAL_TYPE \
+#define RTBUF_SIGNAL_DT \
+ ((double) RTBUF_SIGNAL_SAMPLES / RTBUF_SIGNAL_SAMPLERATE)
+#define RTBUF_SIGNAL_TYPE \
RTBUF_TYPE_DOUBLE_ARRAY(RTBUF_SIGNAL_SAMPLES)
typedef double t_rtbuf_signal[RTBUF_SIGNAL_SAMPLES];
@@ -47,8 +49,35 @@ typedef struct rtbuf_signal_square_data {
int rtbuf_signal_square (s_rtbuf *rtb);
int rtbuf_signal_square_start (s_rtbuf *rtb);
+/* adsr */
+
+enum {
+ RTBUF_SIGNAL_ADSR_VAR_NOTE = 0,
+ RTBUF_SIGNAL_ADSR_VAR_ATTACK,
+ RTBUF_SIGNAL_ADSR_VAR_DECAY,
+ RTBUF_SIGNAL_ADSR_VAR_SUSTAIN,
+ RTBUF_SIGNAL_ADSR_VAR_RELEASE,
+ RTBUF_SIGNAL_ADSR_VAR_N,
+};
+
+typedef struct rtbuf_signal_adsr_data {
+ double samples[RTBUF_SIGNAL_SAMPLES];
+ double start;
+ double stop;
+} s_rtbuf_signal_adsr_data;
+
+int rtbuf_signal_adsr (s_rtbuf *rtb);
+int rtbuf_signal_adsr_start (s_rtbuf *rtb);
+
/* synth */
+enum {
+ RTBUF_SIGNAL_SYNTH_VAR_KEYBOARD = 0,
+ RTBUF_SIGNAL_SYNTH_VAR_ENVELOPE,
+ RTBUF_SIGNAL_SYNTH_VAR_OSCILLATOR,
+ RTBUF_SIGNAL_SYNTH_VAR_N,
+};
+
typedef struct rtbuf_signal_synth_note {
s_rtbuf *envelope;
s_rtbuf *oscillator;
@@ -57,12 +86,7 @@ typedef struct rtbuf_signal_synth_note {
#define RTBUF_SIGNAL_SYNTH_NOTE_SIZE sizeof(s_rtbuf_signal_synth_note)
#define RTBUF_SIGNAL_SYNTH_NOTE_TYPE "signal_synth_note"
-enum {
- RTBUF_SIGNAL_SYNTH_VAR_KEYBOARD = 0,
- RTBUF_SIGNAL_SYNTH_VAR_ENVELOPE,
- RTBUF_SIGNAL_SYNTH_VAR_OSCILLATOR,
- RTBUF_SIGNAL_SYNTH_VAR_N,
-};
+int rtbuf_signal_synth_note_p (s_rtbuf_signal_synth_note *sn);
typedef struct rtbuf_signal_synth_notes {
s_rtbuf_signal_synth_note note[RTBUF_MUSIC_NOTE_MAX];
diff --git a/rtbuf_signal_adsr.c b/rtbuf_signal_adsr.c
index 252e50b..4315b9b 100644
--- a/rtbuf_signal_adsr.c
+++ b/rtbuf_signal_adsr.c
@@ -20,37 +20,51 @@ double adsr (double attack, double decay, double sustain,
return 0.0;
}
-enum {
- RTBUF_SIGNAL_ADSR_VAR_NOTE = 0,
- RTBUF_SIGNAL_ADSR_VAR_ATTACK,
- RTBUF_SIGNAL_ADSR_VAR_DECAY,
- RTBUF_SIGNAL_ADSR_VAR_SUSTAIN,
- RTBUF_SIGNAL_ADSR_VAR_RELEASE,
- RTBUF_SIGNAL_ADSR_VAR_N,
-};
-
-typedef struct rtbuf_signal_adsr_data {
- double samples[RTBUF_SIGNAL_SAMPLES];
-} s_rtbuf_signal_adsr_data;
-
int rtbuf_signal_adsr (s_rtbuf *rtb)
{
s_rtbuf_signal_adsr_data *data;
- int attack = rtb->var[RTBUF_SIGNAL_ADSR_VAR_ATTACK];
- int decay = rtb->var[RTBUF_SIGNAL_ADSR_VAR_DECAY];
- int sustain = rtb->var[RTBUF_SIGNAL_ADSR_VAR_SUSTAIN];
- int release = rtb->var[RTBUF_SIGNAL_ADSR_VAR_RELEASE];
- double *attack_samples = attack < 0 ? 0 : g_rtbuf[attack].data;
- double *decay_samples = decay < 0 ? 0 : g_rtbuf[decay].data;
- double *sustain_samples = sustain < 0 ? 0 : g_rtbuf[sustain].data;
- double *release_samples = release < 0 ? 0 : g_rtbuf[release].data;
double *sample;
unsigned int i = 0;
+ double dt =
data = (s_rtbuf_signal_adsr_data*) rtb->data;
sample = data->samples;
while (i < RTBUF_SIGNAL_SAMPLES) {
- *sample = adsr(
+ if (data->start >= 0.0) {
+ double a = rtbuf_signal_sample(rtb, RTBUF_SIGNAL_ADSR_VAR_ATTACK,
+ i, 0.05);
+ double d = rtbuf_signal_sample(rtb, RTBUF_SIGNAL_ADSR_VAR_DECAY,
+ i, 0.02);
+ double s = rtbuf_signal_sample(rtb, RTBUF_SIGNAL_ADSR_VAR_SUSTAIN,
+ i, 0.666);
+ double r = rtbuf_signal_sample(rtb, RTBUF_SIGNAL_ADSR_VAR_RELEASE,
+ i, 0.2);
+ double start = data->start + (double) i / RTBUF_SIGNAL_SAMPLERATE;
+ double stop = data->stop;
+ if (data->stop >= 0.0)
+ data->stop += (double) i / RTBUF_SIGNAL_SAMPLERATE;
+ a = max(0.0, a);
+ d = max(0.0, d);
+ s = max(0.0, s);
+ r = max(0.0, r);
+ *sample = adsr(a, d, s, r, data->start, data->stop);
+ }
+ else
+ *sample = 0.0;
sample++;
i++;
}
+ if (data->start >= 0.0)
+ data->start += RTBUF_SIGNAL_DT;
+ if (data->stop >= 0.0)
+ data->stop += RTBUF_SIGNAL_DT;
+ return 0;
+}
+
+int rtbuf_signal_adsr_start (s_rtbuf *rtb)
+{
+ s_rtbuf_signal_adsr_data *data;
+ data = (s_rtbuf_signal_adsr_data*) rtb->data;
+ data->start = 0.0;
+ data->stop = -1.0;
+ return 0;
}
diff --git a/rtbuf_signal_synth.c b/rtbuf_signal_synth.c
new file mode 100644
index 0000000..f06fa4a
--- /dev/null
+++ b/rtbuf_signal_synth.c
@@ -0,0 +1,108 @@
+
+#include <stdio.h>
+#include <strings.h>
+#include "rtbuf.h"
+#include "rtbuf_signal.h"
+
+symbol g_sym_start = 0;
+symbol g_sym_stop = 0;
+
+void rtbuf_signal_synth_delete_note (s_rtbuf_signal_synth_data *data,
+ unsigned int i)
+{
+ s_rtbuf_signal_synth_note *sn = &data->notes.note[i];
+ if (sn->envelope || sn->oscillator) {
+ if (sn->envelope) {
+ rtbuf_delete(sn->envelope);
+ sn->envelope = 0;
+ }
+ if (sn->oscillator) {
+ rtbuf_delete(sn->oscillator);
+ sn->oscillator = 0;
+ }
+ data->notes.note_n--;
+ }
+}
+
+s_rtbuf * rtbuf_signal_synth_new_envelope (s_rtbuf *rtb,
+ s_rtbuf_music_note *kn)
+{
+ s_rtbuf_binding *v = &rtb->var[RTBUF_SIGNAL_SYNTH_VAR_ENVELOPE];
+ int i;
+ s_rtbuf *env;
+ if (v->rtb < 0)
+ return 0;
+ if((i = rtbuf_clone(&g_rtbuf[v->rtb])) < 0)
+ return 0;
+ env = &g_rtbuf[i];
+ rtbuf_data_set(env, g_sym_start, &kn->start, sizeof(kn->start));
+ rtbuf_data_set(env, g_sym_stop, &kn->stop, sizeof(kn->stop));
+ return env;
+}
+
+s_rtbuf * rtbuf_signal_synth_new_oscillator (s_rtbuf *rtb)
+{
+ s_rtbuf_binding *v = &rtb->var[RTBUF_SIGNAL_SYNTH_VAR_OSCILLATOR];
+ int i;
+ if (v->rtb < 0)
+ return 0;
+ if ((i = rtbuf_clone(&g_rtbuf[v->rtb])) < 0)
+ return 0;
+ return &g_rtbuf[i];
+}
+
+int rtbuf_signal_synth_note_p (s_rtbuf_signal_synth_note *sn)
+{
+ return sn && sn->envelope && sn->oscillator;
+}
+
+void rtbuf_signal_synth_update_note (s_rtbuf *rtb,
+ s_rtbuf_signal_synth_data *data,
+ unsigned int i,
+ s_rtbuf_music_note *note)
+{
+ s_rtbuf_signal_synth_note *sn = &data->notes.note[i];
+ if (rtbuf_music_note_p(note)) {
+ if (!sn->envelope || !sn->oscillator) {
+ if (!sn->envelope)
+ sn->envelope = rtbuf_signal_synth_new_envelope(rtb, note);
+ if (!sn->oscillator)
+ sn->oscillator = rtbuf_signal_synth_new_oscillator(rtb);
+ data->notes.note_n++;
+ }
+ }
+ else
+ rtbuf_signal_synth_delete_note(data, i);
+}
+
+int rtbuf_signal_synth (s_rtbuf *rtb)
+{
+ s_rtbuf_signal_synth_data *data;
+ s_rtbuf_music_notes *knotes =
+ rtbuf_music_notes(rtb, RTBUF_SIGNAL_SYNTH_VAR_KEYBOARD);
+ unsigned int i = 0;
+ unsigned int kn = knotes ? knotes->note_n : 0;
+ unsigned int n;
+ data = (s_rtbuf_signal_synth_data*) rtb->data;
+ n = data->notes.note_n;
+ while (i < RTBUF_MUSIC_NOTE_MAX && (n > 0 || kn > 0)) {
+ s_rtbuf_music_note *note = knotes ? &knotes->note[i] : 0;
+ if (rtbuf_music_note_p(note))
+ kn--;
+ if (rtbuf_signal_synth_note_p(&data->notes.note[i]))
+ n--;
+ rtbuf_signal_synth_update_note(rtb, data, i, note);
+ i++;
+ }
+ return 0;
+}
+
+int rtbuf_signal_synth_start (s_rtbuf *rtb)
+{
+ (void) rtb;
+ if (!g_sym_start)
+ g_sym_start = symbol_intern("start");
+ if (!g_sym_stop)
+ g_sym_stop = symbol_intern("stop");
+ return 0;
+}