Last active
September 3, 2016 17:28
-
-
Save wware/f52f30df10634ae30f78a1ce4b4af407 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import os | |
import re | |
import time | |
import subprocess | |
os.system("ps ax | grep fluidsynth | cut -c -6 | xargs kill -9") | |
devnull = os.open('/dev/null', os.O_WRONLY) | |
cmd = [ | |
'fluidsynth', | |
'--server', | |
'--no-shell', | |
'--audio-driver=alsa', | |
'-o', 'audio.alsa.device=hw:1,0', | |
'/usr/share/sounds/sf2/FluidR3_GM.sf2', | |
] | |
print ' '.join(cmd) | |
p = subprocess.Popen( | |
cmd, | |
shell=False, | |
stdout=devnull, | |
stderr=devnull | |
) | |
fluid_pid = p.pid | |
# We might want to kill this process later. | |
open(os.environ['HOME'] + '/fluidsynth.pid', 'w').write('%d' % fluid_pid) | |
time.sleep(1) | |
R = os.popen('aconnect -l').read() | |
r2 = re.compile(r"client (\d+): 'FLUID Synth").search(R) | |
assert r2 | |
fluid_num = r2.group(1) | |
connected = False | |
while True: | |
time.sleep(1) | |
R = os.popen('aconnect -l').read() | |
r1 = re.compile(r"client (\d+): 'Teensy MIDI'").search(R) | |
if not r1: | |
connected = False | |
continue | |
if connected: | |
continue | |
connect_cmd = [ | |
'aconnect', | |
r1.group(1), | |
r2.group(1) | |
] | |
print ' '.join(connect_cmd) | |
subprocess.Popen( | |
connect_cmd, | |
shell=False, | |
stdout=devnull, | |
stderr=devnull | |
) | |
connected = True |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _KEYBOARD 0 | |
#define NUM_KEYS 40 | |
#define DIAGNOSTICS 0 | |
#define KEYDOWN_HYSTERESIS 10 | |
#define PIANO 0 | |
#define CELESTA 10 | |
#define TUBULAR_BELLS 14 | |
#define CHURCH_ORGAN 19 | |
#define NYLON_GUITAR 24 | |
#define CELLO 42 | |
#define ORCHESTRAL_HARP 46 | |
#define CHOIR_AAHS 52 | |
#define TRUMPET 56 | |
#define SYNTH_BRASS 62 | |
#define ALTO_SAX 65 | |
#define FLUTE 73 | |
#define INH0 2 | |
#define INH1 14 | |
#define INH2 7 | |
#define INH3 6 | |
#define INH4 8 | |
uint32_t inhibits[] = {INH0, INH1, INH2, INH3, INH4}; | |
#define A_SELECT 15 | |
#define B_SELECT 22 | |
#define C_SELECT 23 | |
// Port A, Port C, Port D | |
uint32_t port_settings[2 * NUM_KEYS]; | |
#define PORT_A 0x400FF000 | |
#define PORT_C 0x400FF080 | |
#define PORT_D 0x400FF0C0 | |
static inline uint32_t read_key(uint32_t X, uint32_t Y, uint32_t portc) { | |
// offset 4 is set output | |
// offset 8 is clear output | |
// offset 16 is read input | |
asm volatile( | |
// digitalWrite(9, LOW); | |
"mov %0, #0x08" "\n" | |
"str %0, [%2, #8]" "\n" | |
// X = 20; | |
"mov %0, #20" "\n" | |
// while (X > 0) X--; | |
"1:" "\n" | |
"subs %0, %0, #1" "\n" | |
"bne 1b" "\n" | |
// digitalWrite(9, HIGH); | |
"mov %0, #0x08" "\n" | |
"str %0, [%2, #4]" "\n" | |
// while (Y > 0) Y--; | |
"2:" "\n" | |
"subs %1, %1, #1" "\n" | |
"bne 2b" "\n" | |
// X = digitalReadFast(10); | |
"ldr %0, [%2, #16]" "\n" | |
"ands %0, %0, #0x10" "\n" | |
// digitalWrite(9, LOW); | |
"mov %1, #0x08" "\n" | |
"str %1, [%2, #8]" "\n" | |
: "+r" (X), "+r" (Y), "+r" (portc) | |
); | |
return !X; | |
} | |
int h = 0; | |
class Key | |
{ | |
public: | |
uint32_t threshold; | |
uint32_t successive_approximate(uint32_t lo, uint32_t hi) { | |
if (hi < lo) return successive_approximate(hi, lo); | |
if (hi - lo <= 1) return hi; | |
uint32_t mid = (lo + hi) >> 1; | |
if (!read_n(mid)) | |
return successive_approximate(lo, mid); | |
else | |
return successive_approximate(mid, hi); | |
} | |
bool read_n(uint32_t n) { | |
digitalWrite(A_SELECT, (id & 1) ? HIGH : LOW); | |
digitalWrite(B_SELECT, (id & 2) ? HIGH : LOW); | |
digitalWrite(C_SELECT, (id & 4) ? HIGH : LOW); | |
int i; | |
for (i = 0; i < 5; i++) { | |
if (i == (id >> 3)) | |
digitalWrite(inhibits[i], LOW); | |
else | |
digitalWrite(inhibits[i], HIGH); | |
} | |
return read_key(0, n, PORT_C); | |
} | |
/** | |
* A numerical index of this key, used to identify it for keyboard scanning. | |
*/ | |
uint32_t id; | |
/** | |
* 1 if the key is pressed/touched, 0 otherwise. | |
*/ | |
uint32_t state; | |
/** | |
* This counter is used for hysteresis (debouncing). | |
*/ | |
uint32_t count; | |
/** | |
* An integer, increments for each half-tone in pitch. | |
*/ | |
int8_t pitch; | |
Key(uint32_t _id) { | |
id = _id; | |
count = state = 0; | |
} | |
int fresh_calibrate(void) { | |
threshold = 0; | |
return calibrate(); | |
} | |
int calibrate(void) { | |
const int _max = 250; | |
int previous = 0, n; | |
for (n = 1; n < _max; n <<=1) { | |
if (!read_n(n)) { | |
threshold = | |
max(threshold, successive_approximate(previous, n) + 1); | |
return threshold; | |
} | |
previous = n; | |
} | |
threshold = max(threshold, _max); // out of luck, probably | |
return threshold; | |
} | |
/** | |
* Detect whether a key is being pressed or touched. This is a single | |
* detection prior to any debouncing logic. | |
*/ | |
bool read(void) { | |
return read_n(threshold); | |
} | |
/** | |
* Checks to see if this key is being pressed/touched. Debounces using a | |
* hysteresis state machine. | |
*/ | |
void check(void) { | |
if (read()) { | |
if (state) { | |
count = 0; | |
} else { | |
if (count < KEYDOWN_HYSTERESIS) { | |
count++; | |
if (count == KEYDOWN_HYSTERESIS) { | |
state = 1; | |
count = 0; | |
keydown(); | |
} | |
} | |
} | |
} else { | |
if (!state) { | |
count = 0; | |
} else { | |
if (count < KEYDOWN_HYSTERESIS) { | |
count++; | |
if (count == KEYDOWN_HYSTERESIS) { | |
state = 0; | |
count = 0; | |
keyup(); | |
} | |
} | |
} | |
} | |
} | |
virtual void keydown(void) { | |
usbMIDI.sendNoteOn(pitch, 127, 1); | |
} | |
virtual void keyup(void) { | |
usbMIDI.sendNoteOff(pitch, 0, 1); | |
} | |
}; | |
Key *keyboard[NUM_KEYS]; | |
class FunctionKey : public Key | |
{ | |
void keyup(void) { /* nada */ } | |
void keydown(void) { | |
switch (id) { | |
case 4: | |
break; | |
default: | |
break; | |
} | |
} | |
}; | |
void setup() { | |
uint8_t j; | |
pinMode(LED_BUILTIN, OUTPUT); | |
#if _KEYBOARD | |
uint8_t i; | |
usbMIDI.sendProgramChange(CHOIR_AAHS, 1); | |
pinMode(10, INPUT_PULLUP); | |
pinMode(9, OUTPUT); | |
digitalWrite(9, LOW); | |
pinMode(2, OUTPUT); | |
pinMode(6, OUTPUT); | |
pinMode(7, OUTPUT); | |
pinMode(8, OUTPUT); | |
pinMode(14, OUTPUT); | |
pinMode(15, OUTPUT); | |
pinMode(22, OUTPUT); | |
pinMode(23, OUTPUT); | |
for (i = 0; i < NUM_KEYS; i++) { | |
keyboard[i] = new Key(i); | |
keyboard[i]->pitch = 60 + i; | |
} | |
for (i = 0; i < NUM_KEYS; i++) { | |
keyboard[i]->fresh_calibrate(); | |
} | |
for (j = 0; j < 3; j++) { | |
for (i = 0; i < NUM_KEYS; i++) { | |
keyboard[i]->calibrate(); | |
} | |
} | |
#endif | |
} | |
uint8_t scanned_key = 0; | |
int chords[4][6] = { | |
{ 60, 64, 67, 70, 72, 76 }, // C major with B flat | |
{ 60, 65, 69, 72, 77, 81 }, // F major | |
{ 62, 65, 67, 71, 74, 77 }, // G major with F | |
{ 60, 64, 67, 72, 76, 79 } // C major | |
}; | |
void loop(void) { | |
static uint8_t led_on = 0; | |
int i; | |
static int j = 0; | |
if (scanned_key == 0) { | |
// toggle the LED | |
digitalWrite(LED_BUILTIN, led_on); | |
led_on = !led_on; | |
} | |
#if _KEYBOARD | |
keyboard[scanned_key]->check(); | |
scanned_key = (scanned_key + 1) % NUM_KEYS; | |
#else | |
delayMicroseconds(500000); | |
switch (j) { | |
case 0: | |
usbMIDI.sendProgramChange(NYLON_GUITAR, 1); | |
break; | |
case 1: | |
usbMIDI.sendProgramChange(CELESTA, 1); | |
break; | |
case 2: | |
usbMIDI.sendProgramChange(TRUMPET, 1); | |
break; | |
case 3: | |
usbMIDI.sendProgramChange(FLUTE, 1); | |
break; | |
} | |
for (i = 0; i < 6; i++) { | |
usbMIDI.sendNoteOn(chords[j][i], 127, 1); | |
delayMicroseconds(100000); | |
} | |
delayMicroseconds(50000); | |
for (i = 0; i < 6; i++) { | |
usbMIDI.sendNoteOff(chords[j][i], 0, 1); | |
delayMicroseconds(100000); | |
} | |
j = (j + 1) % 4; | |
if (j == 0) delayMicroseconds(500000); | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment