-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathHihat.cmajor
More file actions
115 lines (99 loc) · 4.47 KB
/
Copy pathHihat.cmajor
File metadata and controls
115 lines (99 loc) · 4.47 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
// https://www.soundonsound.com/techniques/synthesizing-realistic-cymbals
// https://www.soundonsound.com/techniques/practical-cymbal-synthesis
namespace Percupuff
{
namespace Drums
{
// This generates the sounds for open, closed and pedal hihats. The
// metallic "tick" of the hihat is created by 2 oscillators using
// frequency modulation. White noise simulates the higher frequencies
// that linger a bit longer.
processor Hihat {
input event (std::notes::NoteOn) eventIn;
input event Params paramsIn;
input stream float noiseIn;
output stream float<2> out;
float triggerVelocity = 0.0f;
float feedback = 0.0f;
float noiseLevel = 0.3f;
float outputLevel = 0.5f;
int hihatClosedPitch = 0;
int pedalHihatPitch = 0;
int hihatOpenPitch = 0;
float panning = 0.01f;
event paramsIn(Params p) {
hihatClosedPitch = int(p.hihat1Midi);
pedalHihatPitch = int(p.hihat2Midi);
hihatOpenPitch = int(p.hihat3Midi);
outputLevel = p.hihatLevel * 0.01f;
panning = p.hihatPanning;
}
// The hihats vary in release/decay and how much white noise gets
// added. The pedal hihat also let's through a little bit more low
// frequencies than the other 2.
event eventIn(std::notes::NoteOn n) {
if (int (n.pitch) == hihatClosedPitch) {
triggerVelocity = sqrt(n.velocity);
envelope.releaseIn <- .3f;
noiseLevel = 0.8f;
highpass.frequency <- 9000.0f;
}
if (int (n.pitch) == pedalHihatPitch) {
triggerVelocity = sqrt(n.velocity);
envelope.releaseIn <- .2f;
noiseLevel = 0.2f;
highpass.frequency <- 7000.0f;
}
if (int (n.pitch) == hihatOpenPitch) {
triggerVelocity = sqrt(n.velocity);
envelope.releaseIn <- .8f;
noiseLevel = 0.5f;
highpass.frequency <- 9000.0f;
}
}
node envelope = Envelope;
node osc1 = Oscillator(OscillatorShape::sine);
node osc2 = Oscillator(OscillatorShape::sine);
node highpass = std::filters::butterworth::Processor(std::filters::butterworth::Mode::highPass, 11000.0f);
let invSampleRate = 1.0f / float(processor.frequency);
void main()
{
// Frequencies as described in the article "Synthesizing Realistic Cymbals"
osc1.frequencyIn <- 1047.0f;
osc2.frequencyIn <- 2490.0f;
loop
{
while (triggerVelocity == 0) {
advance();
}
let vel = triggerVelocity;
triggerVelocity = 0.0f;
envelope.triggerIn <- void;
envelope.advance();
float gain = envelope.gainOut;
while (gain > 0.0f && triggerVelocity == 0.0f) {
// Feedback was experimented with but not used. If
// feedback is useful it should be a param, otherwise
// it should be removed from the code here.
osc1.frequencyModIn <- feedback * 0.0f;
osc2.frequencyModIn <- osc1.out * 1.8f;
feedback = osc2.out;
highpass.in <- osc2.out + noiseIn * noiseLevel;
let sample = highpass.out;
let outSample = sample * gain * (0.15f + vel * 0.15f) * outputLevel;
float pan = panning * 0.01f;
float leftGain = 0.5f * (1.0f - pan);
float rightGain = 0.5f * (1.0f + pan);
out <- (outSample * leftGain, outSample * rightGain);
osc1.advance();
osc2.advance();
highpass.advance();
gain = envelope.gainOut;
envelope.advance();
advance();
}
}
}
}
}
}