Stap 5: Aangepaste bericht handlers
Met behulp van midiMessage is OK voor eenvoudige zaken, zoals met de schets doen iets ongeacht welke opmerking wordt verzonden, of misschien selecteren van gedrag op basis van twee of drie opmerkingen, maar als uw code vullen met lange als/dan vinden of switch/case verklaringen moet u voorzichtig. Dit soort structuren kunnen worden moeilijk te handhaven.
Wat zou schoner dan een groeiend aantal conditionals zou een manier om een methode op basis van de waarde van de notitie te starten. Hier is een manier om het te doen:
void midiMessage(MidiMessage message, long timestamp, String bus_name) { int note = (int)(message.getMessage()[1] & 0xFF) ; int vel = (int)(message.getMessage()[2] & 0xFF); println("Bus " + bus_name + ": Note "+ note + ", vel " + vel); invokeNoteHandler(note, vel); } void invokeNoteHandler(int note, int velocity) { try { Class[] cls = new Class[1]; cls[0] = int.class; Method handler = this.getClass().getMethod( "onNote" + note, cls ); handler.invoke(this, velocity); } catch (Exception e) { e.printStackTrace(); } }
Als een MIDI-bericht ontvangt, trekt midiMessage de Nootwaarde en snelheid. Deze waarden naar invokeNoteHandler worden doorgegeven. Dat is waar het plezier gebeurt.
Java reflectie kan code methoden vinden door naam (met getMethod) te noemen. Wij willen een int waarde doorgeven aan een bepaalde methode van het formulier onNote < SomeNoteValue >; om te zoeken naar een methode u moet zowel de naam als een array van klassen met een beschrijving van wat argumenten die methode neemt.
Zodra een verwijzing naar een dergelijke methode is gevonden is aangeroepen met behulp van (verrassing!) aanroepen.
Dit alles gebeurt binnen een try/catch-blok. Als er iets mis gaat (bijvoorbeeld de code probeert te vinden en het aanroepen van een methode die niet bestaat) de uitzondering is meer of minder genegeerd. Het idee hier is dat er methoden voor enige verzameling van notities, en we niet schelen notities waarvoor er geen bijbehorende handler-methode is.
Het laatste deel van dit is om te definiëren van een of meer methoden om iets voor specifieke notities te doen. Bijvoorbeeld:
void onNote48(int vel) { if (vel > 0 ) { currentColor = vel*2; } } void onNote50(int vel) { if (vel > 0 ) { currentColor = vel*2; } }
Niet vreselijk fantasierijke, maar wat dit doet is limiet scherm-kleur verandert in slechts twee opmerkingen.
Hier is misschien een beter voorbeeld:
Eerst, wijzigt u het type van currentColor:
color currentColor = new color(0,0,0);
Nu hebben de opmerking handlers verschillende kleuren instellen:
void onNote48(int vel) { if (vel > 0 ) { currentColor = color(255, vel*2, vel*2); } } void onNote50(int vel) { if (vel > 0 ) { currentColor = color(vel*2, 255, vel*2 ); } } void onNote52(int vel) { if (vel > 0 ) { currentColor = color(vel*2, vel*2, 255); } }
Het belangrijkste punt is dat het gedrag voor een bepaalde opmerking is ingekapseld in een eigen methode in plaats van in een groeiende catch-all-methode worden gepropt.
Kunnen we dingen schoner, maar door alle methoden van de opmerking aangestuurde brengen in een afzonderlijk bestand (bv noteHandlers.pde) zodat u weet precies waar hij moet zoeken als u wilt toevoegen of wijzigen om het even wat.
Uw eigen bericht handlers kunnen alles wat die je wilt, en u wilt misschien in andere parameters doorgeven, misschien doorgeven in het oorspronkelijke bericht van de MIDI zelf. Maar u moet het op u uw versie van invokeNoteHandler zo instellen dat wordt gezocht naar methoden met de juiste parameter handtekening.
Bijvoorbeeld, als u gebruik wilt maken handler methoden, die de opmerking snelheid en de naam van de bus nemen, wilt u wijzigen van de klasse array gebruikt met getMethod om aan te geven welke van deze twee parameter:
void invokeNoteHandler(int note, int velocity, String busName) { try { // An array of size 2 since we are looking for a method that // takes two arguments Class[] cls = new Class[2]; cls[0] = int.class; cls[1] = String.class; Method handler = this.getClass().getMethod( "onNote" + note, cls ); // Now call the located method with the two arguments handler.invoke(this, velocity, busName); } catch (Exception e) { e.printStackTrace(); } }