New York City, NY
Offline
Jr. Member
Karma: 0
Posts: 86
Arduino Rocks! Think befor you code | Thinking supercollider/clojure
|
 |
« on: February 15, 2011, 04:29:43 am » |
I am working on a DIY midi controller using piezo sensors and an arduino board. The idea came to me after seeing todbot " musical arduino - midi drum kit" Here is the basic skerch * MIDI Drum Kit * ------------- * Convert Arduino to a MIDI controller piezo inputs and * the serial port as a MIDI output. * * This sketch is set up to send General MIDI (GM) drum notes * on MIDI channel 1, but it can be easily reconfigured for other * notes and channels *
* piezo buzzer elements as inputs to send MIDI notes of a varying velocity * & duration, depending on forced of impulse imparted to piezo sensor. * * To send MIDI, attach a MIDI out jack (female DIN-5) to Arduino. * DIN-5 pinout is: * pin 2 - Gnd * pin 4 - 220 ohm resistor to +5V * pin 5 - Arduino D1 (TX) * all other pins - unconnected
// what midi channel we're sending on // ranges from 0-15 #define drumchan 1
// general midi drum notes #define note_Middle C 60 - E 89
// define the pins we use
#define piezoZeroPin 0 #define piezoOnePin 1 #define ledPin 13 // for midi out status
// analog threshold for piezo sensing #define PIEZOTHRESHOLD 100
int val,t;
void setup() {
pinMode(ledPin, OUTPUT); Serial.begin(31250); // set MIDI baud rate }
void loop() {
// deal with first piezo, this is kind of a hack val = analogRead(piezoZeroPin); if( val >= PIEZOTHRESHOLD ) { t=0; while(analogRead(piezoZeroPin) >= PIEZOTHRESHOLD/2) { t++; } noteOn(drumchan,note_Middle C, t*2); delay(t); noteOff(drumchan,note_Middle C,0); }
// deal with second piezos, this is kind of a hack val = analogRead(piezoOnePin); if( val >= PIEZOTHRESHOLD ) { t=0; while(analogRead(piezoOnePin) >= PIEZOTHRESHOLD/2) { t++; } noteOn(drumchan,note_C#, t*2); delay(t); noteOff(drumchan,note_C#,0); } }
// Send a MIDI note-on message. Like pressing a piano key // channel ranges from 0-15 void noteOn(byte channel, byte note, byte velocity) { midiMsg( (0x90 | channel), note, velocity); }
// Send a MIDI note-off message. Like releasing a piano key void noteOff(byte channel, byte note, byte velocity) { midiMsg( (0x80 | channel), note, velocity); }
// Send a general MIDI message void midiMsg(byte cmd, byte data1, byte data2) { digitalWrite(ledPin,HIGH); // indicate we're sending MIDI data Serial.print(cmd, BYTE); Serial.print(data1, BYTE); Serial.print(data2, BYTE); digitalWrite(ledPin,LOW); }
Next to expand the number of inputs on the arduino I added 4 multiplexers (4051) The Mux: http://arduino.cc/forum/index.php/topic,51551.msg368972.html#msg368972
|
|
|
|
« Last Edit: March 11, 2011, 07:46:11 pm by Pitchoilcan »
|
Logged
|
|
|
|
|
Manchester (England England)
Offline
Brattain Member
Karma: 272
Posts: 25466
Solder is electric glue
|
 |
« Reply #1 on: February 22, 2011, 03:18:05 pm » |
I am not sure what you are up to you seem to be posting the same thing every few days. Next time you post code please use the # icon so that it goes into a box. Have you built anything yet are are you still looking into what to do?
|
|
|
|
|
Logged
|
|
|
|
|
Brazil
Offline
God Member
Karma: 1
Posts: 615
Wusik Dot Com
|
 |
« Reply #2 on: February 22, 2011, 06:42:25 pm » |
Is there a question somewhere?  Wk
|
|
|
|
|
Logged
|
|
|
|
|
Manchester (England England)
Offline
Brattain Member
Karma: 272
Posts: 25466
Solder is electric glue
|
 |
« Reply #3 on: February 28, 2011, 07:06:40 pm » |
You must only have one setup() and one loop() in a sketch. You must take the code from one of these and add it to the other and then delete the original. You must make sure there are no functions with the same name in each sketch, if there are then change one and all the references to it. You can't use a variable name that you have used as a #define name (like readInZero and all the other pointless varaibles you use to read in a value and print it out.)
Most of all you must be able to read a program and see what it does.
|
|
|
|
|
Logged
|
|
|
|
|
Manchester (England England)
Offline
Brattain Member
Karma: 272
Posts: 25466
Solder is electric glue
|
 |
« Reply #4 on: March 01, 2011, 06:16:25 am » |
Ok I have merged the functions of these two totally rubbish sketches:- /* * MIDI Drum Kit * a demo code in how to read a multiplexed analogue input by Mike Cook * while the code will work the result will be rubbish because it takes too long to get round all the sensors * therefore some hits will be missed * also holding on a hit sensor until it stops is a rubbish way of doing things but that was in the origional sketch */
// what midi channel we're sending on // ranges from 0-15 #define drumchan 1 // note the drum set is normally on channel 9 or 10 // general midi drum notes // analog threshold for piezo sensing #define PIEZOTHRESHOLD 100
//==============================================================
//==============================================================
void setup() {
//4051Mux A B C digital control pins // Mux A Part//
pinMode(8, OUTPUT); // s0 pinMode(9, OUTPUT); // s1 pinMode(10, OUTPUT); // s2 pinMode(13, OUTPUT); Serial.begin(31250); // set MIDI baud rate }
void loop() { //Read Value of 4051 analog-in 0 by setting the values of s0,s1 and s2 int readValue, t, noteToPlay = 30; for(int i = 0; i<4; i++) { // this loop will read each of the four analogue inputs 0 to 3 for (int j= 0; j<7; j++){ // this loop will read 8 inputs from one analogue input noteToPlay++; // increment the note to play this will be used if we find a hit digitalWrite(8, j & 1); // output the binary number j to the three pins 8, 9 & 10 digitalWrite(9, (j >>1)& 1); digitalWrite(10, (j >>2)& 1); readValue = analogRead(i); // read the input pin // everything above this point is the second sketch - everything below is the first sketch if( readValue >= PIEZOTHRESHOLD ) { // we have found a hit sensor t=0; while(analogRead(i) >= PIEZOTHRESHOLD/2) { // hold until the hit drops off t++; // and count how many times round the loop we go } noteOn(drumchan,noteToPlay, t*2); // note on - use the number of times round the loop as a velocity and note length delay(t); noteOff(drumchan,noteToPlay, 0); // note off } // end of we have found a hit } // end of j loop } // end of i loop } // end of loop()
// Send a MIDI note-on message. Like pressing a piano key // channel ranges from 0-15 void noteOn(byte channel, byte note, byte velocity) { midiMsg( (0x90 | channel), note, velocity); }
// Send a MIDI note-off message. Like releasing a piano key void noteOff(byte channel, byte note, byte velocity) { midiMsg( (0x80 | channel), note, velocity); }
// Send a general MIDI message
void midiMsg(byte cmd, byte data1, byte data2) { digitalWrite(13,HIGH); // indicate we're sending MIDI data Serial.print(cmd, BYTE); Serial.print(data1, BYTE); Serial.print(data2, BYTE); digitalWrite(13,LOW); }
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 18
|
 |
« Reply #5 on: March 01, 2011, 03:28:33 pm » |
Hi! Mike and others helped me a lot with their midi projects to build a midi drumset with arduino. This drumset has the following features: -52 possible analog inputs (piezos and other analog sensors ) -optical hihat controller (QTR-1A infrared Reflectance Sensor) -pushbutton to save calibrated values of hihat controller to eeprom. It is called Y(et) A(nother) A(rdunio) MI(di) DRUM(head), because there are severeal approaches which you can find everywhere in the web to do that job. Here you can find the code for your arduino -> http://blog.georgmill.de/2011/03/01/yet-another-arduino-midi-drumhead/Have fun!
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 17
Arduino rocks
|
 |
« Reply #6 on: March 01, 2011, 03:40:51 pm » |
Chloris- the link on your blog page is not working. I would love to take a look at the code. 
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 18
|
 |
« Reply #7 on: March 01, 2011, 03:53:50 pm » |
Yepp. Sorry. Now the link should work. Have fun!
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 17
Arduino rocks
|
 |
« Reply #8 on: March 01, 2011, 04:38:45 pm » |
Thanks. Downloaded just fine now. I will take a look later tonight. 
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 18
|
 |
« Reply #9 on: March 02, 2011, 02:29:01 am » |
There are some pictures now. They illustrate some of the instruments, which are D(o)I(t)Y(ourself)-made. Schematics can be found in other midi projects. I'll post them later. The drums do have only a really few latency, which cannot be heared by non professional musicians (under 10 ms). No disturbing pause between two hits on different instruments. I should mention that is is important that your OS should support low lateny. My linux kernel is patched and has realtime capabilities ( https://rt.wiki.kernel.org/index.php/Main_Page) . The software I used for this project: Ubuntu Studio with recent rt kernel, Hydrogen drumsequencer and Jack ( http://jackaudio.org/) to put things together ;-) Have fun.
|
|
|
|
|
Logged
|
|
|
|
|
New York City, NY
Offline
Jr. Member
Karma: 0
Posts: 86
Arduino Rocks! Think befor you code | Thinking supercollider/clojure
|
 |
« Reply #10 on: March 10, 2011, 08:18:00 pm » |
Mike thanks for the reworking. After much googleing and help from CrossRoads I've arrived at for(i=0; i<8; 1++) and for(j=0; j<3; j++)
so I have a mux array a channel array and the note array
Someone mentioned I should into a for() loop so I take it thats what they were talking about. There are indeed alot of midi drums for the arduino. The Pocket Piano is simular to what I'm trying to do, the only difference I can tell is that it uses audio out. I also found a sketch called pitches.h which is a Hertz to midi conversion array. It is important to me that the output is midi but it was helpfull for understanding how to tie one pitch to one pin.
|
|
|
|
« Last Edit: March 11, 2011, 02:00:23 am by Pitchoilcan »
|
Logged
|
|
|
|
|
New York City, NY
Offline
Jr. Member
Karma: 0
Posts: 86
Arduino Rocks! Think befor you code | Thinking supercollider/clojure
|
 |
« Reply #11 on: March 10, 2011, 10:36:13 pm » |
Mike after testing your sketch I find that it isn't responding, by which I mean blinking the led. the original did two things 1 send midi on TX and blink the led on 13. I know it's just a demo of the mux however I need the loop to contiune. My current working /* * codeexample for useing a 4051 * analog multiplexer / demultiplexer * by david c. and tomek n.* for k3 / malm� h�gskola */ int ledPin = 13; int piezoPin = 4;
int THRESHOLD = 100; // set minimum value that indicates a knock
int val = 0; // variable to store the value coming from the sensor int t = 0; // the "time" measured for how long the knock lasts int r0 = 0; //value of select pin at the 4051 (s0) int r1 = 0; //value of select pin at the 4051 (s1) int r2 = 0; //value of select pin at the 4051 (s2) int count = 0; //which y pin we are selecting
void setup(){ pinMode(ledPin, OUTPUT); Serial.begin(9600); Serial.println("ready"); // indicate we're waiting pinMode(2, OUTPUT); // s0 pinMode(3, OUTPUT); // s1 pinMode(4, OUTPUT); // s2 }
void loop () { digitalWrite(ledPin,LOW); // indicate we're waiting for (count=0; count<=7; count++) { r0 = count & 0x01; r1 = (count>>1) & 0x01; r2 = (count>>2) & 0x01; digitalWrite(2, r0); digitalWrite(3, r1); digitalWrite(4, r2);
//Either read or write the multiplexed pin here
val = analogRead(piezoPin); // read piezo if( val >= THRESHOLD ) { // is it bigger than our minimum? digitalWrite(ledPin, HIGH); // tell the world t = 0; while(analogRead(piezoPin) >= (THRESHOLD/2)) { t++; } // wait for it to go LOW (with a little hysteresis) if(t!=0) Serial.println(t); } }}
is reading one 4051 and blinks the led as it detects a knock at a given treshold, yet there are somethings missing. Like the for()loop and the channel, mux and pins arrays. I think I understand this part : for(int i = 0; i<4; i++) { // this loop will read each of the four analogue inputs 0 to 3 for (int j= 0; j<7; j++){ // this loop will read 8 inputs from one analogue input noteToPlay++; // increment the note to play this will be used if we find a hit I noticed you had the initail note as 30. For midi notes must be between 0 and 127. I had defined my notes as #define note_Middle C 60 #define note_CS 61 #define note_D 62 ,etc for two octaves. I guess it's start at 30 and cound up to the highest note.... Before I saw your post I was thinking along the line of int row = 0; // storeing the bin code
row = bin[count]; int bin [] = {000, 1, 10, 11, 100, 101, 110, 111};//bin = bin�r, some times it is so easy int count = 0; // just a count
bin being one array count another and row the third. I'm also thinking that the way you have it set up, the note get louder and longer each time note on - use the number of times round the loop as a velocity and note length
|
|
|
|
« Last Edit: March 11, 2011, 07:56:30 pm by Pitchoilcan »
|
Logged
|
|
|
|
|
New York City, NY
Offline
Jr. Member
Karma: 0
Posts: 86
Arduino Rocks! Think befor you code | Thinking supercollider/clojure
|
 |
« Reply #12 on: March 11, 2011, 01:57:14 am » |
Most of all you must be able to read a program and see what it does.
right now I using a midi module to read the midi data. But reading the LED ( with my eyes) I get a good sense oh how often a 'Knock' is dectected chloris your drums look real nice. A real playable instrument. Nice. I'm a drummer myself.
|
|
|
|
« Last Edit: March 12, 2011, 12:08:30 am by Pitchoilcan »
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 18
|
 |
« Reply #13 on: March 11, 2011, 12:03:49 pm » |
Thank you.
Have fun.
|
|
|
|
|
Logged
|
|
|
|
|
New York City, NY
Offline
Jr. Member
Karma: 0
Posts: 86
Arduino Rocks! Think befor you code | Thinking supercollider/clojure
|
 |
« Reply #14 on: March 11, 2011, 09:59:49 pm » |
reading pin 2 I have mux #3. Lets say this is the first of three. I would poll the 8 pins for a hit, assigning Y0 C4, Y1 C#, Y2 D, Y3 D#, Y4 E, Y5 F, Y6 F#, and Y7 G. pin 1 will have mux #2 with notes G# to D#, pin O mux #1 with C5 and so on. I'm considering adding a MCP4921 12-Bit DAC and inplementing pitched.h but that gives me audio out and I want midi. Can I use bitwrite to set and save the state of the y pins ======================== ================================== Work In Progress ============================= for (mux_number=0; mux_number <3; mux_number++){ // for (mux_number = 0 to 2){ for (channel_number=0; channel_number <8; channel_number++); // for (channel_number = 0 to 7){ read array [mux_number, channel_number] do your processing // next channel_number } // next mux_number }
Yes, that looks like a pretty efficient way to read the values of the 64 inputs. Now the trick is, after each read, to send the appropriate midi note command Maybe do that as 16x4 array array[i, j] Array will be accessed:
[0,0] = 59 [0,1] = 60 [0,2] = 61 etc, for the 32 notes you have defined. See below for how I think your noteOn/noteOff would be inserted . /* ReadMultiplexedSensorsAndSendMIDI * ------------ * * Reads 4 16 channel Multiplexers and sends the values * * Stephen Williams <http://fluidforms.at> * */
#define CONTROLpin1 2 #define CONTROLpin2 3 #define CONTROLpin3 4 #define CONTROLpin4 5
// Variables: char sensorValueToSend = 0; // Value of the sensor int actualSensorValue = 0; // value from the analog input
// Some error chacking would be good here. //If the values exceede 128 the will not fit in one byte. void sendCommand(char command, char sensorID, char value) { serialWrite(command); serialWrite(sensorID); serialWrite(value); }
void setup() { // set the states of the I/O pins: pinMode(LEDpin, OUTPUT); pinMode(CONTROLpin1, OUTPUT); pinMode(CONTROLpin2, OUTPUT); pinMode(CONTROLpin3, OUTPUT); pinMode(CONTROLpin4, OUTPUT);
beginSerial(19200); }
void loop() { int i; int j; for (i=0; i <16; i++) {
// set control pins on the multiplexers digitalWrite(CONTROLpin1, (i&15)>>3);//bit4 digitalWrite(CONTROLpin2, (i&7)>>2);//bit3 digitalWrite(CONTROLpin3, (i&3)>>1);//bit2 digitalWrite(CONTROLpin4, (i&1) );//bit1
// read the analogue inputs and send the values of the sensors. for(j=0; j<4; j++){
//****************** replace this part actualSensorValue = analogRead(j); // You will have to adjust this line so that can send the // sensor value in one byte. sensorValueToSend = actualSensorValue / 15; sendCommand(0x90, i+16*j, sensorValueToSend); // ******************** with this part //**************************************** val = analogRead(readInZero); // the "#define readInZero 0" type statements are ok for mapping Mux to analog port // Serial.print(readInZero); //use the result << only need for debug if( val >= PIEZOTHRESHOLD ) { t=0; // this while mini-loop reads over & over waiting for the signal to die down? // keep conversion time in mind again while(analogRead(readInZero) >= PIEZOTHRESHOLD/2) { t++; } noteOn(drumchan,note_59, t*2); // replace note_59 with array[i,j] delay(t); noteOff(drumchan,note_59,0); }
// ********************************************* } // if you uncomment this line you can check the control pins // of the multiplexers with your multimeter. //delay(500); } }
|
|
|
|
« Last Edit: March 12, 2011, 12:04:48 am by Pitchoilcan »
|
Logged
|
|
|
|
|
|