Go Down

Topic: MIDI and Trackball (Read 1 time) previous topic - next topic

fionnsdradon

Hi there
I bought one of sparkfuns trackballs and want to incorperate it into a midi controller. They give code that lets it control pitch and volume.
Thing is i'm new to this and can understand code. What i'm kinda looking to do is control one parameter (control change like modulation) with the x or y data and another cc change with the other cc data. I can see how to substitute this code to do that. If I could do that I wanted then to use a push button to allow me to select a number of other cc's, maybe cycling threw 3 or 4 of them. Also ithe code  seems very complicated to just control two things( pitch and volume) or is it?

/*

Roll-a-tone Example Code
SparkFun Electronics 2011
N.Poole

This is some really awfully messy code that I created for the product video.
It's essentially a mashup of the Musical Instrument Shield example code by
Nathan Seidle and the PS/2mouse Library example found at:
www.arduino.cc/playground/ComponentLib/Ps2mouse

I left most of the original comments intact so it shouldn't be too difficult to
pick it apart and figure out what the heck I was thinking.

Roll the ball up and down to control the volume (velocity) of the notes,
Roll side to side to play different notes,
Press the buttons (Yellow and White wires pulled to Ground) to change instruments.

Have fun! Make Music! Modify my code! Who Cares?

*/

#define MDATA 5
#define MCLK 6

  #include <NewSoftSerial.h>
NewSoftSerial mySerial(2, 3); //Soft TX on 3, we don't use RX in this code

byte note = 0; //The MIDI note value to be played
byte resetMIDI = 4; //Tied to VS1053 Reset line
byte ledPin = 13; //MIDI traffic inidicator
int instrument = 11;
int lnote = 0;
int vel = 0;

void gohi(int pin)
{
  pinMode(pin, INPUT);
  digitalWrite(pin, HIGH);
}

void golo(int pin)
{
  pinMode(pin, OUTPUT);
  digitalWrite(pin, LOW);
}

void mouse_write(char data)
{
  char i;
  char parity = 1;

  //  Serial.print("Sending ");
  //  Serial.print(data, HEX);
  //  Serial.print(" to mouse\n");
  //  Serial.print("RTS");
  /* put pins in output mode */
  gohi(MDATA);
  gohi(MCLK);
  delayMicroseconds(300);
  golo(MCLK);
  delayMicroseconds(300);
  golo(MDATA);
  delayMicroseconds(10);
  /* start bit */
  gohi(MCLK);
  /* wait for mouse to take control of clock); */
  while (digitalRead(MCLK) == HIGH)
    ;
  /* clock is low, and we are clear to send data */
  for (i=0; i < 8; i++) {
    if (data & 0x01) {
      gohi(MDATA);
    }
    else {
      golo(MDATA);
    }
    /* wait for clock cycle */
    while (digitalRead(MCLK) == LOW)
      ;
    while (digitalRead(MCLK) == HIGH)
      ;
    parity = parity ^ (data & 0x01);
    data = data >> 1;
  } 
  /* parity */
  if (parity) {
    gohi(MDATA);
  }
  else {
    golo(MDATA);
  }
  while (digitalRead(MCLK) == LOW)
    ;
  while (digitalRead(MCLK) == HIGH)
    ;
  /* stop bit */
  gohi(MDATA);
  delayMicroseconds(50);
  while (digitalRead(MCLK) == HIGH)
    ;
  /* wait for mouse to switch modes */
  while ((digitalRead(MCLK) == LOW) || (digitalRead(MDATA) == LOW))
    ;
  /* put a hold on the incoming data. */
  golo(MCLK);
  //  Serial.print("done.\n");
}

/*
* Get a byte of data from the mouse
*/
char mouse_read(void)
{
  char data = 0x00;
  int i;
  char bit = 0x01;

  //  Serial.print("reading byte from mouse\n");
  /* start the clock */
  gohi(MCLK);
  gohi(MDATA);
  delayMicroseconds(50);
  while (digitalRead(MCLK) == HIGH)
    ;
  delayMicroseconds(5);  /* not sure why */
  while (digitalRead(MCLK) == LOW) /* eat start bit */
    ;
  for (i=0; i < 8; i++) {
    while (digitalRead(MCLK) == HIGH)
      ;
    if (digitalRead(MDATA) == HIGH) {
      data = data | bit;
    }
    while (digitalRead(MCLK) == LOW)
      ;
    bit = bit << 1;
  }
  /* eat parity bit, which we ignore */
  while (digitalRead(MCLK) == HIGH)
    ;
  while (digitalRead(MCLK) == LOW)
    ;
  /* eat stop bit */
  while (digitalRead(MCLK) == HIGH)
    ;
  while (digitalRead(MCLK) == LOW)
    ;

  /* put a hold on the incoming data. */
  golo(MCLK);
  //  Serial.print("Recvd data ");
  //  Serial.print(data, HEX);
  //  Serial.print(" from mouse\n");
  return data;
}

