Created
December 19, 2019 09:09
-
-
Save Electronza/3e255979e734f07f0d07c3a7c131437d to your computer and use it in GitHub Desktop.
chipKIT: TouchClamp click drum machine
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************* | |
____ __ ____ ___ ____ ____ __ __ _ ____ __ | |
( __)( ) ( __)/ __)(_ _)( _ \ / \ ( ( \(__ ) / _\ | |
) _) / (_/\ ) _)( (__ )( ) /( 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