-
Notifications
You must be signed in to change notification settings - Fork 11
/
click_module.ino
243 lines (220 loc) · 6.24 KB
/
click_module.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
232
233
234
235
236
237
238
239
240
241
242
243
/*
* Copyright (c) 2021 Marcel Licence
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Dieses Programm ist Freie Software: Sie können es unter den Bedingungen
* der GNU General Public License, wie von der Free Software Foundation,
* Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
* veröffentlichten Version, weiter verteilen und/oder modifizieren.
*
* Dieses Programm wird in der Hoffnung bereitgestellt, dass es nützlich sein wird, jedoch
* OHNE JEDE GEWÄHR,; sogar ohne die implizite
* Gewähr der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
* Siehe die GNU General Public License für weitere Einzelheiten.
*
* Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
* Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
*/
/*
* this file contains the module controlling the tempo of the looper
* it counts always 4 bars
* min tempo will be calculated depending on the max loop length
*
* Author: Marcel Licence
*/
#define SEQ_TRACK_CNT 12
#define SEQ_STEPS 16
/*
* 1: only 4th notes
* 2: for 8th notes
*/
#define SEQ_SUBSTEP_MUL 2
#define DEFAULT_BPM 140
uint32_t seq_prescaler = 60.0f * 44100.0f / (2.0f * SEQ_SUBSTEP_MUL * (float)DEFAULT_BPM);
uint32_t seq_prescaler_next = 0;
uint32_t seq_pos = 0;
uint32_t seq_bar = 0;
bool seq_click = true; /*!< generate audible click */
bool seq_tempo = true; /*!< control looper with set tempo */
uint32_t seq_counter = 0;
bool seq_active = true;
/*
* This function integrates the metronome sound
* In addition to that it controls the looper if activated
*/
void Click_Process(float *left, float *right)
{
if (seq_active)
{
if (seq_click)
{
if (seq_pos == 0)
{
if (seq_bar == 0)
{
/* create highest pitch sound for the first beat of the first bar */
*left += ((float)((seq_counter & 16) / 16)) * 0.1f;
*right += ((float)((seq_counter & 16) / 16)) * 0.1f;
}
else
{
/* generate middle pitched sound for the first beat of all other bars */
*left += ((float)((seq_counter & 32) / 32)) * 0.1f;
*right += ((float)((seq_counter & 32) / 32)) * 0.1f;
}
}
else if ((seq_pos % 4) == 0)
{
/* generate sound with lowest pitch for 2, 3, 4 */
*left += ((float)((seq_counter & 64) / 64)) * 0.1f;
*right += ((float)((seq_counter & 64) / 64)) * 0.1f;
}
}
/* only if module is active the loop should be reset when jumping to first beat in first bar */
if (seq_tempo)
{
if ((seq_pos == 0) && (seq_counter == 0) && (seq_bar == 0))
{
//Loop_ResetToStart(0, 1);
Loop_SetEndByTempo();
}
if ((seq_pos == 0) && (seq_counter == 1) && (seq_bar == 0))
{
//Loop_ResetToStart(0, 0);
}
}
seq_counter ++;
if (seq_counter > (seq_prescaler / getLoopSpeed()))
{
seq_counter = 0;
seq_pos++;
if (seq_pos >= 16)
{
seq_pos = 0;
seq_bar = (seq_bar + 1) % 4;
}
if (Loop_AnyTrackActive() == false)
{
seq_pos = seq_pos % 4;
seq_bar = 0;
}
}
}
}
/*
* count in two bars
*/
void Click_StartFirst(void)
{
if (seq_active)
{
seq_counter = 0;
seq_bar = 2;
seq_pos = 0;
}
else
{
Loop_ResetToStart(0, 1);
Loop_ResetToStart(0, 0);
}
}
/*
* this function return the relative beat position as float 0..1
* it can be used to display the beat position
*/
float Click_GetRelPos(void)
{
return ((float)seq_bar * 16.0f + (float)seq_pos) / (16.0f * 8.0f);
}
/*
* reset the beat, bar to the beginning
*/
void Click_Reset(uint8_t channel, float value)
{
if (value > 0)
{
seq_pos = 0;
seq_counter = 0;
seq_bar = 0;
}
}
/*
* jump beat to beginning of given bar (quarter)
* todo: there is an issue with this function
*/
void Click_JumpPosQuarter(uint8_t quarter, float value)
{
if (value > 0)
{
seq_pos = 0;
seq_counter = 0;
seq_bar = quarter;
}
}
/*
* toggle the sound of the metronome on/off
*/
void Click_OnOff(uint8_t channel, float value)
{
if (value > 0)
{
if (seq_click)
{
seq_click = false;
Status_TestMsg("Click off");
}
else
{
seq_click = true;
Status_TestMsg("Click on");
}
}
}
/*
* turn the complete module on/off
* when turned off the looper will not be reset by this module
*/
void Click_ToggleOnOff(uint8_t channel, float value)
{
if (value > 0)
{
if (seq_active)
{
seq_active = false;
Status_TestMsg("Metronome off");
}
else
{
seq_active = true;
Status_TestMsg("Metronome on");
}
}
}
/*
* set the tempo
* prescaler will be calculated by samplerate
*/
void Click_SetTempo(uint8_t channel, float value)
{
/*
* time = 4 * 4 / (BPM / 60)
* BPM = ((4 * 4) / time) * 60
*/
float min_val = ((4.0f * 4.0f) / Loop_GetMaxRecLengthSeconds()) * 60;
float max_val = 240;
value = min_val + value * (max_val - min_val);
seq_prescaler = 60.0f * 44100.0f / (2.0f * SEQ_SUBSTEP_MUL * value);
Status_ValueChangedFloat("ClickSetTempo", value);
}