Project in progress
Arduino Due Bass & Drum Computer / Machine

Arduino Due Bass & Drum Computer / Machine © GPL3+

16 step sequencer for bass & drum sounds. Use the General Midi sounds stored in the vs1053.

  • 1,430 views
  • 0 comments
  • 3 respects

Components and supplies

Apps and online services

About this project

Hello, I want to show you my Drum Computer on an Arduino Due with a tft-touchscreen and VS1053 as sound prozessor.

You need:

Operating

Below 0-F to select the pattern or in song-mode song-part

Pattern 0-7: Drum-sounds

Pattern 8-15: Bass-sound

CL button clear the current pattern or the compete song, but not the in memory saved . If you want to clear it, first CL and then SV.

SV save the current pattern or the song. Resetting or power-off will not affect the data.

CP copy the current pattern. Select 0-F and then PA to paste.

note C - Bass

note C# - Snare

note D - HiHat

note D# - Closed HiHat

note E - Hi Tom

note F - Mid Tom

note F# - Lo Tom

note G - Crash

note G# - Cowbell

note A - Bongo

note A# - Lo Bongo

note B - Bell

Wiring

The wiring is as following for the touchscreen:

Touch -> Arduino Due

  • T_IRQ -> 22
  • T_DO -> 24
  • T_DIN -> 26
  • T_CS -> 28
  • T_CLK -> 30

For the display:

Display -> Arduino Due

  • SDO -> A.25
  • LED -> 3.3V
  • SCK -> A.27
  • SDI -> A.26
  • DC -> 9
  • RESET -> 8
  • CS -> 10
  • GND -> GND
  • VCC -> 3.3V

For the VS1053:

  • XCS -> 4
  • XDCS -> 5
  • DREQ -> 6
  • XRST -> 7
  • MOSI -> A.26
  • MISO -> A.25
  • SCK -> A.27
  • 5V -> 5V
  • GND -> GND

Updates

01.30.2018

  • use a faster library for the ILI9341
  • change the instrument variables from bool to word
  • add volume button

02,02,2018

  • add pattern
  • add Clear and Save pattern
  • some code tweaks

02,07,2018

  • add copy and paste

02,23,2018

  • change to Scheduler library
  • implement song mode
  • fix delay on pattern change

02,25,2018

  • add save song
  • some bug fix

03,05,2018

  • add accent

03,07,2018

  • some bugs fixed

04,15,2018

  • some bugs fixed
  • some code tweaks

04,17,2018

  • rework song-mode

Code

Drum ComputerArduino
a simple bass & drum machine
////////////////////////////////////////////
//    2.8" TOUCH SCREEN Bass & Drum       //
//              Maschine                  //
//                                        //
//            rom3 01.2018                //
//                                        //
//                                        //
////////////////////////////////////////////
#include <SPI.h>
#include <ILI9341_due_config.h>
#include <ILI9341_due.h>
#include <SystemFont5x7.h>
#include <URTouch.h>
#include <DueFlashStorage.h>
#include <Scheduler.h>

#define VS_XCS    4 // Control Chip Select Pin (for accessing SPI Control/Status registers)
#define VS_XDCS   5 // Data Chip Select / BSYNC Pin
#define VS_DREQ   6 // Data Request Pin: Player asks for more data
#define VS_RESET  7 //Reset is active low
#define TFT_RST 8
#define TFT_DC 9
#define TFT_CS 10
#define TOUCH_ORIENTATION  LANDSCAPE
#define TEXTCOLOR tft.setTextColor(ILI9341_WHITE,ILI9341_BLUE)
#define BUTTONCOLOR tft.setTextColor(ILI9341_WHITE, ILI9341_RED);
#define TEXTCOLOR2 tft.setTextColor(ILI9341_WHITE,ILI9341_BLACK) 
#define SONGPART tft.printAt("Play part:", 240, 180);tft.print(songPart,HEX);

ILI9341_due tft = ILI9341_due(TFT_CS, TFT_DC, TFT_RST);

URTouch myTouch(30, 28, 26, 24, 22);
DueFlashStorage dueFlashStorage;

SPISettings vs1053(24000000, MSBFIRST, SPI_MODE0);

unsigned short int x, y, xx, yy, tempo = 120, shift, inst, Vol = 100, buff, songPart;
unsigned short pattern[16][14],instrument[13][16];
unsigned short patch[] = {35, 38, 44, 42, 43, 48, 47, 49, 56, 60, 61, 83};
unsigned short bass[] = {35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46};
unsigned short slope, slope2, pat = 0, nextPat = 0, copyTo, color,color1, pos, posx, posy;
short tick = -1;
bool play = false, copyPat = false, mode = false,tool, trueValue = false;
unsigned long currentMillis,previousMillis = 0;
const long interval = 250;

union split {
  short s;  // or use int16_t to be more specific
  //   vs.
  struct Byte {
    char byte1, byte2;  // or use int8_t to be more specific
  }
  byte;
};

void setup() {
  //pinMode(A0,INPUT);
  //analogReadResolution(7);
  //SPI.begin();
  myTouch.InitTouch();
  myTouch.setPrecision(PREC_HI);
  tft.begin();
  tft.setRotation(iliRotation270);

  pinMode(VS_DREQ, INPUT);
  pinMode(VS_XCS, OUTPUT);
  pinMode(VS_XDCS, OUTPUT);
  pinMode(VS_RESET, OUTPUT);
  digitalWrite(VS_XCS, HIGH); //Deselect Controltft.cursorToXY
  digitalWrite(VS_XDCS, HIGH); //Deselect Data
  digitalWrite(VS_RESET, HIGH);

  //Serial.begin(115200); //Use serial for debugging
  //Serial.println("VS1053 Shield Example");

  Scheduler.startLoop(readTouch);

  tft.setFont(SystemFont5x7);
  tft.setTextLetterSpacing(1);
}
void loop() {
  patternMode();
  if (dueFlashStorage.read(0) != 0xFF) {
    readPat(); drawPattern();
    }
  for (pat = 1; pat < 16; pat++) {
    readPat();
  }
  pat = 0;
  talkMIDI(0xB9, 0, 0x78);  //Bank select drums. midi cannel 10
  //talkMIDI(0xbf, 0x0c, 125);  //effect control 1 (sets global reverb decay)
  //talkMIDI(0xbf, 0x5b, 127);
  talkMIDI(0xC9, 30, 0);    //Set instrument number. 0xC9 is a 1 data byte command
  talkMIDI(0xB9, 0x07, Vol);//0x07 is channel message, set channel volume to near max (127)

  talkMIDI(0xB0, 0, 0x00); //Default bank GM1
  talkMIDI(0xC0, 37, 0); //Set instrument number. 0xC0 is a 1 data byte command
  talkMIDI(0xB0, 0x07, Vol);//0x07 is channel message, set channel volume to near max (127)
  //talkMIDI(0xB0, 0x5C, 125);  //effect control 1 (sets global reverb decay)
  while (1) {
    playNotes();
    delay(250 * 60 / tempo);
  }
}
void drawButton(int x, int y, int w, int h, const char* txt)
{
  tft.fillRoundRect(x, y, w, h, 3, ILI9341_RED);
  tft.drawRoundRect(x, y, w, h, 3, ILI9341_WHITE);
  tft.printAt(txt, x + 10, y + 6);
}
void printCopyTo()
{
  tft.printAt("To      :", 240, 195);
  tft.cursorToXY(300, 195);
  tft.print(copyTo, HEX);
}

