-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathBassDrum.cmajor
More file actions
160 lines (136 loc) · 6.4 KB
/
Copy pathBassDrum.cmajor
File metadata and controls
160 lines (136 loc) · 6.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// https://www.soundonsound.com/techniques/synthesizing-drums-bass-drum
namespace Percupuff
{
namespace Drums
{
// Tries to create the sound of an acoustic bass drum.
processor BassDrum {
input event (std::notes::NoteOn) eventIn;
input event Params paramsIn;
output stream float<2> out;
// How hard or fast was the note hit, doubles as trigger.
float triggerVelocity = 0.0f;
// The midi note pitch that should trigger this sound.
int midiNotePitch = 0;
// How loud should this sound be, controlled by kick1Level param.
float outputLevel = 0.5f;
// Should the sound be biased towards the left or right side, or be
// centered. -1 is completely left, and 1 is completely right.
float panning = 0.0f;
event paramsIn(Params p) {
midiNotePitch = int(p.kick1Midi);
outputLevel = p.kick1Level * 0.01f;
panning = p.kick1Panning;
}
// When a note is hit that corresponds with our expected
// midiNotePitch, we take its velocity (how hard it was hit),
// compute the square root and set that as our trigger velocity.
// The code below will use this to start playing the sound and
// adjust its volume and "intensity" accordingly.
event eventIn(std::notes::NoteOn n) {
if (int (n.pitch) == midiNotePitch) {
triggerVelocity = sqrt(n.velocity);
}
}
// The individual components that make up our sound.
node osc = OscillatorBank;
node envelope = Envelope;
node filterEnvelope = Envelope;
node carrier = Oscillator;
node modulator = Oscillator;
Lpf lpf = (0.0f, 0.0f);
void main()
{
// Frequencies taken from the article + experimentation.
osc.frequencyIn <- float<8>(
50,
93,
136,
182,
225,
273,
73,
60
);
// Relative levels of each individual frequency.
osc.levelIn <- float<8>(
2.0f,
0.5f,
0.4f,
0.3f,
0.2f,
0.2f,
1.0f,
1.0f
);
// Our main envelope this is used for gain/volume, but also for
// the pitch of one of our oscillators. Causing a kind of pew
// effect.
envelope.releaseIn <- .25f;
filterEnvelope.releaseIn <- .05f;
// This bass drum sound has two "voices" the oscillator bank
// above provides the expected "thud". This oscillator pair
// provides slightly higher pitched noise, think maybe the
// sound of the pedal hitting the drum and some "air".
carrier.frequencyIn <- 500.0f;
modulator.frequencyIn <- 166.0f;
// Used for the filter.
let invSampleRate = 1.0f / float(processor.frequency);
loop
{
// Do nothing while velocity is 0.
while (triggerVelocity == 0) {
advance();
}
let vel = triggerVelocity;
triggerVelocity = 0.0f;
// Trigger the envelopes.
envelope.triggerIn <- void;
filterEnvelope.triggerIn <- void;
// Extract the first value from the envelopes.
envelope.advance();
filterEnvelope.advance();
float gain = envelope.gainOut;
// Generate sound as long as it would be audible and our
// sound isn't triggered again.
while (gain > 0.0f && triggerVelocity == 0.0f) {
// Modulate the frequency of the first oscillator with
// the gain envelope.
modulator.frequencyModIn <- gain * 0.01f;
let mod = modulator.out;
modulator.advance();
// Modulate the second oscillator with the output of
// the first.
carrier.frequencyModIn <- mod;
let car = carrier.out;
carrier.advance();
// Filter out high frequency content from the output of
// the second oscillator. The cutoff frequency is being
// modulated by the filter envelope. As it has a very
// short release, we very quickly lower the cut off
// frequency, meaning we have a quick boost of higher
// frequencies that then quickly get darkened.
float lpSample = lpf.getSample(car, 1200.0f + 3500.0f * filterEnvelope.gainOut, invSampleRate);
// The oscillator bank also gets modulated by the gain
// envelope.
osc.frequencyModIn <- gain * 0.01f;
// We mix everything together. The sine function
// provides a kind of distortion to make the sound more
// punchy.
float sample = (sin(osc.out * (.01f + 1.5f * vel)) + lpSample * 0.17f) * gain * outputLevel;
osc.advance();
// We create left/right samples according to panning.
float pan = panning * 0.01f;
float leftGain = 0.5f * (1.0f - pan);
float rightGain = 0.5f * (1.0f + pan);
out <- (sample * leftGain, sample * rightGain);
gain = envelope.gainOut;
envelope.advance();
filterEnvelope.advance();
advance();
}
}
}
}
}
}