aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorN.N. <krzyszcz@users.sourceforge.net>2003-05-28 08:52:25 +0000
committerN.N. <krzyszcz@users.sourceforge.net>2003-05-28 08:52:25 +0000
commita511e141ae18c710ec26f7dbe1b562d5835933b8 (patch)
tree268a77e2e294de93f8140069630d40554f325175
parent14e404306dd2b8092d59ed3f1720e2d9424f53a9 (diff)
slave mode
svn path=/trunk/externals/miXed/; revision=662
-rw-r--r--cyclone/hammer/seq.c263
-rw-r--r--test/cyclone/seq-test.pd75
2 files changed, 253 insertions, 85 deletions
diff --git a/cyclone/hammer/seq.c b/cyclone/hammer/seq.c
index a9d58b6..5997d31 100644
--- a/cyclone/hammer/seq.c
+++ b/cyclone/hammer/seq.c
@@ -16,10 +16,14 @@
#include "common/mifi.h"
#include "hammer/file.h"
-#define SEQ_DEBUG
+//#define SEQ_DEBUG
-#define SEQ_INISIZE 256 /* LATER rethink */
-#define SEQ_EOM 255 /* end of message marker, LATER rethink */
+#define SEQ_INISIZE 256 /* LATER rethink */
+#define SEQ_EOM 255 /* end of message marker, LATER rethink */
+#define SEQ_TICKSPERSEC 48
+#define SEQ_MINTICKDELAY 1. /* LATER rethink */
+
+enum { SEQ_IDLEMODE, SEQ_RECMODE, SEQ_PLAYMODE, SEQ_SLAVEMODE };
typedef struct _seqevent
{
@@ -33,11 +37,12 @@ typedef struct _seq
t_canvas *x_canvas;
t_symbol *x_defname;
t_hammerfile *x_filehandle;
- int x_isplaying;
- int x_isrecording;
+ int x_mode;
int x_playhead;
float x_tempo;
+ float x_newtempo;
double x_prevtime;
+ double x_slaveprevtime;
double x_clockdelay;
unsigned char x_status;
int x_evesize;
@@ -47,6 +52,7 @@ typedef struct _seq
t_seqevent *x_sequence;
t_seqevent x_seqini[SEQ_INISIZE];
t_clock *x_clock;
+ t_clock *x_slaveclock;
t_outlet *x_bangout;
} t_seq;
@@ -75,8 +81,7 @@ static void seq_complete(t_seq *x)
else
{
t_seqevent *ep = &x->x_sequence[x->x_nevents];
- double elapsed = clock_gettimesince(x->x_prevtime);
- ep->e_delta = (int)elapsed;
+ ep->e_delta = (int)clock_gettimesince(x->x_prevtime);
x->x_prevtime = clock_getlogicaltime();
if (x->x_evesize < 4)
ep->e_bytes[x->x_evesize] = SEQ_EOM;
@@ -155,6 +160,19 @@ static void seq_endofsysex(t_seq *x)
x->x_status = 0;
}
+static void seq_stoprecording(t_seq *x)
+{
+ if (x->x_status == 240)
+ {
+ post("seq: incomplete sysex"); /* CHECKED */
+ seq_endofsysex(x); /* CHECKED 247 added implicitly */
+ }
+ else if (x->x_status)
+ seq_complete(x);
+ /* CHECKED running status used in recording, but not across recordings */
+ x->x_status = 0;
+}
+
static void seq_stopplayback(t_seq *x)
{
/* FIXME */
@@ -163,26 +181,118 @@ static void seq_stopplayback(t_seq *x)
/* CHECKED bang not sent if playback stopped early */
clock_unset(x->x_clock);
x->x_playhead = 0;
- x->x_isplaying = 0;
}
-static void seq_stoprecording(t_seq *x)
+static void seq_stopslavery(t_seq *x)
{
- if (x->x_status == 240)
+ /* FIXME */
+ clock_unset(x->x_clock);
+ clock_unset(x->x_slaveclock);
+ x->x_playhead = 0;
+}
+
+static void seq_startrecording(t_seq *x, int modechanged)
+{
+ x->x_prevtime = clock_getlogicaltime();
+ x->x_status = 0;
+ x->x_evesize = 0;
+ x->x_expectedsize = -1; /* LATER rethink */
+}
+
+/* CHECKED running status not used in playback */
+static void seq_startplayback(t_seq *x, int modechanged)
+{
+ /* CHECKED bang not sent if sequence is empty */
+ if (x->x_nevents)
{
- post("seq: incomplete sysex"); /* CHECKED */
- seq_endofsysex(x); /* CHECKED 247 added implicitly */
+ if (modechanged)
+ {
+ x->x_playhead = 0;
+ /* playback data never sent within the scheduler event of
+ a start message (even for the first delta <= 0), LATER rethink */
+ x->x_clockdelay = x->x_sequence->e_delta * x->x_newtempo;
+ }
+ else
+ {
+ /* CHECKED tempo change */
+ x->x_clockdelay -= clock_gettimesince(x->x_prevtime);
+ x->x_clockdelay *= x->x_newtempo / x->x_tempo;
+ }
+ if (x->x_clockdelay < 0.)
+ x->x_clockdelay = 0.;
+ clock_delay(x->x_clock, x->x_clockdelay);
+ x->x_prevtime = clock_getlogicaltime();
+ x->x_tempo = x->x_newtempo;
}
- else if (x->x_status)
- seq_complete(x);
- /* CHECKED running status used in recording, but not across recordings */
- x->x_status = 0;
- x->x_isrecording = 0;
+ else x->x_mode = SEQ_IDLEMODE;
+}
+
+static void seq_startslavery(t_seq *x, int modechanged)
+{
+ if (x->x_nevents)
+ {
+ x->x_playhead = 0;
+ x->x_prevtime = 0.;
+ x->x_slaveprevtime = 0.;
+ }
+ else x->x_mode = SEQ_IDLEMODE;
+}
+
+static void seq_setmode(t_seq *x, int newmode)
+{
+ int changed = (x->x_mode != newmode);
+ if (changed)
+ {
+ switch (x->x_mode)
+ {
+ case SEQ_IDLEMODE:
+ break;
+ case SEQ_RECMODE:
+ seq_stoprecording(x);
+ break;
+ case SEQ_PLAYMODE:
+ seq_stopplayback(x);
+ break;
+ case SEQ_SLAVEMODE:
+ seq_stopslavery(x);
+ break;
+ default:
+ bug("seq_setmode (old)");
+ return;
+ }
+ x->x_mode = newmode;
+ }
+ switch (newmode)
+ {
+ case SEQ_IDLEMODE:
+ break;
+ case SEQ_RECMODE:
+ seq_startrecording(x, changed);
+ break;
+ case SEQ_PLAYMODE:
+ seq_startplayback(x, changed);
+ break;
+ case SEQ_SLAVEMODE:
+ seq_startslavery(x, changed);
+ break;
+ default:
+ bug("seq_setmode (new)");
+ }
+}
+
+static void seq_settempo(t_seq *x, float newtempo)
+{
+ if (newtempo < 1e-20)
+ x->x_newtempo = 1e-20;
+ else if (newtempo > 1e20)
+ x->x_newtempo = 1e20;
+ else
+ x->x_newtempo = newtempo;
}
static void seq_clocktick(t_seq *x)
{
- if (x->x_isplaying)
+ if (x->x_mode == SEQ_PLAYMODE || x->x_mode == SEQ_SLAVEMODE)
{
t_seqevent *ep = &x->x_sequence[x->x_playhead++];
unsigned char *bp = ep->e_bytes;
@@ -198,8 +308,8 @@ nextevent:
outlet_float(((t_object *)x)->ob_outlet, *bp++);
}
}
- if (!x->x_isplaying) /* reentrancy protection */
- return;
+ if (x->x_mode != SEQ_PLAYMODE && x->x_mode != SEQ_SLAVEMODE)
+ return; /* protecting against outlet -> 'stop' etc. */
if (x->x_playhead < x->x_nevents)
{
ep++;
@@ -221,63 +331,66 @@ nextevent:
}
else
{
- seq_stopplayback(x);
+ seq_setmode(x, SEQ_IDLEMODE);
/* CHECKED bang sent immediately _after_ last byte */
outlet_bang(x->x_bangout); /* LATER think about reentrancy */
}
}
}
-static void seq_tick(t_seq *x)
+/* timeout handler ('tick' is late) */
+static void seq_slaveclocktick(t_seq *x)
{
- /* FIXME */
+ if (x->x_mode == SEQ_SLAVEMODE) clock_unset(x->x_clock);
}
-/* CHECKED running status not used in playback */
-static void seq_dostart(t_seq *x, float tempo)
-{
- if (x->x_isplaying)
- {
- /* CHECKED tempo change */
- double elapsed = clock_gettimesince(x->x_prevtime);
- double left = x->x_clockdelay - elapsed;
- if (left < 0)
- left = 0;
- else
- left *= tempo / x->x_tempo;
- clock_delay(x->x_clock, x->x_clockdelay = left);
- x->x_prevtime = clock_getlogicaltime();
- x->x_tempo = tempo;
- }
- else
+/* LATER dealing with self-invokation (outlet -> 'tick') */
+static void seq_tick(t_seq *x)
+{
+ if (x->x_mode == SEQ_SLAVEMODE)
{
- if (x->x_isrecording) /* CHECKED 'start' stops recording */
- seq_stoprecording(x);
- /* CHECKED bang not sent if a sequence is empty */
- if (x->x_nevents)
+ if (x->x_slaveprevtime > 0)
{
- x->x_tempo = tempo;
- x->x_playhead = 0;
- x->x_isplaying = 1;
- /* playback data never sent within the scheduler event of
- a start message (even for the first delta <= 0), LATER rethink */
- x->x_clockdelay = x->x_sequence->e_delta * tempo;
+ double elapsed = clock_gettimesince(x->x_slaveprevtime);
+ if (elapsed < SEQ_MINTICKDELAY)
+ return;
+ clock_delay(x->x_slaveclock, elapsed);
+ seq_settempo(x, (float)(elapsed * (SEQ_TICKSPERSEC / 1000.)));
+ if (x->x_prevtime > 0)
+ {
+ x->x_clockdelay -= clock_gettimesince(x->x_prevtime);
+ x->x_clockdelay *= x->x_newtempo / x->x_tempo;
+ }
+ else x->x_clockdelay =
+ x->x_sequence[x->x_playhead].e_delta * x->x_newtempo;
if (x->x_clockdelay < 0.)
x->x_clockdelay = 0.;
clock_delay(x->x_clock, x->x_clockdelay);
x->x_prevtime = clock_getlogicaltime();
+ x->x_slaveprevtime = x->x_prevtime;
+ x->x_tempo = x->x_newtempo;
+ }
+ else
+ {
+ x->x_clockdelay = 0.; /* redundant */
+ x->x_prevtime = 0.; /* redundant */
+ x->x_slaveprevtime = clock_getlogicaltime();
+ x->x_tempo = 1.; /* redundant */
}
}
}
+/* CHECKED bang does the same as 'start 1024', not 'start <current-tempo>'
+ (also if already in SEQ_PLAYMODE) */
static void seq_bang(t_seq *x)
{
- seq_dostart(x, 1.);
+ seq_settempo(x, 1.);
+ seq_setmode(x, SEQ_PLAYMODE); /* CHECKED 'bang' stops recording */
}
static void seq_float(t_seq *x, t_float f)
{
- if (x->x_isrecording)
+ if (x->x_mode == SEQ_RECMODE)
{
/* CHECKED noninteger and out of range silently truncated */
unsigned char c = (unsigned char)f;
@@ -314,28 +427,18 @@ static void seq_list(t_seq *x, t_symbol *s, int ac, t_atom *av)
/* CHECKED anything else/more silently ignored */
}
-static void seq_dorecord(t_seq *x)
-{
- if (x->x_isplaying) /* CHECKED 'record' and 'append' stops playback */
- seq_stopplayback(x);
- x->x_isrecording = 1;
- x->x_prevtime = clock_getlogicaltime();
- x->x_status = 0;
- x->x_evesize = 0;
- x->x_expectedsize = -1; /* LATER rethink */
-}
-
static void seq_record(t_seq *x)
{
- /* CHECKED 'record' resets recording */
+ /* CHECKED 'record' stops playback, resets recording */
seq_doclear(x, 0);
- seq_dorecord(x);
+ seq_setmode(x, SEQ_RECMODE);
}
static void seq_append(t_seq *x)
{
- /* CHECKED if isrecording, 'append' resets the timer */
- seq_dorecord(x);
+ /* CHECKED 'append' stops playback */
+ /* CHECKED if in SEQ_RECMODE, 'append' resets the timer */
+ seq_setmode(x, SEQ_RECMODE);
}
static void seq_start(t_seq *x, t_floatarg f)
@@ -343,31 +446,25 @@ static void seq_start(t_seq *x, t_floatarg f)
if (f < 0)
{
/* FIXME */
+ seq_setmode(x, SEQ_SLAVEMODE);
}
else
{
- float tempo = (f == 0 ? 1. : 1024. / f);
- if (tempo < 1e-20)
- tempo = 1e-20;
- else if (tempo > 1e20)
- tempo = 1e20;
- seq_dostart(x, tempo);
+ seq_settempo(x, (f == 0 ? 1. : 1024. / f));
+ seq_setmode(x, SEQ_PLAYMODE); /* CHECKED 'start' stops recording */
}
}
static void seq_stop(t_seq *x)
{
- if (x->x_isplaying)
- seq_stopplayback(x);
- else if (x->x_isrecording)
- seq_stoprecording(x);
+ seq_setmode(x, SEQ_IDLEMODE);
}
/* CHECKED first delta time is set permanently (it is stored in a file) */
static void seq_delay(t_seq *x, t_floatarg f)
{
if (x->x_nevents)
- /* CHECKED signed/unsigned bug, not emulated */
+ /* CHECKED signed/unsigned bug (not emulated) */
x->x_sequence->e_delta = (f > 0 ? f : 0);
}
@@ -379,7 +476,7 @@ static void seq_hook(t_seq *x, t_floatarg f)
{
t_seqevent *ev = x->x_sequence;
if (f < 0)
- f = 0; /* CHECKED signed/unsigned bug, not emulated */
+ f = 0; /* CHECKED signed/unsigned bug (not emulated) */
while (nevents--) ev++->e_delta *= f;
}
}
@@ -823,6 +920,7 @@ static void seq_print(t_seq *x)
static void seq_free(t_seq *x)
{
if (x->x_clock) clock_free(x->x_clock);
+ if (x->x_slaveclock) clock_free(x->x_slaveclock);
hammerfile_free(x->x_filehandle);
if (x->x_sequence != x->x_seqini)
freebytes(x->x_sequence, x->x_size * sizeof(*x->x_sequence));
@@ -841,7 +939,9 @@ static void *seq_new(t_symbol *s)
x->x_filehandle = hammerfile_new((t_pd *)x, 0,
seq_readhook, seq_writehook, 0);
x->x_tempo = 1.;
- x->x_prevtime = 0;
+ x->x_newtempo = 1.;
+ x->x_prevtime = 0.;
+ x->x_slaveprevtime = 0.;
x->x_size = SEQ_INISIZE;
x->x_nevents = 0;
x->x_sequence = x->x_seqini;
@@ -854,6 +954,7 @@ static void *seq_new(t_symbol *s)
}
else x->x_defname = &s_;
x->x_clock = clock_new(x, (t_method)seq_clocktick);
+ x->x_slaveclock = clock_new(x, (t_method)seq_slaveclocktick);
return (x);
}
@@ -883,7 +984,7 @@ void seq_setup(void)
class_addmethod(seq_class, (t_method)seq_delay,
gensym("delay"), A_FLOAT, 0); /* CHECKED arg obligatory */
class_addmethod(seq_class, (t_method)seq_hook,
- gensym("hook"), A_FLOAT, 0); /* CHECKED arg obligatory */
+ gensym("hook"), A_FLOAT, 0); /* CHECKED arg obligatory */
class_addmethod(seq_class, (t_method)seq_read,
gensym("read"), A_DEFSYM, 0);
class_addmethod(seq_class, (t_method)seq_write,
diff --git a/test/cyclone/seq-test.pd b/test/cyclone/seq-test.pd
index baa645d..66a087b 100644
--- a/test/cyclone/seq-test.pd
+++ b/test/cyclone/seq-test.pd
@@ -1,4 +1,4 @@
-#N canvas 349 176 601 359 12;
+#N canvas 288 50 601 359 12;
#X obj 125 191 seq;
#X msg 61 249 print;
#X floatatom 63 83 5 0 0 0 - - -;
@@ -17,9 +17,9 @@
#X obj 242 319 midiout;
#X msg 217 128 read test.seq;
#X msg 445 215 start \$1;
-#X msg 445 147 512;
-#X floatatom 445 183 5 0 0 0 - - -;
-#X msg 379 147 stop;
+#X msg 445 154 512;
+#X floatatom 445 180 5 0 0 0 - - -;
+#X msg 379 154 stop;
#X msg 217 232 write test.seq;
#X obj 242 293 midiflush;
#X msg 189 293 bang;
@@ -27,6 +27,66 @@
#X msg 231 74 append;
#X msg 217 258 write test.mid;
#X msg 217 154 read test.mid;
+#X msg 448 97 delay \$1;
+#X floatatom 448 74 5 0 0 0 - - -;
+#X obj 379 284 print;
+#X msg 499 151 hook \$1;
+#X floatatom 499 128 5 0 0 0 - - -;
+#X msg 448 284 print;
+#N canvas 329 51 450 309 slavemode 1;
+#X obj 227 237 seq;
+#X obj 227 278 print;
+#X obj 38 142 metro 1000;
+#X obj 38 65 t b 0;
+#X msg 38 92 1;
+#X obj 167 118 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 38 169 random 128;
+#X msg 38 196 144 \, \$1 \, \$1;
+#X obj 227 201 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 261 196 stop;
+#X msg 38 14 500;
+#X floatatom 38 41 5 0 0 0 - - -;
+#X msg 261 169 start -1;
+#X obj 205 118 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 205 168 tick;
+#X msg 165 278 print;
+#X msg 92 14 record;
+#X obj 272 96 / 48;
+#X obj 205 141 metro 21;
+#X obj 272 69 * 1000;
+#X floatatom 272 45 5 0 0 0 - - -;
+#X msg 272 18 1;
+#X msg 158 196 read;
+#X obj 288 278 midiout;
+#X connect 0 0 1 0;
+#X connect 0 0 23 0;
+#X connect 0 1 1 0;
+#X connect 2 0 6 0;
+#X connect 3 0 4 0;
+#X connect 3 1 2 1;
+#X connect 4 0 5 0;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 11 0;
+#X connect 11 0 3 0;
+#X connect 12 0 0 0;
+#X connect 13 0 18 0;
+#X connect 14 0 0 0;
+#X connect 15 0 0 0;
+#X connect 16 0 0 0;
+#X connect 17 0 18 1;
+#X connect 18 0 14 0;
+#X connect 19 0 17 0;
+#X connect 20 0 19 0;
+#X connect 21 0 20 0;
+#X connect 22 0 0 0;
+#X restore 306 28 pd slavemode;
#X connect 0 0 6 0;
#X connect 0 0 21 0;
#X connect 0 1 6 0;
@@ -44,6 +104,8 @@
#X connect 12 0 0 0;
#X connect 12 0 14 0;
#X connect 13 0 21 0;
+#X connect 13 0 29 0;
+#X connect 13 1 29 0;
#X connect 15 0 0 0;
#X connect 16 0 13 0;
#X connect 17 0 18 0;
@@ -56,3 +118,8 @@
#X connect 24 0 0 0;
#X connect 25 0 0 0;
#X connect 26 0 0 0;
+#X connect 27 0 13 0;
+#X connect 28 0 27 0;
+#X connect 30 0 13 0;
+#X connect 31 0 30 0;
+#X connect 32 0 13 0;