Заморочки со звуком
Есть такой широко известный в узких
кругах человек, как Marat Fayzullin. Из-
вестен он тем, что является автором мно-
гих отечественных эмуляторов (многих - с
открытым исхoдним кодом, что сильно по-
влияло на развитие эмулятopoстpoения)
различных 8-разрядных машинок, как-то:
MSX (fMSX), Coleco (ColEm), NES (iNES),
Sega Master System (MasterGear), Nintendo
Gameboy (VGB), Gameboy Advance (VGBA).
Эмуляторы, честно говоря, слабенькие (за-
то одни из самых первых!), и местами
весьма небесплaтные ($35 за эмулятор
iNES, сильно уступающий современным ана-
логам - не хотите? ;). Но есть у них, a
точнее у старых их версий (в новых фича
убрана) одна занятная возможность: скиды-
вать поток данных для aудиoчипa в специ-
альный формат, с расширением .snd (это не
тот .snd, который 8-bit сэмпл). Чипы, ко-
нечно, у всех приставок очень разные. Но
звук в старых эмуляторах выводился через
Adlib, достоверность эмуляции была весьма
низка, a формат .snd был для всех эмуля-
торов Marat'a унифицирован.
Однажды пришла мне в голову идея, не
имеющая никакого практического npumehe-
ния, но имеющая чисто спортивный интерес:
a что, если взять и перехватить в каком-
либо эмуляторе поток данных для звукового
чипа, перевести в список номеров каналов,
частот, громкостей, и т.д, a потом про-
играть всё это дело на AY? Принцип дей-
ствия всех PSG-чипов (включая AY) сходен.
Конечно, некоторые звуковые чипы имеют
большее количество каналов, другие воз-
можности, но можно их разумно урезать.
Стал думать, как-бы это сделать. Для на-
чала нужно было придумать, как nepexba-
тить поток данных - решил найти open-
source-эмулятор и сделать нужные дopaбoт-
ки. Но при первом-же поиске в google на-
ткнулся на совершенно другую вещь: уже
реализованную идею, но для С64 - плеер
музыки с NES (чип 2A03) на SID 8) Называ-
лась эта штука NESSIDPlay (кому интере-
сно, ссылка в конце статьи).
NESSIDPlay использовал в работе .snd-
файлы эмуляторов Marat'a (от iNES, VGB,
MasterGear). Таким образом, необходимость
искать и дорабатывать эмуляторы отпала.
Поискав ещё (довольно долго), я нашёл
описание формата .snd (оно прилагается к
iNes версии 0.7 only):
* SOUNDTRACK FILE FORMAT *
iNES is capable of saving soundtrack into
so-called .SND files, also used by my
other emulators. You can find tools to
work with these files in the EMUTools
package. .SND files have quite simple
format described below:
[ iNES умеет сохранять звуковые треки в
так называемые .SND-файлы, испольуемые и
в других моих эмуляторах. Инструментарий
для работы с такими файлами можно найт в
пакете EMUTools. Файлы .SND имеют доволь-
но простой формат, который описан ниже: ]
┌───────┬───────────────────────────────┐
│ Byte │ Contents │
├───────┼───────────────────────────────┤
│ 0-3 │ String "SND^Z" │
│ 4 │ Version number │
│ 5 │ Number of channels │
│ 6 │ Clock frequency, in Hz │
│ 7-15 │ Reserved, must be zeroes! │
│ 16-EOF│ Sound records of │
│ │ following types: │
│ │ a) channel# | frequency.l | │
│ │ frequency.h | volume │
│ │Change sound on a given channel│
│ │to new frequency (Hz) │
│ │ and volume (0..255). │
│ │ b) FFh │
│ │A single clock "tick". │
│ │ c) FDh | number of ticks │
│ │Multiple clock "ticks" (0..255)│
│ │ d) FEh | channel# | sound type│
│ │Change sound type at a given │
│ │channel. Default type is │
│ │MELODIC for all channels. │
│ │ Currently defined types: │
│ │ 0 - MELODIC │
│ │ 1 - WHITE NOISE │
│ │ 2 - PERIODIC NOISE │
└───────┴───────────────────────────────┘
Это описание формата первой версии. Су-
ществoвaли и последующие, более сложные,
не имеющие обратной совместимости. Чтобы
убедиться, что файл в формате нужной вер-
сии, надо проверить байт номер 5 (start+
4), если он меньше 2 - значит всё ОК.
Некоторые неудобства доставило то, что
значения частот в этом формате хранятся в
герцах - пересчитывать их на лету в зна-
чения для тональных регистров AY довольно
муторно и неинтересно. Я поступил просто
- написал для РС маленькую программку,
которая преобразовывала .snd в мoдифици-
poвaнный формат, где частоты хранились
сразу в значениях для тональных реги-
стров, причём более компактно. Можно было
бы сделать такое преобразование и на
Speccy, при загрузке файла, но я банально
поленился:)
Нужно пояснить, что такое tick. Данные
из файла нужно засылать в звуковой чип с
частотой, указанной в байте start+6 (я
взял 50 герц, т.е. частоту прерываний
Speccy - на приставках эта частота равна
50 или 60 герц, в зависимости от PAL/NTSC
системы). Мы читаем данные и шлём их в
чип до тех пор, пока не встретим байт FFh
(тик) - тогда ждём следующего прерывания.
Либо же, до байта FDh, и ждём столько ти-
ков, сколько указано в следующем за ним
байте (это сделать нужно обязательно, в
файлах полно данных значений).
Теперь o том, как я решил проблему не-
соответствия возможностей 2A03 (чипа NES,
я рассчитывал только на музыку для него)
и AY. Для этого нужно обьяснить, что та-
кое 2A03, и что он умеет.
2A03 не является самостоятельным чипом
(не имеет своего корпуса) - он uhterpupo-
ван в ядро мoдифициpoвaннoгo процессора
6502, применяемого в NES (это и есть его
основная модификация:). Он имеет 4 PSG-
канала, и один цифровой (DMC, Sbit, имеет
DMA - этот канал отсутствовал в ориги-
нaльнoм Famicom, японской версии NES).
Цифровой канал в эмуляторе iNES не эмули-
руется, и в .snd не записывается, поэтому
o нём (и ударных во многих играх с хоро-
шей музыкой;) можно забыть. 0 и 1 каналы
PSG генерируют square-тон в диапазоне
54.6Hz..12.4KHz, они полностью одинаковы.
2 канал выдаёт triangle-тон в диапазоне
27.3Hz..55.9KHz, используется для бас-
партий. Последний, канал номер 3, генери-
рует шум (псевдо-random генератор, часто-
ты 29.3Hz..447KHz). У square-каналов,
triangle-канала и noise-канала имеются
различные уникальные фичи (подробности
читайте в документации), но толку от это-
го никакого - они не эмулируются в iNES,
и в файл не пишутся.
Так как цифровой канал мы отбросили,
нам остаётся только распихать 4 канала
(три тона и шум) по имеющимся трём кана-
лам AY (ведь генератор шума на нём не
имеет своей регулируемой громкости). Я
сделал так: на одном из каналов играл бас
и шум (с громкостью баса, также я пpoбo-
вал менять вместо громкости частоту шума,
a значение частоты из файла urhopupo-
вать). Ещё был вариант - реализовать
triangle-канал с огибающей (для получения
похожего на реальный triangle-канал зву-
ка), но по ленивости своей я этого так и
не сделал.
B итоге получилось нечто, смутно напо-
минaющее исходную мелодию на NES, занима-
ющее около 10-15 килобайт на короткую
мелодию (a что вы хотели от PSG-формата?
:). К сожалению, исходники плеера угpoби-
лись по независящим от меня причинам, и я
не могу продемонстрировать это чудо в pa-
боте. Но если кому-либо эта заморочка по-
казалась интересной - ссылки на неoбхoди-
мую информацию в конце статьи, ассемблер
вам в руки:)
Кстати, занятная информация для облада-
телей приставок NES, построенных на дис-
кpетных элементах (имеющих процессор в
DIPЧO-корпусе). Вполне легко можно сде-
лать псевдо-стерео выход: на первую ногу
чипа выходит сигнал с обоих square-кана-
лов, на вторую - triangle и шум. Паяльник
вам в руки;)
Напоследок скажу для тех, кто захочет
произвести аналогичные эксперименты: не
пытайтесь использовать форматы музыки от
современных эмуляторов (типа .nsf) - это
не поток команд для звукового чипа, a
выдранный из игры плеер + данные (при
проигрывании приходится эмулировать не
только звуковой чип, но и процессор, и
всё необходимое железо - аналогично AY-
Emulator'у).
Сайт Marat'a:
http://fms.komkon.org/
NESSIDPlay:
http://www.zyx.com/chrisc/nessidplay.html
Описание 2A03:
http://web.textfiles.com/
games/nessound.txt
Other articles: