2017-02-20 3 views
0

Je cherche à écrire un simple séquenceur audio MIDI utilisant Javasound.Jouer plusieurs samples dans Javasound

J'ai plusieurs échantillons (un pour chaque pitch MIDI) qui sont chargés dans la mémoire en tant que (globalement accessible) Map<MidiPitch,AudioInputStream>.

Une sous-classe personnalisée de javax.sound.midi.Receiver répond aux événements MIDI entrants comme suit:

Si l'événement est une note sur un clip est obtenu et joué comme suit:

Clip clip = AudioSystem.getClip(); 
clip.open(lookupAIS(pitch)); 
clip.start(); 

Le clip est alors ajouté à un Map<MidiPitch,List<Clip>> accessible globalement, représentant les clips commencés, c'est-à-dire les clips pour lesquels start() a été appelé comme ci-dessus, mais pour lesquels un événement de note-off n'a pas encore été reçu.

Si l'événement est une note-off, la liste correspondante des clips démarrés est obtenue à partir de la carte ci-dessus. Le clip en tête de la liste est supprimé et stop() et close() y sont appelés.

Le Receiver ci-dessus est connecté à MidiSystem.getSequencer() de la manière habituelle, puis appelé ci-après:

sequencer.setSequence(MidiSystem.getSequence(new File(myMidFile))) 
sequencer.open() 
sequencer.start() 

Thread.sleep(aLongTime()) 

sequencer.stop() 
sequencer.close() 

Les travaux ci-dessus lorsque la séquence MIDI conduite est à un tempo lent, mais à des tempos plus, des notes accrocher simplement (même pour des séquences contenant un très petit nombre de notes).

Ma compréhension est que clip.start() est exécuté dans un fil séparé derrière la scène par l'API Javasound.

Quelqu'un peut-il suggérer pourquoi cela pourrait se produire? Est-ce peut-être un problème de synchronisation?

EDIT: Par 'hang', je veux dire que certaines notes sont bloquées, malgré le fait que la sortie du journal signale que la méthode 'stop' correspondante a été appelée.

EDIT2: Il semble que la suspension se produit d'abord lorsqu'une note donnée est jouée pour la deuxième fois. Cela arrive même si la séquence MIDI est monophonique, c'est-à-dire que la note précédente s'est arrêtée.

+0

Est-ce que "se bloquer" signifie que certains clips continuent à jouer? Pouvez-vous prouver (par exemple, log) que votre code a effectivement essayé d'arrêter ce clip? –

+0

@CL Clarifié ci-dessus. – NietzscheanAI

+0

Eh bien on ne va pas jouer au jeu de devinettes juste poster tout votre code ce que vous faites dans chaque étape est inconnu - en théorie tout fonctionne – gpasch

Répondre

1

Votre méthode de chargement du clip pour chaque jeu va être une source considérable de latence variable. Chaque fois que vous appelez ceci, le fichier est lu à nouveau et ne commencera pas à jouer tant que le chargement du fichier ne sera pas terminé.

Je recommande de pré-charger tous les clips et de les conserver en mémoire. Lorsque la note est activée, définissez le curseur de clip sur zéro, puis jouez:

clip[mapIndex].setFramePosition(0); 
clip[mapIndex].start(); 

Ces clips doivent déjà être ouverts. Je les mets dans un tableau et en utilisant "mapIndex" comme un moyen plausible de sélectionner le clip correct qui pourrait fonctionner avec le mappage que vous avez déjà mis en place.

Vous n'aurez probablement pas besoin d '"arrêter" ou de "fermer" les clips tant que la séquence n'est pas terminée, à moins que les clips soient longs et conçus pour être arrêtés en cours ou joués comme boucles.

Cela devrait améliorer considérablement les choses. Je ne peux pas dire si ça va tout réparer.Le CPU fait probablement du multiplexage de threads, et il est plausible qu'à l'occasion, dans votre code actuel, le clip.close soit appelé sur un thread avant que le clip ait fini de se charger sur l'autre.