Midi een noot verhogen.

algemene C code
Berichten: 12
Geregistreerd: 15 Mrt 2013, 00:22

Midi een noot verhogen.

Berichtdoor Round » 15 Mrt 2013, 00:49

Ik ben nieuw op het forum en ook de Arduino is nieuw voor mij.
Een van mijn hobby's is het bouwen van ongewone muziekinstrumenten. De Arduino kan daar een mooie aanvulling voor zijn.

Na een paar weken zoeken en uitproberen is het mij gelukt een stukje code te maken om de midi in op de midi uit te krijgen.

Maar wat ik uiteindelijk wil, is dat de aangeslagen noot op mijn keyboard, b.v C2 (=key 36) , telkens als ik dezelfde C2 weer opnieuw aansla, de key met 1 verhoogd wordt en dat 6 keer. Dus eerst key 36, dan 37, 38, 39, 40, 41.
Daarna moet C2 weer op key 36 beginnen en weer 6 keer met een waarde 1 verhogen.
Dit schijnt Round Robin te heten. Het is bedoeld om een drumpad bij elke aanslag 6 van geluid te veranderen.

Ik ben al dagen bezig geweest om een for instructie in te voegen, maar ik krijg het niet voor elkaar.
Heeft iemand een suggestie.

Dit is de code die ik heb.

byte commandByte;
byte noteByte;
byte velocityByte;
byte noteOn = 144;

void setup(){
Serial.begin(31250);

}

void checkMIDI(){
do{
if (Serial.available()){
commandByte = Serial.read();//read first byte
noteByte = Serial.read();//read next byte
velocityByte = Serial.read();//read final byte
Serial.write(noteOn);
Serial.write(noteByte);
Serial.write(velocityByte);
noteByte=0;
velocityByte=0;
}
}
while (Serial.available() > 24);//when three bytes available
}

void loop(){
checkMIDI();
delay(100);
}
--------------------------------------------------------------------------------------------

Als ik van Serial.write(noteByte); Serial.write(noteByte +1); maak, werkt dat wel. Vandaar dat ik aan een for instructie dacht.

Alvast hartelijk dank voor de te nemen moeite.
Ik zou er erg blij mee zijn.

Advertisement

Gebruikers-avatar
Berichten: 229
Geregistreerd: 20 Jan 2013, 12:01

Re: Midi een noot verhogen.

Berichtdoor astrofrostbyte » 16 Mrt 2013, 13:20

Hey, ik weet niets van Midi maar ik heb even een poging gedaan om een routinetje te schrijven.

de routine incr_note() is toegevoegd, het werkt dus voor elke noot, dus niet specifiek voor noot 36.
Code: Alles selecteren
byte incr_note(byte newkey, byte cnt)
{ static byte notecount = 0;                              <----- bijhouden hoevaak een key langsgekomen is
  static byte prevkey = 255;                              <----- onthouden welke key dit dan is
  if ( newkey == prevkey )                                <----- als een nieuwe key gedrukt is en gelijk aan de vorige gedrukt key
  { if (++notecount >= cnt) notecount = 0;                <----- verhoog keypress counter van 1 tot max cnt-1
  }
  else// newkey != prevkey                                <---- nieuwe noot gaat onaangepast door
  { prevkey = newkey;                                     <---- onthoud deze nieuwe noot
    notecount = 0;                                        <---- reset als andere key geweest is
  }
  return (newkey+notecount);// + 1,2,3,4...(cnt-1)
}
ps . niet geteste code
aanroepen met : noteByte = incr_note(noteByte, 6);

Wat andere opmerkingen betreffende midi protocol:
Volgens mij moet je controleren op groter of gelijk aan 3 bytes in de input buffer: while (Serial.available() >= 24);//when three bytes available
mischien is hier verwarring ontstaan tussen 3Bytes==24bits.

Je kan de ontvangen bytes :status/command/data , nog controleren door bit 7 te testen, dit kan de robuustheid van je systeem verhogen bij communicatie problemen.
als referentie heb ik gebruikt https://ccrma.stanford.edu/~craig/articles/linuxmidi/misc/essenmidi.html
Gear: Arduino- Uno,Due,Ethernet,Mega2560 , OLS LogicAnalyser, TDS1002, Rigol DG1022, J-Link EDU, BusPirate

Berichten: 12
Geregistreerd: 15 Mrt 2013, 00:22

Re: Midi een noot verhogen.

Berichtdoor Round » 16 Mrt 2013, 16:09

Hoi astrofrostbyte,

Te gek, ik ga er vanavond mee aan de slag en laat weten wat het geworden is.

Alvast heel erg bedankt.

Berichten: 12
Geregistreerd: 15 Mrt 2013, 00:22

Re: Midi een noot verhogen.

Berichtdoor Round » 16 Mrt 2013, 20:24

astrofrostbyte,

Zoals je beschrijft hoe het zou moeten werken is het nog mooier dan ik bedacht had. Dat geeft me zelfs meer mogelijkheden.

Ik ben een paar uur aan de slag geweest om jouw code in de bestaande code in te voegen, maar ik weet er duidelijk veel te weinig van af, want het lukt me niet.
Wat later op de avond ga ik er weer naar kijken, want het begint me nu te duizelen en dat leidt tot niets.

Ik houd je op de hoogte.
Nogmaals bedankt voor het meedenken.

Gebruikers-avatar
Berichten: 229
Geregistreerd: 20 Jan 2013, 12:01

Re: Midi een noot verhogen.

Berichtdoor astrofrostbyte » 16 Mrt 2013, 21:48

hier de volledig code
Code: Alles selecteren
byte commandByte;
byte noteByte;
byte velocityByte;
byte noteOn = 144;

void setup()
{ Serial.begin(31250);
}
//-------------------------------------------------------------
byte incr_note(byte newkey, byte cnt)
{ static byte notecount = 0;
  static byte prevkey = 255;
  if ( newkey == prevkey )
  { if (++notecount >= cnt) notecount = 0;
  }
  else// newkey != prevkey
  { prevkey = newkey;
    notecount = 0;
  }
  return (newkey+notecount);
}
//-------------------------------------------------------------
void checkMIDI(){
  do
  { if (Serial.available()){
      commandByte  = Serial.read(); //read 1st byte
      noteByte     = Serial.read(); //read 2nd byte
      velocityByte = Serial.read(); //read final byte
      noteByte = incr_note(noteByte, 6);
      Serial.write(noteOn);
      Serial.write(noteByte);
      Serial.write(velocityByte);
      noteByte=0;
      velocityByte=0;
    }
  } while (Serial.available() >= 3); //at least 3 bytes available
//  while (Serial.available() > 24); //when 25 bytes available
}
//-------------------------------------------------------------
void loop(){
  checkMIDI();
  delay(10);        //  <-- deze mog wel wat korter
}
//-------------------------------------------------------------



De checkMIDI kan iets anders geschreven worden, ik gebruik eigenlijk nooit do-while loops , geen idee waarom. er zat ook twee keer een serial.available in.
Ook een check voor commandbyte toegevoegd
Code: Alles selecteren
void checkMIDI()
{ if (Serial.available() >=3 )
  { if (0x80 && Serial.peek() ) // commandByte?
    { commandByte  = Serial.read(); //read 1st byte
      noteByte     = Serial.read(); //read 2nd byte
      velocityByte = Serial.read(); //read final byte
      noteByte = incr_note(noteByte, 6);
      Serial.write(noteOn);
      Serial.write(noteByte);
      Serial.write(velocityByte);
      noteByte=0;
      velocityByte=0;
    }
    else     // No Commandbyte detected !
    { Serial.read();  // dummy read to flush non Command byte
    }
  }
}//checkMIDI
Gear: Arduino- Uno,Due,Ethernet,Mega2560 , OLS LogicAnalyser, TDS1002, Rigol DG1022, J-Link EDU, BusPirate

Berichten: 12
Geregistreerd: 15 Mrt 2013, 00:22

Re: Midi een noot verhogen.

Berichtdoor Round » 16 Mrt 2013, 23:22

Je bent een kanjer, geweldig dat je dit wilt doen.
Ik ga er mee aan de slag.
Zo leer ik ook het nodige. Super.

Berichten: 12
Geregistreerd: 15 Mrt 2013, 00:22

Re: Midi een noot verhogen.

Berichtdoor Round » 16 Mrt 2013, 23:48

Hoi astrofrostbyte,

Helemaal super, het werkt op een klein foutje na. De tonen gaan niet 1 toon omhoog maar 2.
Dus van b.v key 36 - 38 - 40 en dan weer terug 36 - 38 - 40.

Maar verder is dIt wel helemaal top. Dat dit kan met elke noot geeft me super mogelijkheden.

