-
Notifications
You must be signed in to change notification settings - Fork 0
/
MidiSound.h
122 lines (96 loc) · 3.3 KB
/
MidiSound.h
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
/*
==============================================================================
MidiSound.h
Created: 15 Mar 2022 12:26:27pm
Author: renda
==============================================================================
*/
#pragma once
#include <JuceHeader.h>
struct SquareWaveSound : public juce::SynthesiserSound
{
SquareWaveSound() {}
bool appliesToNote(int) override { return true; }
bool appliesToChannel(int) override { return true; }
};
struct SquareWaveVoice : public juce::SynthesiserVoice
{
SquareWaveVoice()
{
adsrParams.attack = 0.1f;
adsrParams.decay = 0.1;
adsrParams.sustain = 1.0f;
adsrParams.release = 0.1f;
}
void pitchWheelMoved(int) override {}
void controllerMoved(int, int) override {}
bool canPlaySound(juce::SynthesiserSound* sound) override
{
return dynamic_cast<SquareWaveSound*> (sound) != nullptr;
}
void startNote(int midiNoteNumber, float velocity, juce::SynthesiserSound*,
int /*currentPitchWheelPosition*/) override
{
adsr.noteOn();
currentAngle = 0.0;
level = velocity * 0.15;
tailOff = 0.0;
auto cyclesPerSecond = juce::MidiMessage::getMidiNoteInHertz(midiNoteNumber);
auto cyclesPerSample = cyclesPerSecond / getSampleRate();
angleDelta = cyclesPerSample * 2.0 * juce::MathConstants<double>::pi;
}
void stopNote(float velocity, bool allowTailOff) override
{
adsr.noteOff();
if (allowTailOff)
{
if (tailOff == 0.0)
tailOff = 1.0;
}
else
{
clearCurrentNote();
angleDelta = 0.0;
}
}
void renderNextBlock(juce::AudioSampleBuffer& outputBuffer, int startSample, int numSamples) override
{
adsr.setParameters(adsrParams);
if (angleDelta != 0.0)
{
if (tailOff > 0.0) // [7]
{
while (--numSamples >= 0)
{
auto currentSample = std::signbit((float)(std::sin(currentAngle) * level * tailOff));
for (auto i = outputBuffer.getNumChannels(); --i >= 0;)
outputBuffer.addSample(i, startSample, adsr.getNextSample() * currentSample);
currentAngle += angleDelta;
++startSample;
tailOff *= 0.99; // [8]
if (tailOff <= 0.005)
{
clearCurrentNote(); // [9]
angleDelta = 0.0;
break;
}
}
}
else
{
while (--numSamples >= 0) // [6]
{
auto currentSample = std::signbit((float)(std::sin(currentAngle) * level));
for (auto i = outputBuffer.getNumChannels(); --i >= 0;)
outputBuffer.addSample(i, startSample, adsr.getNextSample() * currentSample);
currentAngle += angleDelta;
++startSample;
}
}
}
}
private:
double level = 0.0, tailOff = 0.0;
double currentAngle = 0.0, angleDelta = 0.0;
juce::ADSR adsr; juce::ADSR::Parameters adsrParams;
};