Немига/Звук
< Немига
Этот документ создан для Emuverse и распространяется на условиях лицензии CC-BY-SA-3.0. |
Вызов SOUND
Системная программа SOUND делает следующее:
- Смотрит откуда она вызвана, пропускает одно слово
- Следующее слово трактуется как адрес начала мелодии
- Дальше запускает мелодию на исполнение -- см. Кодирование мелодии ниже
Поэтому, вызов SOUND выглядит примерно так:
jsr pc,.sound br 1$ .word melody 1$: ............ ............ ............ melody: .byte ......... ; мелодия .byte 0 ; индикатор конца мелодии
Кодирование мелодии
- Первым должен быть байт октавы и громкости — Двузначное восьмеричное число (см. описание регистра 170030)
- Далее следуют два байта :
- Байт с номером ноты (бит 7=1, то есть коды от 200 до 214)
- Байт с длительностью (в 1/50 долях секунды)
- Далее повторяются два байта, задающие ноту и ее длительность, а при необходимости, перед ними может стоять байт октавы и громкости.
- Мелодия заканчивается байтом, содержащим нули в разрядах 0..4 и 7. Комбинация разрядов 5 и 6 определяют способ завершения мелодии:
- 000 — никаких действий не производится
- 040 — прерывание по вектору 110
- 100 — зацикливание мелодии
- 140 — очистка байта, следующего после индикатора конца мелодии
Управляющие регистры таймера и звука
RgStSnd - 170020 - регистр состояния RgF - 170022 - регистр частоты -- счётчик 1 RgLength - 170024 - регистр длительности -- счётчик 2 RgOn - 170026 - включение звука (обращение) RgOct - 170030 - регистр октавы и громкости RgOff - 170032 - выключение звука (обращение)
170020 Регистр состояния программируемого таймера ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ │15│14 13 12│11 10 9│ 8 7 6│ 5 4 3│ 2 1 0│ └──┴──┴──┴──┴──┴──┴─┬┴─┬┴─┬┴─┬┴─┬┴─┬┴─┬┴─┬┴─┬┴─┬┘ Фикс прерывания 2 ─┘ │ │ │ │ │ │ │ │ └─ ?? Фикс прерывания 1 ─┘ │ │ │ │ │ │ └ Режим работы 1-го счётчика Блокировка ЗПР2 ─┘ │ │ │ └──┴─ Режим пуска 1-го счётчика Блокировка ЗПР1 ─┘ │ │ 0 1 блокировка счётчика │ │ 1 0 запуск по CO1 │ │ 1 1 запуск по C1 └──┴─ Режим пуска 2-го счётчика 0 1 блокировка счётчика 1 0 запуск по CO2 1 1 запуск по C2
170030 Регистр октавы и громкости ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ │15│14 13 12│11 10 9│ 8 7 6│ 5 4 3│ 2 1 0│ └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴─┬┴─┬┴─┬┴─┬┴─┬┘ │ │ └──┴──┴─ Октава 1..7 └──┴─ Громкость 0..3
Работа со звуком в ПЗУ Немига 3.03
Точка входа подпрограммы SOUND в начале ПЗУ:
160126: JMP @177754 ; SOUND
Звук нажатия клавиши:
160360: TSTB @#177761 ; Флаг блокировки вызова SOUND 160364: BNE 160402 ; <> 0 => не вызывать повторно 160366: CALL @#160126 ; SOUND 160372: BR 160402 160374: DW 160376 ; Адрес мелодии 160376: DB 011, 214, 001, 000 ; Мелодия -- звук длиной 1/50 сек
Обработка продолжения SOUND в обработчике прерывания HALT:
160602: BIT #010000, @#170006 ; Сигнал Н3? 160610: BEQ 161060 ; Нет => Завершаем обработку прерывания HALT ; Обработка сигнала Н3 160612: MOV R4, -(SP) ; Сохраняем R4 160614: TSTB @#177761 ; Флаг блокировки SOUND 160620: BPL 160746 ; bit7=0 - блокировано => переходим 160622: MOV @#177752, R4 ; Берём адрес продолжения мелодии 160626: INCB @#177760 ; Увеличиваем счётчик?? 160632: CMPB @#177760, 177777(R4) ; Сравниваем с длительностью ноты 160640: BLO 160746 ; пока не кончилась => переходим 160642: TSTB (R4) ; 200 ? 160644: BMI 160742 ; да => переходим 160646: BITB #000037, (R4) ; Есть ещё нота мелодии? 160652: BNE 160736 ; да => переходим 160654: BICB #000200, @#177761 ; Снимаем флаг блокировки SOUND ; Обработка флагов завершения мелодии 160662: BITB #000040, (R4) ; 040 и 140 ? 160666: BNE 160712 ; да => переходим 160670: TSTB (R4) ; 000 ? (никаких действий по окончании мелодии) 160672: BEQ 160746 ; да => переходим 160674: MOV @#177750, @#160710 ; Копируем адрес начала мелодии?? 160702: CALL @#160126 ; SOUND 160706: BR 160746 160710: DW ?? ; Окончание мелодии 160712: BITB #000100, (R4)+ 160716: BNE 160732 160720: MOV (SP)+, R4 160722: CLRB @#170006 ; Переход на прерывание по вектору 110 160726: MOV @#000110, PC ; Очистка байта после мелодии 160732: CLRB (R4) 160734: BR 160746 ; 160736: MOVB (R4)+, @#170030 ; Октава и громкость 160742: CALL @#162560 ; Обработка продолжения мелодии
Подпрограмма SOUND:
162474: MOV R4, -(SP) ; Сохраняем R4 162476: BICB #000200, @#177761 ; Предотвращаем повторный вызов SOUND: bit7=0 162504: CLR @#170024 ; Сброс таймер 2 (длительности) 162510: MOV 000002(SP), R4 ; Откуда вызвали SOUND 162514: MOV 000002(R4), R4 ; Получаем адрес мелодии 162520: TSTB (R4) 162522: BEQ 162554 162524: MOV R4, @#177750 ; Запоминаем адрес начала мелодии 162530: MOV #001516, @#170020 ; Пишем в регистр состояния таймера 162536: MOVB (R4)+, @#170030 ; Октава и громкость 162542: CALL @#162560 ; Обработка продолжения мелодии 162546: BISB #000200, @#177761 ; Возвращаем флаг блокировки SOUND: bit7=1 162554: MOV (SP)+, R4 ; Восстанавливаем R4 162556: RETURN ; 162560: MOV R3, -(SP) ; Сохраняем R3 162562: MOVB (R4)+, R3 162564: BIC #177760, R3 ; Оставляем нижние 4 бита -- 00..17 162570: ASL R3 ; и умножаем на 2 162572: MOV 162624(R3), @#170022 ; Выбираем по R3 слово и пишем в первый счётчик 162600: MOVB (R4)+, @#170024 ; Задаём длительность 162604: CLRB @#177760 ; Очищаем счётчик?? 162610: MOV R4, @#177752 ; Запоминаем адрес продолжения мелодии 162614: TST @#170026 ; Устанавливаем триггер таймера 162620: MOV (SP)+, R3 ; Восстанавливаем R3 162622: RETURN ; Значения задержки первого таймера для нот 162624: DW 000000, 003570, 003414, 003246, 003110, 002754, 002630, 002510 162644: DW 002374, 002264, 002160, 002061, 001764, 000000, 000000, 000000
Переменные:
177750: DW ; Адрес начала мелодии 177752: DW ; Текущий адрес мелодии 177760: DB ; Счётчик 177761: DB ; Флаги
Работа этого кода предполагает, что каждые 1/50 секунды будет генерироваться прерывание HALT с выставленным сигналом Н3. Также это используется для организации мигания курсора.
Работа со звуком в ПЗУ Немига 4.06
Подпрограмма SOUND:
162426: MOV R4, -(SP) ; Сохраняем R4 162430: BICB #000200, @#177761 162436: CLR @#170024 ; Сброс таймер 2 (длительности) 162442: MOV 000002(SP), R4 ; Откуда вызвали SOUND 162446: MOV 000002(R4), R4 ; Получаем адрес мелодии 162452: BNE 162460 162454: MOV @#177750, R4 162460: TSTB (R4) 162462: BEQ 162514 162464: MOV R4, @#177750 162470: MOV #001516, @#170020 ; Пишем в регистр состояния таймера 162476: MOVB (R4)+, @#170030 ; Октава и громкость 162502: CALL @#162520 ; Обработка продолжения мелодии 162506: BISB #000200, @#177761 ; Возвращаем флаг блокировки SOUND: bit7=1 162514: MOV (SP)+, R4 ; Восстанавливаем R4 162516: RETURN ; Обработка продолжения мелодии 162520: MOV R3, -(SP) ; Сохраняем R3 162522: MOVB (R4)+, R3 162524: BIC #177760, R3 ; Оставляем нижние 4 бита -- 00..17 162530: ASL R3 ; и умножаем на 2 162532: MOV 162564(R3), @#170022 ; Выбираем по R3 слово и пишем в первый счётчик 162540: MOVB (R4)+, @#170024 ; Задаём длительность 162544: CLRB @#177760 ; Очищаем счётчик длительности ноты 162550: MOV R4, @#177752 ; Запоминаем адрес продолжения мелодии 162554: TST @#170026 ; Устанавливаем триггер таймера 162560: MOV (SP)+, R3 ; Восстанавливаем R3 162562: RETURN ; Значения задержки первого таймера для нот 162564: DW 000000, 002253, 002150, 002050, 001755, 001664, 001577, 001515 162604: DW 001435, 001361, 001306, 001237, 001171, 000000, 000000, 000000
Звук в Бейсик Вильнюс
После ввода оператора PLAY "AB"
, Бейсик выполняет какие-то действия, и затем ожидает в следующем цикле:
065170: CMP R2, @#001456 065174: BNE 065270 065176: ADD #000005, R2 065202: CMP R2, @#177752 065206: BLOS 065262 065210: SUB #000005, R2 065214: CMP R2, @#177752 065220: BLOS 065162 065162: CALL 065372 065372: BICB #000177, @#177761 065400: BEQ 065426 065402: CMP @#177752, #001624 065410: BLO 065426 065412: CMP @#177752, #001663 065420: BHI 065426 065422: ADD #000002, (SP) 065426: RETURN 065170: CMP R2, @#001456