О звуковых каналах GBA
У GBA есть шесть звуковых каналов. Сегодня мы изучим только первые 4 (1-4), которые используются внутренним GBC GBA. Другие два канала - это прямые звуковые каналы, которые могут проигрывать сконвертированные звуковые файлы - о них мы сегодня говорить не будем. ПРИМЕЧАНИЕ: термин "direct sound" в данном контексте является не более чем полуофициальным названием 5 и 6 звуковых каналов GBA и никак не связан с DirectSound, который является частью мультимедийной библиотеки для Windows от Microsoft.
Чтобы мы могли воспользоваться определенными преимуществами, даруемые написанными мною самим макросами и константами, скачайте, пожалуйста, sound.h.
Сегодня мы узнаем, что нужно сделать, чтобы заставить выдать спикеры какой-нибудь звук. Чтобы заставить издать какой-нибудь звук каналы 1 или 2, нужно сделать следующее:
Шаги генерации звука
Включить поддержку звука (я предоставляю макрос SoundOn)
Включить требуемый звуковой канал (я предоставляю макрос Sx_Enable, где x - это нужный вам канал).
Загрузить REG_SOUNDxCNT_L правильным значением (вам придётся сделать это самим :-) ).
Загрузить REG_SOUNDxCNT_H правильным значением (вам придётся сделать это самим).
Загрузить REG_SOUNDxCNT_X правильным значением (сами).
Вот и всё, и поверьте мне, это не так уж много, но может немного смутить.
Канал 1
Во-первых, я дам вам рабочую программу, которая генерирует звук через 1 канал.
;-- Переписано на asm вручную с исходника на BELOGIC.COM с изменениями --;
@include screen.h
@include sound.h
@include keypad.h
@textarea
SoundOn ; Шаг 1: мой макрос включает поддержку звука в REG_SOUNDCNT_X
; REG_SOUNDCNT_X контролирует всю звуковую систему.
S1_Enable ; Шаг 2: мой макрос включает первый звуковой канал.
; S2_Enable включает канал... и так до 4.
ldr r1,=REG_SOUND1CNT_L ; в этих двух строках я делаю шаги 3&4 за раз.
ldr r0,=0xf7800056
str r0,[r1] ; сохраняем данные для шагов 3&4.
ldr r1,=REG_SOUND1CNT_X ; Шаг 5: загружаем регистр.
ldr r0,=0x8400 ; Этот регистр ответственен за что-то, связанное с
str r0,[r1] ; тем, что будет делать канал.
infin ; \
; - наш типичный бесконечный цикл.
b infin ; /
;-- Заканчивайте копировать здесь --;
Я посмотрел, что написано о звуковых регистрах на BeLogic.Com и понял не всё. Основываясь на их списке регистров, у звуковых канало 2 и 4 нет REG_SOUNDxCNT_X, а их регистры REG_SOUNDxCNT_H и REG_SOUNDxCNT_L также 16-ти битны, но разделены 2 байтами, поэтому мы можем писать в них более простым образом и не должны делать шаги 3&4 за раз, а можем разделить загрузки для регистров CNT_L и CNT_H.
Похоже, что канал 3 служит для проигрывания сэмплов, поэтому я о нём больше не буду говорить.
Канал 1 - это очень приятный амплитудный звукогенератор. Поскольку я не очень хорошо понимаю уравнения, используемые на BeLogic, я не могу их объяснить (вообще). Для того, чтобы получить хоть какой-то звук мне пришлось повозиться с используемыми значениям, пока я не получил достаточно хороший эффект.
Канал 2
Канал 2 - это то же самое, что и канал 1, но генерируются только квадратные (square) волны, поэтому нам не нужен регистр REG_SOUND2CNT_X. Вот тот же самый код, подправленный для использования канала 2:
;-- CONVERTED TO ASM BY HAND FROM BELOGIC.COM WITH MODIFICATIONS --;
@include screen.h ;
@include sound.h ;
@include keypad.h ;
@textarea
SoundOn ; Шаг 1: мой макрос, который включает поддержку звука.
S2_Enable ; Шаг 2: мой макрос, включающий второй звуковой канал.
ldr r1,=REG_SOUND2CNT_L ; Шаг 3: в случае со вторым каналом на нужно
; объединять шаги 3 и 4
ldr r0,=0xff80 ; Регистры всё ещё 16-ти битны, но у нас в памяти
; есть пространство для манёвра
str r0,[r1] ; сохраняем данные
ldr r1,=REG_SOUND2CNT_H ; Шаг 4:
ldr r0,=0xf400 ; я думаю, что для повторения звука на втором
str r0,[r1] ; канале, вам необходимо инициализировать этот
; регистр снова, а если это не будет работать, то
; попробуйте проделать это с L и H.
; Шаг 5 не требуется для канала 2, так как у него нет регистра
; REG_SOUND2CNT_X. Канал 2 (и 4) не доставляют нам хлопоты, которые были у
; нас c каналом 1, так как дизайнеры системы памяти были так добры, что дали
; нам два лишних байта, дабы облегчить 32-х битное сохранение.
infin ; \
; - наш стандартный бесконечный цикл.
b infin ; /
;-- STOP COPYING HERE --;
Канал 4
Теперь давайте получим что-нибудь от канала 4. Это псевдослучайный генератор шума. В коде мы просто заменить все '2' в именах регистра на '4' и вперёд:
;-- Сконвертировано из предыдущего примера --;
;-- Код должен работать, но заставить его это сделать у меня не получилось --;
@include screen.h
@include sound.h
@include keypad.h
@textarea
SoundOn
S4_Enable
ldr r1,=REG_SOUND4CNT_L
ldr r0,=0xf700
str r0,[r1]
ldr r1,=REG_SOUND4CNT_H
ldr r0,=0x8400
str r0,[r1]
infin
b infin
;-- Заканчивайте копировать здесь --;
Я не знаю, почему этот код не заработал. Я пытался скомпилировать C-код на BeLogic, но тот код тоже на работает.
ОБНОВЛЕНИЕ: в качестве подарка на День благодарения 2002, код заработал.
Краткий итог
Обратите внимание, что я не объяснял, за что отвечает каждый бит каждого регистра. Я уже говорил, что не понимаю уравнения и определённо не понимаю даже половину содержимого на BeLogic.com. Чтобы добиться больше эффектов, поиграйтесь со значениями регистров - это единственный путь, если не смотреть мануалы на BeLogic.com. Я уже рассказал вам всё (или даже больше), что знаю о звуке в GBA, теперь идите и напишите демку с подпрыгивающими шарами (вверх и вниз) :).
Спасибо,
- Mike H a.k.a GbaGuy
- Нечто невозможное невозможно только до тех пор, пока оно не становится
возможным.
- Jean-Luc Picard, Capt., USS Enterprise
Я знаю, что уже использовал это изречение, но оно особенно подходит для программирования звука.
[C] Mike H, пер. Aquila