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
Fork of ChordJoy by
main.cpp@5:1186eb1f3c2b, 2014-09-22 (annotated)
- Committer:
- andrewhead
- Date:
- Mon Sep 22 06:14:29 2014 +0000
- Revision:
- 5:1186eb1f3c2b
- Parent:
- 4:400a042e762a
Ready to publish.
Who changed what in which revision?
User | Revision | Line number | New 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 | 5:1186eb1f3c2b | 11 | const int COLLECTION_MS = 200; |
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 | 5:1186eb1f3c2b | 47 | // Chords consist of 3 notes, and an integer for the ASCII character |
andrewhead | 5:1186eb1f3c2b | 48 | // that it will output via serial. |
andrewhead | 3:ed89297af2ce | 49 | // Note that 7 is no button pressed, or a 'silent' pitch. |
andrewhead | 5:1186eb1f3c2b | 50 | int chords [LETTERS][BUZZERS + 1] = { |
andrewhead | 5:1186eb1f3c2b | 51 | {0, 7, 7, 114}, // single notes |
andrewhead | 5:1186eb1f3c2b | 52 | {1, 7, 7, 32}, |
andrewhead | 5:1186eb1f3c2b | 53 | {2, 7, 7, 106}, |
andrewhead | 5:1186eb1f3c2b | 54 | {3, 7, 7, 107}, |
andrewhead | 5:1186eb1f3c2b | 55 | {4, 7, 7, 109}, |
andrewhead | 5:1186eb1f3c2b | 56 | {5, 7, 7, 113}, |
andrewhead | 5:1186eb1f3c2b | 57 | {6, 7, 7, 122}, |
andrewhead | 5:1186eb1f3c2b | 58 | {0, 2, 7, 115}, // diads |
andrewhead | 5:1186eb1f3c2b | 59 | {0, 3, 7, 112}, |
andrewhead | 5:1186eb1f3c2b | 60 | {0, 4, 7, 110}, |
andrewhead | 5:1186eb1f3c2b | 61 | {0, 5, 7, 102}, |
andrewhead | 5:1186eb1f3c2b | 62 | {1, 3, 7, 105}, |
andrewhead | 5:1186eb1f3c2b | 63 | {1, 4, 7, 98}, |
andrewhead | 5:1186eb1f3c2b | 64 | {1, 5, 7, 103}, |
andrewhead | 5:1186eb1f3c2b | 65 | {1, 6, 7, 104}, |
andrewhead | 5:1186eb1f3c2b | 66 | {2, 4, 7, 100}, |
andrewhead | 5:1186eb1f3c2b | 67 | {2, 5, 7, 121}, |
andrewhead | 5:1186eb1f3c2b | 68 | {2, 6, 7, 120}, |
andrewhead | 5:1186eb1f3c2b | 69 | {3, 4, 7, 99}, |
andrewhead | 5:1186eb1f3c2b | 70 | {3, 5, 7, 117}, |
andrewhead | 5:1186eb1f3c2b | 71 | {4, 6, 7, 119}, |
andrewhead | 5:1186eb1f3c2b | 72 | {0, 2, 4, 101}, // triads |
andrewhead | 5:1186eb1f3c2b | 73 | {0, 2, 5, 118}, |
andrewhead | 5:1186eb1f3c2b | 74 | {0, 3, 5, 108}, |
andrewhead | 5:1186eb1f3c2b | 75 | {1, 3, 6, 97}, |
andrewhead | 5:1186eb1f3c2b | 76 | {1, 4, 6, 116}, |
andrewhead | 5:1186eb1f3c2b | 77 | {1, 3, 4, 111} |
andrewhead | 0:5ffec551c755 | 78 | }; |
andrewhead | 0:5ffec551c755 | 79 | |
andrewhead | 4:400a042e762a | 80 | void playChord(int chordIndex) { |
andrewhead | 4:400a042e762a | 81 | int *chord = chords[chordIndex]; |
andrewhead | 4:400a042e762a | 82 | for (int i = 0; i < BUZZERS; i++) { |
andrewhead | 4:400a042e762a | 83 | int noteIndex = chord[i]; |
andrewhead | 4:400a042e762a | 84 | if (noteIndex == 7) { |
andrewhead | 4:400a042e762a | 85 | buzzers[i] = 0; |
andrewhead | 0:5ffec551c755 | 86 | } |
andrewhead | 4:400a042e762a | 87 | else { |
andrewhead | 4:400a042e762a | 88 | buzzers[i] = .5f; |
andrewhead | 4:400a042e762a | 89 | int period = notePeriods[noteIndex]; |
andrewhead | 4:400a042e762a | 90 | buzzers[i].period_us(period); |
andrewhead | 4:400a042e762a | 91 | } |
andrewhead | 0:5ffec551c755 | 92 | } |
andrewhead | 0:5ffec551c755 | 93 | } |
andrewhead | 0:5ffec551c755 | 94 | |
andrewhead | 1:b6b866a58a87 | 95 | void setFlag() { |
andrewhead | 3:ed89297af2ce | 96 | collectionTimer.start(); |
andrewhead | 1:b6b866a58a87 | 97 | } |
andrewhead | 1:b6b866a58a87 | 98 | |
andrewhead | 1:b6b866a58a87 | 99 | void silenceBuzzers(void) { |
andrewhead | 0:5ffec551c755 | 100 | // Initialize all duty cycles to off, so we hear nothing. |
andrewhead | 0:5ffec551c755 | 101 | for (int i = 0; i < BUZZERS; i++) { |
andrewhead | 0:5ffec551c755 | 102 | buzzers[i] = 0.0f; |
andrewhead | 0:5ffec551c755 | 103 | } |
andrewhead | 1:b6b866a58a87 | 104 | } |
andrewhead | 1:b6b866a58a87 | 105 | |
andrewhead | 1:b6b866a58a87 | 106 | void registerButtonInterrupts(void) { |
andrewhead | 1:b6b866a58a87 | 107 | for (int i = 0; i < BUTTONS; i++) { |
andrewhead | 5:1186eb1f3c2b | 108 | buttons[i].fall(&setFlag); |
andrewhead | 1:b6b866a58a87 | 109 | } |
andrewhead | 1:b6b866a58a87 | 110 | } |
andrewhead | 1:b6b866a58a87 | 111 | |
andrewhead | 3:ed89297af2ce | 112 | int readChord(void) { |
andrewhead | 3:ed89297af2ce | 113 | /* Detect the current chord from the keys pressed. Return int index of chord. |
andrewhead | 3:ed89297af2ce | 114 | Return -1 if no chord can be found with the current keys. |
andrewhead | 3:ed89297af2ce | 115 | Note that we can only read as many keys as there are buzzers, so check |
andrewhead | 3:ed89297af2ce | 116 | on each key in an ascending order. */ |
andrewhead | 3:ed89297af2ce | 117 | int firstThreeButtons[BUZZERS] = {7, 7, 7}; |
andrewhead | 3:ed89297af2ce | 118 | int pressedCount = 0; |
andrewhead | 3:ed89297af2ce | 119 | for (int i = 0; i < BUTTONS; i++) { |
andrewhead | 5:1186eb1f3c2b | 120 | if (buttons[i].read() == 0) { |
andrewhead | 3:ed89297af2ce | 121 | firstThreeButtons[pressedCount] = i; |
andrewhead | 3:ed89297af2ce | 122 | pressedCount++; |
andrewhead | 3:ed89297af2ce | 123 | } |
andrewhead | 3:ed89297af2ce | 124 | if (pressedCount >= BUZZERS) { |
andrewhead | 3:ed89297af2ce | 125 | break; |
andrewhead | 3:ed89297af2ce | 126 | } |
andrewhead | 3:ed89297af2ce | 127 | } |
andrewhead | 3:ed89297af2ce | 128 | int matchIndex = -1; |
andrewhead | 3:ed89297af2ce | 129 | for (int i = 0; i < LETTERS; i++) { |
andrewhead | 3:ed89297af2ce | 130 | bool chordMatches = true; |
andrewhead | 3:ed89297af2ce | 131 | for (int j = 0; j < BUZZERS; j++) { |
andrewhead | 3:ed89297af2ce | 132 | if (firstThreeButtons[j] != chords[i][j]) { |
andrewhead | 3:ed89297af2ce | 133 | chordMatches = false; |
andrewhead | 3:ed89297af2ce | 134 | break; |
andrewhead | 3:ed89297af2ce | 135 | } |
andrewhead | 3:ed89297af2ce | 136 | } |
andrewhead | 3:ed89297af2ce | 137 | if (chordMatches == true) { |
andrewhead | 3:ed89297af2ce | 138 | matchIndex = i; |
andrewhead | 3:ed89297af2ce | 139 | break; |
andrewhead | 3:ed89297af2ce | 140 | } |
andrewhead | 3:ed89297af2ce | 141 | } |
andrewhead | 5:1186eb1f3c2b | 142 | // pc.printf("Matched chord %d\n", matchIndex); |
andrewhead | 3:ed89297af2ce | 143 | return matchIndex; |
andrewhead | 3:ed89297af2ce | 144 | } |
andrewhead | 3:ed89297af2ce | 145 | |
andrewhead | 1:b6b866a58a87 | 146 | void waitForChord(void) { |
andrewhead | 3:ed89297af2ce | 147 | /* This method should be run in the main loop so that it can print */ |
andrewhead | 1:b6b866a58a87 | 148 | while (true) { |
andrewhead | 3:ed89297af2ce | 149 | if (collectionTimer.read_ms() > COLLECTION_MS) { |
andrewhead | 3:ed89297af2ce | 150 | collectionTimer.stop(); |
andrewhead | 3:ed89297af2ce | 151 | collectionTimer.reset(); |
andrewhead | 3:ed89297af2ce | 152 | int chordIndex = readChord(); |
andrewhead | 4:400a042e762a | 153 | if (chordIndex != -1) { |
andrewhead | 5:1186eb1f3c2b | 154 | playChord(chordIndex); |
andrewhead | 5:1186eb1f3c2b | 155 | int charAscii = chords[chordIndex][BUZZERS]; |
andrewhead | 5:1186eb1f3c2b | 156 | pc.printf("%c", charAscii); |
andrewhead | 4:400a042e762a | 157 | } |
andrewhead | 1:b6b866a58a87 | 158 | } |
andrewhead | 3:ed89297af2ce | 159 | wait_ms(10); |
andrewhead | 1:b6b866a58a87 | 160 | } |
andrewhead | 1:b6b866a58a87 | 161 | } |
andrewhead | 1:b6b866a58a87 | 162 | |
andrewhead | 1:b6b866a58a87 | 163 | int main() { |
andrewhead | 1:b6b866a58a87 | 164 | silenceBuzzers(); |
andrewhead | 1:b6b866a58a87 | 165 | registerButtonInterrupts(); |
andrewhead | 1:b6b866a58a87 | 166 | waitForChord(); |
andrewhead | 0:5ffec551c755 | 167 | } |