Подтвердить что ты не робот

События стрельбы с разрешением микросекунды для MIDI-секвенсора

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

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

При 120 ударах в минуту и ​​при разрешении 120 ppqn (импульсы за такт/четверть ноты) это событие должно срабатывать каждые 4.16666 миллисекунды. Современные секвенсоры имеют более высокие разрешения, такие как 768ppqn, которые требуют, чтобы это событие было запущено каждые 651 микросекунды.

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

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

Благодарим вас за помощь.

4b9b3361

Ответ 1

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

Возможно, вы захотите ознакомиться с интерфейсами API мультимедиа.

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

Ответ 2

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

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

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

Ответ 3

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

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

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

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

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

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

Ответ 4

вместо использования таймера

использовать stopwatch

пример, для 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

которые кажутся ок