-
Notifications
You must be signed in to change notification settings - Fork 0
/
MidiTimer.cpp
74 lines (66 loc) · 1.44 KB
/
MidiTimer.cpp
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
#include "MidiTimer.h"
MidiTimer::MidiTimer (
uint8_t outputPin,
volatile uint8_t &controlRegisterA,
volatile uint8_t &controlRegisterB,
volatile uint16_t &compareRegister)
:
m_outputPin(outputPin),
m_controlRegisterA(controlRegisterA),
m_controlRegisterB(controlRegisterB),
m_compareRegister(compareRegister)
{
}
void MidiTimer::begin ()
{
pinMode (m_outputPin, OUTPUT);
m_controlRegisterA = _BV(COM1A0);
}
void MidiTimer::setNote(int midiNote)
{
m_frequency = midiNoteToFrequency(midiNote);
auto prescaler = midiNoteToPrescaler(midiNote);
auto compare = F_CPU >> 1; // divide by two for high and low portion of wave
compare /= prescaler;
compare = round(compare / m_frequency);
compare--; // subtract one for an extra instruction
// Set the registers
m_compareRegister = compare;
m_controlRegisterB = prescalerToPrescalerBits(prescaler);
}
uint16_t MidiTimer::getFrequency() const
{
return m_frequency;
}
double MidiTimer::midiNoteToFrequency(int midiNote)
{
return 440 * pow(2.0, (midiNote - 69) / 12.0);
}
int MidiTimer::midiNoteToPrescaler(int midiNote)
{
// supported prescalers are 1, 8, 64, 256 or 1024
if (midiNote < 11)
{
return 64;
}
else if (midiNote < 47)
{
return 8;
}
else
{
return 1;
}
}
int MidiTimer::prescalerToPrescalerBits(int prescaler)
{
switch (prescaler)
{
default:
case 1: return 0b1001;
case 8: return 0b1010;
case 64: return 0b1011;
case 256: return 0b1100;
case 1024: return 0b1101;
}
}