void patCopy() {
  for (slope = 0; slope < 13; slope++) {
    instrument[slope][copyTo] = instrument[slope][pat];
  }
  copyPat = false;
}
void savePat() {
  split u;
  for (slope = 0; slope < 13; slope++) {
    u.s = instrument[slope][pat];
    dueFlashStorage.write(((slope * 2) + (pat * 24)), u.byte.byte1);
    dueFlashStorage.write(((slope * 2) + 1 + (pat * 24)), u.byte.byte2);
  }
}
void saveSong() {
  split u;
  for (slope = 0; slope < 13; slope++) {
    for (slope2 = 0;slope2 < 16; slope2++){
       u.s = pattern[slope2][slope + 1];
       dueFlashStorage.write(((slope * 2) + (slope2 * 26) + (408)), u.byte.byte1);
       dueFlashStorage.write(((slope * 2) + (slope2 * 26) + (409)), u.byte.byte2);
  }
}
}
void readPat()
{
  if (dueFlashStorage.read((pat * 26)) != 0xFF) {
    for (slope = 0; slope < 13; slope++) {
      instrument[slope][pat] = makeWord(dueFlashStorage.read((slope * 2) + 1 + (pat * 24)), dueFlashStorage.read((slope * 2) + (pat * 24)));
    }
  }
}
void readSong()
{
  for (slope = 0; slope < 13; slope++) {
    for(slope2=0;slope2<16;slope2++){
    pattern[slope2][slope + 1] = makeWord(dueFlashStorage.read((slope * 2)+(slope2 *26) + (409)), dueFlashStorage.read((slope * 2)+(slope2*26) + (408)));
  }
}
}
void drawPattern()
{
  for (x = 0; x < 16; x++) {
    for (slope2 = 0; slope2 < 13; slope2++) {
      tool = !((instrument[slope2][pat]) & (1 <<  x));
      xx = (x * 12) + 4;
      yy = 212 - (slope2 * 16);
      draw();
      TEXTCOLOR; 
    }
  }
} 

void drawSong()
{
  if (dueFlashStorage.read(408) != 0xFF) {
    readSong();
  }
  for (x = 0; x < 16; x++) {
    for (slope2 = 0; slope2 < 13; slope2++) {
      tool = !((pattern[songPart][slope2 + 1] >> x) & (1));
      xx = (x * 12) + 4;
      yy = 212 - (slope2 * 16);
      draw();
      TEXTCOLOR;
    }
  }
}
void plot() {
  tool = ((instrument[inst][pat] >> shift) & (1));
  instrument[inst][pat] = ((1 << shift) ^ (instrument[inst][pat]));
  draw();
  TEXTCOLOR;
}
void plotSong() {
  tool = ((pattern[songPart][posy] >> shift) & (1));
  pattern[songPart][posy] = ((1 << shift) ^ (pattern[songPart][posy]));
  draw();
  TEXTCOLOR;
}
void draw()
{
 if (tool)
  {
    color = ILI9341_BLUE;
  } else
  {
    color = ILI9341_RED;
  }
  tft.fillRect(xx, yy, 5 , 6, color);
  }
