pull/1/head
asb2m10 11 years ago
parent 26f049653b
commit 9bc7fc9003
  1. 4636
      Builds/MacOSX/Dexed.xcodeproj/project.pbxproj
  2. BIN
      Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate
  3. 46
      README.md
  4. 27
      Source/DXLookNFeel.cpp
  5. 6
      Source/DXLookNFeel.h
  6. 66
      Source/OperatorEditor.cpp
  7. 3
      Source/OperatorEditor.h
  8. 16
      Source/PluginEditor.cpp
  9. 95
      Source/PluginParam.cpp
  10. 4
      Source/PluginParam.h
  11. 3
      Source/PluginProcessor.cpp
  12. 13
      Source/PluginProcessor.h

File diff suppressed because it is too large Load Diff

@ -1,40 +1,50 @@
Dexed DX7 Software Emulator Dexed DX7 Software Emulator
=========================== ===========================
Dexed is a multi platform, multiformat plugin synth that is closely modeled on the Yamaha DX7. Dexed is a multi platform, multi format plugin synth that is closely modeled on the Yamaha DX7.
Under the hood, it uses [music-synthesizer-for-android](https://code.google.com/p/music-synthesizer-for-android) Under the hood, it uses [music-synthesizer-for-android](https://code.google.com/p/music-synthesizer-for-android)
for the synth engine and [JUCE](http://wwww.juce.com) as a plugin wrapper. for the synth engine and [JUCE](http://wwww.juce.com) as a plugin wrapper.
Dexed is licensed on the GPL v2. The msfa component (music synthesizer for android, see msfa in the source The goal of this project is to be a great tool/companion for the original DX7. Yes, the sound engine
folder) stays on the Apache 2.0 license to able to collaborate between projects. with 'float' values parameter; different waveform (à la TX81z) would be great but anything that
goes beyond the DX7 should will be a fork of this project. This is to keep the compatiblity with
the original synth.
Dexed is licensed on the GPL v2. The msfa component (acronym for music synthesizer for android, see msfa
in the source folder) stays on the Apache 2.0 license to able to collaborate between projects.
Features
--------
* Multi platform (OS X, Windows, Linux) and multi format (VST, AU and others that I don't use); by using JUCE
* The sound engine [music-synthesizer-for-android](https://code.google.com/p/music-synthesizer-for-android) is closely modeled on the original DX7 characteristics
* All of the 144 DX7 parameters are available from one single panel
* Fully supports DX7 input and output Sysex messages; including controller change. This means that you can use this with a native DX7/TX7 as a patch editor
* Each operator have a realtime VU meter to know wich one is active
* Can load any DX7/TX7 sysex programs
Binary downloads Binary downloads
---------------- ----------------
It is far from finish but for those who want to try the "music-synthesizer-for-android" project It is far from finished but for those who want to try the "music-synthesizer-for-android" project
on a PC/Mac, you can download it [here](http://le-son666.com/software/dexed). on a PC/Mac, you can download it [here](http://le-son666.com/software/dexed).
Using has a DX7 editor Using as a DX7 editor
---------------------- ---------------------
This plugin can process original DX7 messages. If you change a parameter, it will send the This plugin can process original DX7 messages. If you change a parameter, it will send the
corresponding DX7 sysex to midi out. Not all DAW supports sysex; for example corresponding DX7 sysex to midi out. Not all DAW supports sysex; for example
Ableton Live simply discard any sysex data. Reaper does process midi out, but doesn't pass any Ableton Live simply discard any sysex data. Reaper does process midi out, but doesn't pass any
midi in sysex data to the plugin. midi in sysex input data to the plugin.
(New) Features Randomized programs
-------------- -------------------
* Multi platform (OS X, Windows, Linux) and multi format (VST, AU); by using JUCE Dexed doesn't check the sysex checksum so you can load any type of files. If the checksum doesn't
* The sound engine [music-synthesizer-for-android](https://code.google.com/p/music-synthesizer-for-android) is closely modeled on the original DX7 characteristics match, it will tell you but load it anyway. This features enable a somekind of randomized DX
* All of the 144 DX7 parameters are available from one single panel programs.
* Fully supports DX7 input and output Sysex messages; including controller change. This means that you can use this with a native DX7/TX7 as a patch editor
* Each operator have a realtime VU meter to know wich one is active
* Can load any DX7/TX7 sysex programs. [See this (SynprezFM-II-builtins.tgz)](http://www.synprez.com/SynprezFM/) for great collection of DX7 patches
TODO - Dexed TODO - Dexed
------------ ------------
* Implement a better DX look and feel * Implement a better DX look and feel (amp, pitch, algo)
* Better implementation of the LPF filter * Better implementation of the LPF filter
* Better display of the amplitude envelope * Various code cleanup
* Better display of the algo
TODO - msfa TODO - msfa
----------- -----------

@ -152,12 +152,37 @@ void AlgoDisplay::drawOp(Graphics &g, int x, int y, int num, bool feedback) {
int x1 = (x*21) + 19; int x1 = (x*21) + 19;
g.drawLine(x1, y*14+1, x1, y*14+14, 3); g.drawLine(x1, y*14+1, x1, y*14+14, 3);
} }
}
void VuMeter::paint(Graphics &g) {
// taken from the drawLevelMeter ;
float width = getWidth();
float height = getHeight();
g.setColour (Colours::black);
g.fillRoundedRectangle (0.0f, 0.0f, (float) width, (float) height, 0);
/*g.setColour (Colours::black.withAlpha (0.2f));
g.drawRoundedRectangle (1.0f, 1.0f, width - 2.0f, height - 2.0f, 3.0f, 1.0f);*/
const int totalBlocks = 16;
const int numBlocks = roundToInt (totalBlocks * v);
const float h = (height - 6.0f) / (float) totalBlocks;
for (int i = 0; i < totalBlocks; ++i) {
g.setColour (Colours::red);
if (i >= numBlocks)
g.setColour (Colours::red.withAlpha (0.2f));
else
g.setColour (Colours::red);
//g.fillRoundedRectangle (3.0f + i * w + w * 0.1f, 3.0f, w * 0.8f, height - 6.0f, w * 0.4f);
g.fillRoundedRectangle (3.0f, (height-3.0f) - (3.0f + i * h + h * 0.1f) , width - 6.0f, h * 0.8f, 0);
}
} }
DXLookNFeel::DXLookNFeel() { DXLookNFeel::DXLookNFeel() {
setColour(TextButton::buttonColourId,Colour(0xFF0FC00F)); setColour(TextButton::buttonColourId,Colour(0xFF0FC00F));
setColour(Slider::rotarySliderOutlineColourId,Colour(0xFF0FC00F)); setColour(Slider::rotarySliderOutlineColourId,Colour(0xFF0FC00F));
setColour(Slider::rotarySliderFillColourId,Colour(0xFFFFFFFF)); setColour(Slider::rotarySliderFillColourId,Colour(0xFFFFFFFF));
} }

@ -51,5 +51,9 @@ public:
DXLookNFeel(); DXLookNFeel();
}; };
class VuMeter: public Component {
void paint(Graphics &g);
public :
float v;
};
#endif // DXLOOKNFEEL_H_INCLUDED #endif // DXLOOKNFEEL_H_INCLUDED

@ -86,14 +86,6 @@ OperatorEditor::OperatorEditor ()
opMode->addItem ("FIXED", 2); opMode->addItem ("FIXED", 2);
opMode->addListener (this); opMode->addListener (this);
addAndMakeVisible (opId = new Label ("new label",
"OP1"));
opId->setFont (Font (9.30f, Font::plain));
opId->setJustificationType (Justification::centredLeft);
opId->setEditable (false, false, false);
opId->setColour (TextEditor::textColourId, Colours::black);
opId->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
addAndMakeVisible (opLevel = new Slider ("opLevel")); addAndMakeVisible (opLevel = new Slider ("opLevel"));
opLevel->setRange (0, 99, 1); opLevel->setRange (0, 99, 1);
opLevel->setSliderStyle (Slider::Rotary); opLevel->setSliderStyle (Slider::Rotary);
@ -112,16 +104,6 @@ OperatorEditor::OperatorEditor ()
opCoarse->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); opCoarse->setTextBoxStyle (Slider::NoTextBox, false, 80, 20);
opCoarse->addListener (this); opCoarse->addListener (this);
addAndMakeVisible (gain = new Slider ("new slider"));
gain->setRange (0, 1, 0);
gain->setSliderStyle (Slider::LinearVertical);
gain->setTextBoxStyle (Slider::NoTextBox, true, 80, 20);
gain->setColour (Slider::thumbColourId, Colours::black);
gain->setColour (Slider::trackColourId, Colour (0x00ffffff));
gain->setColour (Slider::rotarySliderFillColourId, Colour (0x000000ff));
gain->setColour (Slider::textBoxBackgroundColourId, Colours::white);
gain->addListener (this);
addAndMakeVisible (khzDisplay = new Label ("khz", addAndMakeVisible (khzDisplay = new Label ("khz",
"1,000 kHz")); "1,000 kHz"));
khzDisplay->setFont (Font (11.00f, Font::plain)); khzDisplay->setFont (Font (11.00f, Font::plain));
@ -133,7 +115,7 @@ OperatorEditor::OperatorEditor ()
khzDisplay->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); khzDisplay->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
addAndMakeVisible (detune = new Slider ("detune")); addAndMakeVisible (detune = new Slider ("detune"));
detune->setRange (0, 14, 1); detune->setRange (-7, 7, 1);
detune->setSliderStyle (Slider::LinearHorizontal); detune->setSliderStyle (Slider::LinearHorizontal);
detune->setTextBoxStyle (Slider::NoTextBox, true, 80, 20); detune->setTextBoxStyle (Slider::NoTextBox, true, 80, 20);
detune->addListener (this); detune->addListener (this);
@ -203,6 +185,9 @@ OperatorEditor::OperatorEditor ()
ampModSens->setTextBoxStyle (Slider::NoTextBox, false, 80, 20); ampModSens->setTextBoxStyle (Slider::NoTextBox, false, 80, 20);
ampModSens->addListener (this); ampModSens->addListener (this);
addAndMakeVisible (vu = new VuMeter());
vu->setName ("vu");
//[UserPreSize] //[UserPreSize]
//[/UserPreSize] //[/UserPreSize]
@ -236,11 +221,9 @@ OperatorEditor::~OperatorEditor()
s_egv3 = nullptr; s_egv3 = nullptr;
s_egv4 = nullptr; s_egv4 = nullptr;
opMode = nullptr; opMode = nullptr;
opId = nullptr;
opLevel = nullptr; opLevel = nullptr;
opFine = nullptr; opFine = nullptr;
opCoarse = nullptr; opCoarse = nullptr;
gain = nullptr;
khzDisplay = nullptr; khzDisplay = nullptr;
detune = nullptr; detune = nullptr;
envDisplay = nullptr; envDisplay = nullptr;
@ -252,6 +235,7 @@ OperatorEditor::~OperatorEditor()
sclRateScaling = nullptr; sclRateScaling = nullptr;
keyVelSens = nullptr; keyVelSens = nullptr;
ampModSens = nullptr; ampModSens = nullptr;
vu = nullptr;
//[Destructor]. You can add your own custom destruction code here.. //[Destructor]. You can add your own custom destruction code here..
@ -264,6 +248,9 @@ void OperatorEditor::paint (Graphics& g)
//[UserPrePaint] Add your own custom painting code here.. //[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint] //[/UserPrePaint]
g.setColour (Colour (0x41000000));
g.fillRect (-5, -8, 293, 100);
//[UserPaint] Add your own custom painting code here.. //[UserPaint] Add your own custom painting code here..
//[/UserPaint] //[/UserPaint]
} }
@ -279,11 +266,9 @@ void OperatorEditor::resized()
s_egv3->setBounds (184, 64, 24, 24); s_egv3->setBounds (184, 64, 24, 24);
s_egv4->setBounds (208, 64, 24, 24); s_egv4->setBounds (208, 64, 24, 24);
opMode->setBounds (24, 48, 104, 16); opMode->setBounds (24, 48, 104, 16);
opId->setBounds (0, 0, 24, 16);
opLevel->setBounds (232, 56, 32, 32); opLevel->setBounds (232, 56, 32, 32);
opFine->setBounds (104, 24, 24, 24); opFine->setBounds (104, 24, 24, 24);
opCoarse->setBounds (80, 24, 24, 24); opCoarse->setBounds (80, 24, 24, 24);
gain->setBounds (260, 0, 24, 88);
khzDisplay->setBounds (32, 8, 88, 16); khzDisplay->setBounds (32, 8, 88, 16);
detune->setBounds (24, 24, 56, 24); detune->setBounds (24, 24, 56, 24);
envDisplay->setBounds (136, 5, 96, 32); envDisplay->setBounds (136, 5, 96, 32);
@ -295,6 +280,7 @@ void OperatorEditor::resized()
sclRateScaling->setBounds (0, 16, 24, 24); sclRateScaling->setBounds (0, 16, 24, 24);
keyVelSens->setBounds (240, 24, 24, 24); keyVelSens->setBounds (240, 24, 24, 24);
ampModSens->setBounds (240, 0, 24, 24); ampModSens->setBounds (240, 0, 24, 24);
vu->setBounds (268, 0, 12, 88);
//[UserResized] Add your own custom resize handling here.. //[UserResized] Add your own custom resize handling here..
//[/UserResized] //[/UserResized]
} }
@ -369,11 +355,6 @@ void OperatorEditor::sliderValueChanged (Slider* sliderThatWasMoved)
updateDisplay(); updateDisplay();
//[/UserSliderCode_opCoarse] //[/UserSliderCode_opCoarse]
} }
else if (sliderThatWasMoved == gain)
{
//[UserSliderCode_gain] -- add your slider handling code here..
//[/UserSliderCode_gain]
}
else if (sliderThatWasMoved == detune) else if (sliderThatWasMoved == detune)
{ {
//[UserSliderCode_detune] -- add your slider handling code here.. //[UserSliderCode_detune] -- add your slider handling code here..
@ -445,12 +426,6 @@ void OperatorEditor::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here... //[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
void OperatorEditor::bind(DexedAudioProcessor *parent, int op) { void OperatorEditor::bind(DexedAudioProcessor *parent, int op) {
int targetNum = op+1;
String opName;
opName << "OP" << targetNum;
opId->setText(opName, NotificationType::dontSendNotification);
parent->opCtrl[op].egLevel[0]->bind(s_egl1); parent->opCtrl[op].egLevel[0]->bind(s_egl1);
parent->opCtrl[op].egLevel[1]->bind(s_egl2); parent->opCtrl[op].egLevel[1]->bind(s_egl2);
parent->opCtrl[op].egLevel[2]->bind(s_egl3); parent->opCtrl[op].egLevel[2]->bind(s_egl3);
@ -474,7 +449,8 @@ void OperatorEditor::bind(DexedAudioProcessor *parent, int op) {
void OperatorEditor::updateGain(float v) { void OperatorEditor::updateGain(float v) {
gain->setValue(v); vu->v = v;
vu->repaint();
} }
@ -493,7 +469,7 @@ void OperatorEditor::updateDisplay() {
txtFreq << freq << " Hz"; txtFreq << freq << " Hz";
} }
int det = detune->getValue() - 7; int det = detune->getValue();
if ( det != 0 ) { if ( det != 0 ) {
if ( det > 0 ) if ( det > 0 )
txtFreq << " +" << det; txtFreq << " +" << det;
@ -524,7 +500,9 @@ BEGIN_JUCER_METADATA
parentClasses="public Component" constructorParams="" variableInitialisers="" parentClasses="public Component" constructorParams="" variableInitialisers=""
snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330" snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330"
fixedSize="1" initialWidth="280" initialHeight="90"> fixedSize="1" initialWidth="280" initialHeight="90">
<BACKGROUND backgroundColour="ffffff"/> <BACKGROUND backgroundColour="ffffff">
<RECT pos="-5 -8 293 100" fill="solid: 41000000" hasStroke="0"/>
</BACKGROUND>
<SLIDER name="egl1" id="dc070cc41347df47" memberName="s_egl1" virtualName="" <SLIDER name="egl1" id="dc070cc41347df47" memberName="s_egl1" virtualName=""
explicitFocusOrder="0" pos="136 40 24 24" min="0" max="99" int="1" explicitFocusOrder="0" pos="136 40 24 24" min="0" max="99" int="1"
style="Rotary" textBoxPos="NoTextBox" textBoxEditable="1" textBoxWidth="80" style="Rotary" textBoxPos="NoTextBox" textBoxEditable="1" textBoxWidth="80"
@ -560,11 +538,6 @@ BEGIN_JUCER_METADATA
<COMBOBOX name="opMode" id="2cf8156bb94cdc40" memberName="opMode" virtualName="" <COMBOBOX name="opMode" id="2cf8156bb94cdc40" memberName="opMode" virtualName=""
explicitFocusOrder="0" pos="24 48 104 16" editable="0" layout="33" explicitFocusOrder="0" pos="24 48 104 16" editable="0" layout="33"
items="RATIO&#10;FIXED" textWhenNonSelected="" textWhenNoItems="(no choices)"/> items="RATIO&#10;FIXED" textWhenNonSelected="" textWhenNoItems="(no choices)"/>
<LABEL name="new label" id="75765097f6c5c142" memberName="opId" virtualName=""
explicitFocusOrder="0" pos="0 0 24 16" edTextCol="ff000000" edBkgCol="0"
labelText="OP1" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="9.3000000000000007105"
bold="0" italic="0" justification="33"/>
<SLIDER name="opLevel" id="f8521c8214fb8993" memberName="opLevel" virtualName="" <SLIDER name="opLevel" id="f8521c8214fb8993" memberName="opLevel" virtualName=""
explicitFocusOrder="0" pos="232 56 32 32" min="0" max="99" int="1" explicitFocusOrder="0" pos="232 56 32 32" min="0" max="99" int="1"
style="Rotary" textBoxPos="NoTextBox" textBoxEditable="1" textBoxWidth="80" style="Rotary" textBoxPos="NoTextBox" textBoxEditable="1" textBoxWidth="80"
@ -577,18 +550,13 @@ BEGIN_JUCER_METADATA
explicitFocusOrder="0" pos="80 24 24 24" min="0" max="31" int="1" explicitFocusOrder="0" pos="80 24 24 24" min="0" max="31" int="1"
style="Rotary" textBoxPos="NoTextBox" textBoxEditable="1" textBoxWidth="80" style="Rotary" textBoxPos="NoTextBox" textBoxEditable="1" textBoxWidth="80"
textBoxHeight="20" skewFactor="1"/> textBoxHeight="20" skewFactor="1"/>
<SLIDER name="new slider" id="21f21cc5fae8e54b" memberName="gain" virtualName=""
explicitFocusOrder="0" pos="260 0 24 88" thumbcol="ff000000"
trackcol="ffffff" rotarysliderfill="ff" textboxbkgd="ffffffff"
min="0" max="1" int="0" style="LinearVertical" textBoxPos="NoTextBox"
textBoxEditable="0" textBoxWidth="80" textBoxHeight="20" skewFactor="1"/>
<LABEL name="khz" id="eb961eed8902a6fc" memberName="khzDisplay" virtualName="" <LABEL name="khz" id="eb961eed8902a6fc" memberName="khzDisplay" virtualName=""
explicitFocusOrder="0" pos="32 8 88 16" bkgCol="6a000000" outlineCol="0" explicitFocusOrder="0" pos="32 8 88 16" bkgCol="6a000000" outlineCol="0"
edTextCol="ff000000" edBkgCol="0" labelText="1,000 kHz" editableSingleClick="0" edTextCol="ff000000" edBkgCol="0" labelText="1,000 kHz" editableSingleClick="0"
editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font" editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font"
fontsize="11" bold="0" italic="0" justification="36"/> fontsize="11" bold="0" italic="0" justification="36"/>
<SLIDER name="detune" id="f093ec8defca2fc2" memberName="detune" virtualName="" <SLIDER name="detune" id="f093ec8defca2fc2" memberName="detune" virtualName=""
explicitFocusOrder="0" pos="24 24 56 24" min="0" max="14" int="1" explicitFocusOrder="0" pos="24 24 56 24" min="-7" max="7" int="1"
style="LinearHorizontal" textBoxPos="NoTextBox" textBoxEditable="0" style="LinearHorizontal" textBoxPos="NoTextBox" textBoxEditable="0"
textBoxWidth="80" textBoxHeight="20" skewFactor="1"/> textBoxWidth="80" textBoxHeight="20" skewFactor="1"/>
<GENERICCOMPONENT name="envDisplay" id="b18856de924c6340" memberName="envDisplay" <GENERICCOMPONENT name="envDisplay" id="b18856de924c6340" memberName="envDisplay"
@ -626,6 +594,8 @@ BEGIN_JUCER_METADATA
virtualName="" explicitFocusOrder="0" pos="240 0 24 24" min="0" virtualName="" explicitFocusOrder="0" pos="240 0 24 24" min="0"
max="4" int="1" style="Rotary" textBoxPos="NoTextBox" textBoxEditable="1" max="4" int="1" style="Rotary" textBoxPos="NoTextBox" textBoxEditable="1"
textBoxWidth="80" textBoxHeight="20" skewFactor="1"/> textBoxWidth="80" textBoxHeight="20" skewFactor="1"/>
<GENERICCOMPONENT name="vu" id="6f952594ea99dc1e" memberName="vu" virtualName=""
explicitFocusOrder="0" pos="268 0 12 88" class="VuMeter" params=""/>
</JUCER_COMPONENT> </JUCER_COMPONENT>
END_JUCER_METADATA END_JUCER_METADATA

@ -75,11 +75,9 @@ private:
ScopedPointer<Slider> s_egv3; ScopedPointer<Slider> s_egv3;
ScopedPointer<Slider> s_egv4; ScopedPointer<Slider> s_egv4;
ScopedPointer<ComboBox> opMode; ScopedPointer<ComboBox> opMode;
ScopedPointer<Label> opId;
ScopedPointer<Slider> opLevel; ScopedPointer<Slider> opLevel;
ScopedPointer<Slider> opFine; ScopedPointer<Slider> opFine;
ScopedPointer<Slider> opCoarse; ScopedPointer<Slider> opCoarse;
ScopedPointer<Slider> gain;
ScopedPointer<Label> khzDisplay; ScopedPointer<Label> khzDisplay;
ScopedPointer<Slider> detune; ScopedPointer<Slider> detune;
ScopedPointer<EnvDisplay> envDisplay; ScopedPointer<EnvDisplay> envDisplay;
@ -91,6 +89,7 @@ private:
ScopedPointer<Slider> sclRateScaling; ScopedPointer<Slider> sclRateScaling;
ScopedPointer<Slider> keyVelSens; ScopedPointer<Slider> keyVelSens;
ScopedPointer<Slider> ampModSens; ScopedPointer<Slider> ampModSens;
ScopedPointer<VuMeter> vu;
//============================================================================== //==============================================================================

@ -72,27 +72,27 @@ DexedAudioProcessorEditor::DexedAudioProcessorEditor (DexedAudioProcessor* owner
// OPERATORS // OPERATORS
addAndMakeVisible(&(operators[0])); addAndMakeVisible(&(operators[0]));
operators[0].setBounds(5, 40, 280, 90); operators[0].setBounds(5, 39, 280, 90);
operators[0].bind(processor, 0); operators[0].bind(processor, 0);
addAndMakeVisible(&(operators[1])); addAndMakeVisible(&(operators[1]));
operators[1].setBounds(290, 40, 280, 90); operators[1].setBounds(290, 39, 280, 90);
operators[1].bind(processor, 1); operators[1].bind(processor, 1);
addAndMakeVisible(&(operators[2])); addAndMakeVisible(&(operators[2]));
operators[2].setBounds(575, 40, 280, 90); operators[2].setBounds(575, 39, 280, 90);
operators[2].bind(processor, 2); operators[2].bind(processor, 2);
addAndMakeVisible(&(operators[3])); addAndMakeVisible(&(operators[3]));
operators[3].setBounds(5, 130, 280, 90); operators[3].setBounds(5, 133, 280, 90);
operators[3].bind(processor, 3); operators[3].bind(processor, 3);
addAndMakeVisible(&(operators[4])); addAndMakeVisible(&(operators[4]));
operators[4].setBounds(290, 130, 280, 90); operators[4].setBounds(290, 133, 280, 90);
operators[4].bind(processor, 4); operators[4].bind(processor, 4);
addAndMakeVisible(&(operators[5])); addAndMakeVisible(&(operators[5]));
operators[5].setBounds(575, 130, 280, 90); operators[5].setBounds(575, 133, 280, 90);
operators[5].bind(processor, 5); operators[5].bind(processor, 5);
// add the midi keyboard component.. // add the midi keyboard component..
@ -141,7 +141,7 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) {
fp_in.read((char *)syx_data, 4104); fp_in.read((char *)syx_data, 4104);
fp_in.close(); fp_in.close();
processor->importSysex((char *) &syx_data); processor->importSysex((char *) &syx_data);
processor->setCurrentProgram(0);
rebuildPresetCombobox(); rebuildPresetCombobox();
presets.setSelectedId(processor->getCurrentProgram()+1, NotificationType::dontSendNotification); presets.setSelectedId(processor->getCurrentProgram()+1, NotificationType::dontSendNotification);
@ -175,7 +175,7 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) {
} }
if (buttonThatWasClicked == storeButton) { if (buttonThatWasClicked == storeButton) {
AlertWindow dialog(String("Store Program Destination"), "", AlertWindow::NoIcon, this); AlertWindow dialog(String("Store Program"), "", AlertWindow::NoIcon, this);
dialog.addTextEditor(String("Name"), processor->getProgramName(processor->getCurrentProgram()), String("Name"), false); dialog.addTextEditor(String("Name"), processor->getProgramName(processor->getCurrentProgram()), String("Name"), false);
StringArray programs; StringArray programs;

@ -112,8 +112,8 @@ void CtrlFloat::updateComponent() {
// ************************************************************************ // ************************************************************************
// CtrlDX - control DX mapping // CtrlDX - control DX mapping
CtrlDX::CtrlDX(String name, int steps, int offset, bool starts1) : Ctrl(name) { CtrlDX::CtrlDX(String name, int steps, int offset, int displayValue) : Ctrl(name) {
add1 = starts1 == 1; this->displayValue = displayValue;
this->steps = steps; this->steps = steps;
dxValue = 0; dxValue = 0;
dxOffset = offset; dxOffset = offset;
@ -147,7 +147,7 @@ int CtrlDX::getValue() {
String CtrlDX::getValueDisplay() { String CtrlDX::getValueDisplay() {
String ret; String ret;
ret << ( getValue() + add1 ); ret << ( getValue() + displayValue );
return ret; return ret;
} }
@ -163,7 +163,7 @@ void CtrlDX::publishValue(float value) {
} }
void CtrlDX::sliderValueChanged(Slider* moved) { void CtrlDX::sliderValueChanged(Slider* moved) {
publishValue(((int) moved->getValue() - add1)); publishValue(((int) moved->getValue() - displayValue));
} }
void CtrlDX::comboBoxChanged(ComboBox* combo) { void CtrlDX::comboBoxChanged(ComboBox* combo) {
@ -172,7 +172,7 @@ void CtrlDX::comboBoxChanged(ComboBox* combo) {
void CtrlDX::updateComponent() { void CtrlDX::updateComponent() {
if (slider != NULL) { if (slider != NULL) {
slider->setValue(getValue() + add1, slider->setValue(getValue() + displayValue,
NotificationType::dontSendNotification); NotificationType::dontSendNotification);
} }
@ -200,6 +200,7 @@ void CtrlDX::updateComponent() {
*/ */
void DexedAudioProcessor::initCtrl() { void DexedAudioProcessor::initCtrl() {
importSysex(BinaryData::startup_syx); importSysex(BinaryData::startup_syx);
currentProgram = 0;
fxCutoff = new CtrlFloat("Cutoff", &fx.uiCutoff); fxCutoff = new CtrlFloat("Cutoff", &fx.uiCutoff);
ctrl.add(fxCutoff); ctrl.add(fxCutoff);
@ -207,7 +208,7 @@ void DexedAudioProcessor::initCtrl() {
fxReso = new CtrlFloat("Resonance", &fx.uiReso); fxReso = new CtrlFloat("Resonance", &fx.uiReso);
ctrl.add(fxReso); ctrl.add(fxReso);
algo = new CtrlDX("ALGORITHM", 32, 134, true); algo = new CtrlDX("ALGORITHM", 32, 134, 1);
ctrl.add(algo); ctrl.add(algo);
feedback = new CtrlDX("FEEDBACK", 8, 135); feedback = new CtrlDX("FEEDBACK", 8, 135);
@ -298,7 +299,7 @@ void DexedAudioProcessor::initCtrl() {
String detune; String detune;
detune << opName << " OSC DETUNE"; detune << opName << " OSC DETUNE";
opCtrl[opVal].detune = new CtrlDX(detune, 15, opTarget + 20); opCtrl[opVal].detune = new CtrlDX(detune, 15, opTarget + 20, -7);
ctrl.add(opCtrl[opVal].detune); ctrl.add(opCtrl[opVal].detune);
String sclBrkPt; String sclBrkPt;
@ -352,9 +353,6 @@ void DexedAudioProcessor::initCtrl() {
} }
int DexedAudioProcessor::importSysex(const char *imported) { int DexedAudioProcessor::importSysex(const char *imported) {
// reset current program
currentProgram = 0;
memcpy(sysex, imported + 6, 4096); memcpy(sysex, imported + 6, 4096);
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
memcpy(patchNames[i], sysex + ((i * 128) + 118), 11); memcpy(patchNames[i], sysex + ((i * 128) + 118), 11);
@ -524,21 +522,19 @@ int DexedAudioProcessor::getCurrentProgram() {
} }
void DexedAudioProcessor::setCurrentProgram(int index) { void DexedAudioProcessor::setCurrentProgram(int index) {
/*// VST has a naughty problem of calling setCurrentProgram after a host has loaded TRACE("setting program %d state %d", index, bypassVstChangeProgram);
// an edited preset. We ignore the 16th value, since we want to keep the user values if ( bypassVstChangeProgram ) {
if ( index == 32 ) { for (int i = 0; i < MAX_ACTIVE_NOTES; i++) {
return; if (voices[i].keydown == false && voices[i].live == true) {
}*/ voices[i].live = false;
}
for (int i = 0; i < MAX_ACTIVE_NOTES; i++) {
if (voices[i].keydown == false && voices[i].live == true) {
voices[i].live = false;
} }
index = index > 31 ? 31 : index;
unpackProgram(index);
lfo.reset(data + 137);
} }
index = index > 31 ? 31 : index; bypassVstChangeProgram = 1;
unpackProgram(index);
currentProgram = index; currentProgram = index;
lfo.reset(data + 137);
updateUI(); updateUI();
} }
@ -559,24 +555,65 @@ const String DexedAudioProcessor::getParameterText(int index) {
return ctrl[index]->getValueDisplay(); return ctrl[index]->getValueDisplay();
} }
struct PluginState {
uint8_t sysex[4011];
uint8_t program[161];
float cutoff;
float reso;
};
//============================================================================== //==============================================================================
void DexedAudioProcessor::getStateInformation(MemoryBlock& destData) { void DexedAudioProcessor::getStateInformation(MemoryBlock& destData) {
// You should use this method to store your parameters in the memory block. // You should use this method to store your parameters in the memory block.
// You could do that either as raw data, or use the XML or ValueTree classes // You could do that either as raw data, or use the XML or ValueTree classes
// as intermediaries to make it easy to save and load complex data.*/ // as intermediaries to make it easy to save and load complex data.
destData.insert(data, 161, 0);
// used to SAVE plugin state
PluginState state;
exportSysex((char *)(&state.sysex));
memcpy(state.program, data, 161);
state.cutoff = fx.uiCutoff;
state.reso = fx.uiReso;
destData.insert(&state, sizeof(PluginState), 0);
} }
void DexedAudioProcessor::setStateInformation(const void* source, void DexedAudioProcessor::setStateInformation(const void* source, int sizeInBytes) {
int sizeInBytes) {
// 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.
memcpy((void *) data, source, sizeInBytes);
// used to LOAD plugin state
PluginState state;
bypassVstChangeProgram = 0;
if ( sizeInBytes < sizeof(PluginState) ) {
TRACE("too small plugin state size %d", sizeInBytes);
return;
}
if ( sizeInBytes > sizeof(PluginState) ) {
TRACE("hmmm, too big plugin state size %d", sizeInBytes);
sizeInBytes = sizeof(PluginState);
}
memcpy((void *) &state, source, sizeInBytes);
importSysex((char *) state.sysex);
memcpy(data, state.program, 161);
fx.uiCutoff = state.cutoff;
fx.uiReso = state.reso;
// TODO: this should only be set if it is a VST
TRACE("setting VST STATE");
updateUI(); updateUI();
} }
//============================================================================== //==============================================================================
void DexedAudioProcessor::getCurrentProgramStateInformation( /*void DexedAudioProcessor::getCurrentProgramStateInformation(
MemoryBlock& destData) { MemoryBlock& destData) {
destData.insert(data, 161, 0); destData.insert(data, 161, 0);
} }
@ -585,5 +622,5 @@ void DexedAudioProcessor::setCurrentProgramStateInformation(const void* source,
int sizeInBytes) { int sizeInBytes) {
memcpy((void *) data, source, sizeInBytes); memcpy((void *) data, source, sizeInBytes);
updateUI(); updateUI();
} }*/

@ -80,11 +80,11 @@ public:
class CtrlDX : public Ctrl { class CtrlDX : public Ctrl {
int dxValue; int dxValue;
int steps; int steps;
int add1;
int dxOffset; int dxOffset;
int displayValue;
public: public:
CtrlDX(String name, int steps, int offset = -1, bool starts1 = false); CtrlDX(String name, int steps, int offset = -1, int displayValue = 0);
void setValueHost(float f); void setValueHost(float f);
float getValueHost(); float getValueHost();
void publishValue(float value); void publishValue(float value);

@ -47,6 +47,7 @@ DexedAudioProcessor::DexedAudioProcessor() {
initCtrl(); initCtrl();
setCurrentProgram(0); setCurrentProgram(0);
sendSysexChange = true; sendSysexChange = true;
bypassVstChangeProgram = 1;
} }
DexedAudioProcessor::~DexedAudioProcessor() { DexedAudioProcessor::~DexedAudioProcessor() {
@ -198,6 +199,7 @@ void DexedAudioProcessor::processMidiMessage(MidiMessage *msg) {
} }
TRACE("update 32bulk voice)"); TRACE("update 32bulk voice)");
importSysex((const char *)buf+4); importSysex((const char *)buf+4);
currentProgram = 0;
refreshUI |= REFRESH_COMP; refreshUI |= REFRESH_COMP;
} }
return; return;
@ -411,7 +413,6 @@ bool DexedAudioProcessor::hasEditor() const {
void DexedAudioProcessor::updateUI() { void DexedAudioProcessor::updateUI() {
AudioProcessorEditor *editor = getActiveEditor(); AudioProcessorEditor *editor = getActiveEditor();
if ( editor == NULL ) { if ( editor == NULL ) {
TRACE("no editor found!?");
return; return;
} }
DexedAudioProcessorEditor *dexedEditor = (DexedAudioProcessorEditor *) editor; DexedAudioProcessorEditor *dexedEditor = (DexedAudioProcessorEditor *) editor;

@ -64,6 +64,14 @@ class DexedAudioProcessor : public AudioProcessor
char sysex[4096]; char sysex[4096];
char patchNames[32][13]; char patchNames[32][13];
/**
* This flag is used to ignore change program when a VST chunk has been loaded.
* This is because the VST host will set the chunk value THEN change the program
* number. By doing this, it erase the current state of the program to the
* original one in the cartrige.
*/
bool bypassVstChangeProgram;
/** /**
* PlugFX * PlugFX
*/ */
@ -162,8 +170,9 @@ public :
//============================================================================== //==============================================================================
void getStateInformation (MemoryBlock& destData); void getStateInformation (MemoryBlock& destData);
void setStateInformation (const void* data, int sizeInBytes); void setStateInformation (const void* data, int sizeInBytes);
void getCurrentProgramStateInformation (MemoryBlock& destData);
void setCurrentProgramStateInformation (const void* data, int sizeInBytes); //void getCurrentProgramStateInformation (MemoryBlock& destData);
//void setCurrentProgramStateInformation (const void* data, int sizeInBytes);
//============================================================================== //==============================================================================
// this is kept up to date with the midi messages that arrive, and the UI component // this is kept up to date with the midi messages that arrive, and the UI component

Loading…
Cancel
Save