Introducing the Colliadora Series

Three visionaries with custom-made MIDI instruments sporting custom button mappings all with the intention of uniting the world by blowing minds.

Description

Three ambitious young men have joined forces. Coming from distinctly different musical backgrounds, they have created a new class of computer musical instrument: custom-built to their rigorous specifications with natural shells and re-programmable through an aesthetically pleasing and easy-to-use graphical user interface running on the Java-based Processing language. With the ability to switch between custom button mappings on the fly and produce more than one musical source at a time, this trio can produce the sound of an orchestra or a thumping dance club. They will blow minds one at a time.

for(int mindsBlown = 3; mindsBlown < ∞; mindsBlown++){

Personal Statement

Mr. McMasters looked through the frosting to look for a triumphant family. He found the Ketsas living in the Jembrana region of Bali during ancient, unseen times. He chronicled four generations of their struggles and triumphs. During the third generation, a holy musical instrument appeared in the dreams of Yalim, the son of Paraseti and Grandson to Djatu. He followed the vision, built the instrument and gave it to his son, Sesho. Sesho went on to use the instrument to unite the people of the Jembrana region and bring peace to the land.

Mr. McMasters has informed us of the properties of this divine tool and we have followed his commands and reconstructed it as faithfully as we can with modern technology. They are gifts from the great ether of inspiration.

Background

Knowledge of Processing, MIDI, XBee radios, circuitry for analog and digital inputs, gourd carving, tonal theory, and Mr. McMasters have all richly contributed to the culmination of these instruments. All required much research.

Audience

Everyone and their babies and their grandparents and their great grandparents.

User Scenario

You come, you hear, your mind explodes, and then you bond with everyone around you who also has an exploded brain.

Implementation

They are made of wood or gourds, they are filled with wires and techy stuff, and they are played with the hands, the mind, and the spirit.

Conclusion

We are closer to understanding Mr. McMasters' story of Yalim from the Four Generations and the byproducts form a bounty of knowledge about microcontrollers, serial communication, the innards of gourds, and many, many other things.

References

All credit goes to Mr. McMasters, Yalim, and the little receptors in ourselves that allow us to hear from the both of them.

Photos

(more photos on the way!)

Charles working on the GUI


the analog PlayStation style joysticks


the bottom of a beautifully soldered XBee breakout board


XBee!


the neck of the GuiToque


thumb board on the back of the neck

Playback Mode Source Code

/*
EXPLANATION OF PLAYBACK MODE

5 Maps uploaded from the GUI:
Maps are different setups for Buttons and all the values contained within them.

10 Buttons per Map:
Buttons are analog joysticks with momentary digital switches on the z-axis.

3 Positions per Button:
Positions are different ways to move a Button:
Low = Low range on the analog stick.
Middle = High reading on the digital switch.
High = High range on the analog stick.

3 Slots per Position:
Slots are places that store Properties of Abilities.
Each Slot value in the fullArray contains two bytes:
Which Map and which Slot on that Map

3 Properties of Abilities per Slot:
Properties include a Declarator of Ability,
Ability, and degree of Ability.
EXAMPLE: Properties for Slot[0]
Property[0] = 1 // a note-on channel change
Property[1] = 144 // note-on for channel one
Property[2] = 254 // an unused byte

Properties for Slot[1]
Property[3] = 4 // an octave change
Property[4] = 146 // octave change on channel 3
Property[5] = 48 // (48 - 60) + pitches on channel 3
*/

#include // Library for Flash memory. This lets us store values in memory so that we can recall our maps without uploading again.
PROGMEM prog_uint16_t savedArray[2250];

byte fullArray[2250]; //This stores all the numbers we'll need for everything.

boolean uploadMode = false; // True if the digital read of the PBULpin is 0, and it runs communication with the GUI from the computer
boolean playbackMode = false; // True if the digital read of the PBULpin is 1, and it runs communication with the CDo
boolean uploadComplete = false; // True once fullArray is loaded up with Serial.read from the GUI.
boolean valuesSaved = true; // True once fullArray is saved into EEPROM.
boolean valuesLoaded = false; //For loading values from EEPROM when in the beginning of playback mode. This takes 256 seconds.
boolean slotParse = false; //For getting active slot values from the fullArray.
int firstSlotbyte = 0;
int secondSlotbyte = 0;
int slotCounter = 0;
boolean propertyParse = false; //For getting property values for each slot.

int activeMap = 0;
byte slot[450]; // number of possible slot numbers
byte declarator[450];
byte ability[450];
byte degree[450];
int propertyCounter = 0;
int PBULpin = 13;

//variables for mux
int muxValue[16];
int a= 2;
int b= 3;
int c= 4;
int d= 5;
int analog0 = 0;

//variables for midiBytes
byte midiByte1[10];
byte midiByte2[10];
byte midiByte3[10];

void setup() {

// initialize serial communications at 9600 bps:
if(digitalRead(PBULpin) == 0){ //uploadMode
Serial.begin(9600);
uploadMode = true;
}else if(digitalRead(PBULpin) == 1){
Serial.begin(31250);
playbackMode = true;
}

// fill Slots with ("blanks")
for (int i = 0; i < 127; i++) {
slot[i] = 254;
}

//variables for mux
pinMode(analog0, INPUT);
pinMode(a,OUTPUT);
pinMode(b,OUTPUT);
pinMode(c,OUTPUT);
pinMode(d,OUTPUT);
}

void loop() {
//============================
===========================================================
//Upload
if(uploadMode){
if(!uploadComplete){
if (Serial.available () > 0) {
for (int i = 0; i < 512; i++){
fullArray[i] = Serial.read();
//Serial.print(Pvalues[i],BYTE); // Uncomment if you need to check for a problem between Processing and Arduino
}
}
uploadComplete = true;
valuesSaved = false;
}
//----------------------------------------------------------------------------------------
if(!valuesSaved){
for (int i = 0; i < 512; i++){
if (fullArray[i] != 255 && fullArray[i] !=-1){
PROGMEM prog_uint16_t savedArray[i] = fullArray[i];
//delay(100); //uncomment if you need to slow it down
}
}
valuesSaved = true;
}
}
//============================================================================================
//Playback
if(playbackMode){
//Load the fullArray from EEPROM
if(!valuesLoaded){
for (int i = 0; i < 512; i++){
fullArray[i] = pgm_read_word_near(savedArray + i);
/* FOR DEBUGGING
Serial.print(i);
Serial.print("\t");
Serial.print(fullArray[i], DEC);
Serial.println();
*/
}
valuesLoaded = true;
}
//----------------------------------------------------------------------------------------------
// copy Slots from fullArray, look for endByte 254 to be done
for (int i = 0; i < 450; i+=2) {
if (!slotParse) { // logic gate
if (fullArray[i] != 254) {// if the full array hasn't reached the 254 yet...
firstSlotbyte = fullArray[i];
secondSlotbyte = fullArray[i+1];
slots[slotCounter] = firstSlotbyte * secondSlotbyte;
slotCounter++;
} else {
slotCounter++;
slotParse = true; // when it reaches a 254, we're finished with the active slots
}
}
}
//-----------------------------------------------------------------------------------------------
//copy the rest of the fullArray into the property array
if (!propertyParse) {
for (int i = slotCounter; i < 2250; i+=3) { // start looking in full array AFTER the slots
if(fullArray[i] !=254){
declarator[propertyCounter] = fullArray[i];
ability[propertyCounter] = fullArray[i+1];
degree[propertyCounter] = fullArray[i+2];
propertyCounter++;
}
}
propertyParse = true;
}
//------------------------------------------------------------------------------------------------
//Constantly read in multiplexer values
for (int muxPin = 0; muxPin < 16; muxPin ++) {
int pinOne = 1 & muxPin;
int pinTwo = 1 & (muxPin >> 1) ;
int pinThree = 1 & (muxPin >> 2);
int pinFour = 1 & (muxPin >> 3);

digitalWrite(a,pinOne);
digitalWrite(b,pinTwo);
digitalWrite(c,pinThree);
digitalWrite(d,pinFour);

muxValue[muxPin] = analogRead(analog0);

//Serial.print(muxValue[muxPin], DEC);
//Serial.print("\t");
}
//--------------------------------------------------------------------------------------------------
//constantly check to see which map is active
for (int i = 8; i < 13; i ++){
if( muxValue[i]== 1023){
activeMap = i-7;
}
}
//--------------------------------------------------------------------------------------------------
//Joysticks
//Analog low for 1 through 5
for (int i = 0; i < 5; i ++){
if(muxValue[i] < 300){ //if position low on button i
for(int j = 0; j < 450; j++){ // look through the slots array to see if it has active slots
if(slot[j] == i*3 || slot[j] == (i*3)+1 || slot[j] == (i*3)+2){ //if it does then grab the properties and send them to the appropriate function
if(declarator[j] == 1){
channelFunction(ability[j]);
}else if(declarator[j] == 2){
pitchFunction(ability[j]);
}else if(declarator[j] == 3){
velocityFunction(ability[j], degree[j]);
}else if(declarator[j] == 4){
octaveFunction(ability[j],degree[j]);
}else if(declarator[j] == 5){
pitchbendFunction(ability[j]);
}else if(declarator[j] == 6){
ccFunction(ability[j],degre[j];
}
}
}
}
}
}

}