2.9. П р и л о ж е н и е к р а з д е л у "Ф о н о в о е м у з ы к а л ь н о е с о п р о в о ж д е н и е" ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Len_Inform EQU 000DH ; Длина блока данных Jiffy EQU 0FC9EH ; Счетчик прерываний Vibrato EQU 008 ; Отклонение частоты при вибрато ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; О с н о в н а я п р о г р а м м а. Вход может быть параллельным, ; но можно "вешать" на Hook &HFD9A, &HFD9F ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Music: PUSH HL ;WWY PUSH DE ; V PUSH BC ; TW▐ Сохранение используемых регистров PUSH AF ; V PUSH IX ; V PUSH IY ;WW[ LD A,(Jiffy) ;WWY LD B,A ; V LD A,(Timer) ; TW▐ Если нового тика не было, - то выход CP B ; V JR Z,Exit ;WW[ LD HL,P_Slot ;WWY DI ; V IN A,(0A8H) ; V LD (HL),A ; V INC HL ; TW▐ Запомним конфигурацию памяти LD A,(0FFFFH) ; V CPL ; V LD (HL),A ;WW[ PUSH HL LD DE,0FFAAH ;RWW▐ Устанавливаем свою конфигурацию: CALL Found_Slot ;[ с л о т 3-2 LD IX,Inform LD IY,All_Data LD C,001H ;Начинаем с первого голоса EXX LD B,003H ;Будем работать с тремя музыкальн. каналами LD DE,Len_Inform Label_0:EXX LD A,C OR A ;Сброс битов регистра флагов DEC (IX+000H) PUSH AF CALL NZ,Tik_mus ;Если длительность ноты не кончилась, то вы- POP AF ;полняем "попутные эффекты". CALL Z,Change ;Иначе перемещаемся по очереди данных INC C ;Переходим к следующему каналу INC C ; 1WW▐3WW▐5, что означает 1,2,3 голос EXX ADD IX,DE ;Указатель на следующий информ. блок DJNZ Label_0 LD A,(Jiffy) ;WRWW▐Считать номер тика LD (Timer),A ;W[ и сохранить для сравнения POP HL LD E,(HL) ;WWY DEC HL ; V LD D,(HL) ; TW▐Восстанавливаем конфигурацию памяти CALL Found_Slot ;WW[ Exit: POP IY ; WWY POP IX ; V POP AF ; V POP BC ; TW▐Восстанавливаем значение регистров POP DE ; V POP HL ;WWW[ RET ;WWW▐ Возврат из программы Timer: Defb 0 P_Slot: Defb 0 S_Slot: Defb 0 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Tik_mus: ;Подпрограмма "попутных эффектов" LD A,(IX+000H) ;Остался ли один тик? DEC A ;Если да и это не 1/32, то "глушим" JR NZ,g_022 LD A,(IX+01H) ;WWY CP 3 ; V RET C ; V OR A ; V LD E,C ; V RES 0,E ; V LD A,(IY+01H) ; V JR NZ,g_023 ; V LD E,C ; TW▐ Для отделения нот друг от друга g_023: OR E ; V "глушим" соответствующий канал, RL E ; V когда остается играть 1 тик RL E ; V RL E ; V OR E ; V JP Label_3 ;WW[ g_022: LD A,(IX+07H) ;WWY OR A ; T▐Если не разрешено "фокусничать", RET NZ ;WW[ то уходим молча !░WWWWWWWWWWWY LD A,(IX+12) ;WWY V OR A ; TW▐ При "Legato" обычно тоже WW[ RET Z ;WW[ CALL Select ;Можем делать вибрато, а можем и не делать ! LD A,(IX+08H) ;Если модуляция включена,то нам делать нечего CP 16 RET Z LD E,0 ;WWY LD L,A ; V LD A,(IX+001H) ; V BIT 1,(IX+002H) ; V JR Z,Tmp_1 ; V RLCA ; V Tmp_1: LD B,(IX+000H) ; V SUB B ; V LD B,A ; V Постепенно (с каждым новым тиком) LD A,L ; TWW▐ глушим все каналы, чтобы сильно не CP B ; V "пищали", так приятней слушается JR C,Gasi ; V музыка, но не забываем, что темп SUB B ; V у голосов может быть разный! RET M ; V LD E,A ; V Gasi: LD A,C ; V RRCA ; V ADD A,88H ; V JP Play ;WW[ Select: PUSH IX ;Вибрато-частотное отклонение LD IX,Golos_1 ;(причем и "+" и "-") от заданного LD E,C ;значения частоты DEC E ;Но у нас только "-",- так приятней слушать LD D,0 ; ADD IX,DE LD H,(IX+0) LD L,(IX+1) LD IX,Vibr_1 RRC E ADD IX,DE LD A,(IX+0) OR A LD E,Vibrato JR Z,Vie DEC A DEC A SBC HL,DE Vie: INC A LD (IX+0),A POP IX PUSH HL JP Leba Vibr_1: Defb 0 Vibr_2: Defb 0 Vibr_3: Defb 0 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма обработки очереди ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Change: LD L,(IX+05H) ;Достали текущий адрес данных LD H,(IX+06H) LD (IX+07H),00 ;Разрешили игру на время Label_5:CALL Command ;Анализ и выполнение команд JR Z,Label_5 ;Движемся пока на выходе Z=1 Restore:CALL Found_Len ;Установка следующей длительности LD (IX+05H),L ;Сохраняем адрес данных LD (IX+06H),H ;до следуюшего обнуления LD E,01111011B ;Запрещаем два соседних голоса LD B,C ;для "играния" обрабатываемого канала INC B Label_6:RLC E DEC B DJNZ Label_6 LD A,(IY+01H) OR E CALL Label_3 LD A,C RRCA ADD A,088H LD E,A LD A,(IX+07H) ;Если пауза или запрещен канал, OR A ;то канал молчит ! LD A,E LD E,B JR NZ,g_020 LD E,(IX+08H) g_020: CALL Play LD A,E CP 16 JR C,g_021 ;Выходим, если амплитуда <16 LD A,06H ;Восстановили значение 6 регистра LD E,(IY+00H) CALL Play ADD A,05H ;Восстановили значение 11 регистра LD E,(IY+02H) CALL Play INC A LD E,(IY+03H) ;Восстановили значение 12 регистра CALL Play INC A LD E,(IY+04H) ;Восстановили значение 13 регистра CALL Play g_021: LD A,(IY+01H) ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Found_Micsher: ;Различные операции с 7 регистром PSG LD (IY+01H),A ; Label_3:LD E,A LD A,07H Play: OUT (0A0H),A PUSH AF LD A,E OUT (0A1H),A POP AF RET ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Found_Slot: ;Установка слотовой LD A,D ;конфигурации OUT (0A8H),A LD A,E LD (0FFFFH),A RET ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Found_Len: ;Установка количества тиков XOR A ;в зависимости от длительности LD B,(IX+02H) ;и темпа F_Len: ADD A,(IX+01H) ; DJNZ F_Len LD (IX+000H),A RET ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Command: LD A,(HL) ;WWY AND 0F0H ; V RRCA ; V RRCA ; V RRCA ; V RRCA ; V LD E,A ; V LD D,0 ; V ADD A,A ; V Анализ номера команды ADD A,E ; TW▐ с последующим переходом LD E,A ; V на подпрограмму выполенния PUSH HL ; V той или иной команды LD HL,Vector ; V с первым параметром ADD HL,DE ; V EX DE,HL ; V POP HL ; V LD A,(HL) ; V AND 00FH ; V PUSH DE ; V RET ;WW[ ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Вектора переходов на подпрограммы выполнения команд ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Vector: JP Com_0 JP Com_1 JP Com_2 JP Com_3 JP Com_4 JP Com_5 JP Com_6 JP Com_7 JP Com_8 JP Com_9 JP Com_10 JP Com_11 JP Com_12 JP Com_13 JP Com_14 JP Com_15 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма меняет значения частот, когда настало время ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_0: PUSH HL LD HL,Notes DEC A ADD A,L LD L,A JR NC,g_001 INC H g_001: LD L,(HL) LD H,0 LD B,(IX+11) LD A,8 SUB B JR Z,g_002 LD B,A g_003: ADD HL,HL DJNZ g_003 g_002: Leiba: PUSH IX LD IX,Golos_1 LD E,C DEC E LD D,0 ADD IX,DE LD (IX+0),H LD (IX+1),L POP IX Leba: LD E,H LD A,C CALL Play LD E,L DEC A CALL Play POP HL INC HL INC A OR A RET Golos_1:Defw 0 Golos_2:Defw 0 Golos_3:Defw 0 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма меняет и запоминает значения 7 регистра PSG ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_1: INC HL LD A,(HL) CALL Found_Micsher g_004: INC HL XOR A RET ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма запоминает значение темпа 1 или 2 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_2: LD (IX+02H),A g_005: JR g_004 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма запоминает значения амлитуды ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_3: INC A LD (IX+08H),A g_006: JR g_005 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма запоминает значения 6 регистра PSG ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_4: ADD A,A LD (IY+00H),A g_007: JR g_006 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма запоминает значения 13 регистра PSG ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_5: LD (IY+04H),A g_008: JR g_007 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма запоминает значения 11 регистра PSG ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_6: LD E,A XOR A LD B,10 g_009: ADD A,E DJNZ g_009 LD (IY+02H),A g_010: JR g_008 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма запоминает значения 12 регистра PSG ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_7: LD E,A XOR A ADD A,E ADD A,E LD (IY+03H),A g_011: JR g_010 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма меняет и запоминает длительность ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_8: LD E,11000000B LD D,10111111B LD B,A RRC B SUB B CP B JR Z,g_013 RLC B INC B RRC B g_012: RRC E DJNZ g_012 LD A,B OR E JR g_014 g_013: RRC E RRC D DJNZ g_013 LD A,B OR E AND D g_014: LD (IX+01H),A g_015: JR g_011 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма выставляет паузу ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_9: LD A,01H LD (IX+07H),A INC HL OR A RET ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма переходит по адресу данных Call or Jump ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_10: INC HL LD E,(HL) INC HL LD D,(HL) INC HL LD (IX+09H),L LD (IX+0AH),H LD HL,Admat ADD HL,DE XOR A RET ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма возвращается из адреса ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_11: LD L,(IX+09H) LD H,(IX+0AH) XOR A RET ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма заглушки канала ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_12: LD A,1 LD (IX+07H),A OR A RET ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; Подпрограмма меняет текущую октаву ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Com_13: LD (IX+11),A g_016: JR g_015 Com_14: LD (IX+12),A JR g_016 Com_15: JR g_016 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ; 8 октава - образец частот (все остальные частоты ; вычисляются в зависимости от октавы и номера ноты) ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Notes: Defb 01BH Defb 019H Defb 018H Defb 016H Defb 015H Defb 014H Defb 013H Defb 012H Defb 011H Defb 010H Defb 00FH Defb 00EH ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Inform: Defb 1 ;Сколько тиков осталось играть 1 голос +0 Defb 8 ;Текущая длительность 1 голоса +1 Defb 1 ;Темп текущего голоса (1 OR 2) +2 Defw Admat_1 ;Адрес хранения данных 1 голоса +3 Defw Admat_1 ;Адрес текущих данных 1 голоса +5 Defb 0 ;1 Если музыка кончилась или пауза +7 Defb 0FH ;Громкость 1 голоса +8 Defw Admat_1 ;Хранение адресов для Call and Jump +9 Defb 05H ;Текущая октава +11 Defb 00 ;Легато или Стаккато +12 Defb 1 ;Сколько тиков осталось играть 2 голос +0 Defb 8 ;Текущая длительность 2 голоса +1 Defb 1 ;Темп текущего голоса (1 OR 2) +2 Defw Admat_2 ;Адрес хранения данных 2 голоса +3 Defw Admat_2 ;Адрес текущих данных 2 голоса +5 Defb 0 ;1 Если музыка кончилась или пауза +7 Defb 0FH ;Громкость 2 голоса +8 Defw Admat_2 ;Хранение адресов для Call and Jump +9 Defb 05H ;Текущая октава +11 Defb 00 ;Легато или Стаккато +12 Defb 1 ;Сколько тиков осталось играть 3 голос +0 Defb 8 ;Текущая длительность 3 голоса +1 Defb 1 ;Темп текущего голоса (1 OR 2) +2 Defw Admat_3 ;Адрес хранения данных 3 голоса +3 Defw Admat_3 ;Адрес текущих данных 3 голоса +5 Defb 0 ;1 Если музыка кончилась или пауза +7 Defb 0FH ;Громкость 3 голоса +8 Defw Admat_3 ;Хранение адресов для call and jump +9 Defb 05H ;Текущая октава +11 Defb 00 ;Легато или Стаккато +12 All_Data: Defb 15 ;Данные для 6 регистра +0 Defb 0B8H ;Данные для 7 регистра +1 Defb 200 ;Данные для 11 регистра +2 Defb 10 ;Данные для 12 регистра +3 Defb 1 ;Данные для 13 регистра +4 ;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Admat: Admat_1: Admat_2: Admat_3: