Немига/Звук: различия между версиями
< Немига
Nzeemin (обсуждение | вклад) (Новая страница: «{{Emuverse}} = Работа со звуком в ПЗУ Немига 3.03 = Точка входа подпрограммы SOUND в начале ПЗУ: <pre> 1…») |
Nzeemin (обсуждение | вклад) Нет описания правки |
||
(не показано 8 промежуточных версий 2 участников) | |||
Строка 1: | Строка 1: | ||
{{Emuverse}} | {{Emuverse}} | ||
{{TOCright}} | |||
== Вызов SOUND == | |||
Системная программа SOUND делает следующее: | |||
# Смотрит откуда она вызвана, пропускает одно слово | |||
# Следующее слово трактуется как адрес начала мелодии | |||
# Дальше запускает мелодию на исполнение -- см. Кодирование мелодии ниже | |||
Поэтому, вызов SOUND выглядит примерно так: | |||
<pre> | |||
jsr pc,.sound | |||
br 1$ | |||
.word melody | |||
1$: ............ | |||
............ | |||
............ | |||
melody: .byte ......... ; мелодия | |||
.byte 0 ; индикатор конца мелодии | |||
</pre> | |||
== Кодирование мелодии == | |||
# Первым должен быть байт октавы и громкости — Двузначное восьмеричное число (см. описание регистра 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 - выключение звука (обращение) | |||
<pre> | |||
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 | |||
</pre> | |||
<pre> | |||
170030 Регистр октавы и громкости | |||
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ | |||
│15│14 13 12│11 10 9│ 8 7 6│ 5 4 3│ 2 1 0│ | |||
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴─┬┴─┬┴─┬┴─┬┴─┬┘ | |||
│ │ └──┴──┴─ Октава 1..7 | |||
└──┴─ Громкость 0..3 | |||
</pre> | |||
= Работа со звуком в ПЗУ Немига 3.03 = | == Работа со звуком в ПЗУ Немига 3.03 == | ||
Точка входа подпрограммы SOUND в начале ПЗУ: | Точка входа подпрограммы SOUND в начале ПЗУ: | ||
Строка 99: | Строка 160: | ||
177761: DB ; Флаги | 177761: DB ; Флаги | ||
</pre> | </pre> | ||
Работа этого кода предполагает, что каждые 1/50 секунды будет генерироваться прерывание HALT с выставленным сигналом Н3. | |||
Также это используется для организации мигания курсора. | |||
== Работа со звуком в ПЗУ Немига 4.06 == | |||
Обработка продолжения SOUND в обработчике прерывания HALT: | |||
<pre> | |||
160610: BIT #010000, @#170006 ; Сигнал Н3? | |||
160616: BEQ 161074 ; Нет => Завершаем обработку прерывания HALT | |||
; Обработка сигнала Н3 | |||
160620: MOV R4, -(SP) ; Сохраняем R4 | |||
160622: TST @#177760 ; Флаг блокировки SOUND | |||
160626: BPL 160750 ; bit7=0 => переходим | |||
160630: MOV @#177752, R4 ; Берём адрес продолжения мелодии | |||
160634: INCB @#177760 ; Увеличиваем счётчик длительности ноты | |||
160640: CMPB @#177760, 177777(R4) ; Сравниваем с длительностью ноты | |||
160646: BLO 160750 ; пока не кончилась => переходим | |||
160650: TSTB (R4) ; 200 ? | |||
160652: BMI 160744 ; да => переходим | |||
160654: BITB #000037, (R4) ; Есть ещё нота мелодии? | |||
160660: BNE 160740 ; да => переходим | |||
160662: BIC #100000, @#177760 ; Снимаем флаг блокировки SOUND | |||
; Обработка флагов завершения мелодии | |||
160670: BITB #000040, (R4) ; 040 и 140 ? | |||
160674: BNE 160712 ; да => переходим | |||
160676: TSTB (R4) ; 000 ? (никаких действий по окончании мелодии) | |||
160700: BEQ 160750 ; да => переходим | |||
160702: CALL @#160126 ; SOUND | |||
160706: BR 160750 | |||
160710: DW 000000 | |||
; Окончание мелодии | |||
160712: BITB #000100, (R4)+ | |||
160716: BNE 160734 | |||
160720: MOV (SP)+, R4 | |||
; Переход на прерывание по вектору 110 | |||
160722: MOV @#000112, -(SP) | |||
160726: MOV @#000110, -(SP) | |||
160732: BR 161074 | |||
; Очистка байта после мелодии | |||
160734: CLRB (R4) | |||
160736: BR 160750 | |||
; | |||
160740: MOVB (R4)+, @#170030 ; Октава и громкость | |||
160744: CALL @#162520 ; Обработка продолжения мелодии | |||
</pre> | |||
Подпрограмма SOUND: | |||
<pre> | |||
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 | |||
</pre> | |||
== Звук в Бейсик Вильнюс == | |||
После ввода оператора <code>PLAY "AB"</code>, Бейсик выполняет какие-то действия, и затем ожидает в следующем цикле: | |||
<pre> | |||
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 | |||
</pre> | |||
[[Категория:Немига]] |
Текущая версия от 23:35, 5 апреля 2018
Этот документ создан для 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 в обработчике прерывания HALT:
160610: BIT #010000, @#170006 ; Сигнал Н3? 160616: BEQ 161074 ; Нет => Завершаем обработку прерывания HALT ; Обработка сигнала Н3 160620: MOV R4, -(SP) ; Сохраняем R4 160622: TST @#177760 ; Флаг блокировки SOUND 160626: BPL 160750 ; bit7=0 => переходим 160630: MOV @#177752, R4 ; Берём адрес продолжения мелодии 160634: INCB @#177760 ; Увеличиваем счётчик длительности ноты 160640: CMPB @#177760, 177777(R4) ; Сравниваем с длительностью ноты 160646: BLO 160750 ; пока не кончилась => переходим 160650: TSTB (R4) ; 200 ? 160652: BMI 160744 ; да => переходим 160654: BITB #000037, (R4) ; Есть ещё нота мелодии? 160660: BNE 160740 ; да => переходим 160662: BIC #100000, @#177760 ; Снимаем флаг блокировки SOUND ; Обработка флагов завершения мелодии 160670: BITB #000040, (R4) ; 040 и 140 ? 160674: BNE 160712 ; да => переходим 160676: TSTB (R4) ; 000 ? (никаких действий по окончании мелодии) 160700: BEQ 160750 ; да => переходим 160702: CALL @#160126 ; SOUND 160706: BR 160750 160710: DW 000000 ; Окончание мелодии 160712: BITB #000100, (R4)+ 160716: BNE 160734 160720: MOV (SP)+, R4 ; Переход на прерывание по вектору 110 160722: MOV @#000112, -(SP) 160726: MOV @#000110, -(SP) 160732: BR 161074 ; Очистка байта после мелодии 160734: CLRB (R4) 160736: BR 160750 ; 160740: MOVB (R4)+, @#170030 ; Октава и громкость 160744: CALL @#162520 ; Обработка продолжения мелодии
Подпрограмма 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