2017-02-14 7 views
1

Ich habe ein Problem mit JFugue 5.0.7: Ich programmiere eine Echtzeit-Anwendung, die Musik unendlich spielt, aber der RealtimePlayer von der Jfugue-Bibliothek mischt Instrumente miteinander.JFugue RealtimePlayer kann nicht mehrere Instrumente gleichzeitig spielen

Ich habe den folgenden Code

public class HelloJFugue { 

    public static int BPM = 150; 
    public static int SIGNATURE = 3; 
    public static boolean RANDOM = false; 

    public static void main(String[] args) throws MidiUnavailableException { 
     RealtimePlayer player = new RealtimePlayer(); 
     BlockingQueue<Pattern> queue = new SynchronousQueue<>(); 

     List<PatternProducer> pProducers = createPatternProducers(); 

     Thread pConsumer = new Thread(new PatternConsumer(player, queue)); 
     Thread pProducer = new Thread(new PatternMediator(queue, pProducers)); 

     pConsumer.start(); 
     pProducer.start(); 
    } 

    private static List<PatternProducer> createPatternProducers() { 
     Random rand = new Random(); 

     PatternProducer rightHand = new PatternProducer() { 
      int counter = 0; 
      String[] patterns = { 
       "Rq Rq E6i D#6i", 
       "E6i D#6i E6i B5i D6i C6i", 
       "A5q Ri C5i E5i A5i", 
       "B5q Ri E5i G#5i B5i", 
       "C6q Ri E5i E6i D#6i", 
       "E6i D#6i E6i B5i D6i C6i", 
       "A5q Ri C5i E5i A5i", 
       "B5q Ri E5i C6i B5i", 
       "A5q Ri E5i E6i D#6i" 
      }; 

      @Override 
      public Pattern getPattern() { 
       Pattern p = new Pattern(patterns[RANDOM ? rand.nextInt(patterns.length - 1) + 1 : counter]) 
         .setVoice(0) 
         .setInstrument("Piano"); 
       counter++; 
       if (counter >= patterns.length) { 
        counter = 1; 
       } 
       return p; 
      } 
     }; 

     PatternProducer leftHand = new PatternProducer() { 
      int counter = 0; 
      String[] patterns = { 
       "Rq Rq Rq", 
       "Rq Rq Rq", 
       "A3i E4i A4i Ri Rq", 
       "E3i E4i G#4i Ri Rq", 
       "A3i E4i A4i Ri Rq", 
       "Rq Rq Rq", 
       "A3i E4i A4i Ri Rq", 
       "E3i E4i G#4i Ri Rq", 
       "A3i E4i A4i Ri Rq" 
      }; 

      @Override 
      public Pattern getPattern() { 
       Pattern p = new Pattern(patterns[RANDOM ? rand.nextInt(patterns.length - 1) + 1 : counter]) 
         .setVoice(1) 
         .setInstrument("Guitar"); 
       counter++; 
       if (counter >= patterns.length) { 
        counter = 1; 
       } 
       return p; 
      } 
     }; 

     return new ArrayList<PatternProducer>() { 
      { 
       add(rightHand); 
       add(leftHand); 
      } 
     }; 
    } 
} 

public class PatternMediator implements Runnable { 

    private BlockingQueue<Pattern> queue; 
    private List<PatternProducer> producers; 

    public PatternMediator(BlockingQueue<Pattern> queue, List<PatternProducer> producers) { 
     this.queue = queue; 
     this.producers = producers; 
    } 

    private void fillQueue() throws InterruptedException { 
     Pattern p = new Pattern(); 
     for (PatternProducer producer : producers) { 
      p.add(producer.getPattern().setTempo(HelloJFugue.BPM)); 
     } 
     this.queue.put(p); 
    } 

    @Override 
    public void run() { 
     while (true) { 
      try { 
       fillQueue(); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(PatternMediator.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
    } 
} 

public class PatternConsumer implements Runnable { 

    private RealtimePlayer player; 
    private BlockingQueue<Pattern> queue; 

    public PatternConsumer(RealtimePlayer player, BlockingQueue<Pattern> queue) { 
     this.player = player; 
     this.queue = queue; 
    } 

    private void playFromQueue() throws InterruptedException { 
     player.play(queue.take()); 
    } 

    @Override 
    public void run() { 
     while (true) { 
      try { 
       playFromQueue(); 
       Thread.sleep(HelloJFugue.SIGNATURE * 60000/HelloJFugue.BPM); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(PatternConsumer.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
    } 
} 

Das Problem ist, dass, wenn das Spielen der beiden Instrumente (Gitarre und Klavier) gemischt werden, und die beiden können nicht simultan gespielt werden. Stattdessen wechselt der Spieler willkürlich zwischen den zwei Instrumenten, so dass nur ein Instrument, das beide Muster spielt, gleichzeitig gehört werden kann.

+0

Ich weiß, dass 'sleep' eine schreckliche Art und Weise zu synchronisieren. Ich probiere nur die Fähigkeiten von JFugue aus. –

+1

Ich sehe, was hier passiert: Stimmen und Instrumente werden von deinen linken und rechten Mustern vermischt. Was JFugue braucht, ist eine Möglichkeit, eine Voice + Layer + Instrument + Note-Tupel als ein einzelnes atomares Element zu erkennen. Angetrieben von Ihrem Beispiel arbeite ich an einer neuen Klasse, "Atom", und einer pattern.atomize() Methode (sowie einem neuen AtomSubparser). Mein Ziel ist, dass Sie den gleichen Code verwenden können, wie Sie haben, mit dem Zusatz eines Aufrufs pattern.atomize(). Ich werde Sie auf dem Laufenden halten und diese Frage beantworten, wenn es funktioniert. –

+0

Danke David Koelle, das ist großartig. –

Antwort

1

Dies wurde mit der Einführung einer Atom in JFugue 5.0.8 gelöst. Ein Atom enthält Stimmen-, Instrumenten- und Noteninformationen in einer Atomeinheit, damit die Instrumente nicht von den Noten getrennt werden, mit denen sie gespielt werden.

beschreibe ich dieses Update ausführlicher hier: https://medium.com/@dmkoelle/whats-new-in-jfugue-5-0-8-7479abca3be4

Verwandte Themen