void mouse_init()
{
  gohi(MCLK);
  gohi(MDATA);
  //  Serial.print("Sending reset to mouse\n");
  mouse_write(0xff);
  mouse_read();  /* ack byte */
  //  Serial.print("Read ack byte1\n");
  mouse_read();  /* blank */
  mouse_read();  /* blank */
  //  Serial.print("Sending remote mode code\n");
  mouse_write(0xf0);  /* remote mode */
  mouse_read();  /* ack */
  //  Serial.print("Read ack byte2\n");
  delayMicroseconds(100);
}

void setup()
{
  Serial.begin(9600);
  mouse_init();
 
    //Setup soft serial for MIDI control
  mySerial.begin(31250);

  //Reset the VS1053
  pinMode(resetMIDI, OUTPUT);
  digitalWrite(resetMIDI, LOW);
  delay(100);
  digitalWrite(resetMIDI, HIGH);
  delay(100);

}

/*
* get a reading from the mouse and report it back to the
* host via the serial line.
*/
void loop()
{
  char mstat;
  char mx;
  char my;

  /* get a reading from the mouse */
  mouse_write(0xeb);  /* give me data! */
  mouse_read();      /* ignore ack */
  mstat = mouse_read();
  mx = mouse_read();
  my = mouse_read();

  /* send the data back up */
  Serial.print(mstat, DEC);
  Serial.print("\tX=");
  Serial.print(mx, DEC);
  Serial.print("\tY=");
  Serial.print(my, DEC);
  Serial.println();
  delay(20);  /* twiddle */
 
  talkMIDI(0xB0, 0x07, 120); //0xB0 is channel message, set channel volume to near max (127)

  //Demo Basic MIDI instruments, GM1
  //=================================================================

  talkMIDI(0xB0, 0, 0x00); //Default bank GM1


  talkMIDI(0xC0, instrument, 0); //Set instrument number. 0xC0 is a 1 data byte command

  note = map(mx, -127, 127, 30, 90);
  vel = map(my, -127, 127, 0, 120);
     
      if(lnote != note){
      //Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
      noteOn(0, note, vel);
      delay(50);}
     
      if(mstat == 9){
          instrument--;
          talkMIDI(0xC0, instrument, 0);}

      if(mstat == 10){
          instrument++;
          talkMIDI(0xC0, instrument, 0);}


lnote = note;
 
}
//Send a MIDI note-on message.  Like pressing a piano key
//channel ranges from 0-15
void noteOn(byte channel, byte note, byte attack_velocity) {
  talkMIDI( (0x90 | channel), note, attack_velocity);
}

//Send a MIDI note-off message.  Like releasing a piano key
void noteOff(byte channel, byte note, byte release_velocity) {
  talkMIDI( (0x80 | channel), note, release_velocity);
}

//Plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that data values are less than 127
void talkMIDI(byte cmd, byte data1, byte data2) {
  digitalWrite(ledPin, HIGH);
  mySerial.print(cmd, BYTE);
  mySerial.print(data1, BYTE);

  //Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes
  //(sort of: http://253.ccarh.org/handout/midiprotocol/)
  if( (cmd & 0xF0) <= 0xB0)
    mySerial.print(data2, BYTE);

  digitalWrite(ledPin, LOW);
}


didcot

Hi fionnsdradon,

I thought I'd reply to this as I've just taken apart an old mouse and am experimenting with this, too. Unfortunately, I'm no expert.

Have you tried your code? Does it work at all?

I'd recommend splitting the task into smaller parts. Use the PS2 sketch and serial monitor to make sure you can get data from the trackball. Then, in a different sketch, use some basic iterations or a digital switch to make sure you can get usable MIDI messages from your Arduino to wherever you want them to go. Once you can do both of those things, it should be pretty easy to use the data from the trackball to control the messages you're sending.

You might also want to follow the guidelines for posting code (there's a sticky somewhere on this forum, I think). You're more likely to get responses better than mine if you do this.

Best of luck.

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy