Skip to content

Commit

Permalink
Update GlitchSprinkler (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
ryukau committed Jul 20, 2024
1 parent 61cf23e commit 40bfc76
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 53 deletions.
96 changes: 69 additions & 27 deletions GlitchSprinkler/source/dsp/dspcore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,14 +368,16 @@ double getPitchRatioFromArray(
}

inline double
getPitchRatio(int semitone, int rootShift, double octave, double cent, Tuning tuning)
getPitchRatio(int semitone, int rootShift, double octave, double cent, Tuning tuningIndex)
{
switch (tuning) {
switch (tuningIndex) {
default:
case Tuning::et12:
return getPitchRatioFromArray(semitone, rootShift, octave, cent, tuningRatioEt12);
case Tuning::et5:
return getPitchRatioFromArray(semitone, rootShift, octave, cent, tuningRatioEt5);
case Tuning::et10:
return getPitchRatioFromArray(semitone, rootShift, octave, cent, tuningRatioEt10);
case Tuning::just5Major:
return getPitchRatioFromArray(
semitone, rootShift, octave, cent, tuningRatioJust5Major);
Expand All @@ -384,17 +386,49 @@ getPitchRatio(int semitone, int rootShift, double octave, double cent, Tuning tu
semitone, rootShift, octave, cent, tuningRatioJust5Minor);
case Tuning::just7:
return getPitchRatioFromArray(semitone, rootShift, octave, cent, tuningRatioJust7);
case Tuning::mtPythagorean:
return getPitchRatioFromArray(
semitone, rootShift, octave, cent, tuningRatioMtPythagorean);
case Tuning::mtThirdComma:
return getPitchRatioFromArray(
semitone, rootShift, octave, cent, tuningRatioMtThirdComma);
case Tuning::mtQuarterComma:
return getPitchRatioFromArray(
semitone, rootShift, octave, cent, tuningRatioMtQuarterComma);
}
// Shouldn't reach here.
}

template<typename Rng, typename Scale, typename Tuning>
inline double getRandomPitch(Rng &rng, const Scale &scale, const Tuning &tuning)
inline double getRandomPitchFixed(Rng &rng, const Scale &scale, const Tuning &tuningTable)
{
std::uniform_int_distribution<size_t> indexDist{0, scale.size() - 1};
const size_t index = scale[indexDist(rng)];
const size_t octave = size_t(1) << (index / tuning.size());
return octave * tuning[index % tuning.size()];
const size_t octave = size_t(1) << (index / tuningTable.size());
return octave * tuningTable[index % tuningTable.size()];
}

template<typename Rng, typename Scale>
inline double getRandomPitch(Rng &rng, const Scale &scale, const Tuning tuningIndex)
{
switch (tuningIndex) {
default:
case Tuning::et12:
return getRandomPitchFixed(rng, scale, tuningRatioEt12);
case Tuning::just5Major:
return getRandomPitchFixed(rng, scale, tuningRatioJust5Major);
case Tuning::just5Minor:
return getRandomPitchFixed(rng, scale, tuningRatioJust5Minor);
case Tuning::just7:
return getRandomPitchFixed(rng, scale, tuningRatioJust7);
case Tuning::mtPythagorean:
return getRandomPitchFixed(rng, scale, tuningRatioMtPythagorean);
case Tuning::mtThirdComma:
return getRandomPitchFixed(rng, scale, tuningRatioMtThirdComma);
case Tuning::mtQuarterComma:
return getRandomPitchFixed(rng, scale, tuningRatioMtQuarterComma);
}
// Shouldn't reach here.
}

void Voice::updateNote()
Expand Down Expand Up @@ -473,41 +507,41 @@ void Voice::updateNote()
if (arpeggioTimer != 0 || arpeggioLoopCounter != 0) {
const auto arpeggioScale = pv[ID::arpeggioScale]->getInt();
if (arpeggioScale == PitchScale::et5Chromatic) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt5, tuningRatioEt5);
arpRatio *= getRandomPitchFixed(rngArpeggio, scaleEt5, tuningRatioEt5);
} else if (arpeggioScale == PitchScale::et12ChurchC) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchC, tuningRatioJust5Major);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchC, tuning);
} else if (arpeggioScale == PitchScale::et12ChurchD) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchD, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchD, tuning);
} else if (arpeggioScale == PitchScale::et12ChurchE) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchE, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchE, tuning);
} else if (arpeggioScale == PitchScale::et12ChurchF) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchF, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchF, tuning);
} else if (arpeggioScale == PitchScale::et12ChurchG) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchG, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchG, tuning);
} else if (arpeggioScale == PitchScale::et12ChurchA) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchA, tuningRatioJust5Minor);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchA, tuning);
} else if (arpeggioScale == PitchScale::et12ChurchB) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchB, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12ChurchB, tuning);
} else if (arpeggioScale == PitchScale::et12Sus2) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12Sus2, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12Sus2, tuning);
} else if (arpeggioScale == PitchScale::et12Sus4) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12Sus4, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12Sus4, tuning);
} else if (arpeggioScale == PitchScale::et12Maj7) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12Maj7, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12Maj7, tuning);
} else if (arpeggioScale == PitchScale::et12Min7) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12Min7, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12Min7, tuning);
} else if (arpeggioScale == PitchScale::et12MajExtended) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12MajExtended, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12MajExtended, tuning);
} else if (arpeggioScale == PitchScale::et12MinExtended) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12MinExtended, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12MinExtended, tuning);
} else if (arpeggioScale == PitchScale::et12WholeTone2) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12WholeTone2, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12WholeTone2, tuning);
} else if (arpeggioScale == PitchScale::et12WholeTone3) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12WholeTone3, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12WholeTone3, tuning);
} else if (arpeggioScale == PitchScale::et12WholeTone4) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12WholeTone4, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12WholeTone4, tuning);
} else if (arpeggioScale == PitchScale::et12Blues) {
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12Blues, tuningRatioEt12);
arpRatio *= getRandomPitch(rngArpeggio, scaleEt12Blues, tuning);
} else if (arpeggioScale == PitchScale::overtone32) {
std::uniform_int_distribution<int> dist{1, 32};
arpRatio *= double(dist(rngArpeggio));
Expand Down Expand Up @@ -565,14 +599,22 @@ void Voice::updateNote()
// Filter.
if (pv[ID::filterSwitch]->getInt()) {
const auto cutoffBaseOctave = pv[ID::filterCutoffBaseOctave]->getDouble();
const auto cutoffModOctave = pv[ID::filterCutoffBaseOctave]->getDouble();
cutoffBase = std::clamp(
freqHz / core.sampleRate * std::exp2(cutoffBaseOctave), double(0), double(0.4999));
const auto cutoffKeyFollow = pv[ID::filterCutoffKeyFollow]->getDouble();
const auto baseFreq
= std::lerp(double(20), freqHz, cutoffKeyFollow) / core.sampleRate;
cutoffBase
= std::clamp(baseFreq * std::exp2(cutoffBaseOctave), double(0), double(0.4999));

const auto cutoffModOctave = pv[ID::filterCutoffModOctave]->getDouble();
cutoffMod = cutoffModOctave <= Scales::filterCutoffModOctave.getMin()
? double(0)
: std::min(cutoffBase * std::exp2(cutoffModOctave), double(0.4999) - cutoffBase);
: std::clamp(
cutoffBase * std::exp2(cutoffModOctave), double(0),
double(0.4999) - cutoffBase);

resonanceBase = pv[ID::filterResonanceBase]->getDouble();
resonanceMod = pv[ID::filterResonanceMod]->getDouble() * (double(1) - resonanceBase);

notchBase = std::exp2(pv[ID::filterNotchBaseOctave]->getDouble());
const auto notchModOctave = std::exp2(pv[ID::filterNotchModOctave]->getDouble());
notchMod = notchModOctave <= Scales::filterNotchModOctave.getMin()
Expand Down
2 changes: 1 addition & 1 deletion GlitchSprinkler/source/dsp/polynomial.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ template<typename Sample> class ResonantEmaLowpass1A1 {
constexpr Sample pi = std::numbers::pi_v<Sample>;
const auto freq = pi * std::clamp(cutValue, Sample(0), Sample(0.4999));

const auto s = 1 - std::cos(Sample(2) * freq);
const auto s = Sample(1) - std::cos(Sample(2) * freq);
const auto c1 = std::sqrt(s * s + Sample(2) * s) - s;

apsValue += interpRate * (apScale - apsValue);
Expand Down
76 changes: 69 additions & 7 deletions GlitchSprinkler/source/dsp/tuning.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
/*
This file can be shorter if the compiler supports C++26. C++26 provides constexpr
everywhere for <cmath>.
- ET or Et : Equal temperament.
- MT or Mt : Meantone temperament.
- Just : Just intonation.
*/

#pragma once
Expand Down Expand Up @@ -54,7 +58,7 @@ std::array<size_t, 6> scaleEt12Blues{0, 3, 5, 6, 7, 10};

/**
```javascript
var cents = [0, 1, 240, 241, 400, 480, 481, 720, 721, 900, 960, 961];
var cents = [0, 0, 240, 240, 400, 480, 480, 720, 720, 900, 960, 960];
console.log(cents.map(v => 2**(v / 1200)));
```
*/
Expand All @@ -74,12 +78,20 @@ std::array<double, 12> tuningRatioEt5{
};
std::array<size_t, 5> scaleEt5{0, 2, 5, 7, 10};

// cents = [0, 120, 240, 300, 360, 480, 600, 720, 840, 960, 1020, 1080];
std::array<double, 12> tuningRatioEt10Minor{
double(1.0000000000000), double(1.0717734625362931), double(1.148698354997035),
double(1.189207115002721), double(1.2311444133449163), double(1.3195079107728942),
double(1.4142135623730951), double(1.515716566510398), double(1.624504792712471),
double(1.7411011265922482), double(1.8025009252216604), double(1.8660659830736148),
// cents = [0, 120, 240, 300, 360, 480, 600, 720, 840, 900, 960, 1080];
std::array<double, 12> tuningRatioEt10{
double(1), // 0: 0
double(1.0717734625362931), // 1: 120
double(1.148698354997035), // 2: 240
double(1.189207115002721), // 3: 300
double(1.2311444133449163), // 4: 360
double(1.3195079107728942), // 5: 480
double(1.4142135623730951), // 6: 600
double(1.515716566510398), // 7: 720
double(1.624504792712471), // 8: 840
double(1.681792830507429), // 9: 900
double(1.7411011265922482), // 10: 960
double(1.8660659830736148), // 11: 1080
};

std::array<double, 12> tuningRatioJust5Major{
Expand All @@ -104,4 +116,54 @@ std::array<double, 13> tuningRatioJust7{
double(7) / double(4),
};

std::array<double, 12> tuningRatioMtPythagorean{
double(1) / double(1), // 0:
double(256) / double(243), // 1:
double(9) / double(8), // 2:
double(32) / double(27), // 3:
double(81) / double(64), // 4:
double(4) / double(3), // 5:
// double(1024) / double(729), // 6: pairs with 1.
double(729) / double(512), // 6: pairs with 11.
double(3) / double(2), // 7:
double(128) / double(81), // 8:
double(27) / double(16), // 9:
double(16) / double(9), // 10:
double(243) / double(128), // 11:
};

// Commented numbers indicate pitches in 12 ET semitone.
std::array<double, 12> tuningRatioMtThirdComma{
double(1.00000000000000), // 0.00000000000000
double(1.07553713917372), // 1.26068811667588
double(1.11572158347028), // 1.89572475332965
double(1.20000000000000), // 3.15641287000552
double(1.24483465182143), // 3.79144950665930
double(1.33886590016434), // 5.05213762333518
// double(1.38888888888889), // 5.68717425998895
double(1.44000000000000), // 6.31282574001105
double(1.49380158218572), // 6.94786237666482
double(1.60663908019721), // 8.20855049334070
double(1.66666666666667), // 8.84358712999448
double(1.79256189862287), // 10.10427524667035
double(1.85953597245047), // 10.73931188332413
};

// Commented numbers indicate pitches in 12 ET semitone.
std::array<double, 12> tuningRatioMtQuarterComma{
double(1.00000000000000), // 0.00000000000000
double(1.06998448796228), // 1.17107857668956
double(1.11803398874989), // 1.93156856932417
double(1.19627902497698), // 3.10264714601374
double(1.25000000000000), // 3.86313713864835
double(1.33748060995284), // 5.03421571533791
// double(1.39754248593737), // 5.79470570797252
double(1.43108350559987), // 6.20529429202748
double(1.49534878122122), // 6.96578428466209
double(1.60000000000000), // 8.13686286135165
double(1.67185076244106), // 8.89735285398626
double(1.78885438199983), // 10.06843143067583
double(1.86918597652653), // 10.82892142331043
};

} // namespace SomeDSP
34 changes: 20 additions & 14 deletions GlitchSprinkler/source/editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,9 @@ bool Editor::prepareUI()

addLabel(mixLeft0, mixTop8, labelWidth, labelHeight, uiTextSize, "Tuning");
std::vector<std::string> tuningItems{
"ET 12", "ET 5", "Just 5 Major", "Just 5 Minor", "Just 7",
"Discrete 2", "Discrete 3", "Discrete 5", "Discrete 7",
"ET 12", "ET 5", "ET 10", "Just 5 Major", "Just 5 Minor",
"Just 7", "MT Pythagorean", "MT 1/3 Comma", "MT 1/4 Comma", "Discrete 2",
"Discrete 3", "Discrete 5", "Discrete 7",
};
for (size_t idx = tuningItems.size(); idx <= Scales::tuningType.getMax(); ++idx) {
tuningItems.push_back("- Reserved " + std::to_string(idx) + " -");
Expand All @@ -151,12 +152,13 @@ bool Editor::prepareUI()

// Filter.
constexpr auto filterLabelWidth = 100.0f;
constexpr auto filterTop0 = mixTop12 + labelY;
constexpr auto filterTop0 = mixTop11 + labelY;
constexpr auto filterTop1 = filterTop0 + 1 * labelY;
constexpr auto filterTop2 = filterTop0 + 2 * labelY;
constexpr auto filterTop3 = filterTop0 + 3 * labelY;
constexpr auto filterTop4 = filterTop0 + 4 * labelY;
constexpr auto filterTop5 = filterTop0 + 5 * labelY;
constexpr auto filterTop6 = filterTop0 + 6 * labelY;
constexpr auto filterLeft0 = left0;
constexpr auto filterLeft1 = filterLeft0 + 1 * filterLabelWidth + 3 * margin;
constexpr auto filterLeft2 = filterLeft0 + 2 * filterLabelWidth + 6 * margin;
Expand All @@ -169,36 +171,40 @@ bool Editor::prepareUI()
addTextKnob(
filterLeft0 + labelWidth + 2 * margin, filterTop1, labelWidth, labelHeight,
uiTextSize, ID::filterDecayRatio, Scales::filterDecayRatio, false, 5);
addLabel(filterLeft0, filterTop2, labelWidth, labelHeight, uiTextSize, "Key Follow");
addTextKnob(
filterLeft0 + labelWidth + 2 * margin, filterTop2, labelWidth, labelHeight,
uiTextSize, ID::filterCutoffKeyFollow, Scales::defaultScale, false, 5);

addLabel(filterLeft1, filterTop2, filterLabelWidth, labelHeight, uiTextSize, "Base");
addLabel(filterLeft1, filterTop3, filterLabelWidth, labelHeight, uiTextSize, "Base");
addLabel(
filterLeft2, filterTop2, filterLabelWidth, labelHeight, uiTextSize, "Env. Mod");
filterLeft2, filterTop3, filterLabelWidth, labelHeight, uiTextSize, "Env. Mod");

addLabel(
filterLeft0, filterTop3, filterLabelWidth, labelHeight, uiTextSize, "Cutoff [oct.]");
filterLeft0, filterTop4, filterLabelWidth, labelHeight, uiTextSize, "Cutoff [oct.]");
addTextKnob(
filterLeft1, filterTop3, filterLabelWidth, labelHeight, uiTextSize,
filterLeft1, filterTop4, filterLabelWidth, labelHeight, uiTextSize,
ID::filterCutoffBaseOctave, Scales::filterCutoffBaseOctave, false, 5);
addTextKnob(
filterLeft2, filterTop3, filterLabelWidth, labelHeight, uiTextSize,
filterLeft2, filterTop4, filterLabelWidth, labelHeight, uiTextSize,
ID::filterCutoffModOctave, Scales::filterCutoffModOctave, false, 5);

addLabel(
filterLeft0, filterTop4, filterLabelWidth, labelHeight, uiTextSize, "Resonance");
filterLeft0, filterTop5, filterLabelWidth, labelHeight, uiTextSize, "Resonance");
addTextKnob(
filterLeft1, filterTop4, filterLabelWidth, labelHeight, uiTextSize,
filterLeft1, filterTop5, filterLabelWidth, labelHeight, uiTextSize,
ID::filterResonanceBase, Scales::defaultScale, false, 5);
addTextKnob(
filterLeft2, filterTop4, filterLabelWidth, labelHeight, uiTextSize,
filterLeft2, filterTop5, filterLabelWidth, labelHeight, uiTextSize,
ID::filterResonanceMod, Scales::defaultScale, false, 5);

addLabel(
filterLeft0, filterTop5, filterLabelWidth, labelHeight, uiTextSize, "Notch [oct.]");
filterLeft0, filterTop6, filterLabelWidth, labelHeight, uiTextSize, "Notch [oct.]");
addTextKnob(
filterLeft1, filterTop5, filterLabelWidth, labelHeight, uiTextSize,
filterLeft1, filterTop6, filterLabelWidth, labelHeight, uiTextSize,
ID::filterNotchBaseOctave, Scales::filterNotchBaseOctave, false, 5);
addTextKnob(
filterLeft2, filterTop5, filterLabelWidth, labelHeight, uiTextSize,
filterLeft2, filterTop6, filterLabelWidth, labelHeight, uiTextSize,
ID::filterNotchModOctave, Scales::filterNotchModOctave, false, 5);

// Waveform.
Expand Down
4 changes: 2 additions & 2 deletions GlitchSprinkler/source/parameter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ DecibelScale<double> Scales::fmIndex(-60.0, 40.0, true);
LinearScale<double> Scales::randomizeFmIndex(0.0, 4.0);

LinearScale<double> Scales::filterDecayRatio(-10.0, 10.0);
LinearScale<double> Scales::filterCutoffBaseOctave(0.0, 10.0);
LinearScale<double> Scales::filterCutoffModOctave(-10, 10);
LinearScale<double> Scales::filterCutoffBaseOctave(-8.0, 16.0);
LinearScale<double> Scales::filterCutoffModOctave(-16, 16);
LinearScale<double> Scales::filterNotchBaseOctave(-4, 4);
LinearScale<double> Scales::filterNotchModOctave(-4, 4);

Expand Down
10 changes: 8 additions & 2 deletions GlitchSprinkler/source/parameter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@ namespace Synth {
enum Tuning : uint32_t {
et12,
et5,
// et10Major, // TODO
// et10Minor, // TODO
et10,
just5Major,
just5Minor,
just7,
mtPythagorean,
mtThirdComma,
mtQuarterComma,
discrete2,
discrete3,
discrete5,
Expand Down Expand Up @@ -110,6 +112,7 @@ enum ID {

filterSwitch,
filterDecayRatio,
filterCutoffKeyFollow,
filterCutoffBaseOctave,
filterCutoffModOctave,
filterResonanceBase,
Expand Down Expand Up @@ -239,6 +242,9 @@ struct GlobalParameter : public ParameterInterface {
value[ID::filterDecayRatio] = std::make_unique<LinearValue>(
Scales::filterDecayRatio.invmap(0.0), Scales::filterDecayRatio, "filterDecayRatio",
Info::kCanAutomate);
value[ID::filterCutoffKeyFollow] = std::make_unique<LinearValue>(
Scales::defaultScale.invmap(1.0), Scales::defaultScale, "filterCutoffKeyFollow",
Info::kCanAutomate);
value[ID::filterCutoffBaseOctave] = std::make_unique<LinearValue>(
Scales::filterCutoffBaseOctave.invmap(0.0), Scales::filterCutoffBaseOctave,
"filterCutoffBaseOctave", Info::kCanAutomate);
Expand Down

0 comments on commit 40bfc76

Please sign in to comment.