Go Down

Topic: MIDI Theremin Controller Project Advice (Read 9844 times) previous topic - next topic

VX967

I should start by saying that I'm new to the Arduino. I'm familiar with a little programming in C/C++, and I can grasp some basic MIDI protocol, but other than that I'm really a musician. I apologize in advance if I don't know what I'm getting myself into. I've highlighted my main questions in bold so it's easier to read this wall of text.

Anyway, I'd like to make a theremin controller, though there's two main differences from most of the theremin projects I've seen online.

First off, I'm not looking to generate any kind of sound with the Arduino itself. I'd just like to send MIDI pitchbend data to a software synth, most likely NI's Massive. I'd like to send the information out of the Arduino's built in USB port, but after Googling some MIDI-based projects, they all seem to require separate MIDI ports attached to the board. So I guess my first questions are:

Can I send MIDI data over the Arduino's USB connection, or do I need a MIDI port?
Wouldn't I need to get a software synth to recognize the Arduino as a MIDI controller? If so, how?

And I've seen a lot of discussion debating Serial.write() vs. Serial.print(). Which am I supposed to use?

Secondly, I'm using a distance sensor (an HC-SR04 Ultrasonic sensor) rather than an antenna of some sort. I've already found a program which simply prints out the distance of an object from the sensor, so I have that working. The values can jump and act a little sporadic at times, but that's only if I move my hand really fast in front of the sensor.

Is an ultrasonic distance sensor fine for a theremin project, or is there some obvious problem with this method of input that I don't know about?

Another problem is scaling the values from the sensor to proper MIDI protocol. The output values need to be scaled down to a proper range for pitchbend data: which, from what I understand of most MIDI stuff, generally operates on a scale from 0 to 127. If that's true for pitchbend, that's not going to be enough for a smooth transition for a large range (hoping for at least a 2 to 3 octave range).

This is a bit confusing because I have an M-Audio Axiom Pro controller with a pitchbend wheel, and the transitions across large ranges are still incredibly smooth. Either the controller is sending out a much larger range of values, or the synth itself performs some kind of pitch smoothing between the standard 128 range it's given. So with that in mind, some final questions:

Is there any insight on how Massive (or software synths in general) handle pitchbend data?
Should I use a range of 128, or could I use a much larger range?


That's all the questions I can come up with for now.

Grumpy_Mike

Quote
Can I send MIDI data over the Arduino's USB connection,

Yes but you will need a helper application like Hairless to convert the serial data into the MIDI bus inside your computer.
http://projectgus.github.io/hairless-midiserial/

Quote
Wouldn't I need to get a software synth to recognize the Arduino as a MIDI controller?

No Hairless will do it for you.

Quote
And I've seen a lot of discussion debating Serial.write() vs. Serial.print(). Which am I supposed to use?

Serial.write() - you can not use Serial.print() now that the BYTE option has be deprecated.

Quote
Is an ultrasonic distance sensor fine for a theremin project,

Seems good to me.

Quote
Should I use a range of 128, or could I use a much larger range?

No Pitchbend data is a 14 bit and the units of bend are set by controller messages 101 and 100

VX967

Awesome, thanks for the insight. Unfortunately my laptop just died on me and is in for repair, but I'll definitely check out Hairless and try out your other suggestions when I get it back in 3-5 business days.

Also, thanks for clearing up the pitchbend issue. Good to know I've got a much larger resolution for that.

Whenever I get my laptop back and make progress (or inevitably stumble into some other issue) I'll make sure to update this thread.

VX967

Okay, so I've got the laptop back. XP

Before I start trying to get the distance sensor working, I'm just trying to interface the Arduino itself with a software synth first.

Downloaded Hairless and I've got it connecting the Arduino to Massive (soft synth). I've found this Instructables page about sending pitchbend data from an Arduino, copied the code and ran it. The code is a little lengthy, so I'll just link to the Instructables page instead of copying it here.  (BTW there's two versions of the code that use different pitchbend ranges. I'm using the full range, which is the second block of code on the page.)

http://www.instructables.com/id/Send-and-Receive-MIDI-with-Arduino/step8/Pitchbend-and-Arduino/

However, I'm getting an error message from Hairless:

Code: [Select]

Warning: got a status byte when we were expecting 1 more data bytes, sending possibly incomplete MIDI message 0xc0 (sometimes 0x80)


It looks like the errors are happening almost every time the MIDImessage() function is called. I know roughly what the error means, but I'm not sure how or where to fix it.

According to the page, it looks like pitchbend data is contained in 7 bits. It'd make sense why Hairless might complain about this, since 8 bits seems more standard for any given MIDI message. When I run it, the program does whack Massive out of tune, so I know that something is working, but besides that it doesn't sound at all like the example video on the Instructables page. Any ideas?

Grumpy_Mike

Quote
According to the page, it looks like pitchbend data is contained in 7 bits.

No it has 14 bits. After the pitch bend message then there are two bytes sent both with the most significant bit at zero.

Quote
since 8 bits seems more standard for any given MIDI message.

The message is the whole two or normally three bytes. The first is the message type and always has the most significant bit set, it is then followed by data which always has the least significant bit as zero.
So hairless is complaining that there is not enough data bytes being sent for the type of message it has received.

VX967

Thanks again for clearing that up. Still learning some of this stuff.

Also, I figured out the problem. I needed to install the MIDI library and call MIDI.begin(), and I also had to conform the baud rate to 115200, the same as Hairless.

Anyway, after an hour of tweaking and combining different sources of code, I've got it working!

Well, almost.

The data is really sporadic, so the pitch of the synth goes all over the place. I'm looking up some tutorials on smoothing data, so hopefully I can get this thing to actually be playable. I think I might have to mount the sensor differently too; right now it's connected directly to the ports of the Arduino, but I think it's pointing downwards a bit and sometimes senses the breadboard in front of it. Figures.

I also still have to set the values to a proper range, so that my hand doesn't have to go back six feet just to reach the bottom octaves. But it's definitely getting there. :D

Grumpy_Mike

Before you add the sensors how about just reading a pot. In that way you will have known good quality solid data to test your software with.

VX967

Actually I've already implemented the smoothing bit. The pitch is definitely a bit more stable, but it still goes out of whack every few seconds, and tends to jump around if my hand is moving too fast. Heck, sometimes the pitch jumps around for a few seconds even if my hand is still.

I'm considering at some point just looking into a more traditional setup involving an antenna of some sort. I feel the distance sensor may not be the best way of approaching this project, as it's just too sporadic to use for something as precise as pitch.

Regardless, I'll try implementing the smoothing code with a simple potentiometer first and see how reliable the data is.

Grumpy_Mike

Again check with a print if your nut is unstable.

You might want to look at the Sharp IR distance sensors before going to RF.

bildakid

I'm using ir sensors to input my data, I'm getting some very interesting sounds out of my device, I can play notes, pitch bend, but for the life of me I can't get the mod wheel working.

I have ir sensors connected to arduino, which is connected to my midi controller though the midi in cable, my controller then plays notes via a softsyth programme on my laptop.

http://www.youtube.com/watch?v=lZUaJt0AyCw

Here is a link to a short video of my third night of work on the project, as you can see it's working but my goal was to have eight sensors driving cc values, but so far I can only get pitch wheel and note on working.

My question is can someone show me simple code to drive say 'main volume'? or Mod wheel, I've looked at a bunch fo charts showing the different possible values but none of them work?


Grumpy_Mike

Quote
I've looked at a bunch fo charts showing the different possible values but none of them work?

Yes they all work if you do the right thing with them. As you are not showing us what you have done with them then it is hard to say.
Have you read the how to use this forum thread?

bildakid

managed to get my volume and cc controls working. My problems were sending the calls to midi needed to byte my vars before sending. Now i have prox sensors working but my problem is dealing with the changing maximum and minimum values. I have a function that takes the prox sensor and converts it to a value between 0-127 but I need to define the max and min possible inputs which over time change. Unlike a pot switch where the min and max values never change using a prox sensors min and max values change depending on ambient light. If anyone knows a way to deal with this please let me know.

  I also wrote a simple function to correct the incoming notes to be in any given scale. You take the note coming from the sensor and divide it by 12, then take the remainder and compare it to an array that defines that scale, so for major scale you create an array
majorScale[] = {1,3,6,8,10}; if the incoming note is found within the array I then tell it to bump up the note to the next value. Worked great and resulted in my device sounding less chaotic .


