diff --git a/Builds/MacOSX/juicysfplugin.xcodeproj/project.pbxproj b/Builds/MacOSX/juicysfplugin.xcodeproj/project.pbxproj index 02c0a02..54de6c0 100644 --- a/Builds/MacOSX/juicysfplugin.xcodeproj/project.pbxproj +++ b/Builds/MacOSX/juicysfplugin.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ 2918F46AFD2AB89F9FA847DC /* include_juce_events.mm in Sources */ = {isa = PBXBuildFile; fileRef = 373EF982A53046CE00BECE68 /* include_juce_events.mm */; }; 2E77C6FAF1BCDB9EB29D20B9 /* PluginProcessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D53CAB963D5051C786D3A52D /* PluginProcessor.cpp */; }; 305606C42BB0F2A12D382D34 /* SoundfontSynthVoice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B5A057FEC371053E83A73E47 /* SoundfontSynthVoice.cpp */; }; + 35099D9322CAA87D00CD4523 /* Params.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35099D9122CAA87D00CD4523 /* Params.cpp */; }; 358E458C22BEE5090087ED8D /* RecentFilesMenuTemplate.nib in Resources */ = {isa = PBXBuildFile; fileRef = 78CC5234CCFE3B170585DDAD /* RecentFilesMenuTemplate.nib */; }; 358E458D22BEE5090087ED8D /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1616112041466F7324D7E19 /* Accelerate.framework */; }; 358E458E22BEE5090087ED8D /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28CA077CDD21D0FEC66FC290 /* AudioToolbox.framework */; }; @@ -285,6 +286,11 @@ 2C66D01D1DD9006E77E2E260 /* include_juce_data_structures.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_data_structures.mm; path = ../../JuceLibraryCode/include_juce_data_structures.mm; sourceTree = SOURCE_ROOT; }; 307CB49DF900DE4A612FF98E /* FluidSynthModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FluidSynthModel.h; path = ../../Source/FluidSynthModel.h; sourceTree = SOURCE_ROOT; }; 35099D9022CA8EF500CD4523 /* Util.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Util.h; path = ../../Source/Util.h; sourceTree = ""; }; + 35099D9122CAA87D00CD4523 /* Params.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Params.cpp; path = ../../Source/Params.cpp; sourceTree = ""; }; + 35099D9222CAA87D00CD4523 /* Params.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Params.h; path = ../../Source/Params.h; sourceTree = ""; }; + 35099D9422CAB0A400CD4523 /* GuiConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GuiConstants.h; path = ../../Source/GuiConstants.h; sourceTree = ""; }; + 35099D9522CAB7CD00CD4523 /* SlidersFragment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SlidersFragment.h; path = ../../Source/SlidersFragment.h; sourceTree = ""; }; + 35099D9622CAC3C800CD4523 /* SharesParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharesParams.h; path = ../../Source/SharesParams.h; sourceTree = ""; }; 35880F58CB540AD30D1B0ED3 /* TablesComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TablesComponent.h; path = ../../Source/TablesComponent.h; sourceTree = SOURCE_ROOT; }; 358E45B422BEE53A0087ED8D /* libpcre.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libpcre.1.dylib; sourceTree = ""; }; 358E45B522BEE53A0087ED8D /* libvorbisenc.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libvorbisenc.2.dylib; sourceTree = ""; }; @@ -521,6 +527,7 @@ 403EB0CF49CF1D62BF359002 /* Source */ = { isa = PBXGroup; children = ( + 35099D9622CAC3C800CD4523 /* SharesParams.h */, DECFA95359BC1DDDD1CC86C3 /* BankAndPreset.cpp */, B000E7A360C0C86ADD3C911D /* BankAndPreset.h */, F1EB35E262DC717222E2F93D /* ExposesComponents.h */, @@ -554,6 +561,10 @@ 358E45F922C80DCA0087ED8D /* SlidersComponent.cpp */, 358E45FA22C80DCA0087ED8D /* SlidersComponent.h */, 35099D9022CA8EF500CD4523 /* Util.h */, + 35099D9122CAA87D00CD4523 /* Params.cpp */, + 35099D9222CAA87D00CD4523 /* Params.h */, + 35099D9422CAB0A400CD4523 /* GuiConstants.h */, + 35099D9522CAB7CD00CD4523 /* SlidersFragment.h */, ); name = Source; sourceTree = ""; @@ -951,6 +962,7 @@ 7DF73014FFCCE46E228216DB /* PluginEditor.cpp in Sources */, E08B3A2AF85F9FCF991F1CA2 /* include_juce_audio_basics.mm in Sources */, C4D76C968347E2ACBAB5B6E7 /* include_juce_audio_devices.mm in Sources */, + 35099D9322CAA87D00CD4523 /* Params.cpp in Sources */, 51C9DBCA840E334DB1804133 /* include_juce_audio_formats.mm in Sources */, 358E45FB22C80DCA0087ED8D /* SlidersComponent.cpp in Sources */, 5E5B833BBDD65F0D4271CA52 /* include_juce_audio_plugin_client_utils.cpp in Sources */, diff --git a/Source/ExposesComponents.h b/Source/ExposesComponents.h index c42d193..b0dda84 100644 --- a/Source/ExposesComponents.h +++ b/Source/ExposesComponents.h @@ -6,11 +6,13 @@ #pragma once #include "FilePickerFragment.h" +#include "SlidersFragment.h" class ExposesComponents { public: virtual ~ExposesComponents() {} virtual FilePickerFragment& getFilePicker() = 0; + virtual SlidersFragment& getSliders() = 0; }; \ No newline at end of file diff --git a/Source/FluidSynthModel.cpp b/Source/FluidSynthModel.cpp index 40bddf3..085323f 100644 --- a/Source/FluidSynthModel.cpp +++ b/Source/FluidSynthModel.cpp @@ -8,15 +8,15 @@ using namespace std; -FluidSynthModel::FluidSynthModel(SharesParams& p) - : sharesParams(p), - synth(nullptr), - settings(nullptr), - currentSoundFontAbsPath(), - currentSampleRate(44100), - initialised(false), - sfont_id(0), - channel(0)/*, +FluidSynthModel::FluidSynthModel(shared_ptr sharedParams) + : sharedParams{sharedParams}, + synth{nullptr}, + settings{nullptr}, + currentSoundFontAbsPath{}, + currentSampleRate{44100}, + initialised{false}, + sfont_id{0}, + channel{0}/*, mod(nullptr)*/ {} @@ -51,9 +51,9 @@ void FluidSynthModel::initialise() { synth = new_fluid_synth(settings); fluid_synth_set_sample_rate(synth, currentSampleRate); - if (sharesParams.getSoundFontPath().isNotEmpty()) { - loadFont(sharesParams.getSoundFontPath()); - changePreset(sharesParams.getBank(), sharesParams.getPreset()); + if (sharedParams->getSoundFontPath().isNotEmpty()) { + loadFont(sharedParams->getSoundFontPath()); + changePreset(sharedParams->getBank(), sharedParams->getPreset()); } fluid_synth_set_gain(synth, 2.0); @@ -189,8 +189,8 @@ void FluidSynthModel::changePreset(int bank, int preset) { preset = bankAndPreset->getPreset(); } changePresetImpl(bank, preset); - sharesParams.setPreset(preset); - sharesParams.setBank(bank); + sharedParams->setPreset(preset); + sharedParams->setBank(bank); } void FluidSynthModel::changePresetImpl(int bank, int preset) { @@ -272,7 +272,7 @@ void FluidSynthModel::onFileNameChanged(const String &absPath, int bank, int pre } unloadAndLoadFont(absPath); changePreset(bank, preset); - sharesParams.setSoundFontPath(absPath); + sharedParams->setSoundFontPath(absPath); eventListeners.call(&FluidSynthModel::Listener::fontChanged, this, absPath); } diff --git a/Source/FluidSynthModel.h b/Source/FluidSynthModel.h index a630cdf..7785306 100644 --- a/Source/FluidSynthModel.h +++ b/Source/FluidSynthModel.h @@ -19,7 +19,7 @@ using namespace std; class FluidSynthModel { public: - FluidSynthModel(SharesParams& p); + FluidSynthModel(shared_ptr sharedParams); ~FluidSynthModel(); fluid_synth_t* getSynth(); @@ -65,7 +65,7 @@ public: const String& getCurrentSoundFontAbsPath(); private: - SharesParams& sharesParams; + shared_ptr sharedParams; fluid_synth_t* synth; fluid_settings_t* settings; diff --git a/Source/GuiConstants.h b/Source/GuiConstants.h new file mode 100644 index 0000000..8223443 --- /dev/null +++ b/Source/GuiConstants.h @@ -0,0 +1,8 @@ +#pragma once + +struct GuiConstants { + inline static const int minWidth = 500; + inline static const int maxWidth = 1900; + inline static const int minHeight = 300; + inline static const int maxHeight = 1000; +}; diff --git a/Source/MidiConstants.h b/Source/MidiConstants.h index f31a69a..68617f2 100644 --- a/Source/MidiConstants.h +++ b/Source/MidiConstants.h @@ -162,3 +162,8 @@ enum fluid_midi_control_change - for case (2) or (3), FLUID_NOISE_FLOOR should be the noise floor for 16 bits (i.e -90 dB). */ #define FLUID_PEAK_ATTENUATION 960.0f + +struct MidiConstants { + inline static const int midiMinValue = 0; + inline static const int midiMaxValue = 127; +}; diff --git a/Source/Params.cpp b/Source/Params.cpp new file mode 100644 index 0000000..a29b722 --- /dev/null +++ b/Source/Params.cpp @@ -0,0 +1,152 @@ +// +// Params.cpp +// juicysfplugin - Shared Code +// +// Created by Alex Birch on 01/07/2019. +// Copyright © 2019 Birchlabs. All rights reserved. +// + +#include "Params.h" +#include "../JuceLibraryCode/JuceHeader.h" +#include "MidiConstants.h" +#include "GuiConstants.h" +#include "SharesParams.h" + +using namespace std; + +Params::Params() noexcept : + uiWidth{GuiConstants::minWidth}, + uiHeight{GuiConstants::minHeight}, + soundFontPath{String()}, + preset{-1}, + bank{-1}, + attack{0}, + decay{0}, + sustain{0}, + release{0}, + filterCutOff{0}, + filterResonance{0} +{ +} + +void Params::setAttributesOnXml(XmlElement& xml) { + xml.setAttribute("uiWidth", uiWidth); + xml.setAttribute("uiHeight", uiHeight); + xml.setAttribute("soundFontPath", soundFontPath); + xml.setAttribute("preset", preset); + xml.setAttribute("bank", bank); + xml.setAttribute("attack", attack); + xml.setAttribute("decay", decay); + xml.setAttribute("sustain", sustain); + xml.setAttribute("release", release); + xml.setAttribute("filterCutOff", filterCutOff); + xml.setAttribute("filterResonance", filterResonance); +} + +void Params::loadAttributesFromXml(shared_ptr xmlState) { + uiWidth = jmin(jmax(xmlState->getIntAttribute("uiWidth", uiWidth), GuiConstants::minWidth), GuiConstants::maxWidth); + uiHeight = jmin(jmax(xmlState->getIntAttribute("uiHeight", uiHeight), GuiConstants::minHeight), GuiConstants::maxHeight); + soundFontPath = xmlState->getStringAttribute("soundFontPath", soundFontPath); + preset = xmlState->getIntAttribute("preset", preset); + bank = xmlState->getIntAttribute("bank", bank); + attack = jmin(jmax(xmlState->getIntAttribute("attack", attack), MidiConstants::midiMinValue), MidiConstants::midiMaxValue); + decay = jmin(jmax(xmlState->getIntAttribute("decay", decay), MidiConstants::midiMinValue), MidiConstants::midiMaxValue); + sustain = jmin(jmax(xmlState->getIntAttribute("sustain", sustain), MidiConstants::midiMinValue), MidiConstants::midiMaxValue); + release = jmin(jmax(xmlState->getIntAttribute("release", release), MidiConstants::midiMinValue), MidiConstants::midiMaxValue); + filterCutOff = jmin(jmax(xmlState->getIntAttribute("filterCutOff", filterCutOff), MidiConstants::midiMinValue), MidiConstants::midiMaxValue); + filterResonance = jmin(jmax(xmlState->getIntAttribute("filterResonance", filterResonance), MidiConstants::midiMinValue), MidiConstants::midiMaxValue); +} + +void Params::acceptMidiControlEvent(int controller, int value) { + switch(static_cast(controller)) { + case SOUND_CTRL2: // MIDI CC 71 Timbre/Harmonic Intensity (filter resonance) + filterResonance = value; + break; + case SOUND_CTRL3: // MIDI CC 72 Release time + release = value; + break; + case SOUND_CTRL4: // MIDI CC 73 Attack time + attack = value; + break; + case SOUND_CTRL5: // MIDI CC 74 Brightness (cutoff frequency, FILTERFC) + filterCutOff = value; + break; + case SOUND_CTRL6: // MIDI CC 75 Decay Time + decay = value; + break; + case SOUND_CTRL10: // MIDI CC 79 undefined + sustain = value; + break; + default: + break; + } +} + +void Params::setSoundFontPath(const String& value) { + soundFontPath = value; +} + +String& Params::getSoundFontPath() { + return soundFontPath; +} +int Params::getPreset() { + return preset; +} +int Params::getBank() { + return bank; +} +int Params::getUiWidth() { + return uiWidth; +} +int Params::getUiHeight() { + return uiHeight; +} +int Params::getAttack() { + return attack; +} +int Params::getDecay() { + return decay; +} +int Params::getSustain() { + return sustain; +} +int Params::getRelease() { + return release; +} +int Params::getFilterCutOff() { + return filterCutOff; +} +int Params::getFilterResonance() { + return filterResonance; +} + +void Params::setPreset(int value) { + preset = value; +} +void Params::setBank(int value) { + bank = value; +} +void Params::setUiWidth(int value) { + uiWidth = value; +} +void Params::setUiHeight(int value) { + uiHeight = value; +} +void Params::setAttack(int value) { + attack = value; +} +void Params::setDecay(int value) { + decay = value; +} +void Params::setSustain(int value) { + sustain = value; +} +void Params::setRelease(int value) { + release = value; +} +void Params::setFilterCutOff(int value) { + filterCutOff = value; +} +void Params::setFilterResonance(int value) { + filterResonance = value; +} diff --git a/Source/Params.h b/Source/Params.h new file mode 100644 index 0000000..e6979f4 --- /dev/null +++ b/Source/Params.h @@ -0,0 +1,59 @@ +#pragma once + +#include "SharesParams.h" +#include "../JuceLibraryCode/JuceHeader.h" + +using namespace std; + +class Params: public SharesParams { +public: + Params() noexcept; + + virtual void setAttributesOnXml(XmlElement& xml) override; + virtual void loadAttributesFromXml(shared_ptr xmlState) override; + virtual void acceptMidiControlEvent(int controller, int value) override; + + virtual void setSoundFontPath(const String& value) override; + virtual String& getSoundFontPath() override; + virtual int getPreset() override; + virtual void setPreset(int value) override; + virtual int getBank() override; + virtual void setBank(int value) override; + + virtual int getUiWidth() override; + virtual void setUiWidth(int value) override; + virtual int getUiHeight() override; + virtual void setUiHeight(int value) override; + + virtual int getAttack() override; + virtual void setAttack(int value) override; + virtual int getDecay() override; + virtual void setDecay(int value) override; + virtual int getSustain() override; + virtual void setSustain(int value) override; + virtual int getRelease() override; + virtual void setRelease(int value) override; + + virtual int getFilterCutOff() override; + virtual void setFilterCutOff(int value) override; + virtual int getFilterResonance() override; + virtual void setFilterResonance(int value) override; + +private: + int uiWidth; + int uiHeight; + + String soundFontPath; + int preset; + int bank; + + int attack; + int decay; + int sustain; + int release; + + int filterCutOff; + int filterResonance; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Params) +}; diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index 8edc3c4..8283425 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -10,20 +10,26 @@ #include "PluginProcessor.h" #include "PluginEditor.h" +#include "GuiConstants.h" //============================================================================== -JuicySFAudioProcessorEditor::JuicySFAudioProcessorEditor (JuicySFAudioProcessor& p) - : AudioProcessorEditor (&p), - processor (p), - midiKeyboard (p.keyboardState, SurjectiveMidiKeyboardComponent::horizontalKeyboard), - tablesComponent(p.getFluidSynthModel()), - filePicker(p.getFluidSynthModel()), - slidersComponent{p.getFluidSynthModel()} +JuicySFAudioProcessorEditor::JuicySFAudioProcessorEditor(JuicySFAudioProcessor& p) + : AudioProcessorEditor{&p}, + processor{p}, + sharedParams{p.sharedParams}, + midiKeyboard{p.keyboardState, SurjectiveMidiKeyboardComponent::horizontalKeyboard}, + tablesComponent{p.getFluidSynthModel()}, + filePicker{p.getFluidSynthModel()}, + slidersComponent{p.sharedParams, p.getFluidSynthModel()} { // set resize limits for this plug-in - setResizeLimits (500, 300, 1900, 1000); + setResizeLimits( + GuiConstants::minWidth, + GuiConstants::minHeight, + GuiConstants::maxWidth, + GuiConstants::maxHeight); - setSize (p.lastUIWidth, p.lastUIHeight); + setSize(sharedParams->getUiWidth(), sharedParams->getUiHeight()); // processor.subscribeToStateChanges(this); @@ -97,9 +103,8 @@ void JuicySFAudioProcessorEditor::resized() tablesComponent.setBounds(rContent); - - processor.lastUIWidth = getWidth(); - processor.lastUIHeight = getHeight(); + sharedParams->setUiWidth(getWidth()); + sharedParams->setUiHeight(getHeight()); // Rectangle r2 (getLocalBounds()); // r2.reduce(0, padding); @@ -150,4 +155,8 @@ bool JuicySFAudioProcessorEditor::keyStateChanged (bool isKeyDown) { FilePickerFragment& JuicySFAudioProcessorEditor::getFilePicker() { return filePicker; +} + +SlidersFragment& JuicySFAudioProcessorEditor::getSliders() { + return slidersComponent; } \ No newline at end of file diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index d0da863..a242cb7 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -42,12 +42,15 @@ public: // void setStateInformation (XmlElement* xmlState) override; virtual FilePickerFragment& getFilePicker() override; + virtual SlidersFragment& getSliders() override; private: // This reference is provided as a quick way for your editor to // access the processor object that created it. JuicySFAudioProcessor& processor; + shared_ptr sharedParams; + SurjectiveMidiKeyboardComponent midiKeyboard; TablesComponent tablesComponent; FilePicker filePicker; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 61f1736..ba3d357 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -15,19 +15,20 @@ #include "ExposesComponents.h" #include "MidiConstants.h" #include "Util.h" +#include "SharesParams.h" +#include "Params.h" + +using namespace std; AudioProcessor* JUCE_CALLTYPE createPluginFilter(); //============================================================================== JuicySFAudioProcessor::JuicySFAudioProcessor() - : AudioProcessor (getBusesProperties()), - lastUIWidth(400), - lastUIHeight(300), - soundFontPath(String()), - lastPreset(-1), - lastBank(-1), - fluidSynthModel(*this)/*, + : AudioProcessor{getBusesProperties()}, + sharedParams{static_pointer_cast(make_shared())}, + fluidSynthModel{sharedParams}/*, + fluidSynthModel{*this}, pluginEditor(nullptr)*/ { initialiseSynth(); @@ -47,10 +48,10 @@ void JuicySFAudioProcessor::initialiseSynth() { // Add some voices... for (int i = numVoices; --i >= 0;) - synth.addVoice (new SoundfontSynthVoice(fluidSynthModel.getSynth())); + synth.addVoice(new SoundfontSynthVoice(fluidSynthModel.getSynth())); // ..and give the synth a sound to play - synth.addSound (new SoundfontSynthSound()); + synth.addSound(new SoundfontSynthSound()); } //============================================================================== @@ -168,6 +169,11 @@ void JuicySFAudioProcessor::processBlock (AudioBuffer& buffer, MidiBuffer // responsibilities of SoundfontSynthVoice. // well, by that logic maybe I should move program change onto Voice. but it doesn't feel like a per-voice concern. if (m.isController()) { + // shared_ptr midi_event{ + // new_fluid_midi_event(), + // [](fluid_midi_event_t *event) { + // delete_fluid_midi_event(midi_event); + // }}; fluid_midi_event_t *midi_event(new_fluid_midi_event()); fluid_midi_event_set_type(midi_event, static_cast(CONTROL_CHANGE)); fluid_midi_event_set_channel(midi_event, fluidSynthModel.getChannel()); @@ -175,6 +181,13 @@ void JuicySFAudioProcessor::processBlock (AudioBuffer& buffer, MidiBuffer fluid_midi_event_set_value(midi_event, m.getControllerValue()); fluid_synth_handle_midi_event(fluidSynth, midi_event); delete_fluid_midi_event(midi_event); + + sharedParams->acceptMidiControlEvent(m.getControllerNumber(), m.getControllerValue()); + + AudioProcessorEditor* editor{getActiveEditor()}; + jassert(dynamic_cast (editor) != nullptr); + ExposesComponents* exposesComponents{dynamic_cast(editor)}; + exposesComponents->getSliders().acceptMidiControlEvent(m.getControllerNumber(), m.getControllerValue()); } else if (m.isProgramChange()) { fluid_midi_event_t *midi_event(new_fluid_midi_event()); fluid_midi_event_set_type(midi_event, static_cast(PROGRAM_CHANGE)); @@ -266,14 +279,8 @@ void JuicySFAudioProcessor::getStateInformation (MemoryBlock& destData) // as intermediaries to make it easy to save and load complex data. // Create an outer XML element.. - XmlElement xml ("MYPLUGINSETTINGS"); - - // add some attributes to it.. - xml.setAttribute ("uiWidth", lastUIWidth); - xml.setAttribute ("uiHeight", lastUIHeight); - xml.setAttribute ("soundFontPath", soundFontPath); - xml.setAttribute ("preset", lastPreset); - xml.setAttribute ("bank", lastBank); + XmlElement xml{"MYPLUGINSETTINGS"}; + sharedParams->setAttributesOnXml(xml); // list::iterator p; // for(p = stateChangeSubscribers.begin(); p != stateChangeSubscribers.end(); p++) { @@ -294,7 +301,7 @@ void JuicySFAudioProcessor::setStateInformation (const void* data, int sizeInByt // You should use this method to restore your parameters from this memory block, // whose contents will have been created by the getStateInformation() call. // This getXmlFromBinary() helper function retrieves our XML from the binary blob.. - ScopedPointer xmlState (getXmlFromBinary (data, sizeInBytes)); + shared_ptr xmlState{getXmlFromBinary(data, sizeInBytes)}; if (xmlState != nullptr) { @@ -307,26 +314,27 @@ void JuicySFAudioProcessor::setStateInformation (const void* data, int sizeInByt // } // ok, now pull out our last window size.. - lastUIWidth = jmax (xmlState->getIntAttribute ("uiWidth", lastUIWidth), 400); - lastUIHeight = jmax (xmlState->getIntAttribute ("uiHeight", lastUIHeight), 300); - soundFontPath = xmlState->getStringAttribute ("soundFontPath", soundFontPath); - lastPreset = xmlState->getIntAttribute ("preset", lastPreset); - lastBank = xmlState->getIntAttribute ("bank", lastBank); + sharedParams->loadAttributesFromXml(xmlState); // Now reload our parameters.. for (auto* param : getParameters()) if (auto* p = dynamic_cast (param)) p->setValue ((float) xmlState->getDoubleAttribute (p->paramID, p->getValue())); - fluidSynthModel.onFileNameChanged(soundFontPath, lastBank, lastPreset); + fluidSynthModel.onFileNameChanged( + sharedParams->getSoundFontPath(), + sharedParams->getBank(), + sharedParams->getPreset()); - AudioProcessorEditor* editor = getActiveEditor(); + AudioProcessorEditor* editor{getActiveEditor()}; if (editor != nullptr) { - editor->setSize(lastUIWidth, lastUIHeight); + editor->setSize( + sharedParams->getUiWidth(), + sharedParams->getUiHeight()); jassert(dynamic_cast (editor) != nullptr); ExposesComponents* exposesComponents = dynamic_cast (editor); - exposesComponents->getFilePicker().setDisplayedFilePath(soundFontPath); + exposesComponents->getFilePicker().setDisplayedFilePath(sharedParams->getSoundFontPath()); } // const String& currentSoundFontAbsPath = fluidSynthModel->getCurrentSoundFontAbsPath(); @@ -354,26 +362,6 @@ FluidSynthModel* JuicySFAudioProcessor::getFluidSynthModel() { return &fluidSynthModel; } -void JuicySFAudioProcessor::setSoundFontPath(const String& value) { - soundFontPath = value; -} - -String& JuicySFAudioProcessor::getSoundFontPath() { - return soundFontPath; -} -int JuicySFAudioProcessor::getPreset() { - return lastPreset; -} -int JuicySFAudioProcessor::getBank() { - return lastBank; -} -void JuicySFAudioProcessor::setPreset(int preset) { - lastPreset = preset; -} -void JuicySFAudioProcessor::setBank(int bank) { - lastBank = bank; -} - //============================================================================== // This creates new instances of the plugin.. AudioProcessor* JUCE_CALLTYPE createPluginFilter() diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 8d60769..5aee38f 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -21,8 +21,7 @@ using namespace std; //============================================================================== /** */ -class JuicySFAudioProcessor : public AudioProcessor, - public SharesParams +class JuicySFAudioProcessor : public AudioProcessor { public: //============================================================================== @@ -67,25 +66,14 @@ public: MidiKeyboardState keyboardState; - virtual void setSoundFontPath(const String& value) override; - virtual String& getSoundFontPath() override; - virtual int getPreset() override; - virtual void setPreset(int preset) override; - virtual int getBank() override; - virtual void setBank(int bank) override; + shared_ptr sharedParams; // void subscribeToStateChanges(StateChangeSubscriber* subscriber); // void unsubscribeFromStateChanges(StateChangeSubscriber* subscriber); - int lastUIWidth, lastUIHeight; - private: void initialiseSynth(); - String soundFontPath; - int lastPreset; - int lastBank; - FluidSynthModel fluidSynthModel; fluid_synth_t* fluidSynth; Synthesiser synth; diff --git a/Source/SharesParams.h b/Source/SharesParams.h index 7cae325..1f25d0b 100644 --- a/Source/SharesParams.h +++ b/Source/SharesParams.h @@ -7,16 +7,42 @@ #include "../JuceLibraryCode/JuceHeader.h" +using namespace std; + class SharesParams { public: virtual ~SharesParams() {} + virtual void setAttributesOnXml(XmlElement& xml) = 0; + virtual void loadAttributesFromXml(shared_ptr xmlState) = 0; + virtual void acceptMidiControlEvent(int controller, int value) = 0; + virtual void setSoundFontPath(const String& value) = 0; virtual String& getSoundFontPath() = 0; virtual int getPreset() = 0; - virtual void setPreset(int preset) = 0; + virtual void setPreset(int value) = 0; virtual int getBank() = 0; - virtual void setBank(int bank) = 0; + virtual void setBank(int value) = 0; + + virtual int getUiWidth() = 0; + virtual void setUiWidth(int value) = 0; + virtual int getUiHeight() = 0; + virtual void setUiHeight(int value) = 0; + + virtual int getAttack() = 0; + virtual void setAttack(int value) = 0; + virtual int getDecay() = 0; + virtual void setDecay(int value) = 0; + virtual int getSustain() = 0; + virtual void setSustain(int value) = 0; + virtual int getRelease() = 0; + virtual void setRelease(int value) = 0; + + virtual int getFilterCutOff() = 0; + virtual void setFilterCutOff(int value) = 0; + virtual int getFilterResonance() = 0; + virtual void setFilterResonance(int value) = 0; + }; diff --git a/Source/SlidersComponent.cpp b/Source/SlidersComponent.cpp index 4d008d5..1fa4325 100644 --- a/Source/SlidersComponent.cpp +++ b/Source/SlidersComponent.cpp @@ -10,10 +10,11 @@ #include "FluidSynthModel.h" #include "MidiConstants.h" -std::function SlidersComponent::makeSliderListener(Slider& slider, int controller) { +std::function SlidersComponent::makeSliderListener(Slider& slider, int controller/*, std::function callback*/) { return [this, controller, &slider]{ // slider.setValue(slider.getValue(), NotificationType::dontSendNotification); fluidSynthModel->setControllerValue(controller, slider.getValue()); + // callback(); }; } @@ -58,7 +59,54 @@ void SlidersComponent::resized() { filterResonanceSlider.setBounds(rFilter.removeFromLeft(sliderWidth + sliderXMargin).withTrimmedTop(labelHeight).withTrimmedLeft(sliderXMargin)); } -SlidersComponent::SlidersComponent(FluidSynthModel* fluidSynthModel) : +void SlidersComponent::acceptMidiControlEvent(int controller, int value) { + switch(static_cast(controller)) { + case SOUND_CTRL2: // MIDI CC 71 Timbre/Harmonic Intensity (filter resonance) + filterResonanceSlider.setValue(value, NotificationType::dontSendNotification); + break; + case SOUND_CTRL3: // MIDI CC 72 Release time + releaseSlider.setValue(value, NotificationType::dontSendNotification); + break; + case SOUND_CTRL4: // MIDI CC 73 Attack time + attackSlider.setValue(value, NotificationType::dontSendNotification); + break; + case SOUND_CTRL5: // MIDI CC 74 Brightness (cutoff frequency, FILTERFC) + filterCutOffSlider.setValue(value, NotificationType::dontSendNotification); + break; + case SOUND_CTRL6: // MIDI CC 75 Decay Time + decaySlider.setValue(value, NotificationType::dontSendNotification); + break; + case SOUND_CTRL10: // MIDI CC 79 undefined + sustainSlider.setValue(value, NotificationType::dontSendNotification); + break; + default: + break; + } +} + +// void SlidersComponent::updateAttackSlider(int value) { +// attackSlider.setValue(value, NotificationType::dontSendNotification); +// } +// void SlidersComponent::updateDecaySlider(int value) { +// decaySlider.setValue(value, NotificationType::dontSendNotification); +// } +// void SlidersComponent::updateSustainSlider(int value) { +// sustainSlider.setValue(value, NotificationType::dontSendNotification); +// } +// void SlidersComponent::updateReleaseSlider(int value) { +// releaseSlider.setValue(value, NotificationType::dontSendNotification); +// } +// void SlidersComponent::updateFilterCutOffSlider(int value) { +// filterCutOffSlider.setValue(value, NotificationType::dontSendNotification); +// } +// void SlidersComponent::updateFilterResonanceSlider(int value) { +// filterResonanceSlider.setValue(value, NotificationType::dontSendNotification); +// } + +SlidersComponent::SlidersComponent( + shared_ptr sharedParams, + FluidSynthModel* fluidSynthModel) : +sharedParams{sharedParams}, fluidSynthModel{fluidSynthModel}, envelopeGroup{"envelopeGroup", "Envelope"}, filterGroup{"filterGroup", "Filter"} diff --git a/Source/SlidersComponent.h b/Source/SlidersComponent.h index ede78d3..97dfeeb 100644 --- a/Source/SlidersComponent.h +++ b/Source/SlidersComponent.h @@ -2,22 +2,38 @@ #include "../JuceLibraryCode/JuceHeader.h" #include "FluidSynthModel.h" +#include "SharesParams.h" +#include "SlidersFragment.h" using namespace std; -class SlidersComponent : public Component +class SlidersComponent : public Component, + public SlidersFragment { public: - SlidersComponent(FluidSynthModel* fluidSynthModel); + SlidersComponent( + shared_ptr sharedParams, + FluidSynthModel* fluidSynthModel); ~SlidersComponent(); void resized() override; const int getDesiredWidth(); + virtual void acceptMidiControlEvent(int controller, int value) override; + + // virtual void updateAttackSlider(int value) override; + // virtual void updateDecaySlider(int value) override; + // virtual void updateSustainSlider(int value) override; + // virtual void updateReleaseSlider(int value) override; + + // virtual void updateFilterCutOffSlider(int value) override; + // virtual void updateFilterResonanceSlider(int value) override; + private: std::function makeSliderListener(Slider& slider, int controller); + shared_ptr sharedParams; FluidSynthModel* fluidSynthModel; GroupComponent envelopeGroup; diff --git a/Source/SlidersFragment.h b/Source/SlidersFragment.h new file mode 100644 index 0000000..255dbe1 --- /dev/null +++ b/Source/SlidersFragment.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../JuceLibraryCode/JuceHeader.h" + +class SlidersFragment { +public: + virtual ~SlidersFragment() {} + + virtual void acceptMidiControlEvent(int controller, int value) = 0; + + // virtual void updateAttackSlider(int value) = 0; + // virtual void updateDecaySlider(int value) = 0; + // virtual void updateSustainSlider(int value) = 0; + // virtual void updateReleaseSlider(int value) = 0; + + // virtual void updateFilterCutOffSlider(int value) = 0; + // virtual void updateFilterResonanceSlider(int value) = 0; +};