ref: 8f84c484bf7868abccedafd1963fbb249defc5dc
parent: 7e6aa6d2a98867e607d584dc9847b43375b0b8dd
author: robs <robs>
date: Sun May 31 10:56:49 EDT 2009
synth pluck improvements
--- a/scripts/alert.sh
+++ b/scripts/alert.sh
@@ -26,7 +26,6 @@
# ---------------------------------------------------------------------------
SOX=../src/sox
-PLAY=../src/play
rm -f 2tones.ul # Make sure we append to a file that's initially empty
@@ -45,4 +44,4 @@
$SOX -c 1 -r 8000 alert.ul alert.au # Add a file header
rm 2tones.ul alert.ul # Tidy up intermediate files
-$PLAY alert.au
+$SOX alert.au -d
--- a/scripts/synth.sh
+++ b/scripts/synth.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-# SoX script: synth.sh (c) 2008 robs@users.sourceforge.net
+# SoX script: synth.sh (c) 2008-9 robs@users.sourceforge.net
#
# 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
@@ -17,7 +17,6 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
sox=../src/sox
-play=../src/play
G0="pl %-26 pl %-19 pl %-14 pl %-10 pl %-7 pl %-2"
A0="pl %-24 pl %-17 pl %-12 pl %-8 pl %-5 pl %0"
@@ -26,12 +25,22 @@
E0="pl %-22 pl %-17 pl %-10 pl %-5 pl %-1 pl %2"
Bb0="pl %-23 pl %-16 pl %-11 pl %-7 pl %-4 pl %1"
-o="overdrive 40 gain -8"
-e="delay 0 .02 .04 .06 .08 .1 remix - $o fade 0"
-s="$sox -q -n -p synth 0 0 0 80 87"
-l="$sox -q -n -p synth 0 0 0 80 0 0"
+o="overdrive 27 gain -11"
+e="delay 0 .02 .04 .06 .08 .1 remix - overdrive 33 gain -8 fade 0"
+s="$sox -q -n -p synth 0 0 1 60 90"
+l="$sox -q -n -p synth 0 0 0 50 20"
-$play -m -v .8 \
+b="$sox -np synth 0 0 0 30 20 pl"
+c3="fade h 0 .75"
+c="fade h 0 .25"
+cs="fade h 0 .25 .05"
+m="fade h 0 .5"
+sb="fade h 0 1"
+r="$sox -np trim 0 .25"
+r2="$sox -np trim 0 .5"
+r3="$sox -np trim 0 .75"
+
+$sox -m -v .8 \
"|$sox \
\"|$sox -n -p synth noise fade 0 .5 .48 trim 0 .15\" \
\"|$sox -n -p synth noise fade h 0 .26 .11 gain -35 lowpass -1 12k\" \
@@ -63,15 +72,15 @@
\"|$l pl %10 $o trim 0 .5 bend .2,-300,.1\" \
\"|$l pl %5 $o trim 0 .5 bend .2,-200,.1\" \
\"|$l pl %0 $o fade 0 .55 .1 bend .2,-200,.1\" \
-\"|$l pl %0 $o fade 0 2 .1\" \
+\"|$l pl %0 $o fade h 0 2 .5\" \
\"|$sox -n -p trim 0 3.95\" \
\"|$l pl %12 $o trim 0 .5 bend .2,-200,.1\" \
\"|$l pl %12 $o trim 0 .5 bend .2,-200,.1\" \
\"|$l pl %12 $o fade 0 .8 .1 bend .2,-200,.1\" \
\"|$l pl %12 $o trim 0 .3 bend .1,-200,.1\" \
-\"|$l pl %12 $o trim 0 1.95 bend .3,-50,1\" \
-\"|$l pl %10 $o trim 0 2 bend .3,-50,1\" \
-\"|$l pl %9 $o trim 0 2 gain -3\" \
+\"|$l pl %12 $o fade 0 1.95 .6 bend .0,-50,1.75 gain 3\" \
+\"|$l pl %10 $o fade 0 2 .6 bend .0,-50,1.9\" \
+\"|$l pl %9 $o trim 0 2 gain -1\" \
\"|$l pl %8 $o fade h 0 1 .3\" \
\"|$l pl %8 $o fade h 0 1 .1 gain 1.5\" \
\"|$l pl %2 pl %7 delay 0 .02 remix - $o trim 0 .25\" \
@@ -83,4 +92,100 @@
\"|$l pl %2 pl %7 delay 0 .02 remix - $o trim 0 .25\" \
\"|$l pl %-5 $o trim 0 .25\" \
\"|$l pl %2 pl %7 delay 0 .02 remix - $o fade h 0 6 6\" \
--p gain -4 remix 1 1 flanger"
+-p gain -4 remix 1 1 flanger" \
+"|$sox \
+\"|$sox -n -p trim 0 1.5\" \
+\"|$b G1 $m contrast\" \
+\"|$b A1 $c3 contrast\" \
+\"|$b G#1 $c\" \
+\"|$b A1 $c3\" \
+\"|$r\" \
+\
+\"|$b C2 $cs\" \
+\"|$b C2 $cs\" \
+\"|$r\" \
+\"|$b B1 $cs\" \
+\"|$b C2 $c3\" \
+\"|$r\" \
+\
+\"|$b D2 $cs\" \
+\"|$b D2 $cs\" \
+\"|$r\" \
+\"|$b C#2 $cs\" \
+\"|$b D2 $c\" \
+\"|$b C#2 $m\" \
+\"|$r\" \
+\
+\"|$b D2 $cs\" \
+\"|$b D2 $cs\" \
+\"|$r\" \
+\"|$b C#2 $cs\" \
+\"|$b D2 $c\" \
+\"|$b C#2 $c\" \
+\"|$b D2 $c\" \
+\"|$b E2 $c\" \
+\
+\"|$b A1 $c3 contrast\" \
+\"|$b B1 $c\" \
+\"|$b A1 $c\" \
+\"|$b G#1 $c\" \
+\"|$b A1 $c\" \
+\"|$b B1 $c\" \
+\
+\"|$b C2 $c3\" \
+\"|$b B1 $c\" \
+\"|$b C2 $c\" \
+\"|$b D2 $c\" \
+\"|$b C2 $c\" \
+\"|$b B1 $c\" \
+\
+\"|$b D2 $c3\" \
+\"|$b E2 $c\" \
+\"|$b D2 $c\" \
+\"|$b C#2 $c\" \
+\"|$b D2 $c\" \
+\"|$b E2 $c\" \
+\
+\"|$b D2 $c3\" \
+\"|$b C#2 $c\" \
+\"|$b D2 $c\" \
+\"|$b E2 $c\" \
+\"|$b D2 $c\" \
+\"|$b C#2 $c\" \
+\
+\"|$b A1 $cs\" \
+\"|$b A1 $cs\" \
+\"|$r\" \
+\"|$b G#1 $c\" \
+\"|$b A1 $c3\" \
+\"|$b B1 $c\" \
+\
+\"|$b C2 $c\" \
+\"|$b B1 $c\" \
+\"|$b C2 $c\" \
+\"|$b D2 $c\" \
+\"|$b C2 $c3\" \
+\"|$r\" \
+\
+\"|$b D2 $m\" \
+\"|$b E2 $m\" \
+\"|$b D2 $c\" \
+\"|$b C#2 $c\" \
+\"|$b D2 $c\" \
+\"|$b E2 $c\" \
+\
+\"|$b F2 $m\" \
+\"|$b Bb1 $m\" \
+\"|$b C2 $c\" \
+\"|$b F2 $c\" \
+\"|$b D2 $c\" \
+\"|$b Bb1 $c\" \
+\
+\"|$b E1 $m\" \
+\"|$b E2 $m\" \
+\"|$b D2 $c\" \
+\"|$b E2 $m\" \
+\"|$b B1 $c\" \
+\
+\"|$b E1 $sb\" \
+-p lowpass -1 1k remix 1p-12 1p-12" -d
--- a/scripts/testtones.sh
+++ b/scripts/testtones.sh
@@ -273,7 +273,7 @@
echo; echo "Plucked scale:"
options=
- overdrive=
+ overdrive="gain -3"
for f in pluck pluck_dist; do
next_file $f 42
note=-29
@@ -289,14 +289,13 @@
$input -t s32 - synth .4 pluck %$note $options >> tmp.s32
note=$(($note - 1))
done
- $input -t s32 - synth pluck %$note $options fade h 0 2 .1 >> tmp.s32
+ $input -t s32 - synth pluck %$note $options fade t 0 4 3.6 >> tmp.s32
- $sox -r $rate -c 1 tmp.s32 $output compand .1,.2 6:-70,-60,-20 -7 -15 .1 \
- $overdrive pad 0 2 remix 1 1 reverb 30
+ $sox -r $rate -c 1 tmp.s32 $output $overdrive remix 1 1 reverb 30
rm -f tmp.s32
- options="0 0 60 60"
- overdrive="overdrive 30 gain -9"
+ options="0 0 60 75 0"
+ overdrive="overdrive gain -10"
done
fi
--- a/sox.1
+++ b/sox.1
@@ -1891,8 +1891,8 @@
and this plays a guitar chord:
.EX
.ne 2
- play -n synth -j -2 pl %-26 pl %-22 pl %-19 pl %-14 pl %-7 \\
- pl %-2 delay 0 .05 .1 .15 .2 .25 remix - fade 0 4 .1 norm -1
+ play -n synth pl G2 pl B2 pl D3 pl G3 pl D4 pl G4 \\
+ delay 0 .05 .1 .15 .2 .25 remix - fade 0 4 .1 norm -1
.EE
.TP
\fBdither\fR [\fB\-a\fR] [\fB\-S\fR\^|\^\fB\-s\fR\^|\^\fB\-f \fIfilter\fR]
--- a/src/effects_i.c
+++ b/src/effects_i.c
@@ -21,6 +21,7 @@
#define LSX_EFF_ALIAS
#include "sox_i.h"
#include <string.h>
+#include <ctype.h>
int lsx_usage(sox_effect_t * effp)
{
@@ -290,9 +291,24 @@
return 440 * pow(2., note / 12);
}
+int lsx_parse_note(char const * text, char * * end_ptr)
+{
+ int result = INT_MAX;
+
+ if (*text >= 'A' && *text <= 'G') {
+ result = (int)(5/3. * (*text++ - 'A') + 9.5) % 12 - 9;
+ if (*text == 'b') {--result; ++text;}
+ else if (*text == '#') {++result; ++text;}
+ if (isdigit(*text))
+ result += 12 * (*text++ - '4');
+ }
+ *end_ptr = (char *)text;
+ return result;
+}
+
/* Read string 'text' and convert to frequency.
* 'text' can be a positive number which is the frequency in Hz.
- * If 'text' starts with a hash '%' and a following number the corresponding
+ * If 'text' starts with a '%' and a following number the corresponding
* note is calculated.
* Return -1 on error.
*/
@@ -305,6 +321,10 @@
if (*end_ptr == text + 1)
return -1;
return calc_note_freq(result, key);
+ }
+ if (*text >= 'A' && *text <= 'G') {
+ int result = lsx_parse_note(text, end_ptr);
+ return result == INT_MAX? - 1 : calc_note_freq((double)result, key);
}
result = strtod(text, end_ptr);
if (end_ptr) {
--- a/src/sox.c
+++ b/src/sox.c
@@ -2091,7 +2091,7 @@
static int enum_option(int option_index, lsx_enum_item const * items)
{
- lsx_enum_item const * p = lsx_find_enum_text(lsx_optarg, items);
+ lsx_enum_item const * p = lsx_find_enum_text(lsx_optarg, items, 0);
if (p == NULL) {
size_t len = 1;
char * set = lsx_malloc(len);
--- a/src/sox.h
+++ b/src/sox.h
@@ -565,7 +565,8 @@
typedef struct {char const *text; unsigned value;} lsx_enum_item;
#define LSX_ENUM_ITEM(prefix, item) {#item, prefix##item},
-lsx_enum_item const * lsx_find_enum_text(char const * text, lsx_enum_item const * lsx_enum_items);
+lsx_enum_item const * lsx_find_enum_text(char const * text, lsx_enum_item const * lsx_enum_items, unsigned flags);
+#define LSX_FET_CASE 1
lsx_enum_item const * lsx_find_enum_value(unsigned value, lsx_enum_item const * lsx_enum_items);
int lsx_enum_option(int c, lsx_enum_item const * items);
sox_bool lsx_strends(char const * str, char const * end);
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -82,6 +82,7 @@
double max, /* Maximum value on the y-axis. (e.g. +1) */
double phase); /* Phase at 1st point; 0..2pi. (e.g. pi/2 for cosine) */
char const * lsx_parsesamples(sox_rate_t rate, const char *str, size_t *samples, int def);
+int lsx_parse_note(char const * text, char * * end_ptr);
double lsx_parse_frequency_k(char const * text, char * * end_ptr, int key);
#define lsx_parse_frequency(a, b) lsx_parse_frequency_k(a, b, INT_MAX)
FILE * lsx_open_input_file(sox_effect_t * effp, char const * filename);
@@ -283,7 +284,7 @@
#define TEXTUAL_PARAMETER(name, enum_table) { \
lsx_enum_item const * e; \
if (argc == 0) break; \
- e = lsx_find_enum_text(*argv, enum_table); \
+ e = lsx_find_enum_text(*argv, enum_table, 0); \
if (e != NULL) { \
p->name = e->value; \
--argc, ++argv; \
--- a/src/synth.c
+++ b/src/synth.c
@@ -6,6 +6,25 @@
* This source code is freely redistributable and may be used for any purpose.
* This copyright notice must be maintained. The authors are not responsible
* for the consequences of using this software.
+ *
+ * Except for synth types: pluck, tpdf, & brownnoise, and sweep types: linear
+ * square & exp, which are:
+ *
+ * Copyright (c) 2006-2009 robs@users.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
@@ -152,12 +171,12 @@
double p1, p2, p3; /* Use depends on synth type */
/* internal stuff */
- double cycle_start_time_s;
- double last_out;
+ double lp_last_out, hp_last_out, hp_last_in, ap_last_out, ap_last_in;
+ double cycle_start_time_s, c0, c1, c2, c3, c4;
PinkNoise pink_noise;
double * buffer;
- size_t buffer_len, pos, dx, dy, acc;
+ size_t buffer_len, pos;
} channel_t;
@@ -208,12 +227,12 @@
chan->p1 = 0.1;
chan->p2 = 0.5;
chan->p3 = 0.6;
- } else if (chan->p2 < 0) { /* try a symetric waveform */
+ } else if (chan->p2 < 0) { /* try a symmetric waveform */
if (chan->p1 <= 0.5) {
chan->p2 = (1 - 2 * chan->p1) / 2;
chan->p3 = chan->p2 + chan->p1;
} else {
- /* symetric is not possible, fall back to asymetrical triangle */
+ /* symetric is not possible, fall back to asymmetrical triangle */
chan->p2 = chan->p1;
chan->p3 = 1;
}
@@ -237,7 +256,7 @@
if (chan->p1 < 0)
chan->p1 = .4;
if (chan->p2 < 0)
- chan->p2 = 0;
+ chan->p2 = .2, chan->p3 = .9;
default: break;
}
@@ -267,12 +286,15 @@
priv_t * p = (priv_t *) effp->priv;
channel_t master, * chan = &master;
int key = INT_MAX, argn = 0;
- char dummy;
+ char dummy, * end_ptr;
--argc, ++argv;
if (argc && !strcmp(*argv, "-n")) p->no_headroom = sox_true, ++argv, --argc;
- if (argc > 1 && !strcmp(*argv, "-j") && sscanf(argv[1], "%i %c", &key, &dummy) == 1) {
+ if (argc > 1 && !strcmp(*argv, "-j") && (
+ sscanf(argv[1], "%i %c", &key, &dummy) == 1 || (
+ (key = lsx_parse_note(argv[1], &end_ptr)) != INT_MAX &&
+ !*end_ptr))) {
argc -= 2;
argv += 2;
}
@@ -299,8 +321,7 @@
}
while (argn < argc) { /* type [combine] [f1[-f2] [off [ph [p1 [p2 [p3]]]]]] */
- char * end_ptr;
- lsx_enum_item const *enum_p = lsx_find_enum_text(argv[argn], synth_type);
+ lsx_enum_item const * enum_p = lsx_find_enum_text(argv[argn], synth_type, LSX_FET_CASE);
if (enum_p == NULL) {
lsx_fail("no type given");
@@ -314,7 +335,7 @@
break;
/* maybe there is a combine-type in next arg */
- enum_p = lsx_find_enum_text(argv[argn], combine_type);
+ enum_p = lsx_find_enum_text(argv[argn], combine_type, LSX_FET_CASE);
if (enum_p != NULL) {
chan->combine = enum_p->value;
if (++argn == argc)
@@ -322,16 +343,21 @@
}
/* read frequencies if given */
- if (isdigit((int) argv[argn][0]) ||
- argv[argn][0] == '.' || argv[argn][0] == '%') {
+ if (!lsx_find_enum_text(argv[argn], synth_type, LSX_FET_CASE) &&
+ argv[argn][0] != '-') {
static const char sweeps[] = ":+/-";
chan->freq2 = chan->freq = lsx_parse_frequency_k(argv[argn], &end_ptr, key);
- if (chan->freq < 0) {
+ if (chan->freq < (chan->type == synth_pluck? 27.5 : 0) ||
+ (chan->type == synth_pluck && chan->freq > 4220)) {
lsx_fail("invalid freq");
return SOX_EOF;
}
if (*end_ptr && strchr(sweeps, *end_ptr)) { /* freq2 given? */
+ if (chan->type >= synth_noise) {
+ lsx_fail("can't sweep this type");
+ return SOX_EOF;
+ }
chan->sweep = strchr(sweeps, *end_ptr) - sweeps;
chan->freq2 = lsx_parse_frequency_k(end_ptr + 1, &end_ptr, key);
if (chan->freq2 < 0) {
@@ -384,7 +410,7 @@
static int start(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
- size_t i, j;
+ size_t i, j, k;
p->samples_done = 0;
@@ -399,24 +425,64 @@
*chan = p->getopts_channels[i % p->getopts_nchannels];
set_default_parameters(chan, i);
if (chan->type == synth_pluck) {
- int32_t r = 0;
- double colour = pow(2., 4 * (chan->p2 - 1));
- double dc = 0, a = 6.9 / (chan->p2 < .25? chan->p2 / .25 * 11 + 7 :
- chan->p2 <= .55? 18 : (1-chan->p2) / .45 * 3 + 15);
- chan->buffer_len = effp->in_signal.rate / chan->freq + .5;
- chan->dx = chan->freq * 1000 + .5;
- chan->dy = effp->in_signal.rate / chan->buffer_len * 1000 + .5;
- chan->pos = chan->acc = 0;
- chan->buffer = malloc(chan->buffer_len * sizeof(*chan->buffer));
- chan->buffer[0] = 0;
- for (j = 1; j < chan->buffer_len; dc += chan->buffer[j++])
- do chan->buffer[j] =
- chan->buffer[j - 1] + (chan->p3 == 0? DRANQD1:dranqd1(r)) * colour;
- while (fabs(chan->buffer[j]) > 1);
- for (dc /= chan->buffer_len, j = 0; j < chan->buffer_len; ++j)
- chan->buffer[j] = range_limit(chan->buffer[j] - dc, -1, 1) * a;
- chan->p3 = .5 * exp(log(.6) / chan->freq / chan->p1);
- lsx_debug("a=%g colour=%g", a, 1/colour);
+ double min, max, frac, p2;
+ double const decay_rate = -2; /* dB / s */
+ double const decay_f = min(912, 266 + 106 * log(chan->freq));
+ double d = sqr(dB_to_linear(decay_rate / chan->freq));
+ d = (d * cos(2 * M_PI * decay_f / effp->in_signal.rate) - 1) / (d - 1);
+ chan->c0 = d - sqrt(d * d - 1);
+ chan->c1 = 1 - chan->c0;
+
+ chan->c1 *= exp(-2e4/ (.05+chan->p1)/ chan->freq/ effp->in_signal.rate);
+
+ chan->c2 = exp(-2 * M_PI * 10 / effp->in_signal.rate);
+ chan->c3 = (1 + chan->c2) * .5;
+
+ if (effp->in_signal.rate < 44100 || effp->in_signal.rate > 48000) {
+ lsx_fail("sample rate for pluck must be 44100-48000; use `rate' to resample");
+ return SOX_EOF;
+ }
+ d = chan->c0 / (chan->c0 + chan->c1);
+
+ chan->buffer_len = effp->in_signal.rate / chan->freq - d;
+ frac = effp->in_signal.rate / chan->freq - d - chan->buffer_len;
+ chan->c4 = (1 - frac) / (1 + frac);
+ chan->pos = 0;
+
+ chan->buffer = lsx_calloc(chan->buffer_len, sizeof(*chan->buffer));
+ for (k = 0, p2 = chan->p2; k < 2 && p2 >= 0; ++k, p2 = chan->p3) {
+ double d1 = 0, d, colour = pow(2., 4 * (p2 - 1));
+ int32_t r = p2 * 100 + .5;
+ for (j = 0; j < chan->buffer_len; ++j) {
+ do d = d1 + (chan->phase? DRANQD1:dranqd1(r)) * colour;
+ while (fabs(d) > 1);
+ chan->buffer[j] += d * (1 - .3 * k);
+ d1 = d * (colour != 1);
+#ifdef TEST_PLUCK
+ chan->buffer[j] = sin(2 * M_PI * j / chan->buffer_len);
+#endif
+ }
+ }
+ for (j = 0, min = max = 0; j < chan->buffer_len; ++j) {
+ double d, t = (double)j / chan->buffer_len;
+ chan->lp_last_out = d =
+ chan->buffer[j] * chan->c1 + chan->lp_last_out * chan->c0;
+
+ chan->ap_last_out =
+ d * chan->c4 + chan->ap_last_in - chan->ap_last_out * chan->c4;
+ chan->ap_last_in = d;
+
+ chan->buffer[j] = chan->buffer[j] * (1 - t) + chan->ap_last_out * t;
+ min = min(min, chan->buffer[j]);
+ max = max(max, chan->buffer[j]);
+ }
+ for (j = 0, d = 0; j < chan->buffer_len; ++j) {
+ chan->buffer[j] = (2 * chan->buffer[j] - max - min) / (max - min);
+ d += sqr(chan->buffer[j]);
+ }
+ lsx_debug("rms=%f c0=%f c1=%f c2=%f c3=%f df=%f d3f=%f",
+ 10 * log(d / chan->buffer_len), chan->c0, chan->c1, chan->c2,
+ chan->c3, decay_f, log(chan->c0)/ -2 / M_PI * effp->in_signal.rate);
}
switch (chan->sweep) {
case Linear: chan->mult = p->samples_to_do?
@@ -587,22 +653,27 @@
break;
case synth_brownnoise:
- do synth_out = chan->last_out + DRANQD1 * (1. / 16);
+ do synth_out = chan->lp_last_out + DRANQD1 * (1. / 16);
while (fabs(synth_out) > 1);
- chan->last_out = synth_out;
+ chan->lp_last_out = synth_out;
break;
case synth_pluck: {
- size_t pos1 = chan->pos + 1 == chan->buffer_len? 0 : chan->pos + 1;
- double t = (double)chan->acc / chan->dy;
- synth_out = chan->buffer[chan->pos] * (1-t) + chan->buffer[pos1] * t;
- for (chan->acc+=chan->dx; chan->acc>=chan->dy; chan->acc-=chan->dy) {
- t = chan->buffer[chan->pos];
- chan->buffer[chan->pos] =
- chan->p3 * (chan->buffer[chan->pos] + chan->last_out);
- chan->last_out = t;
- chan->pos = chan->pos + 1 == chan->buffer_len? 0 : chan->pos + 1;
- }
+ double d = chan->buffer[chan->pos];
+
+ chan->hp_last_out =
+ (d - chan->hp_last_in) * chan->c3 + chan->hp_last_out * chan->c2;
+ chan->hp_last_in = d;
+
+ synth_out = range_limit(chan->hp_last_out, -1, 1);
+
+ chan->lp_last_out = d = d * chan->c1 + chan->lp_last_out * chan->c0;
+
+ chan->ap_last_out = chan->buffer[chan->pos] =
+ (d - chan->ap_last_out) * chan->c4 + chan->ap_last_in;
+ chan->ap_last_in = d;
+
+ chan->pos = chan->pos + 1 == chan->buffer_len? 0 : chan->pos + 1;
break;
}
--- a/src/util.c
+++ b/src/util.c
@@ -58,14 +58,17 @@
return result;
}
-lsx_enum_item const * lsx_find_enum_text(char const * text, lsx_enum_item const * enum_items)
+lsx_enum_item const * lsx_find_enum_text(char const * text, lsx_enum_item const * enum_items, unsigned flags)
{
lsx_enum_item const * result = NULL; /* Assume not found */
+ sox_bool sensitive = !!(flags & LSX_FET_CASE);
while (enum_items->text) {
- if (strcasecmp(text, enum_items->text) == 0)
+ if ((!sensitive && !strcasecmp(text, enum_items->text)) ||
+ ( sensitive && ! strcmp(text, enum_items->text)))
return enum_items; /* Found exact match */
- if (strncasecmp(text, enum_items->text, strlen(text)) == 0) {
+ if ((!sensitive && !strncasecmp(text, enum_items->text, strlen(text))) ||
+ ( sensitive && ! strncmp(text, enum_items->text, strlen(text)))) {
if (result != NULL && result->value != enum_items->value)
return NULL; /* Found ambiguity */
result = enum_items; /* Found sub-string match */
@@ -85,7 +88,7 @@
int lsx_enum_option(int c, lsx_enum_item const * items)
{
- lsx_enum_item const * p = lsx_find_enum_text(lsx_optarg, items);
+ lsx_enum_item const * p = lsx_find_enum_text(lsx_optarg, items, sox_false);
if (p == NULL) {
size_t len = 1;
char * set = lsx_malloc(len);
--- a/src/vol.c
+++ b/src/vol.c
@@ -60,7 +60,7 @@
}
if (have_type) {
- lsx_enum_item const * p = lsx_find_enum_text(type_ptr, vol_types);
+ lsx_enum_item const * p = lsx_find_enum_text(type_ptr, vol_types, 0);
if (!p)
return lsx_usage(effp);
switch (p->value) {