aboutsummaryrefslogtreecommitdiff
path: root/modules/generic/pdp_loop.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/generic/pdp_loop.c')
-rw-r--r--modules/generic/pdp_loop.c296
1 files changed, 296 insertions, 0 deletions
diff --git a/modules/generic/pdp_loop.c b/modules/generic/pdp_loop.c
new file mode 100644
index 0000000..259eb8f
--- /dev/null
+++ b/modules/generic/pdp_loop.c
@@ -0,0 +1,296 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/*
+
+ pdp_loop: a looping packet delay line
+ messages:
+ record x: start recording at position x (default = 0)
+ stop: stop recording
+ float: output packet at position
+ bang: output next packet
+ rewind: rewind
+ loop: set looping mode
+
+*/
+
+
+#include "pdp.h"
+#include "pdp_internals.h"
+
+
+typedef struct pdp_loop_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_outlet *x_outlet1;
+
+ int *x_packet;
+ int x_order; /* size of the packet loop */
+ int x_play_head; /* next position to play back */
+ int x_record_head; /* next position to record to */
+
+ int x_loop;
+ int x_recording_frames; /* nb frames left to record */
+ //int x_recording_shot; /* single frame recording is on */
+} t_pdp_loop;
+
+
+
+
+
+static void pdp_loop_input_0(t_pdp_loop *x, t_symbol *s, t_floatarg f)
+{
+ int in;
+ int out;
+ int packet;
+
+
+ /* if recording is off, ignore packet */
+ if ((!x->x_recording_frames)) return;
+
+ /* store a packet on register ro */
+ if (s == gensym("register_ro")){
+
+ /* delete old & store new */
+ in = x->x_record_head; //% x->x_order;
+ pdp_packet_mark_unused(x->x_packet[in]);
+ packet = pdp_packet_copy_ro((int)f);
+ x->x_packet[in] = packet;
+
+ /* advance head & decrease record counter */
+ x->x_recording_frames--;
+ x->x_record_head++;
+
+ /* turn off recording if we are at the end */
+ if (x->x_record_head == x->x_order) x->x_recording_frames = 0;
+ }
+}
+
+
+static void pdp_loop_bang(t_pdp_loop *x){
+ int out;
+ int packet;
+
+ out = x->x_play_head;
+
+ /* don't play if we're at the end of the sequence and looping is disabled */
+ if ((!x->x_loop) && (out >= x->x_order)) return;
+
+ /* wrap index */
+ out %= x->x_order;
+
+ /* output the current packet */
+ packet = x->x_packet[out];
+ outlet_float(x->x_outlet1, (float)out); // output location
+ if (-1 != packet) outlet_pdp(x->x_outlet0, packet); // output packet
+
+ /* advance playback head */
+ x->x_play_head++;
+
+}
+
+
+
+
+
+
+static void pdp_loop_reset(t_pdp_loop *x)
+{
+ int i;
+ for (i=0; i<x->x_order; i++) {
+ pdp_packet_mark_unused(x->x_packet[i]);
+ x->x_packet[i] = -1;
+ }
+ x->x_play_head = 0;
+ x->x_record_head = 0;
+
+}
+
+static void pdp_loop_record(t_pdp_loop *x, t_floatarg fstart, t_floatarg fdur)
+{
+ int istart = (int)fstart;
+ int idur = (int)fdur;
+ istart %= x->x_order;
+ if (istart<0) istart+= x->x_order;
+ if (idur <= 0) idur = x->x_order - istart;
+
+ x->x_record_head = istart;
+ x->x_recording_frames = idur;
+}
+
+static void pdp_loop_store(t_pdp_loop *x, t_floatarg f)
+{
+ int i = (int)f;
+ i %= x->x_order;
+ if (i<0) i+= x->x_order;
+
+ x->x_record_head = i;
+ x->x_recording_frames = 1;
+}
+
+static void pdp_loop_seek(t_pdp_loop *x, t_floatarg f)
+{
+ int i = (int)f;
+ i %= x->x_order;
+ if (i<0) i+= x->x_order;
+
+ x->x_play_head = i;
+}
+
+static void pdp_loop_seek_hot(t_pdp_loop *x, t_floatarg f)
+{
+ pdp_loop_seek(x, f);
+ pdp_loop_bang(x);
+}
+
+
+static void pdp_loop_stop(t_pdp_loop *x)
+{
+ x->x_recording_frames = 0;
+}
+
+static void pdp_loop_loop(t_pdp_loop *x, t_floatarg f)
+{
+ if (f == 0.0f) x->x_loop = 0;
+ if (f == 1.0f) x->x_loop = 1;
+
+}
+static void pdp_loop_free(t_pdp_loop *x)
+{
+ pdp_loop_reset(x);
+ pdp_dealloc (x->x_packet);
+}
+
+static int pdp_loop_realsize(float f)
+{
+ int order = (int)f;
+ if (order <= 2) order = 2;
+ return order;
+}
+
+
+static void pdp_loop_resize(t_pdp_loop *x, t_floatarg f)
+{
+ int i;
+ int order = pdp_loop_realsize(f);
+ int *newloop;
+
+ /* if size didn't change, do nothing */
+ if (x->x_order == order) return;
+
+ /* create new array */
+ newloop = (int *)pdp_alloc(sizeof(int) * order);
+
+
+ /* extend it */
+ if (x->x_order < order){
+
+ /* copy old packets */
+ for (i=0; i<x->x_order; i++) newloop[i] = x->x_packet[i];
+
+ /* loop extend the rest */
+ for (i=x->x_order; i<order; i++) newloop[i] = pdp_packet_copy_ro(x->x_packet[i % x->x_order]);
+
+ }
+
+ /* or shrink it */
+ else {
+ /* copy part of old packets */
+ for (i=0; i<order; i++) newloop[i] = x->x_packet[i];
+
+ /* delete the other part of old packets */
+ for (i=order; i<x->x_order; i++) pdp_packet_mark_unused(x->x_packet[i]);
+
+ /* adjust heads */
+ x->x_play_head %= order;
+ x->x_record_head %= order;
+
+ }
+
+ /* delete old line & store new */
+ pdp_dealloc (x->x_packet);
+ x->x_packet = newloop;
+ x->x_order = order;
+
+
+}
+
+
+t_class *pdp_loop_class;
+
+
+
+void *pdp_loop_new(t_floatarg f)
+{
+ int i;
+ int order = pdp_loop_realsize(f);
+ t_pdp_loop *x = (t_pdp_loop *)pd_new(pdp_loop_class);
+
+ x->x_order = order;
+ x->x_packet = (int *)pdp_alloc(sizeof(int)*order);
+ for(i=0; i<order; i++) x->x_packet[i] = -1;
+
+ x->x_play_head = 0;
+ x->x_record_head = 0;
+ x->x_recording_frames = 0;
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("seek"));
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_loop = 1;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_loop_setup(void)
+{
+
+
+ pdp_loop_class = class_new(gensym("pdp_loop"), (t_newmethod)pdp_loop_new,
+ (t_method)pdp_loop_free, sizeof(t_pdp_loop), 0, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_loop_class, (t_method)pdp_loop_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_loop_class, (t_method)pdp_loop_record, gensym("record"), A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_loop_class, (t_method)pdp_loop_store, gensym("store"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_loop_class, (t_method)pdp_loop_reset, gensym("reset"), A_NULL);
+ class_addmethod(pdp_loop_class, (t_method)pdp_loop_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_loop_class, (t_method)pdp_loop_stop, gensym("stop"), A_NULL);
+ class_addmethod(pdp_loop_class, (t_method)pdp_loop_seek, gensym("seek"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_loop_class, (t_method)pdp_loop_resize, gensym("size"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_loop_class, (t_method)pdp_loop_loop, gensym("loop"), A_FLOAT, A_NULL);
+ class_addfloat(pdp_loop_class, (t_method)pdp_loop_seek_hot);
+
+}
+
+#ifdef __cplusplus
+}
+#endif