Schönen Guten Abend

one more thing
-----------------

Wenn ich so im Manual lese "liest" es sich sehr danach an als wäre das gerät besonders gut dafür kurze loops aufzunehmen und abzuspielen.
Was würde passieren wenn man laaaaaange loops bzw ganze stücke einspielt?

Bitte entschuldigt meine anfängerfragen. bin leider was sequencer angeht unerfahren.
Das ist schon wichtig - denn es ist eine Stärke - du kannst auch sehr lange Takte spielen und anpassen - der MT lässt dir nie das Gefühl, dass was nicht geht wegen Länge.
Daher hast du dann einfach die Länge die du dann einstellst.
 
Unter Umständen für den Ein oder Anderen ganz interessant, ein kleines Programm in C, welches euklidische Rhythmen generiert. Vorbild war hier der euclidian Mode im Analog Rytm. Zwei euklidisch erzeugte Pattern, die jeweils geshifted mit boolischen Operatoren verglichen werden. Die finale Sequenz kann bei Bedarf ebenfalls rotieren.

C:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define SEQSIZE 16 /*Pattern Length*/

char* init_Array(char* d, const char* s) {
    char* tmp = d;
    while (*s) {
        *d++ = *s++;
    }
    *d = '\0';
    return tmp;
}

char* append_Array(char* d, const char* s) {
    while (*d) {
        ++d;
    }
    while (*s) {
        *d++ = *s++;
    }
    *d = '\0';
    return d;
}

void euclid(int d[], const int size, const int value) {
    char** tmp = (char**)malloc(size * sizeof(char*));
    for (int i = 0; i < size; ++i) {
        tmp[i] = (char*)malloc((size + 1) * sizeof(char));
    }
    int z = size;
    int p = size;
    int t = size;
    int s = value;
    (p < s) ? (p = s, s = t) : 0;
    t = p - s;
    for (int i = 0; i < size; ++i) {
        (i < s) ? init_Array(tmp[i], "X") : init_Array(tmp[i], "-");
    }
    while (t > 1) {
        (z > 0) ? z-- : 0;
        if (t < s) {
            p = s;
            s = t;
        }
        else {
            p = t;
        }
        t = p - s;
        for (int i = 0; i < s; ++i) {
            append_Array(tmp[i], tmp[z - i]);
        }
        z = p;
    }
    int n = 0;
    for (int i = 0; i < z; ++i) {
        int j = 0;
        while (tmp[i][j] != '\0') {
            d[n++] = (tmp[i][j] == 'X') ? 1 : 0;
            ++j;
        }
    }
    for (int i = 0; i < size; ++i) {
        free(tmp[i]);
    }
    free(tmp);
}

void shift(int d[], const int size, int shift_Value) {
    if (!shift_Value) {
        return;
    }
    (shift_Value < 0) ? (shift_Value += size) : 0;
    int* tmp = (int*)malloc(size * sizeof(int));
    for (int i = 0; i < size; ++i) {
        tmp[(i + shift_Value) % size] = d[i];
    }
    for (int i = 0; i < size; ++i) {
        d[i] = tmp[i];
    }
    free(tmp);
}

void cmp(int d[], const int s[], const int size, const int bool_operator) {
    for (int i = 0; i < size; ++i) {
        switch (bool_operator) {
        case 0:
            d[i] &= s[i];
            d[i] = !d[i];
            break;
        case 1:
            d[i] &= s[i];
            break;
        case 2:
            d[i] |= s[i];
            break;
        case 3:
            d[i] ^= s[i];
            break;
        default:
            break;
        }
    }
}

void print_Seq(const int arr[], const int size) {
    for (int i = 0; i < size; ++i) {
        if (arr[i] == 1) {
            printf(" X ");
        }
        else {
            printf(" - ");
        }
    }
}

int main() {
    /*set random Values*/
    srand(time(NULL));
    int rnd_STEPS_A = rand() % (SEQSIZE - 1) + 1;
    int rnd_STEPS_B = rand() % (SEQSIZE - 1) + 1;
    int rnd_SHIFT_A = rand() % (2 * SEQSIZE - 2) - (SEQSIZE-1);
    int rnd_SHIFT_B = rand() % (2 * SEQSIZE - 2) - (SEQSIZE-1);
    int rnd_SHIFT_C = rand() % (2 * SEQSIZE - 2) - (SEQSIZE-1);
    int rnd_CMP_OPERATOR = rand() % 4;
  
    char op[4];
    if (rnd_CMP_OPERATOR == 0) init_Array(op,"NOT");
    else if (rnd_CMP_OPERATOR == 1) init_Array(op, "AND");
    else if (rnd_CMP_OPERATOR == 2) init_Array(op, "OR");
    else init_Array(op, "XOR");

    /*print Counter*/
    for (int i = 0; i < SEQSIZE; ++i) {
        printf("%02i|", i + 1);
    }
    printf(" | Counter\n");
    for (int i = 0; i < SEQSIZE; ++i) {
        printf("---");
    }
    printf("\n");

    /*init euclidian Sequence*/
    int a[SEQSIZE], b[SEQSIZE];
    euclid(a, SEQSIZE, rnd_STEPS_A);
    euclid(b, SEQSIZE, rnd_STEPS_B);

    /*print Seq_A*/
    print_Seq(a, SEQSIZE);
    printf(" | Seq_A -> %i von %i\n", rnd_STEPS_A, SEQSIZE);

    /*shift Seq_A*/
    shift(a, SEQSIZE, rnd_SHIFT_A);

    /*print shifted Seq_A*/
    print_Seq(a, SEQSIZE);
    printf(" | Seq_A shift -> %i\n", rnd_SHIFT_A);

    printf("\n");

    /*print Seq_B*/
    print_Seq(b, SEQSIZE);
    printf(" | Seq_B -> %i von %i\n", rnd_STEPS_B, SEQSIZE);

    /*shift Seq_B*/
    shift(b, SEQSIZE, rnd_SHIFT_B);

    /*print shifted Seq_B*/
    print_Seq(b, SEQSIZE);
    printf(" | Seq_B shift -> %i\n", rnd_SHIFT_B);
    printf("\n");

    /*print Seq_A / Seq_B*/
    print_Seq(a, SEQSIZE);
    printf(" | Seq_A\n");
    print_Seq(b, SEQSIZE);
    printf(" | Seq_B\n");

    /*compare Seq_A / Seq_B*/
    cmp(a, b, SEQSIZE, rnd_CMP_OPERATOR);

    /*print Result*/
    for (int i = 0; i < SEQSIZE; ++i) {
        printf("---");
    }
    printf("\n");

    print_Seq(a, SEQSIZE);
    printf(" | cmp Seq_A %s Seq_B\n\n",op);

    /*shift Result*/
    shift(a, SEQSIZE, rnd_SHIFT_C);

    /*print Pattern*/
    print_Seq(a, SEQSIZE);
    printf(" | Seq_C shift -> %i\n", rnd_SHIFT_C);
    for (int i = 0; i < SEQSIZE; ++i) {
        printf("===");
    }
    printf("\n");

    return 0;
}

Code:
01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16| | Counter
------------------------------------------------
 X  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  | Seq_A -> 1 von 16
 -  -  -  -  X  -  -  -  -  -  -  -  -  -  -  -  | Seq_A shift -> 4

 X  -  X  X  -  X  -  X  X  -  X  X  -  X  -  X  | Seq_B -> 10 von 16
 -  X  -  X  X  -  X  X  -  X  -  X  X  -  X  X  | Seq_B shift -> -12

 -  -  -  -  X  -  -  -  -  -  -  -  -  -  -  -  | Seq_A
 -  X  -  X  X  -  X  X  -  X  -  X  X  -  X  X  | Seq_B
------------------------------------------------
 -  X  -  X  -  -  X  X  -  X  -  X  X  -  X  X  | cmp Seq_A XOR Seq_B

 X  X  -  X  X  -  X  -  X  -  -  X  X  -  X  -  | Seq_C shift -> -11
