ChordJoy is a keyboard application that accepts chordal input from a set of digital ports, outputting letters and the chords that correspond to the piano keyboard keys the user has pressed.

Dependencies:   PinDetect_KL25Z mbed-rtos mbed

Committer:
andrewhead
Date:
Mon Sep 22 02:15:15 2014 +0000
Revision:
4:400a042e762a
Parent:
3:ed89297af2ce
Child:
5:1186eb1f3c2b
Play chords after hearing rising edge!

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewhead 0:5ffec551c755 1 #include "mbed.h"
andrewhead 0:5ffec551c755 2 #include "rtos.h"
andrewhead 0:5ffec551c755 3
andrewhead 1:b6b866a58a87 4
andrewhead 1:b6b866a58a87 5 const int BUTTONS = 7;
andrewhead 0:5ffec551c755 6 const int BUZZERS = 3;
andrewhead 0:5ffec551c755 7 const int LETTERS = 27;
andrewhead 0:5ffec551c755 8
andrewhead 3:ed89297af2ce 9 // Collection is the time that it takes after pressing one key and then reading
andrewhead 3:ed89297af2ce 10 // all the keys to determine what the chord is.
andrewhead 3:ed89297af2ce 11 const int COLLECTION_MS = 500;
andrewhead 3:ed89297af2ce 12 Timer collectionTimer;
andrewhead 1:b6b866a58a87 13
andrewhead 1:b6b866a58a87 14 InterruptIn buttons [BUTTONS] = {
andrewhead 2:49e2b1273f16 15 InterruptIn(D2),
andrewhead 1:b6b866a58a87 16 InterruptIn(D4),
andrewhead 1:b6b866a58a87 17 InterruptIn(D5),
andrewhead 1:b6b866a58a87 18 InterruptIn(D8),
andrewhead 1:b6b866a58a87 19 InterruptIn(D9),
andrewhead 1:b6b866a58a87 20 InterruptIn(D10),
andrewhead 2:49e2b1273f16 21 InterruptIn(D11)
andrewhead 1:b6b866a58a87 22 };
andrewhead 0:5ffec551c755 23 Serial pc(USBTX, USBRX);
andrewhead 1:b6b866a58a87 24
andrewhead 1:b6b866a58a87 25 // Note: there are only THREE PWMs on the board. So this is all we can use
andrewhead 1:b6b866a58a87 26 // for this particular method of sound output. The pins chosen are important
andrewhead 1:b6b866a58a87 27 // because the same PWM will map to multiple outputs. See the reference
andrewhead 1:b6b866a58a87 28 // manual for Mbed for which pins map to distinct PWMs.
andrewhead 1:b6b866a58a87 29 PwmOut buzzers [3] = {
andrewhead 1:b6b866a58a87 30 PwmOut(D0),
andrewhead 1:b6b866a58a87 31 PwmOut(D7),
andrewhead 1:b6b866a58a87 32 PwmOut(D3)
andrewhead 0:5ffec551c755 33 };
andrewhead 0:5ffec551c755 34
andrewhead 0:5ffec551c755 35 // Periods of notes in microseconds
andrewhead 0:5ffec551c755 36 int notePeriods [8] = {
andrewhead 0:5ffec551c755 37 3818, // C4
andrewhead 0:5ffec551c755 38 3412, // D4
andrewhead 0:5ffec551c755 39 3030, // E4
andrewhead 0:5ffec551c755 40 2895, // F4
andrewhead 0:5ffec551c755 41 2551, // G4
andrewhead 0:5ffec551c755 42 2273, // A4
andrewhead 0:5ffec551c755 43 2024, // B4
andrewhead 0:5ffec551c755 44 10000000 // inaudible pitch
andrewhead 0:5ffec551c755 45 };
andrewhead 3:ed89297af2ce 46 // Possible chords that can be played.
andrewhead 3:ed89297af2ce 47 // Note that 7 is no button pressed, or a 'silent' pitch.
andrewhead 0:5ffec551c755 48 int chords [LETTERS][BUZZERS] = {
andrewhead 3:ed89297af2ce 49 {0, 7, 7}, // single notes
andrewhead 0:5ffec551c755 50 {1, 7, 7},
andrewhead 0:5ffec551c755 51 {2, 7, 7},
andrewhead 0:5ffec551c755 52 {3, 7, 7},
andrewhead 0:5ffec551c755 53 {4, 7, 7},
andrewhead 0:5ffec551c755 54 {5, 7, 7},
andrewhead 0:5ffec551c755 55 {6, 7, 7},
andrewhead 0:5ffec551c755 56 {0, 2, 7}, // diads
andrewhead 0:5ffec551c755 57 {0, 3, 7},
andrewhead 0:5ffec551c755 58 {0, 4, 7},
andrewhead 0:5ffec551c755 59 {0, 5, 7},
andrewhead 0:5ffec551c755 60 {1, 3, 7},
andrewhead 0:5ffec551c755 61 {1, 4, 7},
andrewhead 0:5ffec551c755 62 {1, 5, 7},
andrewhead 0:5ffec551c755 63 {1, 6, 7},
andrewhead 0:5ffec551c755 64 {2, 4, 7},
andrewhead 0:5ffec551c755 65 {2, 5, 7},
andrewhead 0:5ffec551c755 66 {2, 6, 7},
andrewhead 0:5ffec551c755 67 {3, 4, 7},
andrewhead 0:5ffec551c755 68 {3, 5, 7},
andrewhead 0:5ffec551c755 69 {4, 6, 7},
andrewhead 0:5ffec551c755 70 {0, 2, 4}, // triads
andrewhead 0:5ffec551c755 71 {0, 2, 5},
andrewhead 0:5ffec551c755 72 {0, 3, 5},
andrewhead 0:5ffec551c755 73 {1, 4, 6},
andrewhead 0:5ffec551c755 74 {1, 3, 4},
andrewhead 0:5ffec551c755 75 {1, 3, 6}
andrewhead 0:5ffec551c755 76 };
andrewhead 0:5ffec551c755 77
andrewhead 4:400a042e762a 78 void playChord(int chordIndex) {
andrewhead 4:400a042e762a 79 int *chord = chords[chordIndex];
andrewhead 4:400a042e762a 80 for (int i = 0; i < BUZZERS; i++) {
andrewhead 4:400a042e762a 81 int noteIndex = chord[i];
andrewhead 4:400a042e762a 82 if (noteIndex == 7) {
andrewhead 4:400a042e762a 83 buzzers[i] = 0;
andrewhead 0:5ffec551c755 84 }
andrewhead 4:400a042e762a 85 else {
andrewhead 4:400a042e762a 86 buzzers[i] = .5f;
andrewhead 4:400a042e762a 87 int period = notePeriods[noteIndex];
andrewhead 4:400a042e762a 88 buzzers[i].period_us(period);
andrewhead 4:400a042e762a 89 }
andrewhead 0:5ffec551c755 90 }
andrewhead 0:5ffec551c755 91 }
andrewhead 0:5ffec551c755 92
andrewhead 1:b6b866a58a87 93 void setFlag() {
andrewhead 3:ed89297af2ce 94 collectionTimer.start();
andrewhead 1:b6b866a58a87 95 }
andrewhead 1:b6b866a58a87 96
andrewhead 1:b6b866a58a87 97 void silenceBuzzers(void) {
andrewhead 0:5ffec551c755 98 // Initialize all duty cycles to off, so we hear nothing.
andrewhead 0:5ffec551c755 99 for (int i = 0; i < BUZZERS; i++) {
andrewhead 0:5ffec551c755 100 buzzers[i] = 0.0f;
andrewhead 0:5ffec551c755 101 }
andrewhead 1:b6b866a58a87 102 }
andrewhead 1:b6b866a58a87 103
andrewhead 1:b6b866a58a87 104 void registerButtonInterrupts(void) {
andrewhead 1:b6b866a58a87 105 for (int i = 0; i < BUTTONS; i++) {
andrewhead 1:b6b866a58a87 106 buttons[i].rise(&setFlag);
andrewhead 1:b6b866a58a87 107 }
andrewhead 1:b6b866a58a87 108 }
andrewhead 1:b6b866a58a87 109
andrewhead 3:ed89297af2ce 110 int readChord(void) {
andrewhead 3:ed89297af2ce 111 /* Detect the current chord from the keys pressed. Return int index of chord.
andrewhead 3:ed89297af2ce 112 Return -1 if no chord can be found with the current keys.
andrewhead 3:ed89297af2ce 113 Note that we can only read as many keys as there are buzzers, so check
andrewhead 3:ed89297af2ce 114 on each key in an ascending order. */
andrewhead 3:ed89297af2ce 115 int firstThreeButtons[BUZZERS] = {7, 7, 7};
andrewhead 3:ed89297af2ce 116 int pressedCount = 0;
andrewhead 3:ed89297af2ce 117 for (int i = 0; i < BUTTONS; i++) {
andrewhead 3:ed89297af2ce 118 if (buttons[i].read() == 1) {
andrewhead 3:ed89297af2ce 119 firstThreeButtons[pressedCount] = i;
andrewhead 3:ed89297af2ce 120 pressedCount++;
andrewhead 3:ed89297af2ce 121 }
andrewhead 3:ed89297af2ce 122 if (pressedCount >= BUZZERS) {
andrewhead 3:ed89297af2ce 123 break;
andrewhead 3:ed89297af2ce 124 }
andrewhead 3:ed89297af2ce 125 }
andrewhead 3:ed89297af2ce 126 int matchIndex = -1;
andrewhead 3:ed89297af2ce 127 for (int i = 0; i < LETTERS; i++) {
andrewhead 3:ed89297af2ce 128 bool chordMatches = true;
andrewhead 3:ed89297af2ce 129 for (int j = 0; j < BUZZERS; j++) {
andrewhead 3:ed89297af2ce 130 if (firstThreeButtons[j] != chords[i][j]) {
andrewhead 3:ed89297af2ce 131 chordMatches = false;
andrewhead 3:ed89297af2ce 132 break;
andrewhead 3:ed89297af2ce 133 }
andrewhead 3:ed89297af2ce 134 }
andrewhead 3:ed89297af2ce 135 if (chordMatches == true) {
andrewhead 3:ed89297af2ce 136 matchIndex = i;
andrewhead 3:ed89297af2ce 137 break;
andrewhead 3:ed89297af2ce 138 }
andrewhead 3:ed89297af2ce 139 }
andrewhead 3:ed89297af2ce 140 pc.printf("Matched chord %d\n", matchIndex);
andrewhead 3:ed89297af2ce 141 return matchIndex;
andrewhead 3:ed89297af2ce 142 }
andrewhead 3:ed89297af2ce 143
andrewhead 1:b6b866a58a87 144 void waitForChord(void) {
andrewhead 3:ed89297af2ce 145 /* This method should be run in the main loop so that it can print */
andrewhead 1:b6b866a58a87 146 while (true) {
andrewhead 3:ed89297af2ce 147 if (collectionTimer.read_ms() > COLLECTION_MS) {
andrewhead 3:ed89297af2ce 148 collectionTimer.stop();
andrewhead 3:ed89297af2ce 149 collectionTimer.reset();
andrewhead 3:ed89297af2ce 150 int chordIndex = readChord();
andrewhead 4:400a042e762a 151 if (chordIndex != -1) {
andrewhead 4:400a042e762a 152 playChord(chordIndex);
andrewhead 4:400a042e762a 153 }
andrewhead 1:b6b866a58a87 154 }
andrewhead 3:ed89297af2ce 155 wait_ms(10);
andrewhead 1:b6b866a58a87 156 }
andrewhead 1:b6b866a58a87 157 }
andrewhead 1:b6b866a58a87 158
andrewhead 1:b6b866a58a87 159 int main() {
andrewhead 1:b6b866a58a87 160 silenceBuzzers();
andrewhead 1:b6b866a58a87 161 registerButtonInterrupts();
andrewhead 1:b6b866a58a87 162 waitForChord();
andrewhead 0:5ffec551c755 163 }