Ik heb na Serial.write(velocityByte en delay van 100 ingevoegd, omdat hij soms bij snel aanslaan zich verslikte, maar dat is nu helemaal in orde.

Binnenkort zal ik op dit een fotoreportage zetten van wat ik aan het bouwen ben.
Super, dit maakt mijn weekend goed.

Gebruikers-avatar
Berichten: 229
Geregistreerd: 20 Jan 2013, 12:01

Re: Midi een noot verhogen.

Berichtdoor astrofrostbyte » 17 Mrt 2013, 12:34

mooi,
Dat verhogen van een noot met 2 ipv 1 heeft denk ik te maken met het MIDI protocol.
Zou het kunnen dat een slag op de drumpad twee frames verstuurd ?, één met een NOTE-ON commandbyte[0x9_], en daarna één met een NOTE-OFF commandbyte[0x8_] ?.
Ik heb te weinig ervaring met MIDI, om dit goed te kunnen beoordelen.

Als dat zo is zouden we de routine alleen kunnen uitvoeren bij een NOTE-OFF commando
Code: Alles selecteren
    void checkMIDI()
    { if (Serial.available() >=3 )
      { if (0x80 && Serial.peek() )       // commandByte?
        { commandByte  = Serial.read();
          noteByte     = Serial.read();
          velocityByte = Serial.read();
          if ( noteByte&0xF0 == 0x80)                         // note-Off commandbyte?
          { noteByte = incr_note(noteByte, 6);
          }
          Serial.write(noteOn);
          Serial.write(noteByte);
          Serial.write(velocityByte);
          noteByte=0;
          velocityByte=0;
        }
        else     // No Commandbyte detected !
        { Serial.read();  // dummy read to flush non Command byte
        }
      }
    }//checkMIDI


De code blijft toch een beetje raar, als je een NOTE-ON of NOTE-OFF command ontvangt verstuur je altijd een NOTE-ON commando, en blijkbaar werkt dat
Gear: Arduino- Uno,Due,Ethernet,Mega2560 , OLS LogicAnalyser, TDS1002, Rigol DG1022, J-Link EDU, BusPirate

Berichten: 12
Geregistreerd: 15 Mrt 2013, 00:22

Re: Midi een noot verhogen.

Berichtdoor Round » 17 Mrt 2013, 14:08

Je hebt het er maar druk mee,maar super, dat je dit doet.

Ik heb de nieuwe code ingevoerd, maar nu laat de Arduino telkens de aangeslagen noot door zonder deze te verhogen.
Voor jou op afstand is dat natuurlijk heel lastig omdat je niets kunt proberen. Des te meer mijn waardering.

In ieder geval geeft deze hulp me een zeer goed gevoel.

Berichten: 27
Geregistreerd: 23 Feb 2013, 12:07

Re: Midi een noot verhogen.

Berichtdoor walker » 17 Mrt 2013, 16:23

Hoi Round,

In de laatste code van de functie checkMIDI van astrofrostbyte zit een typefoutje waardoor de noot waarde niet meer opgehoogd wordt:

if ( noteByte&0xF0 == 0x80) // note-Off commandbyte?
{ noteByte = incr_note(noteByte, 6);
}
noteByte moet hier commandByte zijn.

Ik ben het met astrofrostbyte eens dat het aanmelden en afmelden hier raar is in je code. Als de ene noot afgemeld zou moeten worden, wordt de volgende aangemeld. Dit betekend dat de noten niet goed afgemeld worden. Bij geluiden die vanzelf uitdempen hoor je niet dat ze niet afgemeld worden.

Volgens mij zou het dus zo moeten werken:

aanmelden key 36 (noteByte) in -> aanmelden key 36 (noteByte) uit
afmelden key 36 in -> afmelden key 36 (noteByte) uit en notecounter ophogen met 1

aanmelden key 36 in -> aanmelden key noteByte + notecounter uit
afmelden key 36 in -> afmelden key noteByte + notecounter uit en notecounter ophogen met 1

aanmelden key 36 in -> aanmelden key noteByte + notecounter uit
afmelden key 36 in -> afmelden key noteByte + notecounter uit en notecounter ophogen met 1

enz. tot de zes keer bereikt zijn en dan de notecounter resetten en ook wanneer er een andere key aangemeld wordt notecounter resetten.

In je code gebruik je bij het aanmelden van de noten altijd MIDI kanaal 1 dit komt door de waarde 144 (0x90). Het laagste nibble (4 bits) is hier altijd 0.

Overigens kan het afgemeld van een noot bij MIDI ook door de noot aan te melden met een velocity waarde van 0.

Dus je zou zowel het afmelden als het aanmelden moeten afhandelen en nog een ander punt is dat alle andere MIDI data zoals volume, program change enz. nu niet worden door gestuurd van de ingang naar de uitgang.

Volgende

Terug naar C code

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 11 gasten