Help wanted !!! Building a midi controller

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

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?

Is there a question somewhere? :blush:

Wk

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.

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);
}

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!

Chloris- the link on your blog page is not working. I would love to take a look at the code. :slight_smile:

Yepp. Sorry. Now the link should work.
Have fun!

Thanks. Downloaded just fine now. I will take a look later tonight. :slight_smile:

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 :wink:

Have fun.

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.

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

Grumpy_Mike:
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.

Thank you.

Have fun.

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);
 }
}