Zoeken…


Invoering

De bedoeling van dit onderwerp om enkele basis MIDI-programma's te demonstreren die laten zien hoe te werken met het protocol en geleidelijk nuttige functies toevoegen die complexere toepassingen vereisen.

MIDI THRU Voorbeeld

De MIDI Thru is eenvoudig en gemakkelijk te testen. Als u goed werkt, kunt u uw Arduino-project tussen twee MIDI-apparaten, MIDI IN naar MIDI OUT, installeren en kunt u controleren of de twee apparaten samen werken. Als u de latentie kunt meten, ziet u een toename als gevolg van het vastleggen van seriële buffers en het opnieuw verzenden van instructies.

// This is a simple MIDI THRU.  Everything in, goes right out.
// This has been validate on an Arduino UNO and a Olimex MIDI Shield  

boolean byteReady; 
unsigned char midiByte;

void setup() {
    // put your setup code here, to run once:
    //  Set MIDI baud rate:
    Serial.begin(31250);
    byteReady = false;
    midiByte = 0;  
}

// The Loop that always gets called...
void loop() {
   if (byteReady) {
        byteReady = false;
        Serial.write(midiByte);
    }
}

// The little function that gets called each time loop is called.  
// This is automated somwhere in the Arduino code.
void serialEvent() {
  if (Serial.available()) {
    // get the new byte:
    midiByte = (unsigned char)Serial.read();
    byteReady = true;
  }
}

MIDI Thru met wachtrij

// This is a more complex MIDI THRU.  This version uses a queue.  Queues are important because some
// MIDI messages can be interrupted for real time events.  If you are generating your own messages,
// you may need to stop your message to let a "real time" message through and then resume your message.


#define QUEUE_DEPTH 128

// Queue Logic for storing messages
int headQ = 0;
int tailQ = 0;
unsigned char tx_queue[QUEUE_DEPTH];

void setup() {
    // put your setup code here, to run once:
    //  Set MIDI baud rate:
    Serial.begin(31250);
}

// getQDepth checks for roll over.  Folks have told me this 
// is not required.  Feel free to experiment.
int getQDepth() {
int depth = 0;
    if (headQ < tailQ) {
        depth = QUEUE_DEPTH - (tailQ - headQ);
    } else {
        depth = headQ - tailQ;
    }
    return depth;
}

void addQueue (unsigned char myByte) {
    int depth = 0;
    depth = getQDepth();

    if (depth < (QUEUE_DEPTH-2)) {
        tx_queue[headQ] = myByte;
        headQ++;
        headQ = headQ % QUEUE_DEPTH; // Always keep the headQ limited between 0 and 127
    }
}

unsigned char deQueue() {
    unsigned char myByte;
    myByte = tx_queue[tailQ];
    tailQ++;
    tailQ = tailQ % QUEUE_DEPTH;  // Keep this tailQ contained within a limit
    // Now that we dequeed the byte, it must be sent. 
    return myByte;
}

void loop() {
   if (getQDepth>0) {
        Serial.write(deQueue());
    }
}

// The little function that gets called each time loop is called.  
// This is automated somwhere in the Arduino code.
void serialEvent() {
  if (Serial.available()) {
    // get the new byte:
    addQueue((unsigned char)Serial.read());;
  }
}

MIDI Clock Generation

// This is a MiDI clk generator.  This takes a #defined BPM and 
// makes the appropriate clk rate.  The queue is used to let other messages 
// through, but allows a clock to go immediately to reduce clock jitter

#define QUEUE_DEPTH 128
#define BPM 121
#define MIDI_SYSRT_CLK 0xF8

// clock tracking and calculation
unsigned long lastClock;
unsigned long captClock;
unsigned long clk_period_us;

// Queue Logic for storing messages
int headQ = 0;
int tailQ = 0;
unsigned char tx_queue[QUEUE_DEPTH];

void setup() {
    //  Set MIDI baud rate:
    Serial.begin(31250);
    clk_period_us = 60000000 / (24 * BPM);
    lastClock = micros();
}

// getQDepth checks for roll over.  Folks have told me this 
// is not required.  Feel free to experiment.
int getQDepth() {
int depth = 0;
    if (headQ < tailQ) {
        depth = QUEUE_DEPTH - (tailQ - headQ);
    } else {
        depth = headQ - tailQ;
    }
    return depth;
}

void addQueue (unsigned char myByte) {
    int depth = 0;
    depth = getQDepth();

    if (depth < (QUEUE_DEPTH-2)) {
        tx_queue[headQ] = myByte;
        headQ++;
        headQ = headQ % QUEUE_DEPTH; // Always keep the headQ limited between 0 and 127
    }
}

unsigned char deQueue() {
    unsigned char myByte;
    myByte = tx_queue[tailQ];
    tailQ++;
    tailQ = tailQ % QUEUE_DEPTH;  // Keep this tailQ contained within a limit
    // Now that we dequeed the byte, it must be sent. 
    return myByte;
}

void loop() {
    captClock = micros();
    
    if (lastClock > captClock) {
        // we have a roll over condition - Again, maybe we don't need to do this.
        if (clk_period_us <= (4294967295 - (lastClock - captClock))) {
            // Add a the ideal clock period for this BPM to the last measurement value
            lastClock = lastClock + clk_period_us;
            // Send a clock, bypasing the transmit queue
            Serial.write(MIDI_SYSRT_CLK);
        }
    } else if (clk_period_us <= captClock-lastClock) {
        // Basically the same two commands above, but not within a roll over check
        lastClock = lastClock + clk_period_us;
        // Send a clock, bypasing the transmit queue
        Serial.write(MIDI_SYSRT_CLK);
    }

    if (getQDepth>0) {
        Serial.write(deQueue());
    }
}

// The little function that gets called each time loop is called.  
// This is automated somwhere in the Arduino code.
void serialEvent() {
  if (Serial.available()) {
    // get the new byte:
    addQueue((unsigned char)Serial.read());;
  }
}

MIDI-berichten gedefinieerd

Over het algemeen is het MIDI-protocol onderverdeeld in "berichten". Er zijn 4 algemene klassen van berichten:

  • Kanaalstem
  • Kanaalmodus
  • Systeem gemeenschappelijk
  • Systeem realtime berichten

Berichten beginnen met een bytewaarde boven 0x80. Elke waarde onder 0x7F wordt beschouwd als data. Dit betekent in feite dat 127 de maximale waarde is die kan worden gecodeerd in een enkele MIDI-databyte. Om grotere waarden te coderen, zijn twee of meer MIDI-databytes vereist.

Opgemerkt moet worden dat berichten van begin tot einde zonder onderbreking moeten worden verzonden ... BEHALVE ... Real-Time systeemberichten, die een enkele byte zijn, die in het midden van elk bericht kunnen worden geïnjecteerd.

Kanaal spraakberichten

Status D7..D0 Gegevensbytes Beschrijving
1000nnnn 0kkkkkkk 0vvvvvvv Note Off-gebeurtenis. Dit bericht wordt verzonden wanneer een notitie wordt vrijgegeven (beëindigd). (kkkkkkk) is het nummer van de toets (noot). (vvvvvvv) is de snelheid.
1001nnnn 0kkkkkkk 0vvvvvvv Opmerking over gebeurtenis. Dit bericht wordt verzonden wanneer een notitie is ingedrukt (start). (kkkkkkk) is het nummer van de toets (noot). (vvvvvvv) is de snelheid.
1010nnnn 0kkkkkkk 0vvvvvvv Polyfone toetsdruk (aftertouch). Dit bericht wordt meestal verzonden door op de toets te drukken nadat deze is "ingedrukt". (kkkkkkk) is het nummer van de toets (noot). (vvvvvvv) is de drukwaarde.
1011nnnn 0ccccccc 0vvvvvvv Controle wijzigen. Dit bericht wordt verzonden wanneer een controllerwaarde verandert. Controllers omvatten apparaten zoals pedalen en hendels. Controllernummers 120-127 zijn gereserveerd als "Kanaalmodusberichten" (hieronder). (ccccccc) is het controllernummer (0-119). (vvvvvvv) is de controllerwaarde (0-127).
1100nnnn 0ppppppp Programmawijziging. Dit bericht wordt verzonden wanneer het patchnummer verandert. (ppppppp) is het nieuwe programmanummer.
1101nnnn 0vvvvvvv Kanaaldruk (na aanraking). Dit bericht wordt meestal verzonden door op de toets te drukken nadat deze is "ingedrukt". Dit bericht verschilt van polyfone after-touch. Gebruik dit bericht om de grootste drukwaarde te verzenden (van alle momenteel ingedrukte toetsen). (vvvvvvv) is de drukwaarde.
1110nnnn 0lllllll 0mmmmmmm Pitch Bend Change. Dit bericht wordt verzonden om een verandering in de pitchbuiger aan te geven (typisch wiel of hendel). De pitchbuder wordt gemeten met een waarde van veertien bits. Midden (geen verandering van toonhoogte) is 2000H. Gevoeligheid is een functie van de ontvanger, maar kan worden ingesteld met RPN 0. (lllllll) zijn de minst significante 7 bits. (mmmmmmm) zijn de belangrijkste 7 bits.

Kanaalmodusberichten

Status D7..D0 Gegevensbytes Beschrijving
1011nnnn 0ccccccc 0vvvvvvv Kanaalmodusberichten. Dit is dezelfde code als de besturingswijziging (hierboven), maar implementeert moduscontrole en speciale melding met behulp van gereserveerde controllernummers 120-127. De commando's zijn:
Alles klinkt uit. Wanneer All Sound Off wordt ontvangen, worden alle oscillators uitgeschakeld en worden hun volume-enveloppen zo snel mogelijk op nul gezet. c = 120, v = 0: All Sound Off
Reset alle controllers. Wanneer Reset All Controllers wordt ontvangen, worden alle controllerwaarden teruggezet naar hun standaardwaarden. (Zie specifieke aanbevolen werkwijzen voor standaardinstellingen).
c = 121, v = x: waarde mag alleen nul zijn, tenzij anders toegestaan in een specifieke aanbevolen praktijk.
Lokale bediening. Wanneer Local Control is uitgeschakeld, reageren alle apparaten op een bepaald kanaal alleen op gegevens die via MIDI worden ontvangen. Afgespeelde gegevens, etc. worden genegeerd. Local Control On herstelt de functies van de normale controllers.
c = 122, v = 0: Local Control Off
c = 122, v = 127: Local Control On
Alle notities uitgeschakeld. Wanneer een All Notes Off wordt ontvangen, worden alle oscillators uitgeschakeld.
c = 123, v = 0: Alle noten uit (zie tekst voor beschrijving van actuele modusopdrachten.)
c = 124, v = 0: Omni Mode Off
c = 125, v = 0: Omni Mode On
c = 126, v = M: Monomodus Aan (Poly Uit) waarbij M het aantal kanalen is (Omni Uit) of 0 (Omni Aan)
c = 127, v = 0: Poly Mode aan (Mono uit) (Opmerking: deze vier berichten veroorzaken ook alle noten uit)

Algemene systeemberichten

Status D7..D0 Gegevensbytes Beschrijving
11110000 0iiiiiii [0iiiiiii 0iiiiiii] 0ddddddd --- --- 0ddddddd 11110111 Exclusief systeem. Met dit berichttype kunnen fabrikanten hun eigen berichten maken (zoals bulkdumps, patchparameters en andere niet-spec-gegevens) en biedt een mechanisme voor het maken van extra MIDI-specificatieberichten. De ID-code van de fabrikant (toegewezen door MMA of AMEI) is 1 byte (0iiiiiii) of 3 bytes (0iiiiiii 0iiiiiii 0iiiiiii). Twee van de 1 Byte ID's zijn gereserveerd voor extensies genaamd Universal Exclusive Messages, die niet fabrikant-specifiek zijn. Als een apparaat de ID-code herkent als zijn eigen (of als een ondersteund universeel bericht), luistert het naar de rest van het bericht (0ddddddd). Anders wordt het bericht genegeerd. (Opmerking: alleen realtime berichten mogen worden afwisselend met een systeemexclusie.)
11110001 0nnndddd MIDI Time Code Quarter Frame. nnn = Berichttype dddd = Waarden
11110010 0lllllll 0mmmmmmm Nummerpositie-aanwijzer. Dit is een intern 14-bits register dat het aantal MIDI-beats (1 beat = zes MIDI-klokken) sinds het begin van de song bevat. Ik ben de LSB, m de MSB.
11110011 0sssssss Nummer selecteren. De Song Select geeft aan welke reeks of song moet worden gespeeld.
11110100 Undefined. (Gereserveerd)
11110101 Undefined. (Gereserveerd)
11110110 Verzoek afstemmen. Bij ontvangst van een afstemmingsverzoek moeten alle analoge synthesizers hun oscillators afstemmen.
11110111 Einde van Exclusief. Wordt gebruikt om een System Exclusive dump te beëindigen (zie hierboven).

Systeem realtime berichten

Status D7..D0 Gegevensbytes Beschrijving
11111000 Timing Clock. 24 keer per kwartnoot verzonden wanneer synchronisatie vereist is (zie tekst).
11111001 Undefined. (Gereserveerd)
11111010 Begin. Start het afspelen van de huidige reeks. (Dit bericht wordt gevolgd met timingklokken).
11111011 Doorgaan met. Ga door op het punt waar de reeks is gestopt.
11111100 Hou op. Stop de huidige reeks.
11111101 Undefined. (Gereserveerd)
11111110 Actieve detectie. Dit bericht is bedoeld om herhaaldelijk te worden verzonden om de ontvanger te vertellen dat er een verbinding actief is. Gebruik van dit bericht is optioneel. Wanneer de ontvanger voor het eerst wordt ontvangen, verwacht deze elke 300ms (max) een ander Active Sensing-bericht te ontvangen, en als dit niet het geval is, wordt ervan uitgegaan dat de verbinding is verbroken. Bij beëindiging zal de ontvanger alle stemmen uitschakelen en terugkeren naar de normale (niet-actieve detectie) werking.
11111111 Reset. Reset alle ontvangers in het systeem naar de opstartstatus. Dit moet spaarzaam worden gebruikt, bij voorkeur onder handmatige bediening. Het mag met name niet worden verzonden bij het opstarten.


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow