Skip to content

Instantly share code, notes, and snippets.

@Electronza
Created December 19, 2019 09:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Electronza/3e255979e734f07f0d07c3a7c131437d to your computer and use it in GitHub Desktop.
Save Electronza/3e255979e734f07f0d07c3a7c131437d to your computer and use it in GitHub Desktop.
chipKIT: TouchClamp click drum machine
/*******************************************************************
____ __ ____ ___ ____ ____ __ __ _ ____ __
( __)( ) ( __)/ __)(_ _)( _ \ / \ ( ( \(__ ) / _\
) _) / (_/\ ) _)( (__ )( ) /( O )/ / / _/ / \
(____)\____/(____)\___) (__) (__\_) \__/ \_)__)(____)\_/\_/
Project name: chipKIT: TouchClamp click drum machine
Project page: https://electronza.com/chipkit-vs1053-touchclamp-drums
********************************************************************/
/*********************************************************
VS1053 DRUM MACHINE
HARDWARE: CHIPKIT UNO32 http://chipkit.net/wpcproduct/chipkit-uno32/
ARDUINO UNO CLICK SHIELD http://www.mikroe.com/click/arduino-uno-shield/
TOUCH CLAMP CLICK http://www.mikroe.com/click/touchclamp/
MP3 CLICK http://www.mikroe.com/click/mp3/
SOFTWARE: ARDUINO IDE V.1.6.9
ADAFRUIT MPR121 LIBRARY https://github.com/adafruit/Adafruit_MPR121
Note: in Adafruit_MPR121.cpp, in function
void Adafruit_MPR121::writeRegister(uint8_t reg, uint8_t value)
change Wire.endTransmission();
to Wire.endTransmission(true);
VS1053 CODE INSPIRED FROM https://gist.github.com/microtherion/2636608
PROJECT PAGE: https://electronza.com/
*******************************************************************
This is a library for the MPR121 12-channel Capacitive touch sensor
Designed specifically to work with the MPR121 Breakout in the Adafruit shop
----> https://www.adafruit.com/products/
These sensors use I2C communicate, at least 2 pins are required
to interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
**********************************************************/
#include <Wire.h>
#include <SPI.h>
#include "Adafruit_MPR121.h"
// TouchClamp click uses address 0x5A
// A second touch clamp click can be added, address being changed
// by moving the jumpers onto the TouchClamp click
// One TouchClamp click allows for seven percussion instruments
Adafruit_MPR121 cap = Adafruit_MPR121();
// Keeps track of the last pins touched
// so we know when buttons are 'released'
uint16_t lasttouched = 0;
uint16_t currtouched = 0;
// Here we define the percussion instruments played
// For a complete list see
// http://soundprogramming.net/file-formats/general-midi-drum-note-numbers/
// TouchClamp mapping
// A = 7 (Bass drum 1 - note 36)
// B = 6 (Snare Drum 1 - note 38)
// C = 5 (Low Tom 1 - note 43)
// D = 3 (Mid Tom 1 - note 47)
// E = 2 (High Tom 1 - note 50)
// F = 1 (Ride Cymbal 1 - note 51)
// G = 0 (Pedal Hi-hat - note 44)
// H = 4 (on the touch clamp, not used)
// I will set it to 46 Open Hi-hat
byte drums[] = {44, 51, 50, 47, 46, 43, 38, 36};
// Pin definitions for Arduino Click shield socket B
#define VS_XCS 9 // Control Chip Select Pin (SPI Control/Status registers)
#define VS_XDCS 3 // Data Chip Select / BSYNC Pin
#define VS_DREQ A1 // Data Request Pin: Player asks for more data
#define VS_RESET A2 // Reset is active low
void setup() {
// For debugging, comment if running in standalone mode
// also comment all other Serial... lines
while (!Serial); // needed to keep leonardo/micro from starting too fast!
Serial.begin(9600);
Serial.println("Adafruit MPR121 Capacitive Touch sensor test");
if (!cap.begin(0x5A)) {
Serial.println("MPR121 not found, check wiring?");
while (1);
}
Serial.println("MPR121 found!");
// debugging end
// Set up VS10523 / MP3 click
pinMode(VS_DREQ, INPUT);
pinMode(VS_XCS, OUTPUT);
pinMode(VS_XDCS, OUTPUT);
digitalWrite(VS_XCS, HIGH); //Deselect Control
digitalWrite(VS_XDCS, HIGH); //Deselect Data
pinMode(VS_RESET, OUTPUT);
//Initialize VS1053 chip
digitalWrite(VS_RESET, LOW); //Put VS1053 into hardware reset
// Setup SPI for VS1053
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
//From page 12 of datasheet, max SCI reads are CLKI/7. Input clock is 12.288MHz.
//Internal clock multiplier is 1.0x after power up.
//Therefore, max SPI speed is 1.75MHz.
// ChipKit UNO32 runs at 80MHz
// 80MHz / 1.7MHz = 47.05
// We choose 1/64 as divider. As such the SPI clock is 1.24 MHz
SPI.setClockDivider(SPI_CLOCK_DIV64); //Set SPI bus speed
SPI.transfer(0xFF); //Throw a dummy byte at the bus
delayMicroseconds(20); // just allow for some time to pass
digitalWrite(VS_RESET, HIGH); //Bring up VS1053
// Load the realtime MIDI plugin
VSLoadUserCode();
delay(50);
// Set instrument bank
talkMIDI(0xB0, 0, 0x78); // Percussion bank
// Set instrument
talkMIDI(0xC0, 43, 0);
// set the volume to 120
talkMIDI(0xB0, 0x07, 120);
}
void loop() {
// Get the currently touched pads
currtouched = cap.touched();
for (uint8_t i=0; i<12; i++) {
// it if *is* touched and *wasnt* touched before, alert!
if ((currtouched & _BV(i)) && !(lasttouched & _BV(i)) ) {
Serial.print(i); Serial.println(" touched");
// Play instrument
noteOn(0, drums[i], 127);
delay(5);
}
// if it *was* touched and now *isnt*, alert!
if (!(currtouched & _BV(i)) && (lasttouched & _BV(i)) ) {
Serial.print(i); Serial.println(" released");
// do nothing with the MIDI
}
}
// reset last state
lasttouched = currtouched;
}
/*********************************************************
* VS1053 functions
* ******************************************************/
// Write to VS10xx register
// SCI: Data transfers are always 16bit. When a new SCI operation comes in
// DREQ goes low. We then have to wait for DREQ to go high again.
// XCS should be low for the full duration of operation.
void VSWriteRegister(unsigned char addressbyte, unsigned char highbyte, unsigned char lowbyte) {
while (!digitalRead(VS_DREQ)) ; //Wait for DREQ to go high indicating IC is available
digitalWrite(VS_XCS, LOW); //Select control
//SCI consists of instruction byte, address byte, and 16-bit data word.
SPI.transfer(0x02); //Write instruction
SPI.transfer(addressbyte);
SPI.transfer(highbyte);
SPI.transfer(lowbyte);
while (!digitalRead(VS_DREQ)) ; //Wait for DREQ to go high indicating command is complete
digitalWrite(VS_XCS, HIGH); //Deselect Control
}
// Plugin to put VS10XX into realtime MIDI mode
// Originally from http://www.vlsi.fi/fileadmin/software/VS10XX/vs1053b-rtmidistart.zip
// Permission to reproduce here granted by VLSI solution.
//
const unsigned short sVS1053b_Realtime_MIDI_Plugin[28] = { /* Compressed plugin */
0x0007, 0x0001, 0x8050, 0x0006, 0x0014, 0x0030, 0x0715, 0xb080, /* 0 */
0x3400, 0x0007, 0x9255, 0x3d00, 0x0024, 0x0030, 0x0295, 0x6890, /* 8 */
0x3400, 0x0030, 0x0495, 0x3d00, 0x0024, 0x2908, 0x4d40, 0x0030, /* 10 */
0x0200, 0x000a, 0x0001, 0x0050,
};
// This function loads the user code
void VSLoadUserCode(void) {
int i = 0;
while (i < sizeof(sVS1053b_Realtime_MIDI_Plugin) / sizeof(sVS1053b_Realtime_MIDI_Plugin[0])) {
unsigned short addr, n, val;
addr = sVS1053b_Realtime_MIDI_Plugin[i++];
n = sVS1053b_Realtime_MIDI_Plugin[i++];
while (n--) {
val = sVS1053b_Realtime_MIDI_Plugin[i++];
VSWriteRegister(addr, val >> 8, val & 0xFF);
}
}
}
// Send one MIDI byte
void sendMIDI(byte data)
{
SPI.transfer(0);
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)
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);
}
}
//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);
//talkMIDI( (0xA0 | channel), note, 127);
}
//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);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment