Added code

This commit is contained in:
除村 武志
2020-02-26 17:13:02 +09:00
parent 64dcb731c2
commit 941a120dea
126 changed files with 19555 additions and 1 deletions

View File

@ -0,0 +1,163 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "AdvancedParamsComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
AdvancedParamsComponent::AdvancedParamsComponent (Magical8bitPlug2AudioProcessor& p)
: processor(p)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
volumeCompo.reset (new CustomEnvelopeComponent (p, "volume", "Volume", "isVolumeSequenceEnabled_raw"));
addAndMakeVisible (volumeCompo.get());
volumeCompo->setName ("volume component");
label5.reset (new Label ("new label",
TRANS("Custom Envelopes")));
addAndMakeVisible (label5.get());
label5->setFont (Font (17.00f, Font::plain).withTypefaceStyle ("Regular"));
label5->setJustificationType (Justification::centredLeft);
label5->setEditable (false, false, false);
label5->setColour (TextEditor::textColourId, Colours::black);
label5->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
label5->setBounds (0, 4, 150, 24);
pitchCompo.reset (new CustomEnvelopeComponent (p, "pitch", "Pitch", "isPitchSequenceEnabled_raw"));
addAndMakeVisible (pitchCompo.get());
pitchCompo->setName ("pitch component");
dutyCompo.reset (new CustomEnvelopeComponent (p, "duty", "Duty", "isDutySequenceEnabled_raw"));
addAndMakeVisible (dutyCompo.get());
dutyCompo->setName ("duty component");
coarseOrFineChoice.reset (new ChoiceComponent (p, "pitchSequenceMode_raw", "Resolution"));
addAndMakeVisible (coarseOrFineChoice.get());
coarseOrFineChoice->setName ("Coarse or fine");
//[UserPreSize]
//[/UserPreSize]
setSize (700, 216);
//[Constructor] You can add your own custom stuff here..
p.settingRefs.volumeSequenceListener = (FrameSequenceChangeListener*)volumeCompo.get();
p.settingRefs.pitchSequenceListener = (FrameSequenceChangeListener*)pitchCompo.get();
p.settingRefs.dutySequenceListener = (FrameSequenceChangeListener*)dutyCompo.get();
//[/Constructor]
}
AdvancedParamsComponent::~AdvancedParamsComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
//[/Destructor_pre]
volumeCompo = nullptr;
label5 = nullptr;
pitchCompo = nullptr;
dutyCompo = nullptr;
coarseOrFineChoice = nullptr;
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]
}
//==============================================================================
void AdvancedParamsComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void AdvancedParamsComponent::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
volumeCompo->setBounds (0, 26, getWidth() - 160, 56);
pitchCompo->setBounds (0, 82, getWidth() - 204, 56);
dutyCompo->setBounds (0, 138, getWidth() - 160, 56);
coarseOrFineChoice->setBounds (getWidth() - 4 - 200, 86, 200, 28);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Projucer information section --
This is where the Projucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="AdvancedParamsComponent"
componentName="" parentClasses="public Component" constructorParams="Magical8bitPlug2AudioProcessor&amp; p"
variableInitialisers="processor(p)" snapPixels="8" snapActive="1"
snapShown="1" overlayOpacity="0.330" fixedSize="1" initialWidth="700"
initialHeight="216">
<BACKGROUND backgroundColour="ffffff"/>
<GENERICCOMPONENT name="volume component" id="829adedfc4b9300f" memberName="volumeCompo"
virtualName="" explicitFocusOrder="0" pos="0 26 160M 56" class="CustomEnvelopeComponent"
params="p, &quot;volume&quot;, &quot;Volume&quot;, &quot;isVolumeSequenceEnabled_raw&quot;"/>
<LABEL name="new label" id="bae3132bcad681ce" memberName="label5" virtualName=""
explicitFocusOrder="0" pos="0 4 150 24" edTextCol="ff000000"
edBkgCol="0" labelText="Custom Envelopes" editableSingleClick="0"
editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font"
fontsize="17.0" kerning="0.0" bold="0" italic="0" justification="33"/>
<GENERICCOMPONENT name="pitch component" id="30dd6e142bdc9ed5" memberName="pitchCompo"
virtualName="" explicitFocusOrder="0" pos="0 82 204M 56" class="CustomEnvelopeComponent"
params="p, &quot;pitch&quot;, &quot;Pitch&quot;, &quot;isPitchSequenceEnabled_raw&quot;"/>
<GENERICCOMPONENT name="duty component" id="e5e04cf3ca5aec1" memberName="dutyCompo"
virtualName="" explicitFocusOrder="0" pos="0 138 160M 56" class="CustomEnvelopeComponent"
params="p, &quot;duty&quot;, &quot;Duty&quot;, &quot;isDutySequenceEnabled_raw&quot;"/>
<GENERICCOMPONENT name="Coarse or fine" id="950de1eb69e47c4c" memberName="coarseOrFineChoice"
virtualName="" explicitFocusOrder="0" pos="4Rr 86 200 28" class="ChoiceComponent"
params="p, &quot;pitchSequenceMode_raw&quot;, &quot;Resolution&quot;"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -0,0 +1,73 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
#pragma once
//[Headers] -- You can add your own extra header files here --
#include "../JuceLibraryCode/JuceHeader.h"
#include "CustomEnvelopeComponent.h"
#include "ChoiceComponent.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Projucer.
Describe your class and how it works here!
//[/Comments]
*/
class AdvancedParamsComponent : public Component
{
public:
//==============================================================================
AdvancedParamsComponent (Magical8bitPlug2AudioProcessor& p);
~AdvancedParamsComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
//[/UserMethods]
void paint (Graphics& g) override;
void resized() override;
private:
//[UserVariables] -- You can add your own custom variables in this section.
Magical8bitPlug2AudioProcessor& processor;
//[/UserVariables]
//==============================================================================
std::unique_ptr<CustomEnvelopeComponent> volumeCompo;
std::unique_ptr<Label> label5;
std::unique_ptr<CustomEnvelopeComponent> pitchCompo;
std::unique_ptr<CustomEnvelopeComponent> dutyCompo;
std::unique_ptr<ChoiceComponent> coarseOrFineChoice;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AdvancedParamsComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

226
Source/BaseVoice.cpp Normal file
View File

@ -0,0 +1,226 @@
/*
==============================================================================
BaseVoice.cpp
Created: 11 Nov 2019 9:38:44pm
Author: 除村 武志
==============================================================================
*/
#include "BaseVoice.h"
//---------------------------------------------
//
// Base Voice
// (Abstract)
//
//---------------------------------------------
BaseVoice::BaseVoice (SettingRefs* sRefs)
{
settingRefs = sRefs;
}
bool BaseVoice::canPlaySound (SynthesiserSound* sound)
{
return true;
}
void BaseVoice::startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int currentPitchBendPosition)
{
noteNumber = midiNoteNumber;
envelopePhase = kEnvelopePhaseA;
currentAngle = 0.0;
currentEnvelopeLevel = 0.0;
ampByVelocityAndGain = * (settingRefs->gain) * velocity; // velocity value range is 0.0f-1.0f
calculateAngleDelta();
//
// Envelope
//
double srate = getSampleRate();
if (* (settingRefs->attack) == 0 ) { attack_slope = 1.0; }
else
{
attack_slope = 1.0 / (* (settingRefs->attack) * srate);
}
if (* (settingRefs->decay) == 0 ) { decay_slope = 1.0; }
else
{
decay_slope = 1.0 / (* (settingRefs->decay) * srate);
}
sustain_level = * (settingRefs->suslevel);
if (* (settingRefs->release) == 0 ) { release_slope = 1.0; }
else
{
release_slope = 1.0 / (* (settingRefs->release) * srate);
}
//
// Control frame
//
controlFrameTimer = 0;
currentVolumeSequenceFrame = 0;
if (settingRefs->isVolumeSequenceEnabled())
{
currentEnvelopeLevel = (float) (settingRefs->volumeSequence.valueAt (0)) / 15.0f;
}
}
void BaseVoice::stopNote (float, bool allowTailOff)
{
if (!allowTailOff)
{
clearCurrentNote();
angleDelta = 0.0;
return;
}
if (settingRefs->isVolumeSequenceEnabled())
{
if (settingRefs->volumeSequence.hasRelease)
{
currentVolumeSequenceFrame = settingRefs->volumeSequence.releaseSequenceStartIndex;
currentEnvelopeLevel = (float) (settingRefs->volumeSequence.valueAt (0)) / 15.0f;
}
else
{
clearCurrentNote();
angleDelta = 0.0;
}
return;
}
envelopePhase = kEnvelopePhaseR;
}
void BaseVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples)
{
if (angleDelta == 0.0)
{
return;
}
while (--numSamples >= 0)
{
//
// Envelope
//
if (settingRefs->isVolumeSequenceEnabled())
{
currentEnvelopeLevel = (float) (settingRefs->volumeSequence.valueAt (currentVolumeSequenceFrame)) / 15.0f;
}
else
{
switch (envelopePhase)
{
case kEnvelopePhaseA:
currentEnvelopeLevel += attack_slope;
if (currentEnvelopeLevel > 1.0)
{
currentEnvelopeLevel = 1.0;
envelopePhase = kEnvelopePhaseD;
}
break;
case kEnvelopePhaseD:
currentEnvelopeLevel -= decay_slope;
if (currentEnvelopeLevel < sustain_level)
{
envelopePhase = kEnvelopePhaseS;
currentEnvelopeLevel = sustain_level;
}
break;
case kEnvelopePhaseS:
currentEnvelopeLevel = sustain_level;
break;
case kEnvelopePhaseR:
currentEnvelopeLevel -= release_slope;
if (currentEnvelopeLevel < 0)
{
currentEnvelopeLevel = 0;
clearCurrentNote();
angleDelta = 0.0;
}
break;
}
}
//
// Write to buffer
//
float currentSample = voltageForAngle (currentAngle) * currentEnvelopeLevel * ampByVelocityAndGain;
for (auto i = outputBuffer.getNumChannels(); --i >= 0;)
outputBuffer.addSample (i, startSample, currentSample);
//
// Advance phase
//
calculateAngleDelta();
currentAngle += angleDelta;
while (currentAngle > 2.0 * MathConstants<float>::pi)
{
currentAngle -= 2.0 * MathConstants<float>::pi;
}
//
// Advance control frame
//
controlFrameTimer += 1.0 / getSampleRate();
if (controlFrameTimer >= controlFrameLength)
{
advanceControlFrame();
while (controlFrameTimer >= controlFrameLength)
{
controlFrameTimer -= controlFrameLength;
}
}
onFrameAdvanced();
++startSample;
}
}
void BaseVoice::calculateAngleDelta()
{
auto cyclesPerSecond = MidiMessage::getMidiNoteInHertz (noteNumber);
auto cyclesPerSample = cyclesPerSecond / getSampleRate();
angleDelta = cyclesPerSample * 2.0 * MathConstants<double>::pi;
}
void BaseVoice::advanceControlFrame()
{
currentVolumeSequenceFrame = settingRefs->volumeSequence.nextIndexOf (currentVolumeSequenceFrame);
if (currentVolumeSequenceFrame == FrameSequence::SHOULD_RETIRE)
{
currentEnvelopeLevel = 0;
clearCurrentNote();
angleDelta = 0.0;
}
}

54
Source/BaseVoice.h Normal file
View File

@ -0,0 +1,54 @@
/*
==============================================================================
BaseVoice.h
Created: 11 Nov 2019 9:38:44pm
Author: 除村 武志
==============================================================================
*/
#pragma once
#include "Voices.h"
struct BaseVoice : public SynthesiserVoice
{
SettingRefs* settingRefs;
BaseVoice (SettingRefs* sRefs);
bool canPlaySound (SynthesiserSound* sound) override;
void startNote (int midiNoteNumber, float velocity,
SynthesiserSound*, int currentPitchWheelPosition) override;
void stopNote (float /*velocity*/, bool allowTailOff) override;
void pitchWheelMoved (int) override {}
void controllerMoved (int, int) override {}
void renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples) override;
virtual float voltageForAngle (double angle) = 0;
virtual void onFrameAdvanced() {};
virtual void advanceControlFrame();
virtual void calculateAngleDelta();
protected:
// Basic
int noteNumber;
float ampByVelocityAndGain = 1.0;
// Oscillator State
double currentAngle = 0.0;
double angleDelta = 0.0;
// Envelope
double currentEnvelopeLevel = 0.0;
EnvelopePhase envelopePhase = kEnvelopePhaseA;
double attack_slope = 1.0;
double decay_slope = 0.0; // Positive to decrease
double sustain_level = 1.0;
double release_slope = 1.0; // Positive to decrease
// For Frame Counting for Customs
double controlFrameTimer = 0;
const double controlFrameLength = 1.0 / 60.0;
int currentVolumeSequenceFrame = 0;
};

View File

