diff --git a/Magical8bitPlug2.jucer b/Magical8bitPlug2.jucer
index a8b4e52..7703122 100644
--- a/Magical8bitPlug2.jucer
+++ b/Magical8bitPlug2.jucer
@@ -33,6 +33,10 @@
file="Source/SliderComponent.cpp"/>
+
+
@@ -68,6 +72,13 @@
file="Source/VibratoParamsComponent.h"/>
+
+
+
+
noiseAlgorithm()) {
case kNoiseInfinite2:
cycleLength = MathConstants::pi / 25.0;
@@ -29,10 +31,19 @@ void NoiseVoice::startNote(int midiNoteNumber, float velocity, SynthesiserSound
cycleLength = MathConstants::pi / 8.0;
break;
+ case kNoiseLongNes:
+ case kNoiseShortNes:
+ cycleLength = MathConstants::pi / 20.175;
+ //rgstr = 0x8000;
+ //rgstr = rand();
+ midiNote = midiNoteRange[(midiNote + 8) % 16];
+ break;
+
default:
cycleLength = MathConstants::pi / 8.0;
break;
}
+ TonalVoice::startNote(midiNote, velocity, 0, currentPitchBendPosition);
}
float NoiseVoice::voltageForAngle (double angle)
@@ -58,9 +69,10 @@ float NoiseVoice::voltageForAngle (double angle)
{
if (settingRefs->noiseAlgorithm() == kNoiseInfinite2)
{
- currentVoltage = float (rand() % 16 - 8) / 16.;
+ currentVoltage = float (rand() % 16 - 8) / 16.0;
+ //currentVoltage = float(rand() % 16 - 7.5) / 15.0;
}
- else
+ else if (settingRefs->noiseAlgorithm() == kNoiseLong || settingRefs->noiseAlgorithm() == kNoiseShort)
{
int compareBitPos = settingRefs->noiseAlgorithm() == kNoiseLong ? 1 : 6;
@@ -76,6 +88,14 @@ float NoiseVoice::voltageForAngle (double angle)
currentVoltage = (float)bit0 - 0.5;
}
+ else
+ {
+ int shortFreq = settingRefs->noiseAlgorithm() == kNoiseLongNes ? 1 : 6;
+
+ rgstr >>= 1;
+ rgstr |= ((rgstr ^ (rgstr >> shortFreq)) & 1) << 15;
+ currentVoltage = (float)(rgstr & 1) - 0.5;
+ }
nextAngle = (double) ((int) (angle / cycleLength) + 1) * cycleLength;
diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp
index d165238..bec901f 100644
--- a/Source/PluginEditor.cpp
+++ b/Source/PluginEditor.cpp
@@ -18,6 +18,7 @@
#include "BendParamsComponent.h"
#include "SweepParamsComponent.h"
#include "VibratoParamsComponent.h"
+#include "WaveformParamsComponent.h"
//==============================================================================
Magical8bitPlug2AudioProcessorEditor::Magical8bitPlug2AudioProcessorEditor (Magical8bitPlug2AudioProcessor& p)
@@ -29,7 +30,7 @@ Magical8bitPlug2AudioProcessorEditor::Magical8bitPlug2AudioProcessorEditor (Magi
basicCompo.reset (new BasicParamsComponent (p, *this));
addAndMakeVisible (basicCompo.get());
-
+
envCompo.reset (new EnvelopeParamsComponent (p));
addAndMakeVisible (envCompo.get());
@@ -51,6 +52,10 @@ Magical8bitPlug2AudioProcessorEditor::Magical8bitPlug2AudioProcessorEditor (Magi
vibCompo.reset (new VibratoParamsComponent (p));
addAndMakeVisible (vibCompo.get());
+ // waveform
+ waveformCompo.reset (new WaveformParamsComponent (p));
+ addAndMakeVisible (waveformCompo.get());
+
(p.parameters.getParameter ("isVolumeSequenceEnabled_raw"))->addListener (this);
(p.parameters.getParameter ("isDutySequenceEnabled_raw"))->addListener (this);
@@ -141,7 +146,7 @@ struct
+ genericControlHeight;
const int sweepCompoHeight = componentMargin * 2
+ indexHeight
- + genericControlHeight * 2;
+ + genericControlHeight * 3;
const int vibCompoHeight = componentMargin * 2
+ indexHeight
+ genericControlHeight * 4;
@@ -240,6 +245,11 @@ void Magical8bitPlug2AudioProcessorEditor::resized()
y3 += sizes.sectionSeparatorHeight;
advCompo->setBounds (x, y3, sizes.fullComponentWidth, sizes.advCompoHeight);
+ // Waveform
+ int wrX = sizes.leftMargin + sizes.totalWidth;
+ int wrY = sizes.topMargin;
+ waveformCompo->setBounds(wrX, wrY, waveformCompo->getWidth(), waveformCompo->getHeight());
+
//
// Visibility
//
@@ -272,7 +282,12 @@ void Magical8bitPlug2AudioProcessorEditor::resized()
void Magical8bitPlug2AudioProcessorEditor::resizeWholePanel()
{
- setSize (sizes.totalWidth, sizes.totalHeight (processor.settingRefs.isAdvancedPanelOpen()));
+ int totalWidth = sizes.totalWidth;
+ if (processor.settingRefs.oscillatorType() == kVoiceTypeWaveform)
+ {
+ totalWidth += sizes.leftMargin * 2 + waveformCompo->getWidth();
+ }
+ setSize (totalWidth, sizes.totalHeight (processor.settingRefs.isAdvancedPanelOpen()));
}
void Magical8bitPlug2AudioProcessorEditor::parameterValueChanged (int parameterIndex, float newValue)
@@ -291,3 +306,13 @@ void Magical8bitPlug2AudioProcessorEditor::parameterValueChanged (int parameterI
}
}
+// waveform
+//void Magical8bitPlug2AudioProcessorEditor::waveformInit()
+//{
+// waveformCompo->sliderInit();
+//}
+
+void Magical8bitPlug2AudioProcessorEditor::waveformUpdate()
+{
+ waveformCompo->sliderRepaint();
+}
diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h
index 385b278..1ce2fde 100644
--- a/Source/PluginEditor.h
+++ b/Source/PluginEditor.h
@@ -20,6 +20,7 @@ class NoiseParamsComponent;
class BendParamsComponent;
class SweepParamsComponent;
class VibratoParamsComponent;
+class WaveformParamsComponent;
//==============================================================================
/**
@@ -40,6 +41,10 @@ class Magical8bitPlug2AudioProcessorEditor : public AudioProcessorEditor
void parameterValueChanged (int parameterIndex, float newValue) override;
void parameterGestureChanged (int parameterIndex, bool gestureIsStarting) override {};
+ // waveform
+ //void waveformInit();
+ void waveformUpdate();
+
private:
Magical8bitPlug2AudioProcessor& processor;
@@ -51,6 +56,7 @@ class Magical8bitPlug2AudioProcessorEditor : public AudioProcessorEditor
std::unique_ptr bendCompo;
std::unique_ptr sweepCompo;
std::unique_ptr vibCompo;
+ std::unique_ptr waveformCompo;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Magical8bitPlug2AudioProcessorEditor)
};
diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp
index 27b41f7..11c7499 100644
--- a/Source/PluginProcessor.cpp
+++ b/Source/PluginProcessor.cpp
@@ -13,6 +13,7 @@
#include "PulseVoice.h"
#include "TriangleVoice.h"
#include "NoiseVoice.h"
+#include "WaveformVoice.h"
#include "FrameSequenceParseErrors.h"
#include "EnvelopeParserTest.h"
@@ -21,21 +22,21 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
: parameters (
*this, nullptr, Identifier ("Params"),
{
- //
- // Meta
- //
- std::make_unique ("isAdvancedPanelOpen_raw", "Advanced", false),
+ //
+ // Meta
+ //
+ std::make_unique ("isAdvancedPanelOpen_raw", "Advanced", false),
std::make_unique ("colorScheme", "Color Scheme", StringArray ({"YMCK", "YMCK Dark", "Japan", "Worldwide", "Monotone", "Mono Dark"}), 0),
//
// Basic
//
- std::make_unique ("osc", "OSC Type", StringArray ({"Pulse/Square", "Triangle", "Noise"}), 0),
+ std::make_unique ("osc", "OSC Type", StringArray ({"Pulse/Square", "Triangle", "Noise", "Waveform"}), 0),
std::make_unique ("gain", "Gain", 0.0f, 1.0f, 0.5f),
std::make_unique ("maxPoly", "Max Poly", NormalisableRange (1.0f, //min
- 64.0f, //max
- 1.0f, //step
- 1.0f), //skew
- 8),
+ 64.0f, //max
+ 1.0f, //step
+ 1.0f), //skew
+ 8),
//
// ADSR
//
@@ -45,14 +46,14 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
5.0f, //max
0.001f, //step
0.5f), //skew
- 0.0f), //default
+ 0.0f), //default
std::make_unique ("decay", //ID
"Decay", //name
NormalisableRange (0.0f, //min
5.0f, //max
0.001f, //step
0.5f), //skew
- 0.0f), //default
+ 0.0f), //default
std::make_unique ("suslevel", //ID
"Sustain", //name
0.0f, //min
@@ -64,7 +65,7 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
5.0f, //max
0.001f, //step
0.5f), //skew
- 0.0f), //default
+ 0.0f), //default
//
// Arpeggio
//
@@ -84,7 +85,7 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
1.0f, //max
0.001f, //step
0.5f), //skew
- 0.15f), //default
+ 0.15f), //default
std::make_unique ("vibratoDepth", "Depth", 0.0f, 2.0f, 0.0f),
std::make_unique ("vibratoDelay", "Delay", 0.0f, 1.0f, 0.3f),
std::make_unique ("vibratoIgnoresWheel_raw", "Ignores Wheel", true),
@@ -92,13 +93,14 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
// Sweep
//
std::make_unique ("sweepInitialPitch", "Ini.Pitch", -24, 24, 0),
+ std::make_unique ("sweepEndPitch", "End.Pitch", -24, 24, 0),
std::make_unique ("sweepTime", //ID
"Time", //name
NormalisableRange (0.01f, //min
5.0f, //max
0.001f, //step
0.5f), //skew
- 0.1f), //default
+ 0.1f), //default
//
// For Pulse
//
@@ -106,7 +108,7 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
//
// For Noise
//
- std::make_unique ("noiseAlgorithm_raw", "Algorithm", StringArray ({"4bit Pure Random", "1bit Long Cycle", "1bit Short Cycle"}), 0),
+ std::make_unique ("noiseAlgorithm_raw", "Algorithm", StringArray ({"4bit Pure Random", "1bit Long Cycle", "1bit Short Cycle", "Nes Long Cycle", "Nes Short Cycle"}), 0),
std::make_unique ("restrictsToNESFrequency_raw", "Restricts to NES frequency", false),
//
// Sequence
@@ -114,8 +116,77 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
std::make_unique ("isVolumeSequenceEnabled_raw", "Enabled", false),
std::make_unique ("isPitchSequenceEnabled_raw", "Enabled", false),
std::make_unique ("isDutySequenceEnabled_raw", "Enabled", false),
- std::make_unique ("pitchSequenceMode_raw", "Mode", StringArray ({"Coarse", "Fine"}), 0)
- }
+ std::make_unique ("pitchSequenceMode_raw", "Mode", StringArray ({"Coarse", "Fine8", "Fine16"}), 0),
+ // waveform
+ std::make_unique("waveformX", "X", StringArray({ "16", "32", "64" }), 2),
+ std::make_unique("waveformY", "Y", StringArray({ "16", "32", "64" }), 2),
+ std::make_unique("waveformTemplate", "Template", StringArray({ "Custom", "Sine", "Triangle", "Sawtooth", "Square 6.25%", "Square 18.75%", "Square 31.25%", "Square 37.5%", "Square 43.75%" }), 0),
+ std::make_unique("waveformWave0", "wave", 0, 63, 0),
+ std::make_unique("waveformWave1", "wave", 0, 63, 0),
+ std::make_unique("waveformWave2", "wave", 0, 63, 0),
+ std::make_unique("waveformWave3", "wave", 0, 63, 0),
+ std::make_unique("waveformWave4", "wave", 0, 63, 0),
+ std::make_unique("waveformWave5", "wave", 0, 63, 0),
+ std::make_unique("waveformWave6", "wave", 0, 63, 0),
+ std::make_unique("waveformWave7", "wave", 0, 63, 0),
+ std::make_unique("waveformWave8", "wave", 0, 63, 0),
+ std::make_unique("waveformWave9", "wave", 0, 63, 0),
+ std::make_unique("waveformWave10", "wave", 0, 63, 0),
+ std::make_unique("waveformWave11", "wave", 0, 63, 0),
+ std::make_unique("waveformWave12", "wave", 0, 63, 0),
+ std::make_unique("waveformWave13", "wave", 0, 63, 0),
+ std::make_unique("waveformWave14", "wave", 0, 63, 0),
+ std::make_unique("waveformWave15", "wave", 0, 63, 0),
+ std::make_unique("waveformWave16", "wave", 0, 63, 0),
+ std::make_unique("waveformWave17", "wave", 0, 63, 0),
+ std::make_unique("waveformWave18", "wave", 0, 63, 0),
+ std::make_unique("waveformWave19", "wave", 0, 63, 0),
+ std::make_unique("waveformWave20", "wave", 0, 63, 0),
+ std::make_unique("waveformWave21", "wave", 0, 63, 0),
+ std::make_unique("waveformWave22", "wave", 0, 63, 0),
+ std::make_unique("waveformWave23", "wave", 0, 63, 0),
+ std::make_unique("waveformWave24", "wave", 0, 63, 0),
+ std::make_unique("waveformWave25", "wave", 0, 63, 0),
+ std::make_unique("waveformWave26", "wave", 0, 63, 0),
+ std::make_unique("waveformWave27", "wave", 0, 63, 0),
+ std::make_unique("waveformWave28", "wave", 0, 63, 0),
+ std::make_unique("waveformWave29", "wave", 0, 63, 0),
+ std::make_unique("waveformWave30", "wave", 0, 63, 0),
+ std::make_unique("waveformWave31", "wave", 0, 63, 0),
+ std::make_unique("waveformWave32", "wave", 0, 63, 0),
+ std::make_unique("waveformWave33", "wave", 0, 63, 0),
+ std::make_unique("waveformWave34", "wave", 0, 63, 0),
+ std::make_unique("waveformWave35", "wave", 0, 63, 0),
+ std::make_unique("waveformWave36", "wave", 0, 63, 0),
+ std::make_unique("waveformWave37", "wave", 0, 63, 0),
+ std::make_unique("waveformWave38", "wave", 0, 63, 0),
+ std::make_unique("waveformWave39", "wave", 0, 63, 0),
+ std::make_unique("waveformWave40", "wave", 0, 63, 0),
+ std::make_unique("waveformWave41", "wave", 0, 63, 0),
+ std::make_unique("waveformWave42", "wave", 0, 63, 0),
+ std::make_unique("waveformWave43", "wave", 0, 63, 0),
+ std::make_unique("waveformWave44", "wave", 0, 63, 0),
+ std::make_unique("waveformWave45", "wave", 0, 63, 0),
+ std::make_unique("waveformWave46", "wave", 0, 63, 0),
+ std::make_unique("waveformWave47", "wave", 0, 63, 0),
+ std::make_unique("waveformWave48", "wave", 0, 63, 0),
+ std::make_unique("waveformWave49", "wave", 0, 63, 0),
+ std::make_unique("waveformWave50", "wave", 0, 63, 0),
+ std::make_unique("waveformWave51", "wave", 0, 63, 0),
+ std::make_unique("waveformWave52", "wave", 0, 63, 0),
+ std::make_unique("waveformWave53", "wave", 0, 63, 0),
+ std::make_unique("waveformWave54", "wave", 0, 63, 0),
+ std::make_unique("waveformWave55", "wave", 0, 63, 0),
+ std::make_unique("waveformWave56", "wave", 0, 63, 0),
+ std::make_unique("waveformWave57", "wave", 0, 63, 0),
+ std::make_unique("waveformWave58", "wave", 0, 63, 0),
+ std::make_unique("waveformWave59", "wave", 0, 63, 0),
+ std::make_unique("waveformWave60", "wave", 0, 63, 0),
+ std::make_unique("waveformWave61", "wave", 0, 63, 0),
+ std::make_unique("waveformWave62", "wave", 0, 63, 0),
+ std::make_unique("waveformWave63", "wave", 0, 63, 0)
+
+}
)
, settingRefs (¶meters)
#ifndef JucePlugin_PreferredChannelConfigurations
@@ -129,6 +200,16 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
)
#endif
{
+ // waveform
+ //parameters.createAndAddParameter(std::make_unique("waveformX", "X", StringArray({ "16", "32", "64" }), 2));
+ //parameters.createAndAddParameter(std::make_unique("waveformY", "Y", StringArray({ "16", "32", "64" }), 2));
+ //parameters.createAndAddParameter(std::make_unique("waveformTemplate", "Template", StringArray({ "Custom", "Sine", "Triangle", "Sawtooth", "Square 6.25%", "Square 18.75%", "Square 31.25%", "Square 37.5%", "Square 43.75%" }), 0));
+ //for (int i = 0; i < 64; i++)
+ //{
+ // parameters.createAndAddParameter(std::make_unique("waveformWave" + String(i), "wave" + String(i), 0, 63, 0));
+ //}
+ //settingRefs.setWaveform(¶meters);
+
synth.setCurrentPlaybackSampleRate (44100); // Temporary setup, just in case. The actual sample rate is set in prepareToPlay func.
setupVoice();
@@ -171,6 +252,10 @@ void Magical8bitPlug2AudioProcessor::setupVoice()
case kVoiceTypeNoise:
synth.addVoice (new NoiseVoice (&settingRefs));
break;
+
+ case kVoiceTypeWaveform:
+ synth.addVoice(new WaveformVoice(&settingRefs));
+ break;
}
}
}
@@ -375,8 +460,13 @@ void Magical8bitPlug2AudioProcessor::getStateInformation (MemoryBlock& destData)
copyXmlToBinary (*xml, destData);
}
-void Magical8bitPlug2AudioProcessor::setStateInformation (const void* data, int sizeInBytes)
+void Magical8bitPlug2AudioProcessor::setStateInformation(const void* data, int sizeInBytes)
{
+ //if (Magical8bitPlug2AudioProcessorEditor* activeEditor = (Magical8bitPlug2AudioProcessorEditor*)getActiveEditor())
+ //{
+ // activeEditor->waveformInit();
+ //}
+
std::unique_ptr xmlState (getXmlFromBinary (data, sizeInBytes));
if (xmlState.get() != nullptr)
@@ -473,6 +563,13 @@ void Magical8bitPlug2AudioProcessor::setStateInformation (const void* data, int
}
setupVoice();
+
+ if (Magical8bitPlug2AudioProcessorEditor* activeEditor = (Magical8bitPlug2AudioProcessorEditor*)getActiveEditor())
+ {
+ activeEditor->resized();
+ activeEditor->resizeWholePanel();
+ activeEditor->waveformUpdate();
+ }
}
//==============================================================================
diff --git a/Source/PulseVoice.cpp b/Source/PulseVoice.cpp
index 90efb9b..10d86bf 100644
--- a/Source/PulseVoice.cpp
+++ b/Source/PulseVoice.cpp
@@ -56,7 +56,37 @@ void PulseVoice::advanceControlFrame()
if (settingRefs->isDutySequenceEnabled())
{
- currentDutySequenceFrame = settingRefs->dutySequence.nextIndexOf (currentDutySequenceFrame);
- currentDuty = (PulseDuty)settingRefs->dutySequence.valueAt (currentDutySequenceFrame);
+ //currentDutySequenceFrame = settingRefs->dutySequence.nextIndexOf(currentDutySequenceFrame);
+ //currentDuty = (PulseDuty)settingRefs->dutySequence.valueAt(currentDutySequenceFrame);
+
+ int currentDutySequenceFrameTmp = settingRefs->dutySequence.nextIndexOf(currentDutySequenceFrame);
+ if (currentDutySequenceFrameTmp != FrameSequence::SHOULD_RETIRE)
+ {
+ currentDutySequenceFrame = currentDutySequenceFrameTmp;
+ currentDuty = (PulseDuty)settingRefs->dutySequence.valueAt(currentDutySequenceFrame);
+ }
+ }
+}
+
+void PulseVoice::stopNote(float velocity, bool allowTailOff)
+{
+ TonalVoice::stopNote(velocity, allowTailOff);
+
+ if (!allowTailOff)
+ {
+ return;
+ }
+
+ if (settingRefs->isDutySequenceEnabled())
+ {
+ if (settingRefs->dutySequence.hasRelease)
+ {
+ if (settingRefs->dutySequence.isInRelease(currentDutySequenceFrame)) {
+ // Already in release(Custom Env.)
+ return;
+ }
+ currentDutySequenceFrame = settingRefs->dutySequence.releaseSequenceStartIndex;
+ currentDuty = (PulseDuty)settingRefs->dutySequence.valueAt(currentDutySequenceFrame);
+ }
}
}
diff --git a/Source/PulseVoice.h b/Source/PulseVoice.h
index 97c5340..58ce417 100644
--- a/Source/PulseVoice.h
+++ b/Source/PulseVoice.h
@@ -25,4 +25,5 @@ struct PulseVoice : public TonalVoice
SynthesiserSound*, int currentPitchWheelPosition) override;
float voltageForAngle (double angle) override;
void advanceControlFrame() override;
+ void stopNote(float velocity, bool allowTailOff) override;
};
diff --git a/Source/Settings.cpp b/Source/Settings.cpp
index dd2ebd2..3ef46d3 100644
--- a/Source/Settings.cpp
+++ b/Source/Settings.cpp
@@ -77,3 +77,29 @@ String& SettingRefs::getSequenceString (const String& type)
printf ("*** parameter type invalid!\n");
return volumeSequenceString;
}
+
+//void SettingRefs::setWaveform(AudioProcessorValueTreeState* parameters)
+//{
+// // waveform
+// for (int i = 0; i < 64; i++)
+// {
+// waveformWave[i] = (float*)parameters->getRawParameterValue("waveformWave" + String(i));
+// }
+// waveformX = (float*)parameters->getRawParameterValue("waveformX");
+// waveformY = (float*)parameters->getRawParameterValue("waveformY");
+// waveformTemplate = (float*)parameters->getRawParameterValue("waveformTemplate");
+//}
+
+int SettingRefs::getWaveformX()
+{
+ int range[3] = {16, 32, 64};
+
+ return range[(int)(*waveformX)];
+}
+
+int SettingRefs::getWaveformY()
+{
+ int range[3] = { 16, 32, 64 };
+
+ return range[(int)(*waveformY)] - 1;
+}
diff --git a/Source/Settings.h b/Source/Settings.h
index 738aa72..f7a9d59 100644
--- a/Source/Settings.h
+++ b/Source/Settings.h
@@ -23,7 +23,8 @@ enum VoiceType
{
kVoiceTypePulse = 0,
kVoiceTypeTriangle,
- kVoiceTypeNoise
+ kVoiceTypeNoise,
+ kVoiceTypeWaveform
};
struct PluginSettings
@@ -52,12 +53,15 @@ enum NoiseAlgorithm
kNoiseInfinite2 = 0,
kNoiseLong,
kNoiseShort,
+ kNoiseLongNes,
+ kNoiseShortNes,
};
enum PitchSequenceMode
{
kPitchSequenceModeCoarse = 0,
- kPitchSequenceModeFine
+ kPitchSequenceModeFine,
+ kPitchSequenceModeFine16
};
class FrameSequenceChangeListener
@@ -108,6 +112,7 @@ struct SettingRefs
float* vibratoIgnoresWheel_raw = nullptr;
// Sweep
float* sweepInitialPitch = nullptr;
+ float* sweepEndPitch = nullptr;
float* sweepTime = nullptr;
// For Pulse
float* duty = nullptr;
@@ -123,9 +128,9 @@ struct SettingRefs
FrameSequence volumeSequence;
FrameSequence pitchSequence;
FrameSequence dutySequence;
- String volumeSequenceString = "";
- String pitchSequenceString = "";
- String dutySequenceString = "";
+ String volumeSequenceString; //= "15 x 5, 15 to 0 in 15 [5, 4, 3] | 2, 1, 0";
+ String pitchSequenceString; //= "15 x 5, 15 to 0 in 15 [5, 4, 3] | 2, 1, 0";
+ String dutySequenceString; //= "2 x 5, 2 to 0 in 15 [2, 1, 0] | 2, 1, 0";
bool setSequenceWithString (const String& type, const String& input, ParseError* error);
String& getSequenceString (const String& type);
@@ -152,6 +157,14 @@ struct SettingRefs
bool isDutySequenceEnabled() { return *isDutySequenceEnabled_raw > 0.5; }
PitchSequenceMode pitchSequenceMode() { return (PitchSequenceMode) ((int) (*pitchSequenceMode_raw)); }
+ // waveform
+ //void setWaveform(AudioProcessorValueTreeState* parameters);
+ int getWaveformX();
+ int getWaveformY();
+ float* waveformWave[64];
+ float* waveformX = nullptr;
+ float* waveformY = nullptr;
+ float* waveformTemplate = nullptr;
//
// constructor
@@ -183,6 +196,7 @@ struct SettingRefs
vibratoIgnoresWheel_raw = (float*) parameters->getRawParameterValue ("vibratoIgnoresWheel_raw");
// Sweep
sweepInitialPitch = (float*) parameters->getRawParameterValue ("sweepInitialPitch");
+ sweepEndPitch = (float*)parameters->getRawParameterValue("sweepEndPitch");
sweepTime = (float*) parameters->getRawParameterValue ("sweepTime");
// For Pulse
duty = (float*) parameters->getRawParameterValue ("duty");
@@ -194,6 +208,13 @@ struct SettingRefs
isPitchSequenceEnabled_raw = (float*) parameters->getRawParameterValue ("isPitchSequenceEnabled_raw");
isDutySequenceEnabled_raw = (float*) parameters->getRawParameterValue ("isDutySequenceEnabled_raw");
pitchSequenceMode_raw = (float*) parameters->getRawParameterValue ("pitchSequenceMode_raw");
-
+ // waveform
+ for (int i = 0; i < 64; i++)
+ {
+ waveformWave[i] = (float*)parameters->getRawParameterValue("waveformWave" + String(i));
+ }
+ waveformX = (float*)parameters->getRawParameterValue("waveformX");
+ waveformY = (float*)parameters->getRawParameterValue("waveformY");
+ waveformTemplate = (float*)parameters->getRawParameterValue("waveformTemplate");
}
};
diff --git a/Source/SliderVerticalComponent.cpp b/Source/SliderVerticalComponent.cpp
new file mode 100644
index 0000000..a7e7232
--- /dev/null
+++ b/Source/SliderVerticalComponent.cpp
@@ -0,0 +1,172 @@
+/*
+ ==============================================================================
+
+ 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: 6.0.8
+
+ ------------------------------------------------------------------------------
+
+ The Projucer is part of the JUCE library.
+ Copyright (c) 2020 - Raw Material Software Limited.
+
+ ==============================================================================
+*/
+
+//[Headers] You can add your own extra header files here...
+//[/Headers]
+
+#include "SliderVerticalComponent.h"
+
+
+//[MiscUserDefs] You can add your own user definitions and misc code here...
+//[/MiscUserDefs]
+
+//==============================================================================
+SliderVerticalComponent::SliderVerticalComponent (Magical8bitPlug2AudioProcessor& p, String paramId)
+ : processor(p)
+{
+ //[Constructor_pre] You can add your own custom stuff here..
+ setInterceptsMouseClicks(true, false);
+ for (int i = 0; i < 64; i++)
+ {
+ verticalSliders[i].reset(new juce::Slider("vertical slider"));
+ addAndMakeVisible(verticalSliders[i].get());
+ verticalSliders[i]->setRange(0, 63, 0);
+ verticalSliders[i]->setSliderStyle(juce::Slider::LinearBarVertical);
+ verticalSliders[i]->setTextBoxStyle(juce::Slider::NoTextBox, true, 30, 20);
+ verticalSliders[i]->setBounds(0 + i * 8, 0, 9, 250);
+ verticalSliders[i]->setInterceptsMouseClicks(false, false);
+ attc[i].reset(new SliderAttachment(p.parameters, paramId + String(i), *verticalSliders[i]));
+ }
+ //[/Constructor_pre]
+
+
+ //[UserPreSize]
+ //[/UserPreSize]
+
+ setSize (513, 250);
+
+
+ //[Constructor] You can add your own custom stuff here..
+ baseMaxValue = 63;
+ //[/Constructor]
+}
+
+SliderVerticalComponent::~SliderVerticalComponent()
+{
+ //[Destructor_pre]. You can add your own custom destruction code here..
+ for (int i = 0; i < 64; i++)
+ {
+ attc[i].reset();
+ verticalSliders[i] = nullptr;
+ }
+ //[/Destructor_pre]
+
+
+
+ //[Destructor]. You can add your own custom destruction code here..
+ //[/Destructor]
+}
+
+//==============================================================================
+void SliderVerticalComponent::paint (juce::Graphics& g)
+{
+ //[UserPrePaint] Add your own custom painting code here..
+ //[/UserPrePaint]
+
+ //[UserPaint] Add your own custom painting code here..
+ //[/UserPaint]
+}
+
+void SliderVerticalComponent::resized()
+{
+ //[UserPreResize] Add your own custom resize code here..
+ //[/UserPreResize]
+
+ //[UserResized] Add your own custom resize handling here..
+ //[/UserResized]
+}
+
+void SliderVerticalComponent::mouseDown (const juce::MouseEvent& e)
+{
+ //[UserCode_mouseDown] -- Add your code here...
+ mouseDrag(e);
+ //[/UserCode_mouseDown]
+}
+
+void SliderVerticalComponent::mouseDrag (const juce::MouseEvent& e)
+{
+ //[UserCode_mouseDrag] -- Add your code here...
+ int rate = (baseMaxValue + 1) / (maxValue + 1);
+ int sliderIndex = jlimit(0, numWidth - 1, (int)floor(e.position.x / (getWidth() / ((double)numWidth))));
+ waveValue = jlimit(0, baseMaxValue, (int)(baseMaxValue * ((double)getHeight() - (double)e.position.y) / ((double)getHeight()) + 0.5));
+ waveValue = (int)(waveValue / rate);
+ verticalSliders[sliderIndex]->setValue(((double)waveValue / maxValue * baseMaxValue));
+ getParentComponent()->mouseDrag(e.getEventRelativeTo(getParentComponent()));
+ //[/UserCode_mouseDrag]
+}
+
+
+
+//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
+void SliderVerticalComponent::setForm(int numWidth, int maxValue, int width, int height)
+{
+ this->numWidth = jlimit(0, 64, numWidth);
+ this->maxValue = maxValue;
+
+ int sliderWidth = width / this->numWidth;
+
+ setSize(sliderWidth * this->numWidth + 1, height);
+
+ int rate = (baseMaxValue + 1) / (maxValue + 1);
+
+ for (int i = 0; i < 64; i++)
+ {
+ verticalSliders[i]->setBounds(0 + i * sliderWidth, 0, sliderWidth + 1, height);
+ int value = verticalSliders[i]->getValue();
+ verticalSliders[i]->setValue(((double)(value / rate) / maxValue * baseMaxValue));
+ verticalSliders[i]->repaint();
+ }
+}
+
+void SliderVerticalComponent::setValue(int index, int value)
+{
+ verticalSliders[index]->setValue(((double)value / maxValue * baseMaxValue));
+}
+//[/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
+
+
+
+
+
+
+
+
+
+END_JUCER_METADATA
+*/
+#endif
+
+
+//[EndFile] You can add extra defines here...
+//[/EndFile]
+
diff --git a/Source/SliderVerticalComponent.h b/Source/SliderVerticalComponent.h
new file mode 100644
index 0000000..8356699
--- /dev/null
+++ b/Source/SliderVerticalComponent.h
@@ -0,0 +1,78 @@
+/*
+ ==============================================================================
+
+ 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: 6.0.8
+
+ ------------------------------------------------------------------------------
+
+ The Projucer is part of the JUCE library.
+ Copyright (c) 2020 - Raw Material Software Limited.
+
+ ==============================================================================
+*/
+
+#pragma once
+
+//[Headers] -- You can add your own extra header files here --
+#include
+#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 SliderVerticalComponent : public juce::Component
+{
+public:
+ //==============================================================================
+ SliderVerticalComponent (Magical8bitPlug2AudioProcessor& p, String paramId);
+ ~SliderVerticalComponent() override;
+
+ //==============================================================================
+ //[UserMethods] -- You can add your own custom methods in this section.
+ void setForm(int numWidth, int maxValue, int width, int height);
+ void setValue(int index, int value);
+ int waveValue = -1;
+ //[/UserMethods]
+
+ void paint (juce::Graphics& g) override;
+ void resized() override;
+ void mouseDown (const juce::MouseEvent& e) override;
+ void mouseDrag (const juce::MouseEvent& e) override;
+
+
+
+private:
+ //[UserVariables] -- You can add your own custom variables in this section.
+ std::unique_ptr verticalSliders[64];
+ int numWidth;
+ int maxValue;
+ int baseMaxValue;
+ Magical8bitPlug2AudioProcessor& processor;
+ std::unique_ptr attc[64];
+ //[/UserVariables]
+
+ //==============================================================================
+
+
+ //==============================================================================
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SliderVerticalComponent)
+};
+
+//[EndFile] You can add extra defines here...
+//[/EndFile]
+
diff --git a/Source/SweepParamsComponent.cpp b/Source/SweepParamsComponent.cpp
index 8003e04..a96cf8d 100644
--- a/Source/SweepParamsComponent.cpp
+++ b/Source/SweepParamsComponent.cpp
@@ -51,11 +51,15 @@ SweepParamsComponent::SweepParamsComponent (Magical8bitPlug2AudioProcessor& p)
addAndMakeVisible (timeSlider.get());
timeSlider->setName ("time slider");
+ endPitchSlider.reset (new SliderComponent (p, "sweepEndPitch", "End.Pitch"));
+ addAndMakeVisible (endPitchSlider.get());
+ endPitchSlider->setName ("end pitch slider");
+
//[UserPreSize]
//[/UserPreSize]
- setSize (340, 86);
+ setSize (340, 114);
//[Constructor] You can add your own custom stuff here..
@@ -70,6 +74,7 @@ SweepParamsComponent::~SweepParamsComponent()
label = nullptr;
iniPitchSlider = nullptr;
timeSlider = nullptr;
+ endPitchSlider = nullptr;
//[Destructor]. You can add your own custom destruction code here..
@@ -92,7 +97,8 @@ void SweepParamsComponent::resized()
//[/UserPreResize]
iniPitchSlider->setBounds (0, 26, proportionOfWidth (1.0000f), 28);
- timeSlider->setBounds (0, 54, proportionOfWidth (1.0000f), 28);
+ timeSlider->setBounds (0, 82, proportionOfWidth (1.0000f), 28);
+ endPitchSlider->setBounds (0, 54, proportionOfWidth (1.0000f), 28);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
@@ -115,7 +121,7 @@ BEGIN_JUCER_METADATA
+ overlayOpacity="0.330" fixedSize="1" initialWidth="340" initialHeight="114">
+
END_JUCER_METADATA
diff --git a/Source/SweepParamsComponent.h b/Source/SweepParamsComponent.h
index bd80ed8..e4e5add 100644
--- a/Source/SweepParamsComponent.h
+++ b/Source/SweepParamsComponent.h
@@ -58,6 +58,7 @@ class SweepParamsComponent : public Component
std::unique_ptr label;
std::unique_ptr iniPitchSlider;
std::unique_ptr timeSlider;
+ std::unique_ptr endPitchSlider;
//==============================================================================
diff --git a/Source/TonalVoice.cpp b/Source/TonalVoice.cpp
index f0471bc..ef7b365 100644
--- a/Source/TonalVoice.cpp
+++ b/Source/TonalVoice.cpp
@@ -27,16 +27,28 @@ void TonalVoice::startNote (int midiNoteNumber, float velocity, SynthesiserSound
vibratoCount = 0;
float iniPitch = * (settingRefs->sweepInitialPitch);
+ float endPitch = *(settingRefs->sweepEndPitch);
float time = * (settingRefs->sweepTime);
currentAutoBendAmount = iniPitch;
- autoBendDelta = -1.0 * iniPitch / (time * getSampleRate());
+ autoBendDelta = -1.0 * (iniPitch - endPitch) / (time * getSampleRate());
+
+ //if (*(settingRefs->osc) == kVoiceTypeTriangle)
+ //{
+ // nesPitchCorrection = -12;
+ //}
}
void TonalVoice::advanceControlFrame()
{
BaseVoice::advanceControlFrame();
- currentPitchSequenceFrame = settingRefs->pitchSequence.nextIndexOf (currentPitchSequenceFrame);
+ //currentPitchSequenceFrame = settingRefs->pitchSequence.nextIndexOf(currentPitchSequenceFrame);
+
+ int currentPitchSequenceFrameTmp = settingRefs->pitchSequence.nextIndexOf(currentPitchSequenceFrame);
+ if (currentPitchSequenceFrameTmp != FrameSequence::SHOULD_RETIRE)
+ {
+ currentPitchSequenceFrame = currentPitchSequenceFrameTmp;
+ }
}
void TonalVoice::calculateAngleDelta()
@@ -49,6 +61,10 @@ void TonalVoice::calculateAngleDelta()
{
switch (settingRefs->pitchSequenceMode())
{
+ case kPitchSequenceModeFine16:
+ finePitchInSeq = (double)settingRefs->pitchSequence.valueAt (currentPitchSequenceFrame) / 16.0;
+ break;
+
case kPitchSequenceModeFine:
finePitchInSeq = (double)settingRefs->pitchSequence.valueAt (currentPitchSequenceFrame) / 8.0;
break;
@@ -69,7 +85,8 @@ void TonalVoice::calculateAngleDelta()
+ currentBendAmount
+ currentAutoBendAmount
+ vibratoAmount
- + finePitchInSeq;
+ + finePitchInSeq
+ + nesPitchCorrection;
auto cyclesPerSecond = noteNoToHeltzDouble (noteNoInDouble);
auto cyclesPerSample = cyclesPerSecond / getSampleRate();
@@ -118,19 +135,41 @@ void TonalVoice::onFrameAdvanced()
if (autoBendDelta > 0)
{
// positive slope
- if (currentAutoBendAmount > 0)
+ if (currentAutoBendAmount > *(settingRefs->sweepEndPitch))
{
- currentAutoBendAmount = 0;
+ currentAutoBendAmount = *(settingRefs->sweepEndPitch);
autoBendDelta = 0;
}
}
else
{
// negative slope
- if (currentAutoBendAmount < 0)
+ if (currentAutoBendAmount < *(settingRefs->sweepEndPitch))
{
- currentAutoBendAmount = 0;
+ currentAutoBendAmount = *(settingRefs->sweepEndPitch);
autoBendDelta = 0;
}
}
-};
+}
+
+void TonalVoice::stopNote(float velocity, bool allowTailOff)
+{
+ BaseVoice::stopNote(velocity, allowTailOff);
+
+ if (!allowTailOff)
+ {
+ return;
+ }
+
+ if (settingRefs->isPitchSequenceEnabled())
+ {
+ if (settingRefs->pitchSequence.hasRelease)
+ {
+ if (settingRefs->pitchSequence.isInRelease(currentPitchSequenceFrame)) {
+ // Already in release(Custom Env.)
+ return;
+ }
+ currentPitchSequenceFrame = settingRefs->pitchSequence.releaseSequenceStartIndex;
+ }
+ }
+}
diff --git a/Source/TonalVoice.h b/Source/TonalVoice.h
index 5146fb7..a969762 100644
--- a/Source/TonalVoice.h
+++ b/Source/TonalVoice.h
@@ -36,6 +36,8 @@ struct TonalVoice : public BaseVoice // The base for Pulse and Triangle
// Custom Pitch/Note states
int currentPitchSequenceFrame = 0;
+ double nesPitchCorrection = 0;
+
void startNote (int midiNoteNumber, float velocity,
SynthesiserSound*, int currentPitchWheelPosition) override;
void advanceControlFrame() override;
@@ -46,4 +48,5 @@ struct TonalVoice : public BaseVoice // The base for Pulse and Triangle
double noteNoToHeltzDouble (double noteNoInDouble, const double frequencyOfA = 440);
void onFrameAdvanced() override;
+ void stopNote(float velocity, bool allowTailOff) override;
};
diff --git a/Source/WaveformParamsComponent.cpp b/Source/WaveformParamsComponent.cpp
new file mode 100644
index 0000000..56b6ca3
--- /dev/null
+++ b/Source/WaveformParamsComponent.cpp
@@ -0,0 +1,374 @@
+/*
+ ==============================================================================
+
+ 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: 6.0.8
+
+ ------------------------------------------------------------------------------
+
+ The Projucer is part of the JUCE library.
+ Copyright (c) 2020 - Raw Material Software Limited.
+
+ ==============================================================================
+*/
+
+//[Headers] You can add your own extra header files here...
+//[/Headers]
+
+#include "WaveformParamsComponent.h"
+
+
+//[MiscUserDefs] You can add your own user definitions and misc code here...
+//[/MiscUserDefs]
+
+//==============================================================================
+WaveformParamsComponent::WaveformParamsComponent (Magical8bitPlug2AudioProcessor& p)
+ : processor(p)
+{
+ //[Constructor_pre] You can add your own custom stuff here..
+ //[/Constructor_pre]
+
+ sliderVerticalComponent.reset (new SliderVerticalComponent (p, "waveformWave"));
+ addAndMakeVisible (sliderVerticalComponent.get());
+ sliderVerticalComponent->setName ("slider vertical component");
+
+ sliderVerticalComponent->setBounds (10, 34, 513, 250);
+
+ label.reset (new juce::Label ("label",
+ TRANS("Waveform")));
+ addAndMakeVisible (label.get());
+ label->setFont (juce::Font (17.00f, juce::Font::plain).withTypefaceStyle ("Regular"));
+ label->setJustificationType (juce::Justification::centredLeft);
+ label->setEditable (false, false, false);
+ label->setColour (juce::TextEditor::textColourId, juce::Colours::black);
+ label->setColour (juce::TextEditor::backgroundColourId, juce::Colour (0x00000000));
+
+ label->setBounds (0, 4, 150, 22);
+
+ waveformWaveText.reset (new juce::TextEditor ("waveform wave text"));
+ addAndMakeVisible (waveformWaveText.get());
+ waveformWaveText->setMultiLine (false);
+ waveformWaveText->setReturnKeyStartsNewLine (false);
+ waveformWaveText->setReadOnly (true);
+ waveformWaveText->setScrollbarsShown (false);
+ waveformWaveText->setCaretVisible (false);
+ waveformWaveText->setPopupMenuEnabled (false);
+ waveformWaveText->setText (juce::String());
+
+ waveformWaveText->setBounds (472, 8, 50, 20);
+
+ waveformComboX.reset (new juce::ComboBox ("waveform combo x"));
+ addAndMakeVisible (waveformComboX.get());
+ waveformComboX->setEditableText (false);
+ waveformComboX->setJustificationType (juce::Justification::centredLeft);
+ waveformComboX->setTextWhenNothingSelected (juce::String());
+ waveformComboX->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
+ waveformComboX->addListener (this);
+
+ waveformComboX->setBounds (40, 296, 80, 24);
+
+ waveformXLabel.reset (new juce::Label ("waveform x label",
+ TRANS("X")));
+ addAndMakeVisible (waveformXLabel.get());
+ waveformXLabel->setFont (juce::Font (15.00f, juce::Font::plain).withTypefaceStyle ("Regular"));
+ waveformXLabel->setJustificationType (juce::Justification::centredLeft);
+ waveformXLabel->setEditable (false, false, false);
+ waveformXLabel->setColour (juce::TextEditor::textColourId, juce::Colours::black);
+ waveformXLabel->setColour (juce::TextEditor::backgroundColourId, juce::Colour (0x00000000));
+
+ waveformXLabel->setBounds (16, 296, 24, 24);
+
+ waveformYLabel.reset (new juce::Label ("waveform y label",
+ TRANS("Y")));
+ addAndMakeVisible (waveformYLabel.get());
+ waveformYLabel->setFont (juce::Font (15.00f, juce::Font::plain).withTypefaceStyle ("Regular"));
+ waveformYLabel->setJustificationType (juce::Justification::centredLeft);
+ waveformYLabel->setEditable (false, false, false);
+ waveformYLabel->setColour (juce::TextEditor::textColourId, juce::Colours::black);
+ waveformYLabel->setColour (juce::TextEditor::backgroundColourId, juce::Colour (0x00000000));
+
+ waveformYLabel->setBounds (136, 296, 24, 24);
+
+ waveformComboY.reset (new juce::ComboBox ("waveform combo y"));
+ addAndMakeVisible (waveformComboY.get());
+ waveformComboY->setEditableText (false);
+ waveformComboY->setJustificationType (juce::Justification::centredLeft);
+ waveformComboY->setTextWhenNothingSelected (juce::String());
+ waveformComboY->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
+ waveformComboY->addListener (this);
+
+ waveformComboY->setBounds (160, 296, 80, 24);
+
+ waveformTemplateLabel.reset (new juce::Label ("waveform template label",
+ TRANS("Template")));
+ addAndMakeVisible (waveformTemplateLabel.get());
+ waveformTemplateLabel->setFont (juce::Font (15.00f, juce::Font::plain).withTypefaceStyle ("Regular"));
+ waveformTemplateLabel->setJustificationType (juce::Justification::centredLeft);
+ waveformTemplateLabel->setEditable (false, false, false);
+ waveformTemplateLabel->setColour (juce::TextEditor::textColourId, juce::Colours::black);
+ waveformTemplateLabel->setColour (juce::TextEditor::backgroundColourId, juce::Colour (0x00000000));
+
+ waveformTemplateLabel->setBounds (280, 296, 72, 24);
+
+ waveformComboTemplate.reset (new juce::ComboBox ("waveform combo template"));
+ addAndMakeVisible (waveformComboTemplate.get());
+ waveformComboTemplate->setEditableText (false);
+ waveformComboTemplate->setJustificationType (juce::Justification::centredLeft);
+ waveformComboTemplate->setTextWhenNothingSelected (juce::String());
+ waveformComboTemplate->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
+ waveformComboTemplate->addListener (this);
+
+ waveformComboTemplate->setBounds (352, 296, 168, 24);
+
+
+ //[UserPreSize]
+ //[/UserPreSize]
+
+ setSize (536, 340);
+
+
+ //[Constructor] You can add your own custom stuff here..
+ AudioParameterChoice* cX = (AudioParameterChoice*)p.parameters.getParameter("waveformX");
+ for (int i = 0; i < cX->choices.size(); i++)
+ {
+ String choice = cX->choices[i];
+ waveformComboX->addItem(choice, i + 1);
+ }
+ waveformComboX->setSelectedItemIndex(cX->getIndex());
+ attcX.reset(new ComboBoxAttachment(p.parameters, "waveformX", *waveformComboX));
+
+ AudioParameterChoice* cY = (AudioParameterChoice*)p.parameters.getParameter("waveformY");
+ for (int i = 0; i < cY->choices.size(); i++)
+ {
+ String choice = cY->choices[i];
+ waveformComboY->addItem(choice, i + 1);
+ }
+ waveformComboY->setSelectedItemIndex(cY->getIndex());
+ attcY.reset(new ComboBoxAttachment(p.parameters, "waveformY", *waveformComboY));
+
+ AudioParameterChoice* cTemplate = (AudioParameterChoice*)p.parameters.getParameter("waveformTemplate");
+ for (int i = 0; i < cTemplate->choices.size(); i++)
+ {
+ String choice = cTemplate->choices[i];
+ waveformComboTemplate->addItem(choice, i + 1);
+ }
+ waveformComboTemplate->setSelectedItemIndex(cTemplate->getIndex());
+ attcTemplate.reset(new ComboBoxAttachment(p.parameters, "waveformTemplate", *waveformComboTemplate));
+
+ int fontHeight = waveformWaveText->getFont().getHeight();
+ int topIndent = (waveformWaveText->getHeight() - fontHeight) / 2;
+ int fontWidth = fontHeight;
+ int leftIndent = (waveformWaveText->getWidth() - fontWidth) / 2;
+ waveformWaveText->setBorder(BorderSize(0, 0, 0, 0));
+ waveformWaveText->setIndents(leftIndent, topIndent);
+ //[/Constructor]
+}
+
+WaveformParamsComponent::~WaveformParamsComponent()
+{
+ //[Destructor_pre]. You can add your own custom destruction code here..
+ attcX.reset();
+ attcY.reset();
+ attcTemplate.reset();
+ //[/Destructor_pre]
+
+ sliderVerticalComponent = nullptr;
+ label = nullptr;
+ waveformWaveText = nullptr;
+ waveformComboX = nullptr;
+ waveformXLabel = nullptr;
+ waveformYLabel = nullptr;
+ waveformComboY = nullptr;
+ waveformTemplateLabel = nullptr;
+ waveformComboTemplate = nullptr;
+
+
+ //[Destructor]. You can add your own custom destruction code here..
+ //[/Destructor]
+}
+
+//==============================================================================
+void WaveformParamsComponent::paint (juce::Graphics& g)
+{
+ //[UserPrePaint] Add your own custom painting code here..
+ //[/UserPrePaint]
+
+ //[UserPaint] Add your own custom painting code here..
+ //[/UserPaint]
+}
+
+void WaveformParamsComponent::resized()
+{
+ //[UserPreResize] Add your own custom resize code here..
+ //[/UserPreResize]
+
+ //[UserResized] Add your own custom resize handling here..
+ //[/UserResized]
+}
+
+void WaveformParamsComponent::comboBoxChanged (juce::ComboBox* comboBoxThatHasChanged)
+{
+ //[UsercomboBoxChanged_Pre]
+ //[/UsercomboBoxChanged_Pre]
+
+ if (comboBoxThatHasChanged == waveformComboX.get())
+ {
+ //[UserComboBoxCode_waveformComboX] -- add your combo box handling code here..
+ sliderVerticalComponent->setForm(processor.settingRefs.getWaveformX(), processor.settingRefs.getWaveformY(), 513, 250);
+ //[/UserComboBoxCode_waveformComboX]
+ }
+ else if (comboBoxThatHasChanged == waveformComboY.get())
+ {
+ //[UserComboBoxCode_waveformComboY] -- add your combo box handling code here..
+ sliderVerticalComponent->setForm(processor.settingRefs.getWaveformX(), processor.settingRefs.getWaveformY(), 513, 250);
+ //[/UserComboBoxCode_waveformComboY]
+ }
+ else if (comboBoxThatHasChanged == waveformComboTemplate.get())
+ {
+ //[UserComboBoxCode_waveformComboTemplate] -- add your combo box handling code here..
+ //0:"Custom", 1:"Sine", 2:"Triangle", 3:"Sawtooth", 4:"Square 6.25%", 5:"Square 18.75%", 6:"Square 31.25%", 7:"Square 37.5%", 8:"Square 43.75%"
+ int x = processor.settingRefs.getWaveformX();
+ int y = processor.settingRefs.getWaveformY();
+ if (waveformComboTemplate->getSelectedItemIndex() == 1)
+ {
+ double twopi = MathConstants::pi * 2.0;
+ for (int i = 0; i < x; i++)
+ {
+ sliderVerticalComponent->setValue(i, (int)((std::sin(twopi * i / x) + 1.0) * y / 2.0 + 0.5));
+ }
+ }
+ else if (waveformComboTemplate->getSelectedItemIndex() == 2)
+ {
+ for (int i = 0; i < (x / 2); i++)
+ {
+ sliderVerticalComponent->setValue(i, (int)(i * (double)y / (x / 2 - 1) + 0.5));
+ sliderVerticalComponent->setValue(i + (x / 2), (int)(y - i * (double)y / (x / 2 - 1) + 0.5));
+ }
+ }
+ else if (waveformComboTemplate->getSelectedItemIndex() == 3)
+ {
+ for (int i = 0; i < x; i++)
+ {
+ sliderVerticalComponent->setValue(i, (int)(i * (double)y / (x - 1) + 0.5));
+ }
+ }
+ else if (waveformComboTemplate->getSelectedItemIndex() >= 4 && waveformComboTemplate->getSelectedItemIndex() <= 8)
+ {
+ double duty[5] = { 0.0625, 0.1875, 0.3125, 0.375, 0.4375 };
+ for (int i = 0; i < (int)(x * duty[waveformComboTemplate->getSelectedItemIndex() - 4]); i++)
+ {
+ sliderVerticalComponent->setValue(i, 0);
+ }
+ for (int i = (int)(x * duty[waveformComboTemplate->getSelectedItemIndex() - 4]); i < x; i++)
+ {
+ sliderVerticalComponent->setValue(i, y);
+ }
+ }
+ waveformComboTemplate->setSelectedItemIndex(0);
+ //[/UserComboBoxCode_waveformComboTemplate]
+ }
+
+ //[UsercomboBoxChanged_Post]
+ //[/UsercomboBoxChanged_Post]
+}
+
+void WaveformParamsComponent::mouseDrag (const juce::MouseEvent& e)
+{
+ //[UserCode_mouseDrag] -- Add your code here...
+ int waveValue = sliderVerticalComponent->waveValue;
+ if (waveValue >= 0)
+ {
+ waveformWaveText->setText(String(waveValue));
+ }
+ //[/UserCode_mouseDrag]
+}
+
+
+
+//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
+void WaveformParamsComponent::sliderRepaint()
+{
+ sliderVerticalComponent->setForm(processor.settingRefs.getWaveformX(), processor.settingRefs.getWaveformY(), 513, 250);
+}
+
+//void WaveformParamsComponent::sliderInit()
+//{
+// for (int i = 0; i < 64; i++)
+// {
+// //sliderVerticalComponent->verticalSliders[i]->setValue(0);
+// sliderVerticalComponent->verticalSliders[i]->setRange(0, 63, 1);
+// //sliderVerticalComponent->verticalSliders[i]->repaint();
+// }
+//}
+//[/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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+END_JUCER_METADATA
+*/
+#endif
+
+
+//[EndFile] You can add extra defines here...
+//[/EndFile]
+
diff --git a/Source/WaveformParamsComponent.h b/Source/WaveformParamsComponent.h
new file mode 100644
index 0000000..99c267c
--- /dev/null
+++ b/Source/WaveformParamsComponent.h
@@ -0,0 +1,84 @@
+/*
+ ==============================================================================
+
+ 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: 6.0.8
+
+ ------------------------------------------------------------------------------
+
+ The Projucer is part of the JUCE library.
+ Copyright (c) 2020 - Raw Material Software Limited.
+
+ ==============================================================================
+*/
+
+#pragma once
+
+//[Headers] -- You can add your own extra header files here --
+#include
+#include "SliderVerticalComponent.h"
+//[/Headers]
+
+
+
+//==============================================================================
+/**
+ //[Comments]
+ An auto-generated component, created by the Projucer.
+
+ Describe your class and how it works here!
+ //[/Comments]
+*/
+class WaveformParamsComponent : public Component,
+ public juce::ComboBox::Listener
+{
+public:
+ //==============================================================================
+ WaveformParamsComponent (Magical8bitPlug2AudioProcessor& p);
+ ~WaveformParamsComponent() override;
+
+ //==============================================================================
+ //[UserMethods] -- You can add your own custom methods in this section.
+ void sliderRepaint();
+ //void sliderInit();
+ //[/UserMethods]
+
+ void paint (juce::Graphics& g) override;
+ void resized() override;
+ void comboBoxChanged (juce::ComboBox* comboBoxThatHasChanged) override;
+ void mouseDrag (const juce::MouseEvent& e) override;
+
+
+
+private:
+ //[UserVariables] -- You can add your own custom variables in this section.
+ Magical8bitPlug2AudioProcessor& processor;
+ std::unique_ptr attcX;
+ std::unique_ptr attcY;
+ std::unique_ptr attcTemplate;
+ //[/UserVariables]
+
+ //==============================================================================
+ std::unique_ptr sliderVerticalComponent;
+ std::unique_ptr label;
+ std::unique_ptr waveformWaveText;
+ std::unique_ptr waveformComboX;
+ std::unique_ptr waveformXLabel;
+ std::unique_ptr waveformYLabel;
+ std::unique_ptr waveformComboY;
+ std::unique_ptr waveformTemplateLabel;
+ std::unique_ptr waveformComboTemplate;
+
+
+ //==============================================================================
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WaveformParamsComponent)
+};
+
+//[EndFile] You can add extra defines here...
+//[/EndFile]
+
diff --git a/Source/WaveformVoice.cpp b/Source/WaveformVoice.cpp
new file mode 100644
index 0000000..a2a19b0
--- /dev/null
+++ b/Source/WaveformVoice.cpp
@@ -0,0 +1,39 @@
+/*
+ ==============================================================================
+
+ WaveformVoice.cpp
+ Created: 7 Jul 2021 5:57:30am
+ Author: SHACHO
+
+ ==============================================================================
+*/
+
+#include "WaveformVoice.h"
+
+//---------------------------------------------
+//
+// Waveform Voice
+//
+//---------------------------------------------
+WaveformVoice::WaveformVoice(SettingRefs* sRefs) : TonalVoice(sRefs) {}
+
+float WaveformVoice::voltageForAngle(double angle)
+{
+ int x = settingRefs->getWaveformX();
+ int y = 63; // settingRefs->getWaveformY();
+
+ float sequence[64];
+
+ for (int i = 0; i < x; i++)
+ {
+ sequence[i] = *(settingRefs->waveformWave[i]);
+ }
+
+ double twopi = MathConstants::pi * 2.0;
+ int step = (int)(x * angle / twopi);
+
+ float level = sequence[step];
+ float output = (float)level / (y / 2.0f) - 1.0f;
+
+ return output;
+}
diff --git a/Source/WaveformVoice.h b/Source/WaveformVoice.h
new file mode 100644
index 0000000..27f959c
--- /dev/null
+++ b/Source/WaveformVoice.h
@@ -0,0 +1,18 @@
+/*
+ ==============================================================================
+
+ WaveformVoice.h
+ Created: 7 Jul 2021 5:57:30am
+ Author: SHACHO
+
+ ==============================================================================
+*/
+
+#pragma once
+#include "TonalVoice.h"
+
+struct WaveformVoice : public TonalVoice
+{
+ WaveformVoice(SettingRefs* sRefs);
+ float voltageForAngle(double angle) override;
+};