Author Archives: admin

Arduino Touch Switch Midi Drum Controller

There are some chunks of code not used, I had a note off queue but disabled it as on followed by off seems to work for the drum notes. I’ve been outputting to an Adafruit VS1053 module. The drums[] array holds the notes for each drum.

It uses an Arduino Nano and an MPR121 capacitive touch sensor on the I2C bus. The midi out circuit (thanks to Nuts and Volts) is connected to A2.

// drumkit.ino 2022 Scott McCagg
#define APPNAME "drumkit"
#define VERSION 20221122
#define DEBUG true
#include <Wire.h>

#define VS1053_RX  A2
//#define VS1053_RESET A3
//#define PINRX 11 // MIDI in
//#define PINTX 0

//#define RCDA 5
//#define RCCL 6
/*
// rotary encoder
uint8_t counter = 0;                    //Use this variable to store "steps"
uint8_t currentStateClock;              //Store the status of the clock pin (HIGH or LOW)
uint8_t lastStateClock;                 //Store the PREVIOUS status of the clock pin (HIGH or LOW)
*/

#include <SoftwareSerial.h>
SoftwareSerial MIDIPORT(0, VS1053_RX);
//SoftwareSerial b2b(PINRX, PINTX);

// MIDI defines
#define MIDI_NOTE_ON  0x90
#define MIDI_NOTE_OFF 0x80

#define MIDI_CHAN_MSG 0xB0
#define MIDI_CHAN_BANK 0x00
#define MIDI_CHAN_VOLUME 0x07
#define MIDI_CHAN_PROGRAM 0xC0
#define MIDI_FOOT_PEDAL 0x65
#define VS1053_BANK_DEFAULT 0x00
#define VS1053_BANK_DRUMS1 0x78
#define VS1053_BANK_DRUMS2 0x7F
#define VS1053_BANK_MELODY 0x79
#define VS1053_GM1_OCARINA 89

#define CAPS 1
uint16_t capadrs[CAPS] = { 0x5A };
#include "Adafruit_MPR121.h"
Adafruit_MPR121 cap[CAPS] = Adafruit_MPR121();
// Keeps track of the last pins touched
// so we know when buttons are 'released'
uint16_t lastCap[CAPS];
uint16_t currCap[CAPS];

uint8_t pntr = 0;
char bufr[128];

uint8_t row = 0;
uint8_t col = 0;

#define NQSIZE 1024
uint8_t nqueue[NQSIZE];
uint16_t nqpntr = 0;
uint16_t nqlast = 0;
uint8_t nqwait = 1000;
long nqtimer = millis() + nqwait;

char charbufr;
char inbufr[256];
char inpntr = 0;

char drumbufr[27]; // 12*2, chksum,\0
const uint8_t drums[12] = {
  49, 45, 41, 51, 48, 53, 57, 36, 38, 37, 46, 42
};

void putKit() {
  byte chksum = 0;
  memset(drumbufr, 26, 0);
  for(int j=0; j<12; j++) {
    sprintf(drumbufr+(j*2),"%02x",drums[j]);
    chksum += drums[j];
  }
  sprintf(drumbufr+24,"%02x",chksum);
  Serial.print("drumbufr["); Serial.print(drumbufr); Serial.println("]");
}

void getKit() {
  Serial.println("getKit");
  
}
void setup() {
    Serial.begin(9600);
    if (DEBUG == true) {
      while (!Serial){
      ;
    }
    Serial.print("\n\n\n\n\n\n\n\nBoot...\n");
    Serial.print("APPNAME: ");
    Serial.println(APPNAME);
    Serial.print("VERSION: ");
    Serial.println(VERSION);
  }
  // cap touch boards
  for (int x=0; x < CAPS; x++) {
    if (DEBUG == true) { Serial.print("Starting "); Serial.println(x); }
    if (! cap[x].begin(capadrs[x])) { 
      if (DEBUG == true) { Serial.println(" Fail!"); }
    } 
  }

  MIDIPORT.begin(31250); // MIDI uses a 'strange baud rate'
 /*   
  // VS1053 init
  pinMode(VS1053_RESET, OUTPUT);
  digitalWrite(VS1053_RESET, LOW);
  delay(10);
  digitalWrite(VS1053_RESET, HIGH);
  delay(10); 
  vs1053SetChannelBank(0, VS1053_BANK_DRUMS1);
  vs1053SetInstrument(0, 1);
  vs1053SetChannelVolume(0, 127);

  // Board to board comm
  pinMode(PINRX, INPUT);
  pinMode(PINTX, OUTPUT);
  b2b.begin(19200);
  if (b2b.isListening()) {
    Serial.println("listening");
  }
  // Rotary Encoder
  pinMode(RCCL,INPUT_PULLUP);
  pinMode(RCDA,INPUT_PULLUP);
  // lcd
  lcd.init();
  lcd.clear();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("Arduichord");
 */
  memset(inbufr, '\0', 256);
  inpntr = 0;
  if (DEBUG == true) Serial.println("Up");
}

void loop() {
  if (Serial.available() > 0) {
    charbufr = Serial.read();   
    inbufr[inpntr] = charbufr;
    inpntr++; 
    //Serial.println(charbufr);
    if (charbufr == 13) { // EOL
      inbufr[--inpntr] = 0;
      Serial.println(inbufr);
      // putKit request
      if (strcmp(inbufr, "?") == 0) {
         putKit();
      }
      // getKit
      if (inbufr[0] == '!') {
        getKit();
      }
      // clear input buffer
      memset(inbufr, '\0', 256);
      inpntr = 0;
    }

  }
  if (millis() > nqtimer) { // Note Off Queue
    /*
    if (nqpntr != nqlast) {
      Serial.print("note off:");
      Serial.println(nqueue[nqlast]);
      //noteOn(0x90, nqueue[nqlast], 0x00);
      nqlast++; if (nqlast > 255) nqlast = 0;
      

    }
    nqtimer = millis() + nqwait;
    */
  }
  pntr = 0;
  currCap[pntr] =  cap[pntr].touched(); 
  for (uint8_t i = 0; i < 12; i++) { // it if *is* touched and *wasnt* touched before, alert!
    if ((currCap[pntr] & _BV(i)) && !(lastCap[pntr] & _BV(i)) ) { 
      if (DEBUG == true) { Serial.print("Cap1:"); Serial.println(i); }
      noteOn(0x90, drums[i], 0x45); 
      noteOn(0x90, drums[i], 0x00);
      /*
      nqueue[nqpntr++] = drums[i];
      if (nqpntr > 255) { 
        Serial.println("Queue Reset");
        nqpntr = 0;
      }
    */
    } 
    /*
    if (!(currCap[pntr] & _BV(i)) && (lastCap[pntr] & _BV(i)) ) { // if it *was* touched and now *isnt*, alert!
          //noteOn(0x90, drums[row], 0x00);
    }
    */
  }
  // reset our state
  lastCap[pntr] = currCap[pntr];
}

void noteOn(int cmd, int pitch, int velocity) {
  MIDIPORT.write(cmd);
  MIDIPORT.write(pitch);
  MIDIPORT.write(velocity);
  if (DEBUG == true) Serial.println("noteOn");
}
/*
void vs1053SetInstrument(uint8_t chan, uint8_t inst) {
  if (chan > 15) return;
  inst --; // page 32 has instruments starting with 1 not 0 :(
  if (inst > 127) return;
  
  MIDIPORT.write(MIDI_CHAN_PROGRAM | chan);  
  MIDIPORT.write(inst);
}

void vs1053SetSustain(uint8_t chan, uint8_t vol) {
  if (chan > 15) return;
  if (vol > 127) return;
  
  MIDIPORT.write(MIDI_CHAN_MSG | chan);
  MIDIPORT.write(MIDI_FOOT_PEDAL);
  MIDIPORT.write(vol);
}

void vs1053SetChannelVolume(uint8_t chan, uint8_t vol) {
  if (chan > 15) return;
  if (vol > 127) return;
  
  MIDIPORT.write(MIDI_CHAN_MSG | chan);
  MIDIPORT.write(MIDI_CHAN_VOLUME);
  MIDIPORT.write(vol);
}

void vs1053SetChannelBank(uint8_t chan, uint8_t bank) {
  if (chan > 15) return;
  if (bank > 127) return;
  
  MIDIPORT.write(MIDI_CHAN_MSG | chan);
  MIDIPORT.write((uint8_t)MIDI_CHAN_BANK);
  MIDIPORT.write(bank);
}

void vs1053NoteOn(uint8_t chan, uint8_t n, uint8_t vel) {
  if (chan > 15) return;
  if (n > 127) return;
  if (vel > 127) return;
  if (DEBUG == true) Serial.println(n);
  MIDIPORT.write(MIDI_NOTE_ON | chan);
  MIDIPORT.write(n);
  MIDIPORT.write(vel);
}

void vs1053NoteOff(uint8_t chan, uint8_t n, uint8_t vel) {
  if (chan > 15) return;
  if (n > 127) return;
  if (vel > 127) return;
  
  MIDIPORT.write(MIDI_NOTE_OFF | chan);
  MIDIPORT.write(n);
  MIDIPORT.write(vel);
}
*/

Weather Station Zero

Demo Page Link – http://cozmotronics.com/arduino/weather/

Concept – Monitors the Temperature, Humidity, and Barometric Pressure out on our deck.

Parts – Uses a DHT11 for the temperature and humidity readings and a BMP280 for the barometric pressure. The MCU is an Adafruit Hazzah ESP8266.

Development Prototype
The Circuit

Finished Device:

Update 2019-10-23 – Redesigned using ESP8266 and BME280, complete software overhaul!

1962 Duo Sonic – Only Better!

Custom Build by my brother Todd L. McCagg as my 2018 Brithday/Christmas present

My first guitar was a 1962 Fender Duo Sonic, my brother went to great lengths to not just reproduce that guitar that build it with the best modern hardware available.

  • Fender donor body
  • Warmoth Neck
  • Schaller Bridge
  • HipShot Tuners
  • Kent Armstrong Custom Wound Pickups
  • Switchcraft Switch and Jack
  • Bournes MIL Spec pots

Truly the sweetest guitar I have!