encapsulate responsibility of params. add params for ADSR and filter. attempt to sync Slider. not obviously working yet.

This commit is contained in:
Alex Birch 2019-07-01 23:55:14 +01:00
parent 758dda40a9
commit 218beb00e7
No known key found for this signature in database
GPG Key ID: 305EB1F98D44ACBA
16 changed files with 430 additions and 96 deletions

View File

@ -34,6 +34,7 @@
2918F46AFD2AB89F9FA847DC /* include_juce_events.mm in Sources */ = {isa = PBXBuildFile; fileRef = 373EF982A53046CE00BECE68 /* include_juce_events.mm */; }; 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 */; }; 2E77C6FAF1BCDB9EB29D20B9 /* PluginProcessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D53CAB963D5051C786D3A52D /* PluginProcessor.cpp */; };
305606C42BB0F2A12D382D34 /* SoundfontSynthVoice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B5A057FEC371053E83A73E47 /* SoundfontSynthVoice.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 */; }; 358E458C22BEE5090087ED8D /* RecentFilesMenuTemplate.nib in Resources */ = {isa = PBXBuildFile; fileRef = 78CC5234CCFE3B170585DDAD /* RecentFilesMenuTemplate.nib */; };
358E458D22BEE5090087ED8D /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1616112041466F7324D7E19 /* Accelerate.framework */; }; 358E458D22BEE5090087ED8D /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1616112041466F7324D7E19 /* Accelerate.framework */; };
358E458E22BEE5090087ED8D /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28CA077CDD21D0FEC66FC290 /* AudioToolbox.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; }; 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; }; 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 = "<group>"; }; 35099D9022CA8EF500CD4523 /* Util.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Util.h; path = ../../Source/Util.h; sourceTree = "<group>"; };
35099D9122CAA87D00CD4523 /* Params.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Params.cpp; path = ../../Source/Params.cpp; sourceTree = "<group>"; };
35099D9222CAA87D00CD4523 /* Params.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Params.h; path = ../../Source/Params.h; sourceTree = "<group>"; };
35099D9422CAB0A400CD4523 /* GuiConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GuiConstants.h; path = ../../Source/GuiConstants.h; sourceTree = "<group>"; };
35099D9522CAB7CD00CD4523 /* SlidersFragment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SlidersFragment.h; path = ../../Source/SlidersFragment.h; sourceTree = "<group>"; };
35099D9622CAC3C800CD4523 /* SharesParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharesParams.h; path = ../../Source/SharesParams.h; sourceTree = "<group>"; };
35880F58CB540AD30D1B0ED3 /* TablesComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TablesComponent.h; path = ../../Source/TablesComponent.h; sourceTree = SOURCE_ROOT; }; 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 = "<group>"; }; 358E45B422BEE53A0087ED8D /* libpcre.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libpcre.1.dylib; sourceTree = "<group>"; };
358E45B522BEE53A0087ED8D /* libvorbisenc.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libvorbisenc.2.dylib; sourceTree = "<group>"; }; 358E45B522BEE53A0087ED8D /* libvorbisenc.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libvorbisenc.2.dylib; sourceTree = "<group>"; };
@ -521,6 +527,7 @@
403EB0CF49CF1D62BF359002 /* Source */ = { 403EB0CF49CF1D62BF359002 /* Source */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
35099D9622CAC3C800CD4523 /* SharesParams.h */,
DECFA95359BC1DDDD1CC86C3 /* BankAndPreset.cpp */, DECFA95359BC1DDDD1CC86C3 /* BankAndPreset.cpp */,
B000E7A360C0C86ADD3C911D /* BankAndPreset.h */, B000E7A360C0C86ADD3C911D /* BankAndPreset.h */,
F1EB35E262DC717222E2F93D /* ExposesComponents.h */, F1EB35E262DC717222E2F93D /* ExposesComponents.h */,
@ -554,6 +561,10 @@
358E45F922C80DCA0087ED8D /* SlidersComponent.cpp */, 358E45F922C80DCA0087ED8D /* SlidersComponent.cpp */,
358E45FA22C80DCA0087ED8D /* SlidersComponent.h */, 358E45FA22C80DCA0087ED8D /* SlidersComponent.h */,
35099D9022CA8EF500CD4523 /* Util.h */, 35099D9022CA8EF500CD4523 /* Util.h */,
35099D9122CAA87D00CD4523 /* Params.cpp */,
35099D9222CAA87D00CD4523 /* Params.h */,
35099D9422CAB0A400CD4523 /* GuiConstants.h */,
35099D9522CAB7CD00CD4523 /* SlidersFragment.h */,
); );
name = Source; name = Source;
sourceTree = "<group>"; sourceTree = "<group>";
@ -951,6 +962,7 @@
7DF73014FFCCE46E228216DB /* PluginEditor.cpp in Sources */, 7DF73014FFCCE46E228216DB /* PluginEditor.cpp in Sources */,
E08B3A2AF85F9FCF991F1CA2 /* include_juce_audio_basics.mm in Sources */, E08B3A2AF85F9FCF991F1CA2 /* include_juce_audio_basics.mm in Sources */,
C4D76C968347E2ACBAB5B6E7 /* include_juce_audio_devices.mm in Sources */, C4D76C968347E2ACBAB5B6E7 /* include_juce_audio_devices.mm in Sources */,
35099D9322CAA87D00CD4523 /* Params.cpp in Sources */,
51C9DBCA840E334DB1804133 /* include_juce_audio_formats.mm in Sources */, 51C9DBCA840E334DB1804133 /* include_juce_audio_formats.mm in Sources */,
358E45FB22C80DCA0087ED8D /* SlidersComponent.cpp in Sources */, 358E45FB22C80DCA0087ED8D /* SlidersComponent.cpp in Sources */,
5E5B833BBDD65F0D4271CA52 /* include_juce_audio_plugin_client_utils.cpp in Sources */, 5E5B833BBDD65F0D4271CA52 /* include_juce_audio_plugin_client_utils.cpp in Sources */,

