Информация
- В рейтинге
- 1 627-й
- Откуда
- Санкт-Петербург, Санкт-Петербург и область, Россия
- Дата рождения
- Зарегистрирован
- Активность
Специализация
Десктоп разработчик, Инженер по автоматизации тестирования
Ведущий
C#
.NET
Git
Selenium
Автоматизация тестирования
Можете, пожалуйста, каким-нибудь псевдокодом показать вашу идею?
Именно, для такой задачи генерация аудио в буфере, разумеется, идеальный вариант. Но имхо с таймером намного проще, благо варианты, как я и писал, есть.
Это вопрос перфекционизма :) Вот, кстати, данные очень разнятся по тому лагу, который может заметить человек. Наверное, тренированные профессиональные барабанщики, например, чувствуют лаг и менее 20 мс. И если вы делаете свой продукт не только для себя, стоит иметь это в виду.
Если это антипаттерн, есть какие-то подводные камни, приведите их, пожалуйста. Кроме того, сомнительно, что VLC, Windows Media Player, плеер Chrome и много других программ используют антипаттерн.
Таймер = дёрганье колбэков из потока. И да, потоку нужно в общем случае ставить повышенный приоритет. Если вы про какие-то другие колбэки, то объясните, пожалуйста. Кроме того, воспроизведение аудио != обработка воспроизводимого аудио. Во втором варианте да, напрашивается слушать колбэки от системы воспроизведения, устрйоства и т.д. Но реализацию самого воспроизведения не представляю без таймеров. Я могу заблуждаться, буду рад, если расскажите.
Мне всё-таки кажется, вы про обработку данных, а не воспроизведение. В воспроизведении я не могу трактовать "ровный плейбэк" как-то иначе, нежели "плейбек с низкими задержками". Задержками в воспроизведении конкретных событий, у которых до воспроизведения известны чёткие времена, когда они должны быть проиграны.
Но чем не устраивает вполне себе документированный мультимедийный таймер? За статью спасибо, но она опять же про обработку, а не воспроизведение.
Расскажите, пожалуйста, как вам видится идеальная реализация плейбека. Я только за научиться чему-то новому и полезному. И хотя за всё время существования API в моей библиотеке никогда не было нареканий на механизм воспроизведения (а используют его часто, даже не одну игру с ним сделали типа Guitar Hero), разумеется, всегда есть куда совершенствоваться.
Если я вас правильно понял, то, если на обработке какого-либо события будет задержка, поплывут все последующие события. Таймер и точные метки времени на каждом событии исключают такую ситуацию. Даже если будет лаг, он не повлияет на последующие события.
Обязательно будет статья по macOS, ибо API воспроизведения в библиотеке реализован для Windows и macOS (через нативную прослойку под каждую платформу).
Понял, спасибо. Я всё же склонен думать и о тех, у кого компьютеры слабые, а в системе помимо приложения с использованием моей библиотеки работают и другие программы, разработчики которых, вероятно, тоже решили не париться о загрузке целого ядра. У меня, например, крайне плохая древняя батарея, которая разряжается ультрабыстро, особенно с такими вот энергопотреблениями, которое даёт бесконечный цикл. Мне очень не хочется быть тем звеном в программной цепочке пользователя, которое будет создавать проблемы.
Мультимедийный таймер для меня вляется оптимальным решением. Я верю, что вы столкнулись с мистикой по невыполнению коллбэка. И очень хочется понять, когда такое происходит. Быть может, покопаю на досуге.
Мой компьютер с вами не согласен:
Это я на другом компьютере проверял, там 8 логических ядер, поэтому процент ниже (на том, результаты с которого в статье 4 логических ядра).
В этом как раз и суть проверки на разных машинах. Я мог бы проверить Timer-queue timer на виртуалке, увидеть отличные результаты и объявить в статье, что вот она долгожданная замена мультимедийным таймерам. Но это была бы ложь. Сильно влияет окружение, версия ОС, ещё что-то, наверное.
Не так с
Thread.Yieldто, что загрузка процессора очень высокая, меня такое не устраивает. Тоже не знаю, что у меня не так, но это факт, код я привёл. Точность, конечно, высокая. Но этого мало, чтобы отдавать такое решение пользователям. Я видел в других проектах (уж не вспомню, в каких) баг-репорты в GitHub, когда разработчики вставляли цикл в качестве таймера. В реальном мире люди быстро столкнутся с проблемами, обнаружив высокое использование ЦП и разрядку батареи.Но как можно считать оптимальным решение, которое загружает так сильно CPU?
Касательно
Sleepна 5 мс.Sleepточно так же ориентируется на системный таймер.Sleep(5)будет по факту ждать 15.6 мс. Либо же я не понял, что имеется в виду.Взял ваши результаты, они классные. Поделитесь, пожалуйста, кодом класса
Timer, на котором они получены, я проверю у себя и на виртуалках.Интересная идея, но:
MIDI-файл состоит не из нот, а событий (в том числе и событий нажатия/отпускания нот, конечно). Типичный MIDI-файл содержит несколько десятков тысяч событий, но и с несколькими сотнями не такая уж редкость.
Существование большого числа таймеров выглядит плохой затеей. Таймер не должен блокировать текущий поток, а потому каждый таймер должен сидеть в отдельном. Итого с тонной таймеров имеет тонну потоков. А встроенные таймеры .NET работают именно на потоках из пула потоков. Я вообще думаю, что дефолтного размера пула не хватит, чтобы обслужить MIDI-файл, и возникнут серьёзные задержки.
По графикам видно, что хоть на 100 мс среднее значение зачастую тоже 100, но отклонения могут быть большими (например, 121 мс). В целом я вижу такую корреляцию: выше интервал – выше отклонения. И вот данные разнятся, но я встречал информацию, что отклонения в 15 мс уже могут быть заметны на слух. У меня же стояла задача сделать воспроизведение максимально гладким и точным.
Опыт других аудио- и видеоплееров (согласно отчётам Powercfg, которые я приводил) также показывает, что их разработчики остановились на варианте с одним таймером высокого разрешения. Это не доказательство правоты подхода, конечно, просто косвенный признак.
Во-первых, @mentin выше дал выдержку из документации.
Во-вторых, код
не даёт никаких улучшений по загрузке процессора на моей машине, всё так же больше одного ядра занято. То бишь, таймер ведёт себя по-разному на разном окружении, что не соответствует цели статьи – найти таймер, стабильно тикающий с заданным интервалом в разных конфигурациях системы.
В-третьих, мультимедийные таймеры, которые являются лучшим выбором, работают на специальном высокоприоритетном системном потоке, что даёт меньше шансов на его прерывания и обеспечивает бо́льшую точность.
Здравствуйте. А вы не пробовали замерить реальные дельты между срабатываниями таймера? Я не уверен, что информация от clockres соответствует действительному положению дел. Но не исключено, что ваш метод работает. Было бы интересно попробовать, как .NET таймеры ведут себя после вызова
NtSetTimerResolution.Здравствуйте. Уточните, пожалуйста, какой код вы используете? Если не сложно, прям код таймера для проверки. Я взял тот код, что привёл в статье, добавил
Thread.Yield2-мя способами. Вот так:и вот так:
На локальной машине обоими способами загрузка процессора ровно такая же. Результаты пока в процессе.
Спасибо :-)
Здравствуйте. Но ведь в статье есть раздел про System.Timers.Timer, где приведён график для интервала 1 мс. Вы можете указать в конструкторе 1, но по факту таймер будет тикать в среднем каждые 15.6 мс. Я также привёл выдержку из документации по классу, в которой явно говорится, почему так происходит. При указании интервала меньше интервала системного таймера (а он 15.6), таймер будет срабатывать с интервалом системного таймера.
Видимо, я что-то упустил. Люди уволились, и Apple даёт им 30 дней на поиск работы? А дальше Apple сделает так, что они никуда не устроятся? :-)
Совершенно верно, не понимают. Но, увы, и не поймут, сколь много подобных эссе и мотивирующих речей ни появится. Моё мнение, что человек приходит к Делу в жизни либо через самостоятельные умозаключения, либо через какое-то потрясение (позитивное или негативное, не суть) в жизни, что подталкивает что-то поменять. Зачастую много работают (по своей воле) те, кому очень интересно то, чем они занимаются. К сожалению, многие люди не знают, чем им хочется заниматься, но при этом ничего и не пробуют.
Можно безопасно получать segmentation fault в большом количестве :) А если серьёзно, тоже несколько напрягла эта фраза. Возможностей ступить в лужу с C невероятно много, я всё же считаю его достаточно низкоуровневым.
Однако сам язык полезен, он даёт базу программистам, указатели, работа с памятью. Становится понятно, как устроены вещи под капотом более высокоуровневых языков.
Я для себя, например, нашёл язык полезным для написания платформозависимых API для своей .NET библиотеки. Ошибок с памятью получил уже достаточно :)
Кроме последних патронов везде есть пуля в разрезе. Там патроны рассечены вместе с пулей.