GEMS: Genesis Editor for Music and Sound effects В этой статье пойдет речь об одном очень популярном звуковом движке в играх SMD/Genesis, который носит название GEMS. Он используется в таких достаточно известных и неплохих играх как: Zero Tolerance, Dune: The Battle for Arrakis, Earthworm Jim, Comix Zone и еще куче других. В отличие от своего «коллеги» движка SMPS, GEMS таких ярких разновидностей не имеет. Всю музыку играет здесь z80 с небольшой помощью M68k. Наблюдается комбинированная работа двух этих процессоров. Надо сказать, что некоторое время назад в общий доступ была выложена среда разработки музыки для данного движка и внутри есть неплохая документация о его фичах, но нет таковой о структуре самих данных. Здесь я постараюсь об этом по возможности рассказать.
Составные части мелодии
Вся музыка в формате GEMS лежит в роме в так называемых банках. Используется 4 банка данных GEMS: 1. Patches bank – банк инструментов 2. Sequences bank – банк нотных последовательностей каждой мелодии 3. Modulation bank – банк частотных модуляции 4. Samples bank – банк с PCM сэмплами (DAC) Все оффсеты в банках относительно начала банка. Все банки подвижные: без изменений содержимого банка, его можно передвинуть. По умолчанию все числа/оффсеты little-endian, если не сказано иное. Обозначения: .b – byte = 1 byte .w – word = 2 byte .l – long = 4 byte .v – varies = 2 or 3 byte (в зависимости от игры)
1. Sequence bank структура Общий вид данных в банке следующий: [поинтер на мелодию 0].w [поинтер на мелодию 1].w … мелодия 0 [кол-во каналов].b [поинтеры на каналы].v ; оффсет из двух или трёх байтов. ... мелодия 1 [кол-во каналов].w [поинтеры на каналы].v ; оффсет из двух или трёх байтов. ... мелодия 0 канал 0 [последовательность нот/команд канала] мелодия 0 канал 1 [последовательность нот/команд канала] ...
По поводу .v: в зависимости от конкретной версии движка, одни игры используют в этом месте оффсеты из двух байтов, а другие – из трёх байтов. Примеры игр в которых .v = 3 byte: Comix Zone, Donald In Maui Mallard. Хоть и известные версии GEMS нумеруются 2.0, 2.1...2.8, на самом деле различных версий на много больше, так как разработчики многих игр не поленились, и модифицировали GEMS под свою игру.
Последовательности нот/команд начинают выполнятся одновременно во всех каналах. Так что секвенцией здесь, будем называть весь "пучок" каналов. Оффсеты на канал, указывают на место, откуда начинать выполнять (воспроизводить), так что любой канал любой секвенции может ссылаться на последовательность любого другого канала любой другой секвенции. Но на деле, это не наблюдается.
В банке секвенций - не может содержаться больше 128 ($80) секвенций. По этому в некоторых играх, таких банка два. Пример: Mortal Kombat 3.
Dynamic Voice Allocation
Как видите, у каждой мелодии есть свое количество каналов, прямо как в SMPS. Однако GEMS использует свои каналы, которые не связаны с каналами звука Ямахи или PSG. И этих каналов максимум может быть 16! Как же так, скажете вы, ведь на SMD максимум звуковых каналов может быть всего 10 (6 FM/(5 FM + DAC), 4 PSG). Все просто. Используется так называемое динамическое распределение нот по каналам, которым занимается z80. Облегчили, блин, жизнь разработчикам, а хакерам наоборот усложнили! Распределение идет относительно от используемого голоса/инструмента в данный момент времени и от того свободен ли канал или нет. В итоге, неизвестно в каком канале будет играть та или иная нота, до тех пор, пока не придет время воспроизвести ее! Более подробно, в каждый момент времени GEMS помнит, какой канал, и с каким приоритетом занят. Канал занимается в момент попытки воспроизвести ноту, а освобождается тогда, когда длительность ноты закончилась. Если в момент попытки воспроизвести ноту, есть свободный подходящий канал, то его смело занимаем. Если такого не нашлось, ищем подходящий канал с наименьшим приоритетом, и если его приоритет меньше или равный, то занимаем его. Иначе, нота не будет воспроизведена. Каналы подходящие для инструмента: FM – FM 0-5 PSG – PSG 0-3 DAC – FM 5 NOISE – PSG 3 Темп, таймеры и отсчет времени В движке GEMS существует три таймера: таймер мелодии, таймер звуков, и таймер PCM (DAC). У каждого канала секвенции (последовательности), есть возможность выбрать таймер между таймером мелодии, и таймером звуков. По умолчанию, все каналы секвенции воспроизводятся основываясь на таймере мелодии.
Таймер мелодии – это таймер, который используется мелодиями, чтобы отсчитывать время продолжительностей и задержек последовательностей нот и команд. Таймер мелодии существует на все мелодии один, и чтобы его выставить, нужно использовать команду $68. Таймер мелодии указывается в BPM – тактов в минуту. Длительности и задержки нот, отсчитываются в 1/24 такта (beat). То есть, максимальная точность ритма – 1/24. Другими словами, вы не сможете воспроизводить ноты длительностью 1/32 такта, в терминах GEMS. Но, это можно достичь повышая темп. Если темп повысить в 32/24=4/3 раз, то возможно будет воспроизвести ноты длительностью 1/32 такта старого темпа, но в новом. По этому в некоторых играх такты не совпадают логически, с ритмом музыки.
Таймер звуков – это таймер, который используется звуковыми эффектами (SFX), чтобы их длительности и задержки, не зависили от темпа текущей фоновой музыки. Хорошим тоном является указание всем каналам звуковых эффектов, использование этого темпа. Делается это командой $6D. Темп SFX таймера равен 150 BPM.
Таймер PCM (DAC) – это таймер используемый для воспроизведения PCM/DAC, он работает с частотой указанной дискретизации PCM. Так как в сеге есть только один канал для воспроизведения PCM(DAC), то и таймер для него один. Стандартный GEMS не поддерживает воспроизведение двух PCM одновременно (мультиплексирование), и по этому каждый раз во время попытки воспроизведения, проверяет приоритет текущего воспроизводимого PCM. И если же так случилось, что мы воспроизводим новый PCM, то выбирается частота дискретизации в соответствии с настройкой инструмента, и настройкой самого сэмпла. В инструменте DAC указывается какую частоту использовать: либо конкретную, либо указанную в банке сэмплов для конкретного сэмпла.
Структура нотной последовательности Также как и в SMPS, мелодия на движке GEMS состоит из самих нот, байтов, задающих длительность ноты, а также команд. Но в отличие от того же SMPS, здесь длительность ноты задается до воспроизведения ноты. То есть допустим, в SMPS, чтобы проиграть ноту С0 нужно было записать: $8105, где 5 – длительность ноты. В GEMS это по-другому. В начале, пишется байт, характеризующий текущую величину продолжительности звучания, а потом все последующие ноты играют с данной продолжительностью, пока снова не встретится байт, отвечающий за текущую продолжительность. Еще существуют так называемые «ожидания» – величины простоя после начала воспроизведения ноты или выполнения команды.
Величины нот/команд лежат в следующих диапазонах: $0-$5F: note – Нота $60-$72: cmd – Команда $80-BF: duration – Величина продолжительности звучания нот (сама величина лежит в младших 6 битах) $C0-FF: delay – Величина ожидания (сама величина лежит в младших 6 битах) Числа с $73 до $7F не используются. После всех команд, кроме $60, $64, $65, $6F следует ожидание.
Подробнее о duraions и delays. Для каждого канала в памяти хранится последнее значение duration, delay. Обе величины измеряются в 1/24 долях Beat. Длительность Beat задается темпом мелодии – команда $68. Если в последовательности встречается команда delay или duration, то новое значение сохраняется. Несколько подряд идущих команд duration воспринимаются как одна команда duration, а биты величины объединяются, первый байт – старшие биты, то есть big-endian. Например: 85 A7 в hex 1000 0101 1010 0111 в двоичном 00 0101 10 0111 выбрали значащие 6 бит 01 67 результат в hex Аналогично делается с delays. duration – длительность ноты. delay – промежуток времени между началами нот. Описание команд
$60 Конец последовательности. После этой команды нет delay. $61 Задать номер инструмента для канала. Имеет 1 байт параметр – номер в банке инструментов. $62 Задать номер модуляции для инструмента. Имеет 1 байт параметр – номер в банке модуляций. $63 Ничего не делает. NOP. $64 Начало цикла. Имеет байт параметр, задающий кол-во повторений цикла. Значение $7F для бесконечного цикла. После этой команды нет delay. $65 Конец цикла. После этой команды нет delay. $66 Вкл/выкл retrigger mode у текущего канала. Имеет 1 байт параметр – равный нулю, если выключить, и не равный нулю иначе. Retrigger envelopes mode – означает непрерывное повторение envelope модуляции. В противном случае, envelope срабатывает только во время команды выбора модуляции, и начала ноты, после чего не повторяется. $67 Вкл/выкл sustain mode у текущего канала. Имеет 1 байт параметр – равный нулю, если выключить, и не равный нулю иначе. Sustain mode – это метод эмуляции MIDI контроллера sustain (педаль). При включении sustain, зажимается педаль, при выключении – отпускается. Во время включенного sustain mode, движок GEMS старается на сколько может, меньше прерывать ноты которые были начаты ранее на этом канале. $68 Задать скорость (tempo, темп) для мелодии. Имеет 1 байт параметр – значение скорости в BPM (Beats Per Minute). Результирующий темп после команды, будет равным значению параметра + 40 (в BPM). Темп один на весь GEMS. Другими словами, темп работает глобально. Темп вычисляется достаточно точно на NTSC. На PAL приставке, не правильное вычисление темпа в GEMS приведет к замедлению мелодии в 5/6 раз. $69 Выключить звук у канала (Mute). Имеет 1 байт параметр в формате ???TСCCC. Где T - включить(1)/выключить(0) канал С(0-15). $6A Установить приоритет канала. 0 – самый низкий, $7F – самый высокий. Имеет 1 байт параметр – величина приоритета. Приоритет учитывается в момент начала воспроизведения ноты. $6B Начать воспроизведение другой мелодии. Имеет байт параметр – номер мелодии в банке секвенций. $6C Модуляция. Меняет pitch. Имеет параметр 2 байта – величина pitch. Первый байт – полутон (semitone). Второй байт – дробная часть тона. $6D "Set song to use SFX timebase." Использовать для канала темп SFX = 150 BPM. $6E Установить скорость проигрывания сэмплов DAC. Имеет 1 байт параметр – величина скорости. $6F Прыжок на назначенную позицию. Имеет параметр 2 байта – знаковый оффсет куда прыгать. Оффсет отсчитывается от конца команды, то есть, после последнего байта параметра. Первый байт – младший, второй байт – старший. $70 Записать величину в один из «контейнеров». Имеет 2 параметра – первый: номер контейнера, второй: записываемое значение. $71 Прыжок по условию (оператор ЕСЛИ). Следующие 4 байта имеют вид: [контейнер #][условие][значение][оффсет]. Номер условия – Само условие 1 контейнер != значение 2 контейнер > значение 3 контейнер >= значение 4 контейнер < значение 5 контейнер <= значение остальные числа контейнер == значение Если условие истинно, НЕ происходит прыжок по заданному оффсету, если нет, то происходит. То есть, оффсет указан на "иначе". Оффсет отсчитывается от конца команды, то есть, после последнего байта параметров. $72 Макро команда. Следующий 2 байта имеют вид [# под-команды][параметр]: Команда – действие 0 Остановить последовательность, указанную в параметре. 1 Поставить последовательность на паузу, указанную в параметре. 2 Восстановить воспроизведение всех последовательностей. Параметр не используется. 3 Поставить мелодию на паузу, которая указанна в контейнере под номером 0. Параметр не используется. 4 Задать глобальную громкость. Имеет байт параметр – величина громкости (0 – самая громкая, $7F – самая тихая). 5 Задать громкость канала. Имеет байт параметр – величина громкости (0 – самая громкая, $7F – самая тихая). Величины с $73 до $7F не являются командами и драйвером не используются!
Инструменты GEMS. GEMS позволяет использовать больше возможностей звукового чипа Yamaha, нежели SMPS, поэтому данных о инструментах для гемса больше. В GEMS существует четыре типа инструментов:
0 – FM 1 – DAC 2 – PSG 3 – Noise О каждом можно почитать где-нибудь в другом месте, здесь же я представлю формат в котором они хранятся в GEMS. Для каждого инструмента, первым байтом является тип инструмента. Но для большей интуитивности, я буду указывать этот байт во всех инструментах. 0. Формат FM инструмента. |??????tt| - type |????ovvv| - LFO on, LFO value (register 22 LFO bits) |mm??????| - Channel 3 mode (register 27 channel 3 bits) |??fffaaa| - Feedback, Algorithm (raw register B0) |lraa?fff| - Left/Right, AMS, FMS (raw register B4) 4 operators: (4 times) in order 1,3,2,4 |?dddmmmm| - Detune, Multiply (raw register 30) |?ttttttt| - TLevel (raw register 40) |rr?aaaaa| - Rate Scale, Attack (raw register 50) |a??ddddd| - AM, Decay (raw register 60) |???sssss| - Sustain (raw register 70) |ssssrrrr| - Sustain Level, Release (raw register 80)
|??ffffffffffffff| - 14-bit frequency channel 3 mode operator 4 (A6, A2) |??ffffffffffffff| - 14-bit frequency channel 3 mode operator 3 (AC, A8) |??ffffffffffffff| - 14-bit frequency channel 3 mode operator 1 (AD, A9) |??ffffffffffffff| - 14-bit frequency channel 3 mode operator 2 (AE, AA)
|????kkkk| - Operator On ("Key") - bit for each operator in 4,3,2,1 order |????????| 1: Формат DAC инструмента. |??????tt| - type |??????ss| - DAC Sample Rate (в значениях GEMS) Значение 4 - зарезервировано, означает - брать Sample Rate из описания в банке DAC 2: Формат PSG/NOISE инструмента. (0 - громко, $F - тихо)
Offset | Notation | Range | 0 | Type | 2 or 3 | 1 | Noise Data | [0,7] | 2 | Attack Rate | [0,$FF] | 3 | Sustain Level | [0,$F] | 4 | Attack Level | [0,$F] | 5 | Decay Rate | [0,$FF] | 6 | Release Rate | [0,$FF] |
Внес коррективы, и добавления: r57shell. Последнее обновление 30.01.2014
|