Go Down

Topic: MIDI lib, controlling volume on ch 1 with pot (Read 4156 times) previous topic - next topic

FranPhony

Yes. Should it rather be a local variable ??

Grumpy_Mike

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.

FranPhony

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

Grumpy_Mike

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?

FranPhony

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.

Grumpy_Mike

OK are you sure that code compiles. It chokes for me on the line:-
Code: [Select]
MIDI_CREATE_DEFAULT_INSTANCE();

Grumpy_Mike

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

FranPhony

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 

Grumpy_Mike

Quote
Should oldDATA3 not be updated at the end of this bit of code?
Yes it should sorry.


FranPhony

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

Grumpy_Mike

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

FranPhony

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? 

Grumpy_Mike

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.

FranPhony

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.

FranPhony

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.

Go Up