Paso 5: Controladores de mensaje personalizados
Usando midiMessage es aceptable para casos sencillos, tales como tener el bosquejo hacer algo no importa de qué nota se envía, o tal vez seleccionar comportamiento basado en dos o tres notas, pero si encontrar el código para llenar largos if/then o switch/case declaraciones usted debe tener cuidado. Este tipo de estructuras puede ser difícil de mantener.
Qué sería más limpio que un creciente conjunto de condicionales sería una manera de invocar un método basado en el valor de la nota. Aquí está una manera de hacerlo:
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(); } }
Cuando llega un mensaje MIDI, midiMessage saca el valor de la nota y la velocidad. Pasa los valores a invokeNoteHandler. Es donde sucede la diversión.
Reflexión de Java permite que código encontrar métodos por nombre (usando getMethod) y llamarlos. Queremos pasar un valor int a algún método de la forma onNote < SomeNoteValue >; para encontrar un método que necesita el nombre y un conjunto de clases que describe qué argumentos eso método de la toma.
Una vez se encontró una referencia a un método es invocado usando (¡ sorpresa!) invoca.
Todo esto sucede dentro de un bloque try/catch. Si algo sale mal (por ejemplo, el código intenta encontrar y llamar a un método que no existe) la excepción es más o menos ignorado. La idea aquí es que tenemos métodos para un conjunto de notas, y no nos importa notas que existe ningún método de controlador correspondiente.
La última parte de esta debe definir uno o más métodos para hacer algo de notas específicas. Por ejemplo:
void onNote48(int vel) { if (vel > 0 ) { currentColor = vel*2; } } void onNote50(int vel) { if (vel > 0 ) { currentColor = vel*2; } }
No terriblemente imaginativo, pero lo que hace esto es límite color de la pantalla cambia a sólo dos notas.
Tal vez aquí hay un ejemplo mejor:
En primer lugar, cambiar el tipo de currentColor:
color currentColor = new color(0,0,0);
Ahora tienen los controladores Nota establecer diferentes colores:
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); } }
El punto clave es que el comportamiento de cualquier nota dada se encapsula en su propio método en vez de estar hacinados en un método cada vez más de todo.
Podemos hacer cosas más limpio aún poniendo todos los métodos de manejo de la nota en un archivo separado (e.g. noteHandlers.pde) así que usted sabe exactamente dónde buscar para agregar o cambiar cualquier cosa.
Sus propios controladores de mensaje pueden ser cualquier cosa que desee, y puede pasar en otros parámetros, tal vez pasar en el mensaje MIDI original sí mismo. Sin embargo se establece lo necesita configurar su versión de invokeNoteHandler que localiza métodos con la firma del parámetro correcto.
Por ejemplo, si desea utilizar métodos de control que la velocidad de nota y el nombre de bus, debe cambiar la matriz de clase usada con getMethod para indicar los tipos de estos dos parámetros:
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(); } }