Unified · Split
| @@ -26,7 +26,6 @@ · 25 unmodified lines | |||
| 26 | # --------------------------------------------------------------------------- | 26 | # --------------------------------------------------------------------------- |
| 27 | 27 | ||
| 28 | SOX=../src/sox | 28 | SOX=../src/sox |
| 29 | PLAY=../src/play | ||
| 30 | 29 | ||
| 31 | rm -f 2tones.ul # Make sure we append to a file that's initially empty | 30 | rm -f 2tones.ul # Make sure we append to a file that's initially empty |
| 32 | 31 | ||
| @@ -45,4 +44,4 @@ done · 12 unmodified lines | |||
| 45 | $SOX -c 1 -r 8000 alert.ul alert.au # Add a file header | 44 | $SOX -c 1 -r 8000 alert.ul alert.au # Add a file header |
| 46 | rm 2tones.ul alert.ul # Tidy up intermediate files | 45 | rm 2tones.ul alert.ul # Tidy up intermediate files |
| 47 | 46 | ||
| 48 | $PLAY alert.au | 47 | $SOX alert.au -d |
| @@ -1,6 +1,6 @@ | |||
| 1 | #!/bin/sh | 1 | #!/bin/sh |
| 2 | 2 | ||
| 3 | # SoX script: synth.sh (c) 2008 robs@users.sourceforge.net | 3 | # SoX script: synth.sh (c) 2008-9 robs@users.sourceforge.net |
| 4 | # | 4 | # |
| 5 | # This program is free software; you can redistribute it and/or modify it | 5 | # This program is free software; you can redistribute it and/or modify it |
| 6 | # under the terms of the GNU General Public License as published by the | 6 | # under the terms of the GNU General Public License as published by the |
| @@ -17,7 +17,6 @@ · 10 unmodified lines | |||
| 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| 18 | 18 | ||
| 19 | sox=../src/sox | 19 | sox=../src/sox |
| 20 | play=../src/play | ||
| 21 | 20 | ||
| 22 | G0="pl %-26 pl %-19 pl %-14 pl %-10 pl %-7 pl %-2" | 21 | G0="pl %-26 pl %-19 pl %-14 pl %-10 pl %-7 pl %-2" |
| 23 | A0="pl %-24 pl %-17 pl %-12 pl %-8 pl %-5 pl %0" | 22 | A0="pl %-24 pl %-17 pl %-12 pl %-8 pl %-5 pl %0" |
| @@ -26,12 +25,22 @@ D0="pl %-24 pl %-19 pl %-12 pl %-7 pl %-3 pl %0" · 2 unmodified lines | |||
| 26 | E0="pl %-22 pl %-17 pl %-10 pl %-5 pl %-1 pl %2" | 25 | E0="pl %-22 pl %-17 pl %-10 pl %-5 pl %-1 pl %2" |
| 27 | Bb0="pl %-23 pl %-16 pl %-11 pl %-7 pl %-4 pl %1" | 26 | Bb0="pl %-23 pl %-16 pl %-11 pl %-7 pl %-4 pl %1" |
| 28 | 27 | ||
| 29 | o="overdrive 40 gain -8" | 28 | o="overdrive 27 gain -11" |
| 30 | e="delay 0 .02 .04 .06 .08 .1 remix - $o fade 0" | 29 | e="delay 0 .02 .04 .06 .08 .1 remix - overdrive 33 gain -8 fade 0" |
| 31 | s="$sox -q -n -p synth 0 0 0 80 87" | 30 | s="$sox -q -n -p synth 0 0 1 60 90" |
| 32 | l="$sox -q -n -p synth 0 0 0 80 0 0" | 31 | l="$sox -q -n -p synth 0 0 0 50 20" |
| 33 | 32 | ||
| 34 | $play -m -v .8 \ | 33 | b="$sox -np synth 0 0 0 30 20 pl" |
| 34 | c3="fade h 0 .75" | ||
| 35 | c="fade h 0 .25" | ||
| 36 | cs="fade h 0 .25 .05" | ||
| 37 | m="fade h 0 .5" | ||
| 38 | sb="fade h 0 1" | ||
| 39 | r="$sox -np trim 0 .25" | ||
| 40 | r2="$sox -np trim 0 .5" | ||
| 41 | r3="$sox -np trim 0 .75" | ||
| 42 | |||
| 43 | $sox -m -v .8 \ | ||
| 35 | "|$sox \ | 44 | "|$sox \ |
| 36 | \"|$sox -n -p synth noise fade 0 .5 .48 trim 0 .15\" \ | 45 | \"|$sox -n -p synth noise fade 0 .5 .48 trim 0 .15\" \ |
| 37 | \"|$sox -n -p synth noise fade h 0 .26 .11 gain -35 lowpass -1 12k\" \ | 46 | \"|$sox -n -p synth noise fade h 0 .26 .11 gain -35 lowpass -1 12k\" \ |
| @@ -63,15 +72,15 @@ equalizer 1500 10 8 pad 0 .21 remix 1 1 reverb 10 repeat 56" \ · 25 unmodified lines | |||
| 63 | \"|$l pl %10 $o trim 0 .5 bend .2,-300,.1\" \ | 72 | \"|$l pl %10 $o trim 0 .5 bend .2,-300,.1\" \ |
| 64 | \"|$l pl %5 $o trim 0 .5 bend .2,-200,.1\" \ | 73 | \"|$l pl %5 $o trim 0 .5 bend .2,-200,.1\" \ |
| 65 | \"|$l pl %0 $o fade 0 .55 .1 bend .2,-200,.1\" \ | 74 | \"|$l pl %0 $o fade 0 .55 .1 bend .2,-200,.1\" \ |
| 66 | \"|$l pl %0 $o fade 0 2 .1\" \ | 75 | \"|$l pl %0 $o fade h 0 2 .5\" \ |
| 67 | \"|$sox -n -p trim 0 3.95\" \ | 76 | \"|$sox -n -p trim 0 3.95\" \ |
| 68 | \"|$l pl %12 $o trim 0 .5 bend .2,-200,.1\" \ | 77 | \"|$l pl %12 $o trim 0 .5 bend .2,-200,.1\" \ |
| 69 | \"|$l pl %12 $o trim 0 .5 bend .2,-200,.1\" \ | 78 | \"|$l pl %12 $o trim 0 .5 bend .2,-200,.1\" \ |
| 70 | \"|$l pl %12 $o fade 0 .8 .1 bend .2,-200,.1\" \ | 79 | \"|$l pl %12 $o fade 0 .8 .1 bend .2,-200,.1\" \ |
| 71 | \"|$l pl %12 $o trim 0 .3 bend .1,-200,.1\" \ | 80 | \"|$l pl %12 $o trim 0 .3 bend .1,-200,.1\" \ |
| 72 | \"|$l pl %12 $o trim 0 1.95 bend .3,-50,1\" \ | 81 | \"|$l pl %12 $o fade 0 1.95 .6 bend .0,-50,1.75 gain 3\" \ |
| 73 | \"|$l pl %10 $o trim 0 2 bend .3,-50,1\" \ | 82 | \"|$l pl %10 $o fade 0 2 .6 bend .0,-50,1.9\" \ |
| 74 | \"|$l pl %9 $o trim 0 2 gain -3\" \ | 83 | \"|$l pl %9 $o trim 0 2 gain -1\" \ |
| 75 | \"|$l pl %8 $o fade h 0 1 .3\" \ | 84 | \"|$l pl %8 $o fade h 0 1 .3\" \ |
| 76 | \"|$l pl %8 $o fade h 0 1 .1 gain 1.5\" \ | 85 | \"|$l pl %8 $o fade h 0 1 .1 gain 1.5\" \ |
| 77 | \"|$l pl %2 pl %7 delay 0 .02 remix - $o trim 0 .25\" \ | 86 | \"|$l pl %2 pl %7 delay 0 .02 remix - $o trim 0 .25\" \ |
| @@ -83,4 +92,100 @@ equalizer 1500 10 8 pad 0 .21 remix 1 1 reverb 10 repeat 56" \ · 5 unmodified lines | |||
| 83 | \"|$l pl %2 pl %7 delay 0 .02 remix - $o trim 0 .25\" \ | 92 | \"|$l pl %2 pl %7 delay 0 .02 remix - $o trim 0 .25\" \ |
| 84 | \"|$l pl %-5 $o trim 0 .25\" \ | 93 | \"|$l pl %-5 $o trim 0 .25\" \ |
| 85 | \"|$l pl %2 pl %7 delay 0 .02 remix - $o fade h 0 6 6\" \ | 94 | \"|$l pl %2 pl %7 delay 0 .02 remix - $o fade h 0 6 6\" \ |
| 86 | -p gain -4 remix 1 1 flanger" | 95 | -p gain -4 remix 1 1 flanger" \ |
| 96 | "|$sox \ | ||
| 97 | \"|$sox -n -p trim 0 1.5\" \ | ||
| 98 | \"|$b G1 $m contrast\" \ | ||
| 99 | \"|$b A1 $c3 contrast\" \ | ||
| 100 | \"|$b G#1 $c\" \ | ||
| 101 | \"|$b A1 $c3\" \ | ||
| 102 | \"|$r\" \ | ||
| 103 | \ | ||
| 104 | \"|$b C2 $cs\" \ | ||
| 105 | \"|$b C2 $cs\" \ | ||
| 106 | \"|$r\" \ | ||
| 107 | \"|$b B1 $cs\" \ | ||
| 108 | \"|$b C2 $c3\" \ | ||
| 109 | \"|$r\" \ | ||
| 110 | \ | ||
| 111 | \"|$b D2 $cs\" \ | ||
| 112 | \"|$b D2 $cs\" \ | ||
| 113 | \"|$r\" \ | ||
| 114 | \"|$b C#2 $cs\" \ | ||
| 115 | \"|$b D2 $c\" \ | ||
| 116 | \"|$b C#2 $m\" \ | ||
| 117 | \"|$r\" \ | ||
| 118 | \ | ||
| 119 | \"|$b D2 $cs\" \ | ||
| 120 | \"|$b D2 $cs\" \ | ||
| 121 | \"|$r\" \ | ||
| 122 | \"|$b C#2 $cs\" \ | ||
| 123 | \"|$b D2 $c\" \ | ||
| 124 | \"|$b C#2 $c\" \ | ||
| 125 | \"|$b D2 $c\" \ | ||
| 126 | \"|$b E2 $c\" \ | ||
| 127 | \ | ||
| 128 | \"|$b A1 $c3 contrast\" \ | ||
| 129 | \"|$b B1 $c\" \ | ||
| 130 | \"|$b A1 $c\" \ | ||
| 131 | \"|$b G#1 $c\" \ | ||
| 132 | \"|$b A1 $c\" \ | ||
| 133 | \"|$b B1 $c\" \ | ||
| 134 | \ | ||
| 135 | \"|$b C2 $c3\" \ | ||
| 136 | \"|$b B1 $c\" \ | ||
| 137 | \"|$b C2 $c\" \ | ||
| 138 | \"|$b D2 $c\" \ | ||
| 139 | \"|$b C2 $c\" \ | ||
| 140 | \"|$b B1 $c\" \ | ||
| 141 | \ | ||
| 142 | \"|$b D2 $c3\" \ | ||
| 143 | \"|$b E2 $c\" \ | ||
| 144 | \"|$b D2 $c\" \ | ||
| 145 | \"|$b C#2 $c\" \ | ||
| 146 | \"|$b D2 $c\" \ | ||
| 147 | \"|$b E2 $c\" \ | ||
| 148 | \ | ||
| 149 | \"|$b D2 $c3\" \ | ||
| 150 | \"|$b C#2 $c\" \ | ||
| 151 | \"|$b D2 $c\" \ | ||
| 152 | \"|$b E2 $c\" \ | ||
| 153 | \"|$b D2 $c\" \ | ||
| 154 | \"|$b C#2 $c\" \ | ||
| 155 | \ | ||
| 156 | \"|$b A1 $cs\" \ | ||
| 157 | \"|$b A1 $cs\" \ | ||
| 158 | \"|$r\" \ | ||
| 159 | \"|$b G#1 $c\" \ | ||
| 160 | \"|$b A1 $c3\" \ | ||
| 161 | \"|$b B1 $c\" \ | ||
| 162 | \ | ||
| 163 | \"|$b C2 $c\" \ | ||
| 164 | \"|$b B1 $c\" \ | ||
| 165 | \"|$b C2 $c\" \ | ||
| 166 | \"|$b D2 $c\" \ | ||
| 167 | \"|$b C2 $c3\" \ | ||
| 168 | \"|$r\" \ | ||
| 169 | \ | ||
| 170 | \"|$b D2 $m\" \ | ||
| 171 | \"|$b E2 $m\" \ | ||
| 172 | \"|$b D2 $c\" \ | ||
| 173 | \"|$b C#2 $c\" \ | ||
| 174 | \"|$b D2 $c\" \ | ||
| 175 | \"|$b E2 $c\" \ | ||
| 176 | \ | ||
| 177 | \"|$b F2 $m\" \ | ||
| 178 | \"|$b Bb1 $m\" \ | ||
| 179 | \"|$b C2 $c\" \ | ||
| 180 | \"|$b F2 $c\" \ | ||
| 181 | \"|$b D2 $c\" \ | ||
| 182 | \"|$b Bb1 $c\" \ | ||
| 183 | \ | ||
| 184 | \"|$b E1 $m\" \ | ||
| 185 | \"|$b E2 $m\" \ | ||
| 186 | \"|$b D2 $c\" \ | ||
| 187 | \"|$b E2 $m\" \ | ||
| 188 | \"|$b B1 $c\" \ | ||
| 189 | \ | ||
| 190 | \"|$b E1 $sb\" \ | ||
| 191 | -p lowpass -1 1k remix 1p-12 1p-12" -d | ||
| @@ -273,7 +273,7 @@ if [ $soxver -ge 1403 ]; then · 272 unmodified lines | |||
| 273 | echo; echo "Plucked scale:" | 273 | echo; echo "Plucked scale:" |
| 274 | 274 | ||
| 275 | options= | 275 | options= |
| 276 | overdrive= | 276 | overdrive="gain -3" |
| 277 | for f in pluck pluck_dist; do | 277 | for f in pluck pluck_dist; do |
| 278 | next_file $f 42 | 278 | next_file $f 42 |
| 279 | note=-29 | 279 | note=-29 |
| @@ -289,14 +289,13 @@ if [ $soxver -ge 1403 ]; then · 9 unmodified lines | |||
| 289 | $input -t s32 - synth .4 pluck %$note $options >> tmp.s32 | 289 | $input -t s32 - synth .4 pluck %$note $options >> tmp.s32 |
| 290 | note=$(($note - 1)) | 290 | note=$(($note - 1)) |
| 291 | done | 291 | done |
| 292 | $input -t s32 - synth pluck %$note $options fade h 0 2 .1 >> tmp.s32 | 292 | $input -t s32 - synth pluck %$note $options fade t 0 4 3.6 >> tmp.s32 |
| 293 | 293 | ||
| 294 | $sox -r $rate -c 1 tmp.s32 $output compand .1,.2 6:-70,-60,-20 -7 -15 .1 \ | 294 | $sox -r $rate -c 1 tmp.s32 $output $overdrive remix 1 1 reverb 30 |
| 295 | $overdrive pad 0 2 remix 1 1 reverb 30 | ||
| 296 | 295 | ||
| 297 | rm -f tmp.s32 | 296 | rm -f tmp.s32 |
| 298 | options="0 0 60 60" | 297 | options="0 0 60 75 0" |
| 299 | overdrive="overdrive 30 gain -9" | 298 | overdrive="overdrive gain -10" |
| 300 | done | 299 | done |
| 301 | fi | 300 | fi |
| 302 | 301 | ||
| @@ -1891,8 +1891,8 @@ The following (one long) command plays a chime sound: · 1890 unmodified lines | |||
| 1891 | and this plays a guitar chord: | 1891 | and this plays a guitar chord: |
| 1892 | .EX | 1892 | .EX |
| 1893 | .ne 2 | 1893 | .ne 2 |
| 1894 | play -n synth -j -2 pl %-26 pl %-22 pl %-19 pl %-14 pl %-7 \\ | 1894 | play -n synth pl G2 pl B2 pl D3 pl G3 pl D4 pl G4 \\ |
| 1895 | pl %-2 delay 0 .05 .1 .15 .2 .25 remix - fade 0 4 .1 norm -1 | 1895 | delay 0 .05 .1 .15 .2 .25 remix - fade 0 4 .1 norm -1 |
| 1896 | .EE | 1896 | .EE |
| 1897 | .TP | 1897 | .TP |
| 1898 | \fBdither\fR [\fB\-a\fR] [\fB\-S\fR\^|\^\fB\-s\fR\^|\^\fB\-f \fIfilter\fR] | 1898 | \fBdither\fR [\fB\-a\fR] [\fB\-S\fR\^|\^\fB\-s\fR\^|\^\fB\-f \fIfilter\fR] |
| @@ -21,6 +21,7 @@ · 20 unmodified lines | |||
| 21 | #define LSX_EFF_ALIAS | 21 | #define LSX_EFF_ALIAS |
| 22 | #include "sox_i.h" | 22 | #include "sox_i.h" |
| 23 | #include <string.h> | 23 | #include <string.h> |
| 24 | #include <ctype.h> | ||
| 24 | 25 | ||
| 25 | int lsx_usage(sox_effect_t * effp) | 26 | int lsx_usage(sox_effect_t * effp) |
| 26 | { | 27 | { |
| @@ -290,9 +291,24 @@ static double calc_note_freq(double note, int key) · 263 unmodified lines | |||
| 290 | return 440 * pow(2., note / 12); | 291 | return 440 * pow(2., note / 12); |
| 291 | } | 292 | } |
| 292 | 293 | ||
| 294 | int lsx_parse_note(char const * text, char * * end_ptr) | ||
| 295 | { | ||
| 296 | int result = INT_MAX; | ||
| 297 | |||
| 298 | if (*text >= 'A' && *text <= 'G') { | ||
| 299 | result = (int)(5/3. * (*text++ - 'A') + 9.5) % 12 - 9; | ||
| 300 | if (*text == 'b') {--result; ++text;} | ||
| 301 | else if (*text == '#') {++result; ++text;} | ||
| 302 | if (isdigit(*text)) | ||
| 303 | result += 12 * (*text++ - '4'); | ||
| 304 | } | ||
| 305 | *end_ptr = (char *)text; | ||
| 306 | return result; | ||
| 307 | } | ||
| 308 | |||
| 293 | /* Read string 'text' and convert to frequency. | 309 | /* Read string 'text' and convert to frequency. |
| 294 | * 'text' can be a positive number which is the frequency in Hz. | 310 | * 'text' can be a positive number which is the frequency in Hz. |
| 295 | * If 'text' starts with a hash '%' and a following number the corresponding | 311 | * If 'text' starts with a '%' and a following number the corresponding |
| 296 | * note is calculated. | 312 | * note is calculated. |
| 297 | * Return -1 on error. | 313 | * Return -1 on error. |
| 298 | */ | 314 | */ |
| @@ -306,6 +322,10 @@ double lsx_parse_frequency_k(char const * text, char * * end_ptr, int key) · 7 unmodified lines | |||
| 306 | return -1; | 322 | return -1; |
| 307 | return calc_note_freq(result, key); | 323 | return calc_note_freq(result, key); |
| 308 | } | 324 | } |
| 325 | if (*text >= 'A' && *text <= 'G') { | ||
| 326 | int result = lsx_parse_note(text, end_ptr); | ||
| 327 | return result == INT_MAX? - 1 : calc_note_freq((double)result, key); | ||
| 328 | } | ||
| 309 | result = strtod(text, end_ptr); | 329 | result = strtod(text, end_ptr); |
| 310 | if (end_ptr) { | 330 | if (end_ptr) { |
| 311 | if (*end_ptr == text) | 331 | if (*end_ptr == text) |
| @@ -2091,7 +2091,7 @@ static lsx_enum_item const encodings[] = { · 2090 unmodified lines | |||
| 2091 | 2091 | ||
| 2092 | static int enum_option(int option_index, lsx_enum_item const * items) | 2092 | static int enum_option(int option_index, lsx_enum_item const * items) |
| 2093 | { | 2093 | { |
| 2094 | lsx_enum_item const * p = lsx_find_enum_text(lsx_optarg, items); | 2094 | lsx_enum_item const * p = lsx_find_enum_text(lsx_optarg, items, 0); |
| 2095 | if (p == NULL) { | 2095 | if (p == NULL) { |
| 2096 | size_t len = 1; | 2096 | size_t len = 1; |
| 2097 | char * set = lsx_malloc(len); | 2097 | char * set = lsx_malloc(len); |
| @@ -565,7 +565,8 @@ void lsx_debug(const char *, ...) PRINTF; · 564 unmodified lines | |||
| 565 | typedef struct {char const *text; unsigned value;} lsx_enum_item; | 565 | typedef struct {char const *text; unsigned value;} lsx_enum_item; |
| 566 | #define LSX_ENUM_ITEM(prefix, item) {#item, prefix##item}, | 566 | #define LSX_ENUM_ITEM(prefix, item) {#item, prefix##item}, |
| 567 | 567 | ||
| 568 | lsx_enum_item const * lsx_find_enum_text(char const * text, lsx_enum_item const * lsx_enum_items); | 568 | lsx_enum_item const * lsx_find_enum_text(char const * text, lsx_enum_item const * lsx_enum_items, unsigned flags); |
| 569 | #define LSX_FET_CASE 1 | ||
| 569 | lsx_enum_item const * lsx_find_enum_value(unsigned value, lsx_enum_item const * lsx_enum_items); | 570 | lsx_enum_item const * lsx_find_enum_value(unsigned value, lsx_enum_item const * lsx_enum_items); |
| 570 | int lsx_enum_option(int c, lsx_enum_item const * items); | 571 | int lsx_enum_option(int c, lsx_enum_item const * items); |
| 571 | sox_bool lsx_strends(char const * str, char const * end); | 572 | sox_bool lsx_strends(char const * str, char const * end); |
| @@ -82,6 +82,7 @@ void lsx_generate_wave_table( · 81 unmodified lines | |||
| 82 | double max, /* Maximum value on the y-axis. (e.g. +1) */ | 82 | double max, /* Maximum value on the y-axis. (e.g. +1) */ |
| 83 | double phase); /* Phase at 1st point; 0..2pi. (e.g. pi/2 for cosine) */ | 83 | double phase); /* Phase at 1st point; 0..2pi. (e.g. pi/2 for cosine) */ |
| 84 | char const * lsx_parsesamples(sox_rate_t rate, const char *str, size_t *samples, int def); | 84 | char const * lsx_parsesamples(sox_rate_t rate, const char *str, size_t *samples, int def); |
| 85 | int lsx_parse_note(char const * text, char * * end_ptr); | ||
| 85 | double lsx_parse_frequency_k(char const * text, char * * end_ptr, int key); | 86 | double lsx_parse_frequency_k(char const * text, char * * end_ptr, int key); |
| 86 | #define lsx_parse_frequency(a, b) lsx_parse_frequency_k(a, b, INT_MAX) | 87 | #define lsx_parse_frequency(a, b) lsx_parse_frequency_k(a, b, INT_MAX) |
| 87 | FILE * lsx_open_input_file(sox_effect_t * effp, char const * filename); | 88 | FILE * lsx_open_input_file(sox_effect_t * effp, char const * filename); |
| @@ -283,7 +284,7 @@ char * lsx_usage_lines(char * * usage, char const * const * lines, size_t n); · 195 unmodified lines | |||
| 283 | #define TEXTUAL_PARAMETER(name, enum_table) { \ | 284 | #define TEXTUAL_PARAMETER(name, enum_table) { \ |
| 284 | lsx_enum_item const * e; \ | 285 | lsx_enum_item const * e; \ |
| 285 | if (argc == 0) break; \ | 286 | if (argc == 0) break; \ |
| 286 | e = lsx_find_enum_text(*argv, enum_table); \ | 287 | e = lsx_find_enum_text(*argv, enum_table, 0); \ |
| 287 | if (e != NULL) { \ | 288 | if (e != NULL) { \ |
| 288 | p->name = e->value; \ | 289 | p->name = e->value; \ |
| 289 | --argc, ++argv; \ | 290 | --argc, ++argv; \ |
| @@ -6,6 +6,25 @@ · 5 unmodified lines | |||
| 6 | * This source code is freely redistributable and may be used for any purpose. | 6 | * This source code is freely redistributable and may be used for any purpose. |
| 7 | * This copyright notice must be maintained. The authors are not responsible | 7 | * This copyright notice must be maintained. The authors are not responsible |
| 8 | * for the consequences of using this software. | 8 | * for the consequences of using this software. |
| 9 | * | ||
| 10 | * Except for synth types: pluck, tpdf, & brownnoise, and sweep types: linear | ||
| 11 | * square & exp, which are: | ||
| 12 | * | ||
| 13 | * Copyright (c) 2006-2009 robs@users.sourceforge.net | ||
| 14 | * | ||
| 15 | * This library is free software; you can redistribute it and/or modify it | ||
| 16 | * under the terms of the GNU Lesser General Public License as published by | ||
| 17 | * the Free Software Foundation; either version 2.1 of the License, or (at | ||
| 18 | * your option) any later version. | ||
| 19 | * | ||
| 20 | * This library is distributed in the hope that it will be useful, but | ||
| 21 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser | ||
| 23 | * General Public License for more details. | ||
| 24 | * | ||
| 25 | * You should have received a copy of the GNU Lesser General Public License | ||
| 26 | * along with this library; if not, write to the Free Software Foundation, | ||
| 27 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 9 | */ | 28 | */ |
| 10 | 29 | ||
| 11 | #include "sox_i.h" | 30 | #include "sox_i.h" |
| @@ -152,12 +171,12 @@ typedef struct { · 140 unmodified lines | |||
| 152 | double p1, p2, p3; /* Use depends on synth type */ | 171 | double p1, p2, p3; /* Use depends on synth type */ |
| 153 | 172 | ||
| 154 | /* internal stuff */ | 173 | /* internal stuff */ |
| 155 | double cycle_start_time_s; | 174 | double lp_last_out, hp_last_out, hp_last_in, ap_last_out, ap_last_in; |
| 156 | double last_out; | 175 | double cycle_start_time_s, c0, c1, c2, c3, c4; |
| 157 | PinkNoise pink_noise; | 176 | PinkNoise pink_noise; |
| 158 | 177 | ||
| 159 | double * buffer; | 178 | double * buffer; |
| 160 | size_t buffer_len, pos, dx, dy, acc; | 179 | size_t buffer_len, pos; |
| 161 | } channel_t; | 180 | } channel_t; |
| 162 | 181 | ||
| 163 | 182 | ||
| @@ -208,12 +227,12 @@ static void set_default_parameters(channel_t * chan, size_t c) · 44 unmodified lines | |||
| 208 | chan->p1 = 0.1; | 227 | chan->p1 = 0.1; |
| 209 | chan->p2 = 0.5; | 228 | chan->p2 = 0.5; |
| 210 | chan->p3 = 0.6; | 229 | chan->p3 = 0.6; |
| 211 | } else if (chan->p2 < 0) { /* try a symetric waveform */ | 230 | } else if (chan->p2 < 0) { /* try a symmetric waveform */ |
| 212 | if (chan->p1 <= 0.5) { | 231 | if (chan->p1 <= 0.5) { |
| 213 | chan->p2 = (1 - 2 * chan->p1) / 2; | 232 | chan->p2 = (1 - 2 * chan->p1) / 2; |
| 214 | chan->p3 = chan->p2 + chan->p1; | 233 | chan->p3 = chan->p2 + chan->p1; |
| 215 | } else { | 234 | } else { |
| 216 | /* symetric is not possible, fall back to asymetrical triangle */ | 235 | /* symetric is not possible, fall back to asymmetrical triangle */ |
| 217 | chan->p2 = chan->p1; | 236 | chan->p2 = chan->p1; |
| 218 | chan->p3 = 1; | 237 | chan->p3 = 1; |
| 219 | } | 238 | } |
| @@ -237,7 +256,7 @@ static void set_default_parameters(channel_t * chan, size_t c) · 17 unmodified lines | |||
| 237 | if (chan->p1 < 0) | 256 | if (chan->p1 < 0) |
| 238 | chan->p1 = .4; | 257 | chan->p1 = .4; |
| 239 | if (chan->p2 < 0) | 258 | if (chan->p2 < 0) |
| 240 | chan->p2 = 0; | 259 | chan->p2 = .2, chan->p3 = .9; |
| 241 | 260 | ||
| 242 | default: break; | 261 | default: break; |
| 243 | } | 262 | } |
| @@ -267,12 +286,15 @@ static int getopts(sox_effect_t * effp, int argc, char **argv) · 23 unmodified lines | |||
| 267 | priv_t * p = (priv_t *) effp->priv; | 286 | priv_t * p = (priv_t *) effp->priv; |
| 268 | channel_t master, * chan = &master; | 287 | channel_t master, * chan = &master; |
| 269 | int key = INT_MAX, argn = 0; | 288 | int key = INT_MAX, argn = 0; |
| 270 | char dummy; | 289 | char dummy, * end_ptr; |
| 271 | --argc, ++argv; | 290 | --argc, ++argv; |
| 272 | 291 | ||
| 273 | if (argc && !strcmp(*argv, "-n")) p->no_headroom = sox_true, ++argv, --argc; | 292 | if (argc && !strcmp(*argv, "-n")) p->no_headroom = sox_true, ++argv, --argc; |
| 274 | 293 | ||
| 275 | if (argc > 1 && !strcmp(*argv, "-j") && sscanf(argv[1], "%i %c", &key, &dummy) == 1) { | 294 | if (argc > 1 && !strcmp(*argv, "-j") && ( |
| 295 | sscanf(argv[1], "%i %c", &key, &dummy) == 1 || ( | ||
| 296 | (key = lsx_parse_note(argv[1], &end_ptr)) != INT_MAX && | ||
| 297 | !*end_ptr))) { | ||
| 276 | argc -= 2; | 298 | argc -= 2; |
| 277 | argv += 2; | 299 | argv += 2; |
| 278 | } | 300 | } |
| @@ -299,8 +321,7 @@ static int getopts(sox_effect_t * effp, int argc, char **argv) · 20 unmodified lines | |||
| 299 | } | 321 | } |
| 300 | 322 | ||
| 301 | while (argn < argc) { /* type [combine] [f1[-f2] [off [ph [p1 [p2 [p3]]]]]] */ | 323 | while (argn < argc) { /* type [combine] [f1[-f2] [off [ph [p1 [p2 [p3]]]]]] */ |
| 302 | char * end_ptr; | 324 | lsx_enum_item const * enum_p = lsx_find_enum_text(argv[argn], synth_type, LSX_FET_CASE); |
| 303 | lsx_enum_item const *enum_p = lsx_find_enum_text(argv[argn], synth_type); | ||
| 304 | 325 | ||
| 305 | if (enum_p == NULL) { | 326 | if (enum_p == NULL) { |
| 306 | lsx_fail("no type given"); | 327 | lsx_fail("no type given"); |
| @@ -314,7 +335,7 @@ static int getopts(sox_effect_t * effp, int argc, char **argv) · 7 unmodified lines | |||
| 314 | break; | 335 | break; |
| 315 | 336 | ||
| 316 | /* maybe there is a combine-type in next arg */ | 337 | /* maybe there is a combine-type in next arg */ |
| 317 | enum_p = lsx_find_enum_text(argv[argn], combine_type); | 338 | enum_p = lsx_find_enum_text(argv[argn], combine_type, LSX_FET_CASE); |
| 318 | if (enum_p != NULL) { | 339 | if (enum_p != NULL) { |
| 319 | chan->combine = enum_p->value; | 340 | chan->combine = enum_p->value; |
| 320 | if (++argn == argc) | 341 | if (++argn == argc) |
| @@ -322,16 +343,21 @@ static int getopts(sox_effect_t * effp, int argc, char **argv) · 1 unmodified line | |||
| 322 | } | 343 | } |
| 323 | 344 | ||
| 324 | /* read frequencies if given */ | 345 | /* read frequencies if given */ |
| 325 | if (isdigit((int) argv[argn][0]) || | 346 | if (!lsx_find_enum_text(argv[argn], synth_type, LSX_FET_CASE) && |
| 326 | argv[argn][0] == '.' || argv[argn][0] == '%') { | 347 | argv[argn][0] != '-') { |
| 327 | static const char sweeps[] = ":+/-"; | 348 | static const char sweeps[] = ":+/-"; |
| 328 | 349 | ||
| 329 | chan->freq2 = chan->freq = lsx_parse_frequency_k(argv[argn], &end_ptr, key); | 350 | chan->freq2 = chan->freq = lsx_parse_frequency_k(argv[argn], &end_ptr, key); |
| 330 | if (chan->freq < 0) { | 351 | if (chan->freq < (chan->type == synth_pluck? 27.5 : 0) || |
| 352 | (chan->type == synth_pluck && chan->freq > 4220)) { | ||
| 331 | lsx_fail("invalid freq"); | 353 | lsx_fail("invalid freq"); |
| 332 | return SOX_EOF; | 354 | return SOX_EOF; |
| 333 | } | 355 | } |
| 334 | if (*end_ptr && strchr(sweeps, *end_ptr)) { /* freq2 given? */ | 356 | if (*end_ptr && strchr(sweeps, *end_ptr)) { /* freq2 given? */ |
| 357 | if (chan->type >= synth_noise) { | ||
| 358 | lsx_fail("can't sweep this type"); | ||
| 359 | return SOX_EOF; | ||
| 360 | } | ||
| 335 | chan->sweep = strchr(sweeps, *end_ptr) - sweeps; | 361 | chan->sweep = strchr(sweeps, *end_ptr) - sweeps; |
| 336 | chan->freq2 = lsx_parse_frequency_k(end_ptr + 1, &end_ptr, key); | 362 | chan->freq2 = lsx_parse_frequency_k(end_ptr + 1, &end_ptr, key); |
| 337 | if (chan->freq2 < 0) { | 363 | if (chan->freq2 < 0) { |
| @@ -384,7 +410,7 @@ static int getopts(sox_effect_t * effp, int argc, char **argv) · 46 unmodified lines | |||
| 384 | static int start(sox_effect_t * effp) | 410 | static int start(sox_effect_t * effp) |
| 385 | { | 411 | { |
| 386 | priv_t * p = (priv_t *)effp->priv; | 412 | priv_t * p = (priv_t *)effp->priv; |
| 387 | size_t i, j; | 413 | size_t i, j, k; |
| 388 | 414 | ||
| 389 | p->samples_done = 0; | 415 | p->samples_done = 0; |
| 390 | 416 | ||
| @@ -399,24 +425,64 @@ static int start(sox_effect_t * effp) · 8 unmodified lines | |||
| 399 | *chan = p->getopts_channels[i % p->getopts_nchannels]; | 425 | *chan = p->getopts_channels[i % p->getopts_nchannels]; |
| 400 | set_default_parameters(chan, i); | 426 | set_default_parameters(chan, i); |
| 401 | if (chan->type == synth_pluck) { | 427 | if (chan->type == synth_pluck) { |
| 402 | int32_t r = 0; | 428 | double min, max, frac, p2; |
| 403 | double colour = pow(2., 4 * (chan->p2 - 1)); | 429 | double const decay_rate = -2; /* dB / s */ |
| 404 | double dc = 0, a = 6.9 / (chan->p2 < .25? chan->p2 / .25 * 11 + 7 : | 430 | double const decay_f = min(912, 266 + 106 * log(chan->freq)); |
| 405 | chan->p2 <= .55? 18 : (1-chan->p2) / .45 * 3 + 15); | 431 | double d = sqr(dB_to_linear(decay_rate / chan->freq)); |
| 406 | chan->buffer_len = effp->in_signal.rate / chan->freq + .5; | 432 | d = (d * cos(2 * M_PI * decay_f / effp->in_signal.rate) - 1) / (d - 1); |
| 407 | chan->dx = chan->freq * 1000 + .5; | 433 | chan->c0 = d - sqrt(d * d - 1); |
| 408 | chan->dy = effp->in_signal.rate / chan->buffer_len * 1000 + .5; | 434 | chan->c1 = 1 - chan->c0; |
| 409 | chan->pos = chan->acc = 0; | 435 | |
| 410 | chan->buffer = malloc(chan->buffer_len * sizeof(*chan->buffer)); | 436 | chan->c1 *= exp(-2e4/ (.05+chan->p1)/ chan->freq/ effp->in_signal.rate); |
| 411 | chan->buffer[0] = 0; | 437 | |
| 412 | for (j = 1; j < chan->buffer_len; dc += chan->buffer[j++]) | 438 | chan->c2 = exp(-2 * M_PI * 10 / effp->in_signal.rate); |
| 413 | do chan->buffer[j] = | 439 | chan->c3 = (1 + chan->c2) * .5; |
| 414 | chan->buffer[j - 1] + (chan->p3 == 0? DRANQD1:dranqd1(r)) * colour; | 440 | |
| 415 | while (fabs(chan->buffer[j]) > 1); | 441 | if (effp->in_signal.rate < 44100 || effp->in_signal.rate > 48000) { |
| 416 | for (dc /= chan->buffer_len, j = 0; j < chan->buffer_len; ++j) | 442 | lsx_fail("sample rate for pluck must be 44100-48000; use `rate' to resample"); |
| 417 | chan->buffer[j] = range_limit(chan->buffer[j] - dc, -1, 1) * a; | 443 | return SOX_EOF; |
| 418 | chan->p3 = .5 * exp(log(.6) / chan->freq / chan->p1); | 444 | } |
| 419 | lsx_debug("a=%g colour=%g", a, 1/colour); | 445 | d = chan->c0 / (chan->c0 + chan->c1); |
| 446 | |||
| 447 | chan->buffer_len = effp->in_signal.rate / chan->freq - d; | ||
| 448 | frac = effp->in_signal.rate / chan->freq - d - chan->buffer_len; | ||
| 449 | chan->c4 = (1 - frac) / (1 + frac); | ||
| 450 | chan->pos = 0; | ||
| 451 | |||
| 452 | chan->buffer = lsx_calloc(chan->buffer_len, sizeof(*chan->buffer)); | ||
| 453 | for (k = 0, p2 = chan->p2; k < 2 && p2 >= 0; ++k, p2 = chan->p3) { | ||
| 454 | double d1 = 0, d, colour = pow(2., 4 * (p2 - 1)); | ||
| 455 | int32_t r = p2 * 100 + .5; | ||
| 456 | for (j = 0; j < chan->buffer_len; ++j) { | ||
| 457 | do d = d1 + (chan->phase? DRANQD1:dranqd1(r)) * colour; | ||
| 458 | while (fabs(d) > 1); | ||
| 459 | chan->buffer[j] += d * (1 - .3 * k); | ||
| 460 | d1 = d * (colour != 1); | ||
| 461 | #ifdef TEST_PLUCK | ||
| 462 | chan->buffer[j] = sin(2 * M_PI * j / chan->buffer_len); | ||
| 463 | #endif | ||
| 464 | } | ||
| 465 | } | ||
| 466 | for (j = 0, min = max = 0; j < chan->buffer_len; ++j) { | ||
| 467 | double d, t = (double)j / chan->buffer_len; | ||
| 468 | chan->lp_last_out = d = | ||
| 469 | chan->buffer[j] * chan->c1 + chan->lp_last_out * chan->c0; | ||
| 470 | |||
| 471 | chan->ap_last_out = | ||
| 472 | d * chan->c4 + chan->ap_last_in - chan->ap_last_out * chan->c4; | ||
| 473 | chan->ap_last_in = d; | ||
| 474 | |||
| 475 | chan->buffer[j] = chan->buffer[j] * (1 - t) + chan->ap_last_out * t; | ||
| 476 | min = min(min, chan->buffer[j]); | ||
| 477 | max = max(max, chan->buffer[j]); | ||
| 478 | } | ||
| 479 | for (j = 0, d = 0; j < chan->buffer_len; ++j) { | ||
| 480 | chan->buffer[j] = (2 * chan->buffer[j] - max - min) / (max - min); | ||
| 481 | d += sqr(chan->buffer[j]); | ||
| 482 | } | ||
| 483 | lsx_debug("rms=%f c0=%f c1=%f c2=%f c3=%f df=%f d3f=%f", | ||
| 484 | 10 * log(d / chan->buffer_len), chan->c0, chan->c1, chan->c2, | ||
| 485 | chan->c3, decay_f, log(chan->c0)/ -2 / M_PI * effp->in_signal.rate); | ||
| 420 | } | 486 | } |
| 421 | switch (chan->sweep) { | 487 | switch (chan->sweep) { |
| 422 | case Linear: chan->mult = p->samples_to_do? | 488 | case Linear: chan->mult = p->samples_to_do? |
| @@ -587,22 +653,27 @@ static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, sox_sample_t * o · 164 unmodified lines | |||
| 587 | break; | 653 | break; |
| 588 | 654 | ||
| 589 | case synth_brownnoise: | 655 | case synth_brownnoise: |
| 590 | do synth_out = chan->last_out + DRANQD1 * (1. / 16); | 656 | do synth_out = chan->lp_last_out + DRANQD1 * (1. / 16); |
| 591 | while (fabs(synth_out) > 1); | 657 | while (fabs(synth_out) > 1); |
| 592 | chan->last_out = synth_out; | 658 | chan->lp_last_out = synth_out; |
| 593 | break; | 659 | break; |
| 594 | 660 | ||
| 595 | case synth_pluck: { | 661 | case synth_pluck: { |
| 596 | size_t pos1 = chan->pos + 1 == chan->buffer_len? 0 : chan->pos + 1; | 662 | double d = chan->buffer[chan->pos]; |
| 597 | double t = (double)chan->acc / chan->dy; | 663 | |
| 598 | synth_out = chan->buffer[chan->pos] * (1-t) + chan->buffer[pos1] * t; | 664 | chan->hp_last_out = |
| 599 | for (chan->acc+=chan->dx; chan->acc>=chan->dy; chan->acc-=chan->dy) { | 665 | (d - chan->hp_last_in) * chan->c3 + chan->hp_last_out * chan->c2; |
| 600 | t = chan->buffer[chan->pos]; | 666 | chan->hp_last_in = d; |
| 601 | chan->buffer[chan->pos] = | 667 | |
| 602 | chan->p3 * (chan->buffer[chan->pos] + chan->last_out); | 668 | synth_out = range_limit(chan->hp_last_out, -1, 1); |
| 603 | chan->last_out = t; | 669 | |
| 604 | chan->pos = chan->pos + 1 == chan->buffer_len? 0 : chan->pos + 1; | 670 | chan->lp_last_out = d = d * chan->c1 + chan->lp_last_out * chan->c0; |
| 605 | } | 671 | |
| 672 | chan->ap_last_out = chan->buffer[chan->pos] = | ||
| 673 | (d - chan->ap_last_out) * chan->c4 + chan->ap_last_in; | ||
| 674 | chan->ap_last_in = d; | ||
| 675 | |||
| 676 | chan->pos = chan->pos + 1 == chan->buffer_len? 0 : chan->pos + 1; | ||
| 606 | break; | 677 | break; |
| 607 | } | 678 | } |
| 608 | 679 | ||
| @@ -58,14 +58,17 @@ char const * lsx_find_file_extension(char const * pathname) · 57 unmodified lines | |||
| 58 | return result; | 58 | return result; |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | lsx_enum_item const * lsx_find_enum_text(char const * text, lsx_enum_item const * enum_items) | 61 | lsx_enum_item const * lsx_find_enum_text(char const * text, lsx_enum_item const * enum_items, unsigned flags) |
| 62 | { | 62 | { |
| 63 | lsx_enum_item const * result = NULL; /* Assume not found */ | 63 | lsx_enum_item const * result = NULL; /* Assume not found */ |
| 64 | sox_bool sensitive = !!(flags & LSX_FET_CASE); | ||
| 64 | 65 | ||
| 65 | while (enum_items->text) { | 66 | while (enum_items->text) { |
| 66 | if (strcasecmp(text, enum_items->text) == 0) | 67 | if ((!sensitive && !strcasecmp(text, enum_items->text)) || |
| 68 | ( sensitive && ! strcmp(text, enum_items->text))) | ||
| 67 | return enum_items; /* Found exact match */ | 69 | return enum_items; /* Found exact match */ |
| 68 | if (strncasecmp(text, enum_items->text, strlen(text)) == 0) { | 70 | if ((!sensitive && !strncasecmp(text, enum_items->text, strlen(text))) || |
| 71 | ( sensitive && ! strncmp(text, enum_items->text, strlen(text)))) { | ||
| 69 | if (result != NULL && result->value != enum_items->value) | 72 | if (result != NULL && result->value != enum_items->value) |
| 70 | return NULL; /* Found ambiguity */ | 73 | return NULL; /* Found ambiguity */ |
| 71 | result = enum_items; /* Found sub-string match */ | 74 | result = enum_items; /* Found sub-string match */ |
| @@ -85,7 +88,7 @@ lsx_enum_item const * lsx_find_enum_value(unsigned value, lsx_enum_item const * · 13 unmodified lines | |||
| 85 | 88 | ||
| 86 | int lsx_enum_option(int c, lsx_enum_item const * items) | 89 | int lsx_enum_option(int c, lsx_enum_item const * items) |
| 87 | { | 90 | { |
| 88 | lsx_enum_item const * p = lsx_find_enum_text(lsx_optarg, items); | 91 | lsx_enum_item const * p = lsx_find_enum_text(lsx_optarg, items, sox_false); |
| 89 | if (p == NULL) { | 92 | if (p == NULL) { |
| 90 | size_t len = 1; | 93 | size_t len = 1; |
| 91 | char * set = lsx_malloc(len); | 94 | char * set = lsx_malloc(len); |
| @@ -60,7 +60,7 @@ static int getopts(sox_effect_t * effp, int argc, char **argv) · 59 unmodified lines | |||
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | if (have_type) { | 62 | if (have_type) { |
| 63 | lsx_enum_item const * p = lsx_find_enum_text(type_ptr, vol_types); | 63 | lsx_enum_item const * p = lsx_find_enum_text(type_ptr, vol_types, 0); |
| 64 | if (!p) | 64 | if (!p) |
| 65 | return lsx_usage(effp); | 65 | return lsx_usage(effp); |
| 66 | switch (p->value) { | 66 | switch (p->value) { |