@ -0,0 +1,215 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
#include "PluginEditor.h"
//[/Headers]
#include "BasicParamsComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
BasicParamsComponent::BasicParamsComponent (Magical8bitPlug2AudioProcessor& p, Magical8bitPlug2AudioProcessorEditor& e)
: processor(p),editor(e)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
polyLabel.reset (new Label ("label",
TRANS("Poly")));
addAndMakeVisible (polyLabel.get());
polyLabel->setFont (Font (15.00f, Font::plain).withTypefaceStyle ("Regular"));
polyLabel->setJustificationType (Justification::centredLeft);
polyLabel->setEditable (false, false, false);
polyLabel->setColour (TextEditor::textColourId, Colours::black);
polyLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
polyLabel->setBounds (232, 8, 40, 15);
gainSlider.reset (new SliderComponent (p, "gain", "Gain"));
addAndMakeVisible (gainSlider.get());
gainSlider->setName ("gain slider");
gainSlider->setBounds (0, 32, 360, 32);
oscChoice.reset (new ChoiceComponent (p, "osc", "OSC Type"));
addAndMakeVisible (oscChoice.get());
oscChoice->setName ("osc selector");
oscChoice->setBounds (0, 4, 224, 28);
polyNumberInput.reset (new Slider ("poly number input"));
addAndMakeVisible (polyNumberInput.get());
polyNumberInput->setRange (0, 32, 1);
polyNumberInput->setSliderStyle (Slider::IncDecButtons);
polyNumberInput->setTextBoxStyle (Slider::TextBoxLeft, false, 30, 20);
polyNumberInput->addListener (this);
polyNumberInput->setBounds (268, 4, 86, 24);
advancedSwitch.reset (new CheckBoxComponent (p, "isAdvancedPanelOpen_raw", "Show Advanced Options"));
addAndMakeVisible (advancedSwitch.get());
advancedSwitch->setName ("advanced option switch");
colorSchemeChoice.reset (new ChoiceComponent (p, "colorScheme", "Color"));
addAndMakeVisible (colorSchemeChoice.get());
colorSchemeChoice->setName ("color selector");
//[UserPreSize]
//[/UserPreSize]
setSize (700, 64);
//[Constructor] You can add your own custom stuff here..
oscChoice->setListener (this);
advancedSwitch->setListener (this);
colorSchemeChoice->setListener (this);
colorSchemeChoice->setVisible (p.settingRefs.isAdvancedPanelOpen());
attc.reset (new SliderAttachment (p.parameters, "maxPoly", *polyNumberInput));
//[/Constructor]
}
BasicParamsComponent::~BasicParamsComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
oscChoice->removeListener();
advancedSwitch->removeListener();
attc.reset();
//[/Destructor_pre]
polyLabel = nullptr;
gainSlider = nullptr;
oscChoice = nullptr;
polyNumberInput = nullptr;
advancedSwitch = nullptr;
colorSchemeChoice = nullptr;
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]
}
//==============================================================================
void BasicParamsComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void BasicParamsComponent::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
advancedSwitch->setBounds (getWidth() - 240, 4, 240, 28);
colorSchemeChoice->setBounds (getWidth() - 4 - 185, 32, 185, 28);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
void BasicParamsComponent::sliderValueChanged (Slider* sliderThatWasMoved)
{
//[UsersliderValueChanged_Pre]
//[/UsersliderValueChanged_Pre]
if (sliderThatWasMoved == polyNumberInput.get())
{
//[UserSliderCode_polyNumberInput] -- add your slider handling code here..
processor.setupVoice();
//[/UserSliderCode_polyNumberInput]
}
//[UsersliderValueChanged_Post]
//[/UsersliderValueChanged_Post]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
void BasicParamsComponent::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
{
processor.setupVoice();
editor.resized();
printf ("setup voice!!\n");
}
void BasicParamsComponent::buttonClicked (Button* buttonThatWasClicked)
{
colorSchemeChoice->setVisible (buttonThatWasClicked->getToggleState());
editor.resizeWholePanel();
}
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Projucer information section --
This is where the Projucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="BasicParamsComponent" componentName=""
parentClasses="public Component, public ComboBox::Listener, public Button::Listener"
constructorParams="Magical8bitPlug2AudioProcessor&amp; p, Magical8bitPlug2AudioProcessorEditor&amp; e"
variableInitialisers="processor(p),editor(e)" snapPixels="8"
snapActive="1" snapShown="1" overlayOpacity="0.330" fixedSize="1"
initialWidth="700" initialHeight="64">
<BACKGROUND backgroundColour="ffffff"/>
<LABEL name="label" id="a5b2b89e6dca4fe" memberName="polyLabel" virtualName=""
explicitFocusOrder="0" pos="232 8 40 15" edTextCol="ff000000"
edBkgCol="0" labelText="Poly" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="15.0"
kerning="0.0" bold="0" italic="0" justification="33"/>
<GENERICCOMPONENT name="gain slider" id="4bb22b329fed19e9" memberName="gainSlider"
virtualName="" explicitFocusOrder="0" pos="0 32 360 32" class="SliderComponent"
params="p, &quot;gain&quot;, &quot;Gain&quot;"/>
<GENERICCOMPONENT name="osc selector" id="fa2387d441a3005d" memberName="oscChoice"
virtualName="" explicitFocusOrder="0" pos="0 4 224 28" class="ChoiceComponent"
params="p, &quot;osc&quot;, &quot;OSC Type&quot;"/>
<SLIDER name="poly number input" id="f767aca03a9fe3ae" memberName="polyNumberInput"
virtualName="" explicitFocusOrder="0" pos="268 4 86 24" min="0.0"
max="32.0" int="1.0" style="IncDecButtons" textBoxPos="TextBoxLeft"
textBoxEditable="1" textBoxWidth="30" textBoxHeight="20" skewFactor="1.0"
needsCallback="1"/>
<GENERICCOMPONENT name="advanced option switch" id="9d35239102eeb521" memberName="advancedSwitch"
virtualName="" explicitFocusOrder="0" pos="0Rr 4 240 28" class="CheckBoxComponent"
params="p, &quot;isAdvancedPanelOpen_raw&quot;, &quot;Show Advanced Options&quot;"/>
<GENERICCOMPONENT name="color selector" id="21d73ddc37680dd7" memberName="colorSchemeChoice"
virtualName="" explicitFocusOrder="0" pos="4Rr 32 185 28" class="ChoiceComponent"
params="p, &quot;colorScheme&quot;, &quot;Color&quot;"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -0,0 +1,86 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
#pragma once
//[Headers] -- You can add your own extra header files here --
#include "../JuceLibraryCode/JuceHeader.h"
#include "PluginProcessor.h"
#include "SliderComponent.h"
#include "ChoiceComponent.h"
#include "CheckBoxComponent.h"
class Magical8bitPlug2AudioProcessorEditor;
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Projucer.
Describe your class and how it works here!
//[/Comments]
*/
class BasicParamsComponent : public Component,
public ComboBox::Listener,
public Button::Listener,
public Slider::Listener
{
public:
//==============================================================================
BasicParamsComponent (Magical8bitPlug2AudioProcessor& p, Magical8bitPlug2AudioProcessorEditor& e);
~BasicParamsComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
void comboBoxChanged (ComboBox* comboBoxThatHasChanged) override;
void buttonClicked (Button* buttonThatWasClicked) override;
//[/UserMethods]
void paint (Graphics& g) override;
void resized() override;
void sliderValueChanged (Slider* sliderThatWasMoved) override;
private:
//[UserVariables] -- You can add your own custom variables in this section.
Magical8bitPlug2AudioProcessor& processor;
Magical8bitPlug2AudioProcessorEditor& editor;
std::unique_ptr<SliderAttachment> attc;
//[/UserVariables]
//==============================================================================
std::unique_ptr<Label> polyLabel;
std::unique_ptr<SliderComponent> gainSlider;
std::unique_ptr<ChoiceComponent> oscChoice;
std::unique_ptr<Slider> polyNumberInput;
std::unique_ptr<CheckBoxComponent> advancedSwitch;
std::unique_ptr<ChoiceComponent> colorSchemeChoice;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BasicParamsComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -0,0 +1,131 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "BendParamsComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
BendParamsComponent::BendParamsComponent (Magical8bitPlug2AudioProcessor& p)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
label.reset (new Label ("label",
TRANS("Bend Range")));
addAndMakeVisible (label.get());
label->setFont (Font (17.00f, Font::plain).withTypefaceStyle ("Regular"));
label->setJustificationType (Justification::centredLeft);
label->setEditable (false, false, false);
label->setColour (TextEditor::textColourId, Colours::black);
label->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
label->setBounds (0, 4, 150, 22);
sliderCompo.reset (new SliderComponent (p, "bendRange", "Range"));
addAndMakeVisible (sliderCompo.get());
sliderCompo->setName ("slider");
//[UserPreSize]
//[/UserPreSize]
setSize (340, 58);
//[Constructor] You can add your own custom stuff here..
//[/Constructor]
}
BendParamsComponent::~BendParamsComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
//[/Destructor_pre]
label = nullptr;
sliderCompo = nullptr;
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]
}
//==============================================================================
void BendParamsComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void BendParamsComponent::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
sliderCompo->setBounds (0, 26, proportionOfWidth (1.0000f), 28);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Projucer information section --
This is where the Projucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="BendParamsComponent" componentName=""
parentClasses="public Component" constructorParams="Magical8bitPlug2AudioProcessor&amp; p"
variableInitialisers="" snapPixels="8" snapActive="1" snapShown="1"
overlayOpacity="0.330" fixedSize="1" initialWidth="340" initialHeight="58">
<BACKGROUND backgroundColour="ffffff"/>
<LABEL name="label" id="bae3132bcad681ce" memberName="label" virtualName=""
explicitFocusOrder="0" pos="0 4 150 22" edTextCol="ff000000"
edBkgCol="0" labelText="Bend Range" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="17.0"
kerning="0.0" bold="0" italic="0" justification="33"/>
<GENERICCOMPONENT name="slider" id="b01ddc412ec6dc27" memberName="sliderCompo"
virtualName="" explicitFocusOrder="0" pos="0 26 100% 28" class="SliderComponent"
params="p, &quot;bendRange&quot;, &quot;Range&quot;"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -0,0 +1,68 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
#pragma once
//[Headers] -- You can add your own extra header files here --
#include "../JuceLibraryCode/JuceHeader.h"
#include "SliderComponent.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Projucer.
Describe your class and how it works here!
//[/Comments]
*/
class BendParamsComponent : public Component
{
public:
//==============================================================================
BendParamsComponent (Magical8bitPlug2AudioProcessor& p);
~BendParamsComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
//[/UserMethods]
void paint (Graphics& g) override;
void resized() override;
private:
//[UserVariables] -- You can add your own custom variables in this section.
//[/UserVariables]
//==============================================================================
std::unique_ptr<Label> label;
std::unique_ptr<SliderComponent> sliderCompo;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BendParamsComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -0,0 +1,149 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
#include "PluginProcessor.h"
//[/Headers]
#include "CheckBoxComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
CheckBoxComponent::CheckBoxComponent (Magical8bitPlug2AudioProcessor& p, String paramId, String name)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
toggleButton.reset (new ToggleButton ("toggle button"));
addAndMakeVisible (toggleButton.get());
toggleButton->setButtonText (TRANS("new toggle button"));
toggleButton->addListener (this);
//[UserPreSize]
//[/UserPreSize]
setSize (360, 28);
//[Constructor] You can add your own custom stuff here..
attc.reset (new ButtonAttachment (p.parameters, paramId, *toggleButton));
toggleButton->setButtonText (name);
//[/Constructor]
}
CheckBoxComponent::~CheckBoxComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
attc.reset();
//[/Destructor_pre]
toggleButton = nullptr;
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]
}
//==============================================================================
void CheckBoxComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void CheckBoxComponent::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
toggleButton->setBounds (32, 0, getWidth() - 40, 24);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
void CheckBoxComponent::buttonClicked (Button* buttonThatWasClicked)
{
//[UserbuttonClicked_Pre]
//[/UserbuttonClicked_Pre]
if (buttonThatWasClicked == toggleButton.get())
{
//[UserButtonCode_toggleButton] -- add your button handler code here..
//[/UserButtonCode_toggleButton]
}
//[UserbuttonClicked_Post]
if (buttonThatWasClicked == toggleButton.get() && checkBoxListener != nullptr)
{
checkBoxListener->buttonClicked (buttonThatWasClicked);
}
//[/UserbuttonClicked_Post]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
void CheckBoxComponent::setListener (Button::Listener* lnr)
{
checkBoxListener = lnr;
}
void CheckBoxComponent::removeListener()
{
checkBoxListener = nullptr;
}
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Projucer information section --
This is where the Projucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="CheckBoxComponent" componentName=""
parentClasses="public Component" constructorParams="Magical8bitPlug2AudioProcessor&amp; p, String paramId, String name"
variableInitialisers="" snapPixels="8" snapActive="1" snapShown="1"
overlayOpacity="0.330" fixedSize="1" initialWidth="360" initialHeight="28">
<BACKGROUND backgroundColour="ffffff"/>
<TOGGLEBUTTON name="toggle button" id="78b65dc9a6b61921" memberName="toggleButton"
virtualName="" explicitFocusOrder="0" pos="32 0 40M 24" buttonText="new toggle button"
connectedEdges="0" needsCallback="1" radioGroupId="0" state="0"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -0,0 +1,73 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
#pragma once
//[Headers] -- You can add your own extra header files here --
#include "../JuceLibraryCode/JuceHeader.h"
#include "Defs.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Projucer.
Describe your class and how it works here!
//[/Comments]
*/
class CheckBoxComponent : public Component,
public Button::Listener
{
public:
//==============================================================================
CheckBoxComponent (Magical8bitPlug2AudioProcessor& p, String paramId, String name);
~CheckBoxComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
void setListener (Button::Listener* lnr);
void removeListener();
//[/UserMethods]
void paint (Graphics& g) override;
void resized() override;
void buttonClicked (Button* buttonThatWasClicked) override;
private:
//[UserVariables] -- You can add your own custom variables in this section.
std::unique_ptr<ButtonAttachment> attc;
Button::Listener* checkBoxListener = nullptr;
//[/UserVariables]
//==============================================================================
std::unique_ptr<ToggleButton> toggleButton;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CheckBoxComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

177
Source/ChoiceComponent.cpp Normal file
View File

@ -0,0 +1,177 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "ChoiceComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
ChoiceComponent::ChoiceComponent (Magical8bitPlug2AudioProcessor& p, String paramId, String name)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
comboBox.reset (new ComboBox ("combo box"));
addAndMakeVisible (comboBox.get());
comboBox->setEditableText (false);
comboBox->setJustificationType (Justification::centredLeft);
comboBox->setTextWhenNothingSelected (String());
comboBox->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
comboBox->addListener (this);
label.reset (new Label ("label",
TRANS("Label")));
addAndMakeVisible (label.get());
label->setFont (Font (14.00f, Font::plain).withTypefaceStyle ("Regular"));
label->setJustificationType (Justification::centredRight);
label->setEditable (false, false, false);
label->setColour (TextEditor::textColourId, Colours::black);
label->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
label->setBounds (8, 1, 60, 24);
//[UserPreSize]
//[/UserPreSize]
setSize (360, 28);
//[Constructor] You can add your own custom stuff here..
label->setText (name, dontSendNotification);
AudioParameterChoice* c = (AudioParameterChoice*)p.parameters.getParameter (paramId);
for (int i = 0; i < c->choices.size(); i++)
{
String choice = c->choices[i];
comboBox->addItem (choice, i + 1);
}
attc.reset (new ComboBoxAttachment (p.parameters, paramId, *comboBox));
//[/Constructor]
}
ChoiceComponent::~ChoiceComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
attc.reset();
//[/Destructor_pre]
comboBox = nullptr;
label = nullptr;
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]
}
//==============================================================================
void ChoiceComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void ChoiceComponent::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
comboBox->setBounds (72, 0, getWidth() - 80, 24);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
void ChoiceComponent::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
{
//[UsercomboBoxChanged_Pre]
//[/UsercomboBoxChanged_Pre]
if (comboBoxThatHasChanged == comboBox.get())
{
//[UserComboBoxCode_comboBox] -- add your combo box handling code here..
printf ("value = %d\n", comboBoxThatHasChanged->getSelectedId());
//[/UserComboBoxCode_comboBox]
}
//[UsercomboBoxChanged_Post]
if (comboBoxThatHasChanged == comboBox.get() && comboBoxListener != nullptr)
{
comboBoxListener->comboBoxChanged (comboBoxThatHasChanged);
}
//[/UsercomboBoxChanged_Post]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
void ChoiceComponent::setListener (ComboBox::Listener* lnr)
{
comboBoxListener = lnr;
}
void ChoiceComponent::removeListener()
{
comboBoxListener = nullptr;
}
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Projucer information section --
This is where the Projucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="ChoiceComponent" componentName=""
parentClasses="public Component" constructorParams="Magical8bitPlug2AudioProcessor&amp; p, String paramId, String name"
variableInitialisers="" snapPixels="8" snapActive="1" snapShown="1"
overlayOpacity="0.330" fixedSize="1" initialWidth="360" initialHeight="28">
<BACKGROUND backgroundColour="ffffff"/>
<COMBOBOX name="combo box" id="67bfdf47357e233d" memberName="comboBox"
virtualName="" explicitFocusOrder="0" pos="72 0 80M 24" editable="0"
layout="33" items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/>
<LABEL name="label" id="af1fa4a96c3448e5" memberName="label" virtualName=""
explicitFocusOrder="0" pos="8 1 60 24" edTextCol="ff000000" edBkgCol="0"
labelText="Label" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="14.0"
kerning="0.0" bold="0" italic="0" justification="34"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

75
Source/ChoiceComponent.h Normal file
View File

@ -0,0 +1,75 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
#pragma once
//[Headers] -- You can add your own extra header files here --
#include "../JuceLibraryCode/JuceHeader.h"
#include "PluginProcessor.h"
#include "Defs.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Projucer.
Describe your class and how it works here!
//[/Comments]
*/
class ChoiceComponent : public Component,
public ComboBox::Listener
{
public:
//==============================================================================
ChoiceComponent (Magical8bitPlug2AudioProcessor& p, String paramId, String name);
~ChoiceComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
void setListener (ComboBox::Listener* lnr);
void removeListener();
//[/UserMethods]
void paint (Graphics& g) override;
void resized() override;
void comboBoxChanged (ComboBox* comboBoxThatHasChanged) override;
private:
//[UserVariables] -- You can add your own custom variables in this section.
std::unique_ptr<ComboBoxAttachment> attc;
ComboBox::Listener* comboBoxListener = nullptr;
//[/UserVariables]
//==============================================================================
std::unique_ptr<ComboBox> comboBox;
std::unique_ptr<Label> label;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChoiceComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

98
Source/ColorScheme.cpp Normal file
View File

@ -0,0 +1,98 @@
/*
==============================================================================
ColorScheme.cpp
Created: 8 Dec 2019 1:00:26pm
Author: 除村 武志
==============================================================================
*/
#include "ColorScheme.h"
ColorScheme::ColorScheme (ColorSchemeType type)
{
switch (type)
{
case kColorSchemeYmck:
background = Colour (0xffffffff);
textBoxFill = Colour (0xfff4f4ff);
boxFill = Colour (0xff00aeff);
main = Colour (0xff00aeff);
mainThinLine = Colour (0xff0086ff);
mainDarkened = Colour (0xff0080bb);
accent = Colour (0xffffdd00);
reversedForeground = Colour (0xffffffff);
genericBorder = Colour (0xff0080bb);
warning = Colour (0xffe22be0);
break;
case kColorSchemeYmckDark:
background = Colour (0xff000000);
textBoxFill = Colour (0xff101010);
boxFill = Colour (0xff004070);
main = Colour (0xff00aeff);
mainThinLine = Colour (0xff40A0ff);
mainDarkened = Colour (0xff004070);
accent = Colour (0xffffdd00);
reversedForeground = Colour (0xffffffff);
genericBorder = Colour (0xff0080bb);
warning = Colour (0xffe22be0);
break;
case kColorSchemeFamicom:
background = Colour (0xfff4f5ec);
boxFill = Colour (0xffead780);
textBoxFill = Colour (0xfffdfee9);
main = Colour (0xffc04136);
mainThinLine = Colour (0xff97372b);
mainDarkened = Colour (0xffc5b0ae);
accent = Colour (0xffeed27d);
reversedForeground = Colour (0xff101010);
genericBorder = Colour (0xff641c11);
warning = Colour (0xff641c11);
break;
case kColorSchemeNes:
background = Colour (0xffefefef);
boxFill = Colour (0xff69616e);
textBoxFill = Colour (0xffd1c8c3);
main = Colour (0xff1b1718);
mainThinLine = Colour (0xff000000);
mainDarkened = Colour (0xffa1988f);
accent = Colour (0xffc04136);
reversedForeground = Colour (0xffffffff);
genericBorder = Colour (0xffa1988f);
warning = Colour (0xffc04136);
break;
case kColorSchemeMonotoneLight:
background = Colour (0xffffffff);
boxFill = Colour (0xffffffff);
textBoxFill = Colour (0xfff0f0f0);
main = Colour (0xff202020);
mainThinLine = Colour (0xff000000);
mainDarkened = Colour (0xffc0c0c0);
accent = Colour (0xff808080);
reversedForeground = Colour (0xff000000);
genericBorder = Colour (0xff606060);
warning = Colour (0xff000000);
break;
case kColorSchemeMonotoneDark:
background = Colour (0xff000000);
boxFill = Colour (0xff101010);
textBoxFill = Colour (0xff000000);
main = Colour (0xffffffff);
mainThinLine = Colour (0xffffffff);
mainDarkened = Colour (0xff404040);
accent = Colour (0xffa0a0a0);
reversedForeground = Colour (0xffffffff);
genericBorder = Colour (0xffc0c0c0);
warning = Colour (0xffffffff);
break;
default:
break;
}
}

38
Source/ColorScheme.h Normal file
View File

@ -0,0 +1,38 @@
/*
==============================================================================
ColorScheme.h
Created: 8 Dec 2019 1:00:26pm
Author: 除村 武志
==============================================================================
*/
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
enum ColorSchemeType
{
kColorSchemeYmck = 0,
kColorSchemeYmckDark,
kColorSchemeFamicom,
kColorSchemeNes,
kColorSchemeMonotoneLight,
kColorSchemeMonotoneDark
};
struct ColorScheme
{
Colour background;
Colour boxFill;
Colour textBoxFill;
Colour main;
Colour mainThinLine;
Colour mainDarkened;
Colour accent;
Colour reversedForeground;
Colour genericBorder;
Colour warning;
ColorScheme (ColorSchemeType type);
};

View File

@ -0,0 +1,226 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
#include "PluginProcessor.h"
#include "FrameSequenceParseErrors.h"
//[/Headers]
#include "CustomEnvelopeComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
CustomEnvelopeComponent::CustomEnvelopeComponent (Magical8bitPlug2AudioProcessor& p, String type, String displayName, String flagParameterName)
: processor(p)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
textEditor.reset (new TextEditor ("text editor"));
addAndMakeVisible (textEditor.get());
textEditor->setMultiLine (false);
textEditor->setReturnKeyStartsNewLine (false);
textEditor->setReadOnly (false);
textEditor->setScrollbarsShown (false);
textEditor->setCaretVisible (true);
textEditor->setPopupMenuEnabled (true);
textEditor->setText (String());
toggleButton.reset (new ToggleButton ("toggle button"));
addAndMakeVisible (toggleButton.get());
toggleButton->setButtonText (TRANS("Enabled"));
toggleButton->addListener (this);
toggleButton->setBounds (8, 4, 104, 24);
label.reset (new Label ("new label",
String()));
addAndMakeVisible (label.get());
label->setFont (Font (12.00f, Font::plain).withTypefaceStyle ("Regular"));
label->setJustificationType (Justification::centredLeft);
label->setEditable (false, false, false);
label->setColour (TextEditor::textColourId, Colours::black);
label->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
//[UserPreSize]
//[/UserPreSize]
setSize (540, 56);
//[Constructor] You can add your own custom stuff here..
paramType = type;
attc.reset (new ButtonAttachment (p.parameters, flagParameterName, *toggleButton));
textEditor->addListener (this);
textEditor->setText (p.settingRefs.getSequenceString (type));
toggleButton->setButtonText (displayName);
//[/Constructor]
}
CustomEnvelopeComponent::~CustomEnvelopeComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
//[/Destructor_pre]
textEditor = nullptr;
toggleButton = nullptr;
label = nullptr;
//[Destructor]. You can add your own custom destruction code here..
attc.reset();
//[/Destructor]
}
//==============================================================================
void CustomEnvelopeComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void CustomEnvelopeComponent::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
textEditor->setBounds (112, 4, getWidth() - 124, 24);
label->setBounds (112, 28, getWidth() - 124, 24);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
void CustomEnvelopeComponent::buttonClicked (Button* buttonThatWasClicked)
{
//[UserbuttonClicked_Pre]
//[/UserbuttonClicked_Pre]
if (buttonThatWasClicked == toggleButton.get())
{
//[UserButtonCode_toggleButton] -- add your button handler code here..
//[/UserButtonCode_toggleButton]
}
//[UserbuttonClicked_Post]
//[/UserbuttonClicked_Post]
}
void CustomEnvelopeComponent::lookAndFeelChanged()
{
//[UserCode_lookAndFeelChanged] -- Add your code here...
ColorScheme cs = ColorScheme (processor.settingRefs.colorSchemeType());
labelLookAndFeel.setColour (Label::textColourId, cs.warning);
label->setLookAndFeel (&labelLookAndFeel);
textEditor->applyColourToAllText (cs.mainThinLine, true);
//[/UserCode_lookAndFeelChanged]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
void CustomEnvelopeComponent::textEditorTextChanged (TextEditor& editor)
{
printf ("*** text changed!\n");
String txt = editor.getText();
ParseError err = kParseErrorNone;
processor.settingRefs.setSequenceWithString (paramType, txt, &err);
if (err == kParseErrorValueOutOfRange)
{
if (paramType == "volume")
{
label->setText (getParseErrorString (err, 0, 15), dontSendNotification);
}
else if (paramType == "pitch")
{
label->setText (getParseErrorString (err, -64, 63), dontSendNotification);
}
else if (paramType == "duty")
{
label->setText (getParseErrorString (err, 0, 2), dontSendNotification);
}
}
else
{
label->setText (getParseErrorString (err), dontSendNotification);
}
}
void CustomEnvelopeComponent::sequenceChanged (String& str)
{
textEditor->setText (str);
}
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Projucer information section --
This is where the Projucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="CustomEnvelopeComponent"
componentName="" parentClasses="public Component, TextEditor::Listener, FrameSequenceChangeListener"
constructorParams="Magical8bitPlug2AudioProcessor&amp; p, String type, String displayName, String flagParameterName"
variableInitialisers="processor(p)" snapPixels="8" snapActive="1"
snapShown="1" overlayOpacity="0.330" fixedSize="1" initialWidth="540"
initialHeight="56">
<METHODS>
<METHOD name="lookAndFeelChanged()"/>
</METHODS>
<BACKGROUND backgroundColour="ffffff"/>
<TEXTEDITOR name="text editor" id="9e63a9c08f238222" memberName="textEditor"
virtualName="" explicitFocusOrder="0" pos="112 4 124M 24" initialText=""
multiline="0" retKeyStartsLine="0" readonly="0" scrollbars="0"
caret="1" popupmenu="1"/>
<TOGGLEBUTTON name="toggle button" id="87baaa12bb810ff" memberName="toggleButton"
virtualName="" explicitFocusOrder="0" pos="8 4 104 24" buttonText="Enabled"
connectedEdges="0" needsCallback="1" radioGroupId="0" state="0"/>
<LABEL name="new label" id="ea955df87cc606d6" memberName="label" virtualName=""
explicitFocusOrder="0" pos="112 28 124M 24" edTextCol="ff000000"
edBkgCol="0" labelText="" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="12.0"
kerning="0.0" bold="0" italic="0" justification="33"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -0,0 +1,81 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
#pragma once
//[Headers] -- You can add your own extra header files here --
#include "../JuceLibraryCode/JuceHeader.h"
#include "PluginProcessor.h"
#include "Defs.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Projucer.
Describe your class and how it works here!
//[/Comments]
*/
class CustomEnvelopeComponent : public Component,
TextEditor::Listener,
FrameSequenceChangeListener,
public Button::Listener
{
public:
//==============================================================================
CustomEnvelopeComponent (Magical8bitPlug2AudioProcessor& p, String type, String displayName, String flagParameterName);
~CustomEnvelopeComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
void textEditorTextChanged (TextEditor& editor) override;
void sequenceChanged (String& str) override;
//[/UserMethods]
void paint (Graphics& g) override;
void resized() override;
void buttonClicked (Button* buttonThatWasClicked) override;
void lookAndFeelChanged() override;
private:
//[UserVariables] -- You can add your own custom variables in this section.
Magical8bitPlug2AudioProcessor& processor;
std::unique_ptr<ButtonAttachment> attc;
String paramType;
LookAndFeel_V4 labelLookAndFeel;
//[/UserVariables]
//==============================================================================
std::unique_ptr<TextEditor> textEditor;
std::unique_ptr<ToggleButton> toggleButton;
std::unique_ptr<Label> label;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomEnvelopeComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

15
Source/Defs.h Normal file
View File

@ -0,0 +1,15 @@
/*
==============================================================================
Defs.h
Created: 13 Jul 2019 11:03:52pm
Author: 除村 武志
==============================================================================
*/
#pragma once
typedef AudioProcessorValueTreeState::SliderAttachment SliderAttachment;
typedef AudioProcessorValueTreeState::ButtonAttachment ButtonAttachment;
typedef juce::AudioProcessorValueTreeState::ComboBoxAttachment ComboBoxAttachment;

View File

@ -0,0 +1,196 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "EnvelopeParamsComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
EnvelopeParamsComponent::EnvelopeParamsComponent (Magical8bitPlug2AudioProcessor& p)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
label.reset (new Label ("label",
TRANS("Envelope")));
addAndMakeVisible (label.get());
label->setFont (Font (17.00f, Font::plain).withTypefaceStyle ("Regular"));
label->setJustificationType (Justification::centredLeft);
label->setEditable (false, false, false);
label->setColour (TextEditor::textColourId, Colours::black);
label->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
label->setBounds (0, 4, 150, 22);
attackSlider.reset (new SliderComponent (p, "attack", "Attack"));
addAndMakeVisible (attackSlider.get());
attackSlider->setName ("attack slider");
decaySlider.reset (new SliderComponent (p, "decay", "Decay"));
addAndMakeVisible (decaySlider.get());
decaySlider->setName ("decay slider");
sustainSlider.reset (new SliderComponent (p, "suslevel", "Sustain"));
addAndMakeVisible (sustainSlider.get());
sustainSlider->setName ("sustain slider");
releaseSlider.reset (new SliderComponent (p, "release", "Release"));
addAndMakeVisible (releaseSlider.get());
releaseSlider->setName ("release slider");
warningLabel.reset (new Label ("warning label",
String()));
addAndMakeVisible (warningLabel.get());
warningLabel->setFont (Font (15.00f, Font::plain).withTypefaceStyle ("Regular"));
warningLabel->setJustificationType (Justification::centredRight);
warningLabel->setEditable (false, false, false);
warningLabel->setColour (Label::textColourId, Colour (0xffe22be0));
warningLabel->setColour (TextEditor::textColourId, Colours::black);
warningLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
//[UserPreSize]
//[/UserPreSize]
setSize (340, 142);
//[Constructor] You can add your own custom stuff here..
ColorScheme cs = ColorScheme (p.settingRefs.colorSchemeType());
warningLabelLookAndFeel.setColour (Label::textColourId, cs.warning);
warningLabel->setLookAndFeel (&warningLabelLookAndFeel);
//[/Constructor]
}
EnvelopeParamsComponent::~EnvelopeParamsComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
//[/Destructor_pre]
label = nullptr;
attackSlider = nullptr;
decaySlider = nullptr;
sustainSlider = nullptr;
releaseSlider = nullptr;
warningLabel = nullptr;
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]
}
//==============================================================================
void EnvelopeParamsComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void EnvelopeParamsComponent::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
attackSlider->setBounds (0, 26, proportionOfWidth (1.0000f), 28);
decaySlider->setBounds (0, 54, proportionOfWidth (1.0000f), 28);
sustainSlider->setBounds (0, 82, proportionOfWidth (1.0000f), 28);
releaseSlider->setBounds (0, 110, proportionOfWidth (1.0000f), 28);
warningLabel->setBounds (getWidth() - 8 - 246, 4, 246, 24);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
void EnvelopeParamsComponent::enablementChanged()
{
//[UserCode_enablementChanged] -- Add your code here...
if (isEnabled())
{
warningLabel->setText (TRANS (""), dontSendNotification);
}
else
{
warningLabel->setText (TRANS ("Overridden by Custom Envelope"), dontSendNotification);
}
//[/UserCode_enablementChanged]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Projucer information section --
This is where the Projucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="EnvelopeParamsComponent"
componentName="" parentClasses="public Component" constructorParams="Magical8bitPlug2AudioProcessor&amp; p"
variableInitialisers="" snapPixels="8" snapActive="1" snapShown="1"
overlayOpacity="0.330" fixedSize="1" initialWidth="340" initialHeight="142">
<METHODS>
<METHOD name="enablementChanged()"/>
</METHODS>
<BACKGROUND backgroundColour="ffffff"/>
<LABEL name="label" id="bae3132bcad681ce" memberName="label" virtualName=""
explicitFocusOrder="0" pos="0 4 150 22" edTextCol="ff000000"
edBkgCol="0" labelText="Envelope" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="17.0"
kerning="0.0" bold="0" italic="0" justification="33"/>
<GENERICCOMPONENT name="attack slider" id="93ec1e79c45ddad4" memberName="attackSlider"
virtualName="" explicitFocusOrder="0" pos="0 26 100% 28" class="SliderComponent"
params="p, &quot;attack&quot;, &quot;Attack&quot;"/>
<GENERICCOMPONENT name="decay slider" id="1be45518932375fc" memberName="decaySlider"
virtualName="" explicitFocusOrder="0" pos="0 54 100% 28" class="SliderComponent"
params="p, &quot;decay&quot;, &quot;Decay&quot;"/>
<GENERICCOMPONENT name="sustain slider" id="5c2169fddb4cc33" memberName="sustainSlider"
virtualName="" explicitFocusOrder="0" pos="0 82 100% 28" class="SliderComponent"
params="p, &quot;suslevel&quot;, &quot;Sustain&quot;"/>
<GENERICCOMPONENT name="release slider" id="9d35239102eeb521" memberName="releaseSlider"
virtualName="" explicitFocusOrder="0" pos="0 110 100% 28" class="SliderComponent"
params="p, &quot;release&quot;, &quot;Release&quot;"/>
<LABEL name="warning label" id="624aa3e1415981e3" memberName="warningLabel"
virtualName="" explicitFocusOrder="0" pos="8Rr 4 246 24" textCol="ffe22be0"
edTextCol="ff000000" edBkgCol="0" labelText="" editableSingleClick="0"
editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font"
fontsize="15.0" kerning="0.0" bold="0" italic="0" justification="34"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -0,0 +1,74 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
#pragma once
//[Headers] -- You can add your own extra header files here --
#include "../JuceLibraryCode/JuceHeader.h"
#include "SliderComponent.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Projucer.
Describe your class and how it works here!
//[/Comments]
*/
class EnvelopeParamsComponent : public Component
{
public:
//==============================================================================
EnvelopeParamsComponent (Magical8bitPlug2AudioProcessor& p);
~EnvelopeParamsComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
//[/UserMethods]
void paint (Graphics& g) override;
void resized() override;
void enablementChanged() override;
private:
//[UserVariables] -- You can add your own custom variables in this section.
LookAndFeel_V4 warningLabelLookAndFeel;
//[/UserVariables]
//==============================================================================
std::unique_ptr<Label> label;
std::unique_ptr<SliderComponent> attackSlider;
std::unique_ptr<SliderComponent> decaySlider;
std::unique_ptr<SliderComponent> sustainSlider;
std::unique_ptr<SliderComponent> releaseSlider;
std::unique_ptr<Label> warningLabel;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EnvelopeParamsComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

71
Source/FrameSequence.h Normal file
View File

@ -0,0 +1,71 @@
/*
==============================================================================
FrameSequence.h
Created: 11 Dec 2019 11:37:27am
Author: 除村 武志
==============================================================================
*/
#pragma once
#include <vector>
struct FrameSequence
{
std::vector<int> sequence;
bool isLooped = false;
bool hasRelease = false;
int loopStartIndex = 0;
int releaseSequenceStartIndex = 0;
static const int SHOULD_RETIRE = 65535;
int valueAt (int index)
{
if (index < 0 || index >= sequence.size())
{
return 0;
}
return sequence[index];
}
int nextIndexOf (int current)
{
if (current < releaseSequenceStartIndex) // Hold
{
if (current == releaseSequenceStartIndex - 1) // Reached to the end
{
if (isLooped)
{
return loopStartIndex;
}
else
{
return current; // Hold the last value
}
}
else
{
return current + 1;
}
// No reach here
}
else // Released
{
if (current >= sequence.size() - 1) // Reached to the end
{
return SHOULD_RETIRE;
}
else
{
return current + 1;
}
// No reach here
}
// No reach here
}
};

View File

@ -0,0 +1,84 @@
/*
==============================================================================
FrameSequenceParseErrors.cpp
Created: 11 Dec 2019 7:16:17pm
Author: 除村 武志
==============================================================================
*/
#include "FrameSequenceParseErrors.h"
String getParseErrorString (ParseError err, int minValue, int maxValue)
{
switch (err)
{
case kParseErrorDuplicatedReleaseDelimiter:
return TRANS ("You cannot use \"|\" more than once");
break;
case kParseErrorDuplicatedOpenBracket:
return TRANS ("You cannot use \"[\" more than once");
break;
case kParseErrorDuplicatedCloseBracket:
return TRANS ("You cannot use \"]\" more than once");
break;
case kParseErrorRepeatingInReleaseBlock:
return TRANS ("You cannot use repeat in release phase");
break;
case kParseErrorUnmatchingOpenBracket:
return TRANS ("Unmatching \"[\"");
break;
case kParseErrorUnmatchingCloseBracket:
return TRANS ("Unmatching \"]\"");
break;
case kParseErrorUnmatchingBracketNumber:
return TRANS ("Number of brackets not matching");
break;
case kParseErrorMissingSlopeValueDelimiter:
return TRANS ("\"to\" must be speccified in slope description");
break;
case kParseErrorMissingSlopeLengthDelimiter:
return TRANS ("\"in\" must be speccified in slope description");
break;
case kParseErrorMissingSlopeInitialValue:
return TRANS ("Missing initial value before \"to\"");
break;
case kParseErrorMissingSlopeFinalValue:
return TRANS ("Missing destination value before \"in\"");
break;
case kParseErrorNotANumber:
return TRANS ("Number parse failed.");
break;
case kParseErrorValueOutOfRange:
return String::formatted (TRANS ("Value should be between %d and %d."), minValue, maxValue);
break;
case kParseErrorFrameLengthTooShort:
return TRANS ("Frame count should be more than 2");
break;
case kParseErrorMissingValueForRepeatDelimiter:
return TRANS ("Operator x should be followed by a number.");
break;
case kParseErrorMissingFrameCountForRepeatDelimiter:
return TRANS ("A number should be specified after operator x.");
break;
default:
return "";
}
}

View File

@ -0,0 +1,37 @@
/*
==============================================================================
FrameSequenceParseErrors.h
Created: 11 Dec 2019 5:06:52pm
Author: 除村 武志
==============================================================================
*/
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
enum ParseError
{
kParseErrorNone = 0,
kParseErrorLevelWarning,
kParseErrorLevelFatal,
kParseErrorDuplicatedReleaseDelimiter,
kParseErrorDuplicatedOpenBracket,
kParseErrorDuplicatedCloseBracket,
kParseErrorRepeatingInReleaseBlock,
kParseErrorUnmatchingOpenBracket,
kParseErrorUnmatchingCloseBracket,
kParseErrorUnmatchingBracketNumber,
kParseErrorMissingSlopeValueDelimiter,
kParseErrorMissingSlopeLengthDelimiter,
kParseErrorMissingSlopeInitialValue,
kParseErrorMissingSlopeFinalValue,
kParseErrorNotANumber,
kParseErrorValueOutOfRange,
kParseErrorFrameLengthTooShort,
kParseErrorMissingValueForRepeatDelimiter,
kParseErrorMissingFrameCountForRepeatDelimiter,
};
String getParseErrorString (ParseError err, int minValue = 0, int maxValue = 0);

View File

@ -0,0 +1,462 @@
/*
==============================================================================
FrameSequenceParser.cpp
Created: 11 Dec 2019 8:49:02am
Author: 除村 武志
==============================================================================
*/
#include "FrameSequenceParser.h"
//
// Fileprivate
//
std::vector<int> parseSlope (const String& input,
int minValue,
int maxValue,
ParseError* error)
{
std::vector<int> retval;
// find index of "to"
int toIndex = input.indexOf ("to");
if (toIndex < 0)
{
// Normally this is impossible because it's checking existance of "to" to check if it's a slope
*error = kParseErrorMissingSlopeValueDelimiter;
return retval;
}
if (toIndex < 1)
{
*error = kParseErrorMissingSlopeInitialValue;
return retval;
}
// find index of "in"
int inIndex = input.indexOf ("in");
if (inIndex > input.length() - 3)
{
*error = kParseErrorMissingSlopeFinalValue;
return retval;
}
if (inIndex < 0)
{
*error = kParseErrorMissingSlopeLengthDelimiter;
return retval;
}
// get 3 substrings separated by "to" and "in" and put them into `from`, `to`, `cntStr`
String fromStr = input.substring (0, toIndex);
String toStr = input.substring (toIndex + 2, inIndex);
String cntStr = input.substring (inIndex + 2, input.length());
// remove "f" from `cntStr` if exists
String cntStr_t = cntStr.replace ("f", "");
if (!fromStr.containsOnly ("-0123456789"))
{
*error = kParseErrorNotANumber;
return retval;
}
if (!toStr.containsOnly ("-0123456789"))
{
*error = kParseErrorNotANumber;
return retval;
}
if (!cntStr_t.containsOnly ("-0123456789"))
{
*error = kParseErrorNotANumber;
return retval;
}
// convert each strings to int
double fromValue = fromStr.getDoubleValue();
double toValue = toStr.getDoubleValue();
double cntValue = cntStr_t.getDoubleValue();
if (fromValue > (double)maxValue || toValue > (double)maxValue )
{
*error = kParseErrorValueOutOfRange;
return retval;
}
if (fromValue < (double)minValue || toValue < (double)minValue )
{
*error = kParseErrorValueOutOfRange;
return retval;
}
if (cntValue < 2.0)
{
*error = kParseErrorFrameLengthTooShort;
return retval;
}
// calculate slope as double
double slope = (toValue - fromValue) / (cntValue - 1.0);
for (double i = 0; i < cntValue; i += 1.0)
{
double value = fromValue + slope * i;
int rounded = round (value);
retval.push_back (rounded);
}
return retval;
}
std::vector<int> parseRepeat (const String& input,
int minValue,
int maxValue,
ParseError* error)
{
std::vector<int> retval;
// find index of "x"
int xIndex = input.indexOf ("x");
if (xIndex < 1)
{
*error = kParseErrorMissingValueForRepeatDelimiter;
return retval;
}
if (xIndex > input.length() - 1)
{
*error = kParseErrorMissingFrameCountForRepeatDelimiter;
return retval;
}
// separate into value, count
String valueStr = input.substring (0, xIndex);
String cntStr = input.substring (xIndex + 1, input.length());
// remove "f" from `cntStr` if exists
String cntStr_t = cntStr.replace ("f", "");
if (!valueStr.containsOnly ("-0123456789"))
{
*error = kParseErrorNotANumber;
return retval;
}
if (!cntStr_t.containsOnly ("-0123456789"))
{
*error = kParseErrorNotANumber;
return retval;
}
int value = valueStr.getIntValue();
if (value < minValue || value > maxValue)
{
*error = kParseErrorValueOutOfRange;
return retval;
}
int count = cntStr_t.getIntValue();
for (int i = 0; i < count; i++)
{
retval.push_back (value);
}
return retval;
}
std::vector<int> parseSegment (const String& input,
int minValue,
int maxValue,
ParseError* error)
{
std::vector<int> retval;
StringArray temp;
temp.addTokens (input, ",", "");
for (String aToken : temp)
{
std::vector<int> parsed;
if (aToken.contains ("to"))
{
// parse as slope
parsed = parseSlope (aToken, minValue, maxValue, error);
}
else if (aToken.contains ("x"))
{
// parse as repeat-fixed-value
parsed = parseRepeat (aToken, minValue, maxValue, error);
}
else
{
// parse as single value
if (aToken.length() < 1)
{
*error = kParseErrorNotANumber;
return retval;
}
if (!aToken.containsOnly ("-0123456789"))
{
*error = kParseErrorNotANumber;
return retval;
}
int value = aToken.getIntValue();
if (value < minValue || value > maxValue)
{
*error = kParseErrorValueOutOfRange;
return retval;
}
parsed.push_back (value);
}
retval.insert (retval.end(), parsed.begin(), parsed.end());
}
return retval;
}
FrameSequence FrameSequenceParser::parse (const String& input,
int minValue,
int maxValue,
ParseError* error)
{
FrameSequence fs;
//-----------------------------------
//
// Preprocessing
//
//-----------------------------------
// Remove white spaces
String trimmed = input.replace (" ", "");
//
// Overall structure
//
int releaseBlockIndex = -1;
int repeatStartIndex = -1;
int repeatEndIndex = -1;
int openBracketCount = 0;
int closeBracketCount = 0;
// loop by character
for (int i = 0; i < trimmed.length(); i++)
{
if (trimmed[i] == '|') // found "|":
{
if (releaseBlockIndex >= 0)
{
// if releaseBlockIndex is already determined: Duplication Error
*error = kParseErrorDuplicatedReleaseDelimiter;
return fs;
}
// if(repeatStartIndex >= 0) {
// // if appeard before "[" or "]": Repetition After Release Error
// throw new FrameSequenceParseException(TRANS("You cannot repeat in release phase"), true);
// }
// set releaseBlockIndex
releaseBlockIndex = i + 1;
if (repeatEndIndex < 0)
{
// if "]" is omitted: Also set repeatEndIndex
repeatEndIndex = i;
}
}
if (trimmed[i] == '[') /// found "[":
{
openBracketCount++;
if (openBracketCount > 1)
{
// Duplication Error
*error = kParseErrorDuplicatedOpenBracket;
return fs;
}
if (releaseBlockIndex >= 0)
{
// if repeat end is already defined: Repetition After Release Error
*error = kParseErrorRepeatingInReleaseBlock;
return fs;
}
if (repeatEndIndex >= 0)
{
// if repeat end is already defined: Repetition After Release Error
*error = kParseErrorDuplicatedOpenBracket;
return fs;
}
// set repeatStartIndex
repeatStartIndex = i + 1;
}
if (trimmed[i] == ']') // found "]":
{
closeBracketCount++;
if (closeBracketCount > 1)
{
// Duplication Error
*error = kParseErrorDuplicatedCloseBracket;
return fs;
}
if (repeatStartIndex < 0)
{
// if repeatStartIndex hasn't set: Syntax Error
*error = kParseErrorUnmatchingCloseBracket;
return fs;
}
if (releaseBlockIndex >= 0)
{
// if repeat end is already defined: Repetition After Release Error
*error = kParseErrorRepeatingInReleaseBlock;
return fs;
}
repeatEndIndex = i;
}
}
// if (releaseBlockIndex < 0) { // "|" didn't explicitly specified
// releaseBlockIndex = trimmed.length();
// }
if (openBracketCount != closeBracketCount)
{
*error = kParseErrorUnmatchingBracketNumber;
return fs;
}
if (releaseBlockIndex - repeatEndIndex > 1)
{
// throw new FrameSequenceParseException(TRANS("Elements between repeat block and release block will be ignored"), false);
// FiXME: non-fatal exceptionをどう扱うか
}
// Just for convenience
bool hasRelease = (releaseBlockIndex >= 0);
bool shouldRepeat = (repeatStartIndex >= 0);
//-----------------------------------
//
// Split segments
//
//-----------------------------------
String str_beforeRepeat;
String str_insideRepeat;
String str_release;
if (shouldRepeat)
{
if (hasRelease)
{
str_beforeRepeat = trimmed.substring (0, repeatStartIndex - 1);
}
str_insideRepeat = trimmed.substring (repeatStartIndex, repeatEndIndex);
}
else
{
if (hasRelease)
{
str_beforeRepeat = trimmed.substring (0, releaseBlockIndex - 1);
str_release = trimmed.substring (releaseBlockIndex, trimmed.length());
}
else
{
str_beforeRepeat = trimmed.substring (0, trimmed.length());
}
}
std::cout << "before repeat : " + str_beforeRepeat + "\n";
std::cout << "inside repeat : " + str_insideRepeat + "\n";
std::cout << "after release : " + str_release + "\n";
//-----------------------------------
//
// Parse segments
//
//-----------------------------------
// Parse main segment to get frameSequence
// And set frameSequence value to working variable
// FrameSequence *fs = std::make_unique<FrameSequence>();
std::vector<int> sequence = parseSegment (str_beforeRepeat, minValue, maxValue, error);
if (*error > kParseErrorLevelFatal)
{
return fs;
}
fs.sequence = sequence;
fs.sequence.reserve (1000);
fs.releaseSequenceStartIndex = (int)fs.sequence.size();
if (shouldRepeat) // If repeat segment exists:
{
// Set repeatStartIndex according to current working frameSequence length
fs.isLooped = true;
fs.loopStartIndex = (int)fs.sequence.size();
// Parse repeat segment and to get frameSequence
std::vector<int> repeatSeq = parseSegment (str_insideRepeat, minValue, maxValue, error);
if (*error > kParseErrorLevelFatal)
{
return fs;
}
// Add the result to working frameSequence
fs.sequence.insert (fs.sequence.end(), repeatSeq.begin(), repeatSeq.end());
// Set repeatEndIndex according to current working frameSequence length
fs.releaseSequenceStartIndex = (int)fs.sequence.size();
}
if (hasRelease) // If release exists:
{
// Set releaseStartIndex according to current working frameSequence length
fs.releaseSequenceStartIndex = (int)fs.sequence.size();
fs.hasRelease = true;
// Parse release segment to get frameSequence
std::vector<int> releaseSeq = parseSegment (str_release, minValue, maxValue, error);
if (*error > kParseErrorLevelFatal)
{
return fs;
}
// Add the result to working frameSequence
fs.sequence.insert (fs.sequence.end(), releaseSeq.begin(), releaseSeq.end());
printf ("success");
}
// return the frameSequence
return fs;
}

View File

@ -0,0 +1,19 @@
/*
==============================================================================
FrameSequenceParser.h
Created: 11 Dec 2019 8:49:02am
Author: 除村 武志
==============================================================================
*/
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
#include "FrameSequence.h"
#include "FrameSequenceParseErrors.h"
struct FrameSequenceParser
{
FrameSequence parse (const String& input, int minValue, int maxValue, ParseError* error);
};

View File

@ -0,0 +1,131 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "NoiseParamsComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
NoiseParamsComponent::NoiseParamsComponent (Magical8bitPlug2AudioProcessor& p)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
label.reset (new Label ("label",
TRANS("Noise")));
addAndMakeVisible (label.get());
label->setFont (Font (17.00f, Font::plain).withTypefaceStyle ("Regular"));
label->setJustificationType (Justification::centredLeft);
label->setEditable (false, false, false);
label->setColour (TextEditor::textColourId, Colours::black);
label->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
label->setBounds (0, 4, 150, 22);
algorithmSelector.reset (new ChoiceComponent (p, "noiseAlgorithm_raw", "Noise Type"));
addAndMakeVisible (algorithmSelector.get());
algorithmSelector->setName ("algorithm selector");
//[UserPreSize]
//[/UserPreSize]
setSize (340, 58);
//[Constructor] You can add your own custom stuff here..
//[/Constructor]
}
NoiseParamsComponent::~NoiseParamsComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
//[/Destructor_pre]
label = nullptr;
algorithmSelector = nullptr;
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]
}
//==============================================================================
void NoiseParamsComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void NoiseParamsComponent::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
algorithmSelector->setBounds (0, 26, proportionOfWidth (1.0000f), 28);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Projucer information section --
This is where the Projucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="NoiseParamsComponent" componentName=""
parentClasses="public Component" constructorParams="Magical8bitPlug2AudioProcessor&amp; p"
variableInitialisers="" snapPixels="8" snapActive="1" snapShown="1"
overlayOpacity="0.330" fixedSize="1" initialWidth="340" initialHeight="58">
<BACKGROUND backgroundColour="ffffff"/>
<LABEL name="label" id="bae3132bcad681ce" memberName="label" virtualName=""
explicitFocusOrder="0" pos="0 4 150 22" edTextCol="ff000000"
edBkgCol="0" labelText="Noise" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="17.0"
kerning="0.0" bold="0" italic="0" justification="33"/>
<GENERICCOMPONENT name="algorithm selector" id="b01ddc412ec6dc27" memberName="algorithmSelector"
virtualName="" explicitFocusOrder="0" pos="0 26 100% 28" class="ChoiceComponent"
params="p, &quot;noiseAlgorithm_raw&quot;, &quot;Noise Type&quot;"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -0,0 +1,68 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
#pragma once
//[Headers] -- You can add your own extra header files here --
#include "../JuceLibraryCode/JuceHeader.h"
#include "ChoiceComponent.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Projucer.
Describe your class and how it works here!
//[/Comments]
*/
class NoiseParamsComponent : public Component
{
public:
//==============================================================================
NoiseParamsComponent (Magical8bitPlug2AudioProcessor& p);
~NoiseParamsComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
//[/UserMethods]
void paint (Graphics& g) override;
void resized() override;
private:
//[UserVariables] -- You can add your own custom variables in this section.
//[/UserVariables]
//==============================================================================
std::unique_ptr<Label> label;
std::unique_ptr<ChoiceComponent> algorithmSelector;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NoiseParamsComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

88
Source/NoiseVoice.cpp Normal file
View File

@ -0,0 +1,88 @@
/*
==============================================================================
NoiseVoice.cpp
Created: 11 Nov 2019 9:37:21pm
Author: 除村 武志
==============================================================================
*/
#include "NoiseVoice.h"
//---------------------------------------------
//
// Noise Voice
//
//---------------------------------------------
NoiseVoice::NoiseVoice(SettingRefs *sRefs) : TonalVoice(sRefs) {}
void NoiseVoice::startNote(int midiNoteNumber, float velocity, SynthesiserSound *, int currentPitchBendPosition) {
TonalVoice::startNote(midiNoteNumber, velocity, 0, currentPitchBendPosition);
switch (settingRefs->noiseAlgorithm()) {
case kNoiseInfinite2:
cycleLength = MathConstants<float>::pi / 25.0;
break;
case kNoiseLong:
case kNoiseShort:
cycleLength = MathConstants<float>::pi / 8.0;
break;
default:
cycleLength = MathConstants<float>::pi / 8.0;
break;
}
}
float NoiseVoice::voltageForAngle (double angle)
{
// TODO: StartVoice側でangleDeltaを調整する方が良い
// double dividedAngle = fmod(angle, MathConstants<float>::pi / 2.0);
bool isNewCycle = angle < previousAngle;
bool shouldUpdate = false;
if (isNewCycle)
{
shouldUpdate = true;
}
else if (nextAngle != 0)
{
if (angle >= nextAngle)
{
shouldUpdate = true;
}
}
if (shouldUpdate)
{
if (settingRefs->noiseAlgorithm() == kNoiseInfinite2)
{
currentVoltage = float (rand() % 16 - 8) / 16.;
}
else
{
int compareBitPos = settingRefs->noiseAlgorithm() == kNoiseLong ? 1 : 6;
unsigned int bit0 = rgstr & 0b0000001;
unsigned int compared = (rgstr & 1 << compareBitPos) >> compareBitPos;
unsigned int feedback = bit0 ^ compared;
rgstr = rgstr >> 1;
unsigned int mask = ~ (1 << 14);
unsigned int writeback = feedback << 14;
rgstr = (rgstr & mask) | writeback;
currentVoltage = (float)bit0 - 0.5;
}
nextAngle = (double) ((int) (angle / cycleLength) + 1) * cycleLength;
if (nextAngle >= MathConstants<float>::pi * 2) { nextAngle = 0; }
}
previousAngle = angle;
return currentVoltage;
}

28
Source/NoiseVoice.h Normal file
View File

@ -0,0 +1,28 @@
/*
==============================================================================
NoiseVoice.h
Created: 11 Nov 2019 9:37:21pm
Author: 除村 武志
==============================================================================
*/
#pragma once
#include "TonalVoice.h"
struct NoiseVoice : public TonalVoice {
NoiseVoice(SettingRefs *sRefs);
double cycleLength = MathConstants<float>::pi / 8.0;
// Noise states
float currentVoltage = -0.5;
double nextAngle = cycleLength;
double previousAngle = 0;
unsigned int rgstr = 0b111111111111111;
void startNote (int midiNoteNumber, float velocity,
SynthesiserSound*, int currentPitchWheelPosition) override;
float voltageForAngle (double angle) override;
};

291
Source/PluginEditor.cpp Normal file
View File

@ -0,0 +1,291 @@
/*
==============================================================================
This file was auto-generated!
It contains the basic framework code for a JUCE plugin editor.
==============================================================================
*/
#include "PluginProcessor.h"
#include "PluginEditor.h"
#include "AdvancedParamsComponent.h"
#include "PulseParamsComponent.h"
#include "BasicParamsComponent.h"
#include "EnvelopeParamsComponent.h"
#include "NoiseParamsComponent.h"
#include "BendParamsComponent.h"
#include "SweepParamsComponent.h"
#include "VibratoParamsComponent.h"
//==============================================================================
Magical8bitPlug2AudioProcessorEditor::Magical8bitPlug2AudioProcessorEditor (Magical8bitPlug2AudioProcessor& p)
: AudioProcessorEditor (&p), processor (p)
{
// Make sure that before the constructor has finished, you've set the
// editor's size to whatever you need it to be.
applyLookAndFeel();
basicCompo.reset (new BasicParamsComponent (p, *this));
addAndMakeVisible (basicCompo.get());
envCompo.reset (new EnvelopeParamsComponent (p));
addAndMakeVisible (envCompo.get());
advCompo.reset (new AdvancedParamsComponent (p));
addAndMakeVisible (advCompo.get());
pulCompo.reset (new PulseParamsComponent (p));
addAndMakeVisible (pulCompo.get());
noiCompo.reset (new NoiseParamsComponent (p));
addAndMakeVisible (noiCompo.get());
bendCompo.reset (new BendParamsComponent (p));
addAndMakeVisible (bendCompo.get());
sweepCompo.reset (new SweepParamsComponent (p));
addAndMakeVisible (sweepCompo.get());
vibCompo.reset (new VibratoParamsComponent (p));
addAndMakeVisible (vibCompo.get());
(p.parameters.getParameter ("isVolumeSequenceEnabled_raw"))->addListener (this);
(p.parameters.getParameter ("isDutySequenceEnabled_raw"))->addListener (this);
resizeWholePanel();
}
void Magical8bitPlug2AudioProcessorEditor::applyLookAndFeel()
{
ColorScheme cs = ColorScheme (processor.settingRefs.colorSchemeType());
//
// Slider
//
getLookAndFeel().setColour (Slider::trackColourId, cs.main);
getLookAndFeel().setColour (Slider::thumbColourId, cs.accent);
getLookAndFeel().setColour (Slider::backgroundColourId, cs.mainDarkened);
getLookAndFeel().setColour (Slider::textBoxTextColourId, cs.mainThinLine);
getLookAndFeel().setColour (Slider::textBoxBackgroundColourId, cs.textBoxFill);
getLookAndFeel().setColour (Slider::textBoxOutlineColourId, cs.genericBorder);
getLookAndFeel().setColour (TextButton::ColourIds::buttonColourId, cs.boxFill);
getLookAndFeel().setColour (TextButton::ColourIds::textColourOffId, cs.reversedForeground);
//
// Label
//
getLookAndFeel().setColour (Label::textColourId, cs.mainThinLine);
//
// Toggle Button
//
getLookAndFeel().setColour (ToggleButton::textColourId, cs.mainThinLine);
getLookAndFeel().setColour (ToggleButton::tickDisabledColourId, cs.mainThinLine);
getLookAndFeel().setColour (ToggleButton::tickColourId, cs.mainThinLine);
//
// Text Editor
//
getLookAndFeel().setColour (TextEditor::textColourId, cs.mainThinLine);
getLookAndFeel().setColour (TextEditor::backgroundColourId, cs.textBoxFill);
getLookAndFeel().setColour (TextEditor::outlineColourId, cs.genericBorder);
//
// Combo Box
//
getLookAndFeel().setColour (ComboBox::backgroundColourId, cs.boxFill);
getLookAndFeel().setColour (ComboBox::textColourId, cs.reversedForeground);
getLookAndFeel().setColour (ComboBox::arrowColourId, cs.reversedForeground);
getLookAndFeel().setColour (ComboBox::buttonColourId, cs.mainThinLine);
getLookAndFeel().setColour (ComboBox::outlineColourId, cs.genericBorder);
}
Magical8bitPlug2AudioProcessorEditor::~Magical8bitPlug2AudioProcessorEditor()
{
(processor.parameters.getParameter ("isVolumeSequenceEnabled_raw"))->removeListener (this);
(processor.parameters.getParameter ("isDutySequenceEnabled_raw"))->removeListener (this);
}
//==============================================================================
struct
{
const int totalWidth = 640;
const int topMargin = 10;
const int leftMargin = 10;
const int bottomMargin = 20;
const int halfComponentWidth = 300;
const int fullComponentWidth = 620;
const int sectionSeparatorHeight = 16;
const int verticalSeparatorWidth = 16;
const int componentMargin = 2;
const int indexHeight = 22;
const int genericControlHeight = 28;
const int customEnvelopeHeight = 56;
const int basCompoHeight = componentMargin * 2
+ genericControlHeight * 2;
const int toneSpecificControlHeight = componentMargin * 2
+ indexHeight
+ genericControlHeight;
const int envCompoHeight = componentMargin * 2
+ indexHeight
+ genericControlHeight * 4;
const int bendCompoHeight = componentMargin * 2
+ indexHeight
+ genericControlHeight;
const int sweepCompoHeight = componentMargin * 2
+ indexHeight
+ genericControlHeight * 2;
const int vibCompoHeight = componentMargin * 2
+ indexHeight
+ genericControlHeight * 4;
const int advCompoHeight = componentMargin * 2
+ indexHeight
+ customEnvelopeHeight * 3;
const int totalHeight (bool isAdvOptOn)
{
if (isAdvOptOn)
{
return topMargin
+ basCompoHeight
+ sectionSeparatorHeight
+ toneSpecificControlHeight
+ envCompoHeight
+ bendCompoHeight
+ sectionSeparatorHeight
+ advCompoHeight
+ bottomMargin;
}
else
{
return topMargin
+ basCompoHeight
+ sectionSeparatorHeight
+ toneSpecificControlHeight
+ envCompoHeight
+ bendCompoHeight
+ bottomMargin;
}
}
} sizes;
void Magical8bitPlug2AudioProcessorEditor::paint (Graphics& g)
{
// fill the whole window white
ColorScheme cs = ColorScheme (processor.settingRefs.colorSchemeType());
g.fillAll (cs.background);
int y = sizes.topMargin
+ sizes.basCompoHeight
+ sizes.sectionSeparatorHeight / 2;
g.setColour (cs.genericBorder);
Line<float> line (Point<float> (sizes.leftMargin, y),
Point<float> (sizes.leftMargin + sizes.fullComponentWidth, y));
g.drawLine (line, 1.0f);
}
void Magical8bitPlug2AudioProcessorEditor::resized()
{
applyLookAndFeel();
//
// Header
//
int x = sizes.leftMargin;
int y = sizes.topMargin;
int w = sizes.halfComponentWidth;
basicCompo->setBounds (x, y, sizes.fullComponentWidth, sizes.basCompoHeight);
//
// Main part - Left
//
y = sizes.topMargin + sizes.basCompoHeight + sizes.sectionSeparatorHeight;
pulCompo->setBounds (x, y, w, sizes.toneSpecificControlHeight);
noiCompo->setBounds (x, y, w, sizes.toneSpecificControlHeight);
y += sizes.toneSpecificControlHeight;
envCompo->setBounds (x, y, w, sizes.envCompoHeight);
y += sizes.envCompoHeight;
bendCompo->setBounds (x, y, w, sizes.bendCompoHeight);
y += sizes.bendCompoHeight;
//
// Main part - Right
//
x = sizes.leftMargin + sizes.halfComponentWidth + sizes.verticalSeparatorWidth;
int y2 = sizes.topMargin + sizes.basCompoHeight + sizes.sectionSeparatorHeight;
sweepCompo->setBounds (x, y2, w, sizes.sweepCompoHeight);
y2 += sizes.sweepCompoHeight;
vibCompo->setBounds (x, y2, w, sizes.vibCompoHeight);
y2 += sizes.vibCompoHeight;
//
// Advanced part
//
x = sizes.leftMargin;
int y3 = y > y2 ? y : y2;
y3 += sizes.sectionSeparatorHeight;
advCompo->setBounds (x, y3, sizes.fullComponentWidth, sizes.advCompoHeight);
//
// Visibility
//
switch (processor.settingRefs.oscillatorType())
{
case kVoiceTypePulse:
pulCompo->setVisible (true);
noiCompo->setVisible (false);
break;
case kVoiceTypeNoise:
pulCompo->setVisible (false);
noiCompo->setVisible (true);
break;
default:
pulCompo->setVisible (false);
noiCompo->setVisible (false);
break;
}
//
// Enable/Disable
//
envCompo->setEnabled (!processor.settingRefs.isVolumeSequenceEnabled());
pulCompo->setEnabled (!processor.settingRefs.isDutySequenceEnabled());
sendLookAndFeelChange();
}
void Magical8bitPlug2AudioProcessorEditor::resizeWholePanel()
{
setSize (sizes.totalWidth, sizes.totalHeight (processor.settingRefs.isAdvancedPanelOpen()));
}
void Magical8bitPlug2AudioProcessorEditor::parameterValueChanged (int parameterIndex, float newValue)
{
if (parameterIndex == (processor.parameters.getParameter ("isVolumeSequenceEnabled_raw"))->getParameterIndex())
{
printf ("Volume sequence enabled flag %f\n", newValue);
bool isEnabled = newValue > 0.5;
envCompo->setEnabled (!isEnabled);
}
else if (parameterIndex == (processor.parameters.getParameter ("isDutySequenceEnabled_raw"))->getParameterIndex())
{
printf ("Duty sequence enabled flag %f\n", newValue);
bool isEnabled = newValue > 0.5;
pulCompo->setEnabled (!isEnabled);
}
}

56
Source/PluginEditor.h Normal file
View File

@ -0,0 +1,56 @@
/*
==============================================================================
This file was auto-generated!
It contains the basic framework code for a JUCE plugin editor.
==============================================================================
*/
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
#include "PluginProcessor.h"
class AdvancedParamsComponent;
class PulseParamsComponent;
class BasicParamsComponent;
class EnvelopeParamsComponent;
class NoiseParamsComponent;
class BendParamsComponent;
class SweepParamsComponent;
class VibratoParamsComponent;
//==============================================================================
/**
*/
class Magical8bitPlug2AudioProcessorEditor : public AudioProcessorEditor
, public AudioProcessorParameter::Listener
{
public:
Magical8bitPlug2AudioProcessorEditor (Magical8bitPlug2AudioProcessor&);
~Magical8bitPlug2AudioProcessorEditor();
//==============================================================================
void paint (Graphics&) override;
void resized() override;
void resizeWholePanel();
void applyLookAndFeel();
void parameterValueChanged (int parameterIndex, float newValue) override;
void parameterGestureChanged (int parameterIndex, bool gestureIsStarting) override {};
private:
Magical8bitPlug2AudioProcessor& processor;
std::unique_ptr<BasicParamsComponent> basicCompo;
std::unique_ptr<EnvelopeParamsComponent> envCompo;
std::unique_ptr<AdvancedParamsComponent> advCompo;
std::unique_ptr<PulseParamsComponent> pulCompo;
std::unique_ptr<NoiseParamsComponent> noiCompo;
std::unique_ptr<BendParamsComponent> bendCompo;
std::unique_ptr<SweepParamsComponent> sweepCompo;
std::unique_ptr<VibratoParamsComponent> vibCompo;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Magical8bitPlug2AudioProcessorEditor)
};