================================================


** Process exited - Return Code: 0 **

Vorerst werden die euklidischen Rhythmen unter der Haube im Random Generator des MidiTraC's Anwendung finden, evtl. kommt auch noch ein UI für den User.

Kritik und Ideen im Hinblick auf Optimierung sind willkommen!
 
Zuletzt bearbeitet:
Firmware 1.97

v1.97
Improvement
- new Step Record Mode: allow different dividers & adjustment of Loop Length
- RND use euclidian Algorithm to generate Sequences
- poly to mono Funktion (lowest Note)
- Arpeggiator & Chord depends on Scale
- Scale show used Keys
- revised Manuals
Bugfix:
- transpose Record ends within select Keys
- faster encoder subroutine
- many small UI things...
 

Anhänge

  • MidiTraC_1_97.zip
    637 KB · Aufrufe: 5
Zuletzt bearbeitet:
Vielen Dank für das tolle Update!
Das Firmware Update lief bei mir übrigens unter Linux sehr gut. Den Befehl dafür habe ich aus der "update_MacOS.command" entnommen und das USB Serial Device direkt reingeschrieben. Das sah bei mir dann so aus:

Code:
esptool.py --chip esp32 --port /dev/serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0 --baud 460800 --before default_reset --after hard_reset write_flash 0x0 ./MidiTraC.bin
 
Eine leicht schräge Demo, wo vor allem die neuen Features eingesetzt werden: livejam ->MidiTraC steuert Jupiter Xm & Microfreak...



ratchets lassen sich mit dem Step Sequencer nun extrem schnell realisieren. Da polyphon eingespielt werden kann, bin ich wesentlich schneller am Ziel als mit einem Lauflicht... Gate- und Steplänge können für jeden Step gewählt werden (kleinste Einheit 1/64 Triolen).

Die Spieluhr sequence ist Produkt des aus User Arpeggio Pattern, und Scaler. Im Chord Mode kann ebenfalls der Scaler aktiv sein. Das Ergebnis kommt bei den E-Pianos und dem Hauptthema zum Ausdruck. Chords die ich intuitiv so nicht auf der Klaviatur spielen bzw. finden würde.

Weitere Sequencen wurden mit dem Euklid Generator erzeugt. In der aktuellen Version werden die Parameter noch über ein Random Modul angesteuert. Um alle Parameter des Euclid Generator zugänglich zu machen, muss noch ein wenig am User Interface umgestrickt werden. Grundsätzlich habe ich mich an den Elektrons orientiert, wie oben bereits beschrieben. Der Euclid Generator liefert musikalisch sinnvollere Pattern als nur Random. Der Generator lässt sich schneller bedienen, gefällige Ergebnisse werden per Tastendruck im Gedächtnis behalten, während man sich weiter neue Ergebnisse anhört.
 
Firmware 1.98

Sequenzen lassen sich über einen euklidischen Algorithmus monophon und polyphon generieren. Dabei können nun alle Parameter selbst editiert werden. Eine schnelle Würfel Option ist ebenfalls wählbar.

Das Euklidische Muster kann bis zu 254 Steps umfassen. Erzeugt werden zwei Muster in Abhängigkeit vom Divider (1/128-1/1), die jeweils eigenständig rotieren und mit Vergleichsoperatoren bearbeitet werden können (siehe oben).

Tonhöhen werden schnell über eine große Range eingestellt. Skalen sind unabhängig von der globalen Skala anwendbar. Polyphone Pattern werden über interne Chord und Keying Algorithmen erweitert (bis zu vier Stimmen). Die Duration (Gate Time Range) ist ebenfalls einstellbar und wird wie Velocity zufällig generiert.

Code:
 ________________    ________________
|Ch: 12 Oct: 3+12|  |EuclidSteps: 032|
|RootScale: D-maj|  |SeqA: 012 S: 011|
|GTR:   1/16  1/4|  |SeqB: 004 S: -10|
|M/P: P Rytm: RND|  |A><B: XOR S: 000|
|////////////////|  |////////////////|


Die beiden Demo Pattern wurden nur mit Hilfe der neuen Dicer Funktionen erzeugt, nicht eingespielt. Die Drums sind in dem Fall monophon Schicht für Schicht generiert. Es lassen sich auch polyphone Rhythmus Strukturen direkt erstellen, was für Breaks und Fills durchaus brauchbar ist...

Anhang anzeigen dicer_demo2.mp3

Anhang anzeigen dicer_demo1.mp3
 

Anhänge

  • MidiTraC_1_98.zip
    630,2 KB · Aufrufe: 2
Bugfix:
If using Scaler in ARP-Mode and selected Root Note is different from C, Notes will hang on...
 

Anhänge

  • MidiTraC_1_98b.zip
    630,4 KB · Aufrufe: 5
v1.98c
Improvement:
- Swing with amount over all quantize Levels
50% -> no Swing / lower than 50% -> shift forward otherwise backwards
Bugfix:
- fix RootNote and keying if scaler is active
 

Anhänge

  • MidiTraC_1_98c.zip
    633,7 KB · Aufrufe: 2
v2.00beta

Improvement:
- Realtime Dicer & Euclid Mode
- added Pitch- Rhythm- Euclid Dicer
Button [10] -> dice Pitch (Euclid if RND is active)
Button [11] -> dice Euclid
Button [14] -> dice Rhythm (Velocity & Duration)
Button [OK] -> keep the current pattern & and explore more
Button [Exit] -> keep Pattern and exit

