JFugue RealtimePlayer无法同时播放多个乐器

时间:2017-02-14 17:29:04

标签: java synchronization real-time jfugue

我遇到了JFugue 5.0.7的问题:我编写了一个无限播放音乐的实时应用程序,但是jfugue库提供的RealtimePlayer将乐器相互混合。

我有以下代码

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);
            }
        }
    }
}
问题是,当弹奏两种乐器(吉他和钢琴)混合时,两者不能同时播放。相反,玩家随意地在两种乐器之间进行切换,这样一次只能听到一种演奏这两种乐器的乐器。

1 个答案:

答案 0 :(得分:1)

通过在JFugue 5.0.8中引入if-else解决了这个问题。 Atom包含一个原子单位的语音,乐器和音符信息,因此乐器不会与他们用来演奏的音符断开连接。

我在这里更全面地描述了此更新:https://medium.com/@dmkoelle/whats-new-in-jfugue-5-0-8-7479abca3be4