MIDI lib, controlling volume on ch 1 with pot

This seems to have worked though..

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

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.

  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.

It works!! Thanks Grumpy Mike.

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

Pitch bend is still sending continuously but I think I can figure it out.

Is Old_midiValue a global variable?

Yes. Should it rather be a local variable ??

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.

It works!! Thanks Grumpy Mike.

I think you might have missed a post. Regardless here is the full sketch

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

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?

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.

OK are you sure that code compiles. It chokes for me on the line:-

MIDI_CREATE_DEFAULT_INSTANCE();

Make your loop function this:-

void loop() {
  volume();
  control();
  ProcessAnalogValue();
}

And the ProcessAnalogValue function this:-

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

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

Should oldDATA3 not be updated at the end of this bit of code?

Yes it should sorry.

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.

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

Try this:-

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

Thanks again Grumpy Mike
I got it to work.

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?

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.

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.

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

// 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.

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

#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!?