-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathOBG_Tempo.c
130 lines (105 loc) · 2.71 KB
/
OBG_Tempo.c
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
/**
OBG_Tempo.c
This is the a source file of the AVR Butterfly
application board adaptation of the One Bit Groovebox.
Here are the definitions of the tempo calculator
for the One Bit Groovebox.
*/
#include "Display.h" /* For LCD output. */
#include "Timer.h"
#include "OBG_Sequencer.h" /* Tempo data type, Set_Tempo() et cetera. */
#include "OBG_Tempo.h"
/** Current value of calculated tempo. */
uint32_t current_tempo;
/** Tempo calculator state. */
tempo_calc_state_t tempo_calc_state = TAP1;
/** Timestamp (set when tempo was tapped). */
uint32_t timestamp;
/** Current tap timestamp. */
uint32_t current_tap_timestamp;
/** Previous tap timestamp. */
uint32_t previous_tap_timestamp;
/** Set timestamp (called externally). */
void Set_Tap_Timestamp(uint32_t tap_timestamp)
{
timestamp = tap_timestamp;
}
/** OBG tempo calculator task. */
void OBG_Tempo_Task(void)
{
uint32_t interval;
if(tempo_calc_state == TAP1)
{
/* Get first timestamp. */
previous_tap_timestamp = timestamp;
}
else
{
/* Get current timestamp. */
current_tap_timestamp = timestamp;
/* Calculate interval between two taps. */
interval = Calculate_Timestamp_Interval(previous_tap_timestamp,
current_tap_timestamp);
/* Check if there is an apparent glitch. */
if(interval < MAX_TEMPO_PULSES)
{
return;
}
/* Check if someone forgot to complete four taps sequence. */
if(interval > MIN_TEMPO_PULSES)
{
/* Count this tap as the first one. */
tempo_calc_state = TAP1;
OBG_Tempo_Task();
return;
}
/* Depending on state, calculate new tempo. */
switch(tempo_calc_state)
{
case TAP2:
current_tempo = interval;
break;
case TAP3:
current_tempo = (current_tempo + interval) / 2;
break;
case TAP4:
current_tempo = (current_tempo * 2 + interval) / 3;
break;
default:
break;
}
/* If preliminary tempo calculated, display it. */
if(tempo_calc_state != TAP1)
{
Display_Tempo(current_tempo, F_TAP_TIMER);
}
/* If tempo calculated, set it. */
if(tempo_calc_state == TAP4)
{
Set_Tempo(current_tempo);
}
/* Backup current timestamp. */
previous_tap_timestamp = current_tap_timestamp;
}
/* Set current beat to the corresponding quarter and
transit to the next state. */
switch(tempo_calc_state)
{
case TAP1:
Set_Current_Beat((BEATS / 4) * (1-1));
tempo_calc_state = TAP2;
break;
case TAP2:
Set_Current_Beat((BEATS / 4) * (2-1));
tempo_calc_state = TAP3;
break;
case TAP3:
Set_Current_Beat((BEATS / 4) * (3-1));
tempo_calc_state = TAP4;
break;
case TAP4:
Set_Current_Beat((BEATS / 4) * (4-1));
tempo_calc_state = TAP1;
break;
}
}