View File

@ -6,11 +6,13 @@
#pragma once #pragma once
#include "FilePickerFragment.h" #include "FilePickerFragment.h"
#include "SlidersFragment.h"
class ExposesComponents { class ExposesComponents {
public: public:
virtual ~ExposesComponents() {} virtual ~ExposesComponents() {}
virtual FilePickerFragment& getFilePicker() = 0; virtual FilePickerFragment& getFilePicker() = 0;
virtual SlidersFragment& getSliders() = 0;
}; };

View File

@ -8,15 +8,15 @@
using namespace std; using namespace std;
FluidSynthModel::FluidSynthModel(SharesParams& p) FluidSynthModel::FluidSynthModel(shared_ptr<SharesParams> sharedParams)
: sharesParams(p), : sharedParams{sharedParams},
synth(nullptr), synth{nullptr},
settings(nullptr), settings{nullptr},
currentSoundFontAbsPath(), currentSoundFontAbsPath{},
currentSampleRate(44100), currentSampleRate{44100},
initialised(false), initialised{false},
sfont_id(0), sfont_id{0},
channel(0)/*, channel{0}/*,
mod(nullptr)*/ mod(nullptr)*/
{} {}
@ -51,9 +51,9 @@ void FluidSynthModel::initialise() {
synth = new_fluid_synth(settings); synth = new_fluid_synth(settings);
fluid_synth_set_sample_rate(synth, currentSampleRate); fluid_synth_set_sample_rate(synth, currentSampleRate);
if (sharesParams.getSoundFontPath().isNotEmpty()) { if (sharedParams->getSoundFontPath().isNotEmpty()) {
loadFont(sharesParams.getSoundFontPath()); loadFont(sharedParams->getSoundFontPath());
changePreset(sharesParams.getBank(), sharesParams.getPreset()); changePreset(sharedParams->getBank(), sharedParams->getPreset());
} }
fluid_synth_set_gain(synth, 2.0); fluid_synth_set_gain(synth, 2.0);
@ -189,8 +189,8 @@ void FluidSynthModel::changePreset(int bank, int preset) {
preset = bankAndPreset->getPreset(); preset = bankAndPreset->getPreset();
} }
changePresetImpl(bank, preset); changePresetImpl(bank, preset);
sharesParams.setPreset(preset); sharedParams->setPreset(preset);
sharesParams.setBank(bank); sharedParams->setBank(bank);
} }
void FluidSynthModel::changePresetImpl(int bank, int preset) { void FluidSynthModel::changePresetImpl(int bank, int preset) {
@ -272,7 +272,7 @@ void FluidSynthModel::onFileNameChanged(const String &absPath, int bank, int pre
} }
unloadAndLoadFont(absPath); unloadAndLoadFont(absPath);
changePreset(bank, preset); changePreset(bank, preset);
sharesParams.setSoundFontPath(absPath); sharedParams->setSoundFontPath(absPath);
eventListeners.call(&FluidSynthModel::Listener::fontChanged, this, absPath); eventListeners.call(&FluidSynthModel::Listener::fontChanged, this, absPath);
} }

