Incom ist die Kommunikations-Plattform der Fachhochschule Potsdam mehr erfahren

BeatCircle

BeatCircle

BeatCircle ist ein Step Sequencer mit integriertem Effect Controller.

Idee

Mein Ziel war es ein Interface zu bauen, das wenig musikalische Begabung erfordert und als Stand-Alone ohne weitere Controller agieren kann.

Als Basis sollte ein Step Sequencer dienen, da man hierfür kein perfektes Taktgefühl braucht. Da Step Sequencer relativ begrenzt in der Variation der Rhythmen sind, sollten zusätzlich noch verschiedene Effekt-Parameter ansteuerbar sein. Diese sollte der Benutzer nicht über unzählige Schiebe- oder Drehregler einstellen müssen, damit das Interface oberflächlich nicht zu komplex wird.
Zum anderen sollte der Benutzer physisch mehr gefordert werden und so entschied ich mich für einen Entfernungsmesser.

Bei der Form wollte ich von der typisch linearen Anordnung eines Step Sequencers weg, sie sollte eher an den wiederholenden Loop eines Beats angelehnt werden.

Video Prototyp

pw: beat

Überschrift

Zuerst habe ich mir einen Breadboard-Prototypen gebaut und schnell gemerkt, dass die am Teensy vorhandenen Anschlüsse nicht für die von mir verwendeten Komponenten ausreichen. Deswegen habe ich zwei Multiplexer besorgt, um alle Komponenten anschließen zu können.
Nachdem der Breadboard-Prototyp fertig war, bin ich zum Bau des Gehäuses übergegangen.

Aus einem Block Nussbaumholz habe ich an der Drehbank eine Außenschale gedreht. Für die Abdeckplatte habe ich Aluminiumblech und rotes Plexiglas verwendet.
Hinter der Plexiglasscheibe befestigte ich ein Stück Kupferblech, um diese als kapazitiven Sensor verwenden zu können. Außerdem verbirgt sich dahinter auch der Entfernungsmesser.

Die Knöpfe habe ich aus einem Plexiglasstab gedreht, ausgehöhlt, eine LED eingelassen und dann auf einem Push-Button fixiert.

Am Ende habe ich alle Komponenten mit der Platine verkabelt, im Gehäuse fixiert und mit der Abdeckplatte verschlossen.

Video

Funktionsweise

Beschriftung

Steuerung

Der Benutzer hat die Möglichkeit auf acht verschieden Ebenen jeweils acht Anschläge zu setzen. Zu jedem Anschlag kann auf Wunsch noch ein Control Change gesendet werden. Auf jeder Ebene kann zusätzlich noch ein globaler Control Change gesendet werden.

  • Um einen Anschlag zu setzen, druckt man den gewünschten Button.
  • Um einen Control Change zu senden, hält man den gewünschten Button eine Sekunde gedrückt und justiert mit der anderen Hand die Intensität über den Entfernungsmesser, anschließend lässt man den Button wieder los.
  • Um die Ebene zu wechseln, berührt man die Plexiglasfläche und wählt die gewünschte Ebene über einen der acht Buttons aus.
  • Um einen globalen Control Change zu senden, berührt man die Plexiglasfläche fünf Sekunden und justiert mit der anderen Hand die Intensität über den Entfernungsmesser, anschließend lässt man die Fläche wieder los.
Anzeige

Der BeatCirle verfügt über acht weiße und acht rote LEDs.
Die weißen LEDs zeigen im normal Betrieb an, welche Anschläge aktiviert sind (schwach) und welcher der aktivierten gerade aktiv ist (stark). Während der ebenen Auswahl zeigen sie an, welche Ebene aktiviert ist.
Die roten LEDs zeigen im normal Betrieb an, an welcher Position der Loop sich befindet. Bei der Control Change Änderung zeigen diese die Intensität an.

Code

#include <CapacitiveSensor.h>
#include <Bounce.h>

CapacitiveSensor   touch = CapacitiveSensor(2,22);
int ledbin[8][3] = {{0,0,0},{1,0,0},{0,1,0},{1,1,0},{0,0,1},{1,0,1},{0,1,1},{1,1,1}};
int ledPins[] = {7, 8, 9, 10, 3, 4, 5, 6};
int butPins[] = {19, 18, 17, 16, 15, 14, 13, 12};
Bounce Bouncer[8] = {Bounce(19,5),Bounce(18,5),Bounce(17,5),Bounce(16,5),Bounce(15,5),Bounce(14,5),Bounce(13,5),Bounce(12,5)};
int butStat[8][8] = {};
int disStat[8][8] = {0};
int stepStat[8];
int chanswitch = 4;
int pinCount = 8;
int Step = 0;
byte counter;
int hold[8];
const int numReadings = 25;
int readings[numReadings];
int index = 0;
int total = 0;
int average = 0;
int count;
int holddown;
int stepcount[8];
int holdtouch;

void RealTimeSystem(byte realtimebyte) {

if(realtimebyte == 248) {
    counter++;
    if(counter >= 12) {
        counter = 0;
        if(Step < 7) {
            Step = Step++;
        } else {
            Step = 0;
        }
        for (int thisPin = 0; thisPin < pinCount; thisPin++)  {
            if(butStat[thisPin][Step]==1){
                usbMIDI.sendNoteOn(60, 127, thisPin+1);
                usbMIDI.sendNoteOff(60, 127, thisPin+1);
                usbMIDI.sendControlChange(70+thisPin, 0+disStat[thisPin][Step], thisPin+1);
            }
        }
    }
}

if(realtimebyte == 250 || realtimebyte == 251) { 
    counter = 0; 
} 

if(realtimebyte == 252) { 
    Step = 0;
} 

}

void setup() {

Serial.begin(9600);

pinMode(A1, INPUT);

for (int thisPin = 0; thisPin < pinCount; thisPin++)  {
    pinMode(ledPins[thisPin], OUTPUT);
    pinMode(butPins[thisPin], INPUT_PULLUP);
}

usbMIDI.setHandleRealTimeSystem(RealTimeSystem);

for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;          
}
}

void loop() {
total= total - readings[index];         
readings[index] = touch.capacitiveSensorRaw(5); 
total= total + readings[index];       
index = index + 1;                    
if (index >= numReadings)              
    index = 0;                           
    average = total / numReadings;   

for (int thisPin = 0; thisPin < pinCount; thisPin++) { 
    int sum1 = 0;
    for (int i = 0; i < 8; i++) {
        sum1 += butStat[chanswitch][i];
    }
    if (sum1 > 0 || average>475)  {
        digitalWrite(ledPins[4], 1);
    }

    int sum2 = 0;
    for (int i = 0; i < 8; i++) {
        sum2 += stepStat[i];
    }
    if (sum2 > 0)  {
        digitalWrite(ledPins[0], 1);
    }

    Bouncer[thisPin].update();  
    if(average>480){
        digitalWrite(ledPins[5], ledbin[chanswitch][0]);
        digitalWrite(ledPins[6], ledbin[chanswitch][1]);
        digitalWrite(ledPins[7], ledbin[chanswitch][2]);
        count = count++;
        if (count > 5000) {
            usbMIDI.sendControlChange(chanswitch, map(analogRead(A1),0,620,0,127), chanswitch);
            holdtouch=1;
        }
        if (Bouncer[thisPin].fallingEdge()){
            chanswitch=thisPin;
        }
    } else {
        count = 0;
        holdtouch=0;
        if (digitalRead(butPins[thisPin])==0){

            if (Bouncer[thisPin].duration()>500){
                disStat[chanswitch][thisPin] = map(analogRead(A1),0,620,0,127);
                hold[thisPin]=2;
                holddown = thisPin;
                digitalWrite(ledPins[5], ledbin[thisPin][0]);
                digitalWrite(ledPins[6], ledbin[thisPin][1]);
                digitalWrite(ledPins[7], ledbin[thisPin][2]);
            }

            if (Bouncer[thisPin].fallingEdge()){
                if (butStat[chanswitch][thisPin]==0) {
                    butStat[chanswitch][thisPin] = 1;
                    hold[thisPin] = 1;
                }
            }
        }

        if (Bouncer[thisPin].risingEdge()){

            if (hold[thisPin]==0){
                butStat[chanswitch][thisPin] = 0;
                disStat[chanswitch][thisPin] = 0;
            }

            hold[thisPin] = 0;
        }
        if (butStat[chanswitch][thisPin]==1 && hold[0]<2 && hold[1]<2 && hold[2]<2 && hold[3]<2 && hold[4]<2 && hold[5]<2 && hold[6]<2 && hold[7]<2) {
            digitalWrite(ledPins[5], ledbin[thisPin][0]);
            digitalWrite(ledPins[6], ledbin[thisPin][1]);
            digitalWrite(ledPins[7], ledbin[thisPin][2]);
        }
    }
        if (hold[0]==2 || hold[1]==2 || hold[2]==2 || hold[3]==2 || hold[4]==2 || hold[5]==2 || hold[6]==2 || hold[7]==2 || holdtouch==1 ){
            for (int i = 0; i < 8; i++) {
                if (map(analogRead(A1),0,620,0,9)>i){
                    if (i+holddown>7){
                        stepStat[i+holddown-8]=1;
                    } else {
                        stepStat[i+holddown]=1;
                    }
                }  else if (i+holddown>7){
                    stepStat[i+holddown-8]=0;
                } else {
                    stepStat[i+holddown]=0;
                }

            }
        }  else if (thisPin==Step) {
            stepStat[thisPin]=1;
        } else {
            stepStat[thisPin]=0;
        }

        if (stepStat[thisPin]==1) {
            digitalWrite(ledPins[1], ledbin[thisPin][0]);
            digitalWrite(ledPins[2], ledbin[thisPin][1]);
            digitalWrite(ledPins[3], ledbin[thisPin][2]);
        } 

            digitalWrite(ledPins[0], 0);


        if (butStat[chanswitch][thisPin]==1 && stepStat[thisPin]==1) {
            delay(1);
        } else  {
            digitalWrite(ledPins[4], 0);
        }
}
usbMIDI.read();
}

Fazit

Ich hatte vorher noch keinen Kontakt zu Arduino oder Vergleichbarem, bin aber erstaunlich schnell damit klargekommen. Auch dank der guten Anleitung von Stefan Hermann. Mit meinem Ergebnis bin ich sehr zufrieden. Denn ich hätte mir nicht vorstellen können, das ich meine Idee aus dem Video-Prototypen so gut, und noch besser umsetzten würde.

Ich bin von dem Kurs begeistert und freue mich jetzt schon auf den nächsten Physical Interaction Kurs.

Ein Projekt von

Art des Projekts

Studienarbeit im Grundstudium

Betreuung

Stefan Hermann

Zugehöriger Workspace

Musical Interfaces 2012

Entstehungszeitraum

Wintersemester 2012/2013