Arduino Forum

Using Arduino => Audio => Topic started by: FranPhony on Sep 04, 2015, 10:47 pm

Title: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 04, 2015, 10:47 pm
Good day forum users.

I am a music student from South Africa, hoping to get some pointers.

My ultimate goal is to build a class compliant MIDI Ondes Martenot with Arduino, I am currently using Arduino UNO but will eventually upgrade to something with higher resolution ADC for pitch bend. For the time being however, I will be taking baby steps because there are quite a few concepts involved that I am yet to fully comprehend.

For those who are unfamiliar with the Ondes Martenot, here are a few links:

https://en.wikipedia.org/wiki/Ondes_Martenot

https://www.youtube.com/watch?v=Yy9UBjrUjwo

I am not the first to want to make a MIDI version of the instrument, infact one Mitshubi Abe made such a device in 2012 and I will be basing the my hardware and my code on his version as it seems to work quite all right.

Watch his video demonstration here:

https://www.youtube.com/watch?v=BzYTdDpLfAU

And his code is available on his blog here:

http://gam.boo.jp/blog/archives/2012/09/midiondes_marte.html

Now, I tried my very best to decipher his code but I get errors all over the show. So I have decided to break it into little pieces, the first of which is note on/off on MIDI channel 1, controlled by a switch, and  Channel volume controlled by a sensor (potentiometer for prototyping). Just to clarify, when the button is pressed the message note on, middle C, velocity 127 is sent. The volume of that note is then controlled by the sensor which is linked to channel volume.

This is my current predicament. I have my arduino speaking to FL studio via hairless MIDI and I am getting a middle C at velocity 127 every minute or so. The switch does nothing, the pot does nothing.
Here is the sketch, clearly I have made some horrid mistakes. I urge you to point them out and help me correct them

Code: [Select]
#include <MIDI.h>

#define SWITCH 7

int volumeSensor = 0;
int volumeValue;
int MidiValue = 0;
int Old_midiValue;
int cc = 7;  // channel volume


int Notecounter = 0;
int val1 = 0;

int MIDI_ROOT_NOTE = 60;

MIDI_CREATE_DEFAULT_INSTANCE();

void SendMIDI (char cmd, char data1, char DATA2){
 
  Serial.write (byte(cmd));
  Serial.write (byte(data1));
  Serial.write (byte(DATA2));
}

void Control(){
 
  val1 = digitalRead(SWITCH);
 
  if (val1 = HIGH){
    Notecounter = Notecounter +1;
    if (Notecounter == 1)
    {
      SendMIDI(0x90, MIDI_ROOT_NOTE, 127);
    }
  }
  else{
    SendMIDI(0x80, MIDI_ROOT_NOTE, 127);
    Notecounter = 0;
   
  }
}
 
 
  void Volume(){
   
    volumeValue = analogRead(volumeSensor);
   
    MidiValue = volumeValue / 7.6;
   
    if (MidiValue > 127){
      MidiValue = 127;
    }
    if (MidiValue = Old_midiValue){
      SendMIDI (0xB0, cc, MidiValue);
    }
      Old_midiValue = MidiValue;
     
  }

void setup() {

  MIDI.begin (MIDI_CHANNEL_OFF);
 Serial.begin(115200);
}

void loop() {
 
  Control();
Volume();
  delay (1);

}



Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: Grumpy_Mike on Sep 06, 2015, 08:15 am
Lots of errors here. First always use == in an if statement you have single = in some of them.
Next you can not divide an integer with a floating point number and get a sensible answer just divide it by eight.

Finally the volume control uses two cc channels one for the most significant bits and another for the least significant bits.

Correct those things and post again if you are still having trouble.
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 08, 2015, 09:17 pm
Thanks for the response Grumpy Mike.

I have fixed the switch, it now sends the appropriate noteOn/ noteOff messages, although I can't help but notice some latency(for now I'll blame hairless). I also realised that I was using pull up configuration instead of pull down. I can now play middle C all day.

Code: [Select]
void control () {

  val1 = digitalRead (SWITCH);

  if (val1 == HIGH) {
    noteCounter = noteCounter + 1;
    if (noteCounter == 1) {
      SendMIDI(0x90, MIDI_ROOT_NOTE, 127);
    }
  }
  else {
    SendMIDI(0x90, MIDI_ROOT_NOTE, 0);
    noteCounter = 0;
  }
}


I also tried using note on at 0 velocity, but I'm not sure whether this is a correct implementation of running status.

Sending MSB and LSB for channel volume to their respective cc channels, I admit, is beyond me at this point. Are there any forum entries, tutorials or video tutorials that you (forum users) could refer me to that explains the process?
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: Grumpy_Mike on Sep 08, 2015, 11:51 pm
Quote
Sending MSB and LSB for channel volume to their respective cc channels, I admit, is beyond me at this point.
CC message 07 is the most significant 7 bits of the volume,  message 39 is the least significant 7 bits. Together you have 14 bits to control the volume. So suppose you have a variable called vol that contains a 14 bit number, that is a number from 0 to 16383. You split it up and send it over two CC messages

vol07 = vol >> 7
the variable vol07 is sent as the value of CC message 7

vol39 = vol & 0x7f
the variable vol39 is sent as the value of CC message 39

Quote
I also tried using note on at 0 velocity, but I'm not sure whether this is a correct implementation of running status.
It is not.
Running status means that after the initial note on byte and note number and velocity number subsequent notes are just represented by the note number and velocity number, the note on byte is missed out.
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 09, 2015, 11:23 pm
Quote
So suppose you have a variable called vol that contains a 14 bit number, that is a number from 0 to 16383. You split it up and send it over two CC messages
Thanks Grumpy Mike, I believe I'm on the right track.


With this information, i did the following:

Code: [Select]
void volume () {
 sensorValue = analogRead (SensorPin);
 MidiValue = sensorValue * (16383 / 1023);
 
 if (MidiValue > 16383){
   MidiValue = 16383;
 }
 if (MidiValue < 0){
   MidiValue = 0;
 }
 
  vol07 = (byte)(MidiValue >> 7);
  vol39 = (byte)(MidiValue & 0x7F);
 
  SendMIDI(0xB0, cc7, vol07);
  SendMIDI(0xB0, cc39, vol39);
 
}


I say that I believe I'm on the right track because hairless is giving me rational feedback in the debug window.

Quote
-Serial In: Ch 1: Controller 7 value 0
-Serial In: Ch 1: Controller 39 value 0
None of my plugins are accepting it as channel volume, I can, however, assign it to parameters. Could this problem be related to the code? or the software?
Sure, I can assign it to some other volume control but it seems like a bit of a hack.

Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: Grumpy_Mike on Sep 09, 2015, 11:34 pm
Code: [Select]
  SendMIDI(0xB0, cc7, vol07);
  SendMIDI(0xB0, cc39, vol39);

should this not be:-
Code: [Select]
  SendMIDI(0xB0, 7, vol07);
  SendMIDI(0xB0, 39, vol39);

Or are these constants defined anywhere else?

I am not keen on this line:-
Code: [Select]
MidiValue = sensorValue * (16383 / 1023);
Interger division will seldom give you the answer you need. This is a much better way of scaling the number
Code: [Select]
MidiValue = sensorValue << 4;
And you don't need the value checks it will be right.

Quote
None of my plugins are accepting it as channel volume
That could be down to your plug in, what values is it expecting for volume. The 07 & 39 is for the master volume control you would only expect to send that to the final mixer.
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 09, 2015, 11:42 pm
In the meantime I worked on the remainder of the code. I got pitch bend and reset 0 point to work.

Here's the code in its entirety
Code: [Select]

#include <MIDI.h>
# define SWITCH 7 // switch for noteOn
# define PITCHADJUST 8 // switch to adjust pitch
# define PITCHINPUT 1 // 10 turn pot for pitch bend

int val1 = 0;
int val2 = 0;
int DATA3 = 0;
int noteCounter = 0;
int MIDI_ROOT_NOTE = 60;

int PITCHADJUST_RANGE = 0;
int PITCH_RANGE = 24;

byte LowerBits;
byte UpperBits;

int SensorPin = 0; // Connect the pressure sensor to A0
int sensorValue;
int MidiValue = 0; // volume Value
int Old_midiValue;
int vol07 = 0;
int vol39 = 0;
int cc7 = 7;
int cc39 = 39;

float MIDIPITCHSCALE = 0.03785;

MIDI_CREATE_DEFAULT_INSTANCE();

void SendMIDI (char cmd, char data1, char DATA2) {

  Serial.write(byte (cmd));
  Serial.write(byte (data1));
  Serial.write(byte (DATA2));

}

void control () {

  val1 = digitalRead (SWITCH);

  if (val1 == HIGH) {
    noteCounter = noteCounter + 1;
    if (noteCounter == 1) {
      SendMIDI(0x90, MIDI_ROOT_NOTE, 127);
    }
  }
  else {
    SendMIDI(0x80, MIDI_ROOT_NOTE, 127);
    noteCounter = 0;
  }
}

void volume () {
 sensorValue = analogRead (SensorPin);
 MidiValue = sensorValue * (16383 / 1023);
 
 if (MidiValue > 16383){
   MidiValue = 16383;
 }
 if (MidiValue < 0){
   MidiValue = 0;
 }
 
  vol07 = (byte)(MidiValue >> 7);
  vol39 = (byte)(MidiValue & 0x7F);
 
  SendMIDI(0xB0, cc7, vol07);
  SendMIDI(0xB0, cc39, vol39);
 
}



void ProcessAnalogValue (byte) {

  float _x = Z(1);
  val2 = digitalRead(PITCHADJUST);
  if (val2 == HIGH) {
    DATA3 = analogRead(1);
    PITCHADJUST_RANGE = 608 - DATA3;
  }
  int _Converted = (int) ((_x - 297 + PITCHADJUST_RANGE) / MIDIPITCHSCALE);

  if (_Converted > 16383) {
    _Converted = 16383;
  }
  if (_Converted < 0 ) {
    _Converted = 0;
  }

  LowerBits = (byte)(_Converted & 0x7F);
  _Converted >>= 7;
  UpperBits = (byte)(_Converted & 0x7F);

  SendMIDI(0xE0, LowerBits, UpperBits);
}


float Z (byte PIN)
{
  int tmp;
  int data1 = 0;
  int DATA2 = 0;
  int summary = 0; // summary of input data
  int h;

  // Get average data from Analogpin1
  for (h = 0; h < 10; h ++) {
    data1 = analogRead (PITCHINPUT);
    summary = summary + (data1);
  }
  tmp = summary / 10;
  return (float) tmp;
}


void setup() {

  MIDI.begin(1);
  Serial.begin(115200);
  SendMIDI (0xB0, 0x06, PITCH_RANGE);
  pinMode (PITCHADJUST, INPUT);
  pinMode (SWITCH, INPUT);
}

void loop() {

  volume();
  control();
  ProcessAnalogValue(PITCHINPUT);
  delay (1);
}


Credit for the code goes to Mitshusi Abe, I only tinkered with it to get it working.
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 09, 2015, 11:45 pm
Apologies Mike. On the top of my code I declared and initialized the variables.
I will try out your suggestions.

Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 20, 2015, 07:08 pm
Good day. I finally got some time to get back to my project. I last left off with all my components sending the correct messages, but of course a new problem arose. My volume is extremely noisy, I tried a smoothing cap on the wiper of my pot but it didn't help much. I think it is a code related problem, it should be noted that a constant stream of midi message are sent. Which I think is the root of the problem. Is there a way to tell arduino to only send messages when the pot is turned??

Here is the code for volume controll
Code: [Select]
void volume () {
 sensorValue = analogRead (SensorPin);
 MidiValue = sensorValue << 4;
 

  vol07 = (byte)(MidiValue >> 7);
  vol39 = (byte)(MidiValue & 0x7F);
 
  SendMIDI(0xB0, 7, vol07);
  SendMIDI(0xB0, 39, vol39);
 
}
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: Grumpy_Mike on Sep 20, 2015, 08:02 pm
Quote
. Is there a way to tell arduino to only send messages when the pot is turned??
Yes.
Just remember the last value of the pot you sent and only send it to midi if it is different by at least four.
The abs function helps.
Code: [Select]

if( abs(lastValue - currentValue) > 4) {
// send to MIDI
}
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 23, 2015, 10:19 am
I tried this but it did not work, I tried it with numbers greater than 4 and I also tried it in different parts of the sketch but it is still noisy as can be.

Code: [Select]
void volume () {
 sensorValue = analogRead (SensorPin);
 MidiValue = sensorValue << 4;
 

  vol07 = (byte)(MidiValue >> 7);
  vol39 = (byte)(MidiValue & 0x7F);
 
  if (abs (Old_midiValue - MidiValue) > 4){
 
  SendMIDI(0xB0, 7, vol07);
  SendMIDI(0xB0, 39, vol39);
  }
}




 I'm getting continuous streams of information for note off and pitchbend also, consistent and correct as they may be, I don't think it is necessary to send note off constantly.

Code: [Select]
void control () {

  val1 = digitalRead (SWITCH);

  if (val1 == HIGH) {
    noteCounter = noteCounter + 1;
    if (noteCounter == 1) {
      SendMIDI(0x90, MIDI_ROOT_NOTE, 127);
    }
  }
  else {
    SendMIDI(0x80, MIDI_ROOT_NOTE, 127);
    noteCounter = 0;
  }
}


How do I remedy?

I am looking in to making a basic synth in pure data for this instrument and sending cc7 and cc39 to control one parameter seems to confuse the program. Would it not be easier to just send cc7 ? I also found a few vst's that accepts cc7 as volume, in some cases master volume .
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 23, 2015, 10:32 am
This seems to have worked though..

Code: [Select]
void volume () {
 sensorValue = analogRead (SensorPin);
 MidiValue = sensorValue / 8;
 

  if (abs (Old_midiValue - MidiValue) > 4){
  
  SendMIDI(0xB0, 7, MidiValue);
  
  }
}


I'm still not sure about the note off and pitchbend though. I should also note that somethimes when opening FL studio it tells me it is experiencing an MIDI overflow and then nothing works!!
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: Grumpy_Mike on Sep 23, 2015, 11:52 am
Quote
I'm getting continuous streams of information for note off and pitchbend also
You are not doing this correctly. Yes that code will send a constant stream of not off messages, that is what you have programmed it to do. Every time you read a digital input and it is not high ( I assume that means not pressed although that indicates you have not wired up your switch in the best way ) then a note off is being sent. This means it is continuously being sent. There are many ways round this perhaps the simplest way is to have a boolean variable called say noteOn. When you send a note on message you set this to true, when you send a note off message you set it to false. Then you have an if statement that sends a note off message only if your digital input is low AND your noteOn variable is true. You need to use a compound if statement where there are two conditions.