476
Source/PluginProcessor.cpp Normal file
View File

@ -0,0 +1,476 @@
/*
==============================================================================
This file was auto-generated!
It contains the basic framework code for a JUCE plugin processor.
==============================================================================
*/
#include "PluginProcessor.h"
#include "PluginEditor.h"
#include "PulseVoice.h"
#include "TriangleVoice.h"
#include "NoiseVoice.h"
#include "FrameSequenceParseErrors.h"
//==============================================================================
Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
: parameters (
*this, nullptr, Identifier ("Params"),
{
//
// Meta
//
std::make_unique<AudioParameterBool> ("isAdvancedPanelOpen_raw", "Advanced", false),
std::make_unique<AudioParameterChoice> ("colorScheme", "Color Scheme", StringArray ({"YMCK", "YMCK Dark", "Japan", "Worldwide", "Monotone", "Mono Dark"}), 0),
//
// Basic
//
std::make_unique<AudioParameterChoice> ("osc", "OSC Type", StringArray ({"Pulse/Square", "Triangle", "Noise"}), 0),
std::make_unique<AudioParameterFloat> ("gain", "Gain", 0.0f, 1.0f, 0.5f),
std::make_unique<AudioParameterFloat> ("maxPoly", "Max Poly", NormalisableRange<float> (1.0f, //min
64.0f, //max
1.0f, //step
1.0f), //skew
8),
//
// ADSR
//
std::make_unique<AudioParameterFloat> ("attack", //ID
"Attack", //name
NormalisableRange<float> (0.0f, //min
5.0f, //max
0.001f, //step
0.5f), //skew
0.0f), //default
std::make_unique<AudioParameterFloat> ("decay", //ID
"Decay", //name
NormalisableRange<float> (0.0f, //min
5.0f, //max
0.001f, //step
0.5f), //skew
0.0f), //default
std::make_unique<AudioParameterFloat> ("suslevel", //ID
"Sustain", //name
0.0f, //min
1.0f, //max
1.0f),//default
std::make_unique<AudioParameterFloat> ("release", //ID
"Release", //name
NormalisableRange<float> (0.0f, //min
5.0f, //max
0.001f, //step
0.5f), //skew
0.0f), //default
//
// Arpeggio
//
std::make_unique<AudioParameterBool> ("isArpeggioEnabled_raw", "Enabled", false),
std::make_unique<AudioParameterFloat> ("arpeggioTime", "Time", 0.0f, 0.3f, 0.033f),
std::make_unique<AudioParameterChoice> ("arpeggioDirection", "Direction", StringArray ({"up", "down"}), 0),
//
// Bend
//
std::make_unique<AudioParameterInt> ("bendRange", "Bend Range", 0, 24, 2),
//
// Vibrato
//
std::make_unique<AudioParameterFloat> ("vibratoRate", //ID
"Rate", //name
NormalisableRange<float> (0.01f, //min
1.0f, //max
0.001f, //step
0.5f), //skew
0.15f), //default
std::make_unique<AudioParameterFloat> ("vibratoDepth", "Depth", 0.0f, 2.0f, 0.0f),
std::make_unique<AudioParameterFloat> ("vibratoDelay", "Delay", 0.0f, 1.0f, 0.3f),
std::make_unique<AudioParameterBool> ("vibratoIgnoresWheel_raw", "Ignores Wheel", true),
//
// Sweep
//
std::make_unique<AudioParameterInt> ("sweepInitialPitch", "Ini.Pitch", -24, 24, 0),
std::make_unique<AudioParameterFloat> ("sweepTime", //ID
"Time", //name
NormalisableRange<float> (0.01f, //min
5.0f, //max
0.001f, //step
0.5f), //skew
0.1f), //default
//
// For Pulse
//
std::make_unique<AudioParameterChoice> ("duty", "Duty", StringArray ({"12.5%", "25%", "50%"}), 0),
//
// For Noise
//
std::make_unique<AudioParameterChoice> ("noiseAlgorithm_raw", "Algorithm", StringArray ({"4bit Pure Random", "1bit Long Cycle", "1bit Short Cycle"}), 0),
std::make_unique<AudioParameterBool> ("restrictsToNESFrequency_raw", "Restricts to NES frequency", false),
//
// Sequence
//
std::make_unique<AudioParameterBool> ("isVolumeSequenceEnabled_raw", "Enabled", false),
std::make_unique<AudioParameterBool> ("isPitchSequenceEnabled_raw", "Enabled", false),
std::make_unique<AudioParameterBool> ("isDutySequenceEnabled_raw", "Enabled", false),
std::make_unique<AudioParameterChoice> ("pitchSequenceMode_raw", "Mode", StringArray ({"Coarse", "Fine"}), 0)
}
)
, settingRefs (&parameters)
#ifndef JucePlugin_PreferredChannelConfigurations
, AudioProcessor (BusesProperties()
#if ! JucePlugin_IsMidiEffect
#if ! JucePlugin_IsSynth
.withInput ("Input", AudioChannelSet::stereo(), true)
#endif
.withOutput ("Output", AudioChannelSet::stereo(), true)
#endif
)
#endif
{
synth.setCurrentPlaybackSampleRate (44100); // Temporary setup, just in case. The actual sample rate is set in prepareToPlay func.
setupVoice();
synth.addSound (new GenericSound());
}
Magical8bitPlug2AudioProcessor::~Magical8bitPlug2AudioProcessor()
{
}
//==============================================================================
void Magical8bitPlug2AudioProcessor::setupVoice()
{
int poly = synth.getNumVoices();
for (auto i = 0; i < poly; i++)
{
synth.removeVoice (0);
}
int type = roundToInt (*settingRefs.osc);
for (auto i = 0; i < (int) (*settingRefs.maxPoly); ++i)
{
switch (type)
{
case kVoiceTypePulse:
synth.addVoice (new PulseVoice (&settingRefs));
break;
case kVoiceTypeTriangle:
synth.addVoice (new TriangleVoice (&settingRefs));
break;
case kVoiceTypeNoise:
synth.addVoice (new NoiseVoice (&settingRefs));
break;
}
}
}
//==============================================================================
const String Magical8bitPlug2AudioProcessor::getName() const
{
return JucePlugin_Name;
}
bool Magical8bitPlug2AudioProcessor::acceptsMidi() const
{
#if JucePlugin_WantsMidiInput
return true;
#else
return false;
#endif
}
bool Magical8bitPlug2AudioProcessor::producesMidi() const
{
#if JucePlugin_ProducesMidiOutput
return true;
#else
return false;
#endif
}
bool Magical8bitPlug2AudioProcessor::isMidiEffect() const
{
#if JucePlugin_IsMidiEffect
return true;
#else
return false;
#endif
}
double Magical8bitPlug2AudioProcessor::getTailLengthSeconds() const
{
return 0.0;
}
int Magical8bitPlug2AudioProcessor::getNumPrograms()
{
return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs,
// so this should be at least 1, even if you're not really implementing programs.
}
int Magical8bitPlug2AudioProcessor::getCurrentProgram()
{
return 0;
}
void Magical8bitPlug2AudioProcessor::setCurrentProgram (int index)
{
}
const String Magical8bitPlug2AudioProcessor::getProgramName (int index)
{
return {};
}
void Magical8bitPlug2AudioProcessor::changeProgramName (int index, const String& newName)
{
}
//==============================================================================
void Magical8bitPlug2AudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
// Use this method as the place to do any pre-playback
// initialisation that you need..
synth.setCurrentPlaybackSampleRate (sampleRate);
}
void Magical8bitPlug2AudioProcessor::releaseResources()
{
// When playback stops, you can use this as an opportunity to free up any
// spare memory, etc.
}
#ifndef JucePlugin_PreferredChannelConfigurations
bool Magical8bitPlug2AudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
{
#if JucePlugin_IsMidiEffect
ignoreUnused (layouts);
return true;
#else
// This is the place where you check if the layout is supported.
// In this template code we only support mono or stereo.
if (layouts.getMainOutputChannelSet() != AudioChannelSet::mono()
&& layouts.getMainOutputChannelSet() != AudioChannelSet::stereo())
return false;
// This checks if the input layout matches the output layout
#if ! JucePlugin_IsSynth
if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
return false;
#endif
return true;
#endif
}
#endif
void Magical8bitPlug2AudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
{
synth.renderNextBlock (buffer, midiMessages, 0, buffer.getNumSamples()); // [5]
/*
buffer.clear();
MidiBuffer processedMidi;
int time;
MidiMessage m;
for (MidiBuffer::Iterator i (midiMessages); i.getNextEvent (m, time);)
{
if (m.isNoteOn())
{
uint8 newVel = (uint8)noteOnVel;
m = MidiMessage::noteOn(m.getChannel(), m.getNoteNumber(), newVel);
}
else if (m.isNoteOff())
{
}
else if (m.isAftertouch())
{
}
else if (m.isPitchWheel())
{
}
processedMidi.addEvent (m, time);
}
midiMessages.swapWith (processedMidi);
ScopedNoDenormals noDenormals;
auto totalNumInputChannels = getTotalNumInputChannels();
auto totalNumOutputChannels = getTotalNumOutputChannels();
// In case we have more outputs than inputs, this code clears any output
// channels that didn't contain input data, (because these aren't
// guaranteed to be empty - they may contain garbage).
// This is here to avoid people getting screaming feedback
// when they first compile a plugin, but obviously you don't need to keep
// this code if your algorithm always overwrites all the output channels.
for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
buffer.clear (i, 0, buffer.getNumSamples());
// This is the place where you'd normally do the guts of your plugin's
// audio processing...
// Make sure to reset the state if your inner loop is processing
// the samples and the outer loop is handling the channels.
// Alternatively, you can process the samples with the channels
// interleaved by keeping the same state.
for (int channel = 0; channel < totalNumInputChannels; ++channel)
{
auto* channelData = buffer.getWritePointer (channel);
// ..do something to the data...
}
*/
}
//==============================================================================
bool Magical8bitPlug2AudioProcessor::hasEditor() const
{
return true; // (change this to false if you choose to not supply an editor)
}
AudioProcessorEditor* Magical8bitPlug2AudioProcessor::createEditor()
{
return new Magical8bitPlug2AudioProcessorEditor (*this);
}
//==============================================================================
void Magical8bitPlug2AudioProcessor::getStateInformation (MemoryBlock& destData)
{
auto state = parameters.copyState();
XmlElement* rootElement = new XmlElement ("root");
std::unique_ptr<XmlElement> stateElement = std::unique_ptr<XmlElement> (state.createXml());
rootElement->addChildElement (stateElement.get());
stateElement.release(); // give up the ownership already because xml object will delete it
XmlElement* volEnvElement = new XmlElement ("volumeEnv");
XmlElement* pitEnvElement = new XmlElement ("pitchEnv");
XmlElement* dutEnvElement = new XmlElement ("dutyEnv");
volEnvElement->addTextElement (settingRefs.volumeSequenceString);
pitEnvElement->addTextElement (settingRefs.pitchSequenceString);
dutEnvElement->addTextElement (settingRefs.dutySequenceString);
rootElement->addChildElement (volEnvElement);
rootElement->addChildElement (pitEnvElement);
rootElement->addChildElement (dutEnvElement);
std::unique_ptr<XmlElement> xml (rootElement);
copyXmlToBinary (*xml, destData);
}
void Magical8bitPlug2AudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
std::unique_ptr<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));
if (xmlState.get() != nullptr)
{
if (xmlState->hasTagName ("root"))
{
// ValueTree
XmlElement* valueTreeXml = xmlState->getChildByName (parameters.state.getType());
if (valueTreeXml != nullptr)
{
parameters.replaceState (ValueTree::fromXml (*valueTreeXml));
}
else
{
printf ("Saved plugin parameters are incompatible");
}
// Custom Env
XmlElement* volumeEnvXml = xmlState->getChildByName ("volumeEnv");
XmlElement* pitchEnvXml = xmlState->getChildByName ("pitchEnv");
XmlElement* dutyEnvXml = xmlState->getChildByName ("dutyEnv");
if (volumeEnvXml != nullptr)
{
XmlElement* volElem = volumeEnvXml->getFirstChildElement();
if (volElem != nullptr && volElem->isTextElement())
{
String volStr = volElem->getText();
ParseError err = kParseErrorNone;
settingRefs.setSequenceWithString ("volume", volStr, &err);
if (settingRefs.volumeSequenceListener != nullptr)
{
settingRefs.volumeSequenceListener->sequenceChanged (volStr);
}
Logger::writeToLog ("volume seq = " + volStr);
}
else
{
Logger::writeToLog ("volumeEnv entry found, but seems not like a text element.");
}
}
if (pitchEnvXml != nullptr)
{
XmlElement* pitElem = pitchEnvXml->getFirstChildElement();
if (pitElem != nullptr && pitElem->isTextElement())
{
String pitStr = pitElem->getText();
ParseError err = kParseErrorNone;
settingRefs.setSequenceWithString ("pitch", pitStr, &err);
if (settingRefs.pitchSequenceListener != nullptr)
{
settingRefs.pitchSequenceListener->sequenceChanged (pitStr);
}
Logger::writeToLog ("pitch seq = " + pitStr);
}
else
{
Logger::writeToLog ("pitchEnv entry found, but seems not like a text element.");
}
}
if (dutyEnvXml != nullptr)
{
XmlElement* dutElem = dutyEnvXml->getFirstChildElement();
if (dutElem != nullptr && dutElem->isTextElement())
{
String dutStr = dutElem->getText();
ParseError err = kParseErrorNone;
settingRefs.setSequenceWithString ("duty", dutStr, &err);
if (settingRefs.dutySequenceListener != nullptr)
{
settingRefs.dutySequenceListener->sequenceChanged (dutStr);
}
Logger::writeToLog ("duty seq = " + dutStr);
}
else
{
Logger::writeToLog ("dutyEnv entry found, but seems not like a text element.");
}
}
}
}
setupVoice();
}
//==============================================================================
// This creates new instances of the plugin..
AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
return new Magical8bitPlug2AudioProcessor();
}

83
Source/PluginProcessor.h Normal file
View File

@ -0,0 +1,83 @@
/*
==============================================================================
This file was auto-generated!
It contains the basic framework code for a JUCE plugin processor.
==============================================================================
*/
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
#include "Settings.h"
#include "Voices.h"
//==============================================================================
struct GenericSound : public SynthesiserSound
{
GenericSound() {}
bool appliesToNote (int) override { return true; }
bool appliesToChannel (int) override { return true; }
};
//==============================================================================
/**
*/
class Magical8bitPlug2AudioProcessor : public AudioProcessor
{
public:
//==============================================================================
Magical8bitPlug2AudioProcessor();
~Magical8bitPlug2AudioProcessor();
//==============================================================================
float noteOnVel;
void prepareToPlay (double sampleRate, int samplesPerBlock) override;
void releaseResources() override;
#ifndef JucePlugin_PreferredChannelConfigurations
bool isBusesLayoutSupported (const BusesLayout& layouts) const override;
#endif
void processBlock (AudioBuffer<float>&, MidiBuffer&) override;
//==============================================================================
AudioProcessorEditor* createEditor() override;
bool hasEditor() const override;
//==============================================================================
const String getName() const override;
bool acceptsMidi() const override;
bool producesMidi() const override;
bool isMidiEffect() const override;
double getTailLengthSeconds() const override;
//==============================================================================
int getNumPrograms() override;
int getCurrentProgram() override;
void setCurrentProgram (int index) override;
const String getProgramName (int index) override;
void changeProgramName (int index, const String& newName) override;
//==============================================================================
void getStateInformation (MemoryBlock& destData) override;
void setStateInformation (const void* data, int sizeInBytes) override;
//==============================================================================
void setupVoice();
AudioProcessorValueTreeState parameters;
SettingRefs settingRefs;
private:
//==============================================================================
Synthesiser synth;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Magical8bitPlug2AudioProcessor)
};

