-
Notifications
You must be signed in to change notification settings - Fork 52
Expand file tree
/
Copy pathstd_library_notes.cmajor
More file actions
192 lines (163 loc) · 7.42 KB
/
Copy pathstd_library_notes.cmajor
File metadata and controls
192 lines (163 loc) · 7.42 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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//
// ,ad888ba, 88
// d8"' "8b
// d8 88,dba,,adba, ,aPP8A.A8 88 The Cmajor Standard Library
// Y8, 88 88 88 88 88 88
// Y8a. .a8P 88 88 88 88, ,88 88 (C)2024 Cmajor Software Ltd
// '"Y888Y"' 88 88 88 '"8bbP"Y8 88 https://cmajor.dev
// ,88
// 888P"
//
// The Cmajor standard library may be used under the terms of the ISC license:
//
// Permission to use, copy, modify, and/or distribute this software for any purpose with or
// without fee is hereby granted, provided that the above copyright notice and this permission
// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/// std.notes
/**
These structs are used for events that model the start/stop/control of notes
that are playing in synthesisers.
Unlike sending raw MIDI around, these are strongly typed and use floating point
data so are far nicer to work with.
The objects include a channel ID field, so that a multi-channel input device can
indicate which events should be applied to each of the active notes that are
being played.
*/
namespace std::notes
{
struct NoteOn
{
/// This channel ID is used to associate events which act on a particular voice.
/// When a NoteOn object is sent, the sender will create a unique ID, and
/// use the same ID for any subsequent pitch and control events, and for the
/// final matching NoteOff event.
int32 channel;
/// The pitch uses the same semitone scale as MIDI note numbers, between
/// 0 and 127, where middle C = 60.
float32 pitch;
/// Velocity is between 0 and 1
float32 velocity;
}
struct NoteOff
{
/// This channel ID can be used to associate this NoteOff event with the earlier
/// NoteOn to which it applies.
int32 channel;
/// You may not care exactly what the pitch is when a note is released, but
/// in case it's needed, it's included here.
float32 pitch;
/// Indicates how quickly the key was released: range is 0 to 1.
float32 velocity;
}
/// This message represents a per note aftertouch event (polyphonic aftertouch)
struct Aftertouch
{
/// This channel ID can be used to associate this event with the earlier
/// NoteOn to which it applies.
int32 channel;
/// The pitch of the note affected by this aftertouch
float32 pitch;
/// Key pressure in the range 0 to 1
float32 pressure;
}
struct PitchBend
{
/// This channel ID can be used to associate this event with the earlier
/// NoteOn to which it applies.
int32 channel;
/// The number of semitones to bend up from the original note-on pitch.
float32 bendSemitones;
}
/// This message represents a per channel pressure event (channel aftertouch)
struct Pressure
{
/// This channel ID can be used to associate this event with the earlier
/// NoteOn to which it applies.
int32 channel;
/// Key pressure is in the range 0 to 1
float32 pressure;
}
/// "Slide" refers to a Y-axis controller parameter.
/// (In MPE input devices, this is a MIDI controller number 74)
struct Slide
{
/// This channel ID can be used to associate this event with the earlier
/// NoteOn to which it applies.
int32 channel;
/// The slide position ranges from 0 to 1. Exactly what you choose to do
/// with it depends on the instrument.
float32 slide;
}
struct Control
{
/// This channel ID can be used to associate this event with the earlier
/// NoteOn to which it applies.
int32 channel;
/// This could be used for any kind of controller index, but is probably
/// best used for MIDI controller numbers.
int32 control;
/// The normalised value of the controller, between 0 and 1
float32 value;
}
struct ProgramChange
{
/// The channel affected by this change
int32 channel;
/// The new program selected on this channel
int32 program;
}
//==============================================================================
/// Returns the MIDI note equivalent for a frequency in Hz.
/// This uses the standard A = 440Hz reference tuning.
/// See: noteToFrequency
float32 frequencyToNote (float32 frequency)
{
return (12.0f / log (2.0f)) * log (frequency * (1.0f / 440.0f)) + 69.0f;
}
/// Returns the MIDI note equivalent for a frequency in Hz.
/// The frequencyOfA parameter lets you use non-standard tunings if you need to.
/// See: noteToFrequency
float32 frequencyToNote (float32 frequency, float32 frequencyOfA)
{
return (12.0f / log (2.0f)) * log (frequency * (1.0f / frequencyOfA)) + 69.0f;
}
/// Returns the frequency in Hz for a MIDI note number.
/// You can provide either an integer or floating point argument - the MIDI
/// note scale is in semitone units from 0 to 127, where middle C = 60.
/// This uses the standard A = 440Hz reference tuning.
/// See: frequencyToNote
float32 noteToFrequency<T> (T midiNoteNumber)
{
static_assert (T.isPrimitive && (T.isFloat || T.isInt), "noteToFrequency() requires an integer or floating point argument");
return 440.0f * 2.0f ** ((1.0f / 12.0f) * float32 (midiNoteNumber - 69));
}
/// Returns the frequency in Hz for a MIDI note number.
/// You can provide either an integer or floating point argument - the MIDI
/// note scale is in semitone units from 0 to 127, where middle C = 60.
/// The frequencyOfA parameter lets you use non-standard tunings if you need to.
/// See: frequencyToNote
float32 noteToFrequency<T> (T midiNoteNumber, float32 frequencyOfA)
{
static_assert (T.isPrimitive && (T.isFloat || T.isInt), "noteToFrequency() requires an integer or floating point argument");
return frequencyOfA * 2.0f ** ((1.0f / 12.0f) * float32 (midiNoteNumber - 69));
}
/// Calculates the speed ratio by which playback must be changed to re-pitch a given
/// source note to a target note.
float32 getSpeedRatioBetween (float32 sourceMIDINote, float32 targetMIDINote)
{
return 2.0f ** ((targetMIDINote - sourceMIDINote) * (1.0f / 12.0f));
}
/// Given a source with a known sample rate and pitch, this calculates the ratio at which
/// it would need to be sped-up in order to achieve a target pitch and sample-rate.
float64 getSpeedRatioBetween (float64 sourceSampleRate, float32 sourceMIDINote,
float64 targetSampleRate, float32 targetMIDINote)
{
return (sourceSampleRate / targetSampleRate)
* getSpeedRatioBetween (sourceMIDINote, targetMIDINote);
}
}