8 Step Midi Sequenzer

Ich bin gerade dabei einen Midi Sequenzer zu bauen.

Features:

  • 8 Schritte
  • Anschlag einstellbar
  • Note einstellbar
  • Die CC Befehle sollen ansteuerbar sein
  • LCD Display

Zu den CC Befehlen muss ich noch etwas suchen, oder kann mir jemand Informationen dazu geben, wie man diese mit dem Arduino ansteuert?

Hier auf Seite zwei ein erstes Video: http://www.machzin.de/portfolio/arduino-8-step-mid-step-sequenzer/

Die Delays müssen raus, da sonst die Taster nur alle x-Milisekunden abgefragt werden.

P.s.: Wie frage ich am besten 8 Regler ab, lasse die Meldoie aber dabei weiterspielen?

http://arduino.cc/forum/index.php/topic,30202.0.html

hier geht es um das Thema, also es heisst einfach alles in einer for schleife Programieren und keine Delays verwenden, da diese den gesammten Programmablauf aufhalten ... oder so ähnlich :P

Und wenn man den selben schalter hintereinander abfragt, sollte man schon delays einbringen, wegen dem Kontakte prellen und so ^^

In dem Beispiel werden auch Delays verwendet. Das Problem ist, dass du zwischen den einzelnen Noten pausen haben willst, d.h. du brauchst eine Verzögerung. Könnte aber auch damit funktionieren, dass man für x-Millisekunden eine "stille" Note sendet!

komika: P.s.: Wie frage ich am besten 8 Regler ab, lasse die Meldoie aber dabei weiterspielen?

Im Grunde wie beim Blink-without-Delay. D.h. Du baust eine State-Machine, die ohne Delay auskommt. In einer Variable merkst Du Dir bei welchem Step Du gerade bist. Es werden nicht alle Steps in einem loop() Durchlauf abgearbeitet. Loop:

  • prüfe auf State-Wechsel (abhängig von der Abspielgeschwindigkeit und der vergangenen Zeit), wenn Wechsel, dann "state++"
  • wenn state++, dann "play(state) -> nächsten Step spielen / Note senden
  • Frage alle Regler in einer Schleife ab (ohne Delay) und setze die entsprechenden Werte
  • Frage Encoder und Taster ab und setze die Werte (auch wieder ohne delay, oder max. wenige ms zum entprellen)
  • Update Display (falls nötig)
  • loop ende

Dein projekt finde ich iemlich gut, aber wird das nach nachher noch ein Standalone alone sequencer mit integrieter klangerzeuung oder einfach ein Pc controller?

Ich habe jetzt auch alle meine Teile bestellt, naja, die Pullup wiederstäande habe ich leider vergessen :/

Erstmal wird es nur ein Midicontroller, wenn ich den SID zum laufen bekomme, wirds ne groovebox :D

mkl0815:

komika:
P.s.: Wie frage ich am besten 8 Regler ab, lasse die Meldoie aber dabei weiterspielen?

Im Grunde wie beim Blink-without-Delay. D.h. Du baust eine State-Machine, die ohne Delay auskommt. In einer Variable merkst Du Dir bei welchem Step Du gerade bist. Es werden nicht alle Steps in einem loop() Durchlauf abgearbeitet.
Loop:

  • prüfe auf State-Wechsel (abhängig von der Abspielgeschwindigkeit und der vergangenen Zeit), wenn Wechsel, dann “state++”
  • wenn state++, dann "play(state) → nächsten Step spielen / Note senden
  • Frage alle Regler in einer Schleife ab (ohne Delay) und setze die entsprechenden Werte
  • Frage Encoder und Taster ab und setze die Werte (auch wieder ohne delay, oder max. wenige ms zum entprellen)
  • Update Display (falls nötig)
  • loop ende
int takt = 40; // SH_CP
int speicher = 39; // ST_CP
int daten = 38; // DS
long previousMillis = 0;
long interval;
int encoder0PinA = 22;
 int encoder0PinB = 23;
 int encoder0Pos = 0;
 int encoder0PinALast = LOW;
int step1=0;
int step2=0;
int step3=0;
int step4=0;
int step5=0;
int step6=0;
int step7=0;
int step8=0;
int n=LOW;
//
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 100;
int lastButtonState = LOW; 
int buttonState; 
//