View File

@ -0,0 +1,168 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "PulseParamsComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
PulseParamsComponent::PulseParamsComponent (Magical8bitPlug2AudioProcessor& p)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
label.reset (new Label ("label",
TRANS("Pulse")));
addAndMakeVisible (label.get());
label->setFont (Font (17.00f, Font::plain).withTypefaceStyle ("Regular"));
label->setJustificationType (Justification::centredLeft);
label->setEditable (false, false, false);
label->setColour (TextEditor::textColourId, Colours::black);
label->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
label->setBounds (0, 4, 150, 22);
dutySelector.reset (new ChoiceComponent (p, "duty", "Duty"));
addAndMakeVisible (dutySelector.get());
dutySelector->setName ("duty selector");
warningLabel.reset (new Label ("warning label",
String()));
addAndMakeVisible (warningLabel.get());
warningLabel->setFont (Font (15.00f, Font::plain).withTypefaceStyle ("Regular"));
warningLabel->setJustificationType (Justification::centredRight);
warningLabel->setEditable (false, false, false);
warningLabel->setColour (TextEditor::textColourId, Colours::black);
warningLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
//[UserPreSize]
//[/UserPreSize]
setSize (340, 58);
//[Constructor] You can add your own custom stuff here..
ColorScheme cs = ColorScheme (p.settingRefs.colorSchemeType());
warningLabelLookAndFeel.setColour (Label::textColourId, cs.warning);
warningLabel->setLookAndFeel (&warningLabelLookAndFeel);
//[/Constructor]
}
PulseParamsComponent::~PulseParamsComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
//[/Destructor_pre]
label = nullptr;
dutySelector = nullptr;
warningLabel = nullptr;
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]
}
//==============================================================================
void PulseParamsComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void PulseParamsComponent::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
dutySelector->setBounds (0, 26, proportionOfWidth (1.0000f), 28);
warningLabel->setBounds (getWidth() - 8 - 246, 4, 246, 24);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
void PulseParamsComponent::enablementChanged()
{
//[UserCode_enablementChanged] -- Add your code here...
if (isEnabled())
{
warningLabel->setText (TRANS (""), dontSendNotification);
}
else
{
warningLabel->setText (TRANS ("Overridden by Duty Envelope"), dontSendNotification);
}
//[/UserCode_enablementChanged]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Projucer information section --
This is where the Projucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="PulseParamsComponent" componentName=""
parentClasses="public Component" constructorParams="Magical8bitPlug2AudioProcessor&amp; p"
variableInitialisers="" snapPixels="8" snapActive="1" snapShown="1"
overlayOpacity="0.330" fixedSize="1" initialWidth="340" initialHeight="58">
<METHODS>
<METHOD name="enablementChanged()"/>
</METHODS>
<BACKGROUND backgroundColour="ffffff"/>
<LABEL name="label" id="bae3132bcad681ce" memberName="label" virtualName=""
explicitFocusOrder="0" pos="0 4 150 22" edTextCol="ff000000"
edBkgCol="0" labelText="Pulse" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="17.0"
kerning="0.0" bold="0" italic="0" justification="33"/>
<GENERICCOMPONENT name="duty selector" id="b01ddc412ec6dc27" memberName="dutySelector"
virtualName="" explicitFocusOrder="0" pos="0 26 100% 28" class="ChoiceComponent"
params="p, &quot;duty&quot;, &quot;Duty&quot;"/>
<LABEL name="warning label" id="624aa3e1415981e3" memberName="warningLabel"
virtualName="" explicitFocusOrder="0" pos="8Rr 4 246 24" edTextCol="ff000000"
edBkgCol="0" labelText="" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="15.0"
kerning="0.0" bold="0" italic="0" justification="34"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -0,0 +1,71 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
#pragma once
//[Headers] -- You can add your own extra header files here --
#include "../JuceLibraryCode/JuceHeader.h"
#include "ChoiceComponent.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Projucer.
Describe your class and how it works here!
//[/Comments]
*/
class PulseParamsComponent : public Component
{
public:
//==============================================================================
PulseParamsComponent (Magical8bitPlug2AudioProcessor& p);
~PulseParamsComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
//[/UserMethods]
void paint (Graphics& g) override;
void resized() override;
void enablementChanged() override;
private:
//[UserVariables] -- You can add your own custom variables in this section.
LookAndFeel_V4 warningLabelLookAndFeel;
//[/UserVariables]
//==============================================================================
std::unique_ptr<Label> label;
std::unique_ptr<ChoiceComponent> dutySelector;
std::unique_ptr<Label> warningLabel;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PulseParamsComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

62
Source/PulseVoice.cpp Normal file
View File

@ -0,0 +1,62 @@
/*
==============================================================================
PulseVoice.cpp
Created: 11 Nov 2019 9:36:51pm
Author: 除村 武志
==============================================================================
*/
#include "PulseVoice.h"
//---------------------------------------------
//
// Pulse Voice
//
//---------------------------------------------
PulseVoice::PulseVoice (SettingRefs* sRefs) : TonalVoice (sRefs) {}
void PulseVoice::startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int currentPitchBendPosition)
{
TonalVoice::startNote (midiNoteNumber, velocity, 0, currentPitchBendPosition);
currentDutySequenceFrame = 0;
currentDuty = (PulseDuty) ((int) (*settingRefs->duty));
}
float PulseVoice::voltageForAngle (double angle)
{
float rate = 1.0;
switch (currentDuty)
{
case kPulseDuty125:
rate = 0.25;
break;
case kPulseDuty250:
rate = 0.50;
break;
case kPulseDuty500:
rate = 1.00;
break;
default:
break;
}
return angle < rate * MathConstants<float>::pi ? -1.0 : 1.0;
}
void PulseVoice::advanceControlFrame()
{
TonalVoice::advanceControlFrame();
if (settingRefs->isDutySequenceEnabled())
{
currentDutySequenceFrame = settingRefs->dutySequence.nextIndexOf (currentDutySequenceFrame);
currentDuty = (PulseDuty)settingRefs->dutySequence.valueAt (currentDutySequenceFrame);
}
}

28
Source/PulseVoice.h Normal file
View File

@ -0,0 +1,28 @@
/*
==============================================================================
PulseVoice.h
Created: 11 Nov 2019 9:36:51pm
Author: 除村 武志
==============================================================================
*/
#pragma once
#include "TonalVoice.h"
struct PulseVoice : public TonalVoice
{
PulseVoice (SettingRefs* sRefs);
PulseDuty currentDuty = kPulseDuty500; // May be changed by Duty Sequence
// Custom Duty Sequence states
int currentDutySequenceFrame = 0;
void startNote (int midiNoteNumber, float velocity,
SynthesiserSound*, int currentPitchWheelPosition) override;
float voltageForAngle (double angle) override;
void advanceControlFrame() override;
};

79
Source/Settings.cpp Normal file
View File

@ -0,0 +1,79 @@
/*
==============================================================================
Settings.cpp
Created: 23 May 2019 11:54:44am
Author: 除村 武志
==============================================================================
*/
#include "Settings.h"
#include "FrameSequenceParser.h"
bool SettingRefs::setSequenceWithString (const String& type, const String& input, ParseError* error)
{
FrameSequenceParser parser;
if (type == "volume")
{
FrameSequence res = parser.parse (input, 0, 15, error);
if (*error > kParseErrorLevelFatal)
{
return false;
}
volumeSequence = res;
volumeSequenceString = input;
return true;
}
else if (type == "pitch")
{
FrameSequence res = parser.parse (input, -64, 63, error);
if (*error > kParseErrorLevelFatal)
{
return false;
}
pitchSequence = res;
pitchSequenceString = input;
return true;
}
else if (type == "duty")
{
FrameSequence res = parser.parse (input, 0, 2, error);
if (*error > kParseErrorLevelFatal)
{
return false;
}
dutySequence = res;
dutySequenceString = input;
return true;
}
printf ("*** parameter type invalid!\n");
return false;
}
String& SettingRefs::getSequenceString (const String& type)
{
if (type == "volume")
{
return volumeSequenceString;
}
else if (type == "pitch")
{
return pitchSequenceString;
}
else if (type == "duty")
{
return dutySequenceString;
}
printf ("*** parameter type invalid!\n");
return volumeSequenceString;
}

199
Source/Settings.h Normal file
View File

@ -0,0 +1,199 @@
/*
==============================================================================
Settings.h
Created: 23 May 2019 11:54:44am
Author: 除村 武志
==============================================================================
*/
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
#include "ColorScheme.h"
#include "FrameSequence.h"
#include "FrameSequenceParseErrors.h"
//---------------------------------------------
//
// Plugin Global
//
//---------------------------------------------
enum VoiceType
{
kVoiceTypePulse = 0,
kVoiceTypeTriangle,
kVoiceTypeNoise
};
struct PluginSettings
{
VoiceType type = kVoiceTypePulse;
int maxPoly = 1;
double gain = 1.0;
double arpeggioTime = 0;
double bendRange = 2;
};
//---------------------------------------------
//
// Tone Specific
//
//---------------------------------------------
enum PulseDuty
{
kPulseDuty125 = 0,
kPulseDuty250,
kPulseDuty500,
};
enum NoiseAlgorithm
{
kNoiseInfinite2 = 0,
kNoiseLong,
kNoiseShort,
};
enum PitchSequenceMode
{
kPitchSequenceModeCoarse = 0,
kPitchSequenceModeFine
};
class FrameSequenceChangeListener
{
public:
FrameSequenceChangeListener() {}
virtual ~FrameSequenceChangeListener() {};
virtual void sequenceChanged (String& str) {};
};
struct FrameSequenceParseException
{
String message;
bool isFatal;
FrameSequenceParseException (String mes, bool fatalFlag)
{
message = mes;
isFatal = fatalFlag;
}
};
struct SettingRefs
{
// Meta
float* isAdvancedPanelOpen_raw = nullptr;
float* colorScheme = nullptr;
// Basic
float* osc = nullptr;
float* gain = nullptr;
float* maxPoly = nullptr;
// ADSR
float* attack = nullptr;
float* decay = nullptr;
float* suslevel = nullptr;
float* release = nullptr;
// Arpeggio
float* isArpeggioEnabled_raw = nullptr;
float* arpeggioTime = nullptr;
float* arpeggioDirection = nullptr;
// Bend
float* bendRange = nullptr;
// Vibrato
float* vibratoRate = nullptr;
float* vibratoDepth = nullptr;
float* vibratoDelay = nullptr;
float* vibratoIgnoresWheel_raw = nullptr;
// Sweep
float* sweepInitialPitch = nullptr;
float* sweepTime = nullptr;
// For Pulse
float* duty = nullptr;
// For Noise
float* noiseAlgorithm_raw = nullptr;
float* restrictsToNESFrequency_raw = nullptr;
// Sequence
float* isVolumeSequenceEnabled_raw = nullptr;
float* isPitchSequenceEnabled_raw = nullptr;
float* isDutySequenceEnabled_raw = nullptr;
float* pitchSequenceMode_raw = nullptr;
FrameSequence volumeSequence;
FrameSequence pitchSequence;
FrameSequence dutySequence;
String volumeSequenceString = "";
String pitchSequenceString = "";
String dutySequenceString = "";
bool setSequenceWithString (const String& type, const String& input, ParseError* error);
String& getSequenceString (const String& type);
FrameSequence parseSequenceString (const String& input);
FrameSequenceChangeListener* volumeSequenceListener = nullptr;
FrameSequenceChangeListener* pitchSequenceListener = nullptr;
FrameSequenceChangeListener* dutySequenceListener = nullptr;
//
// accessors
//
int oscillatorType() { return (int) (*osc); }
bool isAdvancedPanelOpen() { return *isAdvancedPanelOpen_raw > 0.5; }
ColorSchemeType colorSchemeType() { return (ColorSchemeType) ((int) (*colorScheme)); }
bool isArpeggioEnabled() { return *isArpeggioEnabled_raw > 0.5; }
NoiseAlgorithm noiseAlgorithm() { return (NoiseAlgorithm) ((int) (*noiseAlgorithm_raw)); }
bool vibratoIgnoresWheel() { return *vibratoIgnoresWheel_raw > 0.5; }
bool isVolumeSequenceEnabled() { return *isVolumeSequenceEnabled_raw > 0.5; }
bool isPitchSequenceEnabled() { return *isPitchSequenceEnabled_raw > 0.5; }
bool isDutySequenceEnabled() { return *isDutySequenceEnabled_raw > 0.5; }
PitchSequenceMode pitchSequenceMode() { return (PitchSequenceMode) ((int) (*pitchSequenceMode_raw)); }
//
// constructor
//
SettingRefs (AudioProcessorValueTreeState* parameters)
{
// Meta
isAdvancedPanelOpen_raw = parameters->getRawParameterValue ("isAdvancedPanelOpen_raw");
colorScheme = parameters->getRawParameterValue ("colorScheme");
// Basic
osc = parameters->getRawParameterValue ("osc");
gain = parameters->getRawParameterValue ("gain");
maxPoly = parameters->getRawParameterValue ("maxPoly");
// ADSR
attack = parameters->getRawParameterValue ("attack");
decay = parameters->getRawParameterValue ("decay");
suslevel = parameters->getRawParameterValue ("suslevel");
release = parameters->getRawParameterValue ("release");
// Arpeggio
isArpeggioEnabled_raw = parameters->getRawParameterValue ("isArpeggioEnabled_raw");
arpeggioTime = parameters->getRawParameterValue ("arpeggioTime");
arpeggioDirection = parameters->getRawParameterValue ("arpeggioDirection");
// Bend
bendRange = parameters->getRawParameterValue ("bendRange");
// Vibrato
vibratoRate = parameters->getRawParameterValue ("vibratoRate");
vibratoDepth = parameters->getRawParameterValue ("vibratoDepth");
vibratoDelay = parameters->getRawParameterValue ("vibratoDelay");
vibratoIgnoresWheel_raw = parameters->getRawParameterValue ("vibratoIgnoresWheel_raw");
// Sweep
sweepInitialPitch = parameters->getRawParameterValue ("sweepInitialPitch");
sweepTime = parameters->getRawParameterValue ("sweepTime");
// For Pulse
duty = parameters->getRawParameterValue ("duty");
// For Noise
noiseAlgorithm_raw = parameters->getRawParameterValue ("noiseAlgorithm_raw");
restrictsToNESFrequency_raw = parameters->getRawParameterValue ("restrictsToNESFrequency_raw");
// Sequence
isVolumeSequenceEnabled_raw = parameters->getRawParameterValue ("isVolumeSequenceEnabled_raw");
isPitchSequenceEnabled_raw = parameters->getRawParameterValue ("isPitchSequenceEnabled_raw");
isDutySequenceEnabled_raw = parameters->getRawParameterValue ("isDutySequenceEnabled_raw");
pitchSequenceMode_raw = parameters->getRawParameterValue ("pitchSequenceMode_raw");
}
};

139
Source/SliderComponent.cpp Normal file
View File

@ -0,0 +1,139 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "SliderComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
SliderComponent::SliderComponent (Magical8bitPlug2AudioProcessor& p, String paramId, String name)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
label.reset (new Label ("label",
TRANS("Label")));
addAndMakeVisible (label.get());
label->setFont (Font (14.00f, Font::plain).withTypefaceStyle ("Regular"));
label->setJustificationType (Justification::centredRight);
label->setEditable (false, false, false);
label->setColour (TextEditor::textColourId, Colours::black);
label->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
label->setBounds (8, 1, 60, 24);
slider.reset (new Slider ("slider"));
addAndMakeVisible (slider.get());
slider->setRange (0, 10, 0.01);
slider->setSliderStyle (Slider::LinearHorizontal);
slider->setTextBoxStyle (Slider::TextBoxRight, false, 50, 20);
//[UserPreSize]
//[/UserPreSize]
setSize (360, 28);
//[Constructor] You can add your own custom stuff here..
label->setText (name, dontSendNotification);
attc.reset (new SliderAttachment (p.parameters, paramId, *slider));
//[/Constructor]
}
SliderComponent::~SliderComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
attc.reset();
//[/Destructor_pre]
label = nullptr;
slider = nullptr;
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]
}
//==============================================================================
void SliderComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void SliderComponent::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
slider->setBounds (72, 1, getWidth() - 80, 24);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Projucer information section --
This is where the Projucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="SliderComponent" componentName=""
parentClasses="public Component" constructorParams="Magical8bitPlug2AudioProcessor&amp; p, String paramId, String name"
variableInitialisers="" snapPixels="8" snapActive="1" snapShown="1"
overlayOpacity="0.330" fixedSize="1" initialWidth="360" initialHeight="28">
<BACKGROUND backgroundColour="ffffff"/>
<LABEL name="label" id="af1fa4a96c3448e5" memberName="label" virtualName=""
explicitFocusOrder="0" pos="8 1 60 24" edTextCol="ff000000" edBkgCol="0"
labelText="Label" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="14.0"
kerning="0.0" bold="0" italic="0" justification="34"/>
<SLIDER name="slider" id="2d6901c46e73c1e" memberName="slider" virtualName=""
explicitFocusOrder="0" pos="72 1 80M 24" min="0.0" max="10.0"
int="0.01" style="LinearHorizontal" textBoxPos="TextBoxRight"
textBoxEditable="1" textBoxWidth="50" textBoxHeight="20" skewFactor="1.0"
needsCallback="0"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

