/* WhySynth DSSI software synthesizer plugin and GUI * * Copyright (C) 2004-2006 Sean Bolton and others. * * 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., 59 Temple Place, Suite 330, Boston, * MA 02111-1307, USA. */ #include #include #include #include #include #include #include "whysynth_types.h" #include "whysynth.h" #include "whysynth_voice.h" y_patch_t y_init_voice = { " <-->", "", /* -PORTS- */ { 1, 0, 0, 0.0f, 0, 0.0f, 0.0f, 0.0f, 0, 0.0f, 0, 0.0f, 0.5f, 0.5f }, /* osc1 */ { 0, 0, 0, 0.0f, 0, 0.0f, 0.0f, 0.0f, 0, 0.0f, 0, 0.0f, 0.5f, 0.5f }, /* osc2 */ { 0, 0, 0, 0.0f, 0, 0.0f, 0.0f, 0.0f, 0, 0.0f, 0, 0.0f, 0.5f, 0.5f }, /* osc3 */ { 0, 0, 0, 0.0f, 0, 0.0f, 0.0f, 0.0f, 0, 0.0f, 0, 0.0f, 0.5f, 0.5f }, /* osc4 */ { 1, 0, 50.0f, 0, 0.0f, 0.0f, 0.0f }, /* vcf1 */ { 0, 0, 50.0f, 0, 0.0f, 0.0f, 0.0f }, /* vcf2 */ 0.0f, 0.2f, 0.0f, 0.8f, 0.5f, 0.5f, 0.5f, 0.5f, /* mix */ 0.5f, /* volume */ 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, /* effects */ 0.984375f, 2, /* glide / bend */ { 1.0f, 0, 0.0f, 0, 0.0f }, /* glfo */ { 1.0f, 0, 0.0f, 0, 0.0f }, /* vlfo */ { 1.0f, 0, 0.0f, 0, 0.0f }, 90.0f, 0.0f, /* mlfo */ { 1, 3, 0.004, 1, 3, 0.001, 1, 3, 0.001, 1, 3, 0.2, 0, 0, 0, 0, 0 }, /* ego */ { 0, 3, 0.1, 1, 3, 0.1, 1, 3, 0.1, 1, 3, 0.2, 0, 0, 0, 0, 0 }, /* eg1 */ { 0, 3, 0.1, 1, 3, 0.1, 1, 3, 0.1, 1, 3, 0.2, 0, 0, 0, 0, 0 }, /* eg2 */ { 0, 3, 0.1, 1, 3, 0.1, 1, 3, 0.1, 1, 3, 0.2, 0, 0, 0, 0, 0 }, /* eg3 */ { 0, 3, 0.1, 1, 3, 0.1, 1, 3, 0.1, 1, 3, 0.2, 0, 0, 0, 0, 0 }, /* eg4 */ 1.0f, 0, 0.0f, 0, 0.0f /* modmix */ }; int y_data_is_comment(char *buf) /* line is blank, whitespace, or first non-whitespace character is '#' */ { int i = 0; while (buf[i]) { if (buf[i] == '#') return 1; if (buf[i] == '\n') return 1; if (buf[i] != ' ' && buf[i] != '\t') return 0; i++; } return 1; } void y_data_parse_text(const char *buf, char *name, int maxlen) { int i = 0, o = 0; unsigned int t; while (buf[i] && o < maxlen) { if (buf[i] < 33 || buf[i] > 126) { break; } else if (buf[i] == '%') { if (buf[i + 1] && buf[i + 2] && sscanf(buf + i + 1, "%2x", &t) == 1) { name[o++] = (char)t; i += 3; } else { break; } } else { name[o++] = buf[i++]; } } /* trim trailing spaces */ while (o && name[o - 1] == ' ') o--; name[o] = '\0'; } int y_data_read_patch(FILE *file, y_patch_t *patch) { int i; char c, buf[256], buf2[180]; y_patch_t tmp; do { if (!fgets(buf, 256, file)) return 0; } while (y_data_is_comment(buf)); if (sscanf(buf, " WhySynth patch format %d begin", &i) != 1 || i != 0) return 0; memcpy(&tmp, &y_init_voice, sizeof(y_patch_t)); while (1) { if (!fgets(buf, 256, file)) return 0; /* 'name %20%20' */ if (sscanf(buf, " name %90s", buf2) == 1) { y_data_parse_text(buf2, tmp.name, 30); continue; /* 'comment %20%20' */ } else if (sscanf(buf, " comment %180s", buf2) == 1) { y_data_parse_text(buf2, tmp.comment, 60); continue; /* -PORTS- */ /* 'oscY 1 1 0 0 0 0 0 0 0.5 0 0 0 0 0.5 0.5' */ /* 'oscY 2 0 0 0 0 0 0 0 0.5 0 0 0 0 0.5 0.5' */ /* 'oscY 3 0 0 0 0 0 0 0 0.5 0 0 0 0 0.5 0.5' */ /* 'oscY 4 0 0 0 0 0 0 0 0.5 0 0 0 0 0.5 0.5' */ } else if (sscanf(buf, " oscY %d", &i) == 1) { struct posc *osc; switch (i) { case 1: osc = &tmp.osc1; break; case 2: osc = &tmp.osc2; break; case 3: osc = &tmp.osc3; break; case 4: osc = &tmp.osc4; break; default: return 0; } if (sscanf(buf, " oscY %d %d %d %d %f %d %f %f %f %d %f %d %f %f %f", &i, &osc->mode, &osc->waveform, &osc->pitch, &osc->detune, &osc->pitch_mod_src, &osc->pitch_mod_amt, &osc->mparam1, &osc->mparam2, &osc->mmod_src, &osc->mmod_amt, &osc->amp_mod_src, &osc->amp_mod_amt, &osc->level_a, &osc->level_b) != 15) return 0; continue; /* 'vcfY 1 1 0 50 0 0 0 0' */ /* 'vcfY 2 0 0 50 0 0 0 0' */ } else if (sscanf(buf, " vcfY %d", &i) == 1) { struct pvcf *vcf; switch (i) { case 1: vcf = &tmp.vcf1; break; case 2: vcf = &tmp.vcf2; break; default: return 0; } if (sscanf(buf, " vcfY %d %d %d %f %d %f %f %f", &i, &vcf->mode, &vcf->source, &vcf->frequency, &vcf->freq_mod_src, &vcf->freq_mod_amt, &vcf->qres, &vcf->mparam) != 8) return 0; continue; /* 'mix 0 0.2 0 0.8 0.5 0.5 0.5 0.5' */ } else if (sscanf(buf, " mix %f %f %f %f %f %f %f %f", &tmp.busa_level, &tmp.busa_pan, &tmp.busb_level, &tmp.busb_pan, &tmp.vcf1_level, &tmp.vcf1_pan, &tmp.vcf2_level, &tmp.vcf2_pan) == 8) { continue; /* 'volume 0.5' */ } else if (sscanf(buf, " volume %f", &tmp.volume) == 1) { continue; /* 'effects 0 0 0 0 0' */ } else if (sscanf(buf, " effects %d %f %f %f %f %f %f %f", &tmp.effect_mode, &tmp.effect_param1, &tmp.effect_param2, &tmp.effect_param3, &tmp.effect_param4, &tmp.effect_param5, &tmp.effect_param6, &tmp.effect_mix) == 8) { continue; /* 'glide 0.984375' */ } else if (sscanf(buf, " glide %f", &tmp.glide_time) == 1) { continue; /* 'bend 2' */ } else if (sscanf(buf, " bend %d", &tmp.bend_range) == 1) { continue; /* 'lfoY g 1 0 0 0 0' */ /* 'lfoY v 1 0 0 0 0' */ /* 'lfoY m 1 0 0 0 0' */ } else if (sscanf(buf, " lfoY %c", &c) == 1) { struct plfo *lfo; switch (c) { case 'g': lfo = &tmp.glfo; break; case 'v': lfo = &tmp.vlfo; break; case 'm': lfo = &tmp.mlfo; break; default: return 0; } if (sscanf(buf, " lfoY %c %f %d %f %d %f", &c, &lfo->frequency, &lfo->waveform, &lfo->delay, &lfo->amp_mod_src, &lfo->amp_mod_amt) != 6) return 0; /* 'mlfo 90 0' */ } else if (sscanf(buf, " mlfo %f %f", &tmp.mlfo_phase_spread, &tmp.mlfo_random_freq) == 2) { continue; /* 'egY o 0 0.1 1 0.1 1 0.1 1 0.2 0.1 1 0 0 0 0 0' */ /* 'egY 1 0 0.1 1 0.1 1 0.1 1 0.2 0.1 1 0 0 0 0 0' */ /* 'egY 2 0 0.1 1 0.1 1 0.1 1 0.2 0.1 1 0 0 0 0 0' */ /* 'egY 3 0 0.1 1 0.1 1 0.1 1 0.2 0.1 1 0 0 0 0 0' */ /* 'egY 4 0 0.1 1 0.1 1 0.1 1 0.2 0.1 1 0 0 0 0 0' */ } else if (sscanf(buf, " egY %c", &c) == 1) { struct peg *eg; switch (c) { case 'o': eg = &tmp.ego; break; case '1': eg = &tmp.eg1; break; case '2': eg = &tmp.eg2; break; case '3': eg = &tmp.eg3; break; case '4': eg = &tmp.eg4; break; default: return 0; } if (sscanf(buf, " egY %c %d %d %f %f %d %f %f %d %f %f %d %f %f %f %f %d %f", &c, &eg->mode, &eg->shape1, &eg->time1, &eg->level1, &eg->shape2, &eg->time2, &eg->level2, &eg->shape3, &eg->time3, &eg->level3, &eg->shape4, &eg->time4, &eg->vel_level_sens, &eg->vel_time_scale, &eg->kbd_time_scale, &eg->amp_mod_src, &eg->amp_mod_amt) != 18) return 0; /* 'modmix 1 0 0 0 0' */ } else if (sscanf(buf, " modmix %f %d %f %d %f", &tmp.modmix_bias, &tmp.modmix_mod1_src, &tmp.modmix_mod1_amt, &tmp.modmix_mod2_src, &tmp.modmix_mod2_amt) == 5) { continue; /* 'WhySynth patch end' */ } else if (sscanf(buf, " WhySynth patch %3s", buf2) == 1 && !strcmp(buf2, "end")) { break; /* finished */ } else { return 0; /* unrecognized line */ } } memcpy(patch, &tmp, sizeof(y_patch_t)); return 1; /* -FIX- error handling yet to be implemented */ } char * y_data_locate_patch_file(const char *origpath, const char *project_dir) { struct stat statbuf; char *path; const char *filename; if (stat(origpath, &statbuf) == 0) return strdup(origpath); else if (!project_dir) return NULL; filename = strrchr(origpath, '/'); if (filename) ++filename; else filename = origpath; if (!*filename) return NULL; path = (char *)malloc(strlen(project_dir) + strlen(filename) + 2); sprintf(path, "%s/%s", project_dir, filename); if (stat(path, &statbuf) == 0) return path; free(path); return NULL; }