shithub: sox

Download patch

ref: 1097cf3938f1b42c149bbfc9f3801c565d741ccb
parent: c732806642d50570b6ab392467df07b78b216f97
author: cbagwell <cbagwell>
date: Tue Apr 11 11:55:17 EDT 2000

Forgot to add speed.c.

--- /dev/null
+++ b/src/speed.c
@@ -1,0 +1,295 @@
+/*
+ * (c) Fabien Coelho <fabien@coelho.net> for sox, 03/2000.
+ *
+ * see sox copyright.
+ *
+ * speed up or down the sound, like a tape.
+ * basically it's like resampling without resampling;-)
+ * this could be done just by changing the rate of the file?
+ * I don't know whether any rate is admissible.
+ * implemented with a slow automaton, but it's easier than one more buffer.
+ * I think it is especially inefficient.
+ */
+
+#include "st.h"
+
+#include <limits.h> /* LONG_MAX */
+
+/* type used for computations.
+ */
+#ifndef SPEED_FLOAT
+#define SPEED_FLOAT float
+#define SPEED_FLOAT_SCAN "%f"
+#endif
+
+/* constants
+ */
+#define FOUR               ((SPEED_FLOAT)(4.0e0))
+#define ONE                ((SPEED_FLOAT)(1.0e0))
+#define HALF               ((SPEED_FLOAT)(0.5e0))
+#define ONESIXTH           ((SPEED_FLOAT)(1.0e0/6.0e0))
+#define ZERO               ((SPEED_FLOAT)(0.0e0))
+
+#define SPEED_USAGE "speed factor (default 1.0, <1 slows)"
+
+/* automaton status
+ */
+typedef enum { sp_input, sp_transfer, sp_compute } buffer_state_t;
+
+/* internal structure
+ */
+typedef struct
+{
+    /* options
+     */
+    SPEED_FLOAT factor;   /* speed factor. */
+
+    /* internals.
+     */
+    int clipped;          /* number of clipped values to report */
+
+    SPEED_FLOAT rate;     /* rate of buffer sweep */
+
+    int compression;      /* integer compression of the signal. */
+    int index;            /* how much of the input buffer is filled */
+    LONG * ibuf;          /* small internal input buffer for compression */
+
+    SPEED_FLOAT cbuf[4];  /* computation buffer for interpolation */
+    SPEED_FLOAT frac;     /* current index position in cbuf */
+    int icbuf;            /* available position in cbuf */
+
+    buffer_state_t state; /* automaton status */
+
+} * speed_t;
+
+/*
+static void debug(char * where, speed_t s)
+{
+    fprintf(stderr, "%s: f=%f r=%f comp=%d i=%d ic=%d frac=%f state=%d v=%f\n",
+	    where, s->factor, s->rate, s->compression, s->index,
+	    s->icbuf, s->frac, s->state, s->cbuf[0]);
+}
+*/
+
+/* compute f(x) with a cubic interpolation...
+ */
+static SPEED_FLOAT cub(
+  SPEED_FLOAT fm1, /* f(-1) */
+  SPEED_FLOAT f0,  /* f(0)  */
+  SPEED_FLOAT f1,  /* f(1)  */
+  SPEED_FLOAT f2,  /* f(2)  */
+  SPEED_FLOAT x)   /* 0.0 <= x < 1.0 */
+{
+    /* a x^3 + b x^2 + c x + d */
+    register SPEED_FLOAT a, b, c, d;
+
+    d = f0;
+    b = HALF * (f1+fm1) - f0;
+    a = ONESIXTH * (f2-f1+fm1-f0-FOUR*b);
+    c = f1 - a - b - d;
+    
+    return ((a * x + b) * x + c) * x + d;
+}
+
+/* clip if necessary, and report. */
+static LONG clip(speed_t speed, SPEED_FLOAT v)
+{
+    if (v < -LONG_MAX)
+    {
+	speed->clipped++;
+	return -LONG_MAX;
+    }
+    else if (v > LONG_MAX)
+    {
+	speed->clipped++;
+	return LONG_MAX;
+    }
+    else
+	return (LONG) v;
+}
+
+/* get options. */
+int st_speed_getopts(effp, n, argv)
+     eff_t effp;
+     int n;
+     char ** argv;
+{
+    speed_t speed = (speed_t) effp->priv;
+
+    speed->factor = ONE; /* default */
+
+    if (n && (!sscanf(argv[0], SPEED_FLOAT_SCAN, &speed->factor) ||
+	      speed->factor<=ZERO))
+    {
+	fail(SPEED_USAGE);
+	return ST_EOF;
+    }
+
+    return ST_SUCCESS;
+}
+
+/* start processing. */
+int st_speed_start(effp)
+     eff_t effp;
+{
+    speed_t speed = (speed_t) effp->priv;
+    speed->clipped = 0;
+
+    if (speed->factor >= ONE)
+    {
+	speed->compression = (int) speed->factor; /* floor */
+	speed->rate = speed->factor / speed->compression;
+    }
+    else
+    {
+	speed->compression = 1;
+	speed->rate = speed->factor;
+    }
+
+    speed->ibuf   = (LONG*) malloc(speed->compression*sizeof(LONG));
+    speed->index  = 0;
+
+    speed->state = sp_input;
+    speed->cbuf[0] = ZERO; /* default previous value for interpolation */
+    speed->icbuf = 1;
+    speed->frac = ZERO;
+
+    if (!speed->ibuf) {
+	fail("malloc failed");
+	return ST_EOF;
+    }
+
+    return ST_SUCCESS;
+}
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+/* transfer input buffer to computation buffer.
+ */
+static void transfer(speed_t speed)
+{
+    register int i;
+    register SPEED_FLOAT s = ZERO;
+
+    for (i=0; i<speed->index; i++)
+	s += (SPEED_FLOAT) speed->ibuf[i];
+    
+    speed->cbuf[speed->icbuf++] = s / ((SPEED_FLOAT) speed->index);
+    
+    if (speed->icbuf == 4)
+	speed->state = sp_compute;
+    else
+	speed->state = sp_input;
+    
+    speed->index = 0;
+}
+
+/* interpolate values
+ */
+static int compute(speed_t speed, LONG * obuf, int olen)
+{
+    register int i;
+
+    for(i = 0;
+	i<olen && speed->frac < ONE;
+	i++, speed->frac += speed->rate)
+	obuf[i] = clip(speed, 
+		       cub(speed->cbuf[0], speed->cbuf[1],
+			   speed->cbuf[2], speed->cbuf[3], 
+			   speed->frac));
+    
+    if (speed->frac >= ONE)
+    {
+	speed->frac -= ONE;
+	speed->cbuf[0] = speed->cbuf[1];
+	speed->cbuf[1] = speed->cbuf[2];
+	speed->cbuf[2] = speed->cbuf[3];
+	speed->icbuf = 3;
+	speed->state = sp_input;
+    }
+
+    return i; /* number of data out */
+}
+
+/* handle a flow.
+ */
+int st_speed_flow(effp, ibuf, obuf, isamp, osamp)
+     eff_t effp;
+     LONG * ibuf, *obuf;
+     LONG * isamp, * osamp;
+{
+    speed_t speed;
+    register int len, iindex, oindex;
+
+    speed = (speed_t) effp->priv;
+
+    len = MIN(*isamp, *osamp);
+    iindex = 0;
+    oindex = 0;
+
+    while (iindex<len && oindex<len)
+    {
+	/* store to input buffer. */
+	if (speed->state==sp_input)
+	{
+	    speed->ibuf[speed->index++] = ibuf[iindex++];
+	    if (speed->index==speed->compression)
+		speed->state = sp_transfer;
+	}
+
+	/* transfer to compute buffer. */
+	if (speed->state==sp_transfer)
+	    transfer(speed);
+
+	/* compute interpolation. */
+	if (speed->state==sp_compute)
+	    oindex += compute(speed, obuf+oindex, len-oindex);
+    }
+
+    *isamp = iindex;
+    *osamp = oindex;
+
+    return ST_SUCCESS;
+}
+
+/* end of stuff. 
+ */
+int st_speed_drain(effp, obuf, osamp)
+     eff_t effp;
+     LONG * obuf;
+     LONG * osamp;
+{
+    speed_t speed = (speed_t) effp->priv;
+    register int i, oindex;
+
+    transfer(speed);
+
+    /* fix up trail by emptying cbuf */
+    for (oindex=0, i=0; i<3 && oindex<*osamp; i++)
+    {
+	oindex += compute(speed, obuf+oindex, *osamp-oindex);
+	speed->cbuf[3] = ZERO;
+	speed->icbuf = 4;
+    }
+
+    *osamp = oindex; /* report how much was generated. */
+
+    return ST_SUCCESS;
+}
+
+/* stop processing. report overflows. 
+ */
+int st_speed_stop(effp)
+     eff_t effp;
+{
+    speed_t speed = (speed_t) effp->priv;
+
+    if (speed->clipped) 
+	warn("SPEED: %d values clipped...", speed->clipped);
+
+    free(speed->ibuf);
+    
+    return ST_SUCCESS;
+}