Code: [Select]
  if(noteOn == true &&  val1 == LOW){
    SendMIDI(0x80, MIDI_ROOT_NOTE, 127);
    noteCounter = 0;
    noteOn = false;
  }

 
Also I can't see where you are updating the value of "Old_midiValue", it needs to be updated every time you take a reading. Otherwise it will always send stuff.

It is much better to to this on the raw value read from the analogue input rather than the cut down value you send to the MIDI.

Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 23, 2015, 12:56 pm
It works!! Thanks Grumpy Mike.

Code: [Select]
void control () {

  val1 = digitalRead (SWITCH);

  if (val1 == HIGH) {
    noteCounter = noteCounter + 1;
    if (noteCounter == 1) {
      SendMIDI(0x90, MIDI_ROOT_NOTE, 127);
      noteOn = true;
    }
  }
 if (noteOn == true && val1 == LOW)
 { 
    SendMIDI(0x80, MIDI_ROOT_NOTE, 127);
    noteCounter = 0;
    noteOn = false;
  }
}




Code: [Select]
void volume () {
 sensorValue = analogRead (SensorPin);
 
 MidiValue = sensorValue / 8;

  if (abs (Old_midiValue - sensorValue) > 4){
 
  SendMIDI(0xB0, 7, MidiValue);
  Old_midiValue = sensorValue;
 
  }
}


Pitch bend is still sending continuously but I think I can figure it out.
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: Grumpy_Mike on Sep 23, 2015, 05:18 pm
Is Old_midiValue a global variable?
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 24, 2015, 09:59 pm
Yes. Should it rather be a local variable ??
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: Grumpy_Mike on Sep 24, 2015, 10:06 pm
No it should be global or a static local one either will do.
I am trying to work out why you say it doesn't work. I have used the technique many times myself and advised others to use it successfully. Therefore you are doing something wrong in trying to implement it. Can you post all the code please so I can take a closer look.
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 25, 2015, 10:56 am
Quote
It works!! Thanks Grumpy Mike.
I think you might have missed a post. Regardless here is the full sketch

Code: [Select]

#include <MIDI.h>
# define SWITCH 7 // switch for noteOn
# define PITCHADJUST 8 // switch to adjust pitch
# define PITCHINPUT 1 // 10 turn pot for pitch bend

int val1 = 0;
int val2 = 0;
int DATA3 = 0;
int noteCounter = 0;
int MIDI_ROOT_NOTE = 60;

int PITCHADJUST_RANGE = 0;
int PITCH_RANGE = 24;

byte LowerBits;
byte UpperBits;

int SensorPin = 0; // Connect the pressure sensor to A0
int sensorValue;
int MidiValue = 0; // volume Value
int Old_midiValue;
bool noteOn;


float MIDIPITCHSCALE = 0.03785;

MIDI_CREATE_DEFAULT_INSTANCE();

void SendMIDI (char cmd, char data1, char DATA2) {

  Serial.write(byte (cmd));
  Serial.write(byte (data1));
  Serial.write(byte (DATA2));

}

void control () {

  val1 = digitalRead (SWITCH);

  if (val1 == HIGH) {
    noteCounter = noteCounter + 1;
    if (noteCounter == 1) {
      SendMIDI(0x90, MIDI_ROOT_NOTE, 127);
      noteOn = true;
    }
  }
 if (noteOn == true && val1 == LOW)
 { 
    SendMIDI(0x80, MIDI_ROOT_NOTE, 127);
    noteCounter = 0;
    noteOn = false;
  }
}

void volume () {
 sensorValue = analogRead (SensorPin);
 
 MidiValue = sensorValue / 8;

  if (abs (Old_midiValue - sensorValue) > 4){
 
  SendMIDI(0xB0, 7, MidiValue);
  Old_midiValue = sensorValue;
 
  }
}



void ProcessAnalogValue (byte) {

  float _x = Z(1);
  val2 = digitalRead(PITCHADJUST);
  if (val2 == HIGH) {
    DATA3 = analogRead(1);
    PITCHADJUST_RANGE = 608 - DATA3;
  }
  int _Converted = (int) ((_x - 297 + PITCHADJUST_RANGE) / MIDIPITCHSCALE);

  if (_Converted > 16383) {
    _Converted = 16383;
  }
  if (_Converted < 0 ) {
    _Converted = 0;
  }

  LowerBits = (byte)(_Converted & 0x7F);
  _Converted >>= 7;
  UpperBits = (byte)(_Converted & 0x7F);

  SendMIDI(0xE0, LowerBits, UpperBits);
}


