Ошибка записи экрана на Айфоне. Как исправить
Удобная функция записи экрана появилась еще в iOS 11: с тех пор пользователи могут без проблем записать происходящее на дисплее iPhone, чтобы, например, быстрее объяснить кому-либо какие настройки включить или просто поделиться контентом. При желании, видео с трансляцией можно всегда превратить в GIF-анимацию. Но вот незадача: иногда случается так, что запись экрана не работает: появляется надпись «Не удалось сохранить запись экрана» — ошибка редкая, но неприятная. Разберемся, что делать, если запись экрана на Айфоне не работает и как это быстро исправить.
Разбираемся, почему возникает ошибка при записи экрана на Айфоне
Не включается запись экрана на Айфоне
Появляется ошибка во время записи экрана на iPhone. Что делать?
Крайне редко во время записи экрана в iOS появляется сообщение «Не удалось сохранить запись экрана», а видео, само собой, не сохраняется в памяти телефона. Обычно пользователи видят на экране разные варианты ошибки.
- Операция не могла быть завершена.
- Не удалось сохранить запись экрана.
- Запись экрана не удалось сохранить из-за 5823.
- Сбой из-за невозможности обработать буфер первого семпла.
Чаще всего проблема возникает, когда вы хотите записать контент, который защищен авторским правом — например, в стриминговом сервисе, когда хочется записать эпизод из сериала или шоу. В этом случае вы увидите ошибку 5823 в сообщении.
Иногда сообщение об ошибке не появляется, а на записи отображается лишь черный экран или картинка без звука. Если все дело в защищенном контенте, то проблемы с телефоном нет — достаточно лишь попробовать сделать запись экрана в другом приложении, например, в YouTube или на сайте в Safari.
Почему запись экрана без звука на Айфоне
Вы можете сделать запись экрана со звуком, но эта функция работает не всегда. Почему так? Для начала стоит кое-что прояснить. Допустим, вы записываете экран из Apple Music, Яндекс.Музыки, но звука нет.
Включили запись экрана, а звука нет?
- Возможно, все дело снова в защите контента: звук не будет записываться из-за авторских прав.
- Попробуйте прибавить громкость на iPhone.
- iPhone подключен по Bluetooth к колонке или наушникам: ошибка случается редко, так как источником звука все равно является сам смартфон, но если ничего не выходит, можете попробовать разорвать соединение и записать экран.
- iPhone подключен по локальной сети к Яндекс.Станции: если управляете воспроизведением с телефона без подключения по Bluetooth, то экран на Айфоне записываться не будет.
Но есть запасной вариант: удерживайте кнопку «Запись экрана» в Пункте управления, затем нажмите внизу на микрофон — тогда запись экрана будет сопровождаться звуком с динамиком и звук запишется. Также вы сможете комментировать происходящее на экране своим голосом — удобно, не правда ли?
Не записывается экран на Айфоне
Если запись экрана на Айфоне идет, но запись не сохраняется из-за внезапно появившейся ошибки, вы можете исправить это вручную. Есть несколько способов.
Если контент защищен, то записать его не удастся
- Перезагрузите iPhone. Еще одна проблема, которая исправляется перезапуском из-за возникшей ошибки в работе iOS.
- Проверьте свободное место в iPhone: запись экрана не сохраняется из-за нехватки места в хранилище.
- Попробуйте перезапустить приложение и начать запись экрана заново.
- Обратите внимание на то, что запись экрана может нестабильно работать в бета-версиях iOS: попробуйте откатиться на стабильную версию, чтобы неполадок не было.
А еще ограничить скринкаст можно через Экранное время. В настройках конфиденциальности нужно отключить специальный параметр.
- Зайдите в Настройки, выберите Экранное время.
- Нажмите «Контент и конфиденциальность» и выберите «Ограничения контента».
- Введите код-пароль для Экранного времени.
- В списке найдите «Запись экрана», нажмите и выберите «Да».
Вообще, Экранное время лучше отключить, чтобы снизить расход батареи и случайно не ограничить работу приложений. О других непонятных функциях в iOS 15 читайте в нашей статье.
Из «Записи экрана» можно включать трансляцию в соцсетях. Удобно!
Кстати, при долгом нажатии на кнопку записи экрана появляется список из нескольких приложений. В моем случае это Фото, Gmail, Telegram и VK. Что он значит? Если выбрать любое из них, то пойдет обратный отсчет, после чего запись экрана оборвется. Дело в том, что так реализован показ экрана iPhone в трансляциях: если вы ведете прямой эфир в соцсети или участвуете во встрече в Google Hangouts, то при необходимости можете включить демонстрацию экрана iPhone именно из этого пункта.
Apple переработала дизайн видеоплеера в iOS 16: теперь он стал удобнее и проще. О том, как теперь смотреть видео в новой iOS, рассказали в нашей статье.
Пишем эмулятор Gameboy, часть 3
В предыдущей части данного цикла статей мы закончили работу над критически важными компонентами нашего эмулятора. Для полноты картины в данной статье мы рассмотрим звуковую систему DMG.
Пишем эмулятор Gameboy, часть 1
Пишем эмулятор Gameboy, часть 2
Пишем эмулятор Gameboy, часть 3
Прежде чем начать, вот ссылка на репозиторий Cookieboy, где можно найти его исходный код и последнюю сборку.
Оглавление
Звуковая система
- Sweep unit. Осуществляет изменение частоты звука с заданным периодом и шагом.
- Length counter. Контролирует длительность вывода звука.
- Envelope unit. Осуществляет изменение громкости звука с заданным периодом.
- Прямоугольная волна. Содержит все три компонента модуляции.
- Прямоугольная волна. Содержит компоненты контроля громкости и длительности.
- Волна произвольной формы. Содержит только компонент контроля длительности. Громкость устанавливается в одном из регистров вручную.
- Генератор шума. Содержит компоненты контроля громкости и длительности.
Третий канал позволяет воспроизводить сигнал произвольной формы из специальной области памяти в секции I/O ports – Wave Pattern RAM. Таким образом, можно воспроизводить цифровой звук произвольного содержания путем своевременного обновления указанной области памяти. Некоторые умудряются воспроизводить что-то похожее на речь.
Четвертый канал позволяет генерировать шум различного характера. Хорошо подходит для озвучивания различных спецэффектов.
Вот упрощенная схема формирования звука в DMG:
После прохождения всех компонентов модуляции звуковой сигнал попадает в микшер, который смешивает различные каналы и выводит в один из выходов. S01 – правое ухо. S02 – левое ухо. Операция смешивания сводится к простому сложению сигналов ото всех источников для конкретного выхода – NR51 указывает, куда и какие каналы должны быть выведены. Далее учитывается громкость для каждого из выходов – сигнал после смешивания умножается на значение громкости данного выхода в регистре NR50 плюс 1.
Не стоит пытаться полностью разобраться в этой схеме – по ходу дела все, что на ней нарисовано, будет рассмотрено подробнее.
NR50 и NR51 являются общими регистрами. Кроме них есть общий регистр NR52, который содержит флаг отключения всего звука, а так же биты, показывающие статус звуковых каналов. Изменять можно только флаг отключения звука. Биты статуса доступны только для чтения и постоянно обновляются.
- Все регистры обнуляются, кроме счетчиков Length counter. Это означает, что нужно обнулить только биты, относящиеся к Duty cycle (далее станет понятно, о чем я).
- Запрещается запись во все регистры, кроме NRX1. Причем, запись может осуществляться только в те биты, которые относятся к Length counter.
Все компоненты, формирующие звук, синхронизированы с тактовым генератором. Для генерации звуковых волн определенной частоты используется сам тактовый генератор. Для модулирующих компонентов выделен отдельный тактовый генератор Frame Sequencer, работающий на частоте 512 Гц. Он так же работает от основного тактового генератора, но позволяет генерировать низкочастотные отсчеты. Для Sweep Unit используется частота 128 Гц. Для Length Counter – 256 Гц. Для Envelope Unit — 64 Гц. Вот как выглядит процесс работы этого тактового генератора, где каждая строка означает один отсчет Frame Sequencer’а:
Length Counter | Envelope unit | Sweep unit |
отсчет | — | отсчет |
— | отсчет | — |
отсчет | — | — |
— | — | — |
отсчет | — | отсчет |
— | — | — |
отсчет | — | — |
— | — | — |
В таблице отмечено, какие отсчеты Frame Sequencer’а генерируют отсчет для компонентов модуляции. Получается, что он циклично проходит такую последовательность отсчетов, что дает нам 8 возможных состояний Frame Sequencer (пронумеруем их от 0 до 7). Здесь важно учитывать, с какой фазой происходят отсчеты для компонентов. Так же стоит учесть, что при запуске звука (флаг в регистре NR52) Frame Sequencer стартует с состояния 1. Очень важно при этом дать понять компонентам модуляции, что вы изменили состояние Frame Sequencer. Одно время я еле нашел эту ошибку, из-за которой не мог пройти один из тестовых ROM’ов.
Разобравшись с общим устройством, перейдем к рассмотрению каждого конкретного канала.
Звуковые каналы 1 и 2
Сначала рассмотрим каналы, генерирующие прямоугольные волны. Здесь не имеет смысла разделять 1 и 2 каналы. Рассмотрев канал 1, можно будет реализовать канал 2 простым урезанием функционала, поскольку они идентичны за исключением Sweep unit.
И так, что такое прямоугольная волна. Внизу на рисунке изображена как раз такая волна.
Не особенно важно, где находится временная ось. В моем эмуляторе используется волна, которая генерирует отрезки «есть сигнал» (1-2, 3-4, 5-6), «нет сигнала» (0-1, 2-3, 4-5). Можно было бы сделать по-другому и поместить временную ось посередине, но это лишь усложнит реализацию, а результат будет идентичным.
На этом рисунке скважность сигнала равна 2, поскольку отрезки с разной амплитудой имеют одинаковую длительность. DMG позволяет генерировать прямоугольные волны с различными значениями скважности, хотя в документации принято использовать величину обратную скважности – коэффициент заполнения (duty cycle). Он кстати и более нагляден, им и будем пользоваться. Выбор дается из 4 различных значений коэффициента заполнения – 0.125, 0.25, 0.5, 0.75. Коэффициент заполнения никак не влияет на частоту, а лишь на характер сигнала. На рисунке ниже показаны различия сигналов при различных коэффициентах заполнения и одинаковой частоте.
Предоставлено 4 значения, хотя, по сути, значений 3 – коэффициенты заполнения 0.25 и 0.75 дают разные на вид волны, но звучание у них идентичное. При воспроизведении звука значение имеет изменение амплитуды, которое имеет одинаковый характер при коэффициентах заполнения 0.25 и 0.75.
Значение коэффициента заполнения содержится в регистре NRX1 в двух верхних битах.
Естественно нам надо знать, какой частоты должен генерироваться сигнал. Для этого используются регистры NRX3 и NRX4. Частота указывается числом длиной 11 бит – младшие 8 бит содержатся в регистре NRX3, старшие 3 бита в регистре NRX4. Таким образом, частота может лежать в пределах от 0 до 2047, но эти значения не относятся к реальной частоте звука. Для перевода этих значений в реальную частоту необходимо воспользоваться следующей формулой:
F = 4194304 / (32 * (2048 – X)) Гц,
где X – частота из регистров NRX3 и NRX4, F – частота звука.
Таким образом, частота звука лежит в пределах от 64 Гц до 131 072 Гц. Не стоит беспокоиться о таких высоких частотах – мало того, что нам будет довольно сложно должным образом сгенерировать звук такой частоты (по теореме Котельникова частота дискретизации должна быть больше 262 144 Гц); так все усложняется тем, что наша техника не способна воспроизвести такое, а наши уши не способны услышать. Более реальный диапазон ограничивается 22 000 Гц – это примерно соответствует верхней границе динамического диапазона человеческого слуха и совсем не случайно и большинства акустических систем. А для таких частот нам достаточно привычной частоты дискретизации в 44 100 Гц.
Формула выше обычно дается в документации как данное, но неплохо бы понимать, почему вычисляется именно так. Посмотрим еще раз на схему работы звуковой системы, там есть компонент Wave generator. В нем содержится таймер, с помощью которого генерируется волна нужной частоты. Период этого таймера равен 4 * (2048 – X). Чтобы волна прошла полный период, таймер должен сделать 8 отсчетов, что и дает нам заветные 32 * (2048 – X) – это значение полного периода волны.
Упомянутый таймер при должной реализации позволит вам не беспокоиться о переводах частот. Если таймер в эмуляторе будет синхронизирован с процессором так же, как и все остальные компоненты,
то все будет работать само собой. Формула 4 * (2048 – X) дает период таймера в тактах.
За 8 отсчетов этого таймера звуковая волна пройдет полный период. Теперь вернемся к коэффициенту заполнения. Он диктует характер изменения волны в течение ее периода. В документации приводятся следующие значения (1 и 0 в правом столбце означает, соответственно, «есть сигнал» и «нет сигнала»):
Коэффициент заполнения | Форма одного периода сигнала |
0.125 | 00000001 |
0.25 | 10000001 |
0.5 | 10000111 |
0.75 | 01111110 |
Помимо частоты в регистре NRX4 хранятся и другие данные. Вот кстати его структура:
Биты | Назначение |
7 | Перезапуск канала |
6 | Бесконечное/конечное воспроизведение |
2-0 | Нижние 3 бита частоты |
Если бит 6 сброшен, то звук воспроизводится бесконечно. Если бит установлен, то в дело вступает Length Counter.
Бит 7 перезапуска именно это и делает. Если в него записывается 1, то канал перезапускается. Это может показаться странным для канала, который воспроизводит бесконечный периодический сигнал, но в действительности это имеет большее значение для компонентов модуляции. О них позже. Помимо этого, упомянутые выше формы сигналов позволяют генерировать правильный сигнал – при перезапуске канала период сигнала тоже стартует с самого начала согласно указанным формам.
Это все, что нужно знать о каналах 1 и 2 в общем. Далее в ход вступают компоненты модуляции. Несмотря на то, что каждый канал содержит свои компоненты модуляции, их принцип работы идентичен. Сейчас мы рассмотрим все компоненты модуляции (канал 1 их все содержит), чтобы больше уже не повторяться.
Sweep unit
Данный компонент контролирует частоту сигнала. Он работает в двух режимах – увеличение или уменьшение частоты. Поддерживаются различные периоды и размеры шага. Контролируется компонент посредством регистра NRX0. Вот его структура:
Биты | Назначение |
6-4 | Период: 000 – компонент выключен 001 – 1/128 с 010 – 2/128 с 011 – 3/128 с 100 – 4/128 с 101 – 5/128 с 110 – 6/128 с 111 – 7/128 с |
3 | Режим: 0 – увеличение частоты 1 – уменьшение частоты |
2-0 | Шаг |
Периоды указаны в миллисекундах, и их следовало бы перевести в такты для отсчета времени, но при должной реализации Frame Sequencer нам это не понадобится. Sweep unit работает на частоте 128 Гц, поэтому периоды не случайно вычисляются относительно 1/128 — это и позволяет забыть о ручном подсчете тактов. Так дело обстоит и с остальными компонентами – Frame Sequencer все считает, остальным ни о чем не надо «беспокоиться».
Теперь шаг. Объяснять его бессмысленно, проще привести формулу, по которой вычисляется следующее значение частоты при очередном отсчете:
F(t) = F(t – 1) ± F(t – 1) / 2 n ,
где F(t) – следующее значение частоты, F(t – 1) – текущее значение частоты, n – значение шага из регистра NRX0. Замечу, что нам нужно использовать не деление, а битовый сдвиг вправо на число шагов из регистра NRX0.
На рисунке ниже изображена работа Sweep unit при NRX0 = 0x61:
Изменение частоты происходит постоянно до тех пор, пока не будет достигнут один из пределов для значения частоты или кто-то не отключит Sweep unit. Если включен режим уменьшения частоты и очередная частота получилась отрицательной, то сохраняется предыдущее значение и вычисления прекращаются. Если включен режим увеличения частоты, и она перевалила за максимальное значение (2047), то канал останавливается, а в соответствующем бите статуса регистра NR52 записывается ноль, сигнализирующий о том, что канал остановлен.
На этом заканчиваются простые вещи и начинаются неочевидные детали. Sweep содержит несколько скрытых регистров, недоступных извне – флаг активности (internal enabled flag) и регистр-буфер для частоты (frequency shadow register). Так же он содержит счетчик для соблюдения установленного в регистре NRX0 периода.
- Частота канала (NRX3 и NRX4) копируется в регистр-буфер частоты.
- Счетчик сбрасывается. Для этого из регистра NRX0 нужно скопировать биты 6-4, т.е. в счетчике окажется число отсчетов на частоте 128 Гц. Frame Sequencer будет генерировать отсчеты на этой частоте, поэтому и счетчик должен ей соответствовать. Как видите, нет лишних преобразований, если все делать правильно.
- Флаг активности устанавливается, если период или шаг не равны нулю. Иначе сбрасывается.
- Если шаг не равен нулю, то тут же происходит вычисление новой частоты и ее проверка на переполнение (не более 2047), но новая частота не сохраняется – все делается лишь ради проверки на переполнение.
Если переполнения не было и шаг не равен нулю, то новое значение частоты записывается в регистры NRX3 и NRX4, а так же в регистр-буфер частоты. Сразу же происходит еще одно вычисление новой частоты и проверка на переполнение, но эта частота не сохраняется – это все делается только ради еще одной проверки переполнения.
Регистр-буфер частоты здесь опустить не получится. Его присутствие приводит к тому, что полноценный ручной контроль частоты канала во время работы Sweep unit невозможен. Мы можем изменить частоту сами, но она будет таковой до тех пор, пока не будет произведен отсчет Sweep unit – поскольку он использует в вычислениях регистр-буфер частоты, то наше значение частоты будет проигнорировано и перезаписано, а вычисления продолжатся, как ни в чем не бывало.
- Как было упомянуто ранее, период со значением 0 означает, что Sweep unit отключен. Это логично и должно было бы быть именно так, но в реальности для DMG период со значением 0 в регистре NRX0 означает, что период равен 8. Никаких вычислений частоты не происходит, просто Sweep unit работает вхолостую. Тестовые ROM’ы это проверяют.
- Представим такой сценарий. Игра установила режим уменьшения частоты. Прошло некоторое время и успело произойти вычисление новой частоты. Если после этого игра попытается установить режим увеличения частоты, то канал будет тут же отключен. Таким образом, если в режиме уменьшения частоты произошло хоть одно вычисление новой частоты, то смена режима на увеличение частоты отключает канал.
Length counter
Данный компонент является простейшим счетчиком. Он отмеряет определенное кол-во отсчетов, а затем отключает подключенный к нему звуковой канал. Данный компонент присутствует у всех каналов и использует для своей работы регистр NRX1 – в нем хранится длительность воспроизведения канала. Приводить его структуру не буду – у всех каналов отведено различное число бит под значение длительности. Помимо этого для Length Counter имеет значение бит 6 в регистре NRX4, который вкл/откл данный компонент.
Frame Sequencer генерирует отсчеты для этого компонента на частоте 256 Гц. Значения в регистре NRX1 указаны в отсчетах на такой частоте, что, в очередной раз, означает свободу от конвертирования. При каждом отсчете изменения записываются обратно в регистр – регистр NRX1 и является счетчиком.
Перед использованием значения длительности из регистра NRX1 его надо преобразовать по следующей формуле:
где Counter – счетчик, Mask – маска, с помощью которой из регистра извлекается только значение длительности (в нем иногда еще находится коэффициент заполнения). Это и даст нам число отсчетов на частоте 256 Гц.
- Если компонент был выключен и сейчас включается посредством бита 6, счетчик не достиг нуля, а текущее состояние Frame Sequencer осуществляет отсчет нашего компонента (все четные состояния), то мы тут же осуществляем отсчет. Это может привести к тому, что счетчик достигнет нуля и канал будет отключен, но тут надо учитывать еще одно условие – отключение канала здесь происходит только в случае, если не осуществляется перезапуск канала, т.е. бит перезапуска равен нулю.
- Если осуществляется перезапуск и счетчик достиг нуля, то в регистр NRX1 записывается максимально возможное значение длительности, т.е. все биты длительности обнуляются (см. формулу выше). Если при этом осуществляется включение компонента (предыдущее значение не важно) и текущее состояние Frame Sequencer осуществляет отсчет нашего компонента, то тут же производим отсчет. Тут уже условий никаких не надо – отключился канал, значит отключился.
Envelope unit
Данный компонент контролирует громкость звука, уменьшая или увеличивая ее с постоянным шагом с определенным периодом. Громкость в данном случае означает амплитуду генерируемого сигнала. Контролируется данный компонент посредством регистра NRX2:
Биты | Назначение |
7-4 | Начальное значение амплитуды |
3 | Режим: 0 – уменьшение 1 – увеличение |
2-0 | Период |
Frame Sequencer генерирует отсчеты для этого компонента на частоте 64 Гц. Значения в регистре NRX2 указаны в отсчетах на такой частоте. При каждом отсчете происходит отсчет внутреннего счетчика периода. Когда он отсчитает один период, то значение амплитуды увеличивается/уменьшается на единицу. При достижении граничных значений вычисления прекращаются. При амплитуде 0, очевидно, канал заглушен, но активен.
На рисунке выше показан график изменения амплитуды сигнала при работе Envelope unit со значением NRX2 равным 0x55. Начальное значение амплитуды устанавливается при перезапуске канала ( trigger ) – в данном случае оно равно 5. В процессе работы оно больше не используется и не модифицируется. Далее с каждым периодом амплитуда уменьшается на один до тех пор, пока не достигнет нуля.
- Как и для Sweep unit период 0 означает, что период равен 8. Опять же, никаких вычислений не происходит – компонент работает вхолостую.
- Если канал перезапускается, и следующее состояние Frame Sequencer генерирует для Envelope отсчет, то счетчик периода устанавливается на единицу больше, чем должен быть.
- Если канал перезапускается, начальное значение амплитуды равно нулю и выставлен режим уменьшения амплитуды, то канал тут же отключается.
- Если текущее (новое значение пока не записали) значение NRX2 содержит период, равный нулю, а счетчик периода еще не закончил отсчет (мы же помним, что период 0 означает 8), то необходимо увеличить на единицу текущее значение амплитуды. В противном случае, проверяем текущий режим – если это уменьшение, то амплитуду надо увеличить на 2. Т.е. это все приведет к немедленному повышению амплитуды генерируемого каналом сигнала.
- Если происходит смена режима, то амплитуда устанавливается равной 16 минус значение амплитуды.
- После всех операций значение амплитуды обрезается до младших 4 бит.
Звуковой канал 3
Данный звуковой канал генерирует волну согласно содержимому в Wave Pattern RAM, которая расположена в области памяти I/O ports. Wave Pattern RAM имеет длину 16 байт и содержит 32 сэмпла. Каждый байт содержит по 2 сэмпла – первый сэмпл в старших 4 битах, второй в младших 4 битах. Содержимое памяти проигрывается циклично с заданной в регистрах NR33 и NR34 частотой (структура этих регистров идентична 1 и 2 каналам).
- 00: канал заглушен, но активен.
- 01: Wave Pattern RAM воспроизводится как есть.
- 10: Wave Pattern RAM воспроизводится с предварительным сдвигом каждого сэмпла на 1 бит вправо.
- 11: Wave Pattern RAM воспроизводится с предварительным сдвигом каждого сэмпла на 2 бита вправо.
Таймер в Wave generator работает с периодом 2 * (2048 – X), где X – частота из регистров NRX3 и NRX4. В данном случае частота означает не частоту звука, а частоту, с которой происходит чтение очередного сэмпла из Wave Pattern RAM.
- При перезапуске канала указатель обнуляется, но в буфер сэмплов не копируется первый байт из Wave Pattern RAM – это произойдет только при следующем отсчете таймера. Это означает, что сначала будет проигран первый сэмпл из буфера сэмпла, который все еще содержит старый байт; при следующем отсчете таймера в буфер будет скопирован первый байт из Wave Pattern RAM, указатель передвинут на второй сэмпл, а значит будет проигран второй сэмпл из Wave Pattern RAM. Далее все продолжится как должно. В итоге, при перезапуске первый сэмпл не будет проигран до тех пор, пока вся Wave Pattern RAM не будет проиграна хотя бы один раз.
- Если канал 3 работает, то игра имеет доступ к Wave Pattern RAM только, если в этот же момент канал 3 производит чтение из нее. Иначе операции чтения возвращают 0xFF, а операции записи игнорируются. Если канал 3 работает и происходит чтение или запись в момент, когда канал 3 читает сэмпл, то операции происходят только на байте, на который указывает указатель текущего сэмпла — не имеет значение, откуда происходит чтение или запись. Операции чтения и записи работают нормально только при отключенном канале 3 – тогда можно читать и записывать в любом месте Wave Pattern RAM.
- Перезапуск канала 3 во время чтения сэмпла приводит к повреждению четырех первых байт в Wave Pattern RAM. Если указатель текущего сэмпла в пределах первых четырех байтов, то первый байт Wave Pattern RAM будет переписан содержимым буфера сэмплов. Если указатель текущего сэмпла в другой позиции, то будут переписаны все 4 первых байта содержимым той четверки байтов (4-7, 8-11, 12-15), где находится указатель. Например, если указатель на 10 байте, то содержимое первых четырех байт будет переписано байтами 8-11.
И так. Ключ к реализации последних двух пунктов – понимание того, что происходит при перезапуске канала (trigger) посредством регистра NR34. Очевидно, что нам надо сбросить счетчик таймера и указатель текущего сэмпла. Указатель сэмпла сбрасываем согласно первому пункту выше – тут все просто. Со счетчиком все не так просто, тут и кроется ключ к решению проблемы.
Обнуление счетчика при перезапуске канала – это очевидное и неправильное решение. На самом деле счетчик инициализируется таким образом, что происходит задержка перед тем, как начинается обновление позиции текущего сэмпла. Задержка равняется периоду таймера (формулу я уже приводил) плюс некая константа (скорее всего не больше 8 тактов), которую вам придется подобрать самим. Т.е. вместо того, чтобы отсчитать один период и обновить позицию указателя, таймер отсчитывает два периода плюс некая константа. После этого таймер работает в штатном режиме, отсчитывая положенный один период.
Вот как это работает в моем эмуляторе. Переменная ClockCounter является счетчиком тактов. Она имеет знаковый тип. Как только она достигает значения, равного периоду таймера, я обновляю позицию указателя текущего сэмпла и сбрасываю счетчик (вычитаю из него значение периода). При перезапуске канала посредством NR34 я устанавливаю ClockCounter = -Period — 3, где Period – значение периода таймера в тактах согласно приведенной ранее формуле, 3 – та самая магическая константа. Это дает необходимую задержку и позволяет узнать, в какой момент времени можно производить чтение/запись Wave Pattern RAM. Если в момент чтения или записи в Wave Pattern RAM переменная ClockCounter равна 3, то эти операции доступны. Иначе – возвращаем 0xFF.
Теперь указатель сэмплов. При перезапуске я записываю в него 1. Именно эта комбинация задержки и значения указателя сэмплов при перезапуске позволяет пройти тестовые ROM’ы. Не забываем только про тот факт, что второй проигрываемый сэмпл после перезапуска – это второй сэмпл в Wave Pattern RAM. Из-за задержки будет два раза проиграно старое содержимое буфера сэмплов (см. первую странность), а затем третий сэмпл из Wave Pattern RAM. Такова особенность моей реализации, поэтому, как только таймер после перезапуска канала пройдет всю задержку (станет неотрицательным), я обновляю содержимое буфера сэмплов.
С повреждением четырех первых сэмплов все элементарно, только теперь ClockCounter должен быть равен 1, чтобы происходило повреждение и перезапись первых байтов Wave Pattern RAM.
Не забываем, что перезапуск канала – это не просто запись в NR34. Все перечисленное и сам перезапуск происходит только тогда, когда в старший бит NR34 записывается 1 и регистр NR30 разрешает воспроизведение (старший бит установлен).
Звуковой канал 4
Этот канал генерирует шум. К нему подключены Length counter и Envelope unit – их поведение ничем не отличается от такового в других каналах. Под них отведены те же самые регистры – NR41 и NR42 соответственно. Данный канал не содержит частоты в привычном понимании – NR43 используется для совершенно других целей, а NR44 содержит все привычные флаги, но биты под частоту не используются.
Генератор шума основан на так называемом LFSR – Linear Feedback Shift Register или регистр сдвига с линейной обратной связью. Это генератор псевдослучайной битовой последовательности. Принцип его работы достаточно прост.
Регистр сдвига представляет собой хранилище для битовой последовательности определенной длины (в DMG регистр сдвига может иметь длину 7 или 15 бит). Определенные биты регистра сдвига отмечаются как отводы (taps) – именно благодаря им генерируется последовательность. В DMG отводами являются 0 и 1 биты регистра сдвига. Для непрерывной работы LFSR используется тактовый генератор, который генерирует отсчеты для вычисления очередного бита псевдослучайно последовательности.
- Отводы суммируются по модулю 2 (операция XOR), и результат сохраняется для дальнейших операций.
- Крайний правый бит (бит 0) регистра сдвига берется в качестве очередного значения генерируемой последовательности.
- Регистр сдвига сдвигается вправо на один бит.
- В освободившийся крайний левый бит записывается результат суммы отводов по модулю 2, который мы сохранили на первом шаге.
где N – длина регистра сдвига в битах. Период определяется максимальным числом различных состояний регистра сдвига кроме одного, когда все биты равны нулю. Таким образом, для 7-битного регистра период будет равен 127, а для 15-битового равен 32767. Это приводит нас к вопросу – вычислять все честно или же использовать заранее сгенерированные последовательности. Результат будет идентичен, поскольку LFSR гарантированно зацикливается. Я использовал второй подход. Последовательности можно найти в файлах LFSR7.inc и LFSR15.inc.
Для управления LFSR используется регистр NR43. Вот его структура:
Биты | Назначение |
7-4 | Сдвиг частоты таймера: 0000: 1/2 0001: 1/2 2 0002: 1/2 3 0003: 1/2 4 … 1101: 1/2 14 1110: не используется 1111: не используется |
3 | Длина регистра сдвига: 0: 15 бит 1: 7 бит |
2-0 | Множитель частоты: 000: 2 001: 1 010: 1/2 011: 1/3 100: 1/4 101: 1/5 110: 1/6 111: 1/7 |
С длиной регистра сдвига все понятно. Остальные биты используются для вычисления частоты тактового генератора LFSR. Вычисляется она (F) по следующей формуле:
F = f * Shift * Ratio,
где f = 4194304 Гц, Shift – сдвиг частоты таймера (значения указаны в таблице выше), Ratio – множитель частоты (значения указаны в таблице выше). Если биты сдвига частоты равны 1110 или 1111, то LFSR не получает отсчетов, а значит канал 4 заглушен.
Реализация
Для реализации звука я выбрал SDL. Эта библиотека имеет предельно простой API для генерации процедурного звука – указываем параметры звука, длину буфера сэмплов, callback-функцию и все. SDL автоматически вызывает эту функцию, где мы и «скармливаем» ей очередную порцию сэмплов. После их воспроизведения функция вызывается еще раз и т.д. Помимо простого API еще одно преимущество SDL – хорошая работа с предельно малыми буферами сэмплов, а для нас как раз очень важна латентность.
Я не буду вдаваться в подробности реализации самих компонентов звуковой системы. Теоретическая часть содержит все необходимое. Лишь коснусь проблемы синхронизации.
Проблема заключается в том, что теперь нам нужно поддерживать не только темп обновления экрана, но и темп генерации сэмплов. SDL вызывает callback-функцию через равные (хотя гарантий этого в документации я не видел) промежутки времени и «ожидает», что мы запишем новую порцию сэмплов. Если этих сэмплов не будет в нужный момент, то мы получим прерывистый звук. В тоже время, может оказаться, что темп эмуляции слишком высокий и очередные порции сэмплов надо будет где-то сохранить для воспроизведения позже.
- нам не надо следить за границами массива – данная структура данных все сделает за нас. Бонусом является еще и то, что кольцевой буфер имеет фиксированный размер;
- хранение порций сэмплов в правильном порядке;
- упрощение реализации ускоренной эмуляции. Дело в том, что при отсутствии достаточного количества свободного места кольцевой буфер перезаписывает уже имеющиеся данные. При ускоренной эмуляции порции сэмплов будут поступать быстрее, чем мы сможем их воспроизвести. Поскольку мы никого не ждем и пишем поверх старого, то темп звука будет соответствовать темпу эмуляции;
- поддержание темпа эмуляции. Это несколько противоречит предыдущему пункту, но дело вот в чем. Если поступила очередная порция сэмплов, а в кольцевом буфере нет для нее места, то вместо перезаписи мы ждем, пока callback-функция не заберет из буфера порцию сэмплов. Только после этого мы добавляет очередные сэмплы в буфер и продолжаем эмуляцию.
Все так хорошо работает по одной простой причине – генерация сэмплов происходит с тем же темпом, с каким работает процессор DMG.
Тестирование
Как и для других компонентов, для звука тоже есть тестовые ROM’ы. Есть только одна хитрость – для DMG и Gameboy Color комплекты тестов разные и запускать стоит их все. Тесты DMG должны быть пройдены без ошибок, а вот тесты для Gameboy Color реальный DMG проходит с ошибками и выводит на экран следующее:
Если при запуске всех тестов сразу их выполнение не прекращается, а зацикливается, то беспокоиться не о чем. Это именно тот случай, когда ROM пытается установить банк ROM’а, которого не существует. Если обрезать номер банка, как это делаю я, то тесты зацикливаются. Тоже самое наблюдается и у Gambatte, а ему доверять можно.
Рекомендую сразу вооружиться исходным кодом тестов и разобраться в том, как они работают. Это намного ускорит процесс, а иной раз это единственный способ понять, что вам нужно сделать. На экран хоть и выводится описание ошибки, но порой сложно понять, что конкретно от вас требуется и какие регистры задействованы.
И так, самые простые тесты – это «01-registers» и «11-regs after power». Первый тестирует то, как происходит чтение и запись регистров звука. Я уже упоминал про то, как стоит учитывать неиспользуемые и недоступные для чтения биты регистров – именно это и проверяет тест. Помимо этого, проверяются результаты операций при вкл/выкл звуке. Второй тестирует поведение регистров при выключении звука. В исходном коде написано подробнее, что конкретно тестируется.
«02-len ctr» тестирует поведение Length counter в граничных условиях. Тестирование происходит для каждого канала отдельно, в процессе выводится номер протестированного канала.
«03-trigger» еще один тест для Length counter, но теперь проверяется его поведение при модификации регистра NRX4. В основном, именно здесь тестируются все упомянутые странности Length counter.
«04-sweep», «05-sweep details» и «06-overflow on trigger» тестируют Sweep unit. Помимо нормальной работы здесь тестируются все упомянутые странности компонента. Для прохождения теста «06-overflow on trigger» в ходе него на экран должно быть выведено:
«07-len sweep period sync» тестирует правильность синхронизации Sweep unit и Length counter. Если Frame Sequencer реализован правильно, то проблем с этим тестом быть не должно.
«08-len ctr during power» тестирует поведение Length counter при выключении звука. Для прохождения теста в ходе него на экране должно быть выведено:
«09-wave read while on» тестирует операции чтения во время работы канала 3. Для прохождения теста на экране должно быть выведено:
На экран через раз выводится значение из Wave Pattern RAM и FF из-за запрета на чтение. Они чередуются (00 FF, 11 FF и т.д.), но в начале операция чтения не проходит два раза и выводится FF FF. Как раз этого добиться сложнее всего, и потребовало у меня перебора разных значений константы и счетчика (определение момента, когда операция чтения разрешена).
«10-wave trigger while on» тестирует повреждение первых байтов Wave Pattern RAM при перезапуске канала 3 во время чтения сэмпла. На экран выводится очень много информации, и полностью она не помещается. Вот результат пройденного теста:
Даже по этому куску видно, где должно происходить повреждение Wave Pattern RAM.
«12-wave write while on» тестирует операции записи в Wave Pattern RAM при работе канала 3. Тут тоже выводится слишком много информации, вот результат пройденного теста:
Вполне видно, где и что искать – тест пытается записать значение 0xF7.
Стоит сказать, что прохождение этих тестов лично мне ничего не дало в протестированных мной играх. И без их прохождения звук был нормальный, а судя по другим эмуляторам с завидной совместимостью, проваливающих все тесты звука – это вообще не нужно. Хотя приятно осознавать, что эмулятор работает так, как реальное железо. Если и попадется игра, зависимая от тонкостей железа, то она будет работать корректно.
Что дальше
- Поддержка последовательного порта или Game link.
- Поддержка малораспространенных MBC-контроллеров – Pocket Camera, Bandai TAMA5, Hudson HUC-3, Hudson HUC-1, картриджи с вибрацией.
Баг происходит при исполнении определенных инструкций процессора с определенными значениями операндов. Это простая часть. Сложнее эмулировать тот факт, что мусор записывается совсем не случайно и имеет определенное содержание. Еще сложнее эмулировать то, что данный баг происходит только в определенные промежутки времени работы LCD-контроллера. Именно для этих деталей я не нашел никакой документации – есть только тестовые ROM’ы, которые не очень помогают. С ними можно реализовать этот баг лишь частично.
Смысла в реализации этого бага минимум – вряд ли какой-то разработчик сознательно его использовал или оставил в релизе игры. Теже баги звука из-за Wave Pattern RAM встречаются в играх, и в них есть практический смысл.
Заключение
На этом цикл статей подошел к концу. Как я и говорил, итогом является эмулятор с хорошей совместимостью и поддержкой всех самых важных функций. Такой не стыдно поставить рядом с другими реализациями. А благодаря использованию тестовых ROM’ов для реализации и тестирования можно говорить о высокой точности эмуляции железа, а не простой совместимости с играми.
Естественно, эмулятору есть куда развиваться. Помимо упомянутого, есть еще одно логичное направление развития эмулятора — эмуляция Gameboy Color (СGB). DMG и CGB являются не просто консолями одного семейства — они практически идентичны внутренне. К существующему эмулятору необходимо дописать буквально несколько модулей.
На данный момент Cookieboy не эмулирует CGB, но я планирую заняться этим в ближайшее время. Об этом тоже будет статья.
Если кто-то решится на реализацию своего эмулятора или же что-то непонятно в самих статьях, то можете обращаться с вопросами, буду рад помочь. В комментариях к статьям или в хабрапочту — неважно.
Что такое буфер звуковой карты. Настройки Audio в Fl Studio
РАБОТА В FL STUDIO
Многие начинающие музыканты работающие со студийными программами как fl studio, поначалу не знают, что такое буфер звуковой карты и настройки audio в Fl Studio. Хотя эти знания могут им помочь в дальнейшем. Так как, если у вас компьютер слабенький, а проект становиться больше компьютер начинает притормаживать во время воспроизведения ваших треков в секвенсоре из-за нехватки ресурсов.
Обычно это происходит когда мы используем много инструментов и vst плагинов, где слабенькому компьютеру уже становиться тяжело обрабатывать звуковую информацию на выходе. И именно поэтому эти настройки нам нужны, для снижения нагрузки на компьютер.
Что такое буфер звуковой карты?
Буфер звуковой карты – это определенное количество дамп памяти, где Fl Studio может обрабатывать звук, до того как он достигнет выходного сигнала вашей звуковой карты.
При меньших значениях звук будет обрабатываться быстрее и с низкой задержкой обработки сигналов. При таких условиях процессор загружается больше и возможны ошибки (опустошения), когда будет происходить обработка сигнала, т.е. воспроизведение трека.
Настройки Audio в Fl Studio.
Чтобы открыть настройки audio в fl studio просто нажмите F10 или же через меню OPTION — Audio settings. И во вкладке Input / output можно выбрать звуковую карту. Которая будет в дальнейшем обрабатывать звук. При выборе звуковой карты вы можете заметить изменения в настройках окна.
При работе в fl studio используйте лучше драйвер asio4all. Он меньше нагружает ваш компьютер. Если у Вас он не установлен, то можете скачать его с официального сайта www.asio4all.org. О том как быстро настроить звуковую карту можете почитать тут.
- Status (статус) — показывает текущее состояние входов и выходов звукового драйвера. А также отображает итоговую задержку выхода, включая плагины.
- Sample rate (Hz) — устанавливает частоту дискретизации при воспроизведении звука через микшер. Чтобы не было проблем со старыми плагинами оставьте этот показатель по умолчанию в 44100 Гц.
- Auto close — эта опция позволяет устранить проблемы при использовании совместно с Fl Studio других аудио программ. В основном проблемы могут появляться когда выбран звуковой драйвер asio4all. Но если появились глюки со звуком включите эту опцию и перезапустите все программы которые используют аудио поток. После этого нужно свернуть fl studio чтобы не было проблем со звуком.
Опции asio4all.
- Buffer length (размер буфера) — этот ползунок позволяет изменить длину буфера в широком диапазоне. При высоких значениях система будет работать стабильнее и без ошибок. Вдобавок будет использовано меньше ресурсов центрального процессора. В случае, какой-нибудь ошибки при проигрывании будут слышны хрипы и посторонние звуки.
- Show ASIO Panel — открывает настройки буферизации, выбора звуковой карты на выходе и отдельные настройки драйвера. По возможности используйте размер буфера в пределах 10 -20 мс.
- Mix in buffer switch — эта опция позволяет добиться на некоторых звуковых картах меньшей задержки.
- Triple buffer — включите тройную буферизацию если вам требуется больше ресурсов для проекта. Эта опция увеличивает задержку вдвое и может вызвать крах (зависание) программы из за несовместимости с некоторыми плагинами.
Опции первичного звукового драйвера.
- Buffer length (размер буфера) — этот ползунок позволяет изменить длину буфера в широком диапазоне. При высоких значениях система будет работать стабильнее и без ошибок. Вдобавок будет использовано меньше ресурсов центрального процессора. В случае, какой-нибудь ошибки при проигрывании будут слышны хрипы и посторонние звуки.
По возможности отрегулируйте этот показатель на 20-40 мс, если позволяет компьютер. Если же у Вас при воспроизведении проекта появился треск, то увеличите этот показатель пока он не пропадет.
Также запомните, что возможность работы без ошибок (опустошения) зависит от мощности процессора, количества оперативной памяти, звуковой карты и выбранной длины буфера значение и сложности проекта.
Перевод мс (миллисекунд) в сэмплы: 1 мс = 44 samples (образцов) на частоте 44100 Гц или 48 samples образцов на частоте 48000 Гц.
- Offset — при увеличении показателя Offset совместимость свойств драйвера с такими операционными системами как Windows Vista увеличивается. 0% — выкл.
- Use polling — при включении этой опции можно значительно уменьшить буфер без его опустошения. Заметьте что на некоторых компьютерах эффект может быть противоположный.
- Use hardware buffer — позволяют использовать аппаратный звуковой буфер поддерживаемый звуковой картой.
- Use 32-Bit Buffer — позволяет использовать буфер в 32-бит с плавающей точкой. Будет работать только под Windows XP или выше.
Поток смешивания звука.
- Priority — определяет приоритет для смешивания звукового потока. Настройте этот параметр взависимости от зависания программы.
- Higher — выделяет максимальные ресурсы для смешивания звукового потока.
- High — выделяет высокие ресурсы процессора.
- Normal — используется средние ресурсы процессора. Уменьшает риск зависания.
Выход плагина.
Эти настройки видимы только при использовании FL Studio как VSTi/DXi плагина или при подключении в качестве ReWire клиента.
- Slave Tempo — при включенииFL Studio будет синхронизироваться с темпом основной программы.
- Record Automation — в рабочем режиме дистанционное управление сообщениями MIDI, от основной программы будут записаны во время сессий записи.
Отслеживание воспроизведения.
При использовании этих настроек можно решить проблему дрожания или неправильной позиции маркера воспроизведения, а также решить проблемы выравнивания в плейлисте записанного звука.
- Playback tracking source — что будет отвечать за источник отслеживания при воспроизведении:
- Driver — по умолчанию позицию воспроизведения использует звуковой драйвер.
- Hybrid — гибрид позиции. Этот вариант лучше подойдет для устранения дрожания при использовании «первичного звукового драйвера».
- Mixer — применяется позиция микшера. Избегайте этого варианта, но если вы используете задержку буфера в 10 мс (441 сэмплов) или меньше, то он может решить проблемы синхронизации звука/видео при использовании некоторых аудио-интерфейсов.
В прежних версиях FL Studio эта опция называлась Use Mixer as Playback Position.
CPU (процессор).
Данные опции необходимы с целью уменьшения перегрузки на процессор и повышения производительности FL Studio на вашем пк.
- Multithreaded generator processing — снижает нагрузку на процессор путем воздействия нескольких ядер процессора при использовании генераторов.
- Multithreaded mixer processing — снижает нагрузку на процессор путем воздействия нескольких ядер процессора в микшере программы.
- Smart disable — все обще выключает как инструменты так и эффекты, если они неактивны, отчего понижает нагрузку на процессор. Примечание: данная функция функционирует в связке с любым плагином, которая имеет переключатель Smart disable. Данная функция будет функционировать только лишь в тех оболочках, в которых включён параметр Smart Disable. Задача данного параметра в опциях звука это массовое включение или отключение Smart Disable во всех плагинах. И для того чтобы использовать «автоматическое отключение» во всех плагинах, вам нужно применить команду через Tools > Macros > Switch smart disable for all plugins. После этого в оболочке любого плагина будет включена опция Smart disable. В случае если «автоматическое отключение» вызывает затруднения с некоторыми плагинами, то в таком случае данную функцию можно отключить для единичных плагинов, через функции Smart disable в меню оболочки. Примечание 2: Умное отключение активно лишь при воспроизведении, при рендеринге оно на время выключается.
- Align tick lengths — способен снизить нагрузку на процессор и увеличить эффективность определенных сторонних плагинов, которые применяют технологию Align tick lengths. Тик считается самой маленькой внутренней единицей времени употребляемой с целью секвенирования автоматизаций и нотных событий (PPQ подсчитывает число тиков (импульсов), к примеру в четверти ноты). Если возникают трудности с плагинами, то тогда включите.
На заметку: некоторые из этих настроек могут вызвать трудности в плагинах. Это будет связано с отсутствием поддержки стандартов VST в самих плагинах.
Настройка задержки звуковой карты и sample rate
Всем доброго времени суток. Сейчас задам, возможно, дилетантский вопросик, но, всё же, он меня терзает.
Недавно обратил внимание на окошко настройки драйвера звуковой карты (Motu M4). Там есть параметры:
Sample Rate: 44.1-192khz
Buffer Size: 16-4096 samples
А также галочки "Use lowest latency settings offsets" и "Sync Windows sample rate to device".Про Sample Rate погуглил — большинство пишут, что выше 44.1 ставить толку никакого. Но есть и менее популярные мнения о том, что при изменении скорости звука может быть полезен 96khz. Поэтому хотел бы уточнить наверняка.
С Buffer Size всё сложно для меня. Как понял, его меняют постоянно — для мониторинга записи ставят ниже, для тяжелой обработки — выше. Но вопрос вот в чем. Какое значение лучше ставить при работе с видео? При сведении звука для фильма, к примеру. Дабы понимать синхронизирован он с видеорядом или нет. И в целом при обычном использовании ПК — фильмы, видео, игры и т.п. влияет ли Buffer Size на задержки? Ибо я использую карту, как преамп для наушников и не всегда на ней работаю.
Ну и по целесообразности настроек с "галочками", если кто подскажет, буду благодарен)