void setup(){
  
   pinMode (encoder0PinA,INPUT);
   pinMode (encoder0PinB,INPUT);
pinMode(takt, OUTPUT);
pinMode(speicher, OUTPUT);
pinMode(daten, OUTPUT);
Serial.begin (9600);
}
void loop(){
   n = digitalRead(encoder0PinA);
   
    if (n != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 
  
    if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = n;
  }
   lastButtonState = n;
  
 //  encoder0PinALast = n;
  unsigned long currentMillis = millis();
 
 if ((encoder0PinALast == LOW) && (n == HIGH)) {
     if (digitalRead(encoder0PinB) == LOW) {
       encoder0Pos--;
     } else {
       encoder0Pos++;
     }
     Serial.print (encoder0Pos);
     Serial.print ("n0:/");
 }encoder0PinALast = n;
 if(encoder0Pos<=0){encoder0Pos=1;}
 //encoder0PinALast = n;
 interval=encoder0Pos*10;
 if(currentMillis - previousMillis > interval && step1==0) {
   step1=1;
digitalWrite(speicher, LOW);
shiftOut(daten, takt, LSBFIRST, 1);
digitalWrite(speicher, HIGH);
previousMillis = currentMillis;   
 }
  if(currentMillis - previousMillis > interval && step1==1 && step2==0) {
   step2=1;
digitalWrite(speicher, LOW);
shiftOut(daten, takt, LSBFIRST, 2);
digitalWrite(speicher, HIGH);
previousMillis = currentMillis;   
 }
   if(currentMillis - previousMillis > interval && step2==1 && step3==0) {
   step3=1;
digitalWrite(speicher, LOW);
shiftOut(daten, takt, LSBFIRST, 4);
digitalWrite(speicher, HIGH);
previousMillis = currentMillis;   
 }
   if(currentMillis - previousMillis > interval && step3==1 && step4==0) {
   step4=1;
digitalWrite(speicher, LOW);
shiftOut(daten, takt, LSBFIRST, 8);
digitalWrite(speicher, HIGH);
previousMillis = currentMillis;   
 }
    if(currentMillis - previousMillis > interval && step4==1 && step5==0) {
   step5=1;
digitalWrite(speicher, LOW);
shiftOut(daten, takt, LSBFIRST, 16);
digitalWrite(speicher, HIGH);
previousMillis = currentMillis;   
 }
    if(currentMillis - previousMillis > interval && step5==1 && step6==0) {
   step6=1;
digitalWrite(speicher, LOW);
shiftOut(daten, takt, LSBFIRST, 32);
digitalWrite(speicher, HIGH);
previousMillis = currentMillis;   
 }

   if(currentMillis - previousMillis > interval && step6==1 && step7==0) {
   step7=1;
digitalWrite(speicher, LOW);
shiftOut(daten, takt, LSBFIRST, 64);
digitalWrite(speicher, HIGH);
previousMillis = currentMillis;   
 }
    if(currentMillis - previousMillis > interval && step7==1 && step8==0) {
   step8=1;
digitalWrite(speicher, LOW);
shiftOut(daten, takt, LSBFIRST, 128);
digitalWrite(speicher, HIGH);
previousMillis = currentMillis;   
 step1=0;
 step2=0;
 step3=0;
 step4=0;
 step5=0;
step6=0;
step7=0;
step8=0;
 
 }
 
 
 


}

So etwa. Dort wo das Schieberegister angesteuert wird, wird auch dann die Midi Note gesendet.
Geht mit Sicherheit auch etwas einfacher.

So ungefähr. Hab aber erstmal nur grob drüber geschaut. Die millis() Rechnerei kannst Du Dir mit den Lib von mir sparen (http://arduino.cc/forum/index.php?action=dlattach;topic=127674.0;attach=27418) Die kann auch mit mehreren Zeiten umgehen, aber eigentlich brauchst Du ggf. nur wenige Objekte.

Ich würde die Steps nicht in verschiedene Variablen packen, sondern eine Variable “step” haben, die am Anfang 0 ist und dann von 0 bis 7 immer wieder durchgezählt wird.
Damit würde aus den 8 einzelnen Blöcken für die Steps nur noch einer werden, der für alle Steps verwendet wird:

  if(currentMillis - previousMillis > interval) {
   step = ++step % 8;   // damit bleibt step immer zwischen 0 und 7.
digitalWrite(speicher, LOW);
shiftOut(daten, takt, LSBFIRST,  (1 << step));  // 1 << step liefert genau ein Byte mit dem step'ten Bit auf 1 gesetzt.
digitalWrite(speicher, HIGH);
previousMillis = currentMillis;   
 }

Am Ende kannst Du Dir dann noch eine Funktion void play(int step) basteln, die dann im o.g. Block aufgerufen wird und die für den entsprechenden Step eingestellte Note per MIDI ausgibt.

...oder so, danke. Das wäre dann meine Überlegung gewesen, wenn es mal knapp mit dem Speicher wird. :cold_sweat:

Das ist nicht nur eine Frage des Speichers, sonder auch der Übersichtlichkeit des Codes. Grundregel ist, wenn Du einen Block mehr als einmal verwendest, mach eine Funktion draus.

Midi hätte ich über eine Funktion gemacht. Hab jetzt 8-Encoder, 8 Potis, jetzt kommen noch 8 Taster und 6 Regler für CC Midi Befehle.

Hallo,

kann ich meine 8 Encoder so abfragen:

x=++x %8

n[x] = digitalRead(encoder0PinA[x]);
   if (n[x] != lastButtonState[x]) {
    // reset the debouncing timer
    lastDebounceTime[x] = millis();
  } 
  if ((millis() - lastDebounceTime[x]) > debounceDelay[x]) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = n[x];
  }
   lastButtonState = n[x];
  unsigned long currentMillis[x] = millis();
 if ((encoder0PinALast[x] == LOW) && (n[x] == HIGH)) {
     if (digitalRead(encoder0PinB[x]) == LOW) {
       encoder0Pos[x]--;
     } else {
       encoder0Pos[x]++;
     }
     
 }encoder0PinALast[x] = n[x];

…oder muss ich den Code für jeden Encoder schreiben.
Konnte es leider noch nicht ausprobieren.