-
Notifications
You must be signed in to change notification settings - Fork 2
/
chord-organ.ino
231 lines (193 loc) · 7.35 KB
/
chord-organ.ino
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
/* --------------------------------------------------------------------------
$$$$$$$\ $$\ $$\ $$\ $$\ $$\ $$\
$$ __$$\ $$ | $$ |$$$\ $$$ |$$$\ $$$ |
$$ | $$ |$$ | $$ |$$$$\ $$$$ |$$$$\ $$$$ |
$$$$$$$\ |$$ | $$ |$$\$$\$$ $$ |$$\$$\$$ $$ |
$$ __$$\ $$ | $$ |$$ \$$$ $$ |$$ \$$$ $$ |
$$ | $$ |$$ | $$ |$$ |\$ /$$ |$$ |\$ /$$ |
$$$$$$$ |\$$$$$$ |$$ | \_/ $$ |$$ | \_/ $$ |
\_______/ \______/ \__| \__|\__| \__|
$$$$$$$\ $$\ $$\ $$\ $$\ $$\ $$\
$$ __$$\ $$ | $$ |$$$\ $$$ |$$$\ $$$ |
$$ | $$ |$$ | $$ |$$$$\ $$$$ |$$$$\ $$$$ |
$$$$$$$\ |$$ | $$ |$$\$$\$$ $$ |$$\$$\$$ $$ |
$$ __$$\ $$ | $$ |$$ \$$$ $$ |$$ \$$$ $$ |
$$ | $$ |$$ | $$ |$$ |\$ /$$ |$$ |\$ /$$ |
$$$$$$$ |\$$$$$$ |$$ | \_/ $$ |$$ | \_/ $$ |
\_______/ \______/ \__| \__|\__| \__|
$$$$$$\ $$$$$$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$$$\
$$ __$$\ $$ __$$\ $$ __$$\ $$ __$$\ $$ __$$\ $$ _____|
$$ / \__|$$ / $$ |$$ | $$ |$$ / $$ |$$ / \__|$$ |
$$ |$$$$\ $$$$$$$$ |$$$$$$$ |$$$$$$$$ |$$ |$$$$\ $$$$$\
$$ |\_$$ |$$ __$$ |$$ __$$< $$ __$$ |$$ |\_$$ |$$ __|
$$ | $$ |$$ | $$ |$$ | $$ |$$ | $$ |$$ | $$ |$$ |
\$$$$$$ |$$ | $$ |$$ | $$ |$$ | $$ |\$$$$$$ |$$$$$$$$\
\______/ \__| \__|\__| \__|\__| \__| \______/ \________|
CHORD ORGAN
This is the code for an Eurorack synth module.
It's built and tested on an Arduino Nano.
Find out more on: http://bummbummgarage.github.io/
---------------------------------------------------------------------- */
/* ##########################################################################
PRESETUP
##########################################################################
*/
const bool debug = false; // Enables the Serial print in several functions. Just for debugging, sound won't work properly when set on.
// Arduino synth library, see https://github.com/dzlonline/the_synth
#include <synth.h>
synth chord; // Initialzing the synth.
// Inputs
const int rootCVIn = A0;
// Potis
const int wavePotiPin = A4;
const int rootPotiPin = A5;
const int shapePotiPin = A6;
// Waveforms
const int waveCount = 5;
const int voiceWaves[waveCount] = { SINE, TRIANGLE, SQUARE, SAW, NOISE };
int voiceWave; // The current wave. Will be intially set in the loop.
// Tune (root note)
int root; // This is the base note of the chord defined in semitones (36-84, C-2 to C+2). Will be set in the loop.
// Low and high define the range.
const int lowestRoot = 36;
const int highestRoot = 84;
int rootDelta; // This is the number of semitones to be added via the CV IN.
int tune; // The resulting tune for the chord (the base note).
// Chord shapes
const int voiceCount = 4;
const int shapeCount = 13;
const int chordShapes[shapeCount][voiceCount] = {
{ 0, 4, 7, 12 }, // Major
{ 0, 3, 7, 12 }, // Minor
{ 0, 4, 7, 11 }, // Major 7th
{ 0, 3, 7, 10 }, // Minor 7th
{ 0, 5, 7, 11 }, // Suspended 4th
{ 0, 7, 12, 0 }, // Power 5th
{ 0, 5, 12, 0 }, // Power 4th
{ 0, 4, 7, 8 }, // Major 6th
{ 0, 3, 7, 8 }, // Minor 6th
{ 0, 3, 6, 0 }, // Diminished
{ 0, 4, 8, 0 }, // Augmented
{ 0, 0, 0, 0 }, // Root
{ -24, -12, 0, 0 } // Sub Octave
};
int chordShape; // The global variable for the current chord shape. Will be set in the loop.
// Misc
const int voiceEnv = 0; // Not needed, we just play the chord along.
const int voiceLength = 0; // Not needed, we just play the chord along.
const int voiceMod = 64; // 64 means no modulation, which is fine, not needed.
/* ##########################################################################
SETUP
##########################################################################
*/
void setup()
{
if ( debug == true ) {
Serial.begin(9600); // Initialize serial communication at 9600 bits per second.
}
chord.begin(); // Start it up
}
/* ##########################################################################
LOOP
##########################################################################
*/
void loop()
{
// Set the wave of the voices.
setWave();
// Set the tune.
setTune();
// Set the shape of the chord.
setShape();
// Prepare the chord.
setupChord();
// Play the chord
for (int v = 0; v < voiceCount; v++) {
chord.trigger(v);
}
}
/* ##########################################################################
FUNCTIONS
##########################################################################
*/
// Set the waveform.
void setWave() {
int v = analogRead(wavePotiPin);
int w = ( v * waveCount ) / 1024;
if ( millis() < 10 || voiceWave != w ) { // Act after booting and when the value has changed.
voiceWave = w;
if ( debug == true ) {
Serial.print("Wave (poti value): ");
Serial.print(voiceWave);
Serial.print(" (");
Serial.print(v);
Serial.println(")");
}
}
}
// Set the tune (resulting root note) from the poti and the CV In.
void setTune() {
// 1. Get the root poti value.
int v = analogRead(rootPotiPin); // The poti value
int r = map(v, 0, 1023, lowestRoot, highestRoot);
if ( millis() < 10 || root != r ) { // Act after booting and when the value has changed.
root = r;
if ( debug == true ) {
Serial.print("Root (poti value): ");
Serial.print(root);
Serial.print(" (");
Serial.print(v);
Serial.println(")");
}
}
// 2. Get the CV In value.
int c = analogRead(rootCVIn);
float unitsPerSemitone = 1024 / 4.9 / 12; // 17,4149659864
int d = c / unitsPerSemitone; // Root is defined by the number of semitones.
if ( millis() < 10 || rootDelta != d ) { // Act after booting and when the value has changed.
rootDelta = d;
if ( debug == true ) {
Serial.print("Root delta (CV IN value): ");
Serial.print(rootDelta);
Serial.print(" (");
Serial.print(c);
Serial.println(")");
}
}
// 3. Calculate the resulting tune.
int t = root + rootDelta;
if ( millis() < 10 || tune != t ) { // Act after booting and when the value has changed.
tune = t;
if ( debug == true ) {
Serial.print("Tune (root + delta): ");
Serial.print(tune);
Serial.print(" (");
Serial.print(root);
Serial.print(" + ");
Serial.print(rootDelta);
Serial.println(")");
}
}
}
// Set the shape of the chord.
void setShape() {
int v = analogRead(shapePotiPin);
int s = ( v * shapeCount ) / 1024;
if ( millis() < 10 || chordShape != s ) { // Act after booting and when the value has changed.
chordShape = s;
if ( debug == true ) {
Serial.print("Chord shape (poti value): ");
Serial.print(chordShape);
Serial.print(" (");
Serial.print(v);
Serial.println(")");
}
}
}
// Setting up the voices for the chord.
void setupChord() {
for (int v = 0; v < voiceCount; v++) {
int baseNote = tune + chordShapes[ chordShape ][ v ];
chord.setupVoice( v, voiceWaves[voiceWave], baseNote, voiceEnv, voiceLength, voiceMod );
}
}