- Realtime Step Mode that acts or feel like a common "Lauflicht" Sequencer
Button [14] -> toggle Mode ([STEP] -> normal / [LIVE] -> new Realtime Mode
Button [07] -> direct access to direct Monitoring (ON/OFF)
Encoder Option to scroll faster around the sequence

Be careful in Live Mode if adjust the Loop Length while Step recording,
the Results maybe not that what expected because of the given LoopLength
of the every single Step! In that case Button [OK] & [11] have a different
Behavior. Button [OK] fixed the LoopLength, Button [11] don't care about!
Please find out and give a Comment...

Bugfix:
- fix quantize function -> that fixes some other strange Behavior overall



Ist alles mit heißer Nadel gestrickt (daher Beta), läuft aber ganz rund...
Der Spaßfaktor im Umgang mit dem Euclidian Generator erhöht sich um ein vielfaches, da sofort jede Parameter Änderung hörbar ist und die Würfelfunktion immer wieder neue Ideen liefern bzw. Mutationen ausrollen.
Beim Step Sequencer erlaubt der Live Modus direkt Steps im Pattern zu setzen, mit dem Encoder kann man schnell an den gewünschten Step scrollen. Im Gegensatz zum Step Modus, wo die fertige Sequence erst nach dem Erstellen eingefügt wird (die Kopier Funktion, die die Sequence eigenständig "auffüllt", steht aber auch im Live Modus zur Verfügung). Gerade bei komplexen Drum Mustern bietet die Live Funktion einen besseren Überblick bzw. Höreindruck, ähnlich wie bei herkömmlichen Lauflicht Sequencern...
 

Anhänge

  • MidiTraC_2beta.zip
    637,5 KB · Aufrufe: 7
Beim Testen und Ausprobieren fallen ja zwischendurch einige Audio Schnipsel an...

Als Höreindruck, wie Dicer, Scaler und Chord Funktionen harmonieren... Ratched mit dem ARP und dem Step Sequencer in den Drum Elementen sind da aus Testzwecken leicht überrepräsentiert, Perkussive Muster sind oft generiert.


Anhang anzeigen 5-Audio 0002 [2024-07-07 164740].mp3

Pattern Wechsel Stresstest inklusive, dass vorherige Pattern klingt immer aus, während das neue Pattern bereits spielt.

Anhang anzeigen 6-Audio 0005 [2024-07-23 145212].mp3

Handyaufnahme...

Anhang anzeigen 4-Audio 0001 [2024-07-13 226546].mp3

Weiche Pattern Übergänge, obwohl immer wieder zwischen vier Pattern schnell hin und her gewechselt wird

Anhang anzeigen 5-Audio 0004 [2024-07-24 124134].mp3

Anhang anzeigen 5-Audio 0002 [2024-07-22 234734].mp3

Die letzten zwei Tracks sind mit der 2.0 Firmware... die Perkussions und Piano Parts sind zum Teil live generiert
 
Zuletzt bearbeitet:
Respekt @aliced25 👍
Fein, dass sich der MidiTraC bzw. die Firmware kontinuierlich weiter entwickelt. Sind denn überhaupt noch Geräte verfügbar?
 
nee, leider nicht.. vielleicht kommen noch ein paar Testrückläufer, die kann ich an Interessierte wieder weitergeben.
 
Added new feature...


so etwas wie ein Scatter- oder Glitch- Effekt. Wenn er aktiv ist, spielt er zufällige Steps, abhängig von der Quantisierung. Es entstehen Breaks & Fills oder neue Melodien aus dem vorhandenen Material. Wenn die Taste losgelassen wird, spielt das Pattern an der richtigen Position, als wäre nichts passiert...
 
Firmware 2.03

Der Dicer Modus wurde neu angelegt und hat einige einzigartige Funktionen hinzubekommen. Es ist möglich einen eigenen Pitch Table aufzunehmen. Dabei werden eingespielten Akkorde bzw. Kadenzen oder Melodien rhythmisch anhand der euklidischen Muster und Divider neu arrangiert. Die verschiedenen Parameter können in Realtime durchgehört und angepasst werden. Es gibt eine PolyMe & MonoMe Funktion, die Voices anhand der eingestellten Scale hinzufügen oder wegnehmen. Außerdem sind einige feste Preset Muster abrufbar...

Die oben beschriebene gLiTCh Funktion ist über zwei Buttons spielbar und springt in Abhängigkeit vom Divider durch das Pattern. Die aufbauenden Klangwände können dabei stehengelassen oder mit dem zweiten Button abgebrochen werden. Dabei entstehen auf Midi Ebene sehr schöne Stutter und gLiTCh Effekte... Es ist vom Prinzip her so, wie bei einem Granular Sampler, dessen Zeiger sich durch das Sample bewegt.

Beim UI wurden einige Kommunikationsaspekte verbessert...

[edit: 2.03]

Der Scaler kann beim Arpeggiator, Transponieren sowie auf Chords angewendet und global deaktiviert werden...
(Nach dem Update bitte die Setup Einstellungen neu abspeichern -> [SHIFT] + [OK] beim Verlassen des Menüs)
 

Anhänge

  • MidiTraC_2_03.zip
    643,3 KB · Aufrufe: 3
Zuletzt bearbeitet:
@Moogulator, vielen Dank für die Erwähnung im Artikel....

Es gibt noch ein kleines Update, welches die Bedienung des Dicers etwas intuitiver macht und die gLiTCh Funktion optimiert.

Midi via USB in Verbindung mit Hairless funktionierte leider nicht optimal, daher habe ich den Weg auch nicht mehr weiter verfolgt. Der verwendete ESP32 hat leider keine USB Host Funktionalität.
In der Hoffnung, dass der MidiTraC irgendwann erwachsen wird, wachsen aber gerade die ersten Blauzähne. Tests zeigen, dass die Übertragung via Bluetooth grundsätzlich funktioniert. Mal schauen, wie sich das im Sync mit anderen Geräten verhält und ob sich der Speicher soweit optimieren lässt, dass es auch unter den aktuellen Specs läuft. Die Wahrscheinlichkeit ist aber eher gering, da die Kapazitäten mittlerweile alle sehr ausgereizt sind.
Daher bastel ich an einer anderen Firmware, die den MidiTraC zum Bluetooth Midi Controller macht. Nichts besonderes aber enorm praktisch, wenn man am Synthrack steht und triviale Sachen wie Mutes, Arm, Start, Stop etc. in der DAW fernsteuern möchte...
 
ein interessantes projekt!
hab ich erst jetzt richtig wahrgenommen, und bin ja kurz davor zu sagen "haette gerne auch einen (wenn verfuegbar)",
bin mir aber noch nicht sicher, ob ich in die 5-pol-din-midi-welt (wieder)einsteigen moechte...

das konzept mit den wiederholungen mittels attributen finde ich gut!
ich frage mich noch, wie das mit dem array und den overdubs funktioniert, wie
kommen die events da "an die richtige stelle"?

fuer grosse cc- und pitchbend-orgien sind 1024 events natuerlich schon knapp,
fuer noten wuerde mir das locker reichen.
 
5-pol-din-midi-welt
wie oben erwähnt, theoretisch funktioniert Bluetooth Midi bzw. USB in Verbindung mit Hairless. Unter Verwendung von entsprechenden Bibliotheken, habe ich das schon zum Laufen bekommen. Ich kenne mich aber mit den Protokollen nicht gut genug aus, um das selber zu implementieren...

das konzept mit den wiederholungen mittels attributen finde ich gut!
ich frage mich noch, wie das mit dem array und den overdubs funktioniert, wie
kommen die events da "an die richtige stelle"?
Jedes Event trägt zusätzlich die Information, nach wieviel Takten es erneut abgespielt werden soll. Dadurch spart man bei Loop basierten Mustern sehr viel Speicherplatz (für einige Bearbeitungsoptionen, wie Transpose Record, Schneiden und Verketten, muss bzw. wird das Pattern konsolidiert). Grundsätzlich ist es egal, wo das Event im Array landet, da jedes Event eine eigene Start und Gate Time Informationen beinhaltet. Schnelle Sortier- und Suchalgorithmen sorgen dafür, dass nicht allzu viel iteriert werden muss beim Abspielen. Doppelt eingespielte Noten, z.B. beim Overdub, werden automatisch erkannt und entfernt. So kann man auf einer existierenden Achtel Hihat Spur einfach mit einem 1/32 oder 1/64 Arpeggiator drüber fahren ohne das die bereits gesetzten Event überfahren werden.

fuer grosse cc- und pitchbend-orgien sind 1024 events natuerlich schon knapp,
fuer noten wuerde mir das locker reichen.
Das Stimmt, daher besteht die Möglichkeit auch CC# Daten bei Bedarf quantisiert bzw. ausgedünnt aufzunehmen. Insgesamt kann hier aber noch einiges optimiert werden. Besonders Aftertouch bereitet noch Probleme...
Die 1024 Events stehen pro Slot (Szene oder Pattern, a' 16 Tracks (Midi Kanäle)), also 5 Mal zur Verfügung. Zwischen den Szenen kann beliebig gewechselt werden. Im Hintergrund können neue Patterns nachgeladen werden...
 
wie oben erwähnt, theoretisch funktioniert Bluetooth Midi bzw. USB in Verbindung mit Hairless.
bluetooth? nee, dann doch lieber 5 pol. haette ja auch noch einige solcher klangerzeuger...

Schnelle Sortier- und Suchalgorithmen sorgen dafür, dass nicht allzu viel iteriert werden muss beim Abspielen.

ok, so kann ich mir das vorstellen. wuerde das denn mit groesseren patterngroessen (auf einer andern mcu etwa)
skalieren? 1k events scheinen ja noch ueberschaubar zu sein.

ansonsten finde ich das ein recht interessantes konzept, so zwischen midi-looper
und sequenzer. und die spontane arbeitsweise so "ohne nachdenken" koennte mir auch gefallen.
 
ok, so kann ich mir das vorstellen. wuerde das denn mit groesseren patterngroessen (auf einer andern mcu etwa)
skalieren?
Das sollte gehen in Abhängigkeit von der maximalen Auflösung & Geschwindigkeit, die unterstützt werden soll. Aktuell läuft der MidiTraC mit 192 Tics pro Takt, 384 Tics funktionieren auch noch problemlos < 250 BPM, also ist noch ein bisschen Luft nach oben. Die Hardware ist eher begrenzt durch den verfügbaren RAM.
 


Zurück
Oben