Pages: [1]   Go Down
Author Topic: Help wanted !!! Building a midi controller  (Read 3192 times)
0 Members and 1 Guest are viewing this topic.
New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Code:
* 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

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 620
Posts: 34003
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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 Offline
God Member
*****
Karma: 3
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Is there a question somewhere?   smiley-red

Wk
Logged


Manchester (England England)
Online Online
Brattain Member
*****
Karma: 620
Posts: 34003
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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)
Online Online
Brattain Member
*****
Karma: 620
Posts: 34003
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok I have merged the functions of these two totally rubbish sketches:-

Code:
/*
* 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 Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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 Offline
Newbie
*
Karma: 0
Posts: 17
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Offline Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

0
Offline Offline
Newbie
*
Karma: 0
Posts: 17
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks. Downloaded just fine now. I will take a look later tonight. smiley
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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 Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Code:
/*
 * 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
Code:
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
Quote
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

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Offline Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you.

Have fun.
Logged

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
=============================

Code:
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
}
Quote
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:
Code:
[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 .
Code:
/* 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

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Pages: [1]   Go Up
Jump to: