JFugue 5.0.9 MusicReceiver неправильно воспроизводит миди-последовательность - PullRequest
0 голосов
/ 29 сентября 2019

Я уже давно играюсь с JFugue 5.0.9. Пока я использую метод Player.play (Pattern), кажется, что все работает нормально.

Но как только я использую Sequence, попробуйте отправить его на внешнее миди-устройствовремя музыки совершенно неправильное и ненадежное.

Я работал с этим миди-устройством через обычное программное обеспечение для секвенирования без каких-либо проблем, но, похоже, он не работает, когда я использую библиотеку JFugue.

Даже что-то простое, как показано на рисунке ниже, не работает правильно. Первые две ноты почти играются вместе (между ними есть небольшая задержка), а последняя нота вообще не воспроизводится.

    private final Predicate<MidiDevice.Info> isGrandPiano() {
        return deviceInfo -> 
                deviceInfo.getName().toLowerCase().contains("portable grand") && 
                deviceInfo.getDescription().toLowerCase().contains("external midi");
    }



    public void playSongOnDevice() {

            Info deviceInfo = Arrays.stream(MidiSystem.getMidiDeviceInfo())
            .filter(isGrandPiano())
            .findFirst()
            .orElse(null);

            try {
                MusicReceiver receiver = new MusicReceiver(MidiSystem.getMidiDevice(deviceInfo));

                receiver.sendSequence(player.getSequence(new Pattern("V0 T60 Dq Eq Fq Gq Dq Eq Fq Gq Dq Eq Fq Gq")));
            } catch (MidiUnavailableException e) {
                e.printStackTrace();
                throw new IllegalArgumentException(e);
            }
        }

Я не вижу, что еще я мог бы сделать, чтобы исправить это,Это даже идет более неправильно, когда я устанавливаю метроном в фоновом режиме с V9. Поэтому я подумал о том, чтобы сделать это как можно более простым.

Хорошая новость заключается в том, что внешнее миди-устройство реагирует (Yamaha DGX-660), плохая новость в том, что он вообще не учитывает времяи, кажется, иногда пропускает заметки. Я играл в тьюринг вкл / выкл местного времени или внешней синхронизации, но никаких изменений в поведении. Я обновил до последней и самой лучшей версии Java 8 и yamaha , но ничего не помогает.

Что мне здесь не хватает? Кстати, также используя Windows 10 .

С уважением,

РЕДАКТИРОВАТЬ: Одно дополнение к этому. Я также тестировал с той же самой последовательностью для игрока, так как она также принимает последовательность. Когда я передаю ту же самую последовательность в Player.play, это работает нормально.

Разница в том, что для receive.sendSequence вы передаете некоторый метод, подобный этому извлечению из org.jfugue.midi.MidiToolsкласс:

    public static void sendSortedMidiMessagesToReceiver(Map<Long, List<MidiMessage>> sortedMidiMessages, float sequenceDivisionType, int sequenceResolution, Receiver receiver) {
            int bpm = MidiDefaults.DEFAULT_TEMPO_BEATS_PER_MINUTE;
            int ticksPerSecond;
            long prevTick = 0L;
            long msTime = 0L; 
            long largestTick = getLargestKey(sortedMidiMessages);

            if (sequenceDivisionType == Sequence.PPQ) {
                ticksPerSecond = (int)(sequenceResolution * bpm / 60.0D);
            } else {
                double framesPerSecond = 
                        (sequenceDivisionType == Sequence.SMPTE_24 ? 24
                          : (sequenceDivisionType == Sequence.SMPTE_25 ? 25
                            : (sequenceDivisionType == Sequence.SMPTE_30 ? 30
                              : (sequenceDivisionType == Sequence.SMPTE_30DROP ? 29.97 : 24))));
                ticksPerSecond = (int)(sequenceResolution * framesPerSecond);
            }

            for (long tick = 0; tick <= largestTick; tick++) {
                if (sortedMidiMessages.containsKey(tick)) {
                    msTime = calculateTime(tick - prevTick, ticksPerSecond);
                    List<MidiMessage> messages = sortedMidiMessages.get(tick);
                    for (MidiMessage message : messages) {
                        if ((message instanceof MetaMessage) && (sequenceDivisionType == Sequence.PPQ) && (((MetaMessage)message).getType() == MidiDefaults.SET_TEMPO_MESSAGE_TYPE)) {
                            ticksPerSecond = calculateTicksPerSecondFromMidiSetTempoMessageData(((MetaMessage)message).getData(), sequenceResolution);
                            msTime = calculateTime(tick - prevTick, ticksPerSecond);
                        } else {
                            receiver.send(message, msTime);
                        }
                    }
                    try {
                        Thread.sleep(msTime); 
                    } catch (Exception ex) {
                        throw new RuntimeException(ex);
                    }
                    prevTick = tick;
                }
            }
        }

Я специально добавил точку останова на строку

    ...
    } else {
                            receiver.send(message, msTime);
    }
    ...

, потому что Thread.sleep (msTime) привлек мое внимание. Я видел эти результаты в последовательности, упомянутой выше:

<code><pre>
msTime  message
0       [-112, 62, 64]
2000    [-128, 62, 64]
2000    [-112, 64, 64]
2000    [-128, 64, 64]
2000    [-112, 65, 64]
2000    [-128, 65, 64]
2000    [-112, 67, 64]
2000    [-128, 67, 64]
2000    [-112, 62, 64]
2000    [-128, 62, 64]
2000    [-112, 64, 64]
2000    [-128, 64, 64]
2000    [-112, 65, 64]
2000    [-128, 65, 64]
2000    [-112, 67, 64]
2000    [-128, 67, 64]
2000    [-112, 62, 64]
2000    [-128, 62, 64]
2000    [-112, 64, 64]
2000    [-128, 64, 64]
2000    [-112, 65, 64]
2000    [-128, 65, 64]
2000    [-112, 67, 64]
2000    [-128, 67, 64]
2000    [-1, 47, 0]

Я не эксперт по миди, но я нахожу это немного странным в первой ноте, у меня msTime в0, что на 2000 для всех остальных. Это может объяснить, почему первые заметки склеены. Я не уверен ...

EDIT2: Использование MidiMapper (я использовал Coolsoft MidiMapper) имеет те же результаты для Microsoft Wavetable Synth. У него точно такая же проблема, поэтому я не думаю, что это связано с моим Piano, так как это внутреннее устройство Windows Midi. Но, как объяснено, это вызвано методом receive.sendSequence. У кого-нибудь есть такие же проблемы с этой версией JFugue 5.0.9?

...