Skip to content

Instantly share code, notes, and snippets.

@stianeikeland
Last active August 29, 2015 14:19
Show Gist options
  • Save stianeikeland/09f2bd28ea9c99e1b10e to your computer and use it in GitHub Desktop.
Save stianeikeland/09f2bd28ea9c99e1b10e to your computer and use it in GitHub Desktop.
🍌🎹 Banana piano
(ns musikk.core
(:require [serial-port :as serial]
[overtone.live :refer :all]
[overtone.inst.sampled-piano :refer :all]))
(def port (serial/open "/dev/tty.usbserial-A800F185" 57600))
(defn chr->int [c]
(-> (char c)
(str)
(Integer.)))
(defn handle-press [input]
(let [idx (chr->int input)
scale (scale :C3 :major)
note (nth scale idx)]
(sampled-piano note)))
(serial/remove-listener port)
(serial/on-byte port handle-press)
const int PORTS[8] = { 2, 3, 4, 5, 6, 7, 8, 9 };
const int THRESHOLDS[8] = { 7, 7, 7, 7, 7, 7, 7, 7 };
bool touched[8];
uint8_t readCapacitivePin(int pinToMeasure) {
// Variables used to translate from Arduino to AVR pin naming
volatile uint8_t* port;
volatile uint8_t* ddr;
volatile uint8_t* pin;
// Here we translate the input pin number from
// Arduino pin number to the AVR PORT, PIN, DDR,
// and which bit of those registers we care about.
byte bitmask;
port = portOutputRegister(digitalPinToPort(pinToMeasure));
ddr = portModeRegister(digitalPinToPort(pinToMeasure));
bitmask = digitalPinToBitMask(pinToMeasure);
pin = portInputRegister(digitalPinToPort(pinToMeasure));
// Discharge the pin first by setting it low and output
*port &= ~(bitmask);
*ddr |= bitmask;
delay(1);
// Prevent the timer IRQ from disturbing our measurement
noInterrupts();
// Make the pin an input with the internal pull-up on
*ddr &= ~(bitmask);
*port |= bitmask;
// Now see how long the pin to get pulled up. This manual unrolling of the loop
// decreases the number of hardware cycles between each read of the pin,
// thus increasing sensitivity.
uint8_t cycles = 17;
if (*pin & bitmask) { cycles = 0;}
else if (*pin & bitmask) { cycles = 1;}
else if (*pin & bitmask) { cycles = 2;}
else if (*pin & bitmask) { cycles = 3;}
else if (*pin & bitmask) { cycles = 4;}
else if (*pin & bitmask) { cycles = 5;}
else if (*pin & bitmask) { cycles = 6;}
else if (*pin & bitmask) { cycles = 7;}
else if (*pin & bitmask) { cycles = 8;}
else if (*pin & bitmask) { cycles = 9;}
else if (*pin & bitmask) { cycles = 10;}
else if (*pin & bitmask) { cycles = 11;}
else if (*pin & bitmask) { cycles = 12;}
else if (*pin & bitmask) { cycles = 13;}
else if (*pin & bitmask) { cycles = 14;}
else if (*pin & bitmask) { cycles = 15;}
else if (*pin & bitmask) { cycles = 16;}
// End of timing-critical section
interrupts();
// Discharge the pin again by setting it low and output
// It's important to leave the pins low if you want to
// be able to touch more than 1 sensor at a time - if
// the sensor is left pulled high, when you touch
// two sensors, your body will transfer the charge between
// sensors.
*port &= ~(bitmask);
*ddr |= bitmask;
return cycles;
}
void setup() {
Serial.begin(57600);
}
void handlePort(int index) {
int cycles = readCapacitivePin(PORTS[index]);
if (!touched[index] && cycles >= THRESHOLDS[index]) {
touched[index] = true;
Serial.print(index);
}
if (touched[index] && cycles < THRESHOLDS[index]) {
touched[index] = false;
}
}
void loop() {
for (int i = 0; i < 8; i++) {
handlePort(i);
delay(10); // cheap-ass debounce..
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment