Custom Waveform

This commit is contained in:
Takeshi Yokemura 2021-08-15 20:41:01 +09:00
parent 47cefdd0e8
commit 915f9eb5bf
20 changed files with 1099 additions and 44 deletions

View File

@ -33,6 +33,10 @@
file="Source/SliderComponent.cpp"/>
<FILE id="qIuf9N" name="SliderComponent.h" compile="0" resource="0"
file="Source/SliderComponent.h"/>
<FILE id="uajfNh" name="SliderVerticalComponent.cpp" compile="1" resource="0"
file="Source/SliderVerticalComponent.cpp"/>
<FILE id="p2nPNB" name="SliderVerticalComponent.h" compile="0" resource="0"
file="Source/SliderVerticalComponent.h"/>
</GROUP>
<FILE id="SFqkUr" name="AdvancedParamsComponent.cpp" compile="1" resource="0"
file="Source/AdvancedParamsComponent.cpp"/>
@ -68,6 +72,13 @@
file="Source/VibratoParamsComponent.h"/>
</GROUP>
<GROUP id="{630C27C7-03AA-CFC6-2FC4-4CE2DBE3640A}" name="Source">
<FILE id="WS1wsR" name="WaveformParamsComponent.cpp" compile="1" resource="0"
file="Source/WaveformParamsComponent.cpp"/>
<FILE id="miNL07" name="WaveformParamsComponent.h" compile="0" resource="0"
file="Source/WaveformParamsComponent.h"/>
<FILE id="vVn1lo" name="WaveformVoice.cpp" compile="1" resource="0"
file="Source/WaveformVoice.cpp"/>
<FILE id="iZpU3j" name="WaveformVoice.h" compile="0" resource="0" file="Source/WaveformVoice.h"/>
<FILE id="H2Vgbj" name="FrameSequenceParseErrors.cpp" compile="1" resource="0"
file="Source/FrameSequenceParseErrors.cpp"/>
<FILE id="Gwt2vB" name="FrameSequenceParseErrors.h" compile="0" resource="0"

View File

@ -154,6 +154,7 @@ void BasicParamsComponent::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
{
processor.setupVoice();
editor.resized();
editor.resizeWholePanel();
printf ("setup voice!!\n");
}

View File

@ -18,7 +18,9 @@
NoiseVoice::NoiseVoice(SettingRefs *sRefs) : TonalVoice(sRefs) {}
void NoiseVoice::startNote(int midiNoteNumber, float velocity, SynthesiserSound *, int currentPitchBendPosition) {
TonalVoice::startNote(midiNoteNumber, velocity, 0, currentPitchBendPosition);
//TonalVoice::startNote(midiNoteNumber, velocity, 0, currentPitchBendPosition);
int midiNote = midiNoteNumber;
int midiNoteRange[16] = { 5, 17, 29, 34, 41, 46, 53, 57, 61, 65, 70, 77, 89, 101, 113, 125 };
switch (settingRefs->noiseAlgorithm()) {
case kNoiseInfinite2:
cycleLength = MathConstants<float>::pi / 25.0;
@ -29,10 +31,19 @@ void NoiseVoice::startNote(int midiNoteNumber, float velocity, SynthesiserSound
cycleLength = MathConstants<float>::pi / 8.0;
break;
case kNoiseLongNes:
case kNoiseShortNes:
cycleLength = MathConstants<float>::pi / 20.175;
//rgstr = 0x8000;
//rgstr = rand();
midiNote = midiNoteRange[(midiNote + 8) % 16];
break;
default:
cycleLength = MathConstants<float>::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;

View File

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

View File

@ -20,6 +20,7 @@ class NoiseParamsComponent;
class BendParamsComponent;
class SweepParamsComponent;
class VibratoParamsComponent;
class WaveformParamsComponent;
//==============================================================================
/**
@ -40,6 +41,10 @@ public:
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 @@ private:
std::unique_ptr<BendParamsComponent> bendCompo;
std::unique_ptr<SweepParamsComponent> sweepCompo;
std::unique_ptr<VibratoParamsComponent> vibCompo;
std::unique_ptr<WaveformParamsComponent> waveformCompo;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Magical8bitPlug2AudioProcessorEditor)
};

View File

@ -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<AudioParameterBool> ("isAdvancedPanelOpen_raw", "Advanced", false),
//
// 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<AudioParameterChoice> ("osc", "OSC Type", StringArray ({"Pulse/Square", "Triangle", "Noise", "Waveform"}), 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),
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<AudioParameterFloat> ("decay", //ID
"Decay", //name
NormalisableRange<float> (0.0f, //min
5.0f, //max
0.001f, //step
0.5f), //skew
0.0f), //default
0.0f), //default
std::make_unique<AudioParameterFloat> ("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<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),
@ -92,13 +93,14 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
// Sweep
//
std::make_unique<AudioParameterInt> ("sweepInitialPitch", "Ini.Pitch", -24, 24, 0),
std::make_unique<AudioParameterInt> ("sweepEndPitch", "End.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
0.1f), //default
//
// For Pulse
//
@ -106,7 +108,7 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
//
// For Noise
//
std::make_unique<AudioParameterChoice> ("noiseAlgorithm_raw", "Algorithm", StringArray ({"4bit Pure Random", "1bit Long Cycle", "1bit Short Cycle"}), 0),
std::make_unique<AudioParameterChoice> ("noiseAlgorithm_raw", "Algorithm", StringArray ({"4bit Pure Random", "1bit Long Cycle", "1bit Short Cycle", "Nes Long Cycle", "Nes Short Cycle"}), 0),
std::make_unique<AudioParameterBool> ("restrictsToNESFrequency_raw", "Restricts to NES frequency", false),
//
// Sequence
@ -114,8 +116,77 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
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)
}
std::make_unique<AudioParameterChoice> ("pitchSequenceMode_raw", "Mode", StringArray ({"Coarse", "Fine8", "Fine16"}), 0),
// waveform
std::make_unique<AudioParameterChoice>("waveformX", "X", StringArray({ "16", "32", "64" }), 2),
std::make_unique<AudioParameterChoice>("waveformY", "Y", StringArray({ "16", "32", "64" }), 2),
std::make_unique<AudioParameterChoice>("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<AudioParameterFloat>("waveformWave0", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave1", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave2", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave3", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave4", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave5", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave6", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave7", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave8", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave9", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave10", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave11", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave12", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave13", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave14", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave15", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave16", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave17", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave18", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave19", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave20", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave21", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave22", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave23", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave24", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave25", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave26", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave27", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave28", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave29", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave30", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave31", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave32", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave33", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave34", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave35", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave36", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave37", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave38", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave39", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave40", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave41", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave42", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave43", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave44", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave45", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave46", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave47", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave48", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave49", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave50", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave51", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave52", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave53", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave54", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave55", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave56", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave57", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave58", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave59", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave60", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave61", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave62", "wave", 0, 63, 0),
std::make_unique<AudioParameterFloat>("waveformWave63", "wave", 0, 63, 0)
}
)
, settingRefs (&parameters)
#ifndef JucePlugin_PreferredChannelConfigurations
@ -129,6 +200,16 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
)
#endif
{
// waveform
//parameters.createAndAddParameter(std::make_unique<AudioParameterChoice>("waveformX", "X", StringArray({ "16", "32", "64" }), 2));
//parameters.createAndAddParameter(std::make_unique<AudioParameterChoice>("waveformY", "Y", StringArray({ "16", "32", "64" }), 2));
//parameters.createAndAddParameter(std::make_unique<AudioParameterChoice>("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<AudioParameterInt>("waveformWave" + String(i), "wave" + String(i), 0, 63, 0));
//}
//settingRefs.setWaveform(&parameters);
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<XmlElement> 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();
}
}
//==============================================================================

View File

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

View File

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

View File

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

View File

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

View File

@ -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
<JUCER_COMPONENT documentType="Component" className="SliderVerticalComponent"
componentName="" parentClasses="public juce::Component" constructorParams="Magical8bitPlug2AudioProcessor&amp; p, String paramId"
variableInitialisers="processor(p)" snapPixels="8" snapActive="1"
snapShown="1" overlayOpacity="0.330" fixedSize="1" initialWidth="513"
initialHeight="250">
<METHODS>
<METHOD name="mouseDrag (const juce::MouseEvent&amp; e)"/>
<METHOD name="mouseDown (const juce::MouseEvent&amp; e)"/>
</METHODS>
<BACKGROUND backgroundColour="ffffff"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -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 <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 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<juce::Slider> verticalSliders[64];
int numWidth;
int maxValue;
int baseMaxValue;
Magical8bitPlug2AudioProcessor& processor;
std::unique_ptr<SliderAttachment> attc[64];
//[/UserVariables]
//==============================================================================
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SliderVerticalComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -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
<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">
overlayOpacity="0.330" fixedSize="1" initialWidth="340" initialHeight="114">
<BACKGROUND backgroundColour="ffffff"/>
<LABEL name="label" id="bae3132bcad681ce" memberName="label" virtualName=""
explicitFocusOrder="0" pos="0 4 150 22" edTextCol="ff000000"
@ -126,8 +132,11 @@ BEGIN_JUCER_METADATA
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"
virtualName="" explicitFocusOrder="0" pos="0 82 100% 28" class="SliderComponent"
params="p, &quot;sweepTime&quot;, &quot;Time&quot;"/>
<GENERICCOMPONENT name="end pitch slider" id="25cde38cec6274db" memberName="endPitchSlider"
virtualName="" explicitFocusOrder="0" pos="0 54 100% 28" class="SliderComponent"
params="p, &quot;sweepEndPitch&quot;, &quot;End.Pitch&quot;"/>
</JUCER_COMPONENT>
END_JUCER_METADATA

View File

@ -58,6 +58,7 @@ private:
std::unique_ptr<juce::Label> label;
std::unique_ptr<SliderComponent> iniPitchSlider;
std::unique_ptr<SliderComponent> timeSlider;
std::unique_ptr<SliderComponent> endPitchSlider;
//==============================================================================

View File

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

View File

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

View File

@ -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<int>(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<float>::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
<JUCER_COMPONENT documentType="Component" className="WaveformParamsComponent"
componentName="" parentClasses="public Component" constructorParams="Magical8bitPlug2AudioProcessor&amp; p"
variableInitialisers="processor(p)" snapPixels="8" snapActive="1"
snapShown="1" overlayOpacity="0.330" fixedSize="1" initialWidth="536"
initialHeight="340">
<METHODS>
<METHOD name="mouseDrag (const juce::MouseEvent&amp; e)"/>
</METHODS>
<BACKGROUND backgroundColour="ffffff"/>
<GENERICCOMPONENT name="slider vertical component" id="d3c5ea1dec0891ea" memberName="sliderVerticalComponent"
virtualName="" explicitFocusOrder="0" pos="10 34 513 250" class="SliderVerticalComponent"
params="p, &quot;waveformWave&quot;"/>
<LABEL name="label" id="bae3132bcad681ce" memberName="label" virtualName=""
explicitFocusOrder="0" pos="0 4 150 22" edTextCol="ff000000"
edBkgCol="0" labelText="Waveform" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="17.0"
kerning="0.0" bold="0" italic="0" justification="33"/>
<TEXTEDITOR name="waveform wave text" id="a0d4c4fff23ba9a7" memberName="waveformWaveText"
virtualName="" explicitFocusOrder="0" pos="472 8 50 20" initialText=""
multiline="0" retKeyStartsLine="0" readonly="1" scrollbars="0"
caret="0" popupmenu="0"/>
<COMBOBOX name="waveform combo x" id="47a8fb84e28a923b" memberName="waveformComboX"
virtualName="" explicitFocusOrder="0" pos="40 296 80 24" editable="0"
layout="33" items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/>
<LABEL name="waveform x label" id="80e4ef8bbf096c16" memberName="waveformXLabel"
virtualName="" explicitFocusOrder="0" pos="16 296 24 24" edTextCol="ff000000"
edBkgCol="0" labelText="X" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="15.0"
kerning="0.0" bold="0" italic="0" justification="33"/>
<LABEL name="waveform y label" id="9d743f56f93330a9" memberName="waveformYLabel"
virtualName="" explicitFocusOrder="0" pos="136 296 24 24" edTextCol="ff000000"
edBkgCol="0" labelText="Y" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="15.0"
kerning="0.0" bold="0" italic="0" justification="33"/>
<COMBOBOX name="waveform combo y" id="519e5c60d0487582" memberName="waveformComboY"
virtualName="" explicitFocusOrder="0" pos="160 296 80 24" editable="0"
layout="33" items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/>
<LABEL name="waveform template label" id="c0bf04a500a0f7b" memberName="waveformTemplateLabel"
virtualName="" explicitFocusOrder="0" pos="280 296 72 24" edTextCol="ff000000"
edBkgCol="0" labelText="Template" editableSingleClick="0" editableDoubleClick="0"
focusDiscardsChanges="0" fontname="Default font" fontsize="15.0"
kerning="0.0" bold="0" italic="0" justification="33"/>
<COMBOBOX name="waveform combo template" id="a71bba02a0c84649" memberName="waveformComboTemplate"
virtualName="" explicitFocusOrder="0" pos="352 296 168 24" editable="0"
layout="33" items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

View File

@ -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 <JuceHeader.h>
#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<ComboBoxAttachment> attcX;
std::unique_ptr<ComboBoxAttachment> attcY;
std::unique_ptr<ComboBoxAttachment> attcTemplate;
//[/UserVariables]
//==============================================================================
std::unique_ptr<SliderVerticalComponent> sliderVerticalComponent;
std::unique_ptr<juce::Label> label;
std::unique_ptr<juce::TextEditor> waveformWaveText;
std::unique_ptr<juce::ComboBox> waveformComboX;
std::unique_ptr<juce::Label> waveformXLabel;
std::unique_ptr<juce::Label> waveformYLabel;
std::unique_ptr<juce::ComboBox> waveformComboY;
std::unique_ptr<juce::Label> waveformTemplateLabel;
std::unique_ptr<juce::ComboBox> waveformComboTemplate;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WaveformParamsComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]

39
Source/WaveformVoice.cpp Normal file
View File

@ -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<float>::pi * 2.0;
int step = (int)(x * angle / twopi);
float level = sequence[step];
float output = (float)level / (y / 2.0f) - 1.0f;
return output;
}

18
Source/WaveformVoice.h Normal file
View File

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