Arduino Sequencer zu mehreren Entwickeln?

Dieses Thema im Forum "Lötkunst" wurde erstellt von Rupertt, 30. Mai 2011.

  1. Rupertt

    Rupertt Tach

    Hallo,

    ich habe einen Hybrid aus 16step sequencer mit poti pro step und 8 track midi looper gebaut und
    stoße bei einigen Programmieraufgaben an meine Grenzen.
    Daher wär die Frage ob man solch ein Gerät nicht zu mehreren entwickeln kann.

    Das Gerät steht soweit und die steps laufen durch, tempo lässt sich regeln usw.

    Was ganz wichtig wäre das das teil zu einer mpc o.ä. synct, start/stop empfängt usw.

    Da ich einen Computer job habe, ists mir doch zuviel am Wochenende auch noch n paar Stunden ins coden zu stecken.

    Hat jemand Interesse daran?
     
  2. Flub

    Flub Tach

    habe gerade einen kompletten sequencer mit nem arduino mega gebaut, wenn ihr wollt kann ich mal ein video zeigen, und den code veröffentlichen
    es ist ein 10 kanal trigger sequencer man kann die auflösung wechseln zwischen 32stel und 16tel, man kann 4 Takte programmieren und einstellen, zwischen welchen bars es im kreis läuft. dann kann man insgesamt 16 sequenzen mit jeweils 4 takten und 10 kanällen speichern, die dann auch wenn das gerät aus ist, gespeicher sind. und noch viel mehr so zeug wie z.b. takte kopieren und sequenzen kopieren. usw

    edit: im endeffekt, kann man sich alle funktionen die man sich so vorstellen kann einfach dazu programmieren, es ist sozusagen ein kinderspiel.

    ich hab auch einen clock eingang eingebaut, sodass man ihn synchron zu midi oder aderen systemen laufen lassen kann. außerdem kann man über usb komplette songstrukturen mit der software max arrangieren oder sich z.b. einen controller mit 16 fußtastern bauen, mit dem man auswählen kann welche von den 16 sequenzen laufen soll.. (für live performances auch als gitarrist oder so).

    ich hatte keine ahnugn von digitalem, nur ein bisschen vom programmieren und es ist wirklich leicht. das schwierigste war die gehäusekonstruktion...

    in verbindung mit shift registern und shcaltern kann man auch ganz leicht einen steuerspannungsequencer bauen. dessen takt von einem kanal des sequencers gesteuert wird.
     
  3. Rupertt

    Rupertt Tach

    ein video wäre super.
    Ich poste später auch mal eine genaurere beschreibung und ein Foto
     
  4. citric acid

    citric acid aktiviert

    wollte immer mal anfangen was mit arduino zu machen. hatte bis dato aber immer muffe .... wie schwer ist der einstig in s coden wirklich?
    Gibt´s gute deutsche dokus dazu ? oder ist da auch alle auf englisch?
     
  5. Ardurino, also wenns wo massenhaft dokus gibt dann da, ist sozusagen die Kelly Family der Microcontroller-Umgebungen :mrgreen:
     
  6. Rupertt

    Rupertt Tach

    So, ich hatte mal wieder ein wenig Zeit und habe mir eine Frontplatte gebaut und alles verkabelt.
    Gibt es hier jemanden der mir sagen kann ob meine Art den sequencer zu programmieren die passenden ist,
    oder ist mein Ansatz schon falsch?

    Der sequencer ist öfter instabil, scheint abzustürzen und die LED sind nicht immer im Sync zur gespielten Note.


    Gruß
     

    Anhänge:

  7. Flub

    Flub Tach

    schreib hier mal den quelltext rein, habe auch einen mit dem arduino mega gebaut.
     
  8. Rupertt

    Rupertt Tach

    Die sourcen liegen in meine vorigen Beitrag.
    Was ich mich ja frage ist wie ich die einzelnen Steps in eine Funktion packen dann,
    dann muss ich nicht 8x 90% den selben code schreiben.

    Ich habe gelesen das man für korrektes timing die function timer_start = millis(); nicht nehmen sollte,
    habs aber nie geschaft das anders zu bauen,
     
  9. Burt

    Burt Tach

    Hi,
    empfehle:
    - Verwendung von Arrays um den Code zu komprimieren. Mit dem x in der loop() kannst Du indizieren, dann fällt der Overhead weg.
    - das LED Ein/Ausschalten über einen TimerInterrupt zu steuern. Dazu gibts eine Lib auf der Arduino Homepage, MsTimer2.
    Das verhindert, daß der gesamte Code angehalten wird, bloß um eine LED zu triggern. delay() ist Gift für den Programmablauf.

    Beste Grüße
    Burt
     
  10. Rupertt

    Rupertt Tach

    Hallo burt,

    danke für den Tip mit den arrays, das hat den code sehr entschlackt.
    Gibt es aber einen Grund warum die LEDs jetzt nur noch ganz schwach leuchten?
    Das mit dem Interuppt muss ich mir noch anschauen.


    EDIT:

    sorry das mit den LEDs hat sich erldigt
     

    Anhänge:

  11. Flub

    Flub Tach

    also mach doch eine Variable "Timer" vom Typ long, der du bei jedem Step des Sequencers die aktuelle Zahl der vergangenen milli- oder microsekunden zuweist.
    dann überprüfst du im loop ob, die differenz vom gespeichert wert und dem momentan Zustand an vergangenen Sekunden größer ist als dein gewünschtes zeitintervall.

    das sieht dann ungefähr so aus:
    Code:
    unsigned long Timer = 0;
    void loop() {
      if ((millis() - Timer) > 100) {
      //gib die spannungen oder die midi signale für step x aus...
        Timer = millis();
        if (step < 16) {  
          step++;
         } else {
          step = 0;
        }
      }
    }
    
     
  12. Rupertt

    Rupertt Tach

    versteh ich noch nicht, schön wäre es ja mit richtigen BPM Werten arbeiten zu können, so das per default 120BPm gelten und ich dann
    in Schritten rauf und runter gehen kann, da würde aber das delay für die LED noch stören.
     
  13. Rupertt

    Rupertt Tach

    Ich versuche gerade den Blink neu zu machen,
    im beispiel werden die MStimer aufrufe in der function setup aufgerufen,
    woher weiss ich denn dann welcher step gerade aktiv ist?
    Wenn ich es in meine play function einbaue bekomme ich beim kompilieren einen Fehler:
    Code:
    sequencer_2_8x_array_func.cpp: In function »void playstep(int)«:
    sequencer_2_8x_array_func.cpp:153: Fehler: falsche Benutzung eines void-Ausdruckes
    wie gehts richtig?

    Code:
    void flash(int LED) {
      static boolean output = HIGH;
      
      digitalWrite(LEDpins[LED], output);
      output = !output;
    }
    
    void playstep(int stepnr) {
    
       if (currentSwitchState[stepnr] == 1) {
                    AnalogValue = analogRead(stepnr);
                    note = AnalogValue/8;
                    noteOn(0xB0, 0x7B, 0x00);
                    noteOn(0x90, note, 0x7F);
                    
                    MsTimer2::set(50, flash(stepnr)); // 500ms period
                    MsTimer2::start();
    //                digitalWrite(LEDpins[stepnr], HIGH);
    //                delay(50);
    //                digitalWrite(LEDpins[stepnr], LOW);
                    delay(currentTime);
                } else {
                  delay(currentTime);
                }
    
    }
     
  14. Jens Groh

    Jens Groh bin angekommen

    Wohlmeinender allgemeiner Rat: Verschätzt euch mal nicht mit dem Schwierigkeitsgrad. :school: MIDI ist trotz der geringen Übertragungsrate eine "Hard-Realtime"-Aufgabe, und das erfordert entsprechende informatische Kenntnisse und ziemlich unvermeidbar ein RTOS. Hier wäre eines:
    http://www.arduino.cc/cgi-bin/yabb2/YaB ... 1256745982
     
  15. Rupertt

    Rupertt Tach

    grrr. demotiviere mich nicht. bin froh das ich wieder einen Schritt weiter bin :floet:
     
  16. Jens Groh

    Jens Groh bin angekommen

    Nein, nein, freu dich an dem, was geht, und lass dir die Erfahrungen nicht entgehen! Ist immer besser als sie nicht zu machen. Und auch gemeinsames Werkeln ist wunderbar. Wollte nur die Ganzneulinge warnen, dass "Arduino geht einfach" (was sicher stimmt) nicht bedeutet, dass alles mit Arduino einfach geht.
    Ohne-RTOS-Tip: Interrupts benutzen. Semaphoren, Queues und ähnliches Synchronisationszeug nach Bedarf selber bauen. Vielleicht reichts schon, also auch ohne Luxus wie Scheduler, Prioritäten, reentrante Speicherverwaltung. Erst wenn damit so gar nichts gleichzeitig zuverlässig UND tight werden will, wieder zu meinen Unkenrufen zurückblättern.
    :peace:
     
  17. Rupertt

    Rupertt Tach

    rein logisch wird mir klar was du vorhast, aber mit dem umsetzen komm ich nicht klar.
    Im grunde muss ich ja nur die 100 durch eine variable austauschen, das geht auch.
    Nur macht der sequencer jetzt nach dem letzten step eine Pause, im moment habe ich 8 Steps.
    Das anpassen der Variable currentTime geht auch noch nicht, das dürfte aber an der Verkabelung liegen.

    Ich finds auch gut die for schleife los zu sein, macht mehr sinn so.

    Code:
        if ((millis() - Timer) > currentTime) {
      
        Timer = millis();
    
        if (step < 8) {
           
           currentSwitchState[step] = digitalRead(switchPins[step]);
           playstep(step);  
           step++; 
         } else {
           step = 0;
        }
      }
    dies ist der Code der die up/down Buttons abfragt:
    Code:
     currentTimeState = digitalRead(timePin1);
          if (currentTimeState == 1) {
            currentTime = currentTime + 50;
          }
    
      currentTimeStateDown = digitalRead(timePin2);
          if (currentTimeStateDown == 1) {       
            if (currentTime <= 50) {
              currentTime = 100;
            } else {     
              currentTime = currentTime - 50;
            }
          }

    Eine andere Frage ist ob ich den Bereich den der Poti abdeckt eingrenzen kann?
    Wenn ich zu weit nach links oder rechts drehe kommt da nicht mehr viel, nur ein ultrahoher pitch oder das gegenteil.
     
  18. Burt

    Burt Tach

    Dein Code macht eine Pause, weil Du einen 'Leerdurchlauf' in der Schleife hast. Wenn Dein Zähler =8 ist und Du
    auf 0 zurücksetzt, gibts kein playstep.

    Die Potis beim Arduino gehen von 0-1023. Wenn Du den Bereich eingrenzen willst, dann dividiere
    (oder schiebe rechts, ist wesentlich schneller) durch einen entsprechenden Skalierungsfaktor.
    Beispiel: durch 4 dividieren (oder 2 nach rechts schieben), um auf Werte zwischen 0 und 256 zu kommen.
    Um die kleinen Werte loszuwerden einen Offset dazuaddieren.
     
  19. Rupertt

    Rupertt Tach

    der macht mit diesem code immer noch eine pause :sad:
    Code:
    f (step < 8) {
           
           currentSwitchState[step] = digitalRead(switchPins[step]);
           playstep(step);  
           step++; 
         } else {
           currentSwitchState[step] = digitalRead(switchPins[step]);
           playstep(step);  
           step = 0;
        }
     
  20. Burt

    Burt Tach

    Ist zu erwarten, da Du jetzt einen 9ten step mit abspielst (index '8').
    Stell Deinen Ablauf etwas um, so daß Du nach dem Hochzählen prüfst,
    ob Deine Überlaufbedingung ( >= '8') eintritt, setze Deinen Zähler, falls
    notwendig, auf 0.
     
  21. Flub

    Flub Tach

    mein vorgeschlagener code war anders aufgebaut.

    vor der sache mit der bedingung für den step wird der aktuelle step verarbeitet, dann gibts auch keinen leerdurchlauf. ich habe in meinem code an der besagten stell kommentiert...
     
  22. Rupertt

    Rupertt Tach


    ah, das war damit gemeint, jetzt versteh ich das.
     
  23. Rupertt

    Rupertt Tach

    Hallo,
    ich habe das programm jetzt delay frei(mit externer hilfe).
    Nun wollte ich mich an daran setzen das timing einstellen zu können,
    mein code lief schoneinmal, wenn ich jetzt aber den "up" button drücke bleibt der sequencer stehen
    und schein abgestürzt.

    Im grunde gibt es eine variable currentTime, diese will ich mit 2 up/down buttons regeln,
    drückt man den up button werden 50ms hinzugefügt vice versa beim down button.
    Sieht jemand hier warum das programm crasht?
    Code:
    void loop() {
    
    
    //timing settings  
      currentTimeState = digitalRead(timePin1);
          if (currentTimeState == 1) {
            currentTime = currentTime + 50;
          }
    
      currentTimeStateDown = digitalRead(timePin2);
          if (currentTimeStateDown == 1) {       
            if (currentTime <= 50) {
              currentTime = 100;
            } else {     
              currentTime = currentTime - 50;
            }
          }
          
    //play button action
      playState = digitalRead(playPin);
      
      if (playState != lastplayState) {
        
        // change the state of the led when someone pressed the button
        if (playState == 1) { 
          if(playing==1) {
            playing=0;
            noteOn(0xB0, 0x78, 0x00);
          } else { 
            playing=1;         
          }
        }
        // remember the current state of the button
        lastplayState = playState;
      }
    
    //Main sequence
      if (playing == 1) {
        
      if ((millis() - Timer) > currentTime) {
      
        Timer = millis();
        currentSwitchState[step] = digitalRead(switchPins[step]);
        playstep(step); 
        if (step < 7) {
          step++; 
        } else {
          step = 0;
        }
      }
    }   
        
    
    }
    
     
  24. Flub

    Flub Tach

    ich denke mal du benutzt Drucktaster. Wenn ja solltest du sie wie folgt in der Setup Funktion vorbereiten um den internen pullup widerstand für die Taster zu benutzen.

    pinMode(ButtonPin, INPUT);
    digitalWrite(ButtonPin, HIGH);

    Der Normalzustand am ButtonPin ist jetzt also HIGH, wenn du drückst ist der PIn LOW.

    wenn du im loop jetzt überprüfst, ob der button gedrückt wurde oder nicht (if (digitalRead(ButtonPin) == LOW) {}) ), musst du bedenken, das die abläufe ja sehr schnell sind, bei 16Mhz macht der 16 Millionen Mal pro sekunde was, das heißt du würdest bei einem Tastendruck die Aktion, die eigentlich nur einmal für jeden Tastendruck geschehen soll, viel öfters als gewollt ausführen. Das heißt du brauchst noch eine Variable angibt, ob die taste zwischenzeitlich schon losgelassen wurde, sodass du nicht alles öfters ausführst.

    also die variable definieren : z.b.

    boolean button_ok = true;

    im loop dann...:

    if (digitalRead(ButtonPin)== LOW) {
    (if (button_ok == true) {
    mach was...
    }
    button_ok = false;
    } else {
    button_ok = true; // wenn digitalRead nicht LOW war
    }

    jetzt ist sozusagen fast alles schon und gut, dann muss der taster nur noch entprellt werden, weil du sonst ganz oft doppel oder dreifach trigger hast.
    guck bei den arduino tutorials nach "debouncing"
     
  25. Rupertt

    Rupertt Tach

    mir fällt gerade auf das wenn ich nur die ersten 4 steps aktiviert habe das der sequencer dann für die nicht aktiven steps ne pause macht, kann
    man das so einrichten das er diese steps dann überspringt?

    Ich habe schon versucht currentSwitchState auf 1 zu püfen und wenn nicht dann soll er step++ machen, das hat aber nicht geholfen :sad:
    Code:
     if (playing == 1) {
        
        if ((millis() - Timer) > currentTime) {
          Timer = millis();
          currentSwitchState[step] = digitalRead(switchPins[step]);
          playstep(step);
          
          if (step < 7) {
            step++; 
          } else {
            step = 0;
          }
        }
    }   
    Code:
          if(currentSwitchState[step] == 0) {
            step++;
    oder muss ich ich da dort ein break oder sowas einbauen?

    EDIT:

    Moment, eigentlich will ich die pausen ja haben, macht ja den groove ein wenig aus...
    Einzig eine 2x8 option solls irgentwann geben
     
  26. Rupertt

    Rupertt Tach

    Welcher wertebereich für den pitch ist den Sinnvoll,
    im Moment teile ich die 1024 durch 8, was aber mindestnes das erste und letzte viertel in
    extreme Tonlagen bringt.
    Ich habe auch schon durch 16 geteilt und den start auf 32 und mehr hochgesetzt,
    ganz zufrieden war ich damit auch nicht.
    Ist dieser Bereich bei allen synth gleich? also 0-128?

    Code:
    note[stepnr] = AnalogValue[stepnr]/8;
     
  27. Moogulator

    Moogulator Admin

    Bending sind heute 14 Bit, früher schon auch mal weniger.
     
  28. Rupertt

    Rupertt Tach

    Dann wundert es mich das ich mit meine 128 schon so tief/hoch komme, 14bit wären ja 16.384.

    Da ich jetzt in der Modularwelt angekommen bin frage ich mich ob ich in den arduino einen cv/gate einbauen soll oder
    das einfach per Midi->CV Interface regeln kann, da fehlt mir die Erfahrung.
     

Diese Seite empfehlen