bildakid

Here is my code for my prox synth

#include <SoftwareSerial.h>

byte note = 0;    // The MIDI note value to be played
////billy finger vars
int IRpin = A0;
int IRpin2 = A1;
int IRpin3 = A2;
int IRpin4 = A3;
int IRemitter = 5;
//int IRemitter2 = 9;

int ambientIR;
int obstacleIR;
int value[10];
int distance;

int fingers[] = {IRpin,IRpin2,IRpin3,IRpin4};
int lastNotes[] = {0,0,0,0};
int noteMax[] = {0,0,0,0};
int noteMin[] = {1000,1000,1000,1000};
int scaleMajor[] ={2,4,7,9,11};
int minorScale[] = {2,5,8};
///end of billy vars

int pitchbend = 224;
int modwheel = 176;
int lsb = 0;
int msb = 0;

//software serial
SoftwareSerial midiSerial(2, 3); // digital pins that we'll use for soft serial RX & TX

void setup() {
    Serial.begin(9600);
      midiSerial.begin(31250);
      pinMode(IRemitter,OUTPUT);
      digitalWrite(IRemitter,LOW);
}

void loop() {
    for(int x=0;x<4;x++){//ren though the sensors
      int tempVal = 0;
      distance = readIR(6,x);
      if(distance > noteMax
  • ){noteMax
  • = distance;}
          if(distance < noteMin
  • ){noteMin
  • = distance;}

          if((distance > noteMin
  • +1) && (distance < noteMax
  • -1)){
            tempVal = ((distance * 127) / (noteMax
  • )); 
            if(x==0){ 
             int temptVal = (((distance - noteMin
  • ) * 127) / (noteMax
  • - noteMin
  • ));
             int adjustVal = tempVal - (tempVal%12);
             for(int z=0;z<5;z++){
               if (adjustVal = scaleMajor[z]){
                 tempVal++;
               }
             }
              if(lastNotes
  • != tempVal){
                byte tempVal2 = 45;
                noteOn(0x90, tempVal, tempVal2);
                lastNotes
  • = tempVal;
              }
             }
             if(x==1){
                  ccSend(19,tempVal);
             }
             if(x==2){
                  ccSend(20,tempVal);
             }
             if(x==3){           
               int tempVal3 = 127-tempVal;
              ccSend(32,tempVal3);// volume!!!!
             }
             
           }
         
         
        Serial.print(x);
        Serial.print("(");
        Serial.print(noteMax
  • );
        Serial.print(":");
        Serial.print(tempVal);
        Serial.print(":");
        Serial.print(noteMin
  • );
        Serial.print(")    ");
      }
    Serial.println();
      }


    void noteOn(byte cmd, byte data1, byte data2) {
        midiSerial.write(cmd);
        midiSerial.write(data1);
        midiSerial.write(data2);
    }

    void ccSend(byte CCnumber, byte CCdata){
    byte CCchannel = 0xB0;
      midiSerial.write(CCchannel);
      midiSerial.write(CCnumber);
      midiSerial.write(CCdata);
    }
     
     
     
    int readIR(int times,int fingerNum){
      for(int x=0;x<times;x++){
        digitalWrite(IRemitter,LOW);
        delay(1);
        ambientIR = analogRead(fingers[fingerNum]);
        digitalWrite(IRemitter,HIGH);
        delay(1);
        obstacleIR = analogRead(fingers[fingerNum]);
        value
  • = ambientIR-obstacleIR;
      }
      distance = 0;
      for(int x=0;x<times;x++){
        distance +=value
  • ;
      }
      return(distance/times);
    }
     
      I have the volume working but for the life of me still can't get mod to work?


Grumpy_Mike

Read that code. See all the black squares? Did you put them there?
This is why we ask people to use code tags when posting code.
Please read the how to use this forum sticky post.

bildakid

#14
Jan 18, 2014, 11:39 pm Last Edit: Jan 19, 2014, 03:21 am by bildakid Reason: 1
I copy pasted the code from my project to the form, I have a visual disability that makes it difficult to read.
I'm just trying to reach out to others doing similar creative things with arduino and midi, If anyone has some code examples to show how to send controls to the mod wheel would be much appreciated.

Go Up