float Z (byte PIN)
{
  int tmp;
  int data1 = 0;
  int DATA2 = 0;
  int summary = 0; // summary of input data
  int h;

  // Get average data from Analogpin1
  for (h = 0; h < 10; h ++) {
    data1 = analogRead (PITCHINPUT);
    summary = summary + (data1);
  }
  tmp = summary / 10;
  return (float) tmp;
}


void setup() {

  MIDI.begin(1);
  Serial.begin(57600);
  SendMIDI (0xB0, 0x06, PITCH_RANGE);
  pinMode (PITCHADJUST, INPUT);
  pinMode (SWITCH, INPUT);
}

void loop() {

  volume();
  control();
  ProcessAnalogValue(PITCHINPUT);
  delay (1);
}
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: Grumpy_Mike on Sep 25, 2015, 11:20 am
Yes you need to do the same trick of seeing if the value has changes by a small amount on the pitch bend as well to stop it sending all the time.
There are also other errors in the pitch end stuff like you not accessing the variable passed to it.
Do you need help with that?
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 25, 2015, 01:46 pm
Quote
Do you need help with that?
I do indeed, I thought I could sus it out but I am banging my head against the wall with little success. As it is it works perfectly accept for the streaming issue, I will just have to adjust the math in the near future to scale it to my keyboard.
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: Grumpy_Mike on Sep 25, 2015, 01:52 pm
OK are you sure that code compiles. It chokes for me on the line:-
Code: [Select]
MIDI_CREATE_DEFAULT_INSTANCE();
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: Grumpy_Mike on Sep 25, 2015, 02:05 pm
Make your loop function this:-
Code: [Select]
void loop() {
  volume();
  control();
  ProcessAnalogValue();
}


And the ProcessAnalogValue function this:-
Code: [Select]
void ProcessAnalogValue () {
static int oldDATA3 =  0;
  float _x = Z(1);
 
  if (digitalRead(PITCHADJUST) == HIGH) {
    DATA3 = analogRead(1);
    PITCHADJUST_RANGE = 608 - DATA3;
  }
  if( abs(oldDATA3-DATA3) > 2){
  int _Converted = (int) ((_x - 297 + PITCHADJUST_RANGE) / MIDIPITCHSCALE);

  if (_Converted > 16383) {
    _Converted = 16383;
  }
  if (_Converted < 0 ) {
    _Converted = 0;
  }

  LowerBits = (_Converted & 0x7F);
  UpperBits = ((_Converted >>7) & 0x7F);

  SendMIDI(0xE0, LowerBits, UpperBits);
 }
}
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 26, 2015, 10:09 am
Should oldDATA3 not be updated at the end of this bit of code?

 I tried this and it works in part, initially pitchbend sends no information until pitch reset button is pressed. Thereafter pitchbend seems to send continuous data although I think it might be as a result of the pot that I am using bouncing between values. I will test with the 10 turn pot to see if the result differs 
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: Grumpy_Mike on Sep 26, 2015, 10:14 am
Quote
Should oldDATA3 not be updated at the end of this bit of code?
Yes it should sorry.

Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 26, 2015, 12:42 pm
I have wired up the 10 turn pot and its not the problem. What happens now is when reset button is held in and pot value changes by 2 the reset pitchbend message is send. Turning of the pot does not change pitch.

Code: [Select]
void ProcessAnalogValue () {
static int oldDATA3 =  0;
  float _x = Z(1);
 
  if (digitalRead(PITCHADJUST) == HIGH) {
    DATA3 = analogRead(1);
    PITCHADJUST_RANGE = 608 - DATA3;
  }
  if( abs(oldDATA3-DATA3) > 2){
  int _Converted = (int) ((_x - 297 + PITCHADJUST_RANGE) / MIDIPITCHSCALE);

  if (_Converted > 16383) {
    _Converted = 16383;
  }
  if (_Converted < 0 ) {
    _Converted = 0;
  }

  LowerBits = (_Converted & 0x7F);
  UpperBits = ((_Converted >>7) & 0x7F);

  SendMIDI(0xE0, LowerBits, UpperBits);
  oldDATA3 = DATA3;
 }
}
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: Grumpy_Mike on Sep 26, 2015, 10:23 pm
Try this:-
Code: [Select]
void ProcessAnalogValue () {
static int oldDATA3 =  0;
  float _x = Z(1);
 
  if (digitalRead(PITCHADJUST) == HIGH) {
    DATA3 = analogRead(1);
    PITCHADJUST_RANGE = 608 - DATA3;
  if( abs(oldDATA3-DATA3) > 2){
  int _Converted = (int) ((_x - 297 + PITCHADJUST_RANGE) / MIDIPITCHSCALE);

  if (_Converted > 16383) {
    _Converted = 16383;
  }
  if (_Converted < 0 ) {
    _Converted = 0;
  }

  LowerBits = (_Converted & 0x7F);
  UpperBits = ((_Converted >>7) & 0x7F);

  SendMIDI(0xE0, LowerBits, UpperBits);
  oldDATA3 = DATA3;
   }
  }
 }
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Sep 27, 2015, 01:04 am
Thanks again Grumpy Mike
I got it to work.

 
Code: [Select]
DATA3 = analogRead(1);
  if (digitalRead(PITCHADJUST) == HIGH) {
    PITCHADJUST_RANGE = 608 - DATA3;
  }


In the first if statement it was only reading analog when Pitchadjust is set high. All is not well though, I can hear the increments. Is there some way to achieve finer resolution with the arduino uno? 
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: Grumpy_Mike on Sep 27, 2015, 07:03 am
The resolution is limited to ten bits. You could try changing the threshold from two to one. The only other thing is to average several readings but you soon run into latency issues.

You could also try reducing the range you bend it over. I must say I haven't noticed this when I made a theremin using IR distance sensors.
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Oct 04, 2015, 09:20 pm
My bend range is +/- 24 two reach a total of four octaves. This must stay, I will probably purchase a teensy for its 13bit ADC sometime in the near future. In the meantime I have shifted my attention to an octave change function to further expand the instruments range. I am also planning on adding a 49 key keyboard with shift registers once my bloody parts arrive. This will take up all my digital pins so I thought I would use a pot for octave change whereby the lowest values (0 - 10) would send one octave down message, the highest values (110- 127) would send one octave up message and values around 64 would send rootnote 60. I haven't got time to tinker with the code as I've been busy with assignments galore. I'll update the thread as soon as I make progress on the matter.
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Nov 10, 2015, 01:09 pm
Good day.

My parts have arrived and I've drawn up my schematic on fritzing, It should be attached to this message..

I will be borrowing this bit of code from 'codetinkerhack' as a basic outline for the keyboard sketch
Code: [Select]
// Pin Definitions
// Rows are connected to
const int row1 = 5;
const int row2 = 6;
const int row3 = 7;
const int row4 = 8;

// The 74HC595 uses a serial communication
// link which has three pins
const int clock = 9;
const int latch = 10;
const int data = 11;


uint8_t keyToMidiMap[32];

boolean keyPressed[32];

int noteVelocity = 127;


// use prepared bit vectors instead of shifting bit left everytime
int bits[] = { B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000 };


// 74HC595 shift to next column
void scanColumn(int value) {
digitalWrite(latch, LOW); //Pulls the chips latch low
shiftOut(data, clock, MSBFIRST, value); //Shifts out the 8 bits to the shift register
digitalWrite(latch, HIGH); //Pulls the latch high displaying the data
}

void setup() {

// Map scan matrix buttons/keys to actual Midi note number. Lowest num 41 corresponds to F MIDI note.
keyToMidiMap[0] = 48;
keyToMidiMap[1] = 41;
keyToMidiMap[2] = 42;
keyToMidiMap[3] = 43;
keyToMidiMap[4] = 44;
keyToMidiMap[5] = 45;
keyToMidiMap[6] = 46;
keyToMidiMap[7] = 47;

keyToMidiMap[8] = 56;
keyToMidiMap[1 + 8] = 49;
keyToMidiMap[2 + 8] = 50;
keyToMidiMap[3 + 8] = 51;
keyToMidiMap[4 + 8] = 52;
keyToMidiMap[5 + 8] = 53;
keyToMidiMap[6 + 8] = 54;
keyToMidiMap[7 + 8] = 55;

keyToMidiMap[16] = 64;
keyToMidiMap[1 + 16] = 57;
keyToMidiMap[2 + 16] = 58;
keyToMidiMap[3 + 16] = 59;
keyToMidiMap[4 + 16] = 60;
keyToMidiMap[5 + 16] = 61;
keyToMidiMap[6 + 16] = 62;
keyToMidiMap[7 + 16] = 63;

keyToMidiMap[24] = 72;
keyToMidiMap[1 + 24] = 65;
keyToMidiMap[2 + 24] = 66;
keyToMidiMap[3 + 24] = 67;
keyToMidiMap[4 + 24] = 68;
keyToMidiMap[5 + 24] = 69;
keyToMidiMap[6 + 24] = 70;
keyToMidiMap[7 + 24] = 71;

// setup pins output/input mode
pinMode(data, OUTPUT);
pinMode(clock, OUTPUT);
pinMode(latch, OUTPUT);

pinMode(row1, INPUT);
pinMode(row2, INPUT);
pinMode(row3, INPUT);
pinMode(row4, INPUT);

    Serial.begin(31250);

delay(1000);

}

void loop() {

for (int col = 0; col < 8; col++) {

// shift scan matrix to following column
scanColumn(bits[col]);

// check if any keys were pressed - rows will have HIGH output in this case corresponding
int groupValue1 = digitalRead(row1);
int groupValue2 = digitalRead(row2);
int groupValue3 = digitalRead(row3);
int groupValue4 = digitalRead(row4);

// process if any combination of keys pressed
if (groupValue1 != 0 || groupValue2 != 0 || groupValue3 != 0
|| groupValue4 != 0) {

if (groupValue1 != 0 && !keyPressed[col]) {
keyPressed[col] = true;
noteOn(0x91, keyToMidiMap[col], noteVelocity);
}

if (groupValue2 != 0 && !keyPressed[col + 8]) {
keyPressed[col + 8] = true;
noteOn(0x91, keyToMidiMap[col + 8], noteVelocity);
}

if (groupValue3 != 0 && !keyPressed[col + 16]) {
keyPressed[col + 16] = true;
noteOn(0x91, keyToMidiMap[col + 16], noteVelocity);
}

if (groupValue4 != 0 && !keyPressed[col + 24]) {
keyPressed[col + 24] = true;
noteOn(0x91, keyToMidiMap[col + 24], noteVelocity);
}

}

//  process if any combination of keys released
if (groupValue1 == 0 && keyPressed[col]) {
keyPressed[col] = false;
noteOn(0x91, keyToMidiMap[col], 0);
}

if (groupValue2 == 0 && keyPressed[col + 8]) {
keyPressed[col + 8] = false;
noteOn(0x91, keyToMidiMap[col + 8], 0);
}

if (groupValue3 == 0 && keyPressed[col + 16]) {
keyPressed[col + 16] = false;
noteOn(0x91, keyToMidiMap[col + 16], 0);
}

if (groupValue4 == 0 && keyPressed[col + 24]) {
keyPressed[col + 24] = false;
noteOn(0x91, keyToMidiMap[col + 24], 0);
}

}

}


void noteOn(int cmd, int pitch, int velocity) {
  Serial.write(cmd);
Serial.write(pitch);
Serial.write(velocity);
}


My problems to solve are:
1. Getting the sketch to work with my 7 x 16 button matrix which is not quite as conventional as the keyboard used for the original code.
2. Merging this bit of code with my preexisting sketch for the ondes, ie. incorperating it with the midi library.

The keyboard and keyboard related thing will be sending on midi channel 2, I intend to add a volume pedal instead of a velocity sensitive element.

My main concern though is merging the two bits of sketch, with this I am again in over my head although I am eager to learn.
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Nov 17, 2015, 02:44 pm
Hello again.

I had no luck with the code for the keyboard above. I have made some progress with this bit of code from youtube

Code: [Select]
#define NUM_ROWS 3
#define NUM_COLS 8

#define NOTE_ON_CMD 0x91
#define NOTE_OFF_CMD 0x81
#define NOTE_VELOCITY 127

//MIDI baud rate
#define SERIAL_RATE 9600

// Pin Definitions

// Row input pins

const int row1Pin = 6;
const int row2Pin = 7;
const int row3Pin = 8;

// 74HC595 pins
const int dataPin = 9;
const int latchPin = 10;
const int clockPin = 11;

boolean keyPressed[NUM_ROWS][NUM_COLS];
uint8_t keyToMidiMap[3][8] ={
                                        36, 37, 38, 39,
                                        40, 41, 42, 43, 44, 45, 46, 47,
                                        48, 49, 50, 51, 52, 53,  54, 55
                                          };

// bitmasks for scanning columns
int bits[] =
{
  B00000001,
  B00000010,
  B00000100,
  B00001000,
  B00010000,
  B00100000,
  B01000000,
  B10000000
};

void setup()
{
  int note = 36;

  for(int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
  {
    for(int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
    {
      keyPressed[rowCtr][colCtr] = false;
      note++;
    }
  }

  // setup pins output/input mode
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);

  pinMode(row1Pin, INPUT);
  pinMode(row2Pin, INPUT);
  pinMode(row3Pin, INPUT);


  Serial.begin(SERIAL_RATE);
}

void loop()
{
  for (int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
  {
    //scan next column
    scanColumn(colCtr);

    //get row values at this column
    int rowValue[NUM_ROWS];
    rowValue[0] = digitalRead(row1Pin);
    rowValue[1] = digitalRead(row2Pin);
    rowValue[2] = digitalRead(row3Pin);
 

    // process keys pressed
    for(int rowCtr=0; rowCtr<NUM_ROWS; ++rowCtr)
    {
      if(rowValue[rowCtr] != 0 && !keyPressed[rowCtr][colCtr])
      {
        keyPressed[rowCtr][colCtr] = true;
        noteOn(rowCtr,colCtr);
      }
    }

    // process keys released
    for(int rowCtr=0; rowCtr<NUM_ROWS; ++rowCtr)
    {
      if(rowValue[rowCtr] == 0 && keyPressed[rowCtr][colCtr])
      {
        keyPressed[rowCtr][colCtr] = false;
        noteOff(rowCtr,colCtr);
      }
    }
  }
}

void scanColumn(int colNum)
{
  digitalWrite(latchPin, LOW);

  if(0 <= colNum && colNum <= 7)
  {
    shiftOut(dataPin, clockPin, MSBFIRST, B00000000); //right sr
    shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum]); //left sr

  }
  digitalWrite(latchPin, HIGH);
}