View File

@ -19,7 +19,7 @@ using namespace std;
class FluidSynthModel { class FluidSynthModel {
public: public:
FluidSynthModel(SharesParams& p); FluidSynthModel(shared_ptr<SharesParams> sharedParams);
~FluidSynthModel(); ~FluidSynthModel();
fluid_synth_t* getSynth(); fluid_synth_t* getSynth();
@ -65,7 +65,7 @@ public:
const String& getCurrentSoundFontAbsPath(); const String& getCurrentSoundFontAbsPath();
private: private:
SharesParams& sharesParams; shared_ptr<SharesParams> sharedParams;
fluid_synth_t* synth; fluid_synth_t* synth;
fluid_settings_t* settings; fluid_settings_t* settings;

8
Source/GuiConstants.h Normal file
View File

@ -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;
};

View File

@ -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). - 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 #define FLUID_PEAK_ATTENUATION 960.0f
struct MidiConstants {
inline static const int midiMinValue = 0;
inline static const int midiMaxValue = 127;
};

152
Source/Params.cpp Normal file
View File

@ -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<XmlElement> 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<fluid_midi_control_change>(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;
}

59
Source/Params.h Normal file
View File

@ -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<XmlElement> 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)
};

View File

@ -10,20 +10,26 @@
#include "PluginProcessor.h" #include "PluginProcessor.h"
#include "PluginEditor.h" #include "PluginEditor.h"
#include "GuiConstants.h"
//============================================================================== //==============================================================================
JuicySFAudioProcessorEditor::JuicySFAudioProcessorEditor (JuicySFAudioProcessor& p) JuicySFAudioProcessorEditor::JuicySFAudioProcessorEditor(JuicySFAudioProcessor& p)
: AudioProcessorEditor (&p), : AudioProcessorEditor{&p},
processor (p), processor{p},
midiKeyboard (p.keyboardState, SurjectiveMidiKeyboardComponent::horizontalKeyboard), sharedParams{p.sharedParams},
tablesComponent(p.getFluidSynthModel()), midiKeyboard{p.keyboardState, SurjectiveMidiKeyboardComponent::horizontalKeyboard},
filePicker(p.getFluidSynthModel()), tablesComponent{p.getFluidSynthModel()},
slidersComponent{p.getFluidSynthModel()} filePicker{p.getFluidSynthModel()},
slidersComponent{p.sharedParams, p.getFluidSynthModel()}
{ {
// set resize limits for this plug-in // 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); // processor.subscribeToStateChanges(this);
@ -97,9 +103,8 @@ void JuicySFAudioProcessorEditor::resized()
tablesComponent.setBounds(rContent); tablesComponent.setBounds(rContent);
sharedParams->setUiWidth(getWidth());
processor.lastUIWidth = getWidth(); sharedParams->setUiHeight(getHeight());
processor.lastUIHeight = getHeight();
// Rectangle<int> r2 (getLocalBounds()); // Rectangle<int> r2 (getLocalBounds());
// r2.reduce(0, padding); // r2.reduce(0, padding);
@ -150,4 +155,8 @@ bool JuicySFAudioProcessorEditor::keyStateChanged (bool isKeyDown) {
FilePickerFragment& JuicySFAudioProcessorEditor::getFilePicker() { FilePickerFragment& JuicySFAudioProcessorEditor::getFilePicker() {
return filePicker; return filePicker;
}
SlidersFragment& JuicySFAudioProcessorEditor::getSliders() {
return slidersComponent;
} }

View File

@ -42,12 +42,15 @@ public:
// void setStateInformation (XmlElement* xmlState) override; // void setStateInformation (XmlElement* xmlState) override;
virtual FilePickerFragment& getFilePicker() override; virtual FilePickerFragment& getFilePicker() override;
virtual SlidersFragment& getSliders() override;
private: private:
// This reference is provided as a quick way for your editor to // This reference is provided as a quick way for your editor to
// access the processor object that created it. // access the processor object that created it.
JuicySFAudioProcessor& processor; JuicySFAudioProcessor& processor;
shared_ptr<SharesParams> sharedParams;
SurjectiveMidiKeyboardComponent midiKeyboard; SurjectiveMidiKeyboardComponent midiKeyboard;
TablesComponent tablesComponent; TablesComponent tablesComponent;
FilePicker filePicker; FilePicker filePicker;

View File

@ -15,19 +15,20 @@
#include "ExposesComponents.h" #include "ExposesComponents.h"
#include "MidiConstants.h" #include "MidiConstants.h"
#include "Util.h" #include "Util.h"
#include "SharesParams.h"
#include "Params.h"
using namespace std;
AudioProcessor* JUCE_CALLTYPE createPluginFilter(); AudioProcessor* JUCE_CALLTYPE createPluginFilter();
//============================================================================== //==============================================================================
JuicySFAudioProcessor::JuicySFAudioProcessor() JuicySFAudioProcessor::JuicySFAudioProcessor()
: AudioProcessor (getBusesProperties()), : AudioProcessor{getBusesProperties()},
lastUIWidth(400), sharedParams{static_pointer_cast<SharesParams>(make_shared<Params>())},
lastUIHeight(300), fluidSynthModel{sharedParams}/*,
soundFontPath(String()), fluidSynthModel{*this},
lastPreset(-1),
lastBank(-1),
fluidSynthModel(*this)/*,
pluginEditor(nullptr)*/ pluginEditor(nullptr)*/
{ {
initialiseSynth(); initialiseSynth();
@ -47,10 +48,10 @@ void JuicySFAudioProcessor::initialiseSynth() {
// Add some voices... // Add some voices...
for (int i = numVoices; --i >= 0;) 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 // ..and give the synth a sound to play
synth.addSound (new SoundfontSynthSound()); synth.addSound(new SoundfontSynthSound());
} }
//============================================================================== //==============================================================================
@ -168,6 +169,11 @@ void JuicySFAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer
// responsibilities of SoundfontSynthVoice. // 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. // 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()) { if (m.isController()) {
// shared_ptr<fluid_midi_event_t> 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_t *midi_event(new_fluid_midi_event());
fluid_midi_event_set_type(midi_event, static_cast<int>(CONTROL_CHANGE)); fluid_midi_event_set_type(midi_event, static_cast<int>(CONTROL_CHANGE));
fluid_midi_event_set_channel(midi_event, fluidSynthModel.getChannel()); fluid_midi_event_set_channel(midi_event, fluidSynthModel.getChannel());
@ -175,6 +181,13 @@ void JuicySFAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer
fluid_midi_event_set_value(midi_event, m.getControllerValue()); fluid_midi_event_set_value(midi_event, m.getControllerValue());
fluid_synth_handle_midi_event(fluidSynth, midi_event); fluid_synth_handle_midi_event(fluidSynth, midi_event);
delete_fluid_midi_event(midi_event); delete_fluid_midi_event(midi_event);
sharedParams->acceptMidiControlEvent(m.getControllerNumber(), m.getControllerValue());
AudioProcessorEditor* editor{getActiveEditor()};
jassert(dynamic_cast<ExposesComponents*> (editor) != nullptr);
ExposesComponents* exposesComponents{dynamic_cast<ExposesComponents*>(editor)};
exposesComponents->getSliders().acceptMidiControlEvent(m.getControllerNumber(), m.getControllerValue());
} else if (m.isProgramChange()) { } else if (m.isProgramChange()) {
fluid_midi_event_t *midi_event(new_fluid_midi_event()); fluid_midi_event_t *midi_event(new_fluid_midi_event());
fluid_midi_event_set_type(midi_event, static_cast<int>(PROGRAM_CHANGE)); fluid_midi_event_set_type(midi_event, static_cast<int>(PROGRAM_CHANGE));
@ -266,14 +279,8 @@ void JuicySFAudioProcessor::getStateInformation (MemoryBlock& destData)
// as intermediaries to make it easy to save and load complex data. // as intermediaries to make it easy to save and load complex data.
// Create an outer XML element.. // Create an outer XML element..
XmlElement xml ("MYPLUGINSETTINGS"); XmlElement xml{"MYPLUGINSETTINGS"};
sharedParams->setAttributesOnXml(xml);
// 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);
// list<StateChangeSubscriber*>::iterator p; // list<StateChangeSubscriber*>::iterator p;
// for(p = stateChangeSubscribers.begin(); p != stateChangeSubscribers.end(); 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, // You should use this method to restore your parameters from this memory block,
// whose contents will have been created by the getStateInformation() call. // whose contents will have been created by the getStateInformation() call.
// This getXmlFromBinary() helper function retrieves our XML from the binary blob.. // This getXmlFromBinary() helper function retrieves our XML from the binary blob..
ScopedPointer<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes)); shared_ptr<XmlElement> xmlState{getXmlFromBinary(data, sizeInBytes)};
if (xmlState != nullptr) if (xmlState != nullptr)
{ {
@ -307,26 +314,27 @@ void JuicySFAudioProcessor::setStateInformation (const void* data, int sizeInByt
// } // }
// ok, now pull out our last window size.. // ok, now pull out our last window size..
lastUIWidth = jmax (xmlState->getIntAttribute ("uiWidth", lastUIWidth), 400); sharedParams->loadAttributesFromXml(xmlState);
lastUIHeight = jmax (xmlState->getIntAttribute ("uiHeight", lastUIHeight), 300);
soundFontPath = xmlState->getStringAttribute ("soundFontPath", soundFontPath);
lastPreset = xmlState->getIntAttribute ("preset", lastPreset);
lastBank = xmlState->getIntAttribute ("bank", lastBank);
// Now reload our parameters.. // Now reload our parameters..
for (auto* param : getParameters()) for (auto* param : getParameters())
if (auto* p = dynamic_cast<AudioProcessorParameterWithID*> (param)) if (auto* p = dynamic_cast<AudioProcessorParameterWithID*> (param))
p->setValue ((float) xmlState->getDoubleAttribute (p->paramID, p->getValue())); 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) { if (editor != nullptr) {
editor->setSize(lastUIWidth, lastUIHeight); editor->setSize(
sharedParams->getUiWidth(),
sharedParams->getUiHeight());
jassert(dynamic_cast<ExposesComponents*> (editor) != nullptr); jassert(dynamic_cast<ExposesComponents*> (editor) != nullptr);
ExposesComponents* exposesComponents = dynamic_cast<ExposesComponents*> (editor); ExposesComponents* exposesComponents = dynamic_cast<ExposesComponents*> (editor);
exposesComponents->getFilePicker().setDisplayedFilePath(soundFontPath); exposesComponents->getFilePicker().setDisplayedFilePath(sharedParams->getSoundFontPath());
} }
// const String& currentSoundFontAbsPath = fluidSynthModel->getCurrentSoundFontAbsPath(); // const String& currentSoundFontAbsPath = fluidSynthModel->getCurrentSoundFontAbsPath();
@ -354,26 +362,6 @@ FluidSynthModel* JuicySFAudioProcessor::getFluidSynthModel() {
return &fluidSynthModel; 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.. // This creates new instances of the plugin..
AudioProcessor* JUCE_CALLTYPE createPluginFilter() AudioProcessor* JUCE_CALLTYPE createPluginFilter()

View File

@ -21,8 +21,7 @@ using namespace std;
//============================================================================== //==============================================================================
/** /**
*/ */
class JuicySFAudioProcessor : public AudioProcessor, class JuicySFAudioProcessor : public AudioProcessor
public SharesParams
{ {
public: public:
//============================================================================== //==============================================================================
@ -67,25 +66,14 @@ public:
MidiKeyboardState keyboardState; MidiKeyboardState keyboardState;
virtual void setSoundFontPath(const String& value) override; shared_ptr<SharesParams> sharedParams;
virtual String& getSoundFontPath() override;
virtual int getPreset() override;
virtual void setPreset(int preset) override;
virtual int getBank() override;
virtual void setBank(int bank) override;
// void subscribeToStateChanges(StateChangeSubscriber* subscriber); // void subscribeToStateChanges(StateChangeSubscriber* subscriber);
// void unsubscribeFromStateChanges(StateChangeSubscriber* subscriber); // void unsubscribeFromStateChanges(StateChangeSubscriber* subscriber);
int lastUIWidth, lastUIHeight;
private: private:
void initialiseSynth(); void initialiseSynth();
String soundFontPath;
int lastPreset;
int lastBank;
FluidSynthModel fluidSynthModel; FluidSynthModel fluidSynthModel;
fluid_synth_t* fluidSynth; fluid_synth_t* fluidSynth;
Synthesiser synth; Synthesiser synth;

View File

@ -7,16 +7,42 @@
#include "../JuceLibraryCode/JuceHeader.h" #include "../JuceLibraryCode/JuceHeader.h"
using namespace std;
class SharesParams { class SharesParams {
public: public:
virtual ~SharesParams() {} virtual ~SharesParams() {}
virtual void setAttributesOnXml(XmlElement& xml) = 0;
virtual void loadAttributesFromXml(shared_ptr<XmlElement> xmlState) = 0;
virtual void acceptMidiControlEvent(int controller, int value) = 0;
virtual void setSoundFontPath(const String& value) = 0; virtual void setSoundFontPath(const String& value) = 0;
virtual String& getSoundFontPath() = 0; virtual String& getSoundFontPath() = 0;
virtual int getPreset() = 0; virtual int getPreset() = 0;
virtual void setPreset(int preset) = 0; virtual void setPreset(int value) = 0;
virtual int getBank() = 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;
}; };

View File

@ -10,10 +10,11 @@
#include "FluidSynthModel.h" #include "FluidSynthModel.h"
#include "MidiConstants.h" #include "MidiConstants.h"
std::function<void()> SlidersComponent::makeSliderListener(Slider& slider, int controller) { std::function<void()> SlidersComponent::makeSliderListener(Slider& slider, int controller/*, std::function<void()> callback*/) {
return [this, controller, &slider]{ return [this, controller, &slider]{
// slider.setValue(slider.getValue(), NotificationType::dontSendNotification); // slider.setValue(slider.getValue(), NotificationType::dontSendNotification);
fluidSynthModel->setControllerValue(controller, slider.getValue()); fluidSynthModel->setControllerValue(controller, slider.getValue());
// callback();
}; };
} }
@ -58,7 +59,54 @@ void SlidersComponent::resized() {
filterResonanceSlider.setBounds(rFilter.removeFromLeft(sliderWidth + sliderXMargin).withTrimmedTop(labelHeight).withTrimmedLeft(sliderXMargin)); filterResonanceSlider.setBounds(rFilter.removeFromLeft(sliderWidth + sliderXMargin).withTrimmedTop(labelHeight).withTrimmedLeft(sliderXMargin));
} }
SlidersComponent::SlidersComponent(FluidSynthModel* fluidSynthModel) : void SlidersComponent::acceptMidiControlEvent(int controller, int value) {
switch(static_cast<fluid_midi_control_change>(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<SharesParams> sharedParams,
FluidSynthModel* fluidSynthModel) :
sharedParams{sharedParams},
fluidSynthModel{fluidSynthModel}, fluidSynthModel{fluidSynthModel},
envelopeGroup{"envelopeGroup", "Envelope"}, envelopeGroup{"envelopeGroup", "Envelope"},
filterGroup{"filterGroup", "Filter"} filterGroup{"filterGroup", "Filter"}

View File

@ -2,22 +2,38 @@
#include "../JuceLibraryCode/JuceHeader.h" #include "../JuceLibraryCode/JuceHeader.h"
#include "FluidSynthModel.h" #include "FluidSynthModel.h"
#include "SharesParams.h"
#include "SlidersFragment.h"
using namespace std; using namespace std;
class SlidersComponent : public Component class SlidersComponent : public Component,
public SlidersFragment
{ {
public: public:
SlidersComponent(FluidSynthModel* fluidSynthModel); SlidersComponent(
shared_ptr<SharesParams> sharedParams,
FluidSynthModel* fluidSynthModel);
~SlidersComponent(); ~SlidersComponent();
void resized() override; void resized() override;
const int getDesiredWidth(); 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: private:
std::function<void()> makeSliderListener(Slider& slider, int controller); std::function<void()> makeSliderListener(Slider& slider, int controller);
shared_ptr<SharesParams> sharedParams;
FluidSynthModel* fluidSynthModel; FluidSynthModel* fluidSynthModel;
GroupComponent envelopeGroup; GroupComponent envelopeGroup;

18
Source/SlidersFragment.h Normal file
View File

@ -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;
};