Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
e7bd8df
remove locks in juce::Syntesiser
vberthiaume Nov 16, 2025
3f10c69
add comment on osc.initialize. Some faffing in the .vscode config fil…
vberthiaume Nov 17, 2025
7a88a1f
remove osc init from audio thread
vberthiaume Nov 17, 2025
56fe364
faff
vberthiaume Nov 17, 2025
dfff46b
farbot
vberthiaume Nov 17, 2025
fd8d186
attempt
vberthiaume Nov 18, 2025
48ab8fb
building
vberthiaume Nov 18, 2025
d513263
make curSelection atomic
vberthiaume Nov 18, 2025
6e49826
json
vberthiaume Nov 19, 2025
8af75c8
wip -- attempt to use CRTP for the Selection class [skip ci]
vberthiaume Nov 19, 2025
b3c7a0c
cleanup json [skip ci]
vberthiaume Nov 19, 2025
bb74891
remove CRTP stuff
vberthiaume Nov 21, 2025
b054c36
start the array of lfos [skip ci]
vberthiaume Nov 27, 2025
37b9e1f
wip
vberthiaume Nov 27, 2025
21e4758
more wip -- not sure about this at all lol
vberthiaume Nov 27, 2025
1cb0b07
bring the useful bits from the locksNeedsRebase branch
vberthiaume Nov 28, 2025
af314e8
building
vberthiaume Dec 1, 2025
2e08358
fixing build and some warnings
vberthiaume Dec 2, 2025
efe6ceb
cleanup, only missing random lfo init
vberthiaume Dec 7, 2025
869a152
comment
vberthiaume Dec 7, 2025
f64461d
cleanup. builds but asserts at runtime -- actually need to swap them …
vberthiaume Dec 7, 2025
3854691
put logic in to change the lfo shape, but somehow we always get shape…
vberthiaume Dec 7, 2025
a566999
cleanup and don't make the lfo random a table, just call the lambda. …
vberthiaume Dec 7, 2025
cb21d93
comment
vberthiaume Dec 8, 2025
c9af456
wip - building not running [skip ci]
vberthiaume Dec 8, 2025
a21f156
cleanup
vberthiaume Dec 9, 2025
1fc19db
remove processor chain
vberthiaume Dec 9, 2025
63210b6
remove updateOscillators. We can run but get an assert when changing …
vberthiaume Dec 9, 2025
f0a9c62
fix assert
vberthiaume Dec 12, 2025
95f7438
cleanup and made sure the noise osc logic was sound 🚀
vberthiaume Dec 12, 2025
c066ca0
create lock free synth
vberthiaume Dec 15, 2025
bd9b750
cmake cleanup
vberthiaume Dec 15, 2025
cef83be
update juce
vberthiaume Dec 15, 2025
9255f54
actually use the lock free synth lol
vberthiaume Dec 15, 2025
ef012dc
comment
vberthiaume Dec 16, 2025
cd043bc
build
vberthiaume Dec 16, 2025
796c05f
build
vberthiaume Dec 16, 2025
83dd6a4
build
vberthiaume Dec 16, 2025
b7a53a8
build
vberthiaume Dec 16, 2025
395ba1b
build
vberthiaume Dec 16, 2025
7f2fd4b
build
vberthiaume Dec 16, 2025
a5b58ce
cleanup
vberthiaume Dec 16, 2025
3c4ee38
cleanup
vberthiaume Dec 16, 2025
43b4b01
building
vberthiaume Dec 16, 2025
686b2a8
cleanup
vberthiaume Dec 16, 2025
ceacc47
cleanup
vberthiaume Dec 16, 2025
e946253
cleanup -- also pulse is the same wave as sawd
vberthiaume Dec 19, 2025
1198c18
fix pulse
vberthiaume Dec 22, 2025
7716b90
building
vberthiaume Dec 22, 2025
c265301
cleanup
vberthiaume Dec 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,24 @@
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch - Linux",
"name": "Launch Reaper Linux",
"type": "cppdbg",
"request": "launch",
"program": "/usr/local/bin/reaper",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"preLaunchTask": "ProPhat CMake Configure and Debug Build"
},
{
"name": "Launch Prophat Linux",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/Builds/ProPhat_artefacts/Debug/Standalone/ProPhat",
// "program": "/usr/local/bin/reaper",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
Expand All @@ -17,7 +30,7 @@
"preLaunchTask": "ProPhat CMake Configure and Debug Build"
},
{
"name": "(lldb) Launch",
"name": "Launch Prophat Mac",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/Builds/ProPhat_artefacts/Debug/Standalone/ProPhat.app",
Expand All @@ -29,7 +42,7 @@
"MIMode": "lldb"
},
{
"name": "(gdb) Launch - Windows",
"name": "Launch Prophat Windows",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}\\Builds\\ProPhat_artefacts\\Debug\\Standalone\\ProPhat.exe",
Expand All @@ -42,15 +55,27 @@
"miDebuggerPath": "C:\\path\\to\\gdb.exe"
},
{
"name": "Debug Catch2 Tests",
"name": "Launch Catch2 Tests Mac",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/Builds/Tests",
"args": [],
"cwd": "${workspaceFolder}/Builds",
"stopAtEntry": false,
"environment": [],
"MIMode": "lldb", // use "gdb" on Linux if preferred
"MIMode": "lldb",
"preLaunchTask": "Build and Debug Tests"
},
{
"name": "Launch Catch2 Tests Mac",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/Builds/Tests",
"args": [],
"cwd": "${workspaceFolder}/Builds",
"stopAtEntry": false,
"environment": [],
"MIMode": "gdb",
"preLaunchTask": "Build and Debug Tests"
}
]
Expand Down
14 changes: 7 additions & 7 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
"args": [
"-B",
"Builds",
"-G",
"Ninja",
"-DCMAKE_BUILD_TYPE=Debug",
"-DCMAKE_C_COMPILER_LAUNCHER=sccache",
"-DCMAKE_CXX_COMPILER_LAUNCHER=sccache",
"-DFORMATS=Standalone", //change this to allow for other builds, e.g., -DFORMATS="Standalone;AU;VST3;AUv3"
// "-G",
// "Ninja",
// "-DCMAKE_BUILD_TYPE=Debug",
// "-DCMAKE_C_COMPILER_LAUNCHER=sccache",
// "-DCMAKE_CXX_COMPILER_LAUNCHER=sccache",
"-DFORMATS=VST3", //change this to allow for other builds, e.g., -DFORMATS="Standalone;AU;VST3;AUv3"
"."
],
"group": {
Expand Down Expand Up @@ -67,7 +67,7 @@
"command": "bash",
"args": [
"-c",
"cmake --build Builds -j8 --config Release"
"cmake --build Builds -j`nproc` --config Release"
],
"dependsOn": [
"CMake: Configure (Release)"
Expand Down
2 changes: 1 addition & 1 deletion JUCE
Submodule JUCE updated 337 files
2 changes: 1 addition & 1 deletion modules/farbot
Submodule farbot updated 1 files
+2 −2 CMakeLists.txt
190 changes: 75 additions & 115 deletions source/DSP/GainedOscillator.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,31 @@ class GainedOscillator
GainedOscillator () :
distribution ((T) -1, (T) 1)
{
//TODO: I should compare these waves on the scope with the waves from the prophet
oscs[OscShape::none].initialise ([] (T /*x*/) { return T (0); });
oscs[OscShape::saw].initialise ([] (T x) { return juce::jmap (x, T (-juce::MathConstants<T>::pi), T (juce::MathConstants<T>::pi), T (-1), T (1)); }, 2);

oscs[OscShape::sawTri].initialise ([] (T x)
{
T y = juce::jmap (x, T (-juce::MathConstants<T>::pi), T (juce::MathConstants<T>::pi), T (-1), T (1)) / 2;

if (x < 0)
return y += juce::jmap (x, T (-juce::MathConstants<T>::pi), T (0), T (-1), T (1)) / 2;
else
return y += juce::jmap (x, T (0), T (juce::MathConstants<T>::pi), T (1), T (-1)) / 2;
}, 128);

oscs[OscShape::triangle].initialise ([] (T x)
{
if (x < 0)
return juce::jmap (x, T (-juce::MathConstants<T>::pi), T (0), T (-1), T (1));
else
return juce::jmap (x, T (0), T (juce::MathConstants<T>::pi), T (1), T (-1));
}, 128);

oscs[OscShape::pulse].initialise ([] (T x) { if (x < 0) return T (-1); else return T (1); }, 16);
oscs[OscShape::noise].initialise ([this] (T /*x*/) { return distribution (generator); });

setOscShape (OscShape::saw);
setGain (Constants::defaultOscLevel);
}
Expand All @@ -39,11 +64,44 @@ class GainedOscillator
{
jassert (newValue > 0);

auto& osc = processorChain.template get<oscIndex> ();
osc.setFrequency (newValue, force);
curOsc.load()->setFrequency (newValue, force);
}

void setOscShape (OscShape::Values newShape) { nextOsc.store (newShape); }
void setOscShape (OscShape::Values newShape)
{
//TODO: AFAICT we never get in here so probably useless?
// Early-out if the requested shape is already selected.
auto* currentPtr = curOsc.load();
auto* requestedPtr = &oscs[static_cast<std::size_t> (newShape)];
if (currentPtr == requestedPtr)
return;

//this is to make sure we preserve the same gain after we re-init, right?
bool wasActive = isActive;
isActive = true;

if (newShape == OscShape::none)
isActive = false;

switch (newShape)
{
case OscShape::none: curOsc.store (&oscs[OscShape::none]); break;
case OscShape::saw: curOsc.store (&oscs[OscShape::saw]); break;
case OscShape::sawTri: curOsc.store (&oscs[OscShape::sawTri]); break;
case OscShape::triangle: curOsc.store (&oscs[OscShape::triangle]); break;
case OscShape::pulse: curOsc.store (&oscs[OscShape::pulse]); break;
case OscShape::noise: curOsc.store (&oscs[OscShape::noise]); break;
default: jassertfalse;
}

if (wasActive != isActive)
{
if (isActive)
setGain (lastActiveGain);
else
setGain (0);
}
}

/**
* @brief Sets the gain for the oscillator in the processorChain.
Expand All @@ -58,142 +116,44 @@ class GainedOscillator
else
lastActiveGain = newGain;

auto& gain = processorChain.template get<gainIndex> ();
gain.setGainLinear (newGain);
}

T getGain () { return lastActiveGain; }

void reset () noexcept { processorChain.reset (); }
void reset () noexcept
{
curOsc.load ()->reset();
gain.reset();
}

template <typename ProcessContext>
void process (const ProcessContext& context) noexcept
{
updateOscillators();

processorChain.process (context);
curOsc.load ()->process (context);
gain.process (context);
}

void prepare (const juce::dsp::ProcessSpec& spec)
{
processorChain.prepare (spec);
for (auto& osc : oscs)
osc.prepare (spec);

gain.prepare (spec);
}

private:
enum
{
oscIndex,
gainIndex
};

std::atomic<OscShape::Values> currentOsc { OscShape::none }, nextOsc { OscShape::saw };

void updateOscillators();
std::array<juce::dsp::Oscillator<T>, OscShape::actualTotal> oscs;
std::atomic<juce::dsp::Oscillator<T>*> curOsc { nullptr };

bool isActive = true;

T lastActiveGain {};

juce::dsp::ProcessorChain<juce::dsp::Oscillator<T>, juce::dsp::Gain<T>> processorChain;
juce::dsp::Gain<T> gain;

std::uniform_real_distribution<T> distribution;
std::default_random_engine generator;
};

//====================================================================================================

template <std::floating_point T>
void GainedOscillator<T>::updateOscillators()
{
//compare the current osc type with the (buffered next osc type). Get outta here if they the same
const auto nextOscBuf { nextOsc.load() };
if (currentOsc == nextOscBuf)
return;

//this is to make sure we preserve the same gain after we re-init, right?
bool wasActive = isActive;
isActive = true;

auto& osc = processorChain.template get<oscIndex>();
switch (nextOscBuf)
{
case OscShape::none:
osc.initialise ([&] (T /*x*/) { return T (0); });
isActive = false;
break;

