Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions dsp/Params.cmajor
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ namespace Percupuff
float cowbellPanning;
float cowbellVelocity;
float cowbellMidi;
float maracasLevel;
float maracasPanning;
float maracasVelocity;
float maracasMidi;
float sideStickLevel;
float sideStickPanning;
float sideStickVelocity;
Expand Down Expand Up @@ -173,6 +177,10 @@ namespace Percupuff
p.cowbellPanning = 0.0f;
p.cowbellVelocity = 100.0f;
p.cowbellMidi = 56.0f;
p.maracasLevel = 50.0f;
p.maracasPanning = 0.0f;
p.maracasVelocity = 100.0f;
p.maracasMidi = 70.0f;
p.sideStickLevel = 50.0f;
p.sideStickPanning = 0.0f;
p.sideStickVelocity = 100.0f;
Expand Down Expand Up @@ -260,6 +268,10 @@ namespace Percupuff
input event float cowbellPanning [[ name: "cowbellPanning", min: -100, max: 100, init: 0, step: 5 ]];
input event float cowbellVelocity [[ name: "cowbellVelocity", min: 0, max: 100, init: 100, step: 1 ]];
input event float cowbellMidi [[ name: "cowbellMidi", min: 0, max: 127, init: 56, step: 1 ]];
input event float maracasLevel [[ name: "maracasLevel", min: 0, max: 100, init: 50, step: 1 ]];
input event float maracasPanning [[ name: "maracasPanning", min: -100, max: 100, init: 0, step: 5 ]];
input event float maracasVelocity [[ name: "maracasVelocity", min: 0, max: 100, init: 100, step: 1 ]];
input event float maracasMidi [[ name: "maracasMidi", min: 0, max: 127, init: 70, step: 1 ]];
input event float sideStickLevel [[ name: "sideStickLevel", min: 0, max: 100, init: 50, step: 1 ]];
input event float sideStickPanning [[ name: "sideStickPanning", min: -100, max: 100, init: 0, step: 5 ]];
input event float sideStickVelocity [[ name: "sideStickVelocity", min: 0, max: 100, init: 100, step: 1 ]];
Expand Down Expand Up @@ -350,6 +362,10 @@ namespace Percupuff
event cowbellPanning (float f) { params.cowbellPanning = f; update(); }
event cowbellVelocity (float f) { params.cowbellVelocity = f; update(); }
event cowbellMidi (float f) { params.cowbellMidi = f; update(); }
event maracasLevel (float f) { params.maracasLevel = f; update(); }
event maracasPanning (float f) { params.maracasPanning = f; update(); }
event maracasVelocity (float f) { params.maracasVelocity = f; update(); }
event maracasMidi (float f) { params.maracasMidi = f; update(); }
event sideStickLevel (float f) { params.sideStickLevel = f; update(); }
event sideStickPanning (float f) { params.sideStickPanning = f; update(); }
event sideStickVelocity (float f) { params.sideStickVelocity = f; update(); }
Expand Down
4 changes: 4 additions & 0 deletions dsp/Percupuff.cmajor
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ namespace Percupuff
bongos = Drums::Bongos;
sideStick = Drums::SideStick;
rideBell = Drums::RideBell;
maracas = Drums::Maracas;
gainLimiter = std::levels::ConstantGain (float<2>, 1.0f);
mpe = std::midi::MPEConverter;
}
Expand All @@ -57,6 +58,7 @@ namespace Percupuff
p.paramsOut -> electricSnare.paramsIn;
p.paramsOut -> sideStick.paramsIn;
p.paramsOut -> rideBell.paramsIn;
p.paramsOut -> maracas.paramsIn;

// Send the midi events so the sound processors know when to start playing.
midiIn -> mpe;
Expand All @@ -71,6 +73,7 @@ namespace Percupuff
mpe -> bongos.eventIn;
mpe -> sideStick.eventIn;
mpe -> rideBell.eventIn;
mpe -> maracas.eventIn;
mpe -> noteOn;

// Some sounds use noise.
Expand All @@ -95,6 +98,7 @@ namespace Percupuff
bongos -> gainLimiter;
sideStick -> gainLimiter;
rideBell -> gainLimiter;
maracas -> gainLimiter;

