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 Interactive Device Design

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?

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 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 }