void noteOn(int row, int col)
{
  Serial.write(NOTE_ON_CMD);
  Serial.write(keyToMidiMap[row][col]);
  Serial.write(NOTE_VELOCITY);
}

void noteOff(int row, int col)
{
  Serial.write(NOTE_OFF_CMD);
  Serial.write(keyToMidiMap[row][col]);
  Serial.write(NOTE_VELOCITY);
}


My keyboard consists of a 20 button matrix ( 3 x 8 ) and a 29 button matrix ( 4 x 8 ). I have been trying to get the 20 button matrix two work with this code, although my results are less than ideal.  As it is I get only three notes from each ground instead of 4 for ground 1 and 8 for grounds 2 and 3 each. So out of the 20 keys I only get three notes and I can change the value of those notes with the keytomidimap fuction but I can't get nabouring notes to work properly if at all.

Where am I going wrong here?
Also, can anyone tell me whether it is possible to use this bit of code with the midi library!?
Title: Re: MIDI lib, controlling volume on ch 1 with pot
Post by: FranPhony on Nov 19, 2015, 11:00 pm
I managed to get the keys working with this last bit of code. I then tried to structure it like the ondes sketch so that I can just add them together with minimal hassles. Here is my attempt
Code: [Select]
#include <MIDI.h>
#define NUM_ROWS 3
#define NUM_COLS 8

// Pin Definitions

// Row input pins
const int row1Pin = 6;
const int row2Pin = 7;
const int row3Pin = 8;


// 74HC595 pins
const int dataPin = 9;
const int latchPin = 10;
const int clockPin = 11;

boolean keyPressed[NUM_ROWS][NUM_COLS];
uint8_t keyToMidiMap[NUM_ROWS][NUM_COLS]={                  32, 33, 34, 35,
                                            36, 37, 38, 39, 40, 41, 42, 43,
                                            44, 45, 46, 47, 48, 49, 50, 51,
                                            52, 53, 54, 55,};


// bitmasks for scanning columns
int bits[] =
{
  B00000001,
  B00000010,
  B00000100,
  B00001000,
  B00010000,
  B00100000,
  B01000000,
  B10000000
};

MIDI_CREATE_DEFAULT_INSTANCE();

void SendMIDI (char cmd, char data1, char DATA2) {
  Serial.write(byte (cmd));
  Serial.write(byte (data1));
  Serial.write(byte (DATA2));
}


void keyNotes()
{

  for(int colCtr = 0; colCtr < NUM_COLS; colCtr ++)
  {
    for(int rowCtr = 0; rowCtr < NUM_ROWS; rowCtr ++)
    {
      keyPressed[rowCtr][colCtr] = false;

    }
  }



  for (int colCtr = 0; colCtr < NUM_COLS; colCtr ++)
  {
    //scan next column
    scanColumn(colCtr);

    //get row values at this column
    int rowValue[NUM_ROWS];
    rowValue[0] = digitalRead(row1Pin);
    rowValue[1] = digitalRead(row2Pin);
    rowValue[2] = digitalRead(row3Pin);


    // process keys pressed
    for(int rowCtr=0; rowCtr<NUM_ROWS; rowCtr ++)
    {
      if(rowValue[rowCtr] != 0 && !keyPressed[rowCtr][colCtr])
      {
        keyPressed[rowCtr][colCtr] = true;
       SendMIDI (0x91, (rowCtr,colCtr), 127);
      }
    }

    // process keys released
    for(int rowCtr=0; rowCtr<NUM_ROWS; rowCtr ++)
    {
      if(rowValue[rowCtr] == 0 && keyPressed[rowCtr][colCtr])
      {
        keyPressed[rowCtr][colCtr] = false;
        SendMIDI (0x11,  (rowCtr,colCtr), 0);
      }
    }
  }
}

void scanColumn(int colNum)
{
  digitalWrite(latchPin, LOW);

  if(0 <= colNum && colNum <= 7)
 
  {
    shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum]); //right sr

  }
  else
  {
    shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum-8]); //right sr
  }
  digitalWrite(latchPin, HIGH);
  }
 
void setup() {

  MIDI.begin(1);
  Serial.begin(9600);
    // setup pins output/input mode
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);

  pinMode(row1Pin, INPUT);
  pinMode(row2Pin, INPUT);
  pinMode(row3Pin, INPUT);

}

void loop(){
 
  keyNotes ();
 
}


I am getting constants streams of note-ons with note values of 0 - 7. I don't think I'm calling the corresponding key number from 'keyToMidiMap' properly.. I'm out of ideas for today, help would be appreciated