Wednesday, September 28, 2011

How To Make A USB Beeper


Overview
This USB Beeper adds a MIDI-accessible piezo beeper transducer to any modern PC without the need for archaic hardware or virtual emulation. Create 1-bit music melodies using a real beeper speaker for that authentic sound. I strongly encourage individuals to customise this code or write their own from scratch.


Example Video




Usage
The USB Beeper driver included in this post provides for two channels. Data sent to MIDI channel 1 will play notes back using a simple square wave. Data sent to MIDI channel 2 will generate noisy sounds useful for percussion.



Hardware
You will need a piezo buzzer audio transducer and a Teensy 2.0 board. Simply solder digital pin 0 of the Teensy board to the red wire of the buzzer. Solder ground of the Teensy board to the black wire of the buzzer.


Software
Install Teensyduino.

Replace Arduino > Contents > Resources > Java > hardware > teensy > cores > usb_midi > usb_api.cpp with http://milkcrate.com.au/_other/downloads/projects/usb_buzzer/usb_api.cpp

Replace Arduino > Contents > Resources > Java > hardware > teensy > cores > usb_midi > usb_api.h with http://milkcrate.com.au/_other/downloads/projects/usb_buzzer/usb_api.h

This will add high resolution pitch bends to the MIDI read functionality of the Teensyduino (at the time of writing).


Teensyduino Code
// Teensyduino MIDI Out Example - Receive Note On and Off
// by Sebastian Tomczak
// 1 September 2011

/*

Functionality:
* The piezo transducer responds to MIDI note messages received via USB by playing a tone


Hardware Setup:
* USB connection from Teensy board to host computer
* Connect the red wire of the piezo transducer to

*/

#include "math.h"
#include <avr/pgmspace.h>

float frequency;
float bend_amount = 0;
float current_pitch = 0;
byte play_flag = 0;
float delay_time;

float note_A = 440.0;

int sample_flag = 0;
int sample_counter;
int sample_speed = 4;
int sample_previous = 0;

long voice_1_previous;


void setup() {
usbMIDI.setHandleNoteOn(noteon);
usbMIDI.setHandleNoteOff(noteoff);
usbMIDI.setHandlePitchChange(PitchChange);
usbMIDI.setHandleControlChange(controlchange);
pinMode(0, OUTPUT);
pinMode(11, OUTPUT);
digitalWrite(11, HIGH);
}

void loop() {
usbMIDI.read();
play();
sample();
}

void noteon(byte channel, byte note, byte velocity) {
if(channel == 0) {
if(velocity > 0) {
digitalWrite(11, 1);
frequency = note_A * pow(2, (float(note) - 69.0 + bend_amount) / 12.0);
delay_time = 500000 / frequency;
current_pitch = note;
play_flag = 1;
}
else {
digitalWrite(11, 0);
play_flag = 0;
}
}

if(channel == 1) {
if(velocity > 0) {
sample_flag = 1;
sample_speed = 128 - note;
play_flag = 0;
}

else {
sample_flag = 0;
}
}
}

void noteoff(byte channel, byte note, byte velocity) {
if(channel == 0) {
digitalWrite(11, 0);
play_flag = 0;
}

if(channel == 1) {
sample_flag = 0;
}
}

void PitchChange(byte channel, unsigned int bend) {
if(channel == 0) {
bend_amount = (bend / 682.625) - 12;
if(play_flag == 1) {
frequency = note_A * pow(2.00, (current_pitch - 69.0 + bend_amount) / 12.0);
delay_time = 500000.0 / frequency;
}

}
}

void play() {
if(play_flag == 1 && sample_flag == 0) {
PORTB = 1;
delayMicroseconds(delay_time);
PORTB = 0;
delayMicroseconds(delay_time);
}

}

void sample() {
if(sample_flag == 1) {
if(sample_counter < sample_speed) {
sample_counter ++;
}
if(sample_counter >= sample_speed) {
digitalWrite(0, random(2));
sample_counter = 0;
}
}

}

void controlchange(byte controller, byte value, byte channel) {
if(controller == 70) {
PORTB = value & 1;
}
}

2 comments:

2xAA said...

Awesome video - great project! :D
Really, your video skills are great :3

www.sillones.nom.es said...

For my part one and all have to go through this.