module ayfx
;-Minimal ayFX player2 v0.16 20.06.06--------------------------;
; ;
; Простейший плеер эффектов. Проигрывает эффекты на одном AY, ;
; без музыки на фоне. Громкость проигрывания эффектов задаётся ;
; при их вызове. Приоритет выбора каналов: если есть свободные ;
; каналы, выбирается один из них. Если свободных каналов нет, ;
; выбирается наиболее давно звучащий. Процедура проигрывания ;
; использует регистры AF,BC,DE,HL,IX. ;
;P.S. от Alone Coder'а: задействовал IY и еще 2 байта, чтобы
;не играть эффект, когда он тише музыки (убрано для TFM музыки)
;P.P.S. TurboSound fix 16.02.18
; ;
; Инициализация: ;
; ld hl, адрес банка эффектов ;
; call AFXINIT ;
; ;
; Запуск эффекта: ;
; ld a, номер эффекта (0..255) ;
; ld c, относительная громкость (-15..15) ;
; call AFXPLAY ;
; ;
; В обработчике прерывания: ;
; call AFXFRAME ;
; ;
;--------------------------------------------------------------;
; описатели каналов, по 5+2 байт на канал:
; +0 (2) текущий адрес (канал свободен, если старший байт =#00)
; +2 (2) время звучания эффекта
; +4 (1) громкость эффекта
; +6 (2) ПЕРИОД ТОНАЛЬНИКА
; ...
afxChDesc DS 3*(5+2)
;--------------------------------------------------------------;
; Инициализация плеера эффектов. ;
; Выключает все каналы, устанавливает переменные. ;
; Вход: HL = адрес банка с эффектами ;
;--------------------------------------------------------------;
INIT
ld a,(hl)
ld (afxEffectsAll),a
INC HL
LD (afxBnkAdr+1),HL ;сохраняем адрес таблицы смещений
LD HL,afxChDesc ;помечаем все каналы как пустые
LD DE,#00FF
LD B,3
afxInit0
LD (HL),D
INC HL
LD (HL),D
INC HL
LD (HL),E
INC HL
LD (HL),E
INC HL
LD (HL),D
INC HL
LD (HL),D
INC HL
LD (HL),D
INC HL
DJNZ afxInit0
ifdef TFM
ld a,(TURBOFMON)
or a
ret nz ;TFM present
ld a,#c9 ;ret
ld (waitstatus),a
endif
RET ;TFM absent
;--------------------------------------------------------------;
; Проигрывание текущего кадра. ;
; Параметров не имеет. ;
;--------------------------------------------------------------;
FRAME
LD BC,#03FD
LD IX,afxChDesc
afxFrame0
PUSH BC
LD H,(IX+1) ;сравнение старшего байта
;адреса на <11
ld a,h
or a
jp z,afxFrame7 ;канал не играет, пропускаем
LD L,(IX+0)
LD E,(HL) ;берём значение информационного байта
INC HL
LD A,11
SUB B ;выбираем регистр громкости:
LD D,B ;(11-3=8, 11-2=9, 11-1=10)
LD B,#FF ;начало вывода значения
ifndef TFM ;для TurboSound!!! выключено для TFM
OUT (C),B ;AY #1(0) ;т.к.может вырубиться при HY=#FF
LD HY,B ;выкл громкости
endif
;
ifdef TFM
call waitstatus
endif
OUT (C),A ;выбрали регистр громкости
ifdef TFM
call waitstatus
endif
ifndef TFM ;для TurboSound!!! выключено для TFM
IN A,(C)
CP 16
JR NC,$+4
SUB 3;4
JR NC,$+3
XOR A
LD (curvolCHN),A
endif
LD A,E
AND #0F
ADD A,(IX+4) ;применяем текущую громкость канала
CP 15
JP M,$+5
LD A,15
OR A
JP P,$+4
XOR A
ifndef TFM ;для TurboSound!!! выключено для TFM
CP 13 ;громкую часть эффекта не глушим
JR NC,curvON
curvolCHN=$+1
CP 0
JR C,curvOFF
curvON
LD HY,#BF ;вкл
curvOFF
LD B,HY
else
LD B,#BF
endif
OUT (C),A ;собственно вывод громкости
BIT 5,E ;будет изменение тона?
JR Z,afxFrame1 ;тон не изменяется
LD A,(HL)
LD (IX+5),A
INC HL
LD A,(HL)
LD (IX+6),A
INC HL
afxFrame1
LD A,3 ;выбираем регистры тона:
SUB D ;3-3=0, 3-2=1, 3-1=2
ADD A,A ;0*2=0, 1*2=2, 2*2=4
LD B,#FF ;выводим значения тона
ifdef TFM
call waitstatus
endif
OUT (C),A
ifdef TFM
call waitstatus
endif
ifndef TFM ;для TurboSound!!! выключено для TFM
LD B,HY
else
LD B,#BF
endif
LD D,(IX+5) ;младший байт тона может быть 0xfe!!!
OUT (C),D
LD B,#FF
OUT (C),B ;AY #1(0) ;т.к.может вырубиться при HY=#FF
INC A
ifdef TFM
call waitstatus
endif
OUT (C),A
ifdef TFM
call waitstatus
endif
ifndef TFM ;для TurboSound!!! выключено для TFM
LD B,HY
else
LD B,#BF
endif
LD D,(IX+6)
OUT (C),D
;afxFrame1
BIT 6,E ;будет изменение шума?
JR Z,afxFrame3 ;шум не изменяется
LD A,(HL) ;читаем значение шума
SUB #20
JR C,afxFrame2 ;меньше #20, играем дальше
LD H,A ;иначе конец эффекта
LD (IX+2),#FE ;делаем время наибольшим-1
LD (IX+3),#FF
LD E,#90 ;выключаем тон и шум в микшере
JR afxFrame3
afxFrame2
INC HL
LD B,#FF ;вывод значения шума
LD D,6
ifdef TFM
call waitstatus
endif
OUT (C),D
ifdef TFM
call waitstatus
endif
ifndef TFM ;для TurboSound!!! выключено для TFM
LD B,HY
else
LD B,#BF
endif
OUT (C),A
afxFrame3
POP BC ;восстанавливаем значение цикла в B
PUSH BC
INC B ;4..2 ;количество сдвигов для флагов TN
LD A,%01101111 ;маска для флагов TN
afxFrame4
RRC E ;сдвигаем флаги и маску
RRCA
DJNZ afxFrame4
LD D,A
LD BC,#FFFD ;читаем регистр микшера
LD A,7
ifdef TFM
call waitstatus
endif
OUT (C),A
ifdef TFM
call waitstatus
endif
IN A,(C)
XOR E ;накладываем флаги канала
AND D
XOR E
ifndef TFM ;для TurboSound!!! выключено для TFM
LD B,HY
else
LD B,#BF
endif
OUT (C),A ;выводим обратно в микшер ;может быть 0xfe!!!
LD B,#FF
OUT (C),B ;AY #1(0) ;т.к.может вырубиться при HY=#FF
afxFrame5
LD C,(IX+2) ;увеличиваем счётчик времени
LD B,(IX+3)
INC BC
afxFrame6
LD (IX+2),C
LD (IX+3),B
LD (IX+0),L ;сохраняем изменившийся адрес
LD (IX+1),H
afxFrame7
LD BC,5+2 ;переходим к следующему каналу
ADD IX,BC
POP BC
DEC B
JP NZ,afxFrame0
RET
;--------------------------------------------------------------;
; Запуск эффекта на свободном канале. При отсутствии ;
; свободных каналов выбирается наиболее давно звучащий. ;
; Вход: A = номер эффекта 0..255 ;
; С = относительная громкость -15..15 ;
;--------------------------------------------------------------;
PLAY
afxEffectsAll=$+1
cp 0
ret nc
push ix
PUSH BC ;сохраняем громкость
LD DE,0 ;в DE наибольшее время при поиске
LD H,E
LD L,A
ADD HL,HL
afxBnkAdr
LD BC,0 ;адрес таблицы смещений эффектов
ADD HL,BC
LD C,(HL)
INC HL
LD B,(HL)
ADD HL,BC ;адрес эффекта получен в hl
PUSH HL ;сохраняем адрес эффекта на стеке
LD HL,afxChDesc ;поиск пустого канала
LD B,3
afxPlay0
INC HL
INC HL
LD A,(HL) ;сравниваем время канала с наибольшим
INC HL
INC HL
CP E
JR C,afxPlay1
LD C,A
LD A,(HL)
CP D
JR C,afxPlay1
LD E,C ;запоминаем наибольшее время
LD D,A
PUSH HL ;запоминаем адрес канала +3 в IX
POP IX
afxPlay1
INC HL
INC HL
INC HL
DJNZ afxPlay0
POP DE ;забираем адрес эффекта из стека
LD (IX-4),E ;заносим в описатель канала
LD (IX-3),D
LD (IX-2),B ;зануляем время звучания
LD (IX-1),B
POP BC ;забираем громкость
LD (IX-0),C ;и заносим её в описатель канала
pop ix
ret
ifdef TFM
waitstatus
;bc=#fffd
IN F,(C)
JP M,$-2
ret
endif
endmodule