ref: bd9a87f83679670922ae60e1bfdfb84d11430fed
parent: 8fa8463f38cdfa14f0d2b2330d431f0f96e47402
author: robs <robs>
date: Thu Nov 30 16:04:53 EST 2006
Fix parser, fix exp defaults, allow abbreviations.
--- a/src/synth.c
+++ b/src/synth.c
@@ -16,6 +16,26 @@
#include <ctype.h>
#include "st_i.h"
+typedef struct {char const *text; int value;} enum_item;
+#define ENUM_ITEM(prefix, item) {#item, prefix##item},
+
+static enum_item const * find(char const * text, enum_item const * enum_items)
+{
+ enum_item const * result = NULL; /* Assume not found */
+
+ while (enum_items->text)
+ {
+ if (strncasecmp(text, enum_items->text, strlen(text)) == 0)
+ {
+ if (result != NULL && result->value != enum_items->value)
+ return NULL; /* Found ambiguity */
+ result = enum_items; /* Found match */
+ }
+ ++enum_items;
+ }
+ return result;
+}
+
static st_effect_t st_synth_effect;
#define PCOUNT 5
@@ -24,17 +44,40 @@
#define SYNTH_SQUARE 1
#define SYNTH_SAWTOOTH 2
#define SYNTH_TRIANGLE 3
-#define SYNTH_TRAPETZ 4
+#define SYNTH_TRAPEZIUM 4
+#define SYNTH_TRAPETZ SYNTH_TRAPEZIUM /* Deprecated name for trapezium */
#define SYNTH_WHITENOISE 5
+#define SYNTH_NOISE SYNTH_WHITENOISE /* Just a handy alias */
#define SYNTH_PINKNOISE 6
#define SYNTH_BROWNNOISE 7
-#define SYNTH_VOICENOISE 8
-#define SYNTH_EXP 9
+#define SYNTH_EXP 8
#define SYNTH_CREATE 0x000
#define SYNTH_MIX 0x100
#define SYNTH_AMOD 0x200
#define SYNTH_FMOD 0x400
+
+enum_item const synth_type[] = {
+ ENUM_ITEM(SYNTH_,SINE )
+ ENUM_ITEM(SYNTH_,SQUARE )
+ ENUM_ITEM(SYNTH_,SAWTOOTH )
+ ENUM_ITEM(SYNTH_,TRIANGLE )
+ ENUM_ITEM(SYNTH_,TRAPEZIUM )
+ ENUM_ITEM(SYNTH_,TRAPETZ )
+ ENUM_ITEM(SYNTH_,WHITENOISE)
+ ENUM_ITEM(SYNTH_,NOISE )
+ ENUM_ITEM(SYNTH_,PINKNOISE )
+ ENUM_ITEM(SYNTH_,BROWNNOISE)
+ ENUM_ITEM(SYNTH_,EXP )
+ {0}};
+
+enum_item const combine_type[] = {
+ ENUM_ITEM(SYNTH_,CREATE)
+ ENUM_ITEM(SYNTH_,MIX )
+ ENUM_ITEM(SYNTH_,AMOD )
+ ENUM_ITEM(SYNTH_,FMOD )
+ {0}};
+
/* do not ask me for the colored noise, i copied the
* algorithm somewhere...
*/
@@ -271,121 +314,64 @@
argn++;
}
/* for one or more channel */
- /* type [mix] [f1[-f2]] [p0] [p1] [p2] [p3] [p4] */
- for(c=0;c<MAXCHAN;c++){
- if(n > argn){
- /* next par must be type */
- if( strcasecmp(argv[argn],"sine")==0){
- synth->type[c]=SYNTH_SINE;
- argn++; /* 1 */
- }else if( strcasecmp(argv[argn],"square")==0){
- synth->type[c]=SYNTH_SQUARE;
- argn++; /* 1 */
- }else if( strcasecmp(argv[argn],"sawtooth")==0){
- synth->type[c]=SYNTH_SAWTOOTH;
- argn++; /* 1 */
- }else if( strcasecmp(argv[argn],"triangle")==0){
- synth->type[c]=SYNTH_TRIANGLE;
- argn++; /* 1 */
- }else if( strcasecmp(argv[argn],"exp")==0){
- synth->type[c]=SYNTH_EXP;
- argn++; /* 1 */
- }else if( strcasecmp(argv[argn],"trapetz")==0){
- synth->type[c]=SYNTH_TRAPETZ;
- argn++;
- }else if( strcasecmp(argv[argn],"whitenoise")==0){
- synth->type[c]=SYNTH_WHITENOISE;
- argn++; /* 1 */
- }else if( strcasecmp(argv[argn],"noise")==0){
- synth->type[c]=SYNTH_WHITENOISE;
- argn++; /* 1 */
- }else if( strcasecmp(argv[argn],"pinknoise")==0){
- synth->type[c]=SYNTH_PINKNOISE;
- argn++; /* 1 */
- }else if( strcasecmp(argv[argn],"brownnoise")==0){
- synth->type[c]=SYNTH_BROWNNOISE;
- argn++; /* 1 */
- }else if( strcasecmp(argv[argn],"voicenoise")==0){
- synth->type[c]=SYNTH_VOICENOISE;
- argn++; /* 1 */
- }else{
- /* type not given, error */
- st_warn("synth: no type given");
- st_fail(st_synth_effect.usage);
- return(ST_EOF);
- }
- if(n > argn){
- /* maybe there is a mix-type in next arg */
- if(strcasecmp(argv[argn],"create")==0){
- synth->mix[c]=SYNTH_CREATE;
- argn++;
- }else if(strcasecmp(argv[argn],"mix")==0){
- synth->mix[c]=SYNTH_MIX;
- argn++;
- }else if(strcasecmp(argv[argn],"amod")==0){
- synth->mix[c]=SYNTH_AMOD;
- argn++;
- }else if(strcasecmp(argv[argn],"fmod")==0){
- synth->mix[c]=SYNTH_FMOD;
- argn++;
- }
- if(n > argn){
- /* read frequency's if given */
- synth->freq[c]= StringToFreq(argv[argn],&hlp);
- synth->freq2[c] = synth->freq[c];
- if(synth->freq[c] < 0.0){
- st_warn("synth: illegal freq");
- st_fail(st_synth_effect.usage);
- return(ST_EOF);
- }
- if(*hlp=='-') {
- /* freq2 given ! */
- char *hlp2;
- synth->freq2[c]=StringToFreq(hlp+1,&hlp2);
- if(synth->freq2[c] < 0.0){
- st_warn("synth: illegal freq2");
- st_fail(st_synth_effect.usage);
- return(ST_EOF);
- }
- }
- argn++;
- i=0;
- /* read rest of parameters */
- while(n > argn){
- if( ! isdigit((int)argv[argn][0]) ){
- /* not a digit, must be type of next channel */
- break;
- }
- if( i >= PCOUNT) {
- st_warn("synth: too many parameters");
- st_fail(st_synth_effect.usage);
- return(ST_EOF);
-
- }
- synth->par[c][i]=strtod(argv[argn],&hlp);
- if(hlp==argv[argn]){
- /* error in number */
- st_warn("synth: parameter error");
- st_fail(st_synth_effect.usage);
- return(ST_EOF);
- }
- i++;
- argn++;
- }/* .. while */
- if(n > argn){
- /* got here by 'break', scan parms for next chan */
- }else{
- break;
- }
- }
- }
- } /* if n > argn */
- }/* for .. */
+ /* type [combine] [f1[-f2]] [p0] [p1] [p2] [p3] [p4] */
+ for (c = 0; c < MAXCHAN && n > argn; c++) {
+ enum_item const * p = find(argv[argn], synth_type);
+ if (p == NULL) {
+ st_fail("no type given");
+ return ST_EOF;
+ }
+ synth->type[c] = p->value;
+ if (++argn == n) break;
+
+ /* maybe there is a combine-type in next arg */
+ p = find(argv[argn], combine_type);
+ if (p != NULL) {
+ synth->mix[c] = p->value;
+ if (++argn == n) break;
+ }
+
+ /* read frequencies if given */
+ if (isdigit((int)argv[argn][0]) || argv[argn][0] == '%') {
+ synth->freq2[c] = synth->freq[c] = StringToFreq(argv[argn], &hlp);
+ if (synth->freq[c] < 0) {
+ st_fail("invalid freq");
+ return ST_EOF;
+ }
+ if (*hlp == '-') { /* freq2 given? */
+ char * hlp2;
+ synth->freq2[c] = StringToFreq(hlp + 1, &hlp2);
+ if (synth->freq2[c] < 0) {
+ st_fail("invalid freq2");
+ return ST_EOF;
+ }
+ if (synth->length_str == NULL) {
+ st_fail("length must be given when using freq2");
+ return ST_EOF;
+ }
+ }
+ if (++argn == n) break;
+ }
+
+ /* read rest of parameters */
+ for (i = 0; argn < n && isdigit((int)argv[argn][0]); ++i, ++argn) {
+ if (i == PCOUNT) {
+ st_fail("too many parameters");
+ return ST_EOF;
+ }
+ synth->par[c][i] = strtod(argv[argn], &hlp);
+ if (hlp == argv[argn]) {
+ st_fail("parameter error");
+ return ST_EOF;
+ }
+ }
+ if (argn == n) break;
+ }
/* make some intelligent parameter initialization for channels
* where no parameters were given
*
- * - of only parms for one channel were given, copy to ther channels
+ * - if only parms for one channel were given, copy to other channels
* - if parm for 2 channels were given, copy to channel 1->3, 2->4
* - if parm for 3 channels were given, copy 2->4
*/
@@ -491,6 +477,16 @@
/* Initialize pink noise signals with different numbers of rows. */
InitializePinkNoise( &(synth->pinkn[c]),10+2*c);
break;
+ case SYNTH_EXP:
+ /* p2 is position of maximum*/
+ if (synth->par[c][2] < 0)
+ synth->par[c][2] = 0.5;
+
+ /* p2 is amplitude */
+ if (synth->par[c][3] < 0)
+ synth->par[c][3] = 1;
+ break;
+
default:
break;
}
@@ -737,20 +733,20 @@
static st_effect_t st_synth_effect = {
"synth",
- "Usage: synth [length] type mix [freq[-freq2]] [off] [ph] [p1] [p2] [p3]\n"
- " <length> length in sec or hh:mm:ss.frac, 0=inputlength, default=0\n"
- " <type> is sine, square, triangle, sawtooth, trapetz, exp,\n"
- " whitenoise, pinknoise, brownnoise, default=sine\n"
- " <mix> is create, mix, amod, default=create\n"
- " <freq> frequency at beginning in Hz, not used for noise..\n"
- " <freq2> frequency at end in Hz, not used for noise..\n"
- " <freq/2> can be given as %%n, where 'n' is the number of\n"
- " half notes in respect to A (440Hz)\n"
- " <off> Bias (DC-offset) of signal in percent, default=0\n"
- " <ph> phase shift 0..100 shift phase 0..2*Pi, not used for noise..\n"
- " <p1> square: Ton/Toff, triangle+trapetz: rising slope time (0..100)\n"
- " <p2> trapetz: ON time (0..100)\n"
- " <p3> trapetz: falling slope position (0..100)",
+ "Usage: synth [len] {[type] [combine] [freq[-freq2]] [off] [ph] [p1] [p2] [p3]}\n"
+ " length length in sec or hh:mm:ss.frac, 0=inputlength, default=0\n"
+ " type is sine, square, triangle, sawtooth, trapezium, exp,\n"
+ " [white]noise, pinknoise, brownnoise; default=sine\n"
+ " combine is create, mix, amod, fmod; default=create\n"
+ " freq frequency at beginning in Hz, not used for noise..\n"
+ " freq2 frequency at end in Hz, not used for noise..\n"
+ " freqs can be given as %n, where 'n' is the number of\n"
+ " half notes relative to A (440Hz)\n"
+ " off Bias (DC-offset) of signal in percent; default=0\n"
+ " ph phase shift 0..100 shift phase 0..2*Pi, not used for noise..\n"
+ " p1 square: Ton, triangle+trapezium+exp: rising slope time (0..100)\n"
+ " p2 trapezium: ON time, exp: amplitude (0..100)\n"
+ " p3 trapezium: falling slope position (0..100)",
ST_EFF_MCHAN,
st_synth_getopts,
st_synth_start,