Post on 31-Aug-2014
description
@neilmendoza
Musical Machines and Flapping Phones !
Neil Mendoza
@neilmendoza
Who are you?
@neilmendoza
@neilmendoza
@neilmendoza
@neilmendoza
@neilmendoza
@neilmendoza
@neilmendoza
What are musical notes?
@neilmendoza
@neilmendoza
Melody: Stepper
@neilmendoza
What is a stepper?
@neilmendoza
Stepper Drivers
@neilmendoza
So many wires…
@neilmendoza
Measure resistance of coils…
@neilmendoza
@neilmendoza
#include <Stepper.h>!// change this to fit the number of steps per revolution// for your motorconst int stepsPerRevolution = 48; !// initialize the stepper library on the motor shieldStepper myStepper(stepsPerRevolution, 12,13); !// give the motor control pins names:const int pwmA = 3;const int pwmB = 11;const int brakeA = 9;const int brakeB = 8;const int dirA = 12;const int dirB = 13;!void setup(){ // set the PWM and brake pins so that the direction pins // can be used to control the motor: pinMode(pwmA, OUTPUT); pinMode(pwmB, OUTPUT); pinMode(brakeA, OUTPUT); pinMode(brakeB, OUTPUT); digitalWrite(pwmA, HIGH); digitalWrite(pwmB, HIGH); digitalWrite(brakeA, LOW); digitalWrite(brakeB, LOW);! // set the motor speed (for multiple steps only): myStepper.setSpeed(2);}!void loop(){ myStepper.step(48); myStepper.step(-48);! delay(2000);}
Motor Shield R3 Code
@neilmendoza
Step Direction Driver Code
int dirpin = 2;int steppin = 3;!void setup() { pinMode(dirpin, OUTPUT); pinMode(steppin, OUTPUT);}!void loop(){ int i;! digitalWrite(dirpin, LOW); // Set the direction. delay(100);!! for (i = 0; i<4000; i++) // Iterate for 4000 microsteps. { digitalWrite(steppin, LOW); // This LOW to HIGH change is what creates the digitalWrite(steppin, HIGH); // "Rising Edge" so the easydriver knows to when to step. delayMicroseconds(500); // This delay time is close to top speed for this } // particular motor. Any faster the motor stalls.! digitalWrite(dirpin, HIGH); // Change direction. delay(100);!! for (i = 0; i<4000; i++) // Iterate for 4000 microsteps { digitalWrite(steppin, LOW); // This LOW to HIGH change is what creates the digitalWrite(steppin, HIGH); // "Rising Edge" so the easydriver knows to when to step. delayMicroseconds(500); // This delay time is close to top speed for this } // particular motor. Any faster the motor stalls.}
@neilmendoza
Controller: MIDI
@neilmendoza
MIDI Circuit
@neilmendoza
Simple MIDI Code#include <SoftwareSerial.h>!int midiByte0 = -1;int midiByte1 = -1;int midiByte2 = -1;!#define HI_NIBBLE(b) (((b)>>4) & 0x0F)#define LO_NIBBLE(b) ((b) & 0x0F)!#define NOTE_ON_STATUS B1001#define NOTE_OFF_STATUS B1000#define CC_STATUS B1011#define PITCHBEND_STATUS B1110!#define MIDI_BAUD_RATE 31250!const int LED = 13;const int MIDI_IN = 8; !SoftwareSerial midiIn(MIDI_IN, 9); // RX, TX!void setup(){ pinMode(LED, OUTPUT); midiIn.begin(MIDI_BAUD_RATE);}!void loop(){ updateMidi(); }!void noteOn(int channel, int note, int vel){ digitalWrite(LED, HIGH);}!void noteOff(int channel, int note){ digitalWrite(LED, LOW);}
void updateMidi(){ int b = midiIn.read(); if(b!= -1) { midiByte2 = midiByte1; midiByte1 = midiByte0; midiByte0 = b; // only work if we've got a status byte // of some sort if(!(midiByte2 & B10000000)) return; int st = HI_NIBBLE(midiByte2); int channel = LO_NIBBLE(midiByte2); // now check to see if we have a midi if(st == NOTE_ON_STATUS) { if(midiByte0 == 0) { // if the volume is zero, it's a note off noteOff(channel, midiByte1); } else { noteOn(channel, midiByte1, midiByte0); } } else if(st == NOTE_OFF_STATUS) { noteOff(channel, midiByte1); } }}
@neilmendoza
MIDI to Frequency Code#include <SoftwareSerial.h> !int midiByte0 = -1; int midiByte1 = -1; int midiByte2 = -1; !#define HI_NIBBLE(b) (((b)>>4) & 0x0F) #define LO_NIBBLE(b) ((b) & 0x0F) !#define NOTE_ON_STATUS B1001 #define NOTE_OFF_STATUS B1000 #define CC_STATUS B1011 #define PITCHBEND_STATUS B1110 !#define MIDI_BAUD_RATE 31250 !const unsigned LED_PIN = 13; const unsigned STEP_PIN = 3; const unsigned DIR_PIN = 2; const unsigned MIDI_IN_PIN = 10; !SoftwareSerial midiIn(MIDI_IN_PIN, 9); // RX, TX !unsigned long halfPeriodMicros = 0; !void setup() { pinMode(LED_PIN, OUTPUT); pinMode(STEP_PIN, OUTPUT); pinMode(DIR_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); digitalWrite(STEP_PIN, LOW); digitalWrite(DIR_PIN, LOW); midiIn.begin(MIDI_BAUD_RATE); } !void loop() { if (halfPeriodMicros != 0) { digitalWrite(STEP_PIN, HIGH); delayMicroseconds(halfPeriodMicros); digitalWrite(STEP_PIN, LOW); delayMicroseconds(halfPeriodMicros); } }
!double midiToFrequency(int midiNote) { return 440.0 * exp(0.057762265 * (midiNote - 69.0)); } !void noteOn(int channel, int midiNote, int vel) { halfPeriodMicros = 0.5 * 1000000.0 / midiToFrequency(midiNote); digitalWrite(LED_PIN, HIGH); } !void noteOff(int channel, int midiNote) { halfPeriodMicros = 0; digitalWrite(LED_PIN, LOW); } !void updateMidi() { int b = midiIn.read(); if(b != -1) { midiByte2 = midiByte1; midiByte1 = midiByte0; midiByte0 = b; // only work if we've got a status byte // of some sort if(!(midiByte2 & B10000000)) return; int st = HI_NIBBLE(midiByte2); int channel = LO_NIBBLE(midiByte2); // now check to see if we have a midi if(st == NOTE_ON_STATUS) { if(midiByte0 == 0) { // if the volume is zero, it's a note off noteOff(channel, midiByte1); } else { noteOn(channel, midiByte1, midiByte0); } } else if(st == NOTE_OFF_STATUS) { noteOff(channel, midiByte1); } } }
@neilmendoza
Oscillator Code#include "Oscillator.h" unsigned long Oscillator::elapsedMicros = 0; !Oscillator::Oscillator(unsigned channel) : channel(channel), periodMicros(0), halfPeriodMicros(0) {} void Oscillator::noteOn(unsigned channel, unsigned note, unsigned vel) { if (this->channel == channel) { periodMicros = 1000000.0 / midiToFrequency(note); halfPeriodMicros = 0.5 * periodMicros; } }; !void Oscillator::noteOff(unsigned channel, unsigned note) { if (this->channel == channel) { periodMicros = 0; halfPeriodMicros = 0; } }; !void Oscillator::update() { if(periodMicros > 0) { unsigned long elapsedPeriodMicros = elapsedMicros % periodMicros; if(elapsedPeriodMicros > halfPeriodMicros != !wave) { // wave form has flipped wave = !wave; if (wave) risingEdge(); else fallingEdge(); } } }; !double Oscillator::midiToFrequency(int midiNote) { return 440.0 * exp(0.057762265 * (midiNote - 69.0)); }
@neilmendoza
DEMO
@neilmendoza
Percussion: Car Door Lock “Solenoid”
@neilmendoza
Driver Circuit
@neilmendoza
Car Door Lock Code = Blink
int carDoorPin = 10;!// the setup routine runs once when you press reset:void setup(){ // initialize the digital pin as an output. pinMode(carDoorPin, OUTPUT); }!// the loop routine runs over and over again forever:void loop(){ digitalWrite(carDoorPin, HIGH); // turn the LED on (HIGH is the voltage level) delay(1000); // wait for a second digitalWrite(carDoorPin, LOW); // turn the LED off by making the voltage LOW delay(1000); // wait for a second}
@neilmendoza
DEMO
DEMO
@neilmendoza
Other Coily Things
@neilmendoza
https://github.com/isthisgood/scrapheap-orchestra
@neilmendoza
@neilmendoza@neilmendoza
@neilmendoza
@neilmendoza
@neilmendoza
@neilmendoza
VS
@neilmendoza
@neilmendoza
Many phones still speak the same language as 1990s modems (AT commands)
ATD0123456789 = Call 0123456789 AT+CHUP = Hang up call
@neilmendoza
Cheap phones that talk serial Sony Ericsson T237(US)/T230(UK)
@neilmendoza
Phone circuit
@neilmendoza
@neilmendoza
Make a Call#include <SoftwareSerial.h>!const String PHONE_NUMBER = “07956641707";!SoftwareSerial phone(2, 3);!void setup(){ // start talking to phone over serial phone.begin(9600); // start talking to computer over serial // to receive trigger and send debug // messages Serial.begin(9600);}!void loop(){}!void serialEvent(){ // received a serial event call number if (Serial.available()) { // prepare the AT command String command("ATD"); command += PHONE_NUMBER; command += ";"; // send it to the phone phone.println(command); // debug message Serial.print("Sent AT command: "); Serial.println(command); // clear the serial buffer and wait for // next time Serial.flush(); }}
@neilmendoza
Receive a Call
#include <SoftwareSerial.h>!SoftwareSerial phone(2, 3);!unsigned long lastCallTime = 0;String buffer;!void setup(){ // start talking to phone over serial phone.begin(9600); // start talking to computer over serial // to receive trigger and send debug // messages Serial.begin(9600);}!void loop(){ // check for calls bool callReceived = checkForCalls(); // if we got a call send a message to the computer if (callReceived) { Serial.println("I got a call :)"); }}
bool checkForCalls(){ bool callReceived = false; if (phone.available()) { char newChar = (char)phone.read(); if (isNewLine(newChar)) { if (!buffer.equals("") && !buffer.equals(" ")) { Serial.println(buffer); if (buffer.indexOf("RING") != -1) { lastCallTime = millis(); callReceived = true; } } buffer = ""; } else { buffer = buffer + newChar; } } return callReceived;}!bool isNewLine(char c){ return c == '\n' || c == '\r' || c == '\t';}
@neilmendoza
DEMO
@neilmendoza
Android
@neilmendoza
https://github.com/mik3y/usb-serial-for-android
USB On The Go (OTG) Cable
@neilmendoza
Mobile Music
+
@neilmendoza
DEMO
@neilmendoza
githhub.com/neilmendoza/musicalmachines !
www.neilmendoza.com !
@neilmendoza