|
- /*
- ZynAddSubFX - a software synthesizer
-
- Controller.cpp - (Midi) Controllers implementation
- Copyright (C) 2002-2005 Nasca Octavian Paul
- Author: Nasca Octavian Paul
-
- 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.
- */
-
- #include "Controller.h"
- #include "../Misc/Util.h"
- #include "../Misc/Time.h"
- #include "../Misc/XMLwrapper.h"
- #include <cmath>
- #include <cstdio>
-
- #include <rtosc/ports.h>
- #include <rtosc/port-sugar.h>
- using namespace rtosc;
-
- #define rObject Controller
-
- #undef rChangeCb
- #define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); }
- const rtosc::Ports Controller::ports = {
- rParamZyn(panning.depth, "Depth of Panning MIDI Control"),
- rParamZyn(filtercutoff.depth, "Depth of Filter Cutoff MIDI Control"),
- rParamZyn(filterq.depth, "Depth of Filter Q MIDI Control"),
- rParamZyn(bandwidth.depth, "Depth of Bandwidth MIDI Control"),
- rToggle(bandwidth.exponential, "Bandwidth Exponential Mode"),
- rParamZyn(modwheel.depth, "Depth of Modwheel MIDI Control"),
- rToggle(modwheel.exponential, "Modwheel Exponential Mode"),
- rToggle(pitchwheel.is_split, "If PitchWheel Has unified bendrange or not"),
- rParamI(pitchwheel.bendrange, "Range of MIDI Pitch Wheel"),
- rParamI(pitchwheel.bendrange_down, "Lower Range of MIDI Pitch Wheel"),
- rToggle(expression.receive, "Expression MIDI Receive"),
- rToggle(fmamp.receive, "FM amplitude MIDI Receive"),
- rToggle(volume.receive, "Volume MIDI Receive"),
- rToggle(sustain.receive, "Sustain MIDI Receive"),
- rToggle(portamento.receive, "Portamento MIDI Receive"),
- rToggle(portamento.portamento, "UNDOCUMENTED"),
- rParamZyn(portamento.time, "Portamento Length"),
- rToggle(portamento.proportional, "If all portamentos are proportional to the distance they span"),
- rParamZyn(portamento.propRate, "Portamento proportional rate"),
- rParamZyn(portamento.propDepth, "Portamento proportional depth"),
- rParamZyn(portamento.pitchthresh, "Threshold for portamento"),
- rToggle(portamento.pitchthreshtype, "Type of threshold"),
- rParamZyn(portamento.updowntimestretch, "UNDOCUMENTED"),
- rParamZyn(resonancecenter.depth, "Resonance Center MIDI Depth"),
- rParamZyn(resonancebandwidth.depth, "Resonance Bandwidth MIDI Depth"),
- rToggle(NRPN.receive, "NRPN MIDI Enable"),
- rAction(defaults),
- };
- #undef rChangeCb
-
- Controller::Controller(const SYNTH_T &synth_, const AbsTime *time_)
- :time(time_), last_update_timestamp(0), synth(synth_)
- {
- defaults();
- resetall();
- }
-
- Controller &Controller::operator=(const Controller &c)
- {
- //just pretend that undefined behavior doesn't exist...
- memcpy(this, &c, sizeof(Controller));
- return *this;
- }
-
- Controller::~Controller()
- {}
-
- void Controller::defaults()
- {
- pitchwheel.bendrange = 200; //2 halftones
- pitchwheel.bendrange_down = 0; //Unused by default
- pitchwheel.is_split = false;
- expression.receive = 1;
- panning.depth = 64;
- filtercutoff.depth = 64;
- filterq.depth = 64;
- bandwidth.depth = 64;
- bandwidth.exponential = 0;
- modwheel.depth = 80;
- modwheel.exponential = 0;
- fmamp.receive = 1;
- volume.receive = 1;
- sustain.receive = 1;
- NRPN.receive = 1;
-
- portamento.portamento = 0;
- portamento.used = 0;
- portamento.proportional = 0;
- portamento.propRate = 80;
- portamento.propDepth = 90;
- portamento.receive = 1;
- portamento.time = 64;
- portamento.updowntimestretch = 64;
- portamento.pitchthresh = 3;
- portamento.pitchthreshtype = 1;
- portamento.noteusing = -1;
- resonancecenter.depth = 64;
- resonancebandwidth.depth = 64;
-
- initportamento(440.0f, 440.0f, false); // Now has a third argument
- setportamento(0);
- }
-
- void Controller::resetall()
- {
- setpitchwheel(0); //center
- setexpression(127);
- setpanning(64);
- setfiltercutoff(64);
- setfilterq(64);
- setbandwidth(64);
- setmodwheel(64);
- setfmamp(127);
- setvolume(127);
- setsustain(0);
- setresonancecenter(64);
- setresonancebw(64);
-
- //reset the NRPN
- NRPN.parhi = -1;
- NRPN.parlo = -1;
- NRPN.valhi = -1;
- NRPN.vallo = -1;
- }
-
- void Controller::setpitchwheel(int value)
- {
- pitchwheel.data = value;
- float cents = value / 8192.0f;
- if(pitchwheel.is_split && cents < 0)
- cents *= pitchwheel.bendrange_down;
- else
- cents *= pitchwheel.bendrange;
- pitchwheel.relfreq = powf(2, cents / 1200.0f);
- //fprintf(stderr,"%ld %ld -> %.3f\n",pitchwheel.bendrange,pitchwheel.data,pitchwheel.relfreq);fflush(stderr);
- }
-
- void Controller::setexpression(int value)
- {
- expression.data = value;
- if(expression.receive != 0)
- expression.relvolume = value / 127.0f;
- else
- expression.relvolume = 1.0f;
- }
-
- void Controller::setpanning(int value)
- {
- panning.data = value;
- panning.pan = (value / 128.0f - 0.5f) * (panning.depth / 64.0f);
- }
-
- void Controller::setfiltercutoff(int value)
- {
- filtercutoff.data = value;
- filtercutoff.relfreq =
- (value - 64.0f) * filtercutoff.depth / 4096.0f * 3.321928f; //3.3219f..=ln2(10)
- }
-
- void Controller::setfilterq(int value)
- {
- filterq.data = value;
- filterq.relq = powf(30.0f, (value - 64.0f) / 64.0f * (filterq.depth / 64.0f));
- }
-
- void Controller::setbandwidth(int value)
- {
- bandwidth.data = value;
- if(bandwidth.exponential == 0) {
- float tmp = powf(25.0f, powf(bandwidth.depth / 127.0f, 1.5f)) - 1.0f;
- if((value < 64) && (bandwidth.depth >= 64))
- tmp = 1.0f;
- bandwidth.relbw = (value / 64.0f - 1.0f) * tmp + 1.0f;
- if(bandwidth.relbw < 0.01f)
- bandwidth.relbw = 0.01f;
- }
- else
- bandwidth.relbw =
- powf(25.0f, (value - 64.0f) / 64.0f * (bandwidth.depth / 64.0f));
- ;
- }
-
- void Controller::setmodwheel(int value)
- {
- modwheel.data = value;
- if(modwheel.exponential == 0) {
- float tmp =
- powf(25.0f, powf(modwheel.depth / 127.0f, 1.5f) * 2.0f) / 25.0f;
- if((value < 64) && (modwheel.depth >= 64))
- tmp = 1.0f;
- modwheel.relmod = (value / 64.0f - 1.0f) * tmp + 1.0f;
- if(modwheel.relmod < 0.0f)
- modwheel.relmod = 0.0f;
- }
- else
- modwheel.relmod =
- powf(25.0f, (value - 64.0f) / 64.0f * (modwheel.depth / 80.0f));
- }
-
- void Controller::setfmamp(int value)
- {
- fmamp.data = value;
- fmamp.relamp = value / 127.0f;
- if(fmamp.receive != 0)
- fmamp.relamp = value / 127.0f;
- else
- fmamp.relamp = 1.0f;
- }
-
- void Controller::setvolume(int value)
- {
- volume.data = value;
- if(volume.receive != 0)
- volume.volume = powf(0.1f, (127 - value) / 127.0f * 2.0f);
- else
- volume.volume = 1.0f;
- }
-
- void Controller::setsustain(int value)
- {
- sustain.data = value;
- if(sustain.receive != 0)
- sustain.sustain = ((value < 64) ? 0 : 1);
- else
- sustain.sustain = 0;
- }
-
- void Controller::setportamento(int value)
- {
- portamento.data = value;
- if(portamento.receive != 0)
- portamento.portamento = ((value < 64) ? 0 : 1);
- }
-
- int Controller::initportamento(float oldfreq,
- float newfreq,
- bool legatoflag)
- {
- portamento.x = 0.0f;
-
- if(legatoflag) { // Legato in progress
- if(portamento.portamento == 0)
- return 0;
- }
- else // No legato, do the original if...return
- if((portamento.used != 0) || (portamento.portamento == 0))
- return 0;
- ;
-
- float portamentotime = powf(100.0f, portamento.time / 127.0f) / 50.0f; //portamento time in seconds
-
- if(portamento.proportional) {
- //If there is a min(float,float) and a max(float,float) then they
- //could be used here
- //Linear functors could also make this nicer
- if(oldfreq > newfreq) //2 is the center of propRate
- portamentotime *=
- powf(oldfreq / newfreq
- / (portamento.propRate / 127.0f * 3 + .05),
- (portamento.propDepth / 127.0f * 1.6f + .2));
- else //1 is the center of propDepth
- portamentotime *=
- powf(newfreq / oldfreq
- / (portamento.propRate / 127.0f * 3 + .05),
- (portamento.propDepth / 127.0f * 1.6f + .2));
- }
-
- if((portamento.updowntimestretch >= 64) && (newfreq < oldfreq)) {
- if(portamento.updowntimestretch == 127)
- return 0;
- portamentotime *= powf(0.1f,
- (portamento.updowntimestretch - 64) / 63.0f);
- }
- if((portamento.updowntimestretch < 64) && (newfreq > oldfreq)) {
- if(portamento.updowntimestretch == 0)
- return 0;
- portamentotime *= powf(0.1f,
- (64.0f - portamento.updowntimestretch) / 64.0f);
- }
-
- //printf("%f->%f : Time %f\n",oldfreq,newfreq,portamentotime);
-
- portamento.dx = synth.buffersize_f / (portamentotime * synth.samplerate_f);
- portamento.origfreqrap = oldfreq / newfreq;
-
- float tmprap = ((portamento.origfreqrap > 1.0f) ?
- (portamento.origfreqrap) :
- (1.0f / portamento.origfreqrap));
-
- float thresholdrap = powf(2.0f, portamento.pitchthresh / 12.0f);
- if((portamento.pitchthreshtype == 0) && (tmprap - 0.00001f > thresholdrap))
- return 0;
- if((portamento.pitchthreshtype == 1) && (tmprap + 0.00001f < thresholdrap))
- return 0;
-
- portamento.used = 1;
- portamento.freqrap = portamento.origfreqrap;
- return 1;
- }
-
- void Controller::updateportamento()
- {
- if(portamento.used == 0)
- return;
-
- portamento.x += portamento.dx;
- if(portamento.x > 1.0f) {
- portamento.x = 1.0f;
- portamento.used = 0;
- }
- portamento.freqrap =
- (1.0f - portamento.x) * portamento.origfreqrap + portamento.x;
- }
-
-
- void Controller::setresonancecenter(int value)
- {
- resonancecenter.data = value;
- resonancecenter.relcenter =
- powf(3.0f, (value - 64.0f) / 64.0f * (resonancecenter.depth / 64.0f));
- }
- void Controller::setresonancebw(int value)
- {
- resonancebandwidth.data = value;
- resonancebandwidth.relbw =
- powf(1.5f, (value - 64.0f) / 64.0f * (resonancebandwidth.depth / 127.0f));
- }
-
-
- //Returns 0 if there is NRPN or 1 if there is not
- int Controller::getnrpn(int *parhi, int *parlo, int *valhi, int *vallo)
- {
- if(NRPN.receive == 0)
- return 1;
- if((NRPN.parhi < 0) || (NRPN.parlo < 0) || (NRPN.valhi < 0)
- || (NRPN.vallo < 0))
- return 1;
-
- *parhi = NRPN.parhi;
- *parlo = NRPN.parlo;
- *valhi = NRPN.valhi;
- *vallo = NRPN.vallo;
- return 0;
- }
-
-
- void Controller::setparameternumber(unsigned int type, int value)
- {
- switch(type) {
- case C_nrpnhi:
- NRPN.parhi = value;
- NRPN.valhi = -1;
- NRPN.vallo = -1; //clear the values
- break;
- case C_nrpnlo:
- NRPN.parlo = value;
- NRPN.valhi = -1;
- NRPN.vallo = -1; //clear the values
- break;
- case C_dataentryhi:
- if((NRPN.parhi >= 0) && (NRPN.parlo >= 0))
- NRPN.valhi = value;
- break;
- case C_dataentrylo:
- if((NRPN.parhi >= 0) && (NRPN.parlo >= 0))
- NRPN.vallo = value;
- break;
- }
- }
-
-
-
- void Controller::add2XML(XMLwrapper& xml)
- {
- xml.addpar("pitchwheel_bendrange", pitchwheel.bendrange);
- xml.addpar("pitchwheel_bendrange_down", pitchwheel.bendrange_down);
- xml.addparbool("pitchwheel_split", pitchwheel.is_split);
-
- xml.addparbool("expression_receive", expression.receive);
- xml.addpar("panning_depth", panning.depth);
- xml.addpar("filter_cutoff_depth", filtercutoff.depth);
- xml.addpar("filter_q_depth", filterq.depth);
- xml.addpar("bandwidth_depth", bandwidth.depth);
- xml.addpar("mod_wheel_depth", modwheel.depth);
- xml.addparbool("mod_wheel_exponential", modwheel.exponential);
- xml.addparbool("fm_amp_receive", fmamp.receive);
- xml.addparbool("volume_receive", volume.receive);
- xml.addparbool("sustain_receive", sustain.receive);
-
- xml.addparbool("portamento_receive", portamento.receive);
- xml.addpar("portamento_time", portamento.time);
- xml.addpar("portamento_pitchthresh", portamento.pitchthresh);
- xml.addpar("portamento_pitchthreshtype", portamento.pitchthreshtype);
- xml.addpar("portamento_portamento", portamento.portamento);
- xml.addpar("portamento_updowntimestretch", portamento.updowntimestretch);
- xml.addpar("portamento_proportional", portamento.proportional);
- xml.addpar("portamento_proprate", portamento.propRate);
- xml.addpar("portamento_propdepth", portamento.propDepth);
-
- xml.addpar("resonance_center_depth", resonancecenter.depth);
- xml.addpar("resonance_bandwidth_depth", resonancebandwidth.depth);
- }
-
- void Controller::getfromXML(XMLwrapper& xml)
- {
- pitchwheel.bendrange = xml.getpar("pitchwheel_bendrange",
- pitchwheel.bendrange,
- -6400,
- 6400);
- pitchwheel.bendrange_down = xml.getpar("pitchwheel_bendrange_down",
- pitchwheel.bendrange_down,
- -6400,
- 6400);
- pitchwheel.is_split = xml.getparbool("pitchwheel_split",
- pitchwheel.is_split);
-
- expression.receive = xml.getparbool("expression_receive",
- expression.receive);
- panning.depth = xml.getpar127("panning_depth", panning.depth);
- filtercutoff.depth = xml.getpar127("filter_cutoff_depth",
- filtercutoff.depth);
- filterq.depth = xml.getpar127("filter_q_depth", filterq.depth);
- bandwidth.depth = xml.getpar127("bandwidth_depth", bandwidth.depth);
- modwheel.depth = xml.getpar127("mod_wheel_depth", modwheel.depth);
- modwheel.exponential = xml.getparbool("mod_wheel_exponential",
- modwheel.exponential);
- fmamp.receive = xml.getparbool("fm_amp_receive",
- fmamp.receive);
- volume.receive = xml.getparbool("volume_receive",
- volume.receive);
- sustain.receive = xml.getparbool("sustain_receive",
- sustain.receive);
-
- portamento.receive = xml.getparbool("portamento_receive",
- portamento.receive);
- portamento.time = xml.getpar127("portamento_time",
- portamento.time);
- portamento.pitchthresh = xml.getpar127("portamento_pitchthresh",
- portamento.pitchthresh);
- portamento.pitchthreshtype = xml.getpar127("portamento_pitchthreshtype",
- portamento.pitchthreshtype);
- portamento.portamento = xml.getpar127("portamento_portamento",
- portamento.portamento);
- portamento.updowntimestretch = xml.getpar127(
- "portamento_updowntimestretch",
- portamento.updowntimestretch);
- portamento.proportional = xml.getpar127("portamento_proportional",
- portamento.proportional);
- portamento.propRate = xml.getpar127("portamento_proprate",
- portamento.propRate);
- portamento.propDepth = xml.getpar127("portamento_propdepth",
- portamento.propDepth);
-
-
- resonancecenter.depth = xml.getpar127("resonance_center_depth",
- resonancecenter.depth);
- resonancebandwidth.depth = xml.getpar127("resonance_bandwidth_depth",
- resonancebandwidth.depth);
- }
|