// Output the result.
gainLimiter -> out;
Expand Down
122 changes: 122 additions & 0 deletions dsp/drums/Maracas.cmajor
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
namespace Percupuff
{
namespace Drums
{
processor Maracas {
input event (std::notes::NoteOn) eventIn;
output stream float<2> out;
input event Params paramsIn;

float triggerVelocity = 0.0f;
int midiNotePitch = 0;
float outputLevel = 0.5f;
float panning = 0.0f;

event paramsIn(Params p) {
midiNotePitch = int(p.maracasMidi);
outputLevel = p.maracasLevel * 0.01f;
panning = p.maracasPanning;
}

event eventIn(std::notes::NoteOn n) {
if (int(n.pitch) == midiNotePitch)
triggerVelocity = sqrt(n.velocity);
}

node envelope = Envelope;
node noise = std::noise::White;

// Two fixed filters for "dark" and "bright" tone blending
node hpfBright = std::filters::butterworth::Processor(
std::filters::butterworth::Mode::highPass, 5000.0f
);

node lpfBright = std::filters::butterworth::Processor(
std::filters::butterworth::Mode::lowPass, 9000.0f
);

node hpfDark = std::filters::butterworth::Processor(
std::filters::butterworth::Mode::highPass, 3200.0f
);

node lpfDark = std::filters::butterworth::Processor(
std::filters::butterworth::Mode::lowPass, 7000.0f
);

void main()
{
envelope.attackIn <- 0.0008f; // quicker attack for snappy bursts

loop
{
while (triggerVelocity == 0)
advance();

let baseVel = triggerVelocity;
triggerVelocity = 0.0f;

float burstCount = 4 + (baseVel * 25);
float burstSpacing = 0.00008f + (1.0f - baseVel) * 0.0004f;

for (int i = 0; i < int(burstCount); ++i)
{
float velJitter = 0.8f + (noise.out * 0.2f);
float burstVel = baseVel * velJitter;

// control brightness blend (0 = dark, 1 = bright)
float brightMix = (noise.out * 0.5f + 0.5f);

// shorter envelope release for each burst
envelope.releaseIn <- 0.0012f + (noise.out * 0.01f);
envelope.triggerIn <- void;
envelope.advance();

float gain = envelope.gainOut;

// Alternate stereo motion slightly
float altPan = ((i % 2 == 0) ? -0.4f : 0.4f) + (panning * 0.01f);

while (gain > 0.001f)
{
// Slightly โ€œgrainyโ€ random noise burst
float raw = noise.out * (2.2f + noise.out * 0.1f);

// Process both bright and dark chains
hpfBright.in <- raw;
lpfBright.in <- hpfBright.out;
float bright = lpfBright.out;

hpfDark.in <- raw;
lpfDark.in <- hpfDark.out;
float dark = lpfDark.out;

// Blend between dark and bright versions
float filtered = dark * (1.0f - brightMix) + bright * brightMix;

float outSample = filtered * gain * baseVel * outputLevel;

float leftGain = 0.5f * (1.0f - altPan);
float rightGain = 0.5f * (1.0f + altPan);
out <- (outSample * leftGain, outSample * rightGain);

noise.advance();
hpfBright.advance();
lpfBright.advance();
hpfDark.advance();
lpfDark.advance();
envelope.advance();
advance();

gain = envelope.gainOut;
}

float jitter = (noise.out * 0.0003f);
int silentSamples = int((burstSpacing + jitter) * float(processor.frequency));
for (int s = 0; s < silentSamples; ++s)
advance();
}
}
}
}
}
}
1 change: 1 addition & 0 deletions percupuff.cmajorpatch
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"dsp/drums/Bongos.cmajor",
"dsp/drums/SideStick.cmajor",
"dsp/drums/RideBell.cmajor",
"dsp/drums/Maracas.cmajor",
"dsp/Percupuff.cmajor"
],
"view": {
Expand Down
2 changes: 2 additions & 0 deletions view/src/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export const instruments = {

cowbell: { name: "Cowbell", group: "๐Ÿฎ", midi: 56 },

maracas: { name: "Maracas", group: null, midi: 70 },

// Example of adding an instrument without having it show up in the UI yet.
sideStick: { name: "Side Stick", group: null, midi: 37 },
} as const;
Expand Down