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

main.cpp

Committer:
andrewhead
Date:
2014-09-22
Revision:
5:1186eb1f3c2b
Parent:
4:400a042e762a

File content as of revision 5:1186eb1f3c2b:

#include "mbed.h"
#include "rtos.h"


const int BUTTONS = 7;
const int BUZZERS = 3;
const int LETTERS = 27;

// Collection is the time that it takes after pressing one key and then reading
// all the keys to determine what the chord is.
const int COLLECTION_MS = 200;
Timer collectionTimer;

InterruptIn buttons [BUTTONS] = {
    InterruptIn(D2),
    InterruptIn(D4),
    InterruptIn(D5),
    InterruptIn(D8),
    InterruptIn(D9),
    InterruptIn(D10),
    InterruptIn(D11)
};
Serial pc(USBTX, USBRX);

// Note: there are only THREE PWMs on the board. So this is all we can use
// for this particular method of sound output. The pins chosen are important
// because the same PWM will map to multiple outputs. See the reference
// manual for Mbed for which pins map to distinct PWMs.
PwmOut buzzers [3] = {
    PwmOut(D0),
    PwmOut(D7),
    PwmOut(D3)
};

// Periods of notes in microseconds
int notePeriods [8] = {
    3818,   // C4
    3412,   // D4
    3030,   // E4
    2895,   // F4
    2551,   // G4
    2273,   // A4
    2024,   // B4
    10000000 // inaudible pitch
};
// Possible chords that can be played.
// Chords consist of 3 notes, and an integer for the ASCII character
//  that it will output via serial.
// Note that 7 is no button pressed, or a 'silent' pitch.
int chords [LETTERS][BUZZERS + 1] = {
    {0, 7, 7, 114}, // single notes
    {1, 7, 7, 32},
    {2, 7, 7, 106},
    {3, 7, 7, 107},
    {4, 7, 7, 109},
    {5, 7, 7, 113},
    {6, 7, 7, 122},
    {0, 2, 7, 115}, // diads
    {0, 3, 7, 112},
    {0, 4, 7, 110},
    {0, 5, 7, 102},
    {1, 3, 7, 105},
    {1, 4, 7, 98},
    {1, 5, 7, 103},
    {1, 6, 7, 104},
    {2, 4, 7, 100},
    {2, 5, 7, 121},
    {2, 6, 7, 120},
    {3, 4, 7, 99},
    {3, 5, 7, 117},
    {4, 6, 7, 119},
    {0, 2, 4, 101}, // triads
    {0, 2, 5, 118},
    {0, 3, 5, 108},
    {1, 3, 6, 97},
    {1, 4, 6, 116},
    {1, 3, 4, 111}
};

void playChord(int chordIndex) {
    int *chord = chords[chordIndex];
    for (int i = 0; i < BUZZERS; i++) {
        int noteIndex = chord[i];
        if (noteIndex == 7) {
            buzzers[i] = 0;
        }
        else {
            buzzers[i] = .5f;
            int period = notePeriods[noteIndex];
            buzzers[i].period_us(period);
        }
    }
}

void setFlag() {
    collectionTimer.start();
}

void silenceBuzzers(void) {
    // Initialize all duty cycles to off, so we hear nothing.
    for (int i = 0; i < BUZZERS; i++) {
        buzzers[i] = 0.0f;
    }
}

void registerButtonInterrupts(void) {
    for (int i =  0; i < BUTTONS; i++) {
        buttons[i].fall(&setFlag);
    }   
}

int readChord(void) {
    /* Detect the current chord from the keys pressed. Return int index of chord.
       Return -1 if no chord can be found with the current keys.
       Note that we can only read as many keys as there are buzzers, so check
       on each key in an ascending order. */
    int firstThreeButtons[BUZZERS] = {7, 7, 7};
    int pressedCount = 0;
    for (int i = 0; i < BUTTONS; i++) {
        if (buttons[i].read() == 0) {
            firstThreeButtons[pressedCount] = i;
            pressedCount++;   
        }
        if (pressedCount >= BUZZERS) {
            break;
        }
    }
    int matchIndex = -1;
    for (int i = 0; i < LETTERS; i++) {
        bool chordMatches = true;
        for (int j = 0; j < BUZZERS; j++) {
            if (firstThreeButtons[j] != chords[i][j]) {
                chordMatches = false;
                break;            
            }
        }
        if (chordMatches == true) {
            matchIndex = i;
            break;
        }
    }
    // pc.printf("Matched chord %d\n", matchIndex);
    return matchIndex;
}

void waitForChord(void) {
     /* This method should be run in the main loop so that it can print */
     while (true) {
        if (collectionTimer.read_ms() > COLLECTION_MS) {
            collectionTimer.stop();
            collectionTimer.reset();
            int chordIndex = readChord();
            if (chordIndex != -1) {
                playChord(chordIndex);
                int charAscii = chords[chordIndex][BUZZERS];
                pc.printf("%c", charAscii);
            }
        }
        wait_ms(10);
    }   
}

int main() {
    silenceBuzzers();
    registerButtonInterrupts();
    waitForChord();
}