case OscShape::saw:
{
osc.initialise ([](T x)
{
//this is a sawtooth wave; as x goes from -pi to pi, y goes from -1 to 1
return juce::jmap (x, T (-juce::MathConstants<T>::pi), T (juce::MathConstants<T>::pi), T (-1), T (1));
}, 2);
}
break;

case OscShape::sawTri:
{
osc.initialise ([](T x)
{
T y = juce::jmap (x, T (-juce::MathConstants<T>::pi), T (juce::MathConstants<T>::pi), T (-1), T (1)) / 2;

if (x < 0)
return y += juce::jmap (x, T (-juce::MathConstants<T>::pi), T (0), T (-1), T (1)) / 2;
else
return y += juce::jmap (x, T (0), T (juce::MathConstants<T>::pi), T (1), T (-1)) / 2;

}, 128);
}
break;

case OscShape::triangle:
{
osc.initialise ([](T x)
{
if (x < 0)
return juce::jmap (x, T (-juce::MathConstants<T>::pi), T (0), T (-1), T (1));
else
return juce::jmap (x, T (0), T (juce::MathConstants<T>::pi), T (1), T (-1));

}, 128);
}
break;

case OscShape::pulse:
{
osc.initialise ([](T x)
{
if (x < 0)
return T (-1);
else
return T (1);
}, 128);
}
break;

case OscShape::noise:
{
osc.initialise ([&](T /*x*/)
{
return distribution (generator);
});
}
break;

case OscShape::totalSelectable:
default:
jassertfalse;
break;
}

if (wasActive != isActive)
{
if (isActive)
setGain (lastActiveGain);
else
setGain (0);
}

currentOsc.store (nextOscBuf);
}
Loading
Loading