70
Source/SliderComponent.h Normal file
View File

@ -0,0 +1,70 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
#pragma once
//[Headers] -- You can add your own extra header files here --
#include "../JuceLibraryCode/JuceHeader.h"
#include "PluginProcessor.h"
#include "Defs.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Projucer.
Describe your class and how it works here!
//[/Comments]
*/
class SliderComponent : public Component
{
public:
//==============================================================================
SliderComponent (Magical8bitPlug2AudioProcessor& p, String paramId, String name);
~SliderComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
//[/UserMethods]
void paint (Graphics& g) override;
void resized() override;
private:
//[UserVariables] -- You can add your own custom variables in this section.
std::unique_ptr<SliderAttachment> attc;
//[/UserVariables]
//==============================================================================
std::unique_ptr<Label> label;
std::unique_ptr<Slider> slider;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SliderComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -0,0 +1,140 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "SweepParamsComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
SweepParamsComponent::SweepParamsComponent (Magical8bitPlug2AudioProcessor& p)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
label.reset (new Label ("label",
TRANS("Auto Bend")));
addAndMakeVisible (label.get());
label->setFont (Font (17.00f, Font::plain).withTypefaceStyle ("Regular"));
label->setJustificationType (Justification::centredLeft);
label->setEditable (false, false, false);
label->setColour (TextEditor::textColourId, Colours::black);
label->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
label->setBounds (0, 4, 150, 22);
iniPitchSlider.reset (new SliderComponent (p, "sweepInitialPitch", "Ini.Pitch"));
addAndMakeVisible (iniPitchSlider.get());
iniPitchSlider->setName ("inital pitch slider");
timeSlider.reset (new SliderComponent (p, "sweepTime", "Time"));
addAndMakeVisible (timeSlider.get());
timeSlider->setName ("time slider");
//[UserPreSize]
//[/UserPreSize]
setSize (340, 86);
//[Constructor] You can add your own custom stuff here..
//[/Constructor]
}
SweepParamsComponent::~SweepParamsComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
//[/Destructor_pre]
label = nullptr;
iniPitchSlider = nullptr;
timeSlider = nullptr;
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]
}
//==============================================================================
void SweepParamsComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void SweepParamsComponent::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
iniPitchSlider->setBounds (0, 26, proportionOfWidth (1.0000f), 28);
timeSlider->setBounds (0, 54, proportionOfWidth (1.0000f), 28);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Projucer information section --
This is where the Projucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="SweepParamsComponent" componentName=""
parentClasses="public Component" constructorParams="Magical8bitPlug2AudioProcessor&amp; p"
variableInitialisers="" snapPixels="8" snapActive="1" snapShown="1"
overlayOpacity="0.330" fixedSize="1" initialWidth="340" initialHeight="86">
<BACKGROUND backgroundColour="ffffff"/>
<LABEL name="label" id="bae3132bcad681ce" memberName="label" virtualName=""
explicitFocusOrder="0" pos="0 4 150 22" edTextCol="ff000000"
edBkgCol="0" labelText="Auto Bend" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="17.0"
kerning="0.0" bold="0" italic="0" justification="33"/>
<GENERICCOMPONENT name="inital pitch slider" id="93ec1e79c45ddad4" memberName="iniPitchSlider"
virtualName="" explicitFocusOrder="0" pos="0 26 100% 28" class="SliderComponent"
params="p, &quot;sweepInitialPitch&quot;, &quot;Ini.Pitch&quot;"/>
<GENERICCOMPONENT name="time slider" id="1be45518932375fc" memberName="timeSlider"
virtualName="" explicitFocusOrder="0" pos="0 54 100% 28" class="SliderComponent"
params="p, &quot;sweepTime&quot;, &quot;Time&quot;"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -0,0 +1,69 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
#pragma once
//[Headers] -- You can add your own extra header files here --
#include "../JuceLibraryCode/JuceHeader.h"
#include "SliderComponent.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Projucer.
Describe your class and how it works here!
//[/Comments]
*/
class SweepParamsComponent : public Component
{
public:
//==============================================================================
SweepParamsComponent (Magical8bitPlug2AudioProcessor& p);
~SweepParamsComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
//[/UserMethods]
void paint (Graphics& g) override;
void resized() override;
private:
//[UserVariables] -- You can add your own custom variables in this section.
//[/UserVariables]
//==============================================================================
std::unique_ptr<Label> label;
std::unique_ptr<SliderComponent> iniPitchSlider;
std::unique_ptr<SliderComponent> timeSlider;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SweepParamsComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

136
Source/TonalVoice.cpp Normal file
View File

@ -0,0 +1,136 @@
/*
==============================================================================
TonalVoice.cpp
Created: 11 Nov 2019 9:36:34pm
Author: 除村 武志
==============================================================================
*/
#include "TonalVoice.h"
//---------------------------------------------
//
// Tonal Voice
// The base for pulse/triangle (Abstract)
//
//---------------------------------------------
TonalVoice::TonalVoice (SettingRefs* sRefs) : BaseVoice (sRefs) {}
void TonalVoice::startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int currentPitchBendPosition)
{
BaseVoice::startNote (midiNoteNumber, velocity, 0, currentPitchBendPosition);
currentBendAmount = 0;
currentPitchSequenceFrame = 0;
vibratoCount = 0;
float iniPitch = * (settingRefs->sweepInitialPitch);
float time = * (settingRefs->sweepTime);
currentAutoBendAmount = iniPitch;
autoBendDelta = -1.0 * iniPitch / (time * getSampleRate());
}
void TonalVoice::advanceControlFrame()
{
BaseVoice::advanceControlFrame();
currentPitchSequenceFrame = settingRefs->pitchSequence.nextIndexOf (currentPitchSequenceFrame);
}
void TonalVoice::calculateAngleDelta()
{
int noteNumberMod = 0;
double finePitchInSeq = 0;
if (settingRefs->isPitchSequenceEnabled())
{
switch (settingRefs->pitchSequenceMode())
{
case kPitchSequenceModeFine:
finePitchInSeq = (double)settingRefs->pitchSequence.valueAt (currentPitchSequenceFrame) / 8.0;
break;
case kPitchSequenceModeCoarse:
noteNumberMod = settingRefs->pitchSequence.valueAt (currentPitchSequenceFrame);
break;
default:
break;
}
}
double byWheel = settingRefs->vibratoIgnoresWheel() ? 1.0 : currentModWheelValue;
double vibratoAmount = * (settingRefs->vibratoDepth) * sin (getVibratoPhase()) * byWheel;
double noteNoInDouble = noteNumber
+ noteNumberMod
+ currentBendAmount
+ currentAutoBendAmount
+ vibratoAmount
+ finePitchInSeq;
auto cyclesPerSecond = noteNoToHeltzDouble (noteNoInDouble);
auto cyclesPerSample = cyclesPerSecond / getSampleRate();
angleDelta = cyclesPerSample * 2.0 * MathConstants<double>::pi;
}
void TonalVoice::pitchWheelMoved (int amount)
{
currentBendAmount = * (settingRefs->bendRange) * ((double) (amount - 8192)) / 8192.0;
}
void TonalVoice::controllerMoved (int type, int amount)
{
if (type == 1) // Modulation
{
currentModWheelValue = (double)amount / 127.0;
}
}
double TonalVoice::noteNoToHeltzDouble (double noteNoInDouble, const double frequencyOfA)
{
return frequencyOfA * std::pow (2.0, (noteNoInDouble - 69) / 12.0);
}
double TonalVoice::getVibratoPhase()
{
double sec = (double)vibratoCount / getSampleRate();
float delay = * (settingRefs->vibratoDelay);
float rate = * (settingRefs->vibratoRate);
if ( sec < delay ) { return 0.0; }
double phase = fmodf (( sec - delay ), rate) / rate * MathConstants<double>::twoPi;
return phase;
}
void TonalVoice::onFrameAdvanced()
{
vibratoCount++;
currentAutoBendAmount = currentAutoBendAmount + autoBendDelta;
if (autoBendDelta > 0)
{
// positive slope
if (currentAutoBendAmount > 0)
{
currentAutoBendAmount = 0;
autoBendDelta = 0;
}
}
else
{
// negative slope
if (currentAutoBendAmount < 0)
{
currentAutoBendAmount = 0;
autoBendDelta = 0;
}
}
};

