Merge pull request #17 from trylle/master
Issue #15 workaround and miscellaneous improvements
This commit is contained in:
commit
f4336c5e1e
6 changed files with 186 additions and 15 deletions
|
@ -797,6 +797,11 @@ PluginGui::PluginGui (JuceOplvstiAudioProcessor* ownerFilter)
|
||||||
keyscaleAttenuationComboBox->addItem ("-6.0", 4);
|
keyscaleAttenuationComboBox->addItem ("-6.0", 4);
|
||||||
keyscaleAttenuationComboBox->addListener (this);
|
keyscaleAttenuationComboBox->addListener (this);
|
||||||
|
|
||||||
|
addAndMakeVisible (groupComponent4 = new GroupComponent ("new group",
|
||||||
|
"Channels"));
|
||||||
|
groupComponent4->setTextLabelPosition (Justification::centredLeft);
|
||||||
|
groupComponent4->setColour (GroupComponent::outlineColourId, Colour (0xff007f00));
|
||||||
|
groupComponent4->setColour (GroupComponent::textColourId, Colour (0xff007f00));
|
||||||
|
|
||||||
//[UserPreSize]
|
//[UserPreSize]
|
||||||
frequencyComboBox->setColour (ComboBox::textColourId, Colour (COLOUR_MID));
|
frequencyComboBox->setColour (ComboBox::textColourId, Colour (COLOUR_MID));
|
||||||
|
@ -908,13 +913,29 @@ PluginGui::PluginGui (JuceOplvstiAudioProcessor* ownerFilter)
|
||||||
vibratoButton2->setColour(TextButton::buttonColourId, Colour(COLOUR_MID));
|
vibratoButton2->setColour(TextButton::buttonColourId, Colour(COLOUR_MID));
|
||||||
keyscaleEnvButton2->setColour(TextButton::buttonColourId, Colour(COLOUR_MID));
|
keyscaleEnvButton2->setColour(TextButton::buttonColourId, Colour(COLOUR_MID));
|
||||||
sustainButton2->setColour(TextButton::buttonColourId, Colour(COLOUR_MID));
|
sustainButton2->setColour(TextButton::buttonColourId, Colour(COLOUR_MID));
|
||||||
|
|
||||||
|
for (int i = 0; i < channels.size(); ++i)
|
||||||
|
{
|
||||||
|
ImageButton *channel=new ImageButton("new button");
|
||||||
|
|
||||||
|
addAndMakeVisible(channel);
|
||||||
|
channel->addListener(this);
|
||||||
|
|
||||||
|
channel->setImages(false, true, true,
|
||||||
|
ImageCache::getFromMemory(channeloff_png, channeloff_pngSize), 1.000f, Colour(0x00000000),
|
||||||
|
Image(), 1.000f, Colour(0x00000000),
|
||||||
|
ImageCache::getFromMemory(channelon_png, channelon_pngSize), 1.000f, Colour(0x00000000));
|
||||||
|
|
||||||
|
channels[i]=channel;
|
||||||
|
}
|
||||||
//[/UserPreSize]
|
//[/UserPreSize]
|
||||||
|
|
||||||
setSize (440, 810);
|
setSize (440, 874);
|
||||||
|
|
||||||
|
|
||||||
//[Constructor] You can add your own custom stuff here..
|
//[Constructor] You can add your own custom stuff here..
|
||||||
processor = ownerFilter;
|
processor = ownerFilter;
|
||||||
|
startTimer(1000/30);
|
||||||
//[/Constructor]
|
//[/Constructor]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -998,6 +1019,7 @@ PluginGui::~PluginGui()
|
||||||
dbLabel4 = nullptr;
|
dbLabel4 = nullptr;
|
||||||
keyscaleAttenuationComboBox2 = nullptr;
|
keyscaleAttenuationComboBox2 = nullptr;
|
||||||
keyscaleAttenuationComboBox = nullptr;
|
keyscaleAttenuationComboBox = nullptr;
|
||||||
|
groupComponent4 = nullptr;
|
||||||
|
|
||||||
|
|
||||||
//[Destructor]. You can add your own custom destruction code here..
|
//[Destructor]. You can add your own custom destruction code here..
|
||||||
|
@ -1093,7 +1115,10 @@ void PluginGui::resized()
|
||||||
dbLabel4->setBounds (336, 440, 72, 16);
|
dbLabel4->setBounds (336, 440, 72, 16);
|
||||||
keyscaleAttenuationComboBox2->setBounds (264, 432, 72, 24);
|
keyscaleAttenuationComboBox2->setBounds (264, 432, 72, 24);
|
||||||
keyscaleAttenuationComboBox->setBounds (264, 88, 72, 24);
|
keyscaleAttenuationComboBox->setBounds (264, 88, 72, 24);
|
||||||
|
groupComponent4->setBounds (16, 800, 408, 64);
|
||||||
//[UserResized] Add your own custom resize handling here..
|
//[UserResized] Add your own custom resize handling here..
|
||||||
|
for (int i = 0; i < channels.size(); ++i)
|
||||||
|
channels[i]->setBounds(32+24*i+4, 824+4, 16, 16);
|
||||||
//[/UserResized]
|
//[/UserResized]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1431,6 +1456,12 @@ void PluginGui::buttonClicked (Button* buttonThatWasClicked)
|
||||||
processor->loadInstrumentFromFile(files[0]);
|
processor->loadInstrumentFromFile(files[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PluginGui::timerCallback()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Hiopl::CHANNELS; ++i)
|
||||||
|
channels[i]->setState(processor->isChannelActive(i+1) ? Button::buttonDown : Button::buttonNormal);
|
||||||
|
}
|
||||||
//[/MiscUserCode]
|
//[/MiscUserCode]
|
||||||
|
|
||||||
|
|
||||||
|
@ -1444,10 +1475,10 @@ void PluginGui::buttonClicked (Button* buttonThatWasClicked)
|
||||||
BEGIN_JUCER_METADATA
|
BEGIN_JUCER_METADATA
|
||||||
|
|
||||||
<JUCER_COMPONENT documentType="Component" className="PluginGui" componentName=""
|
<JUCER_COMPONENT documentType="Component" className="PluginGui" componentName=""
|
||||||
parentClasses="public AudioProcessorEditor, public FileDragAndDropTarget, public DragAndDropContainer"
|
parentClasses="public AudioProcessorEditor, public FileDragAndDropTarget, public DragAndDropContainer, public Timer"
|
||||||
constructorParams="JuceOplvstiAudioProcessor* ownerFilter" variableInitialisers=" AudioProcessorEditor (ownerFilter)"
|
constructorParams="JuceOplvstiAudioProcessor* ownerFilter" variableInitialisers=" AudioProcessorEditor (ownerFilter)"
|
||||||
snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.33"
|
snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.33"
|
||||||
fixedSize="0" initialWidth="440" initialHeight="810">
|
fixedSize="0" initialWidth="440" initialHeight="874">
|
||||||
<BACKGROUND backgroundColour="ff000000"/>
|
<BACKGROUND backgroundColour="ff000000"/>
|
||||||
<GROUPCOMPONENT name="new group" id="d2c7c07bf2d78c30" memberName="groupComponent"
|
<GROUPCOMPONENT name="new group" id="d2c7c07bf2d78c30" memberName="groupComponent"
|
||||||
virtualName="" explicitFocusOrder="0" pos="16 8 408 336" outlinecol="ff007f00"
|
virtualName="" explicitFocusOrder="0" pos="16 8 408 336" outlinecol="ff007f00"
|
||||||
|
@ -1829,6 +1860,9 @@ BEGIN_JUCER_METADATA
|
||||||
virtualName="" explicitFocusOrder="0" pos="264 88 72 24" editable="0"
|
virtualName="" explicitFocusOrder="0" pos="264 88 72 24" editable="0"
|
||||||
layout="33" items="-0.0 -3.0 -1.5 -6.0" textWhenNonSelected=""
|
layout="33" items="-0.0 -3.0 -1.5 -6.0" textWhenNonSelected=""
|
||||||
textWhenNoItems="(no choices)"/>
|
textWhenNoItems="(no choices)"/>
|
||||||
|
<GROUPCOMPONENT name="new group" id="52f9803abb342980" memberName="groupComponent4"
|
||||||
|
virtualName="" explicitFocusOrder="0" pos="16 800 408 64" outlinecol="ff007f00"
|
||||||
|
textcol="ff007f00" title="Channels" textpos="33"/>
|
||||||
</JUCER_COMPONENT>
|
</JUCER_COMPONENT>
|
||||||
|
|
||||||
END_JUCER_METADATA
|
END_JUCER_METADATA
|
||||||
|
@ -1910,6 +1944,30 @@ static const unsigned char resource_PluginGui_logarithmic_saw_png[] = { 137,80,7
|
||||||
const char* PluginGui::logarithmic_saw_png = (const char*) resource_PluginGui_logarithmic_saw_png;
|
const char* PluginGui::logarithmic_saw_png = (const char*) resource_PluginGui_logarithmic_saw_png;
|
||||||
const int PluginGui::logarithmic_saw_pngSize = 206;
|
const int PluginGui::logarithmic_saw_pngSize = 206;
|
||||||
|
|
||||||
|
// JUCER_RESOURCE: channeloff_png, 414, "../img/channeloff.png"
|
||||||
|
static const unsigned char resource_PluginGui_channeloff_png[] = { 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,
|
||||||
|
0,0,0,9,112,72,89,115,0,0,11,19,0,0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,222,8,25,20,6,56,156,246,144,159,0,0,0,29,105,84,88,116,67,111,109,109,101,110,116,0,0,0,0,0,67,114,101,97,116,101,100,32,
|
||||||
|
119,105,116,104,32,71,73,77,80,100,46,101,7,0,0,1,2,73,68,65,84,56,203,165,211,61,78,66,65,20,5,224,143,193,82,119,224,62,104,40,166,196,194,202,10,66,65,137,149,75,120,121,193,21,216,104,108,164,32,178,
|
||||||
|
128,183,1,94,66,67,66,172,172,140,27,176,178,192,202,70,139,55,26,2,138,2,39,153,102,230,220,159,185,231,220,154,85,100,14,113,138,46,154,233,118,138,17,10,185,183,101,122,88,9,110,99,129,11,20,104,164,
|
||||||
|
83,164,187,69,226,252,128,204,64,230,67,166,239,55,100,250,137,51,176,86,185,122,104,249,11,153,86,226,182,161,150,254,188,192,185,220,141,255,160,234,242,26,71,117,209,25,142,229,27,90,95,69,105,46,58,
|
||||||
|
193,107,72,211,30,218,30,67,116,67,146,106,178,67,130,9,154,193,158,8,201,36,113,135,216,136,105,72,14,235,237,144,160,135,81,248,118,92,182,133,10,21,183,129,162,174,244,46,122,194,157,104,166,244,252,
|
||||||
|
167,145,24,163,35,247,80,79,186,62,138,14,112,43,122,81,154,111,168,60,198,165,220,85,229,196,245,101,186,199,44,233,60,89,26,88,47,181,221,145,27,127,133,212,246,93,231,79,44,229,73,181,37,137,229,213,
|
||||||
|
0,0,0,0,73,69,78,68,174,66,96,130,0,0};
|
||||||
|
|
||||||
|
const char* PluginGui::channeloff_png = (const char*) resource_PluginGui_channeloff_png;
|
||||||
|
const int PluginGui::channeloff_pngSize = 414;
|
||||||
|
|
||||||
|
// JUCER_RESOURCE: channelon_png, 326, "../img/channelon.png"
|
||||||
|
static const unsigned char resource_PluginGui_channelon_png[] = { 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,
|
||||||
|
0,0,0,9,112,72,89,115,0,0,11,19,0,0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,222,8,25,20,6,39,17,254,157,106,0,0,0,29,105,84,88,116,67,111,109,109,101,110,116,0,0,0,0,0,67,114,101,97,116,101,100,32,
|
||||||
|
119,105,116,104,32,71,73,77,80,100,46,101,7,0,0,0,170,73,68,65,84,56,203,173,147,177,13,194,48,16,69,159,143,148,176,81,20,101,129,84,84,68,217,5,89,176,0,204,16,193,0,30,0,69,202,8,169,88,131,12,64,145,
|
||||||
|
139,176,82,64,116,230,117,182,252,206,242,249,159,99,201,145,45,80,1,13,144,235,110,15,180,64,192,51,198,199,221,66,62,0,55,190,83,227,185,207,139,77,36,159,128,11,191,217,83,146,209,241,248,20,152,110,
|
||||||
|
94,35,207,20,148,60,233,24,156,190,249,133,141,157,104,195,172,84,162,221,182,210,72,244,85,22,114,33,17,209,144,88,233,69,19,102,165,21,32,36,20,8,162,217,174,13,114,141,103,156,146,216,49,80,146,1,197,
|
||||||
|
74,249,140,231,250,151,97,114,169,227,252,6,230,208,38,246,228,75,209,233,0,0,0,0,73,69,78,68,174,66,96,130,0,0};
|
||||||
|
|
||||||
|
const char* PluginGui::channelon_png = (const char*) resource_PluginGui_channelon_png;
|
||||||
|
const int PluginGui::channelon_pngSize = 326;
|
||||||
|
|
||||||
|
|
||||||
//[EndFile] You can add extra defines here...
|
//[EndFile] You can add extra defines here...
|
||||||
//[/EndFile]
|
//[/EndFile]
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define __JUCE_HEADER_450C07F5C14097B8__
|
#define __JUCE_HEADER_450C07F5C14097B8__
|
||||||
|
|
||||||
//[Headers] -- You can add your own extra header files here --
|
//[Headers] -- You can add your own extra header files here --
|
||||||
|
#include <array>
|
||||||
#include "JuceHeader.h"
|
#include "JuceHeader.h"
|
||||||
#include "PluginProcessor.h"
|
#include "PluginProcessor.h"
|
||||||
//[/Headers]
|
//[/Headers]
|
||||||
|
@ -36,6 +37,7 @@
|
||||||
class PluginGui : public AudioProcessorEditor,
|
class PluginGui : public AudioProcessorEditor,
|
||||||
public FileDragAndDropTarget,
|
public FileDragAndDropTarget,
|
||||||
public DragAndDropContainer,
|
public DragAndDropContainer,
|
||||||
|
public Timer,
|
||||||
public ComboBoxListener,
|
public ComboBoxListener,
|
||||||
public SliderListener,
|
public SliderListener,
|
||||||
public ButtonListener
|
public ButtonListener
|
||||||
|
@ -53,6 +55,7 @@ public:
|
||||||
void fileDragMove (const StringArray& files, int x, int y);
|
void fileDragMove (const StringArray& files, int x, int y);
|
||||||
void fileDragExit (const StringArray& files);
|
void fileDragExit (const StringArray& files);
|
||||||
void filesDropped (const StringArray& files, int x, int y);
|
void filesDropped (const StringArray& files, int x, int y);
|
||||||
|
void timerCallback();
|
||||||
//[/UserMethods]
|
//[/UserMethods]
|
||||||
|
|
||||||
void paint (Graphics& g);
|
void paint (Graphics& g);
|
||||||
|
@ -78,12 +81,17 @@ public:
|
||||||
static const int square_pngSize;
|
static const int square_pngSize;
|
||||||
static const char* logarithmic_saw_png;
|
static const char* logarithmic_saw_png;
|
||||||
static const int logarithmic_saw_pngSize;
|
static const int logarithmic_saw_pngSize;
|
||||||
|
static const char* channeloff_png;
|
||||||
|
static const int channeloff_pngSize;
|
||||||
|
static const char* channelon_png;
|
||||||
|
static const int channelon_pngSize;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//[UserVariables] -- You can add your own custom variables in this section.
|
//[UserVariables] -- You can add your own custom variables in this section.
|
||||||
static const uint32 COLOUR_MID = 0xff007f00;
|
static const uint32 COLOUR_MID = 0xff007f00;
|
||||||
JuceOplvstiAudioProcessor* processor;
|
JuceOplvstiAudioProcessor* processor;
|
||||||
|
std::array<ScopedPointer<ImageButton>, Hiopl::CHANNELS> channels;
|
||||||
//[/UserVariables]
|
//[/UserVariables]
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
@ -162,6 +170,7 @@ private:
|
||||||
ScopedPointer<Label> dbLabel4;
|
ScopedPointer<Label> dbLabel4;
|
||||||
ScopedPointer<ComboBox> keyscaleAttenuationComboBox2;
|
ScopedPointer<ComboBox> keyscaleAttenuationComboBox2;
|
||||||
ScopedPointer<ComboBox> keyscaleAttenuationComboBox;
|
ScopedPointer<ComboBox> keyscaleAttenuationComboBox;
|
||||||
|
ScopedPointer<GroupComponent> groupComponent4;
|
||||||
|
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
|
@ -4,8 +4,11 @@
|
||||||
#include "IntFloatParameter.h"
|
#include "IntFloatParameter.h"
|
||||||
#include "SbiLoader.h"
|
#include "SbiLoader.h"
|
||||||
|
|
||||||
|
const char *JuceOplvstiAudioProcessor::PROGRAM_INDEX = "Program Index";
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
JuceOplvstiAudioProcessor::JuceOplvstiAudioProcessor()
|
JuceOplvstiAudioProcessor::JuceOplvstiAudioProcessor()
|
||||||
|
: i_program(-1)
|
||||||
{
|
{
|
||||||
// Initalize OPL
|
// Initalize OPL
|
||||||
velocity = false;
|
velocity = false;
|
||||||
|
@ -121,6 +124,9 @@ JuceOplvstiAudioProcessor::JuceOplvstiAudioProcessor()
|
||||||
active_notes[i] = NO_NOTE;
|
active_notes[i] = NO_NOTE;
|
||||||
}
|
}
|
||||||
currentScaledBend = 1.0f;
|
currentScaledBend = 1.0f;
|
||||||
|
|
||||||
|
for (int i = 1; i <= Hiopl::CHANNELS; ++i)
|
||||||
|
available_channels.push_back(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JuceOplvstiAudioProcessor::initPrograms()
|
void JuceOplvstiAudioProcessor::initPrograms()
|
||||||
|
@ -380,6 +386,8 @@ void JuceOplvstiAudioProcessor::applyPitchBend()
|
||||||
|
|
||||||
JuceOplvstiAudioProcessor::~JuceOplvstiAudioProcessor()
|
JuceOplvstiAudioProcessor::~JuceOplvstiAudioProcessor()
|
||||||
{
|
{
|
||||||
|
for (int i=0; i < params.size(); ++i)
|
||||||
|
delete params[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
@ -598,6 +606,9 @@ void JuceOplvstiAudioProcessor::updateGuiIfPresent()
|
||||||
|
|
||||||
void JuceOplvstiAudioProcessor::setCurrentProgram (int index)
|
void JuceOplvstiAudioProcessor::setCurrentProgram (int index)
|
||||||
{
|
{
|
||||||
|
if (i_program==index)
|
||||||
|
return;
|
||||||
|
|
||||||
i_program = index;
|
i_program = index;
|
||||||
std::vector<float> &v_params = programs[getProgramName(index)];
|
std::vector<float> &v_params = programs[getProgramName(index)];
|
||||||
for (unsigned int i = 0; i < params.size() && i < v_params.size(); i++) {
|
for (unsigned int i = 0; i < params.size() && i < v_params.size(); i++) {
|
||||||
|
@ -634,7 +645,7 @@ void JuceOplvstiAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuf
|
||||||
buffer.clear(0, 0, buffer.getNumSamples());
|
buffer.clear(0, 0, buffer.getNumSamples());
|
||||||
MidiBuffer::Iterator midi_buffer_iterator(midiMessages);
|
MidiBuffer::Iterator midi_buffer_iterator(midiMessages);
|
||||||
|
|
||||||
MidiMessage midi_message(0);
|
MidiMessage midi_message;
|
||||||
int sample_number;
|
int sample_number;
|
||||||
while (midi_buffer_iterator.getNextEvent(midi_message,sample_number)) {
|
while (midi_buffer_iterator.getNextEvent(midi_message,sample_number)) {
|
||||||
if (midi_message.isNoteOn()) {
|
if (midi_message.isNoteOn()) {
|
||||||
|
@ -642,10 +653,22 @@ void JuceOplvstiAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuf
|
||||||
//the beginning of the current buffer
|
//the beginning of the current buffer
|
||||||
int n = midi_message.getNoteNumber();
|
int n = midi_message.getNoteNumber();
|
||||||
float noteHz = (float)MidiMessage::getMidiNoteInHertz(n);
|
float noteHz = (float)MidiMessage::getMidiNoteInHertz(n);
|
||||||
int ch = 1;
|
int ch;
|
||||||
while (ch <= Hiopl::CHANNELS && NO_NOTE != active_notes[ch]) {
|
|
||||||
ch += 1;
|
if (!available_channels.empty())
|
||||||
|
{
|
||||||
|
ch = available_channels.front();
|
||||||
|
available_channels.pop_front();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ch = used_channels.back(); // steal earliest/longest running active channel if out of free channels
|
||||||
|
used_channels.pop_back();
|
||||||
|
Opl->KeyOff(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
used_channels.push_front(ch);
|
||||||
|
|
||||||
switch (getEnumParameter("Carrier Velocity Sensitivity")) {
|
switch (getEnumParameter("Carrier Velocity Sensitivity")) {
|
||||||
case 0:
|
case 0:
|
||||||
Opl->SetAttenuation(ch, 2, getEnumParameter("Carrier Attenuation"));
|
Opl->SetAttenuation(ch, 2, getEnumParameter("Carrier Attenuation"));
|
||||||
|
@ -678,8 +701,22 @@ void JuceOplvstiAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuf
|
||||||
while (ch <= Hiopl::CHANNELS && n != active_notes[ch]) {
|
while (ch <= Hiopl::CHANNELS && n != active_notes[ch]) {
|
||||||
ch += 1;
|
ch += 1;
|
||||||
}
|
}
|
||||||
Opl->KeyOff(ch);
|
if (ch <= Hiopl::CHANNELS)
|
||||||
active_notes[ch] = NO_NOTE;
|
{
|
||||||
|
for (auto i = used_channels.begin(); i != used_channels.end(); ++i)
|
||||||
|
{
|
||||||
|
if (*i == ch)
|
||||||
|
{
|
||||||
|
used_channels.erase(i);
|
||||||
|
available_channels.push_back(ch);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Opl->KeyOff(ch);
|
||||||
|
active_notes[ch]=NO_NOTE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (midi_message.isPitchWheel()) {
|
else if (midi_message.isPitchWheel()) {
|
||||||
int bend = midi_message.getPitchWheelValue() - 0x2000; // range -8192 to 8191
|
int bend = midi_message.getPitchWheelValue() - 0x2000; // range -8192 to 8191
|
||||||
|
@ -705,21 +742,82 @@ AudioProcessorEditor* JuceOplvstiAudioProcessor::createEditor()
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void JuceOplvstiAudioProcessor::getStateInformation (MemoryBlock& destData)
|
|
||||||
|
// JUCE requires that JSON names are valid Identifiers (restricted character set) even though the JSON standard allows any valid string.
|
||||||
|
// Per http://www.juce.com/forum/topic/problem-spaces-json-identifier jules allowed Strings to bypass the assertion check
|
||||||
|
// but a regression occured in 4317f60 re-enabling this check, so we need to sanitize the names.
|
||||||
|
// Technically, the code still works without this, but it will trigger a gargantuan number of assertions hindering effective debugging.
|
||||||
|
Identifier stringToIdentifier(const String &s)
|
||||||
{
|
{
|
||||||
destData.ensureSize(sizeof(float) * getNumParameters());
|
return s.replaceCharacters(" ", "_");
|
||||||
|
}
|
||||||
|
|
||||||
|
void JuceOplvstiAudioProcessor::getStateInformation(MemoryBlock& destData)
|
||||||
|
{
|
||||||
|
ReferenceCountedObjectPtr<DynamicObject> v(new DynamicObject);
|
||||||
|
|
||||||
|
v->setProperty(stringToIdentifier(PROGRAM_INDEX), i_program);
|
||||||
|
|
||||||
for (int i = 0; i < getNumParameters(); i++) {
|
for (int i = 0; i < getNumParameters(); i++) {
|
||||||
float p = getParameter(i);
|
double p = getParameter(i);
|
||||||
destData.copyFrom((void*)&p, i*sizeof(float), sizeof(float));
|
|
||||||
|
v->setProperty(stringToIdentifier(getParameterName(i)), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String s = JSON::toString(v.get());
|
||||||
|
|
||||||
|
destData.setSize(s.length());
|
||||||
|
destData.copyFrom(s.getCharPointer(), 0, destData.getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
void JuceOplvstiAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
|
void JuceOplvstiAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
|
||||||
{
|
{
|
||||||
|
if (sizeInBytes < 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const char *first = static_cast<const char *>(data);
|
||||||
|
const char *last = first + sizeInBytes - 1;
|
||||||
|
|
||||||
|
// simple check for JSON data - assume always object
|
||||||
|
if (*first=='{' && *last=='}')
|
||||||
|
{
|
||||||
|
// json format
|
||||||
|
String s(first, sizeInBytes);
|
||||||
|
var v = JSON::fromString(s);
|
||||||
|
|
||||||
|
{
|
||||||
|
var program = v[stringToIdentifier(PROGRAM_INDEX)];
|
||||||
|
|
||||||
|
if (!program.isVoid())
|
||||||
|
i_program = program;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<getNumParameters(); ++i)
|
||||||
|
{
|
||||||
|
var param = v[stringToIdentifier(getParameterName(i))];
|
||||||
|
|
||||||
|
if (!param.isVoid())
|
||||||
|
setParameter(i, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateGuiIfPresent();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
float* fdata = (float*)data;
|
float* fdata = (float*)data;
|
||||||
for (unsigned int i = 0; i < sizeInBytes / sizeof(float); i++) {
|
const int parametersToLoad = std::min<int>(sizeInBytes / sizeof(float), getNumParameters());
|
||||||
|
|
||||||
|
for (int i = 0; i < parametersToLoad; i++) {
|
||||||
setParameter(i, fdata[i]);
|
setParameter(i, fdata[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @param idx 1-based channel index
|
||||||
|
// @note since this is just reading off pod, "safe" to access without a mutex by other threads such as GUI
|
||||||
|
int JuceOplvstiAudioProcessor::isChannelActive(int idx) const
|
||||||
|
{
|
||||||
|
return active_notes[idx] != NO_NOTE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#ifndef PLUGINPROCESSOR_H_INCLUDED
|
#ifndef PLUGINPROCESSOR_H_INCLUDED
|
||||||
#define PLUGINPROCESSOR_H_INCLUDED
|
#define PLUGINPROCESSOR_H_INCLUDED
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
#include "../JuceLibraryCode/JuceHeader.h"
|
#include "../JuceLibraryCode/JuceHeader.h"
|
||||||
#include "hiopl.h"
|
#include "hiopl.h"
|
||||||
#include "FloatParameter.h"
|
#include "FloatParameter.h"
|
||||||
|
@ -53,6 +54,8 @@ public:
|
||||||
void loadInstrumentFromFile(String filename);
|
void loadInstrumentFromFile(String filename);
|
||||||
void setParametersByRegister(int register_base, int op, uint8 value);
|
void setParametersByRegister(int register_base, int op, uint8 value);
|
||||||
|
|
||||||
|
int isChannelActive(int idx) const;
|
||||||
|
|
||||||
void updateGuiIfPresent();
|
void updateGuiIfPresent();
|
||||||
|
|
||||||
const String getParameterName (int index);
|
const String getParameterName (int index);
|
||||||
|
@ -88,7 +91,10 @@ private:
|
||||||
int i_program;
|
int i_program;
|
||||||
bool velocity;
|
bool velocity;
|
||||||
static const int NO_NOTE=-1;
|
static const int NO_NOTE=-1;
|
||||||
|
static const char *PROGRAM_INDEX;
|
||||||
int active_notes[Hiopl::CHANNELS+1]; // keyed by channel
|
int active_notes[Hiopl::CHANNELS+1]; // keyed by channel
|
||||||
|
std::deque<int> available_channels; // most recently freed at end
|
||||||
|
std::deque<int> used_channels; // most recently used at end
|
||||||
float currentScaledBend;
|
float currentScaledBend;
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
BIN
img/channeloff.png
Normal file
BIN
img/channeloff.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 414 B |
BIN
img/channelon.png
Normal file
BIN
img/channelon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 326 B |
Loading…
Reference in a new issue