aboutsummaryrefslogtreecommitdiff
path: root/cyclone/sickle/record.c
diff options
context:
space:
mode:
Diffstat (limited to 'cyclone/sickle/record.c')
-rw-r--r--cyclone/sickle/record.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/cyclone/sickle/record.c b/cyclone/sickle/record.c
new file mode 100644
index 0000000..ba2e3b5
--- /dev/null
+++ b/cyclone/sickle/record.c
@@ -0,0 +1,242 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "shared.h"
+#include "sickle/sic.h"
+#include "sickle/arsic.h"
+
+typedef struct _record
+{
+ t_arsic x_arsic;
+ float x_startpoint; /* the inputs */
+ float x_endpoint;
+ int x_appendmode;
+ int x_loopmode;
+ int x_startindex;
+ int x_endindex; /* (one past last record position) */
+ int x_pauseindex;
+ int x_phase; /* writing head */
+ float x_sync;
+ float x_syncincr;
+ int x_isrunning; /* to know if sync should be 0.0 or 1.0 */
+ t_clock *x_clock;
+} t_record;
+
+static t_class *record_class;
+
+static void record_tick(t_record *x)
+{
+ arsic_redraw((t_arsic *)x);
+}
+
+static void record_setsync(t_record *x)
+{
+ /* CHECKED: clipped to array size -- using indices, not points */
+ float range = (float)(x->x_endindex - x->x_startindex);
+ int phase = x->x_phase;
+ if (phase == SHARED_INT_MAX || range < 1.0)
+ {
+ x->x_sync = (x->x_isrunning ? 1.0 : 0); /* CHECKED */
+ x->x_syncincr = 0;
+ }
+ else
+ {
+ x->x_sync = (float)(phase - x->x_startindex) / range;
+ x->x_syncincr = 1.0 / range;
+ }
+}
+
+static void record_mstoindex(t_record *x)
+{
+ t_arsic *sic = (t_arsic *)x;
+ x->x_startindex = (int)(x->x_startpoint * sic->s_ksr);
+ if (x->x_startindex < 0)
+ x->x_startindex = 0; /* CHECKED */
+ x->x_endindex = (int)(x->x_endpoint * sic->s_ksr);
+ if (x->x_endindex > sic->s_vecsize
+ || x->x_endindex <= 0)
+ x->x_endindex = sic->s_vecsize; /* CHECKED (both ways) */
+ record_setsync(x);
+}
+
+static void record_set(t_record *x, t_symbol *s)
+{
+ arsic_setarray((t_arsic *)x, s, 1);
+ record_mstoindex(x);
+}
+
+static void record_startpoint(t_record *x, t_floatarg f)
+{
+ x->x_startpoint = f;
+ record_mstoindex(x);
+}
+
+static void record_endpoint(t_record *x, t_floatarg f)
+{
+ x->x_endpoint = f;
+ record_mstoindex(x);
+}
+
+static void record_float(t_record *x, t_float f)
+{
+ if (x->x_isrunning = (f != 0))
+ {
+ /* CHECKED: no (re)start in append mode */
+ /* LATER consider restart if x->x_pauseindex == SHARED_INT_MAX */
+ x->x_phase = x->x_appendmode ? x->x_pauseindex : x->x_startindex;
+ if (x->x_phase >= x->x_endindex) x->x_phase = SHARED_INT_MAX;
+ }
+ else if (x->x_phase != SHARED_INT_MAX) /* CHECKED: no rewind */
+ {
+ record_tick(x);
+ x->x_pauseindex = x->x_phase;
+ x->x_phase = SHARED_INT_MAX;
+ }
+ record_setsync(x);
+}
+
+static void record_append(t_record *x, t_floatarg f)
+{
+ if (f != 0)
+ {
+ x->x_appendmode = 1; /* CHECKED: always allow appending */
+ }
+ else x->x_appendmode = 0;
+}
+
+static void record_loop(t_record *x, t_floatarg f)
+{
+ x->x_loopmode = (f != 0);
+}
+
+static t_int *record_perform(t_int *w)
+{
+ t_arsic *sic = (t_arsic *)(w[1]);
+ int nblock = (int)(w[2]);
+ int nch = sic->s_nchannels;
+ t_float *out = (t_float *)(w[3 + nch]);
+ t_record *x = (t_record *)sic;
+ int phase = x->x_phase;
+ int endphase = x->x_endindex;
+ float sync = x->x_sync;
+ if (sic->s_playable && endphase > phase)
+ {
+ int vecsize = sic->s_vecsize;
+ float syncincr = x->x_syncincr;
+ int ch, over, i, nxfer;
+loopover:
+ if ((nxfer = endphase - phase) > nblock)
+ {
+ nxfer = nblock;
+ over = 0;
+ }
+ else over = 1;
+ ch = nch;
+ while (ch--)
+ {
+ t_float *vp = sic->s_vectors[ch];
+ if (vp)
+ {
+ t_float *ip = (t_float *)(w[3 + ch]);
+ vp += phase;
+ i = nxfer;
+ /* LATER consider handling under and overflows */
+ while (i--) *vp++ = *ip++;
+ }
+ }
+ i = nxfer;
+ while (i--)
+ {
+ *out++ = sync;
+ sync += syncincr;
+ }
+ if (over)
+ {
+ nblock -= nxfer;
+ if (x->x_loopmode
+ && (phase = x->x_startindex) < endphase)
+ {
+ x->x_phase = phase;
+ x->x_sync = sync = 0;
+ if (nblock > 0) goto loopover;
+ goto done;
+ }
+ clock_delay(x->x_clock, 0);
+ /* CHECKED: no restart in append mode */
+ x->x_pauseindex = SHARED_INT_MAX;
+ x->x_phase = SHARED_INT_MAX;
+ x->x_sync = 1.0;
+ x->x_syncincr = 0;
+ }
+ else
+ {
+ x->x_phase += nxfer;
+ x->x_sync = sync;
+ goto done;
+ }
+ }
+ while (nblock--) *out++ = sync;
+done:
+ return (w + sic->s_nperfargs + 1);
+}
+
+static void record_dsp(t_record *x, t_signal **sp)
+{
+ arsic_dsp((t_arsic *)x, sp, record_perform, 1);
+ record_mstoindex(x);
+}
+
+static void record_free(t_record *x)
+{
+ arsic_free((t_arsic *)x);
+ if (x->x_clock) clock_free(x->x_clock);
+}
+
+static void *record_new(t_symbol *s, t_floatarg f)
+{
+ /* one auxiliary signal: sync output */
+ t_record *x = (t_record *)arsic_new(record_class, s, (int)f, 0, 1);
+ if (x)
+ {
+ int nch = arsic_getnchannels((t_arsic *)x);
+ arsic_setminsize((t_arsic *)x, 2);
+ x->x_startpoint = 0;
+ x->x_endpoint = 0;
+ x->x_appendmode = 0;
+ x->x_loopmode = 0;
+ x->x_pauseindex = SHARED_INT_MAX;
+ x->x_phase = SHARED_INT_MAX;
+ x->x_isrunning = 0;
+ record_mstoindex(x);
+ x->x_clock = clock_new(x, (t_method)record_tick);
+ while (--nch)
+ inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft-2"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft-1"));
+ outlet_new((t_object *)x, &s_signal);
+ }
+ return (x);
+}
+
+void record_tilde_setup(void)
+{
+ record_class = class_new(gensym("record~"),
+ (t_newmethod)record_new,
+ (t_method)record_free,
+ sizeof(t_record), 0,
+ A_DEFSYM, A_DEFFLOAT, 0);
+ arsic_setup(record_class, record_dsp, record_float);
+ class_addmethod(record_class, (t_method)record_startpoint,
+ gensym("ft-2"), A_FLOAT, 0);
+ class_addmethod(record_class, (t_method)record_endpoint,
+ gensym("ft-1"), A_FLOAT, 0);
+ class_addmethod(record_class, (t_method)record_append,
+ gensym("append"), A_FLOAT, 0);
+ class_addmethod(record_class, (t_method)record_loop,
+ gensym("loop"), A_FLOAT, 0);
+ class_addmethod(record_class, (t_method)record_set,
+ gensym("set"), A_SYMBOL, 0);
+}