void drawRaster() {
  tft.fillScreen(ILI9341_BLUE);
  BUTTONCOLOR;

  drawButton(236, 212, 80, 20, "Start/Stop");
  drawButton(246, 20, 30, 20, "--");
  drawButton(281, 20, 30, 20, "++");
  drawButton(246, 60, 30, 20, "--");
  drawButton(281, 60, 30, 20, "++");
  drawButton(246, 90, 30, 20, "CL");
  drawButton(281, 90, 30, 20, "SV");
    if (!mode) {
    drawButton(246, 120, 30, 20, "CP");
    drawButton(281, 120, 30, 20, "PA");
    drawButton(236, 150, 80, 20, "Song  Mode");
    tft.fillRect(195, 32, 35, 14, ILI9341_WHITE);
    tft.fillRect(195, 48, 35, 14, ILI9341_BLACK);
    tft.fillRect(195, 64, 35, 14, ILI9341_WHITE);
    tft.fillRect(195, 80, 35, 14, ILI9341_BLACK);
    tft.fillRect(195, 96, 35, 14, ILI9341_WHITE);
    tft.fillRect(195, 112, 35, 14, ILI9341_BLACK);
    tft.fillRect(195, 128, 35, 14, ILI9341_WHITE);
    tft.fillRect(195, 144, 35, 14, ILI9341_WHITE);
    tft.fillRect(195, 160, 35, 14, ILI9341_BLACK);
    tft.fillRect(195, 176, 35, 14, ILI9341_WHITE);
    tft.fillRect(195, 192, 35, 14, ILI9341_BLACK);
    tft.fillRect(195, 208, 35, 14, ILI9341_WHITE);
    TEXTCOLOR;
    tft.printAt("Acc", 195, 23);
  }
  else {
    drawButton(236, 150, 80, 20, "Pat.  Mode");
    tft.fillRect(2, 224, 10, 14, ILI9341_BLACK);
    tft.cursorToXY(6, 227);
    tft.print(tick, HEX);
    }
  TEXTCOLOR;
  tft.printAt("Bass & Drum-Computer", 40, 5);
  for (int x = 0; x < 17; x++) {
    tft.drawFastVLine((x * 12) + 0, 14, 239, ILI9341_WHITE);
    tft.drawFastVLine((x * 12) + 1, 14, 239, ILI9341_WHITE);
  }
  for (int x = 14; x < 239; x += 16) {
    tft.drawFastHLine(0, x, 192, ILI9341_WHITE);
    tft.drawFastHLine(0, x + 1, 192, ILI9341_WHITE);
  }
}
void patternMode() {
  tick = -1;
  drawRaster();

  TEXTCOLOR;
  tft.cursorToXY(300, 180);
  tft.print(pat,HEX);
  tft.cursorToXY(300, 195);
  tft.print(nextPat,HEX);
  tft.cursorToXY(260, 10 );
  tft.print(tempo);
  tft.printAt("bpm", 285, 10);
  tft.cursorToXY(260, 50 );
  tft.print(Vol);
  tft.printAt("Vol", 285, 50);
  tft.fillRect(2, 224, 10, 14, ILI9341_BLACK);
  tft.drawRect(1, 15, 12, 224, ILI9341_RED);
  tft.printAt("Play Pat:", 240, 180);
  tft.printAt("Next Pat:", 240, 195);
  for (x = 0; x < 16; x++) {
    tft.cursorToXY(6 + (x * 12), 227);
    tft.print(x, HEX);
  }
}
void playNotes() {
  /*tempo=(analogRead(A0)*2);
  if (tempo < 100) {
        tft.cursorToXY(261, 10 );
        tft.print(" ");
        tft.print(tempo);
      }
      else {
        tft.cursorToXY(260, 10 );
        tft.print(tempo);
      }*/
  if(!mode){
    if(copyPat) tft.printAt("Copy", 240, 180);
  else
  {
    tft.printAt("Play", 240, 180);
    tft.cursorToXY(300, 180);
    tft.print(pat, HEX);
    tft.cursorToXY(300, 195);
    tft.print(nextPat, HEX);
    }
  if (!play)  return;
      if (tick != -1) {
      tft.fillRect((tick) * 12 + 2, 224, 10, 14, ILI9341_BLUE);
      tft.drawRect((tick) * 12 + 1, 15, 12, 224, ILI9341_WHITE);
      tft.cursorToXY(6 + (tick * 12), 227);
      tft.print(tick, HEX);
    }
    tick += 1;
    if (tick == 16) {
      tick = 0;
      if ((pat != nextPat)&&(!copyPat)) {
        pat = nextPat;
        readPat();
        drawPattern();
        }
    }
    tft.fillRect((tick) * 12 + 2, 224, 10, 14, ILI9341_BLACK);
    tft.drawRect((tick) * 12 + 1, 15, 12, 224, ILI9341_RED);
    tft.cursorToXY(6 + (tick * 12), 227);
    tft.print(tick, HEX);

    for (slope = 0; slope < 12; slope++) {
      if ((instrument[slope][pat] >> tick) & (1) & (pat < 8)) noteOn(9, patch[slope], 40+(((instrument[12][pat] >> tick) & (1))*20));
      if ((instrument[slope][pat] >> tick) & (1) & (pat > 7)) noteOn(0, bass[slope], 40+(((instrument[12][pat] >> tick) & (1))*20));
    }return;
  }
  if (!play)  return;
  else {
          SONGPART;
          tick += 1;
    if (tick == 16) {
      tick = 0;
      if (pos == 13) {
        pos = 0;
        songPart +=1;
        if(songPart<16) drawSong();
        if(songPart>15){
        songPart=0;
        tft.fillRect((songPart) * 12 + 2, 224, 10, 14, ILI9341_BLACK);
        tft.cursorToXY(6 + ((songPart) * 12), 227);
        tft.print(songPart, HEX);

        tft.fillRect(182, 224, 10, 14, ILI9341_BLUE);
        tft.cursorToXY(186, 227);
        tft.print(15, HEX);
        }else{
        tft.fillRect((songPart-1) * 12 + 2, 224, 10, 14, ILI9341_BLUE);
        tft.cursorToXY(6 + ((songPart-1) * 12), 227);
        tft.print(songPart-1, HEX);

        tft.fillRect(songPart * 12 + 2, 224, 10, 14, ILI9341_BLACK);
        tft.cursorToXY(6 + (songPart * 12), 227);
        tft.print(songPart, HEX);
        }
      }
      if (pos == 0)
      {
        tft.drawRect(1, 15, 192, 16, ILI9341_WHITE);
      }
      tft.drawRect(1, 207 - (pos * 16), 192, 16, ILI9341_RED);
      tft.drawRect(1, 223 - (pos * 16), 192, 16, ILI9341_WHITE);
      pos += 1;
      }
      for (slope = 0; slope < 12; slope++) {
      for(slope2 = 0; slope2<16;slope2++){
      if (pattern[songPart][pos] & (1<< slope2)) {
         if ((instrument[slope][slope2] >> tick) & (1)&(slope2<8)) {noteOn(9, patch[slope], 40+(((instrument[12][slope2] >> tick) & (1))*20));}
      else{
         if ((instrument[slope][slope2] >> tick) & (1)) noteOn(0, bass[slope], 40+(((instrument[12][slope2] >> tick) & (1))*20));
      }
      }
     }
}
}
}
void songMode()
{
  SONGPART;
  pos = 1;
  tick = 15;
  drawRaster();

  TEXTCOLOR;
  tft.printAt("bpm", 285, 10);
  tft.cursorToXY(260, 10 );
  tft.print(tempo);
  tft.printAt("Vol", 285, 50);
  tft.cursorToXY(260, 50 );
  tft.print(Vol);

  tft.drawRect(1, 207, 192, 16, ILI9341_RED);

  for (x = 0; x < 16; x++) {
    tft.cursorToXY(6 + (x * 12), 227);
    tft.print(x, HEX);
  }
  tick = -1;
  drawSong();
}
void readTouch() {
  currentMillis = millis();
    
  if ((myTouch.dataAvailable() == true) && (currentMillis - previousMillis >= interval)) {
    previousMillis = currentMillis;
    myTouch.read();
    x = myTouch.getX();  //Get touch point
    y = myTouch.getY();
    
    //play note
    if((!mode)&&(x>195)&&(x<230)){
    for(yy=0;yy<12;yy++)
    {
    if((y>(yy*16)+32)&&(y<(yy*16)+47)){
    break;  
    }
}
  if(pat<8){
  noteOn(9, patch[11-yy], 60);
}else {noteOn(0, bass[11-yy], 60);}
return;
}

    if ((x > 235) && (x < 317) && (y > 211) && (y < 236)) {
      play = !play;  //Start/Stop button
      return;
    }

      if ((x > 245) & (x < 275) & (y > 15) & (y < 40) || (x > 280) & (x < 310) & (y > 15) & (y < 40)) { //tempo buttons
      if (x > 280) {
        tempo += 1;
      }
      else {
        tempo -= 1;
      }
      if (tempo < 100) {
        tft.cursorToXY(261, 10 );
        tft.print(" ");
        tft.print(tempo);
      }
      else {
        tft.cursorToXY(260, 10 );
        tft.print(tempo);
        }return;
    }

    if ((x > 245) & (x < 275) & (y > 60) & (y < 85) || (x > 280) & (x < 310) & (y > 60) & (y < 85)) { //volume button
      if (x > 280) {
        Vol += 1; if (Vol > 127)Vol = 127; talkMIDI(0xbf, 0x07
            , Vol);
      }
      else {
        Vol -= 1;
        if (Vol < 0)Vol = 0;
        talkMIDI(0xbf, 0x07, Vol);
      }
      if (Vol < 100) {
        tft.cursorToXY(261, 50 );
        tft.print(" ");
        tft.print(Vol);
      }
      else {
        tft.cursorToXY(260, 50 );
        tft.print(Vol);
        }return;
    }

    if ((x > 245) & (x < 275) & (y > 90) & (y < 115)) {
      if (!mode) // clear pattern
      { for (slope = 0; slope < 13; slope++) {
          instrument[slope][pat] = 0;
        }
        for (xx = 4; xx < 185; xx += 12)
        {
          for (yy = 20; yy < 228; yy += 16)
          { 
            tool=true;
            draw();
            TEXTCOLOR;
            }
        }
      } else //clear song
      { for (slope = 1; slope < 14; slope++) {
        for (slope2 = 0;slope2<16;slope2++){
          pattern[slope2][slope] = 0;
        }
      }
        for (xx = 4; xx < 185; xx += 12)
        {
          for (yy = 20; yy < 228; yy += 16)
          { 
            tool=true;
            draw();
            TEXTCOLOR;
            }
        }
      }
    }
    if ((x > 280) & (x < 310) & (y > 90) & (y < 115)) // save pattern / song
    {
      if (!mode) {
        savePat();
      } else {
        saveSong();
        }return;
    }

    if ((y > 224) & (y < 236)) {
        for (slope = 0; slope < 16; slope++) {
        if ((x > (slope * 12) & (x < ((slope * 12) + 12)))) //read pattern
        { if(!mode){
          if (copyPat) {
            copyTo = slope;
            printCopyTo();
           }
          if ((!play)&&(!copyPat)) {
            pat = slope;
            drawPattern();
            }
          nextPat = slope; 
          return;
        }else{
          songPart = slope;
          SONGPART;
          drawSong();
          return;
        }
      }
    }
  }
    if ((x > 245) & (x < 275) & (y > 120) & (y < 145) & (!mode)) //copy pattern
    {
      copyPat = true;
      return;
    }
    if ((x > 280) & (x < 310) & (y > 120) & (y < 145) & (!mode)) //paste pattern
    {
      patCopy();
      pat = nextPat = copyTo;
      drawPattern();
      tft.cursorToXY(240, 195);
      tft.print("Next Pat:");
      return;
    }
    if ((x > 235) && (x < 317) & (y > 150) & (y < 175)) //song mode
    {
      play = false;
      mode = !mode;
      if (!mode) {
        patternMode(); 
        drawPattern();
        }
      else {
        songMode();
      }
      return;
    }
    if (!mode) {
      for (slope = 0; slope < 13; slope++) {
        if ((y > (208 - (slope * 16))) && (y < (220 - (slope * 16)))) {
          inst = slope;
          yy = 212 - (slope * 16);
          trueValue = true;
          break;
        }
      }
      if(!trueValue)return;
      for (slope = 0; slope < 16; slope++)
        if ((x > (slope * 12)) && (x < (slope * 12) + 12)) {
          shift = slope;
          xx = (slope * 12) + 4;
          trueValue = false;
          if(!mode) plot();
          else { posy = yy + 16; plotSong(); }
          }
          return;
    }
    if (mode) {
      for (slope = 0; slope < 13; slope++) {
        if ((y > (208 - (slope * 16))) && (y < (220 - (slope * 16)))) {
          posy = slope + 1;
          yy = 212 - (slope * 16);
          trueValue = true;
          break;
        }
      }
      if(!trueValue)return;
      for (slope = 0; slope < 16; slope++)
        if ((x > (slope * 12)) && (x < (slope * 12) + 12)) {
          shift = slope;
          xx = (slope * 12) + 4;
          trueValue = false;
          plotSong();
          }
    return;
    }
  }
yield();
}
/*

  File:     MP3_Shield_RealtimeMIDI.ino
  Author:   Matthias Neeracher

  This code is in the public domain, with the exception of the contents of sVS1053b_Realtime_MIDI_Plugin.

  The code is based on Nathan Seidle's Sparkfun Electronics example code for the Sparkfun
  MP3 Player and Music Instrument shields and and VS1053 breakout board.

  http://www.sparkfun.com/Code/MIDI_Example.pde
  http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Dev/Arduino/Shields/VS_Shield_Example.zip

       Spark Fun Electronics 2011
       Nathan Seidle

       This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

  THEORY OF OPERATIONS

  The VS1053b has two ways of playing MIDI: One method is that you simply send a Standard MIDI level 0 file through
  SPI, and the chip will play it. This works exactly the same way as MP3 mode and will not be discussed further here.
  The other method is that the VS1053b has a "Real Time MIDI mode", in which it will instantly execute MIDI commands
  sent to it through either the UART or SPI.

  Real Time MIDI mode can be enabled with two different methods, controlled by USE_GPIO_INIT
   (1) Setting GPIO1 to HIGH (which is hardwired in the Sparkfun Music Instrument shield, and can be done through
       pin 4 in the MP3 Player Shield)
   (0) Sending a small software patch through SPI.

  MIDI data can be sent with two different methods as well, controlled by USE_SPI_MIDI
   (0) Through a (software) serial connection on pin 3, at 31250 baud
   (1) Through SPI, at an arbitrary data rate. For SPI, each byte of MIDI data needs to be prefixed by a 0 byte
       (The V1053b data sheet erroneously states that the padding should be a 0xFF byte).

  Both initialization methods and both transmission methods can be selected through the #defines below. Out of the box,
  it probably makes most sense to enable real time MIDI through pin 4, and send serial data through pin 3, but if you
  want to cut the traces for pin 3 and 4 and use those pins for another purpose, the alternative methods may come in
  handy.
*/
void sendMIDI(byte data)
{
  SPI.transfer(0x00);
  SPI.transfer(data);
}
//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) {
  //
  // Wait for chip to be ready (Unlikely to be an issue with real time MIDI)
  //
  SPI.beginTransaction(vs1053);
  while (!digitalRead(VS_DREQ));
  digitalWrite(VS_XDCS, LOW);
  sendMIDI(cmd);
  //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 || (cmd & 0xF0) >= 0xE0) {
    sendMIDI(data1);
    sendMIDI(data2);
  } else {
    sendMIDI(data1);
  }
  digitalWrite(VS_XDCS, HIGH);
  SPI.endTransaction();
  }
//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);
}

Comments

Similar projects you might like

Arduino Morse Code Machine

Project showcase by Vlada Krsmanovic

  • 10,570 views
  • 1 comment
  • 31 respects

Minimal MIDI Drum Kit with 3D Printer

Project tutorial by ryokosaka

  • 9,882 views
  • 1 comment
  • 29 respects

Arduino-Based Bitcoin Candy Vending Machine

Project tutorial by Team Elkrem

  • 3,767 views
  • 17 comments
  • 38 respects

Onboard computer for bicycle

Project in progress by Pararera

  • 3,244 views
  • 15 comments
  • 15 respects

Morse Code Machine

Project showcase by brzi

  • 3,123 views
  • 1 comment
  • 7 respects

Arduino Due TIC TAC TOE with Touchscreen

Project tutorial by rom3

  • 1,873 views
  • 5 comments
  • 0 respects
Add projectSign up / Login