Запуская события в разрешение микросекунды для секвенсера midi

Существует ли способ запустить события в C# в разрешении нескольких микросекунд?

Я создаю секвенсер MIDI, и он требует, чтобы событие было запущено каждая галочка MIDI, которая будет затем играть любое примечание, зарегистрированное в то время.

В 120 ударах в минуту и в разрешении 120 ppqn (импульсы на удар/четвертную ноту), то событие должно запустить каждые 4,16666 миллисекунды. Современные секвенсеры имеют более высокие разрешения такой как 768ppqn, который потребовал бы что событие запускаться каждую 651 микросекунду.

Лучшее разрешение для коротко синхронизированных мероприятий, которые я учредил, имеет 1 миллисекунду. Как я могу пойти кроме того?

Эта проблема, должно быть, была уже решена любым секвенсером MIDI C# или плеером файла MIDI. Возможно, я просто не рассмотрение проблемы через прямой угол.

Спасибо за помощь.

12
задан Gustavo Mori 3 June 2011 в 18:34
поделиться

4 ответа

Большинство миди-секвенсоров / миди-плееров либо преобразуют большие блоки времени в форму волны (для воспроизведения через динамики компьютера), либо принимают большой блок инструкций MIDI (для внешнего устройства, подключенного к порту MIDI. ). В любом случае блок данных копируется на звуковую карту, и звуковая карта заботится о точном времени.

Возможно, вы захотите взглянуть на API управления мультимедиа.

См. этот пост на дискуссионном форуме Microsoft

6
ответ дан 2 December 2019 в 22:21
поделиться

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

Итак, MIDI-события помещаются в отсортированную очередь, вы просматриваете первое и устанавливаете таймер на срабатывание как можно ближе к этому времени.Когда срабатывает таймер, потребляйте все события из очереди, которые истекли, пока вы не встретите будущее событие. Рассчитайте время до этого события. Перенести таймер.

Конечно, если вы выводите на свою звуковую карту, подход принципиально другой, и вы должны подсчитывать семплы для всех ваших таймингов.

3
ответ дан 2 December 2019 в 22:21
поделиться

В .NET невозможно добиться точного срабатывания событий на микросекундных интервалах.

На самом деле, поскольку Windows сама по себе не является ОС реального времени, выполнение чего-либо со 100% точностью до определенных микросекунд в программах пользовательского режима практически невозможно.

Подробнее о том, почему это так сложно, читайте в статье журнала MSDN: Implement a Continuously Updating, High-Resolution Time Provider for Windows. Хотя в статье говорится о Windows NT, она в целом применима и к более поздним версиям Windows.

Заключение этой статьи подводит итог:

Если вы теперь думаете, что можете получить системное время с почти произвольной точностью, просто небольшое предупреждение: не забывайте о вытеснении многозадачной системы, такой как Windows NT. В лучшем случае, отметка времени, которую вы получите, будет отклонена только на время, необходимое для считывания счетчика производительности и преобразования этого показания в абсолютное время. В худших случаях, прошедшее время может легко может быть порядка десятков миллисекунд.

Хотя это может что вы прошли через все это напрасно, будьте уверены, что вы это не так. Даже выполнение вызова Win32 API GetSystemTimeAsFileTime (или gettimeofday в Unix) подчиняется тем же условиям, так что вы на самом деле делаете не хуже. В большинстве случаев вы получите хорошие результаты. Просто не выполняйте ничего, требующего в реальном времени предсказуемости на основе временных штампов в Windows NT.

1
ответ дан 2 December 2019 в 22:21
поделиться

вместо таймера

используйте секундомер

пример, для 10x 1 секунды

    static void Main(string[] args)
    {
        Stopwatch masterSW;
        Stopwatch sw=null;
        int count;

        sw = Stopwatch.StartNew();
        sw.Reset();

        for (int i = 0; i < 10; i++)
        {
            count = 0;
            masterSW = Stopwatch.StartNew();
            while (count!=1536) //1537*651 microsecond is about a second (1.0005870 second)
            {
                if (!sw.IsRunning)
                    sw.Start();

                if (sw.Elapsed.Ticks >= 6510)
                {
                    count++;
                    sw.Reset();
                }
            }

            Debug.WriteLine("Ticks: " + masterSW.Elapsed.Ticks.ToString());
        }
    }

выведет:

Тики: 10005392 (что составляет 1.0005392 секунды)
Тики: 10004792
Тики: 10004376
Тики: 10005408
Клещи: 10004398
Клещи: 10004426
Клещи: 10004268
Клещи: 10004427
Клещи: 10005161
Клещи: 10004306

что вроде как нормально

0
ответ дан 2 December 2019 в 22:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: