Code-Outlet von Andreas Bahr, Zürich
Blinksy ist eine Beatbox-Erweiterung für die von Jonas Guggenheim & den Sporthorses geschaffene "Guggenheim Box", eine Telefonkabinen-artige Installation mit Lichtschranken. Vereinfacht formuliert erlaubt die Box und ihre Erweiterungen, einen Modul-Synthsizer zu "spielen".
The Sporthoses sind eine Live-Performance-Band deren Auftritte nicht nur die Ohren, sondern auch die Augen erfreuen. Weitere Information & Videos zum Instrument / der Band finden Sie auf der Website:
Kern ist ein Arduino Nano. Über einen Drehschalter mit 4 Positionen können 4 verschiedene Pattern ausgewählt werden, die maximal 4 LED-Lampen direkt ansteuern. Diese triggern die Lichtschranken anstelle eines Sporthorse-Musikers.
In der ersten Version der Hardware nach meinem Entwurf waren 2 kräftige LEDs pro Kanal vorgesehen, meine Idee war, mehr LED = mehr Licht = weniger Anfällig auf Streulicht. Die Musiker haben aber Dank ihrer Erfahrung im Instrumentenbau eine bessere Lösung gefunden: der Einsatz von einfachen Optiken. So konnten mit einzelnen LEDs perfekte Resultate erzielt werden.
In der Arduino-Welt muss mit C/C++ programmiert werden. Ich mag C nicht, muss aber zugeben, es ist wesentlich effizienter damit zu arbeiten, als mit Maschinensprache/Assembler...
Die aktuelle Version erlaubt das Task-Synchrone umschalten der Pattern während der Live-Performance. Die Pattern selbst sind im Header des Scripts definiert.
Die hier angebotene Ino-Datei können Sie mit der Arduino-IDE verwenden. Sie lässt sich aber auch mit einem normalen Text-Editor lesen.
Die etwas einfachere erste Version eignet sich sehr gut um die Funktionsweise der Software zu erkennen: Der HW-Timer des Prozessors wird verwendet für das korrekte Timing, er meldet via einen Interupt das vergehen der Zeit zurück an die Software...
/* blinksy v0.4 * music sequencer with lights * for the Guggenheim-Box * copyleft 2017 button3 & the sporthorses * ----------------------------------------- * sequencer plays a note by switching * a light off for some milliseconds. * in the musical setup, write any character * for a note, leave blank otherwise. * ----------------------------------------- * 4 sets with 4 tracks on 4 led-lamps * BPM values from 20 to 180 */ // MUSIC SETUP ========================================== // SET 1 ------------------------------------------------ int set1bpm = 40; // TICK RULER "1...2...3...4...5...6...7...8..." char set1track1[33] = "x x x x "; char set1track2[33] = " x x x x "; char set1track3[33] = " "; char set1track4[33] = " "; // SET 2 ------------------------------------------------ int set2bpm = 80; // TICK RULER "1...2...3...4...5...6...7...8..." char set2track1[33] = "x x x x "; char set2track2[33] = "x x x x x x x x "; char set2track3[33] = " x x x x "; char set2track4[33] = " "; // SET 3 ------------------------------------------------ int set3bpm = 60; // TICK RULER "1...2...3...4...5...6...7...8..." char set3track1[33] = " "; char set3track2[33] = " "; char set3track3[33] = " "; char set3track4[33] = " "; // SET 4 ------------------------------------------------ int set4bpm = 60; // TICK RULER "1...2...3...4...5...6...7...8..." char set4track1[33] = " "; char set4track2[33] = " "; char set4track3[33] = " "; char set4track4[33] = " "; // ====================================================== // internal setup volatile int loopCount = 0; const unsigned long CLOCK_FREQ = 250000; unsigned int impulseMiliSec = 10; unsigned int compareON = 20000; unsigned int compareOFF = 10000; int bpm = 60; char track1[33]; char track2[33]; char track3[33]; char track4[33]; // system initialisation void setup() { Serial.begin(9600); noInterrupts(); // BPM flash pinMode(LED_BUILTIN, OUTPUT); // on-board led // 4 lights pinMode(12, OUTPUT); // light 1 pinMode(11, OUTPUT); // light 2 pinMode(10, OUTPUT); // light 3 pinMode(9, OUTPUT); // light 4 digitalWrite(12, HIGH); // switch them OFF digitalWrite(11, HIGH); digitalWrite(10, HIGH); digitalWrite(9, HIGH); // set-switch pinMode(5, INPUT_PULLUP); // prg 1 pinMode(6, INPUT_PULLUP); // prg 2 pinMode(7, INPUT_PULLUP); // prg 3 pinMode(8, INPUT_PULLUP); // prg 4 // load music data if(digitalRead(8) == LOW) { bpm = set4bpm; strcpy(track1, set4track1); strcpy(track2, set4track2); strcpy(track3, set4track3); strcpy(track4, set4track4); } else { if(digitalRead(7) == LOW) { bpm = set3bpm; strcpy(track1, set3track1); strcpy(track2, set3track2); strcpy(track3, set3track3); strcpy(track4, set3track4); } else { if(digitalRead(6) == LOW) { bpm = set2bpm; strcpy(track1, set2track1); strcpy(track2, set2track2); strcpy(track3, set2track3); strcpy(track4, set2track4); } else { bpm = set1bpm; strcpy(track1, set1track1); strcpy(track2, set1track2); strcpy(track3, set1track3); strcpy(track4, set1track4); } } } // calculate timer-compare-values compareON = (CLOCK_FREQ / (bpm * 32 / 60)) - 1; compareOFF = (int)(((float)impulseMiliSec / 1000) / (1 / (float)CLOCK_FREQ) - 1); // timer 1 setup TCCR1A = 0; TCCR1B = 0; OCR1A = compareON; OCR1B = compareOFF; TCCR1B |= _BV(CS10); // clock ON TCCR1B |= _BV(CS11); // prescale 64 TCCR1B |= _BV(WGM12); // mode: ctc TIMSK1 |= _BV(OCIE1A); // enable interrupt TIMSK1 |= _BV(OCIE1B); // enable interrupt interrupts(); } // impulse ON ISR(TIMER1_COMPA_vect) { // metronome BPM flash if(loopCount == 0) digitalWrite(LED_BUILTIN, HIGH); else digitalWrite(LED_BUILTIN, LOW); // play sequence if(track1[loopCount] != ' ') digitalWrite(12, HIGH); if(track2[loopCount] != ' ') digitalWrite(11, HIGH); if(track3[loopCount] != ' ') digitalWrite(10, HIGH); if(track4[loopCount] != ' ') digitalWrite(9, HIGH); // ticks gear if(loopCount == 31) loopCount = 0; else loopCount++; } // impulse OFF ISR(TIMER1_COMPB_vect) { digitalWrite(12, LOW); digitalWrite(11, LOW); digitalWrite(10, LOW); digitalWrite(9, LOW); } // status infos void loop() { Serial.println(bpm); Serial.println(compareON); Serial.println(compareOFF); Serial.println("---------"); delay(1000); }