49
Source/TonalVoice.h Normal file
View File

@ -0,0 +1,49 @@
/*
==============================================================================
TonalVoice.h
Created: 11 Nov 2019 9:36:34pm
Author: 除村 武志
==============================================================================
*/
#pragma once
#include "BaseVoice.h"
struct TonalVoice : public BaseVoice // The base for Pulse and Triangle
{
TonalVoice (SettingRefs* sRefs);
float voltageForAngle (double angle) override = 0;
// Vibrato
double vibratoPhase = 0;
double vibratoPhaseDelta = 0;
// BendState
double currentBendAmount = 0;
// Auto Bend
double currentAutoBendAmount = 0;
double autoBendDelta = 0;
// Vibrato
int vibratoCount;
double currentModWheelValue;
double getVibratoPhase();
// Custom Pitch/Note states
int currentPitchSequenceFrame = 0;
void startNote (int midiNoteNumber, float velocity,
SynthesiserSound*, int currentPitchWheelPosition) override;
void advanceControlFrame() override;
void calculateAngleDelta() override;
void pitchWheelMoved (int) override;
void controllerMoved (int, int) override;
double noteNoToHeltzDouble (double noteNoInDouble, const double frequencyOfA = 440);
void onFrameAdvanced() override;
};

34
Source/TriangleVoice.cpp Normal file
View File

@ -0,0 +1,34 @@
/*
==============================================================================
TriangleVoice.cpp
Created: 11 Nov 2019 9:37:04pm
Author: 除村 武志
==============================================================================
*/
#include "TriangleVoice.h"
//---------------------------------------------
//
// Triangle Voice
//
//---------------------------------------------
TriangleVoice::TriangleVoice (SettingRefs* sRefs) : TonalVoice (sRefs) {}
float TriangleVoice::voltageForAngle (double angle)
{
int sequence[32] = { 1, 2, 3, 4, 5, 6, 7, 8,
8, 7, 6, 5, 4, 3, 2, 1,
0, -1, -2, -3, -4, -5, -6, -7,
-7, -6, -5, -4, -3, -2, -1, 0
};
double twopi = MathConstants<float>::pi * 2.0;
int step = (int) (32 * angle / twopi);
int level = sequence[step];
float output = ((float)level - 0.5f) / 7.5f;
return output;
}

18
Source/TriangleVoice.h Normal file
View File

@ -0,0 +1,18 @@
/*
==============================================================================
TriangleVoice.h
Created: 11 Nov 2019 9:37:04pm
Author: 除村 武志
==============================================================================
*/
#pragma once
#include "TonalVoice.h"
struct TriangleVoice : public TonalVoice
{
TriangleVoice (SettingRefs* sRefs);
float voltageForAngle (double angle) override;
};

View File

@ -0,0 +1,158 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "VibratoParamsComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]
//==============================================================================
VibratoParamsComponent::VibratoParamsComponent (Magical8bitPlug2AudioProcessor& p)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
label.reset (new Label ("label",
TRANS("Vibrato")));
addAndMakeVisible (label.get());
label->setFont (Font (17.00f, Font::plain).withTypefaceStyle ("Regular"));
label->setJustificationType (Justification::centredLeft);
label->setEditable (false, false, false);
label->setColour (TextEditor::textColourId, Colours::black);
label->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
label->setBounds (0, 4, 150, 22);
ratioSlider.reset (new SliderComponent (p, "vibratoRate", "Rate"));
addAndMakeVisible (ratioSlider.get());
ratioSlider->setName ("ratio slider");
depthSlider.reset (new SliderComponent (p, "vibratoDepth", "Depth"));
addAndMakeVisible (depthSlider.get());
depthSlider->setName ("depth slider");
delaySlider.reset (new SliderComponent (p, "vibratoDelay", "Delay"));
addAndMakeVisible (delaySlider.get());
delaySlider->setName ("delay slider");
ignoreWheelSwitch.reset (new CheckBoxComponent (p, "vibratoIgnoresWheel_raw", "Ignores Wheel"));
addAndMakeVisible (ignoreWheelSwitch.get());
ignoreWheelSwitch->setName ("ignore wheel switch");
//[UserPreSize]
//[/UserPreSize]
setSize (340, 142);
//[Constructor] You can add your own custom stuff here..
//[/Constructor]
}
VibratoParamsComponent::~VibratoParamsComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
//[/Destructor_pre]
label = nullptr;
ratioSlider = nullptr;
depthSlider = nullptr;
delaySlider = nullptr;
ignoreWheelSwitch = nullptr;
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]
}
//==============================================================================
void VibratoParamsComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void VibratoParamsComponent::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
ratioSlider->setBounds (0, 26, proportionOfWidth (1.0000f), 28);
depthSlider->setBounds (0, 54, proportionOfWidth (1.0000f), 28);
delaySlider->setBounds (0, 82, proportionOfWidth (1.0000f), 28);
ignoreWheelSwitch->setBounds (0, 110, proportionOfWidth (1.0000f), 28);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Projucer information section --
This is where the Projucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="VibratoParamsComponent" componentName=""
parentClasses="public Component" constructorParams="Magical8bitPlug2AudioProcessor&amp; p"
variableInitialisers="" snapPixels="8" snapActive="1" snapShown="1"
overlayOpacity="0.330" fixedSize="1" initialWidth="340" initialHeight="142">
<BACKGROUND backgroundColour="ffffff"/>
<LABEL name="label" id="bae3132bcad681ce" memberName="label" virtualName=""
explicitFocusOrder="0" pos="0 4 150 22" edTextCol="ff000000"
edBkgCol="0" labelText="Vibrato" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="17.0"
kerning="0.0" bold="0" italic="0" justification="33"/>
<GENERICCOMPONENT name="ratio slider" id="93ec1e79c45ddad4" memberName="ratioSlider"
virtualName="" explicitFocusOrder="0" pos="0 26 100% 28" class="SliderComponent"
params="p, &quot;vibratoRate&quot;, &quot;Rate&quot;"/>
<GENERICCOMPONENT name="depth slider" id="1be45518932375fc" memberName="depthSlider"
virtualName="" explicitFocusOrder="0" pos="0 54 100% 28" class="SliderComponent"
params="p, &quot;vibratoDepth&quot;, &quot;Depth&quot;"/>
<GENERICCOMPONENT name="delay slider" id="5c2169fddb4cc33" memberName="delaySlider"
virtualName="" explicitFocusOrder="0" pos="0 82 100% 28" class="SliderComponent"
params="p, &quot;vibratoDelay&quot;, &quot;Delay&quot;"/>
<GENERICCOMPONENT name="ignore wheel switch" id="9d35239102eeb521" memberName="ignoreWheelSwitch"
virtualName="" explicitFocusOrder="0" pos="0 110 100% 28" class="CheckBoxComponent"
params="p, &quot;vibratoIgnoresWheel_raw&quot;, &quot;Ignores Wheel&quot;"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -0,0 +1,72 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 5.4.5
------------------------------------------------------------------------------
The Projucer is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
==============================================================================
*/
#pragma once
//[Headers] -- You can add your own extra header files here --
#include "../JuceLibraryCode/JuceHeader.h"
#include "SliderComponent.h"
#include "CheckBoxComponent.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Projucer.
Describe your class and how it works here!
//[/Comments]
*/
class VibratoParamsComponent : public Component
{
public:
//==============================================================================
VibratoParamsComponent (Magical8bitPlug2AudioProcessor& p);
~VibratoParamsComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
//[/UserMethods]
void paint (Graphics& g) override;
void resized() override;
private:
//[UserVariables] -- You can add your own custom variables in this section.
//[/UserVariables]
//==============================================================================
std::unique_ptr<Label> label;
std::unique_ptr<SliderComponent> ratioSlider;
std::unique_ptr<SliderComponent> depthSlider;
std::unique_ptr<SliderComponent> delaySlider;
std::unique_ptr<CheckBoxComponent> ignoreWheelSwitch;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VibratoParamsComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

11
Source/Voices.cpp Normal file
View File

@ -0,0 +1,11 @@
/*
==============================================================================
Voices.cpp
Created: 22 May 2019 7:05:29pm
Author: 除村 武志
==============================================================================
*/
#include "Voices.h"

21
Source/Voices.h Normal file
View File

@ -0,0 +1,21 @@
/*
==============================================================================
Voices.h
Created: 22 May 2019 7:05:29pm
Author: 除村 武志
==============================================================================
*/
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
#include "Settings.h"
enum EnvelopePhase
{
kEnvelopePhaseA,
kEnvelopePhaseD,
kEnvelopePhaseS,
kEnvelopePhaseR
};