AY

Общие замечания

Формат является родным для ZX Spectrum и Amstrad CPC, поэтому может проигрываться как в эмуляторах, так и на реальных компьютерах ZX Spectrum и Amstrad CPC без использования специальных плееров.

Формат этого файла был предложен автором plug-in’а DeliAY к DeliTracker’у (компьютер Amiga). Имя этого человека Patrik Rak. На IBM PC эти файлы стало возможно послушать благодаря программе AYPlay James McKay’я. К этой программе прилагается также утилита AYMake, но она имеет ряд ограничений, не позволяющая использовать возможности AY-формата полностью.

Нижеследующее описание составлено в результате моей годовой работы с AY-файлами, но во все тонкости этого формата удалось проникнуть лишь после продолжительной переписки с Patrik Rak’ом.

Формат файла

Итак, как уже было сказано, формат разрабатывался под Amiga с её процессором MC68000. В связи с этим все данные размером в слово представлены в порядке "первый байт – старший". Кроме того, этот процессор накладывает ещё одно ограничение на AY-формат – необходимо, чтобы все двухбайтовые слова были выровнены на двухбайтовые смещения относительно начала AY-файла.

Второе важное замечание – все указатели в этом формате являются числами со знаком и фактически являются смещением относительно текущей позиции в файле до нужных данных. Диапазон такого смещения от -32768 до +32767. Это накладывает достаточно жёсткие ограничения на размер AY-файла, вполне можно столкнуться с ситуацией, что при конкретных условиях создать AY-файл не возможно.

AY-файл является последовательностью записей. Порядок следования записей не имеет никакого значения, за исключением заголовка, который находится в самом начале файла.

Структура заголовка

СмещениеДлина в байтахОбозначениеОписание
+04FileIDИдентификатор файла 'ZXAY'.
+44TypeIDТип данных в контейнере. Ay_Emul пока поддерживает следующие типы:
'EMUL' – эмуляция процессора Z80;
'AMAD' – аналог FXM;
'ST11' – контейнер ST1.
+81FileVersionВерсия файла, можете использовать это поле по своему усмотрению, однако автор формата рекомендует нумеровать версии по порядку. Первую версию можно обозвать 0, если в последствии что-нибудь понадобится изменить и переделать, новый файл можно обозвать 1, и так далее.
+91PlayerVersionВерсия проигрывателя, который необходим для проигрывания данного AY-файла. Пока существует 3 версии проигрывателей по мере их развития:
0 – используйте ноль, если не знаете, какой версии проигрыватель вам нужен;
1 – самая первая версия;
2 – первые 256 байт адресного пространства заполняются кодом 0xC9 (RET);
3 – последняя на сегодняшний день версия, полная эмуляция Z80, плюс поддержка порта динамика ZX Spectrum (бипера), подробно описано ниже.
+102PSpecialPlayerЭто для AY-файлов, которые содержат проигрыватель в кодах MC68000. Патрик Рак говорит, что он сделал только один такой файл ещё на Amiga, поэтому на это поле можно не обращать внимания.
+122PAuthorСмещение до строки с завершающим нулём, в которой хранится имя автора всех песен в данном AY-файле.
+142PMiscАналогично, но до строки с прочей информацией.
+161NumOfSongsКоличество мелодий в файле, уменьшенное на 1.
+171FirstSongНомер песни, которая должна исполняться первой (тоже уменьшено на 1).
+182PSongsStructureОтносительное смещение до первой записи "Структура песни".

Размер заголовка равен 20 байтам.

Последнее смещение указывает на записи "Структура песни" (по одной записи на каждую песню, эти записи идут друг за другом). Таким образом, и EMUL, и AMAD, и ST11, и другие типы могут содержать более одной мелодии в одном AY-файле.

Запись "Структура песни"

СмещениеДлина в байтахОбозначениеОписание
+02PSongNameОтносительное смещение до строки с завершающим нулём, в которой содержится имя песни.
+22PSongDataСмещение до записи "Данные песни".

Всё, что описано выше, справедливо для любого AY-файла. Далее описаны типы данных в контейнере.

Тип 'EMUL'

Запись "Данные песни" для типа 'EMUL' имеет следующую структуру:

СмещениеДлина в байтахОбозначениеОписание
+01AChanНомер канала компьютера Amiga, который будет использован для эмуляции канала A AY.
+11BChanНомер канала компьютера Amiga, который будет использован для эмуляции канала B AY.
+21CChanНомер канала компьютера Amiga, который будет использован для эмуляции канала C AY.
+31NoiseНомер канала компьютера Amiga, который будет использован для эмуляции канала шума AY.
Наиболее типично для этих четырёх байт сочетание 0, 1, 2, 3. Допускается использование указанных номеров в любом порядке. Однако все это актуально только при проигрывании AY-файла на Amiga.
+42SongLengthПродолжительность музыки в 1/50 секунды. Нуль означает то, что длина неизвестна (бесконечна).
+62FadeLengthПродолжительность затухания звука в конце мелодии в 1/50 секунды.
+81HiRegСодержимое верхних половинок всех общих регистров Z80 перед началом эмуляции (AF, AF', HL, HL', DE, DE', BC, BC', IX и IY).
+91LoRegСодержимое нижних половинок тех же регистров, даже регистров флагов.
+102PPointsОтносительное смещение до записи "Указатели".
+122PAddressesОтносительное смещение до записи "Блоки данных".

Запись "Указатели" содержит адреса стека, процедур инициализации и проигрывания данной мелодии:

СмещениеДлина в байтахОбозначениеОписание
+02StackЗначение регистра SP перед началом эмуляции.
+22INITАдрес подпрограммы инициализации песни в адресном пространстве Z80. Может быть равен нулю (описано далее).
+42INTERRUPTАдрес подпрограммы проигрывания (вызывается по прерыванию, т.е. 50 раз в секунду). Может быть равен нулю (описано далее).

Запись "Блоки данных" состоит из последовательности по три слова:

СмещениеДлина в байтахОбозначениеОписание
+02Address1Адрес первого блока в памяти Z80.
+22Length1Длина первого блока в байтах.
+62Offset1Относительное смещение до этого блока в данном AY-файле.
+82Address2Адрес второго блока в памяти Z80.
+102Length2Длина второго блока в байтах.
+122Offset2Относительное смещение до этого блока в данном AY-файле.
и так далее, пока не будет встречено Address = 0, что означает конец записи "Блоки данных".

Минимально необходимый контроль целостности

Если вы хотите, чтобы ваш собственный проигрыватель AY-файлов проигрывал большинство ныне существующих файлов, стоит придерживаться следующих правил (они позволят проиграть даже некорректно созданные AY-файлы) при загрузке блоков:

  1. Если Address + Length > 65536, необходимо уменьшить длину блока Length так, чтобы эта сумма не превышала 65536.
  2. Если ТекущаяПозицияВФайле + Offset + Length > РазмерФайла, опять таки нужно подкорректировать Length.

Требования к проигрывателю

А теперь подробно о том, как проигрыватель версии 3 должен проигрывать AY-файлы типа 'EMUL'.

  1. Заполнить диапазон #0000–#00FF байтом #C9.
  2. Заполнить диапазон #0100–#3FFF байтом #FF.
  3. Заполнить диапазон #4000–#FFFF байтом #00.
  4. Поместить по адресу #0038 байт #FB.
  5. Если INIT для данной песни равен нулю, необходимо поместить адрес первого загруженного блока в первой инструкции CALL (смотри следующие пункты 6 и 7).
  6. Если INTERRUPT для данной песни равен нулю, необходимо поместить по нулевому адресу следующий плеер:
            DI
            CALL INIT
    LOOP:   IM 2
            EI
            HALT
            JR LOOP
    
  7. Если INTERRUPT не равен нулю, то нужно использовать другой плеер:
            DI
            CALL INIT
    LOOP:   IM 1
            EI
            HALT
            CALL INTERRUPT
            JR LOOP
    
  8. Загрузить все блоки для данной песни.
  9. Загрузить в нижние половинки общих регистров Z80, включая флаговые, значение LoReg.
  10. Загрузить в верхние половинки регистров Z80 значение HiReg.
  11. Загрузить в регистр I значение 3 (номер версии плеера).
  12. Загрузить в регистр SP значение Stack.
  13. Загрузить в PC значение 0.
  14. Запретить прерывания и установить режим IM0.
  15. Произвести сброс AY.
  16. Запустить эмуляцию Z80.

Обратите внимание, что блоки можно загружать прямо поверх стандартного плеера. Вы можете использовать это, когда возникает необходимость использовать свои коды проигрывателя вместо стандартного. В этом случае, можно помещать плеер по адресу INIT или даже #0001. Вообще, блоки данных можно загружать по любому адресу, кроме 0.

Ay_Emul работает как проигрыватель версии 3.

Тип 'AMAD'

Запись "Данные песни" для типа 'AMAD' имеет следующую структуру:

СмещениеДлина в байтахОбозначениеОписание
+02AllocAddressАдрес расположения блока данных в памяти ZX Spectrum.
+21AndsixДанный параметр равен либо 31, либо 15 и отражает особенность некоторых плееров Amadeus, в которых по команде AND после сложения текущего значения шума с параметром команды 8D (добавка к шуму) происходит обрезание результата до 5 или 4 бит соответственно.
+31LoopsКоличество повторов (loops).
+42LoopLenДлина мелодии (одного loop) в прерываниях.
+62FadeOffsetPrecise fade specification (не используется в Ay_Emul)
+82FadeLenHow long to fade (не используется в Ay_Emul)
+101AChanНазначение аналогично типу 'EMUL'.
+111BChanНазначение аналогично типу 'EMUL'.
+121CChanНазначение аналогично типу 'EMUL'.
+131NoiseНазначение аналогично типу 'EMUL'.
+14???ZXDataОригинальный блок данных с ZX Spectrum. Полное описание этого блока приведено в описании формата FXM.

Тип 'ST11'

Запись "Данные песни" для типа 'ST11' имеет следующую структуру:

СмещениеДлина в байтахОбозначениеОписание
+01AChanНазначение аналогично типу 'EMUL'.
+11BChanНазначение аналогично типу 'EMUL'.
+21CChanНазначение аналогично типу 'EMUL'.
+31NoiseНазначение аналогично типу 'EMUL'.
+44UnknownВ существующих файлах здесь обычно последовательность (0,0,0,50), но есть один с (0,0,0,255).
+8???ZXDataОригинальный блок данных с ZX Spectrum. Полное описание этого блока приведено в описании формата ST1.

Дальнейшее развитие: как вы можете помочь?

Теперь немного о недостатках формата и о том, как именно описанные правила применяются в Ay_Emul.

Первый недостаток заключён в том, что спецификация допускает понятие "бесконечное проигрывание", то есть когда значение поля SongLength равно нулю. В Ay_Emul такого понятия нет, и поэтому такие файлы вместо "бесконечности" будут проигрываться 15000 прерываний.

Второй недостаток заключается в неясности термина "1/50 секунды".

Если это период прерываний ZX Spectrum, то он зависит от двух параметров – частоты Z80 и количества тактов Z80 между прерываниями (по крайней мере, так реализованы отечественные аналоги ZX Spectrum). Однако ни в спецификации по AY-файлам, ни по проигрывателям, ничего не сказано о значениях для этих параметров. В Ay_Emul по умолчанию используются частота Z80 3494400 Гц и период прерываний 69888 тактов (то есть получается та самая 1/50 секунды).

Но если музыка играется без синхронизации с прерываниями, то отсутствие данных о частоте процессора уже критично: если человек, создающий AY-файл, измеряет длительность и переводит её в указанные единицы для одной частоты CPU, а проигрыватель у конечного пользователя играет на другой, то файл либо не доиграется до нужного момента, либо проиграется дальше, чем надо.

Третий недостаток заключается в том, что нет возможности загрузить блок по адресу #0000, поскольку нулевое слово означает конец последовательности блоков данных. Эта проблема может быть решена за счёт того, что самый первый блок может иметь нулевой адрес, однако для совместимости с другими версиями AY-проигрывателей на Amiga и на PC в Ay_Emul это не сделано.

Ещё можно добавить, что формат AY подразумевает только модель памяти 48К. Однако, музыку, которую было бы нельзя впихнуть в рамки 48К памяти не так уж и много.

Развитие формата на PC произошло благодаря James McKay, который реализовал поддержку бипера. Однако его утилита AYMake не поддерживает поля, связанные с продолжительностью звучания модулей и по сети разошлось множество AY-файлов без этой важной информации.

Команда Project AY (энтузиасты формата во главе с bcass) переделала многие существовавшие на тот момент AY-файлы, добавив в них эту информацию, а также существенно пополнила коллекцию.

Patrik Rak выпустил plug-in для DeliPlayer, и теперь мы можем увидеть авторский вариант поддержки AY-файлов на PC.

Tim Fardel сделал плеер SpecAY для реального ZX Spectrum, в результате большую часть коллекции возможно послушать на родном оборудовании.

Ну а с остальными достоинствами и недостатками AY-файлов вы можете разобраться сами, если решите вплотную заняться доработкой существующих или выдиранием новых из программ Speccy. Мои утилиты с исходными текстами для создания и работы с AY-файлами (AYMakeR, aysplitr, ay2sna) вы можете найти на официальном сайте Ay_Emul.

Продолжительность звучания поможет определить утилита YMTOOL.EXE от Arnaud Carre: достаточно конвертировать AY-файл в YM6, задав продолжительность 10–30 минут, и утилита поможет найти тело цикла.