diff --git a/hi_core/hi_modules/synthesisers/editors/WaveSynthBody.cpp b/hi_core/hi_modules/synthesisers/editors/WaveSynthBody.cpp
index 54a5af778f..75d8eb6998 100644
--- a/hi_core/hi_modules/synthesisers/editors/WaveSynthBody.cpp
+++ b/hi_core/hi_modules/synthesisers/editors/WaveSynthBody.cpp
@@ -182,6 +182,17 @@ WaveSynthBody::WaveSynthBody (ProcessorEditor *p)
pulseSlider2->setTextBoxStyle (Slider::TextBoxRight, false, 40, 20);
pulseSlider2->addListener (this);
+ addAndMakeVisible (semiToneSlider1 = new HiSlider ("SemiTones 1"));
+ semiToneSlider1->setRange (-12, 12, 1);
+ semiToneSlider1->setSliderStyle (Slider::RotaryHorizontalVerticalDrag);
+ semiToneSlider1->setTextBoxStyle (Slider::TextBoxRight, false, 40, 20);
+ semiToneSlider1->addListener (this);
+
+ addAndMakeVisible (semiToneSlider2 = new HiSlider ("SemiTones 2"));
+ semiToneSlider2->setRange (-12, 12, 1);
+ semiToneSlider2->setSliderStyle (Slider::RotaryHorizontalVerticalDrag);
+ semiToneSlider2->setTextBoxStyle (Slider::TextBoxRight, false, 40, 20);
+ semiToneSlider2->addListener (this);
//[UserPreSize]
@@ -219,6 +230,14 @@ WaveSynthBody::WaveSynthBody (ProcessorEditor *p)
pulseSlider2->setup(getProcessor(), WaveSynth::SpecialParameters::PulseWidth2, "Pulse Width 2");
pulseSlider2->setMode(HiSlider::Mode::NormalizedPercentage);
+ semiToneSlider1->setup(getProcessor(), WaveSynth::SpecialParameters::SemiTones1, "SemiTones 1");
+ semiToneSlider1->setMode(HiSlider::Discrete, -12.0, 12.0);
+ semiToneSlider1->setRange(-12.0, 12.0, 1.0);
+
+ semiToneSlider2->setup(getProcessor(), WaveSynth::SpecialParameters::SemiTones2, "SemiTones 2");
+ semiToneSlider2->setMode(HiSlider::Discrete, -12.0, 12.0);
+ semiToneSlider2->setRange(-12.0, 12.0, 1.0);
+
voiceAmountEditor->setFont(GLOBAL_FONT());
voiceAmountLabel->setFont(GLOBAL_FONT());
fadeTimeEditor->setFont(GLOBAL_FONT());
@@ -258,6 +277,8 @@ WaveSynthBody::~WaveSynthBody()
enableSecondButton = nullptr;
pulseSlider1 = nullptr;
pulseSlider2 = nullptr;
+ semiToneSlider1 = nullptr;
+ semiToneSlider2 = nullptr;
//[Destructor]. You can add your own custom destruction code here..
@@ -297,26 +318,28 @@ void WaveSynthBody::resized()
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
- octaveSlider->setBounds (158, 15, 128, 48);
- waveFormSelector->setBounds (26, 65, 128, 24);
- waveformDisplay->setBounds (26, 15, 128, 48);
+ octaveSlider->setBounds (160, 17, 128, 48);
+ waveFormSelector->setBounds (25, 42, 128, 24);
+ waveformDisplay->setBounds (25, 15, 128, 24);
fadeTimeLabel->setBounds ((getWidth() / 2) + 7, 61, 79, 24);
voiceAmountLabel->setBounds ((getWidth() / 2) + -69, 62, 79, 24);
voiceAmountEditor->setBounds ((getWidth() / 2) + -30 - (68 / 2), 80, 68, 16);
fadeTimeEditor->setBounds ((getWidth() / 2) + 12, 80, 51, 16);
- octaveSlider2->setBounds (getWidth() - 161 - 128, 15, 128, 48);
- waveFormSelector2->setBounds (getWidth() - 26 - 128, 65, 128, 24);
- waveformDisplay2->setBounds (getWidth() - 26 - 128, 15, 128, 48);
+ octaveSlider2->setBounds (getWidth() - 161 - 128, 17, 128, 48);
+ waveFormSelector2->setBounds (getWidth() - 26 - 128, 42, 128, 24);
+ waveformDisplay2->setBounds (getWidth() - 26 - 128, 15, 128, 24);
mixSlider->setBounds ((getWidth() / 2) - (128 / 2), 13, 128, 48);
- panSlider->setBounds (160, 73, 128, 48);
- panSlider2->setBounds (getWidth() - 161 - 128, 73, 128, 48);
- detuneSlider2->setBounds (getWidth() - 26 - 128, 94, 128, 48);
- detuneSlider->setBounds (25, 96, 128, 48);
+ panSlider->setBounds (25, 134, 128, 48);
+ panSlider2->setBounds (getWidth() - 26 - 128, 134, 128, 48);
+ detuneSlider2->setBounds (getWidth() - 161 - 128, 134, 128, 48);
+ detuneSlider->setBounds (160, 134, 128, 48);
enableSecondButton->setBounds ((getWidth() / 2) + -64, 136, 128, 28);
enableSyncButton->setBounds((getWidth() / 2) + -64, 166, 128, 28);
- pulseSlider1->setBounds (160, 132, 128, 48);
- pulseSlider2->setBounds (getWidth() - 161 - 128, 132, 128, 48);
+ pulseSlider1->setBounds (25, 77, 128, 48);
+ pulseSlider2->setBounds (getWidth() - 26 - 128, 77, 128, 48);
+ semiToneSlider1->setBounds (160, 77, 128, 48);
+ semiToneSlider2->setBounds (getWidth() - 161 - 128, 77, 128, 48);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
@@ -371,6 +394,16 @@ void WaveSynthBody::sliderValueChanged (Slider* sliderThatWasMoved)
//[UserSliderCode_pulseSlider2] -- add your slider handling code here..
//[/UserSliderCode_pulseSlider2]
}
+ else if (sliderThatWasMoved == semiToneSlider1)
+ {
+ //[UserSliderCode_semiToneSlider1] -- add your slider handling code here..
+ //[/UserSliderCode_semiToneSlider1]
+ }
+ else if (sliderThatWasMoved == semiToneSlider2)
+ {
+ //[UserSliderCode_semiToneSlider2] -- add your slider handling code here..
+ //[/UserSliderCode_semiToneSlider2]
+ }
//[UsersliderValueChanged_Post]
//[/UsersliderValueChanged_Post]
@@ -384,13 +417,13 @@ void WaveSynthBody::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
if (comboBoxThatHasChanged == waveFormSelector)
{
//[UserComboBoxCode_waveFormSelector] -- add your combo box handling code here..
-
+
//[/UserComboBoxCode_waveFormSelector]
}
else if (comboBoxThatHasChanged == waveFormSelector2)
{
//[UserComboBoxCode_waveFormSelector2] -- add your combo box handling code here..
-
+
//[/UserComboBoxCode_waveFormSelector2]
}
@@ -566,6 +599,16 @@ BEGIN_JUCER_METADATA
int="0.010000000000000000208" style="RotaryHorizontalVerticalDrag"
textBoxPos="TextBoxRight" textBoxEditable="1" textBoxWidth="40"
textBoxHeight="20" skewFactor="1" needsCallback="1"/>
+
+
END_JUCER_METADATA
diff --git a/hi_core/hi_modules/synthesisers/editors/WaveSynthBody.h b/hi_core/hi_modules/synthesisers/editors/WaveSynthBody.h
index 269d3ea5a0..a30f2a19b8 100644
--- a/hi_core/hi_modules/synthesisers/editors/WaveSynthBody.h
+++ b/hi_core/hi_modules/synthesisers/editors/WaveSynthBody.h
@@ -60,6 +60,9 @@ class WaveSynthBody : public ProcessorEditorBody,
octaveSlider->updateValue();
octaveSlider2->updateValue();
+ semiToneSlider1->updateValue();
+ semiToneSlider2->updateValue();
+
detuneSlider->updateValue();
detuneSlider2->updateValue();
@@ -87,7 +90,7 @@ class WaveSynthBody : public ProcessorEditorBody,
octaveSlider2->setEnabled(false);
detuneSlider2->setEnabled(false);
panSlider2->setEnabled(false);
-
+
}
};
@@ -105,8 +108,8 @@ class WaveSynthBody : public ProcessorEditorBody,
{
return h;
}
-
-
+
+
//[/UserMethods]
@@ -144,6 +147,8 @@ class WaveSynthBody : public ProcessorEditorBody,
ScopedPointer enableSyncButton;
ScopedPointer pulseSlider1;
ScopedPointer pulseSlider2;
+ ScopedPointer semiToneSlider1;
+ ScopedPointer semiToneSlider2;
//==============================================================================
diff --git a/hi_core/hi_modules/synthesisers/synths/WaveSynth.cpp b/hi_core/hi_modules/synthesisers/synths/WaveSynth.cpp
index 5e41175b8b..2d889976b9 100644
--- a/hi_core/hi_modules/synthesisers/synths/WaveSynth.cpp
+++ b/hi_core/hi_modules/synthesisers/synths/WaveSynth.cpp
@@ -41,6 +41,8 @@ WaveSynth::WaveSynth(MainController *mc, const String &id, int numVoices) :
ModulatorSynth(mc, id, numVoices),
octaveTranspose1((int)getDefaultValue(OctaveTranspose1)),
octaveTranspose2((int)getDefaultValue(OctaveTranspose2)),
+ semiTones1((int)getDefaultValue(SemiTones1)),
+ semiTones2((int)getDefaultValue(SemiTones2)),
detune1(getDefaultValue(Detune1)),
detune2(getDefaultValue(Detune2)),
pan1(getDefaultValue(Pan1)),
@@ -68,10 +70,12 @@ WaveSynth::WaveSynth(MainController *mc, const String &id, int numVoices) :
scaleFunction = [](float input) { return input * 2.0f - 1.0f; };
parameterNames.add("OctaveTranspose1");
+ parameterNames.add("SemiTones1");
parameterNames.add("WaveForm1");
parameterNames.add("Detune1");
parameterNames.add("Pan1");
parameterNames.add("OctaveTranspose2");
+ parameterNames.add("SemiTones2");
parameterNames.add("WaveForm2");
parameterNames.add("Detune2");
parameterNames.add("Pan2");
@@ -91,7 +95,7 @@ WaveSynth::WaveSynth(MainController *mc, const String &id, int numVoices) :
for (int i = 0; i < numVoices; i++)
addVoice(new WaveSynthVoice(this));
-
+
addSound(new WaveSound());
}
@@ -100,7 +104,9 @@ void WaveSynth::restoreFromValueTree(const ValueTree &v)
ModulatorSynth::restoreFromValueTree(v);
loadAttribute(OctaveTranspose1, "OctaveTranspose1");
+ loadAttribute(SemiTones1, "SemiTones1");
loadAttribute(OctaveTranspose2, "OctaveTranspose2");
+ loadAttribute(SemiTones2, "SemiTones2");
loadAttribute(Detune1, "Detune1");
loadAttribute(Detune2, "Detune2");
loadAttribute(WaveForm1, "WaveForm1");
@@ -119,7 +125,9 @@ ValueTree WaveSynth::exportAsValueTree() const
ValueTree v = ModulatorSynth::exportAsValueTree();
saveAttribute(OctaveTranspose1, "OctaveTranspose1");
+ saveAttribute(SemiTones1, "SemiTones1");
saveAttribute(OctaveTranspose2, "OctaveTranspose2");
+ saveAttribute(SemiTones2, "SemiTones2");
saveAttribute(Detune1, "Detune1");
saveAttribute(Detune2, "Detune2");
saveAttribute(WaveForm1, "WaveForm1");
@@ -174,10 +182,12 @@ float WaveSynth::getDefaultValue(int parameterIndex) const
switch (parameterIndex)
{
case OctaveTranspose1: return 0.0f;
+ case SemiTones1: return 0.0f;
case WaveForm1: return (float)WaveformComponent::WaveformType::Saw;
case Detune1: return 0.0f;
case Pan1: return 0.0f;
case OctaveTranspose2: return 0.0f;
+ case SemiTones2: return 0.0f;
case WaveForm2: return (float)WaveformComponent::WaveformType::Saw;
case Detune2: return 0.0f;
case Pan2: return 0.0f;
@@ -229,10 +239,12 @@ float WaveSynth::getAttribute(int parameterIndex) const
switch (parameterIndex)
{
case OctaveTranspose1: return (float)octaveTranspose1;
+ case SemiTones1: return (float)semiTones1;
case WaveForm1: return (float)waveForm1;
case Detune1: return detune1;
case Pan1: return pan1;
case OctaveTranspose2: return (float)octaveTranspose2;
+ case SemiTones2: return (float)semiTones2;
case WaveForm2: return (float)waveForm2;
case Detune2: return detune2;
case Pan2: return pan2;
@@ -258,9 +270,15 @@ void WaveSynth::setInternalAttribute(int parameterIndex, float newValue)
case OctaveTranspose1: octaveTranspose1 = (int)newValue;
refreshPitchValues(true);
break;
+ case SemiTones1: semiTones1 = (int)newValue;
+ refreshPitchValues(true);
+ break;
case OctaveTranspose2: octaveTranspose2 = (int)newValue;
refreshPitchValues(false);
break;
+ case SemiTones2: semiTones2 = (int)newValue;
+ refreshPitchValues(false);
+ break;
case Detune1: detune1 = newValue;
refreshPitchValues(true);
break;
@@ -331,11 +349,11 @@ void WaveSynth::refreshPulseWidth(bool left)
double WaveSynth::getPitchValue(bool getLeftValue)
{
- const double octaveValue = pow(2.0, (double)getLeftValue ? octaveTranspose1 : octaveTranspose2);
-
+ const double octaveValue = pow(2.0, (double)(getLeftValue ? octaveTranspose1 : octaveTranspose2));
+ const double semiToneValue = pow(2.0, (double)(getLeftValue ? semiTones1 : semiTones2) / 12.0);
const double detuneValue = pow(2.0, (getLeftValue ? detune1 : detune2) / 1200.0);
- return octaveValue * detuneValue;
+ return octaveValue * semiToneValue * detuneValue;
}
@@ -358,7 +376,7 @@ WaveSynthVoice::WaveSynthVoice(ModulatorSynth *ownerSynth) :
#else
octaveTransposeFactor2(1.0)
#endif
-
+
{
setWaveForm(WaveformComponent::Saw, true);
setWaveForm(WaveformComponent::Saw, false);
@@ -388,7 +406,7 @@ void WaveSynthVoice::startNote(int midiNoteNumber, float /*velocity*/, Synthesis
rightGenerator.setFrequency(cyclesPerSecond * octaveTransposeFactor2);
leftGenerator.setStartOffset((double)getCurrentHiseEvent().getStartOffset());
-
+
if(enableSecondOsc)
rightGenerator.setStartOffset((double)getCurrentHiseEvent().getStartOffset());
@@ -464,18 +482,18 @@ void WaveSynthVoice::calculateBlock(int startSample, int numSamples)
while (--numSamples >= 0)
{
auto leftDelta = (float)uptimeDelta;
-
+
if (voicePitchValues != nullptr)
leftDelta *= *voicePitchValues;
leftGenerator.setFreqModulationValue(leftDelta);
-
+
auto rightDelta = (float)uptimeDelta;
-
+
if (voicePitchValues != nullptr)
rightDelta *= *voicePitchValues;
-
+
if (secondPitchValues != nullptr)
rightDelta *= *secondPitchValues;
@@ -511,7 +529,7 @@ void WaveSynthVoice::calculateBlock(int startSample, int numSamples)
leftGenerator.setFreqModulationValue(leftDelta);
-
+
voicePitchValues++;
*outL = leftGenerator.getAndInc();
@@ -520,9 +538,9 @@ void WaveSynthVoice::calculateBlock(int startSample, int numSamples)
}
}
-
+
-
+
#else
@@ -559,7 +577,7 @@ void WaveSynthVoice::calculateBlock(int startSample, int numSamples)
#endif
-
+
#if HISE_USE_WRONG_VOICE_RENDERING_ORDER
getOwnerSynth()->effectChain->renderVoice(voiceIndex, voiceBuffer, startIndex, samplesToCopy);
@@ -572,7 +590,7 @@ void WaveSynthVoice::calculateBlock(int startSample, int numSamples)
auto leftSamples = voiceBuffer.getWritePointer(0, startIndex);
auto rightSamples = voiceBuffer.getWritePointer(1, startIndex);
-
+
auto& tBuffer = wavesynth->getTempBufferForMixCalculation();
@@ -641,7 +659,7 @@ void WaveSynthVoice::setWaveForm(WaveformComponent::WaveformType type, bool left
{
switch ((int)type)
{
- case hise::WaveformComponent::Sine:
+ case hise::WaveformComponent::Sine:
left ? leftGenerator.setWaveform(mf::PolyBLEP::SINE) : rightGenerator.setWaveform(mf::PolyBLEP::SINE); break;
case hise::WaveformComponent::Triangle:
left ? leftGenerator.setWaveform(mf::PolyBLEP::TRIANGLE) : rightGenerator.setWaveform(mf::PolyBLEP::TRIANGLE); break;
@@ -663,7 +681,7 @@ void WaveSynthVoice::setWaveForm(WaveformComponent::WaveformType type, bool left
break;
}
-
+
}
diff --git a/hi_core/hi_modules/synthesisers/synths/WaveSynth.h b/hi_core/hi_modules/synthesisers/synths/WaveSynth.h
index b36893f2f1..ff680feb02 100644
--- a/hi_core/hi_modules/synthesisers/synths/WaveSynth.h
+++ b/hi_core/hi_modules/synthesisers/synths/WaveSynth.h
@@ -103,7 +103,7 @@ class WaveSynthVoice: public ModulatorSynthVoice
{
return noiseGenerator.nextFloat();
}
-
+
static float getPulse(double voiceUptime, double uptimeDelta)
{
const double pulseWidth = 0.5;
@@ -116,7 +116,7 @@ class WaveSynthVoice: public ModulatorSynthVoice
const double phase = fmod(voiceUptime, 1.0) * 1024.0;
int index = (int)phase;
-
+
float v1 = sinTable[index & 2047];
float v2 = sinTable[(index +1) & 2047];
@@ -128,7 +128,7 @@ class WaveSynthVoice: public ModulatorSynthVoice
return currentSample;
}
- static float getBoxFilteredSaw(double phase, double kernelSize)
+ static float getBoxFilteredSaw(double phase, double kernelSize)
{
double a, b;
@@ -232,6 +232,8 @@ class WaveSynth: public ModulatorSynth,
PulseWidth1, ///< 0 ... **1** | Determines the first pulse width for waveforms that support this (eg. square)
PulseWidth2, ///< 0 ... **1** | Determines the second pulse width for waveforms that support this (eg. square)
HardSync, ///< **Off** ... On | Syncs the second oscillator to the first
+ SemiTones1, ///< -12 ... **0** ... 12 | The semitone transpose amount for the first Oscillator.
+ SemiTones2, ///< -12 ... **0** ... 12 | The semitone transpose amount for the second Oscillator.
numWaveSynthParameters
};
@@ -256,7 +258,7 @@ class WaveSynth: public ModulatorSynth,
const Processor *getChildProcessor(int processorIndex) const override;
-
+
float getDefaultValue(int parameterIndex) const override;;
void getWaveformTableValues(int displayIndex, float const** tableValues, int& numValues, float& normalizeValue) override;
@@ -327,6 +329,7 @@ class WaveSynth: public ModulatorSynth,
AudioSampleBuffer tempBuffer;
int octaveTranspose1, octaveTranspose2;
+ int semiTones1, semiTones2;
float mix;