14 votes

Java reçoit des données du clavier MIDI

J'ai conçu mon propre synthétiseur en java et je veux maintenant le connecter avec un clavier midi. Ma classe ci-dessous recherche tous les appareils midi qui ont des émetteurs. Elle trouve avec succès mon clavier midi. J'ajoute mes propres récepteurs à chaque émetteur pour chaque appareil afin qu'il puisse capter tout ce qui est possible. En lisant tous les documents d'aide et la doc Java, je sais qu'un émetteur envoie des événements Midi à un récepteur qui les traite ensuite avec la méthode d'envoi. J'ai donc écrit ma propre classe interne implémentant le récepteur et j'ai simplement utilisé une instruction println pour vérifier si quelque chose avait été détecté dans la méthode d'envoi. Cependant, rien n'est détecté du tout. Il semble y avoir très peu d'aide pour faire une chose aussi simple et j'ai regardé tous les fichiers d'aide, javadoc et forum. Je suis sûr qu'il doit y avoir quelque chose de vraiment évident qui m'a échappé.

Mon synthétiseur ne doit pas être confondu avec le synthétiseur d'interface et ce n'est pas un instrument midi. Il utilise un algorithme de synthèse et possède une méthode de lecture. En gros, j'ai juste besoin que le clavier midi envoie un événement note on qui invoquera la méthode de lecture.

import javax.sound.midi.*;
import java.util.ArrayList;
import java.util.List;
import java.io.*;
public class MidiHandler
{
    //ArrayList of MidiDevices
    private ArrayList<MidiDevice> devices = new ArrayList<MidiDevice>();

    public MidiHandler()
    {
        MidiDevice device;
        MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
        for (int i = 0; i < infos.length; i++) {
            try {
                device = MidiSystem.getMidiDevice(infos[i]);
                //does the device have any transmitters?
                if (device.getTransmitters().size() > 0) {
                    //if it does, add it to the device list
                    System.out.println(infos[i] + ": " + device.getTransmitters().size());
                    devices.add(device);
                }
            } catch (MidiUnavailableException e) {}
        }
        //if any transmitting devices were found
        if(devices.size()>0) {
            //for each device
            for(int i = 0; i<devices.size(); i++) {
                try {
                    //get all transmitters
                    List<Transmitter> transmitters = devices.get(i).getTransmitters();
                    //and for each transmitter
                    for(int j = 0; j<transmitters.size();j++) {
                        //create a new receiver
                        transmitters.get(i).setReceiver(
                            //using my own MidiInputReceiver
                            new MidiInputReceiver(devices.get(i).getDeviceInfo().toString())
                        );
                    }
                    //open each device
                    devices.get(i).open();
                    //if code gets this far without throwing an exception
                    //print a success message
                    System.out.println(devices.get(i).getDeviceInfo()+" Was Opened");
                } catch (MidiUnavailableException e) {}
            }
        }
    }
    //tried to write my own class. I thought the send method handles an MidiEvents sent to it
    public class MidiInputReceiver implements Receiver {
        public String name;
        public MidiInputReceiver(String name) {
            this.name = name;
        }
        public void send(MidiMessage msg, long timeStamp) {
            System.out.println("midi received");
        }
        public void close() {}
    }
}

NOTE : J'ai déjà vu cela : Java MIDI - obtenir des données du piano ? .

et ceci : http://www.jsresources.org/examples/MidiInDump.html

Le séquenceur d'interface semble trop compliqué pour ce que je veux aussi.

16voto

sjlevine29 Points 176

J'ai constaté que la fonction MidiDevice getTransmitters() semble renvoyer la liste des émetteurs actuels. déjà ouvert des émetteurs, pas des émetteurs qui sont disponible sur à ouvrir. Je crois que la façon d'ouvrir un nouvel émetteur est via la méthode getTransmitter(). J'ai modifié votre code pour le faire :

import javax.sound.midi.*;
import java.util.ArrayList;
import java.util.List;
import java.io.*;
    public class MidiHandler
{

    public MidiHandler()
    {
        MidiDevice device;
        MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
        for (int i = 0; i < infos.length; i++) {
            try {
            device = MidiSystem.getMidiDevice(infos[i]);
            //does the device have any transmitters?
            //if it does, add it to the device list
            System.out.println(infos[i]);

            //get all transmitters
            List<Transmitter> transmitters = device.getTransmitters();
            //and for each transmitter

            for(int j = 0; j<transmitters.size();j++) {
                //create a new receiver
                transmitters.get(j).setReceiver(
                        //using my own MidiInputReceiver
                        new MidiInputReceiver(device.getDeviceInfo().toString())
                );
            }

            Transmitter trans = device.getTransmitter();
            trans.setReceiver(new MidiInputReceiver(device.getDeviceInfo().toString()));

            //open each device
            device.open();
            //if code gets this far without throwing an exception
            //print a success message
            System.out.println(device.getDeviceInfo()+" Was Opened");

        } catch (MidiUnavailableException e) {}
    }

}
//tried to write my own class. I thought the send method handles an MidiEvents sent to it
public class MidiInputReceiver implements Receiver {
    public String name;
    public MidiInputReceiver(String name) {
        this.name = name;
    }
    public void send(MidiMessage msg, long timeStamp) {
        System.out.println("midi received");
    }
    public void close() {}
    }
}

Sur mon matériel (j'ai un simple contrôleur MIDI USB branché), le code affiche correctement "midi received" après la création d'une instance de MidiHandler.

J'espère que cela vous aidera !

3voto

Robert Points 21

J'ai découvert que vous devez ouvrir le périphérique avant d'appeler setRecceiver(), sinon la méthode send() du récepteur est appelée avec toutes les données MIDI résiduelles de la dernière fois que vous avez lancé l'application.

device.open();

Transmitter trans = device.getTransmitter();    
// set new receiver after opening so that the input buffer will be flushed
trans.setReceiver(new MidiInputReceiver(device.getDeviceInfo().toString()));

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X