zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit ffca051ad9d7bfef49192de413a96e7f0c04605e
parent f6082564d4a88962ab230a4e124b5b2ae90a6783
Author: Johannes Lorenz <johannes89@ist-einmalig.de>
Date:   Mon, 18 Sep 2017 21:48:51 +0200

Tmp commit

Diffstat:
Msrc/Effects/Chorus.cpp | 35+++++++++++++++++++++++++----------
Msrc/Misc/Master.cpp | 399+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/Misc/Microtonal.cpp | 46++++++++++++++++++++++++++++++++--------------
Msrc/Misc/Part.cpp | 51+++++++++++++++++++++++++++++++++++----------------
Msrc/Params/ADnoteParameters.cpp | 156++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/Synth/OscilGen.cpp | 9++++++---
6 files changed, 565 insertions(+), 131 deletions(-)

diff --git a/src/Effects/Chorus.cpp b/src/Effects/Chorus.cpp @@ -39,17 +39,32 @@ rtosc::Ports Chorus::ports = { rEnd}, //Pvolume/Ppanning are common - rEffPar(Pfreq, 2, rShort("freq"), "Effect Frequency"), - rEffPar(Pfreqrnd, 3, rShort("rand"), "Frequency Randomness"), + rEffParVol(rDefault(64)), + rEffParPan(), + rEffPar(Pfreq, 2, rShort("freq"), + rPresets(50, 45, 29, 26, 29, 57, 33, 53, 40, 55), + "Effect Frequency"), + rEffPar(Pfreqrnd, 3, rShort("rand"), + rPreset(4, 117) rPreset(6, 34) rPreset(7, 34) rPreset(9, 105) + rDefault(0), "Frequency Randomness"), rEffPar(PLFOtype, 4, rShort("shape"), - rOptions(sine, tri), "LFO Shape"), - rEffPar(PStereo, 5, rShort("stereo"), "Stereo Mode"), - rEffPar(Pdepth, 6, rShort("depth"), "LFO Depth"), - rEffPar(Pdelay, 7, rShort("delay"), "Delay"), - rEffPar(Pfeedback,8, rShort("fb"), "Feedback"), - rEffPar(Plrcross, 9, rShort("l/r"), "Left/Right Crossover"), - rEffParTF(Pflangemode, 10, rShort("flange"), "Flange Mode"), - rEffParTF(Poutsub, 11, rShort("sub"), "Output Subtraction"), + rOptions(sine, tri), + rPresets(sine, sine, tri, sine, sine, sine, tri, tri, tri, sine), + "LFO Shape"), + rEffPar(PStereo, 5, rShort("stereo"), + rPresets(90, 98, 42, 42, 50, 60, 40, 94, 62), "Stereo Mode"), + rEffPar(Pdepth, 6, rShort("depth"), + rPresets(40, 56, 97, 115, 115, 23, 35, 35, 12), "LFO Depth"), + rEffPar(Pdelay, 7, rShort("delay"), + rPresets(85, 90, 95, 18, 9, 3, 3, 3, 19), "Delay"), + rEffPar(Pfeedback,8, rShort("fb"), + rPresets(64, 64, 90, 90, 31, 62, 109, 54, 97), "Feedback"), + rEffPar(Plrcross, 9, rShort("l/r"), rPresets(119, 19, 127, 127, 127), + rDefault(0), "Left/Right Crossover"), + rEffParTF(Pflangemode, 10, rShort("flange"), rDefault(false), + "Flange Mode"), + rEffParTF(Poutsub, 11, rShort("sub"), rPreset(4, true), rPreset(7, true), + rDefault(false), "Output Subtraction"), }; #undef rBegin #undef rEnd diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp @@ -16,6 +16,7 @@ #include "Part.h" +#include "zyn-version.h" #include "../Misc/Stereo.h" #include "../Misc/Util.h" #include "../Params/LFOParams.h" @@ -32,6 +33,7 @@ #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> +#include <fstream> #include <iostream> #include <algorithm> #include <cmath> @@ -51,12 +53,18 @@ static const Ports sysefxPort = rDoc("gain on part to sysefx routing"), 0, [](const char *m, RtData&d) { - //ok, this is going to be an ugly workaround - //we know that if we are here the message previously MUST have - //matched Psysefxvol#/ - //and the number is one or two digits at most - const char *index_1 = m; - index_1 -=2; + //we know that if we are here the location must + //be ...Psysefxvol#N/part#M + //and the number "N" is one or two digits at most + + // go backto the '/' + const char* m_findslash = m + strlen(m), + * loc_findslash = d.loc + strlen(d.loc); + for(;*loc_findslash != '/'; --m_findslash, --loc_findslash) + assert(*loc_findslash == *m_findslash); + assert(m_findslash + 1 == m); + + const char *index_1 = loc_findslash-1; assert(isdigit(*index_1)); if(isdigit(index_1[-1])) index_1--; @@ -80,9 +88,15 @@ static const Ports sysefsendto = {"to#" STRINGIFY(NUM_SYS_EFX) "::i", rProp(parameter) rDoc("sysefx to sysefx routing gain"), 0, [](const char *m, RtData&d) { - //same ugly workaround as before - const char *index_1 = m; - index_1 -=2; + //same workaround as before + //go backto the '/' + const char* m_findslash = m + strlen(m), + * loc_findslash = d.loc + strlen(d.loc); + for(;*loc_findslash != '/'; --m_findslash, --loc_findslash) + assert(*loc_findslash == *m_findslash); + assert(m_findslash + 1 == m); + + const char *index_1 = loc_findslash-1; assert(isdigit(*index_1)); if(isdigit(index_1[-1])) index_1--; @@ -100,6 +114,202 @@ static const Ports sysefsendto = }} }; +#define rBegin [](const char *msg, RtData &d) { rtosc::AutomationMgr &a = *(AutomationMgr*)d.obj +#define rEnd } + +static int extract_num(const char *&msg) +{ + while(*msg && !isdigit(*msg)) msg++; + int num = atoi(msg); + while(isdigit(*msg)) msg++; + return num; +} + +static int get_next_int(const char *msg) +{ + return extract_num(msg); +} + +static const Ports mapping_ports = { + {"offset::f", rProp(parameter) rShort("off") rLinear(-50, 50) rMap(unit, percent), 0, + rBegin; + int slot = d.idx[1]; + int param = d.idx[0]; + if(!strcmp("f",rtosc_argument_string(msg))) { + a.setSlotSubOffset(slot, param, rtosc_argument(msg, 0).f); + a.updateMapping(slot, param); + d.broadcast(d.loc, "f", a.getSlotSubOffset(slot, param)); + } else + d.reply(d.loc, "f", a.getSlotSubOffset(slot, param)); + rEnd}, + {"gain::f", rProp(parameter) rShort("gain") rLinear(-200, 200) rMap(unit, percent), 0, + rBegin; + int slot = d.idx[1]; + int param = d.idx[0]; + if(!strcmp("f",rtosc_argument_string(msg))) { + a.setSlotSubGain(slot, param, rtosc_argument(msg, 0).f); + a.updateMapping(slot, param); + d.broadcast(d.loc, "f", a.getSlotSubGain(slot, param)); + } else + d.reply(d.loc, "f", a.getSlotSubGain(slot, param)); + rEnd}, +}; + +static const Ports auto_param_ports = { + {"used:", rProp(parameter) rProp(read-only) rDoc("If automation is assigned to anything"), 0, + rBegin; + int slot = d.idx[1]; + int param = d.idx[0]; + + d.reply(d.loc, a.slots[slot].automations[param].used ? "T" : "F"); + rEnd}, + {"active::T:F", rProp(parameter) rDoc("If automation is being actively used"), 0, + rBegin; + int slot = d.idx[1]; + int param = d.idx[0]; + if(rtosc_narguments(msg)) + a.slots[slot].automations[param].active = rtosc_argument(msg, 0).T; + else + d.reply(d.loc, a.slots[slot].automations[param].active ? "T" : "F"); + rEnd}, + {"path:", rProp(parameter) rProp(read-only) rDoc("Path of parameter"), 0, + rBegin; + int slot = d.idx[1]; + int param = d.idx[0]; + d.reply(d.loc, "s", a.slots[slot].automations[param].param_path); + rEnd}, + {"clear:", 0, 0, + rBegin; + int slot = d.idx[1]; + int param = d.idx[0]; + a.clearSlotSub(slot, param); + rEnd}, + {"mapping/", 0, &mapping_ports, + rBegin; + SNIP; + mapping_ports.dispatch(msg, d); + rEnd}, + + //{"mapping", rDoc("Parameter mapping control"), 0, + // rBegin; + // int slot = d.idx[1]; + // int param = d.idx[0]; + // if(!strcmp("b", rtosc_argument_string(msg))) { + // int len = rtosc_argument(msg, 0).b.len / sizeof(float); + // float *data = (float*)rtosc_argument(msg, 0).b.data; + // } else { + // d.reply(d.loc, "b", + // a.slots[slot].automations[param].map.npoints*sizeof(float), + // a.slots[slot].automations[param].map.control_points); + // } + // rEnd}, +}; + +static const Ports slot_ports = { + //{"learn-binding:s", rDoc("Create binding for automation path with midi-learn"), 0, + // rBegin; + // (void) m; + // //m->automate.createBinding(rtosc_argument(msg, 0).i, + // // rtosc_argument(msg, 1).s, + // // rtosc_argument(msg, 2).T); + // rEnd}, + //{"create-binding:s", rDoc("Create binding for automation path"), 0, + // rBegin; + // m->automate.createBinding(rtosc_argument(msg, 0).i, + // rtosc_argument(msg, 1).s, + // rtosc_argument(msg, 2).T); + // rEnd}, + {"value::f", rProp(parameter) rMap(default, 0.5) rLinear(0, 1) rDoc("Access current value in slot 'i' (0..1)"), 0, + rBegin; + int num = d.idx[0]; + if(!strcmp("f",rtosc_argument_string(msg))) { + a.setSlot(num, rtosc_argument(msg, 0).f); + d.broadcast(d.loc, "f", a.getSlot(num)); + } else + d.reply(d.loc, "f", a.getSlot(num)); + rEnd}, + + {"name::s", rProp(parameter) rDoc("Access name of automation slot"), 0, + rBegin; + int num = d.idx[0]; + if(!strcmp("s",rtosc_argument_string(msg))) { + a.setName(num, rtosc_argument(msg, 0).s); + d.broadcast(d.loc, "s", a.getName(num)); + } else + d.reply(d.loc, "s", a.getName(num)); + rEnd}, + {"midi-cc::i", rProp(parameter) rMap(default, -1) rDoc("Access assigned midi CC slot") , 0, + rBegin; + int slot = d.idx[0]; + if(rtosc_narguments(msg)) + a.slots[slot].midi_cc = rtosc_argument(msg, 0).i; + else + d.reply(d.loc, "i", a.slots[slot].midi_cc); + + rEnd}, + {"active::T:F", rProp(parameter) rMap(default, F) rDoc("If Slot is enabled"), 0, + rBegin; + int slot = d.idx[0]; + if(rtosc_narguments(msg)) + a.slots[slot].active = rtosc_argument(msg, 0).T; + else + d.reply(d.loc, a.slots[slot].active ? "T" : "F"); + rEnd}, + {"learning:", rProp(parameter) rMap(default, -1) rDoc("If slot is trying to find a midi learn binding"), 0, + rBegin; + int slot = d.idx[0]; + d.reply(d.loc, "i", a.slots[slot].learning); + rEnd}, + {"clear:", 0, 0, + rBegin; + int slot = d.idx[0]; + a.clearSlot(slot); + rEnd}, + {"param#4/", rDoc("Info on individual param mappings"), &auto_param_ports, + rBegin; + (void)a; + d.push_index(get_next_int(msg)); + SNIP; + auto_param_ports.dispatch(msg, d); + d.pop_index(); + rEnd}, +}; + +static const Ports automate_ports = { + {"active-slot::i", rProp(parameter) rMap(min, -1) rMap(max, 16) rDoc("Active Slot for macro learning"), 0, + rBegin; + if(!strcmp("i",rtosc_argument_string(msg))) { + a.active_slot = rtosc_argument(msg, 0).i; + d.broadcast(d.loc, "i", a.active_slot); + } else + d.reply(d.loc, "i", a.active_slot); + rEnd}, + {"learn-binding-new-slot:s", rDoc("Learn a parameter assigned to a new slot"), 0, + rBegin; + int free_slot = a.free_slot(); + if(free_slot >= 0) { + a.createBinding(free_slot, rtosc_argument(msg, 0).s, true); + a.active_slot = free_slot; + } + rEnd}, + {"learn-binding-same-slot:s", rDoc("Learn a parameter appending to the active-slot"), 0, + rBegin; + if(a.active_slot >= 0) + a.createBinding(a.active_slot, rtosc_argument(msg, 0).s, true); + rEnd}, + // TODO: remove rNoWalk + {"slot#16/", rNoWalk rDoc("Parameters of individual automation slots"), &slot_ports, + rBegin; + (void)a; + d.push_index(get_next_int(msg)); + SNIP; + slot_ports.dispatch(msg, d); + d.pop_index(); + rEnd}, +}; + +#undef rBegin +#undef rEnd #define rBegin [](const char *msg, RtData &d) { Master *m = (Master*)d.obj #define rEnd } @@ -110,6 +320,7 @@ static const Ports watchPorts = { rEnd}, }; + extern const Ports bankPorts; static const Ports master_ports = { rString(last_xmz, XMZ_PATH_MAX, "File name for last name loaded if any."), @@ -118,12 +329,13 @@ static const Ports master_ports = { rRecursp(insefx, 8, "Insertion Effect"),//NUM_INS_EFX rRecur(microtonal, "Microtonal Mapping Functionality"), rRecur(ctl, "Controller"), - rArrayI(Pinsparts, NUM_INS_EFX, rOpt(-2, Master), rOpt(-1, Off), - rOptions(Part1, Part2, Part3, Part4, Part5, Part6, - Part7, Part8, Part9, Part10, Part11, Part12, - Part13, Part14, Part15, Part16) rDefault(Off), - "Part to insert part onto"), - {"Pkeyshift::i", rShort("key shift") rProp(parameter) rLinear(0,127) rDefault(64) rDoc("Global Key Shift"), 0, [](const char *m, RtData&d) { + rArrayOption(Pinsparts, NUM_INS_EFX, rOpt(-2, Master), rOpt(-1, Off), + rOptions(Part1, Part2, Part3, Part4, Part5, Part6, + Part7, Part8, Part9, Part10, Part11, Part12, + Part13, Part14, Part15, Part16) rDefault([Off...]), + "Part to insert part onto"), + {"Pkeyshift::i", rShort("key shift") rProp(parameter) rLinear(0,127) + rDefault(64) rDoc("Global Key Shift"), 0, [](const char *m, RtData&d) { if(rtosc_narguments(m)==0) { d.reply(d.loc, "i", ((Master*)d.obj)->Pkeyshift); } else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') { @@ -172,14 +384,16 @@ static const Ports master_ports = { keys[i] = m->activeNotes[i] ? 'T' : 'F'; d.broadcast(d.loc, keys); rEnd}, - {"Pvolume::i", rShort("volume") rProp(parameter) rLinear(0,127) rDefault(80) rDoc("Master Volume"), 0, + {"Pvolume::i", rShort("volume") rProp(parameter) rLinear(0,127) + rDefault(80) rDoc("Master Volume"), 0, [](const char *m, rtosc::RtData &d) { if(rtosc_narguments(m)==0) { d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume); } else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') { ((Master*)d.obj)->setPvolume(limit<char>(rtosc_argument(m,0).i,0,127)); d.broadcast(d.loc, "i", ((Master*)d.obj)->Pvolume);}}}, - {"volume::i", rShort("volume") rProp(parameter) rLinear(0,127) rDefault(80) rDoc("Master Volume"), 0, + {"volume::i", rShort("volume") rProp(parameter) rLinear(0,127) + rDefault(80) rDoc("Master Volume"), 0, [](const char *m, rtosc::RtData &d) { if(rtosc_narguments(m)==0) { d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume); @@ -233,13 +447,12 @@ static const Ports master_ports = { [](const char *,RtData &d) { Master *M = (Master*)d.obj; M->frozenState = false;}}, - {"midi-learn/", 0, &rtosc::MidiMapperRT::ports, + {"automate/", rDoc("MIDI Learn/Plugin Automation support"), &automate_ports, [](const char *msg, RtData &d) { - Master *M = (Master*)d.obj; SNIP; - printf("residue message = <%s>\n", msg); - d.obj = &M->midi; - rtosc::MidiMapperRT::ports.dispatch(msg,d);}}, + d.obj = (void*)&((Master*)d.obj)->automate; + automate_ports.dispatch(msg, d); + }}, {"close-ui:", rDoc("Request to close any connection named \"GUI\""), 0, [](const char *, RtData &d) { d.reply("/close-ui", "");}}, @@ -265,8 +478,8 @@ static const Ports master_ports = { [](const char *, rtosc::RtData &d) {d.reply("/undo_pause", "");}}, {"undo_resume:",rProp(internal) rDoc("resume undo event recording"),0, [](const char *, rtosc::RtData &d) {d.reply("/undo_resume", "");}}, - {"config/", rDoc("Top Level Application Configuration Parameters"), &Config::ports, - [](const char *, rtosc::RtData &d){d.forward();}}, + {"config/", rNoWalk rDoc("Top Level Application Configuration Parameters"), + &Config::ports, [](const char *, rtosc::RtData &d){d.forward();}}, {"presets/", rDoc("Parameter Presets"), &preset_ports, rBOIL_BEGIN SNIP preset_ports.dispatch(msg, data); @@ -290,6 +503,14 @@ static const Ports master_ports = { rBOIL_END}, {"bank/", rDoc("Controls for instrument banks"), &bankPorts, [](const char*,RtData&) {}}, + {"learn:s", rProp(depricated) rDoc("MIDI Learn"), 0, + rBegin; + int free_slot = m->automate.free_slot(); + if(free_slot >= 0) { + m->automate.createBinding(free_slot, rtosc_argument(msg, 0).s, true); + m->automate.active_slot = free_slot; + } + rEnd}, }; #undef rBegin @@ -366,15 +587,18 @@ vuData::vuData(void) Master::Master(const SYNTH_T &synth_, Config* config) :HDDRecorder(synth_), time(synth_), ctl(synth_, &time), microtonal(config->cfg.GzipCompression), bank(config), + automate(16,4,8), frozenState(false), pendingMemory(false), synth(synth_), gzip_compression(config->cfg.GzipCompression) { bToU = NULL; uToB = NULL; - //Setup MIDI - midi.frontend = [this](const char *msg) {bToU->raw_write(msg);}; - midi.backend = [this](const char *msg) {applyOscEvent(msg);}; + //Setup MIDI Learn + automate.set_ports(master_ports); + automate.set_instance(this); + //midi.frontend = [this](const char *msg) {bToU->raw_write(msg);}; + automate.backend = [this](const char *msg) {applyOscEvent(msg);}; memory = new AllocatorClass(); swaplr = 0; @@ -445,6 +669,7 @@ void Master::defaults() for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { part[npart]->defaults(); + part[npart]->partno = npart % NUM_MIDI_CHANNELS; part[npart]->Prcvchn = npart % NUM_MIDI_CHANNELS; } @@ -523,8 +748,7 @@ void Master::setController(char chan, int type, int par) { if(frozenState) return; - //TODO add chan back - midi.handleCC(type,par); + automate.handleMidi(chan, type, par); if((type == C_dataentryhi) || (type == C_dataentrylo) || (type == C_nrpnhi) || (type == C_nrpnlo)) { //Process RPN and NRPN by the Master (ignore the chan) ctl.setparameternumber(type, par); @@ -728,13 +952,19 @@ bool Master::runOSC(float *outl, float *outr, bool offline) } if(!d.matches) {// && !ports.apropos(msg)) { fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40); - fprintf(stderr, "Unknown address<BACKEND:%s> '%s:%s'\n", + fprintf(stderr, "Unknown address<BACKEND:%s> '%s:%s'\n", offline ? "offline" : "online", uToB->peak(), rtosc_argument_string(uToB->peak())); fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); } } + + if(automate.damaged) { + d.broadcast("/damage", "s", "/automate/"); + automate.damaged = 0; + } + if(events>1 && false) fprintf(stderr, "backend: %d events per cycle\n",events); @@ -1253,4 +1483,113 @@ void Master::getfromXML(XMLwrapper& xml) } } +static rtosc_version version_in_rtosc_fmt() +{ + return rtosc_version + { + (unsigned char) version.get_major(), + (unsigned char) version.get_minor(), + (unsigned char) version.get_revision() + }; +} + +char* Master::getXMLData() +{ + XMLwrapper xml; + + xml.beginbranch("MASTER"); + add2XML(xml); + xml.endbranch(); + + return xml.getXMLdata(); +} + +int Master::saveOSC(const char *filename) +{ + std::string savefile = rtosc::save_to_file(ports, this, + "ZynAddSubFX", + version_in_rtosc_fmt()); + + zyn::Config config; + zyn::SYNTH_T* synth = new zyn::SYNTH_T; + synth->buffersize = 256; + synth->samplerate = 48000; + synth->alias(); + + zyn::Master master2(*synth, &config); + int rval = master2.loadOSCFromStr(savefile.c_str()); + + + if(rval < 0) + { + std::cerr << "invalid savefile!" << std::endl; + std::cerr << "complete savefile:" << std::endl; + std::cerr << savefile << std::endl; + std::cerr << "first entry that could not be parsed:" << std::endl; + + for(int i = -rval + 1; savefile[i]; ++i) + if(savefile[i] == '\n') + { + savefile.resize(i); + break; + } + std::cerr << (savefile.c_str() - rval) << std::endl; + + rval = -1; + } + else + { + char* xml = getXMLData(), + * xml2 = master2.getXMLData(); + + rval = strcmp(xml, xml2) ? -1 : 0; + + if(rval == 0) + { + if(filename) + { + std::ofstream ofs(filename); + ofs << savefile; + } + else if(!filename) + std::cout << savefile << std::endl; + } + else + { + std::cout << savefile << std::endl; + std::cerr << "Can not write OSC savefile!! (see tmp1.txt and tmp2.txt)" + << std::endl; + std::ofstream tmp1("tmp1.txt"), tmp2("tmp2.txt"); + tmp1 << xml; + tmp2 << xml2; + } + + free(xml); + free(xml2); + } + return rval; +} + +int Master::loadOSCFromStr(const char *filename) +{ + return rtosc::load_from_file(filename, + ports, this, + "ZynAddSubFX", version_in_rtosc_fmt()); +} + +string loadfile(string fname) +{ + std::ifstream t(fname.c_str()); + std::string str((std::istreambuf_iterator<char>(t)), + std::istreambuf_iterator<char>()); + return str; +} + +int Master::loadOSC(const char *filename) +{ + int rval = loadOSCFromStr(loadfile(filename).c_str()); + return rval < 0 ? rval : 0; +} + + } diff --git a/src/Misc/Microtonal.cpp b/src/Misc/Microtonal.cpp @@ -42,25 +42,37 @@ namespace zyn { * A good lookup table should be a good finalization of this */ const rtosc::Ports Microtonal::ports = { - rToggle(Pinvertupdown, rShort("inv."), rDefault(false), "key mapping inverse"), - rParamZyn(Pinvertupdowncenter, rShort("center"), rDefault(60), "center of the inversion"), - rToggle(Penabled, rShort("enable"), rDefault(false), "Enable for microtonal mode"), - rParamZyn(PAnote, rShort("1/1 midi note"), rDefault(69), "The note for 'A'"), - rParamF(PAfreq, rShort("ref freq"), rDefault(440.0f), "Frequency of the 'A' note"), - rParamZyn(Pscaleshift, rShort("shift"), rDefault(64), "UNDOCUMENTED"), - rParamZyn(Pfirstkey, rShort("first key"), rDefault(0), "First key to retune"), - rParamZyn(Plastkey, rShort("last key"), rDefault(127), "Last key to retune"), - rParamZyn(Pmiddlenote, rShort("middle"), rDefault(60), "Scale degree 0 note"), + rToggle(Pinvertupdown, rShort("inv."), rDefault(false), + "key mapping inverse"), + rParamZyn(Pinvertupdowncenter, rShort("center"), rDefault(60), + "center of the inversion"), + rToggle(Penabled, rShort("enable"), rDefault(false), + "Enable for microtonal mode"), + rParamZyn(PAnote, rShort("1/1 midi note"), rDefault(69), + "The note for 'A'"), + rParamF(PAfreq, rShort("ref freq"), rDefault(440.0f), + "Frequency of the 'A' note"), + rParamZyn(Pscaleshift, rShort("shift"), rDefault(64), + "UNDOCUMENTED"), + rParamZyn(Pfirstkey, rShort("first key"), rDefault(0), + "First key to retune"), + rParamZyn(Plastkey, rShort("last key"), rDefault(127), + "Last key to retune"), + rParamZyn(Pmiddlenote, rShort("middle"), rDefault(60), + "Scale degree 0 note"), //TODO check to see if this should be exposed rParamZyn(Pmapsize, rDefault(12), "Size of key map"), rToggle(Pmappingenabled, rDefault(false), "Mapping Enable"), - rParams(Pmapping, 128, rDefault("form:i"), "Mapping of keys"), - rParamZyn(Pglobalfinedetune, rShort("fine"), rDefault(64), "Fine detune for all notes"), + rParams(Pmapping, 128, /*rDefault([1 1 2 ...]),*/ "Mapping of keys"), + rParamZyn(Pglobalfinedetune, rShort("fine"), rDefault(64), + "Fine detune for all notes"), - rString(Pname, MICROTONAL_MAX_NAME_LEN, rShort("name"), rDefault(""), "Microtonal Name"), - rString(Pcomment, MICROTONAL_MAX_NAME_LEN, rShort("comment"), rDefault(""), "Microtonal comments"), + rString(Pname, MICROTONAL_MAX_NAME_LEN, rShort("name"), + rDefault("12tET"), "Microtonal Name"), + rString(Pcomment, MICROTONAL_MAX_NAME_LEN, rShort("comment"), + rDefault("Equal Temperament 12 notes per octave"), "Microtonal comments"), {"octavesize:", rDoc("Get octave size"), 0, [](const char*, RtData &d) { @@ -572,6 +584,9 @@ int Microtonal::loadscl(SclInfo &scl, const char *filename) char tmp[500]; OctaveTuning tmpoctave[MAX_OCTAVE_SIZE]; + if(!file) + return 2; + fseek(file, 0, SEEK_SET); //loads the short description @@ -623,6 +638,9 @@ int Microtonal::loadkbm(KbmInfo &kbm, const char *filename) float tmpPAfreq = 440.0f; char tmp[500]; + if(!file) + return 2; + fseek(file, 0, SEEK_SET); //loads the mapsize if(loadline(file, tmp) != 0 || sscanf(tmp, "%d", &x) == 0) @@ -845,7 +863,7 @@ void Microtonal::apply(void) { char buf[100*MAX_OCTAVE_SIZE] = {0}; char tmpbuf[100] = {0}; - for (int i=0;i<getoctavesize();i++){ + for (int i=0;i<octavesize;i++){ if (i!=0) strncat(buf, "\n", sizeof(buf)-1); tuningtoline(i,tmpbuf,100); diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp @@ -47,7 +47,10 @@ static const Ports partPorts = { rRecurs(kit, 16, "Kit"),//NUM_KIT_ITEMS rRecursp(partefx, 3, "Part Effect"), rRecur(ctl, "Controller"), - rToggle(Penabled, rShort("enable") rDefault(0), "Part enable"), + rParamZyn(partno, rProp(internal), + "How many parts are before this in the Master"), + rToggle(Penabled, rShort("enable"), rDefaultDepends(partno), + rPresets(true), rDefault(false), "Part enable"), #undef rChangeCb #define rChangeCb obj->setPvolume(obj->Pvolume); rParamZyn(Pvolume, rShort("Vol"), rDefault(96),"Part Volume"), @@ -56,32 +59,40 @@ static const Ports partPorts = { rParamZyn(Ppanning, rShort("pan"), rDefault(64), "Set Panning"), #undef rChangeCb #define rChangeCb obj->setkeylimit(obj->Pkeylimit); - rParamI(Pkeylimit, rShort("limit"), rProp(parameter), rMap(min,0), rMap(max, POLYPHONY), rDefault(15), "Key limit per part"), + rParamI(Pkeylimit, rShort("limit"), rProp(parameter), + rMap(min,0), rMap(max, POLYPHONY), rDefault(15), "Key limit per part"), #undef rChangeCb #define rChangeCb rParamZyn(Pminkey, rShort("min"), rDefault(0), "Min Used Key"), rParamZyn(Pmaxkey, rShort("max"), rDefault(127), "Max Used Key"), rParamZyn(Pkeyshift, rShort("shift"), rDefault(64), "Part keyshift"), rParamZyn(Prcvchn, rOptions(ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8, ch9, ch10, ch11, ch12, ch13, ch14, ch15, ch16), - rDefault(ch1), "Active MIDI channel"), + rPresets(ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8, ch9, ch10, ch11, ch12, ch13, ch14, ch15, ch16), + "Active MIDI channel"), rParamZyn(Pvelsns, rShort("sense"), rDefault(64), "Velocity sensing"), rParamZyn(Pveloffs, rShort("offset"), rDefault(64),"Velocity offset"), - rToggle(Pnoteon, rDefault(1), "If the channel accepts note on events"), // TODO:true? - rOption(Pkitmode, rOptions(Off, Multi-Kit, Single-Kit), rDefault(Off), "Kit mode/enable\n" + rToggle(Pnoteon, rDefault(true), "If the channel accepts note on events"), + rOption(Pkitmode, rOptions(Off, Multi-Kit, Single-Kit), rDefault(Off), + "Kit mode/enable\n" "Off - Only the first kit is ever utilized\n" "Multi-kit - Every applicable kit is run for a note\n" "Single-kit - The first applicable kit is run for a given note"), - rToggle(Pdrummode, rDefault(0), "Drum mode enable\n" + rToggle(Pdrummode, rDefault(false), "Drum mode enable\n" "When drum mode is enabled all keys are mapped to 12tET and legato is disabled"), - rToggle(Ppolymode, rDefault(1), "Polyphony mode"), - rToggle(Plegatomode, rDefault(0), "Legato mode"), + rToggle(Ppolymode, rDefault(true), "Polyphony mode"), + rToggle(Plegatomode, rDefault(false), "Legato mode"), rParamZyn(info.Ptype, rDefault(0), "Class of Instrument"), - rString(info.Pauthor, MAX_INFO_TEXT_SIZE, rDefault(), "Instrument author"), - rString(info.Pcomments, MAX_INFO_TEXT_SIZE, rDefault(), "Instrument comments"), - rString(Pname, PART_MAX_NAME_LEN, rDefault(), "User specified label"), - rArrayI(Pefxroute, NUM_PART_EFX, rDefault(Next Effect), - rOptions(Next Effect,Part Out,Dry Out), "Effect Routing"), - rArrayT(Pefxbypass, NUM_PART_EFX, "If an effect is bypassed"), + rString(info.Pauthor, MAX_INFO_TEXT_SIZE, rDefault(""), + "Instrument author"), + rString(info.Pcomments, MAX_INFO_TEXT_SIZE, rDefault(""), + "Instrument comments"), + rString(Pname, PART_MAX_NAME_LEN, rDefault(""), "User specified label"), + rArrayI(Pefxroute, NUM_PART_EFX, + rOptions(Next Effect,Part Out,Dry Out), + ":default\0=[\"Next Effect\"S ...]\0", + "Effect Routing"), + rArrayT(Pefxbypass, NUM_PART_EFX, rDefault([false...]), + "If an effect is bypassed"), {"captureMin:", rDoc("Capture minimum valid note"), NULL, [](const char *, RtData &r) {Part *p = (Part*)r.obj; p->Pminkey = p->lastnote;}}, @@ -158,14 +169,20 @@ static const Ports partPorts = { #undef rObject #define rObject Part::Kit static const Ports kitPorts = { + rSelf(Part::Kit, rEnabledBy(Penabled)), rRecurp(padpars, "Padnote parameters"), rRecurp(adpars, "Adnote parameters"), rRecurp(subpars, "Adnote parameters"), - rToggle(Penabled, "Kit item enable"), + rToggle(firstkit, rProp(internal), "If this is the part's first kit"), + rToggle(Penabled, rDefaultDepends(firstkit), + rPreset(true, true), rPreset(false, false), + "Kit item enable"), rToggle(Pmuted, rDefault(false), "Kit item mute"), rParamZyn(Pminkey, rDefault(0), "Kit item min key"), rParamZyn(Pmaxkey, rDefault(127) "Kit item max key"), - rToggle(Padenabled, "ADsynth enable"), + rToggle(Padenabled, rDefaultDepends(firstkit), + rPreset(true, true), rPreset(false, false) + "ADsynth enable"), rToggle(Psubenabled, rDefault(false), "SUBsynth enable"), rToggle(Ppadenabled, rDefault(false), "PADsynth enable"), rParamZyn(Psendtoparteffect, @@ -328,6 +345,7 @@ void Part::defaultsinstrument() for(int n = 0; n < NUM_KIT_ITEMS; ++n) { //kit[n].Penabled = false; + kit[n].firstkit = false; kit[n].Pmuted = false; kit[n].Pminkey = 0; kit[n].Pmaxkey = 127; @@ -339,6 +357,7 @@ void Part::defaultsinstrument() if(n != 0) setkititemstatus(n, 0); } + kit[0].firstkit = true; kit[0].Penabled = 1; kit[0].Padenabled = 1; kit[0].adpars->defaults(); diff --git a/src/Params/ADnoteParameters.cpp b/src/Params/ADnoteParameters.cpp @@ -70,19 +70,26 @@ static const Ports voicePorts = { rRecurp(FMAmpEnvelope, "Modulator Amplitude Envelope"), rRecurp(VoiceFilter, "Optional Voice Filter"), - rToggle(Enabled, rShort("enable"), "Voice Enable"), - rParamI(Unison_size, rShort("size"), rMap(min, 0), rMap(max, 50), rDefault(1), "Number of subvoices"), - rParamZyn(Unison_phase_randomness, rShort("ph.rnd."), rDefault(127), "Phase Randomness"), - rParamZyn(Unison_frequency_spread, rShort("detune"), rDefault(60), "Subvoice detune"), +// rToggle(Enabled, rShort("enable"), "Voice Enable"), + rParamI(Unison_size, rShort("size"), rMap(min, 0), rMap(max, 50), + rDefault(1), "Number of subvoices"), + rParamZyn(Unison_phase_randomness, rShort("ph.rnd."), rDefault(127), + "Phase Randomness"), + rParamZyn(Unison_frequency_spread, rShort("detune"), rDefault(60), + "Subvoice detune"), rParamZyn(Unison_stereo_spread, rShort("spread"), rDefault(64), - "Subvoice L/R Separation"), - rParamZyn(Unison_vibratto, rShort("vib."), rDefault(64), "Subvoice vibratto"), + "Subvoice L/R Separation"), + rParamZyn(Unison_vibratto, rShort("vib."), rDefault(64), + "Subvoice vibratto"), rParamZyn(Unison_vibratto_speed, rShort("speed"), rDefault(64), - "Subvoice vibratto speed"), - rOption(Unison_invert_phase, rShort("inv."), rDefault(0), - rOptions(none, random, 50%, 33%, 25%), "Subvoice Phases"), - rOption(Type, rShort("type"), rOptions(Sound,White,Pink,DC), rDefault(Sound), "Type of Sound"), - rParamZyn(PDelay, rShort("delay"), rDefault(0), "Voice Startup Delay"), + "Subvoice vibratto speed"), + rOption(Unison_invert_phase, rShort("inv."), + rOptions(none, random, 50%, 33%, 25%), rDefault(none), + "Subvoice Phases"), + rOption(Type, rShort("type"), rOptions(Sound,White,Pink,DC), + rDefault(Sound), "Type of Sound"), + rParamZyn(PDelay, rShort("delay"), rDefault(0), + "Voice Startup Delay"), rToggle(Presonance, rShort("enable"), "Resonance Enable"), rParamI(Pextoscil, rShort("ext."), rMap(min, -1), rMap(max, 16), "External Oscillator Selection"), @@ -109,38 +116,56 @@ static const Ports voicePorts = { //Amplitude Stuff rParamZyn(PPanning, rShort("pan."), "Panning"), - rParamZyn(PVolume, rShort("vol."), rDefault(100), "Volume"), - rToggle(PVolumeminus, rShort("inv."), rDefault(false), "Signal Inverter"), //do we really need this?? - rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), rDefault(127), "Velocity Sensing"), - rToggle(PAmpEnvelopeEnabled, rShort("enable"), rDefault(false), "Amplitude Envelope Enable"), - rToggle(PAmpLfoEnabled, rShort("enable"), rDefault(false), "Amplitude LFO Enable"), + rParamZyn(PVolume, rShort("vol."), rDefault(100), + "Volume"), + rToggle(PVolumeminus, rShort("inv."), rDefault(false), + "Signal Inverter"), //do we really need this?? + rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), rDefault(127), + "Velocity Sensing"), + rToggle(PAmpEnvelopeEnabled, rShort("enable"), rDefault(false), + "Amplitude Envelope Enable"), + rToggle(PAmpLfoEnabled, rShort("enable"), rDefault(false), + "Amplitude LFO Enable"), //Filter Stuff - rToggle(PFilterEnabled, rShort("enable"), rDefault(false), "Filter Enable"), - rToggle(PFilterEnvelopeEnabled, rShort("enable"), rDefault(false), "Filter Envelope Enable"), - rToggle(PFilterLfoEnabled, rShort("enable"), rDefault(false), "Filter LFO Enable"), - rParamZyn(PFilterVelocityScale, rShort("v.scale"), rDefault(0), "Filter Velocity Magnitude"), - rParamZyn(PFilterVelocityScaleFunction, rShort("v.sense"), rDefault(64), "Filter Velocity Function Shape"), + rToggle(PFilterEnabled, rShort("enable"), rDefault(false), + "Filter Enable"), + rToggle(PFilterEnvelopeEnabled, rShort("enable"), rDefault(false), + "Filter Envelope Enable"), + rToggle(PFilterLfoEnabled, rShort("enable"), rDefault(false), + "Filter LFO Enable"), + rParamZyn(PFilterVelocityScale, rShort("v.scale"), rDefault(0), + "Filter Velocity Magnitude"), + rParamZyn(PFilterVelocityScaleFunction, rShort("v.sense"), rDefault(64), + "Filter Velocity Function Shape"), //Modulator Stuff rOption(PFMEnabled, rShort("mode"), rOptions(none, morph, ring, phase, - frequency, pulse), rDefault(false), "Modulator mode"), - rParamI(PFMVoice, rShort("voice"), rDefault(-1), "Modulator Oscillator Selection"), - rParamZyn(PFMVolume, rShort("vol."), rDefault(90), "Modulator Magnitude"), - rParamZyn(PFMVolumeDamp, rShort("damp."), rDefault(64), "Modulator HF dampening"), - rParamZyn(PFMVelocityScaleFunction, rShort("sense"), rDefault(64), "Modulator Velocity Function"), + frequency, pulse), rDefault(none), "Modulator mode"), + rParamI(PFMVoice, rShort("voice"), rDefault(-1), + "Modulator Oscillator Selection"), + rParamZyn(PFMVolume, rShort("vol."), rDefault(90), + "Modulator Magnitude"), + rParamZyn(PFMVolumeDamp, rShort("damp."), rDefault(64), + "Modulator HF dampening"), + rParamZyn(PFMVelocityScaleFunction, rShort("sense"), rDefault(64), + "Modulator Velocity Function"), //nominally -8192..8191 rParamI(PFMDetune, rShort("fine"), rLinear(0, 16383), rDefault(8192), "Modulator Fine Detune"), - rParamI(PFMCoarseDetune, rShort("coarse"), rDefault(0), "Modulator Coarse Detune"), + rParamI(PFMCoarseDetune, rShort("coarse"), rDefault(0), + "Modulator Coarse Detune"), rParamZyn(PFMDetuneType, rShort("type"), - rOptions(L35cents, L10cents, E100cents, E1200cents), - rDefault(L35cents), - "Modulator Detune Magnitude"), - rToggle(PFMFixedFreq, rShort("fixed"), rDefault(false), "Modulator Frequency Fixed"), - rToggle(PFMFreqEnvelopeEnabled, rShort("enable"), rDefault(false), "Modulator Frequency Envelope"), - rToggle(PFMAmpEnvelopeEnabled, rShort("enable"), rDefault(false), "Modulator Amplitude Envelope"), + rOptions(L35cents, L10cents, E100cents, E1200cents), + rDefault(L35cents), + "Modulator Detune Magnitude"), + rToggle(PFMFixedFreq, rShort("fixed"), rDefault(false), + "Modulator Frequency Fixed"), + rToggle(PFMFreqEnvelopeEnabled, rShort("enable"), rDefault(false), + "Modulator Frequency Envelope"), + rToggle(PFMAmpEnvelopeEnabled, rShort("enable"), rDefault(false), + "Modulator Amplitude Envelope"), //weird stuff for PCoarseDetune @@ -259,29 +284,40 @@ static const Ports globalPorts = { rLinear(0, 16383), rDefault(8192), "Fine Detune"), rParamI(PCoarseDetune, rShort("coarse"), rDefault(0), "Coarse Detune"), rParamZyn(PDetuneType, rShort("type"), - rOptions(L35cents, L10cents, E100cents, E1200cents), - rDefault(L10cents), - "Detune Scaling Type"), - rParamZyn(PBandwidth, rShort("bw."), rDefault(64), "Relative Fine Detune Gain"), + rOptions(L35cents, L10cents, E100cents, E1200cents), + rDefault(L10cents), + "Detune Scaling Type"), + rParamZyn(PBandwidth, rShort("bw."), rDefault(64), + "Relative Fine Detune Gain"), //Amplitude - rParamZyn(PPanning, rShort("pan"), rDefault(64), "Panning of ADsynth (0 random, 1 left, 127 right)"), + rParamZyn(PPanning, rShort("pan"), rDefault(64), + "Panning of ADsynth (0 random, 1 left, 127 right)"), rParamZyn(PVolume, rShort("vol"), rDefault(90), "volume control"), - rParamZyn(PAmpVelocityScaleFunction, rShort("scale"), rDefault(64), "Volume Velocity Control"), - - rParamZyn(Fadein_adjustment, rDefault(FADEIN_ADJUSTMENT_SCALE), "Adjustment for anti-pop strategy."), - rParamZyn(PPunchStrength, rShort("strength"), rDefault(0), "Punch Strength"), - rParamZyn(PPunchTime, rShort("time"), rDefault(60), "Length of Punch"), - rParamZyn(PPunchStretch, rShort("stretch"), rDefault(64), "How Punch changes with note frequency"), - rParamZyn(PPunchVelocitySensing, rShort("v.sns"), rDefault(72), "Punch Velocity control"), + rParamZyn(PAmpVelocityScaleFunction, rShort("scale"), rDefault(64), + "Volume Velocity Control"), + + rParamZyn(Fadein_adjustment, rDefault(FADEIN_ADJUSTMENT_SCALE), + "Adjustment for anti-pop strategy."), + rParamZyn(PPunchStrength, rShort("strength"), rDefault(0), + "Punch Strength"), + rParamZyn(PPunchTime, rShort("time"), rDefault(60), + "Length of Punch"), + rParamZyn(PPunchStretch, rShort("stretch"), rDefault(64), + "How Punch changes with note frequency"), + rParamZyn(PPunchVelocitySensing, rShort("v.sns"), rDefault(72), + "Punch Velocity control"), //Filter - rParamZyn(PFilterVelocityScale, rShort("scale"), rDefault(64), "Filter Velocity Magnitude"), - rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), rDefault(64), "Filter Velocity Function Shape"), + rParamZyn(PFilterVelocityScale, rShort("scale"), rDefault(64), + "Filter Velocity Magnitude"), + rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), rDefault(64), + "Filter Velocity Function Shape"), //Resonance - rToggle(Hrandgrouping, rDefault(false), "How randomness is applied to multiple voices using the same oscil"), + rToggle(Hrandgrouping, rDefault(false), + "How randomness is applied to multiple voices using the same oscil"), //weird stuff for PCoarseDetune {"detunevalue:", rMap(unit,cents) rDoc("Get detune in cents"), NULL, @@ -327,12 +363,16 @@ static const Ports globalPorts = { #undef rObject #define rObject ADnoteParameters -#define rChangeCb obj->last_update_timestamp = obj->time.time(); +#define rChangeCb obj->last_update_timestamp = obj->time->time(); static const Ports adPorts = {//XXX 16 should not be hard coded rSelf(ADnoteParameters), rPaste, rArrayPaste, rRecurs(VoicePar, NUM_VOICES), + {"VoicePar#" STRINGIFY(NUM_VOICES) "/Enabled::T:F", + rProp(parameter) rShort("enable") rDoc("Voice Enable") + rDefault([true false false ...]), + NULL, rArrayTCbMember(VoicePar, Enabled)}, rRecur(GlobalPar, "Adnote Parameters"), }; #undef rChangeCb @@ -361,16 +401,16 @@ ADnoteGlobalParam::ADnoteGlobalParam(const AbsTime *time_) : time(time_), last_update_timestamp(0) { FreqEnvelope = new EnvelopeParams(0, 0, time_); - FreqEnvelope->ASRinit(64, 50, 64, 60); + FreqEnvelope->init(EnvelopeParams::ad_global_freq_env); FreqLfo = new LFOParams(70, 0, 64, 0, 0, 0, 0, 0, time_); AmpEnvelope = new EnvelopeParams(64, 1, time_); - AmpEnvelope->ADSRinit_dB(0, 40, 127, 25); + AmpEnvelope->init(EnvelopeParams::ad_global_amp_env); AmpLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 1, time_); GlobalFilter = new FilterParams(2, 94, 40, time_); FilterEnvelope = new EnvelopeParams(0, 1, time_); - FilterEnvelope->ADSRinit_filter(64, 40, 64, 70, 60, 64); + FilterEnvelope->init(EnvelopeParams::ad_global_filter_env); FilterLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 2, time_); Reson = new Resonance(); } @@ -517,22 +557,22 @@ void ADnoteVoiceParam::enable(const SYNTH_T &synth, FFTwrapper *fft, FMSmp = new OscilGen(synth, fft, NULL); AmpEnvelope = new EnvelopeParams(64, 1, time); - AmpEnvelope->ADSRinit_dB(0, 100, 127, 100); + AmpEnvelope->init(EnvelopeParams::ad_voice_amp_env); AmpLfo = new LFOParams(90, 32, 64, 0, 0, 30, 0, 1, time); FreqEnvelope = new EnvelopeParams(0, 0, time); - FreqEnvelope->ASRinit(30, 40, 64, 60); + FreqEnvelope->init(EnvelopeParams::ad_voice_freq_env); FreqLfo = new LFOParams(50, 40, 0, 0, 0, 0, 0, 0, time); VoiceFilter = new FilterParams(2, 50, 60, time); FilterEnvelope = new EnvelopeParams(0, 0, time); - FilterEnvelope->ADSRinit_filter(90, 70, 40, 70, 10, 40); + FilterEnvelope->init(EnvelopeParams::ad_voice_filter_env); FilterLfo = new LFOParams(50, 20, 64, 0, 0, 0, 0, 2, time); FMFreqEnvelope = new EnvelopeParams(0, 0, time); - FMFreqEnvelope->ASRinit(20, 90, 40, 80); + FMFreqEnvelope->init(EnvelopeParams::ad_voice_fm_freq_env); FMAmpEnvelope = new EnvelopeParams(64, 1, time); - FMAmpEnvelope->ADSRinit(80, 90, 127, 100); + FMAmpEnvelope->init(EnvelopeParams::ad_voice_fm_amp_env); } /* @@ -1116,7 +1156,7 @@ void ADnoteVoiceParam::getfromXML(XMLwrapper& xml, unsigned nvoice) Unison_invert_phase = xml.getpar127("unison_invert_phase", Unison_invert_phase); Unison_phase_randomness = xml.getpar127("unison_phase_randomness", - Unison_phase_randomness); + Unison_phase_randomness); Type = xml.getpar127("type", Type); PDelay = xml.getpar127("delay", PDelay); diff --git a/src/Synth/OscilGen.cpp b/src/Synth/OscilGen.cpp @@ -85,7 +85,9 @@ const rtosc::Ports OscilGen::non_realtime_ports = { //TODO update to rArray and test - {"phase#128::c:i", rProp(parameter) rLinear(0,127) rDoc("Sets harmonic phase"), + {"phase#128::c:i", rProp(parameter) rLinear(0,127) + rDefault([64 ...]) + rDoc("Sets harmonic phase"), NULL, [](const char *m, rtosc::RtData &d) { const char *mm = m; while(*mm && !isdigit(*mm)) ++mm; @@ -108,7 +110,8 @@ const rtosc::Ports OscilGen::non_realtime_ports = { } }}, //TODO update to rArray and test - {"magnitude#128::c:i", rProp(parameter) rLinear(0,127) rDoc("Sets harmonic magnitude"), + {"magnitude#128::c:i", rProp(parameter) rLinear(0,127) + rDefault([127 64 64 ...]) rDoc("Sets harmonic magnitude"), NULL, [](const char *m, rtosc::RtData &d) { //printf("I'm at '%s'\n", d.loc); const char *mm = m; @@ -1384,7 +1387,7 @@ void OscilGen::getfromXML(XMLwrapper& xml) if(xml.enterbranch("HARMONICS")) { - Phmag[0] = 64; + Phmag[0] = 127; // TODO: correct? Phphase[0] = 64; for(int n = 0; n < MAX_AD_HARMONICS; ++n) { if(xml.enterbranch("HARMONIC", n + 1) == 0)