-
Notifications
You must be signed in to change notification settings - Fork 0
/
Columns.cpp
134 lines (111 loc) · 3.84 KB
/
Columns.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
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
#include <stdarg.h>
#include <stdio.h>
#include "Arduino.h"
/**
* Column of controls of a single item from the sequence: a pitch potentiometer, an on/off button
* and a status led.
*/
struct Column {
int pitch; // pitch as set on potentiometer (pot value scaled to 0-127 range)
int potValue = 0; // current potentiometer value
boolean enabled = true; // flip-flop controlled by button
boolean buttonState = LOW; // current button state
long buttonChanged = 0; // timestamp of last state change
};
/**
* Whole set of columns, connected to arduino with a set of wires:
* - three digital output pins to multiplexer, to select one of the columns
* - common analog input pin from potentiometers
* - common digital input pin from buttons
*/
class Columns {
private:
Column *columns;
const int numOfColumns;
int muxInhibitPin;
int muxPinA, muxPinB, muxPinC;
int highlightedColNr;
long highlightStarted = 0;
int pitchPin;
int togglePin;
const int MAX_POT_VALUE = 550; // due to voltage drop on mux, it won't be the usual 1024
const int MAX_PITCH = 127; // max possible pitch in our synthesizer
long lastRefresh = 0;
public:
Columns(int numOfColumns) : numOfColumns(numOfColumns) {
columns = new Column[numOfColumns];
}
void setupMuxPins(int inhibitPin, int pinA, int pinB, int pinC) {
this->muxInhibitPin = inhibitPin;
this->muxPinA = pinA;
this->muxPinB = pinB;
this->muxPinC = pinC;
pinMode(inhibitPin, OUTPUT);
pinMode(pinA, OUTPUT);
pinMode(pinB, OUTPUT);
pinMode(pinC, OUTPUT);
deselect();
}
void setupInputPins(int pitchPin, int togglePin) {
this->pitchPin = pitchPin;
this->togglePin = togglePin;
pinMode(pitchPin, INPUT);
pinMode(togglePin, INPUT);
}
Column &operator[](int colNr) {
highlight(colNr);
return columns[colNr];
}
void select(int colNr) {
digitalWrite(muxInhibitPin, HIGH);
digitalWrite(muxPinA, bitRead(colNr, 0));
digitalWrite(muxPinB, bitRead(colNr, 1));
digitalWrite(muxPinC, bitRead(colNr, 2));
digitalWrite(muxInhibitPin, LOW);
}
void deselect() {
digitalWrite(muxInhibitPin, HIGH);
}
void highlight(int colNr) {
highlightStarted = millis();
highlightedColNr = colNr;
}
void read() {
// do not refresh too often as this highlights all leds temporarily
boolean needToRefresh = millis() - lastRefresh > 25;
if (needToRefresh) {
lastRefresh = millis();
for (int colNr = 0; colNr < numOfColumns; colNr++) {
select(colNr);
read(columns[colNr]);
}
}
// update led highlighting to show what has been recently played
boolean highlightStillOn = millis() - highlightStarted <= 75;
if (columns[highlightedColNr].enabled && highlightStillOn) {
select(highlightedColNr);
} else {
deselect();
}
}
void read(Column &column) {
// read pot value, then calculate pitch
int readPotValue = analogRead(pitchPin);
int minimumMeaningfulDifference = MAX_POT_VALUE / MAX_PITCH;
if (abs(column.potValue - readPotValue) >= minimumMeaningfulDifference) {
column.potValue = readPotValue;
column.pitch = map(readPotValue, 0, MAX_POT_VALUE, 0, MAX_PITCH);
column.pitch = MAX_PITCH - column.pitch; // inverse
}
// debounce button, then establish column enabled state
int readButtonState = digitalRead(togglePin);
boolean changedRecently = millis() - column.buttonChanged <= 50;
if (column.buttonState != readButtonState && !changedRecently) {
column.buttonState = readButtonState;
column.buttonChanged = millis();
if (readButtonState == HIGH) {
column.enabled = !column.enabled;
}
}
}
};