2017-01-23 10:15:08 +00:00
|
|
|
/*
|
|
|
|
==============================================================================
|
|
|
|
|
|
|
|
This file was auto-generated!
|
|
|
|
|
|
|
|
It contains the basic startup code for a Juce application.
|
|
|
|
|
|
|
|
==============================================================================
|
|
|
|
*/
|
|
|
|
#include "PluginProcessor.h"
|
|
|
|
#include "PluginEditor.h"
|
|
|
|
#include "Engine/Params.h"
|
|
|
|
|
2019-09-02 15:03:43 +00:00
|
|
|
// Compare JUCE_VERSION against this to check for JUCE 5.4.3 and earlier
|
|
|
|
#define JUCE_543 328707
|
|
|
|
|
2017-01-23 10:15:08 +00:00
|
|
|
//only sse2 version on windows
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
#define __SSE2__
|
|
|
|
#define __SSE__
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __SSE2__
|
|
|
|
#include <xmmintrin.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
#define S(T) (juce::String(T))
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
ObxdAudioProcessor::ObxdAudioProcessor()
|
|
|
|
: bindings()
|
|
|
|
, programs()
|
|
|
|
, configLock("__" JucePlugin_Name "ConfigLock__")
|
|
|
|
{
|
|
|
|
isHostAutomatedChange = true;
|
|
|
|
midiControlledParamSet = false;
|
|
|
|
lastMovedController = 0;
|
|
|
|
lastUsedParameter = 0;
|
|
|
|
|
|
|
|
synth.setSampleRate(44100);
|
|
|
|
|
|
|
|
PropertiesFile::Options options;
|
|
|
|
options.applicationName = JucePlugin_Name;
|
|
|
|
options.storageFormat = PropertiesFile::storeAsXML;
|
|
|
|
options.millisecondsBeforeSaving = 2500;
|
|
|
|
options.processLock = &configLock;
|
|
|
|
config = new PropertiesFile(getDocumentFolder().getChildFile("Settings.xml"), options);
|
|
|
|
|
2019-09-01 16:23:00 +00:00
|
|
|
currentSkin = config->containsKey("skin") ? config->getValue("skin") : "discoDSP Blue";
|
2017-01-23 10:15:08 +00:00
|
|
|
currentBank = "Init";
|
|
|
|
|
|
|
|
scanAndUpdateBanks();
|
|
|
|
initAllParams();
|
|
|
|
|
|
|
|
if (bankFiles.size() > 0)
|
|
|
|
{
|
|
|
|
loadFromFXBFile(bankFiles[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ObxdAudioProcessor::~ObxdAudioProcessor()
|
|
|
|
{
|
|
|
|
config->saveIfNeeded();
|
|
|
|
config = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
void ObxdAudioProcessor::initAllParams()
|
|
|
|
{
|
|
|
|
for (int i = 0 ; i < PARAM_COUNT; i++)
|
|
|
|
{
|
|
|
|
setParameter(i, programs.currentProgramPtr->values[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
int ObxdAudioProcessor::getNumParameters()
|
|
|
|
{
|
|
|
|
return PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
float ObxdAudioProcessor::getParameter (int index)
|
|
|
|
{
|
|
|
|
return programs.currentProgramPtr->values[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObxdAudioProcessor::setParameter (int index, float newValue)
|
|
|
|
{
|
|
|
|
if(!midiControlledParamSet || index==MIDILEARN || index==UNLEARN)
|
|
|
|
lastUsedParameter = index;
|
|
|
|
programs.currentProgramPtr->values[index] = newValue;
|
|
|
|
switch(index)
|
|
|
|
{
|
|
|
|
case SELF_OSC_PUSH:
|
|
|
|
synth.processSelfOscPush(newValue);
|
|
|
|
break;
|
|
|
|
case PW_ENV_BOTH:
|
|
|
|
synth.processPwEnvBoth(newValue);
|
|
|
|
break;
|
|
|
|
case PW_OSC2_OFS:
|
|
|
|
synth.processPwOfs(newValue);
|
|
|
|
break;
|
|
|
|
case ENV_PITCH_BOTH:
|
|
|
|
synth.processPitchModBoth(newValue);
|
|
|
|
break;
|
|
|
|
case FENV_INVERT:
|
|
|
|
synth.processInvertFenv(newValue);
|
|
|
|
break;
|
|
|
|
case LEVEL_DIF:
|
|
|
|
synth.processLoudnessDetune(newValue);
|
|
|
|
break;
|
|
|
|
case PW_ENV:
|
|
|
|
synth.processPwEnv(newValue);
|
|
|
|
break;
|
|
|
|
case LFO_SYNC:
|
|
|
|
synth.procLfoSync(newValue);
|
|
|
|
break;
|
|
|
|
case ECONOMY_MODE:
|
|
|
|
synth.procEconomyMode(newValue);
|
|
|
|
break;
|
|
|
|
case VAMPENV:
|
|
|
|
synth.procAmpVelocityAmount(newValue);
|
|
|
|
break;
|
|
|
|
case VFLTENV:
|
|
|
|
synth.procFltVelocityAmount(newValue);
|
|
|
|
break;
|
|
|
|
case ASPLAYEDALLOCATION:
|
|
|
|
synth.procAsPlayedAlloc(newValue);
|
|
|
|
break;
|
|
|
|
case BENDLFORATE:
|
|
|
|
synth.procModWheelFrequency(newValue);
|
|
|
|
break;
|
|
|
|
case FOURPOLE:
|
|
|
|
synth.processFourPole(newValue);
|
|
|
|
break;
|
|
|
|
case LEGATOMODE:
|
|
|
|
synth.processLegatoMode(newValue);
|
|
|
|
break;
|
|
|
|
case ENVPITCH:
|
|
|
|
synth.processEnvelopeToPitch(newValue);
|
|
|
|
break;
|
|
|
|
case OSCQuantize:
|
|
|
|
synth.processPitchQuantization(newValue);
|
|
|
|
break;
|
|
|
|
case VOICE_COUNT:
|
|
|
|
synth.setVoiceCount(newValue);
|
|
|
|
break;
|
|
|
|
case BANDPASS:
|
|
|
|
synth.processBandpassSw(newValue);
|
|
|
|
break;
|
|
|
|
case FILTER_WARM:
|
|
|
|
synth.processOversampling(newValue);
|
|
|
|
break;
|
|
|
|
case BENDOSC2:
|
|
|
|
synth.procPitchWheelOsc2Only(newValue);
|
|
|
|
break;
|
|
|
|
case BENDRANGE:
|
|
|
|
synth.procPitchWheelAmount(newValue);
|
|
|
|
break;
|
|
|
|
case NOISEMIX:
|
|
|
|
synth.processNoiseMix(newValue);
|
|
|
|
break;
|
|
|
|
case OCTAVE:
|
|
|
|
synth.processOctave(newValue);
|
|
|
|
break;
|
|
|
|
case TUNE:
|
|
|
|
synth.processTune(newValue);
|
|
|
|
break;
|
|
|
|
case BRIGHTNESS:
|
|
|
|
synth.processBrightness(newValue);
|
|
|
|
break;
|
|
|
|
case MULTIMODE:
|
|
|
|
synth.processMultimode(newValue);
|
|
|
|
break;
|
|
|
|
case LFOFREQ:
|
|
|
|
synth.processLfoFrequency(newValue);
|
|
|
|
break;
|
|
|
|
case LFO1AMT:
|
|
|
|
synth.processLfoAmt1(newValue);
|
|
|
|
break;
|
|
|
|
case LFO2AMT:
|
|
|
|
synth.processLfoAmt2(newValue);
|
|
|
|
break;
|
|
|
|
case LFOSINWAVE:
|
|
|
|
synth.processLfoSine(newValue);
|
|
|
|
break;
|
|
|
|
case LFOSQUAREWAVE:
|
|
|
|
synth.processLfoSquare(newValue);
|
|
|
|
break;
|
|
|
|
case LFOSHWAVE:
|
|
|
|
synth.processLfoSH(newValue);
|
|
|
|
break;
|
|
|
|
case LFOFILTER:
|
|
|
|
synth.processLfoFilter(newValue);
|
|
|
|
break;
|
|
|
|
case LFOOSC1:
|
|
|
|
synth.processLfoOsc1(newValue);
|
|
|
|
break;
|
|
|
|
case LFOOSC2:
|
|
|
|
synth.processLfoOsc2(newValue);
|
|
|
|
break;
|
|
|
|
case LFOPW1:
|
|
|
|
synth.processLfoPw1(newValue);
|
|
|
|
break;
|
|
|
|
case LFOPW2:
|
|
|
|
synth.processLfoPw2(newValue);
|
|
|
|
break;
|
|
|
|
case PORTADER:
|
|
|
|
synth.processPortamentoDetune(newValue);
|
|
|
|
break;
|
|
|
|
case FILTERDER:
|
|
|
|
synth.processFilterDetune(newValue);
|
|
|
|
break;
|
|
|
|
case ENVDER:
|
|
|
|
synth.processEnvelopeDetune(newValue);
|
|
|
|
break;
|
|
|
|
case XMOD:
|
|
|
|
synth.processOsc2Xmod(newValue);
|
|
|
|
break;
|
|
|
|
case OSC2HS:
|
|
|
|
synth.processOsc2HardSync(newValue);
|
|
|
|
break;
|
|
|
|
case OSC2P:
|
|
|
|
synth.processOsc2Pitch(newValue);
|
|
|
|
break;
|
|
|
|
case OSC1P:
|
|
|
|
synth.processOsc1Pitch(newValue);
|
|
|
|
break;
|
|
|
|
case PORTAMENTO:
|
|
|
|
synth.processPortamento(newValue);
|
|
|
|
break;
|
|
|
|
case UNISON:
|
|
|
|
synth.processUnison(newValue);
|
|
|
|
break;
|
|
|
|
case FLT_KF:
|
|
|
|
synth.processFilterKeyFollow(newValue);
|
|
|
|
break;
|
|
|
|
case OSC1MIX:
|
|
|
|
synth.processOsc1Mix(newValue);
|
|
|
|
break;
|
|
|
|
case OSC2MIX:
|
|
|
|
synth.processOsc2Mix(newValue);
|
|
|
|
break;
|
|
|
|
case PW:
|
|
|
|
synth.processPulseWidth(newValue);
|
|
|
|
break;
|
|
|
|
case OSC1Saw:
|
|
|
|
synth.processOsc1Saw(newValue);
|
|
|
|
break;
|
|
|
|
case OSC2Saw:
|
|
|
|
synth.processOsc2Saw(newValue);
|
|
|
|
break;
|
|
|
|
case OSC1Pul:
|
|
|
|
synth.processOsc1Pulse(newValue);
|
|
|
|
break;
|
|
|
|
case OSC2Pul:
|
|
|
|
synth.processOsc2Pulse(newValue);
|
|
|
|
break;
|
|
|
|
case VOLUME:
|
|
|
|
synth.processVolume(newValue);
|
|
|
|
break;
|
|
|
|
case UDET:
|
|
|
|
synth.processDetune(newValue);
|
|
|
|
break;
|
|
|
|
case OSC2_DET:
|
|
|
|
synth.processOsc2Det(newValue);
|
|
|
|
break;
|
|
|
|
case CUTOFF:
|
|
|
|
synth.processCutoff(newValue);
|
|
|
|
break;
|
|
|
|
case RESONANCE:
|
|
|
|
synth.processResonance(newValue);
|
|
|
|
break;
|
|
|
|
case ENVELOPE_AMT:
|
|
|
|
synth.processFilterEnvelopeAmt(newValue);
|
|
|
|
break;
|
|
|
|
case LATK:
|
|
|
|
synth.processLoudnessEnvelopeAttack(newValue);
|
|
|
|
break;
|
|
|
|
case LDEC:
|
|
|
|
synth.processLoudnessEnvelopeDecay(newValue);
|
|
|
|
break;
|
|
|
|
case LSUS:
|
|
|
|
synth.processLoudnessEnvelopeSustain(newValue);
|
|
|
|
break;
|
|
|
|
case LREL:
|
|
|
|
synth.processLoudnessEnvelopeRelease(newValue);
|
|
|
|
break;
|
|
|
|
case FATK:
|
|
|
|
synth.processFilterEnvelopeAttack(newValue);
|
|
|
|
break;
|
|
|
|
case FDEC:
|
|
|
|
synth.processFilterEnvelopeDecay(newValue);
|
|
|
|
break;
|
|
|
|
case FSUS:
|
|
|
|
synth.processFilterEnvelopeSustain(newValue);
|
|
|
|
break;
|
|
|
|
case FREL:
|
|
|
|
synth.processFilterEnvelopeRelease(newValue);
|
|
|
|
break;
|
|
|
|
case PAN1:
|
|
|
|
synth.processPan(newValue,1);
|
|
|
|
break;
|
|
|
|
case PAN2:
|
|
|
|
synth.processPan(newValue,2);
|
|
|
|
break;
|
|
|
|
case PAN3:
|
|
|
|
synth.processPan(newValue,3);
|
|
|
|
break;
|
|
|
|
case PAN4:
|
|
|
|
synth.processPan(newValue,4);
|
|
|
|
break;
|
|
|
|
case PAN5:
|
|
|
|
synth.processPan(newValue,5);
|
|
|
|
break;
|
|
|
|
case PAN6:
|
|
|
|
synth.processPan(newValue,6);
|
|
|
|
break;
|
|
|
|
case PAN7:
|
|
|
|
synth.processPan(newValue,7);
|
|
|
|
break;
|
|
|
|
case PAN8:
|
|
|
|
synth.processPan(newValue,8);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//DIRTY HACK
|
|
|
|
//This should be checked to avoid stalling on gui update
|
|
|
|
//It is needed because some hosts do wierd stuff
|
|
|
|
if(isHostAutomatedChange)
|
|
|
|
sendChangeMessage();
|
|
|
|
}
|
|
|
|
|
|
|
|
const String ObxdAudioProcessor::getParameterName (int index)
|
|
|
|
{
|
|
|
|
switch(index)
|
|
|
|
{
|
|
|
|
case SELF_OSC_PUSH:
|
|
|
|
return S("SelfOscPush");
|
|
|
|
case ENV_PITCH_BOTH:
|
|
|
|
return S("EnvPitchBoth");
|
|
|
|
case FENV_INVERT:
|
|
|
|
return S("FenvInvert");
|
|
|
|
case PW_OSC2_OFS:
|
|
|
|
return S("PwOfs");
|
|
|
|
case LEVEL_DIF:
|
|
|
|
return S("LevelDif");
|
|
|
|
case PW_ENV_BOTH:
|
|
|
|
return S("PwEnvBoth");
|
|
|
|
case PW_ENV:
|
|
|
|
return S("PwEnv");
|
|
|
|
case LFO_SYNC:
|
|
|
|
return S("LfoSync");
|
|
|
|
case ECONOMY_MODE:
|
|
|
|
return S("EconomyMode");
|
|
|
|
case UNLEARN:
|
|
|
|
return S("MidiUnlearn");
|
|
|
|
case MIDILEARN:
|
|
|
|
return S("MidiLearn");
|
|
|
|
case VAMPENV:
|
|
|
|
return S("VAmpFactor");
|
|
|
|
case VFLTENV:
|
|
|
|
return S("VFltFactor");
|
|
|
|
case ASPLAYEDALLOCATION:
|
|
|
|
return S("AsPlayedAllocation");
|
|
|
|
case BENDLFORATE:
|
|
|
|
return S("VibratoRate");
|
|
|
|
case FOURPOLE:
|
|
|
|
return S("FourPole");
|
|
|
|
case LEGATOMODE:
|
|
|
|
return S("LegatoMode");
|
|
|
|
case ENVPITCH:
|
|
|
|
return S("EnvelopeToPitch");
|
|
|
|
case OSCQuantize:
|
|
|
|
return S("PitchQuant");
|
|
|
|
case VOICE_COUNT:
|
|
|
|
return S("VoiceCount");
|
|
|
|
case BANDPASS:
|
|
|
|
return S("BandpassBlend");
|
|
|
|
case FILTER_WARM:
|
|
|
|
return S("Filter_Warm");
|
|
|
|
case BENDRANGE:
|
|
|
|
return S("BendRange");
|
|
|
|
case BENDOSC2:
|
|
|
|
return S("BendOsc2Only");
|
|
|
|
case OCTAVE:
|
|
|
|
return S("Octave");
|
|
|
|
case TUNE:
|
|
|
|
return S("Tune");
|
|
|
|
case BRIGHTNESS:
|
|
|
|
return S("Brightness");
|
|
|
|
case NOISEMIX:
|
|
|
|
return S("NoiseMix");
|
|
|
|
case OSC1MIX:
|
|
|
|
return S("Osc1Mix");
|
|
|
|
case OSC2MIX:
|
|
|
|
return S("Osc2Mix");
|
|
|
|
case MULTIMODE:
|
|
|
|
return S("Multimode");
|
|
|
|
case LFOSHWAVE:
|
|
|
|
return S("LfoSampleHoldWave");
|
|
|
|
case LFOSINWAVE:
|
|
|
|
return S("LfoSineWave");
|
|
|
|
case LFOSQUAREWAVE:
|
|
|
|
return S("LfoSquareWave");
|
|
|
|
case LFO1AMT:
|
|
|
|
return S("LfoAmount1");
|
|
|
|
case LFO2AMT:
|
|
|
|
return S("LfoAmount2");
|
|
|
|
case LFOFILTER:
|
|
|
|
return S("LfoFilter");
|
|
|
|
case LFOOSC1:
|
|
|
|
return S("LfoOsc1");
|
|
|
|
case LFOOSC2:
|
|
|
|
return S("LfoOsc2");
|
|
|
|
case LFOFREQ:
|
|
|
|
return S("LfoFrequency");
|
|
|
|
case LFOPW1:
|
|
|
|
return S("LfoPw1");
|
|
|
|
case LFOPW2:
|
|
|
|
return S("LfoPw2");
|
|
|
|
case PORTADER:
|
|
|
|
return S("PortamentoDetune");
|
|
|
|
case FILTERDER:
|
|
|
|
return S("FilterDetune");
|
|
|
|
case ENVDER:
|
|
|
|
return S("EnvelopeDetune");
|
|
|
|
case PAN1:
|
|
|
|
return S("Pan1");
|
|
|
|
case PAN2:
|
|
|
|
return S("Pan2");
|
|
|
|
case PAN3:
|
|
|
|
return S("Pan3");
|
|
|
|
case PAN4:
|
|
|
|
return S("Pan4");
|
|
|
|
case PAN5:
|
|
|
|
return S("Pan5");
|
|
|
|
case PAN6:
|
|
|
|
return S("Pan6");
|
|
|
|
case PAN7:
|
|
|
|
return S("Pan7");
|
|
|
|
case PAN8:
|
|
|
|
return S("Pan8");
|
|
|
|
case XMOD:
|
|
|
|
return S("Xmod");
|
|
|
|
case OSC2HS:
|
|
|
|
return S("Osc2HardSync");
|
|
|
|
case OSC1P:
|
|
|
|
return S("Osc1Pitch");
|
|
|
|
case OSC2P:
|
|
|
|
return S("Osc2Pitch");
|
|
|
|
case PORTAMENTO:
|
|
|
|
return S("Portamento");
|
|
|
|
case UNISON:
|
|
|
|
return S("Unison");
|
|
|
|
case FLT_KF:
|
|
|
|
return S("FilterKeyFollow");
|
|
|
|
case PW:
|
|
|
|
return S("PulseWidth");
|
|
|
|
case OSC2Saw:
|
|
|
|
return S("Osc2Saw");
|
|
|
|
case OSC1Saw:
|
|
|
|
return S("Osc1Saw");
|
|
|
|
case OSC1Pul:
|
|
|
|
return S("Osc1Pulse");
|
|
|
|
case OSC2Pul:
|
|
|
|
return S("Osc2Pulse");
|
|
|
|
case VOLUME:
|
|
|
|
return S("Volume");
|
|
|
|
case UDET:
|
|
|
|
return S("VoiceDetune");
|
|
|
|
case OSC2_DET:
|
|
|
|
return S("Oscillator2detune");
|
|
|
|
case CUTOFF:
|
|
|
|
return S("Cutoff");
|
|
|
|
case RESONANCE:
|
|
|
|
return S("Resonance");
|
|
|
|
case ENVELOPE_AMT:
|
|
|
|
return S("FilterEnvAmount");
|
|
|
|
case LATK:
|
|
|
|
return S("Attack");
|
|
|
|
case LDEC:
|
|
|
|
return S("Decay");
|
|
|
|
case LSUS:
|
|
|
|
return S("Sustain");
|
|
|
|
case LREL:
|
|
|
|
return S("Release");
|
|
|
|
case FATK:
|
|
|
|
return S("FilterAttack");
|
|
|
|
case FDEC:
|
|
|
|
return S("FilterDecay");
|
|
|
|
case FSUS:
|
|
|
|
return S("FilterSustain");
|
|
|
|
case FREL:
|
|
|
|
return S("FilterRelease");
|
|
|
|
}
|
2019-09-01 17:02:11 +00:00
|
|
|
return {};
|
2017-01-23 10:15:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const String ObxdAudioProcessor::getParameterText (int index)
|
|
|
|
{
|
|
|
|
return String(programs.currentProgramPtr->values[index],2);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
const String ObxdAudioProcessor::getName() const
|
|
|
|
{
|
|
|
|
return JucePlugin_Name;
|
|
|
|
}
|
|
|
|
|
|
|
|
const String ObxdAudioProcessor::getInputChannelName (int channelIndex) const
|
|
|
|
{
|
|
|
|
return String (channelIndex + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
const String ObxdAudioProcessor::getOutputChannelName (int channelIndex) const
|
|
|
|
{
|
|
|
|
return String (channelIndex + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ObxdAudioProcessor::isInputChannelStereoPair (int index) const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ObxdAudioProcessor::isOutputChannelStereoPair (int index) const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ObxdAudioProcessor::acceptsMidi() const
|
|
|
|
{
|
|
|
|
#if JucePlugin_WantsMidiInput
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ObxdAudioProcessor::producesMidi() const
|
|
|
|
{
|
|
|
|
#if JucePlugin_ProducesMidiOutput
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ObxdAudioProcessor::silenceInProducesSilenceOut() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
double ObxdAudioProcessor::getTailLengthSeconds() const
|
|
|
|
{
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
int ObxdAudioProcessor::getNumPrograms()
|
|
|
|
{
|
|
|
|
return PROGRAMCOUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ObxdAudioProcessor::getCurrentProgram()
|
|
|
|
{
|
|
|
|
return programs.currentProgram;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObxdAudioProcessor::setCurrentProgram (int index)
|
|
|
|
{
|
|
|
|
programs.currentProgram = index;
|
|
|
|
programs.currentProgramPtr = programs.programs + programs.currentProgram;
|
|
|
|
isHostAutomatedChange = false;
|
|
|
|
for(int i = 0 ; i < PARAM_COUNT;i++)
|
|
|
|
setParameter(i,programs.currentProgramPtr->values[i]);
|
|
|
|
isHostAutomatedChange = true;
|
|
|
|
sendChangeMessage();
|
|
|
|
updateHostDisplay();
|
|
|
|
}
|
|
|
|
|
|
|
|
const String ObxdAudioProcessor::getProgramName (int index)
|
|
|
|
{
|
|
|
|
return programs.programs[index].name;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObxdAudioProcessor::changeProgramName (int index, const String& newName)
|
|
|
|
{
|
|
|
|
programs.programs[index].name = newName;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
void ObxdAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
|
|
|
|
{
|
|
|
|
// Use this method as the place to do any pre-playback
|
|
|
|
// initialisation that you need..
|
|
|
|
nextMidi= new MidiMessage(0xF0);
|
|
|
|
midiMsg = new MidiMessage(0xF0);
|
|
|
|
synth.setSampleRate(sampleRate);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObxdAudioProcessor::releaseResources()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void ObxdAudioProcessor::processMidiPerSample(MidiBuffer::Iterator* iter,const int samplePos)
|
|
|
|
{
|
|
|
|
while (getNextEvent(iter, samplePos))
|
|
|
|
{
|
|
|
|
if(midiMsg->isNoteOn())
|
|
|
|
{
|
|
|
|
synth.procNoteOn(midiMsg->getNoteNumber(),midiMsg->getFloatVelocity());
|
|
|
|
}
|
|
|
|
if (midiMsg->isNoteOff())
|
|
|
|
{
|
|
|
|
synth.procNoteOff(midiMsg->getNoteNumber());
|
|
|
|
}
|
|
|
|
if(midiMsg->isPitchWheel())
|
|
|
|
{
|
|
|
|
// [0..16383] center = 8192;
|
|
|
|
synth.procPitchWheel((midiMsg->getPitchWheelValue()-8192) / 8192.0);
|
|
|
|
}
|
|
|
|
if(midiMsg->isController() && midiMsg->getControllerNumber()==1)
|
|
|
|
synth.procModWheel(midiMsg->getControllerValue() / 127.0);
|
|
|
|
if(midiMsg->isController())
|
|
|
|
{
|
|
|
|
lastMovedController = midiMsg->getControllerNumber();
|
|
|
|
if(programs.currentProgramPtr->values[MIDILEARN] > 0.5)
|
|
|
|
bindings.controllers[lastMovedController] = lastUsedParameter;
|
|
|
|
if(programs.currentProgramPtr->values[UNLEARN] >0.5)
|
|
|
|
{
|
|
|
|
midiControlledParamSet = true;
|
|
|
|
bindings.controllers[lastMovedController] = 0;
|
|
|
|
setParameter(UNLEARN,0);
|
|
|
|
lastMovedController = 0;
|
|
|
|
lastUsedParameter = 0;
|
|
|
|
midiControlledParamSet = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(bindings.controllers[lastMovedController] > 0)
|
|
|
|
{
|
|
|
|
midiControlledParamSet = true;
|
|
|
|
setParameter(bindings.controllers[lastMovedController],midiMsg->getControllerValue() / 127.0);
|
|
|
|
setParameter(MIDILEARN,0);
|
|
|
|
lastMovedController = 0;
|
|
|
|
lastUsedParameter = 0;
|
|
|
|
|
|
|
|
midiControlledParamSet = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if(midiMsg->isSustainPedalOn())
|
|
|
|
{
|
|
|
|
synth.sustainOn();
|
|
|
|
}
|
|
|
|
if(midiMsg->isSustainPedalOff() || midiMsg->isAllNotesOff()||midiMsg->isAllSoundOff())
|
|
|
|
{
|
|
|
|
synth.sustainOff();
|
|
|
|
}
|
|
|
|
if(midiMsg->isAllNotesOff())
|
|
|
|
{
|
|
|
|
synth.allNotesOff();
|
|
|
|
}
|
|
|
|
if(midiMsg->isAllSoundOff())
|
|
|
|
{
|
|
|
|
synth.allSoundOff();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ObxdAudioProcessor::getNextEvent(MidiBuffer::Iterator* iter,const int samplePos)
|
|
|
|
{
|
|
|
|
if (hasMidiMessage && midiEventPos <= samplePos)
|
|
|
|
{
|
|
|
|
*midiMsg = *nextMidi;
|
|
|
|
hasMidiMessage = iter->getNextEvent(*nextMidi, midiEventPos);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObxdAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
|
|
|
|
{
|
|
|
|
//SSE flags set
|
|
|
|
#ifdef __SSE__
|
|
|
|
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
|
|
|
|
#endif
|
|
|
|
#ifdef __SSE2__
|
|
|
|
// _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
MidiBuffer::Iterator ppp(midiMessages);
|
|
|
|
hasMidiMessage = ppp.getNextEvent(*nextMidi,midiEventPos);
|
|
|
|
|
|
|
|
int samplePos = 0;
|
|
|
|
int numSamples = buffer.getNumSamples();
|
|
|
|
float* channelData1 = buffer.getWritePointer(0);
|
|
|
|
float* channelData2 = buffer.getWritePointer(1);
|
|
|
|
|
|
|
|
AudioPlayHead::CurrentPositionInfo pos;
|
|
|
|
if (getPlayHead() != 0 && getPlayHead()->getCurrentPosition (pos))
|
|
|
|
{
|
|
|
|
synth.setPlayHead(pos.bpm,pos.ppqPosition);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (samplePos < numSamples)
|
|
|
|
{
|
|
|
|
processMidiPerSample(&ppp,samplePos);
|
|
|
|
|
|
|
|
synth.processSample(channelData1+samplePos,channelData2+samplePos);
|
|
|
|
|
|
|
|
samplePos++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
bool ObxdAudioProcessor::hasEditor() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
AudioProcessorEditor* ObxdAudioProcessor::createEditor()
|
|
|
|
{
|
|
|
|
return new ObxdAudioProcessorEditor (this);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
2019-09-02 15:03:43 +00:00
|
|
|
void ObxdAudioProcessor::getStateInformation(MemoryBlock& destData)
|
2017-01-23 10:15:08 +00:00
|
|
|
{
|
|
|
|
XmlElement xmlState = XmlElement("Datsounds");
|
|
|
|
xmlState.setAttribute(S("currentProgram"), programs.currentProgram);
|
|
|
|
|
|
|
|
XmlElement* xprogs = new XmlElement("programs");
|
|
|
|
for (int i = 0; i < PROGRAMCOUNT; ++i)
|
|
|
|
{
|
|
|
|
XmlElement* xpr = new XmlElement("program");
|
|
|
|
xpr->setAttribute(S("programName"), programs.programs[i].name);
|
2019-09-02 15:03:43 +00:00
|
|
|
xpr->setAttribute(S("voiceCount"), Motherboard::MAX_VOICES);
|
2017-01-23 10:15:08 +00:00
|
|
|
|
|
|
|
for (int k = 0; k < PARAM_COUNT; ++k)
|
|
|
|
{
|
|
|
|
xpr->setAttribute(String(k), programs.programs[i].values[k]);
|
|
|
|
}
|
|
|
|
|
|
|
|
xprogs->addChildElement(xpr);
|
|
|
|
}
|
|
|
|
|
|
|
|
xmlState.addChildElement(xprogs);
|
|
|
|
|
|
|
|
for (int i = 0; i < 255; ++i)
|
|
|
|
{
|
|
|
|
xmlState.setAttribute(String(i), bindings.controllers[i]);
|
|
|
|
}
|
|
|
|
|
2019-09-02 15:03:43 +00:00
|
|
|
copyXmlToBinary(xmlState, destData);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObxdAudioProcessor::getCurrentProgramStateInformation(MemoryBlock& destData)
|
|
|
|
{
|
|
|
|
XmlElement xmlState = XmlElement("Datsounds");
|
|
|
|
|
|
|
|
for (int k = 0; k < PARAM_COUNT; ++k)
|
|
|
|
{
|
|
|
|
xmlState.setAttribute(String(k), programs.currentProgramPtr->values[k]);
|
|
|
|
}
|
|
|
|
|
|
|
|
xmlState.setAttribute(S("voiceCount"), Motherboard::MAX_VOICES);
|
|
|
|
xmlState.setAttribute(S("programName"), programs.currentProgramPtr->name);
|
|
|
|
|
|
|
|
copyXmlToBinary(xmlState, destData);
|
2017-01-23 10:15:08 +00:00
|
|
|
}
|
2019-09-01 19:01:24 +00:00
|
|
|
|
2019-09-02 15:03:43 +00:00
|
|
|
void ObxdAudioProcessor::setStateInformation(const void* data, int sizeInBytes)
|
2017-01-23 10:15:08 +00:00
|
|
|
{
|
2019-09-02 15:03:43 +00:00
|
|
|
#if JUCE_VERSION <= JUCE_543
|
|
|
|
XmlElement * const xmlState = getXmlFromBinary(data, sizeInBytes);
|
|
|
|
#else
|
|
|
|
std::unique_ptr<XmlElement> xmlState = getXmlFromBinary(data, sizeInBytes);
|
|
|
|
#endif
|
|
|
|
if (xmlState)
|
2017-01-23 10:15:08 +00:00
|
|
|
{
|
|
|
|
XmlElement* xprogs = xmlState->getFirstChildElement();
|
|
|
|
if (xprogs->hasTagName(S("programs")))
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
forEachXmlChildElement(*xprogs, e)
|
|
|
|
{
|
2019-09-02 15:03:43 +00:00
|
|
|
bool newFormat = e->hasAttribute("voiceCount");
|
2017-01-23 10:15:08 +00:00
|
|
|
programs.programs[i].setDefaultValues();
|
|
|
|
|
|
|
|
for (int k = 0; k < PARAM_COUNT; ++k)
|
|
|
|
{
|
2019-09-02 15:03:43 +00:00
|
|
|
float value = float(e->getDoubleAttribute(String(k), programs.programs[i].values[k]));
|
|
|
|
if (!newFormat && k == VOICE_COUNT) value *= 0.25f;
|
|
|
|
programs.programs[i].values[k] = value;
|
2017-01-23 10:15:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
programs.programs[i].name = e->getStringAttribute(S("programName"), S("Default"));
|
|
|
|
|
|
|
|
++i;
|
2019-09-02 15:03:43 +00:00
|
|
|
}
|
2017-01-23 10:15:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 255; ++i)
|
|
|
|
{
|
|
|
|
bindings.controllers[i] = xmlState->getIntAttribute(String(i), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
setCurrentProgram(xmlState->getIntAttribute(S("currentProgram"), 0));
|
2019-09-01 17:02:11 +00:00
|
|
|
|
2019-09-02 15:03:43 +00:00
|
|
|
#if JUCE_VERSION <= JUCE_543
|
2019-09-01 17:02:11 +00:00
|
|
|
delete xmlState;
|
2019-09-02 15:03:43 +00:00
|
|
|
#endif
|
|
|
|
}
|
2017-01-23 10:15:08 +00:00
|
|
|
}
|
|
|
|
|
2019-09-02 15:03:43 +00:00
|
|
|
void ObxdAudioProcessor::setCurrentProgramStateInformation(const void* data, int sizeInBytes)
|
2017-01-23 10:15:08 +00:00
|
|
|
{
|
2019-09-02 15:03:43 +00:00
|
|
|
#if JUCE_VERSION <= JUCE_543
|
|
|
|
XmlElement * const e = getXmlFromBinary(data, sizeInBytes);
|
|
|
|
#else
|
|
|
|
std::unique_ptr<XmlElement> e = getXmlFromBinary(data, sizeInBytes);
|
|
|
|
#endif
|
|
|
|
if (e)
|
2017-01-23 10:15:08 +00:00
|
|
|
{
|
|
|
|
programs.currentProgramPtr->setDefaultValues();
|
|
|
|
|
2019-09-02 15:03:43 +00:00
|
|
|
bool newFormat = e->hasAttribute("voiceCount");
|
2017-01-23 10:15:08 +00:00
|
|
|
for (int k = 0; k < PARAM_COUNT; ++k)
|
|
|
|
{
|
2019-09-02 15:03:43 +00:00
|
|
|
float value = float(e->getDoubleAttribute(String(k), programs.currentProgramPtr->values[k]));
|
|
|
|
if (!newFormat && k == VOICE_COUNT) value *= 0.25f;
|
|
|
|
programs.currentProgramPtr->values[k] = value;
|
2017-01-23 10:15:08 +00:00
|
|
|
}
|
|
|
|
|
2019-09-02 15:03:43 +00:00
|
|
|
programs.currentProgramPtr->name = e->getStringAttribute(S("programName"), S("Default"));
|
2017-01-23 10:15:08 +00:00
|
|
|
|
|
|
|
setCurrentProgram(programs.currentProgram);
|
2019-09-01 17:02:11 +00:00
|
|
|
|
2019-09-02 15:03:43 +00:00
|
|
|
#if JUCE_VERSION <= JUCE_543
|
2019-09-01 17:02:11 +00:00
|
|
|
delete e;
|
2019-09-02 15:03:43 +00:00
|
|
|
#endif
|
2017-01-23 10:15:08 +00:00
|
|
|
}
|
|
|
|
}
|
2019-09-01 17:02:11 +00:00
|
|
|
|
2017-01-23 10:15:08 +00:00
|
|
|
//==============================================================================
|
|
|
|
bool ObxdAudioProcessor::loadFromFXBFile(const File& fxbFile)
|
|
|
|
{
|
|
|
|
MemoryBlock mb;
|
|
|
|
if (! fxbFile.loadFileAsData(mb))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const void* const data = mb.getData();
|
|
|
|
const size_t dataSize = mb.getSize();
|
|
|
|
|
|
|
|
if (dataSize < 28)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const fxSet* const set = (const fxSet*) data;
|
|
|
|
|
|
|
|
if ((! compareMagic (set->chunkMagic, "CcnK")) || fxbSwap (set->version) > fxbVersionNum)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (compareMagic (set->fxMagic, "FxBk"))
|
|
|
|
{
|
|
|
|
// bank of programs
|
|
|
|
if (fxbSwap (set->numPrograms) >= 0)
|
|
|
|
{
|
|
|
|
const int oldProg = getCurrentProgram();
|
|
|
|
const int numParams = fxbSwap (((const fxProgram*) (set->programs))->numParams);
|
|
|
|
const int progLen = (int) sizeof (fxProgram) + (numParams - 1) * (int) sizeof (float);
|
|
|
|
|
|
|
|
for (int i = 0; i < fxbSwap (set->numPrograms); ++i)
|
|
|
|
{
|
|
|
|
if (i != oldProg)
|
|
|
|
{
|
|
|
|
const fxProgram* const prog = (const fxProgram*) (((const char*) (set->programs)) + i * progLen);
|
|
|
|
if (((const char*) prog) - ((const char*) set) >= (ssize_t) dataSize)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (fxbSwap (set->numPrograms) > 0)
|
|
|
|
setCurrentProgram (i);
|
|
|
|
|
|
|
|
if (! restoreProgramSettings (prog))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fxbSwap (set->numPrograms) > 0)
|
|
|
|
setCurrentProgram (oldProg);
|
|
|
|
|
|
|
|
const fxProgram* const prog = (const fxProgram*) (((const char*) (set->programs)) + oldProg * progLen);
|
|
|
|
if (((const char*) prog) - ((const char*) set) >= (ssize_t) dataSize)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (! restoreProgramSettings (prog))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (compareMagic (set->fxMagic, "FxCk"))
|
|
|
|
{
|
|
|
|
// single program
|
|
|
|
const fxProgram* const prog = (const fxProgram*) data;
|
|
|
|
|
|
|
|
if (! compareMagic (prog->chunkMagic, "CcnK"))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
changeProgramName (getCurrentProgram(), prog->prgName);
|
|
|
|
|
|
|
|
for (int i = 0; i < fxbSwap (prog->numParams); ++i)
|
|
|
|
setParameter (i, fxbSwapFloat (prog->params[i]));
|
|
|
|
}
|
|
|
|
else if (compareMagic (set->fxMagic, "FBCh"))
|
|
|
|
{
|
|
|
|
// non-preset chunk
|
|
|
|
const fxChunkSet* const cset = (const fxChunkSet*) data;
|
|
|
|
|
|
|
|
if ((size_t) fxbSwap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (size_t) dataSize)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
setStateInformation(cset->chunk, fxbSwap (cset->chunkSize));
|
|
|
|
}
|
|
|
|
else if (compareMagic (set->fxMagic, "FPCh"))
|
|
|
|
{
|
|
|
|
// preset chunk
|
|
|
|
const fxProgramSet* const cset = (const fxProgramSet*) data;
|
|
|
|
|
|
|
|
if ((size_t) fxbSwap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (size_t) dataSize)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
setCurrentProgramStateInformation(cset->chunk, fxbSwap (cset->chunkSize));
|
|
|
|
|
|
|
|
changeProgramName (getCurrentProgram(), cset->name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
currentBank = fxbFile.getFileName();
|
|
|
|
|
|
|
|
updateHostDisplay();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ObxdAudioProcessor::restoreProgramSettings(const fxProgram* const prog)
|
|
|
|
{
|
|
|
|
if (compareMagic (prog->chunkMagic, "CcnK")
|
|
|
|
&& compareMagic (prog->fxMagic, "FxCk"))
|
|
|
|
{
|
|
|
|
changeProgramName (getCurrentProgram(), prog->prgName);
|
|
|
|
|
|
|
|
for (int i = 0; i < fxbSwap (prog->numParams); ++i)
|
|
|
|
setParameter (i, fxbSwapFloat (prog->params[i]));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
void ObxdAudioProcessor::scanAndUpdateBanks()
|
|
|
|
{
|
|
|
|
bankFiles.clearQuick();
|
|
|
|
|
|
|
|
DirectoryIterator it(getBanksFolder(), false, "*.fxb", File::findFiles);
|
|
|
|
while (it.next())
|
|
|
|
{
|
2019-09-01 17:02:11 +00:00
|
|
|
bankFiles.addUsingDefaultSort(it.getFile());
|
2017-01-23 10:15:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const Array<File>& ObxdAudioProcessor::getBankFiles() const
|
|
|
|
{
|
|
|
|
return bankFiles;
|
|
|
|
}
|
|
|
|
|
|
|
|
File ObxdAudioProcessor::getCurrentBankFile() const
|
|
|
|
{
|
|
|
|
return getBanksFolder().getChildFile(currentBank);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
File ObxdAudioProcessor::getDocumentFolder() const
|
|
|
|
{
|
|
|
|
File folder = File::getSpecialLocation(File::userDocumentsDirectory).getChildFile("discoDSP").getChildFile("OB-Xd");
|
|
|
|
if (folder.isSymbolicLink())
|
|
|
|
folder = folder.getLinkedTarget();
|
|
|
|
return folder;
|
|
|
|
}
|
|
|
|
|
|
|
|
File ObxdAudioProcessor::getSkinFolder() const
|
|
|
|
{
|
|
|
|
return getDocumentFolder().getChildFile("Skins");
|
|
|
|
}
|
|
|
|
|
|
|
|
File ObxdAudioProcessor::getBanksFolder() const
|
|
|
|
{
|
|
|
|
return getDocumentFolder().getChildFile("Banks");
|
|
|
|
}
|
|
|
|
|
|
|
|
File ObxdAudioProcessor::getCurrentSkinFolder() const
|
|
|
|
{
|
|
|
|
return getSkinFolder().getChildFile(currentSkin);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObxdAudioProcessor::setCurrentSkinFolder(const String& folderName)
|
|
|
|
{
|
|
|
|
currentSkin = folderName;
|
|
|
|
|
|
|
|
config->setValue("skin", folderName);
|
|
|
|
config->setNeedsToBeSaved(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
// This creates new instances of the plugin..
|
|
|
|
AudioProcessor* JUCE_CALLTYPE createPluginFilter()
|
|
|
|
{
|
|
|
|
return new ObxdAudioProcessor();
|
|
|
|
}
|