Лучшая практика для asyn c воспроизводить отдельные MIDI-сообщения? - PullRequest
1 голос
/ 28 мая 2020

Я разобрал MIDI-файл на массив нот (тональность, скорость, время, а также темп MIDI-файла и его события изменения). Мне нужно воспроизвести их асинхронно из приложения GUI (LCL) (я не могу использовать MCISendString, потому что мне нужно обрабатывать эти сообщения). Дело в том, что в MIDI обычно тысячи нот. Как вы думаете, как лучше всего их воспроизвести?

У меня есть несколько идей, но они медленные и непрактичные:

  • Позвоните группе BeginThread s одновременно с функцией, которая ожидает (Sleep или Delay) в течение указанного времени и воспроизводит заметку (есть ограничение на потоки, и это действительно нестабильно).
  • Сортировка меток времени и затем прогоняя их через один поток, который будет засыпать / задерживать currentNoteTime-previousNoteTime и воспроизводить ноту. Может быть медленным, особенно при попытке все это отсортировать.
  • Напишите другое приложение, которое будет фоновым процессом, и выполните эту работу (непрофессиональный боджинг).

Я работаю с Lazarus (Object Pascal), но при необходимости я могу использовать и код Delphi. Спасибо за ваше время.

1 Ответ

3 голосов
/ 28 мая 2020

Все подходы к потоковой передаче (спящий режим, задержка, и т. Д. c) завершатся ошибкой на Windows, так как вы не получите точность выше 16 мс (в лучшем случае), что приведет к неправильному воспроизведению ваших данных с большой задержкой . Это известная проблема, вы можете найти ее в Интернете.

Я являюсь автором библиотеки DryWetMIDI C# с функцией воспроизведения. Мой подход:

  1. Сортировка всех событий по времени и установка указателя на начало MIDI-данных
  2. Запуск высокоточного таймера с использованием Windows Мультимедийных таймеров API который будет тикать каждые 1 мс
  3. На каждом тике посмотрите, какие события должны быть воспроизведены в текущее время, и отправьте эти события на устройство вывода
  4. Перемещение указателя вперед по воспроизведенным событиям

Но учтите, что этот подход работает только для Windows. Для других систем вам необходимо использовать API-интерфейс c, специфичный для ОС, для запуска высокоточных таймеров.

...