From 2fbdf974338bde8576efdae40a819a76b2391033 Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Sun, 5 Nov 2023 11:22:55 +0000 Subject: Initial import of the open source release --- lib/Makefile | 21 + lib/aplib.h | 4 + lib/aplib.z80 | 162 ++ lib/cpcrslib/GphStrStd.s | 412 +++++ lib/cpcrslib/LICENSE | 20 + lib/cpcrslib/Makefile | 19 + lib/cpcrslib/Sprites.s | 37 + lib/cpcrslib/TileMap.h | 304 ++++ lib/cpcrslib/Wyz.s | 1414 +++++++++++++++++ lib/cpcrslib/cpc_ClrScr.s | 11 + lib/cpcrslib/cpc_CollSp.s | 126 ++ lib/cpcrslib/cpc_DisableEnableFirmware.s | 28 + lib/cpcrslib/cpc_GetScrAddress.s | 65 + lib/cpcrslib/cpc_GetSp.s | 49 + lib/cpcrslib/cpc_GphStr.s | 700 +++++++++ lib/cpcrslib/cpc_Keyboard.s | 344 +++++ lib/cpcrslib/cpc_PrintStr.s | 27 + lib/cpcrslib/cpc_PutMaskSp.s | 79 + lib/cpcrslib/cpc_PutMaskSp2x8.s | 45 + lib/cpcrslib/cpc_PutMaskSp4x16.s | 56 + lib/cpcrslib/cpc_PutSp.s | 54 + lib/cpcrslib/cpc_PutSp2x14.s | 50 + lib/cpcrslib/cpc_PutSpTr.s | 75 + lib/cpcrslib/cpc_PutSpXOR.s | 79 + lib/cpcrslib/cpc_PutSprite.s | 108 ++ lib/cpcrslib/cpc_RLI.s | 39 + lib/cpcrslib/cpc_RRI.s | 39 + lib/cpcrslib/cpc_Random.s | 34 + lib/cpcrslib/cpc_SetBorder.s | 10 + lib/cpcrslib/cpc_SetColour.s | 16 + lib/cpcrslib/cpc_SetInk.s | 12 + lib/cpcrslib/cpc_SetMode.s | 13 + lib/cpcrslib/cpc_SetModo.s | 9 + lib/cpcrslib/cpc_TileMap.s | 1332 ++++++++++++++++ lib/cpcrslib/cpc_UnExoOpt.s | 183 +++ lib/cpcrslib/cpc_Uncrunch.s | 308 ++++ lib/cpcrslib/cpcrslib.h | 116 ++ lib/cpcrslib/cpcwyzlib.h | 18 + lib/cpcrslib/make.bat | 19 + lib/plw.h | 19 + lib/plw/Makefile | 34 + lib/plw/README.md | 16 + lib/plw/player/Makefile | 11 + lib/plw/player/PlayerLightWeight.asm | 1694 +++++++++++++++++++++ lib/plw/player/PlayerLightWeight_SoundEffects.asm | 458 ++++++ lib/plw/player/player.asm | 43 + lib/plw/plw_init.z80 | 14 + lib/plw/plw_init_sound_effects.z80 | 9 + lib/plw/plw_is_sound_effect_on.z80 | 7 + lib/plw/plw_play.z80 | 6 + lib/plw/plw_play_sound_effect.z80 | 48 + lib/plw/plw_player.asm | 1193 +++++++++++++++ lib/plw/plw_player.c | 3 + lib/plw/plw_stop.z80 | 6 + 54 files changed, 9998 insertions(+) create mode 100644 lib/Makefile create mode 100644 lib/aplib.h create mode 100644 lib/aplib.z80 create mode 100644 lib/cpcrslib/GphStrStd.s create mode 100644 lib/cpcrslib/LICENSE create mode 100644 lib/cpcrslib/Makefile create mode 100644 lib/cpcrslib/Sprites.s create mode 100644 lib/cpcrslib/TileMap.h create mode 100644 lib/cpcrslib/Wyz.s create mode 100644 lib/cpcrslib/cpc_ClrScr.s create mode 100644 lib/cpcrslib/cpc_CollSp.s create mode 100644 lib/cpcrslib/cpc_DisableEnableFirmware.s create mode 100644 lib/cpcrslib/cpc_GetScrAddress.s create mode 100644 lib/cpcrslib/cpc_GetSp.s create mode 100644 lib/cpcrslib/cpc_GphStr.s create mode 100644 lib/cpcrslib/cpc_Keyboard.s create mode 100644 lib/cpcrslib/cpc_PrintStr.s create mode 100644 lib/cpcrslib/cpc_PutMaskSp.s create mode 100644 lib/cpcrslib/cpc_PutMaskSp2x8.s create mode 100644 lib/cpcrslib/cpc_PutMaskSp4x16.s create mode 100644 lib/cpcrslib/cpc_PutSp.s create mode 100644 lib/cpcrslib/cpc_PutSp2x14.s create mode 100644 lib/cpcrslib/cpc_PutSpTr.s create mode 100644 lib/cpcrslib/cpc_PutSpXOR.s create mode 100644 lib/cpcrslib/cpc_PutSprite.s create mode 100644 lib/cpcrslib/cpc_RLI.s create mode 100644 lib/cpcrslib/cpc_RRI.s create mode 100644 lib/cpcrslib/cpc_Random.s create mode 100644 lib/cpcrslib/cpc_SetBorder.s create mode 100644 lib/cpcrslib/cpc_SetColour.s create mode 100644 lib/cpcrslib/cpc_SetInk.s create mode 100644 lib/cpcrslib/cpc_SetMode.s create mode 100644 lib/cpcrslib/cpc_SetModo.s create mode 100644 lib/cpcrslib/cpc_TileMap.s create mode 100644 lib/cpcrslib/cpc_UnExoOpt.s create mode 100644 lib/cpcrslib/cpc_Uncrunch.s create mode 100644 lib/cpcrslib/cpcrslib.h create mode 100644 lib/cpcrslib/cpcwyzlib.h create mode 100644 lib/cpcrslib/make.bat create mode 100644 lib/plw.h create mode 100644 lib/plw/Makefile create mode 100644 lib/plw/README.md create mode 100644 lib/plw/player/Makefile create mode 100644 lib/plw/player/PlayerLightWeight.asm create mode 100644 lib/plw/player/PlayerLightWeight_SoundEffects.asm create mode 100644 lib/plw/player/player.asm create mode 100644 lib/plw/plw_init.z80 create mode 100644 lib/plw/plw_init_sound_effects.z80 create mode 100644 lib/plw/plw_is_sound_effect_on.z80 create mode 100644 lib/plw/plw_play.z80 create mode 100644 lib/plw/plw_play_sound_effect.z80 create mode 100644 lib/plw/plw_player.asm create mode 100644 lib/plw/plw_player.c create mode 100644 lib/plw/plw_stop.z80 (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..a8bf391 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,21 @@ +all: aplib.lib cpcrslib.lib plw.lib + +AS=sdasz80 +AR=sdar + +aplib.lib: aplib.z80 + $(AS) -o $< + $(AR) -rcD $@ aplib.rel + +cpcrslib.lib: $(wildcard cpcrslib/*.s) + make -C cpcrslib + +plw.lib: $(wildcard plw/*.z80) + make -C plw + +.PHONY: clean +clean: + rm -f *.rel *.lib + make -C cpcrslib clean + make -C plw clean + diff --git a/lib/aplib.h b/lib/aplib.h new file mode 100644 index 0000000..79de9c6 --- /dev/null +++ b/lib/aplib.h @@ -0,0 +1,4 @@ +#ifndef _APLIB_H +#define _APLIB_H +extern void aplib_uncompress(const unsigned char *dst, unsigned char *src); +#endif diff --git a/lib/aplib.z80 b/lib/aplib.z80 new file mode 100644 index 0000000..6a5d8d4 --- /dev/null +++ b/lib/aplib.z80 @@ -0,0 +1,162 @@ +; See apultra for licence. +; +; Z80 Version by Dan Weiss +; Call depack. +; +; hl = source +; de = dest + +; C convention +.globl _aplib_uncompress +; register call +.globl aplib_depack + +; aPPack decompressor +; original source by dwedit +; very slightly adapted by utopian +; optimized by Metalbrain + +;hl = source +;de = dest + +; this is to enable undocumented Z80 opcodes in SDCC assembler +.ez80 + +_aplib_uncompress:: + ld hl, #2 + add hl, sp + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +aplib_depack:: + ld ixl, #128 + +apbranch1: + ldi +aploop0: + ld ixh, #1 ;LWM = 0 +aploop: + call ap_getbit + jr nc, apbranch1 + call ap_getbit + jr nc, apbranch2 + ld b, #0 + call ap_getbit + jr nc, apbranch3 + ld c, #16 ;get an offset +apget4bits: + call ap_getbit + rl c + jr nc, apget4bits + jr nz, apbranch4 + ld a, b +apwritebyte: + ld (de), a ;write a 0 + inc de + jr aploop0 +apbranch4: + and a + ex de, hl ;write a previous byte (1-15 away from dest) + sbc hl, bc + ld a, (hl) + add hl, bc + ex de, hl + jr apwritebyte +apbranch3: + ld c, (hl) ;use 7 bit offset, length = 2 or 3 + inc hl + rr c + ret z ;if a zero is encountered here, it is EOF + ld a, #2 + adc a,b + push hl + ld iyh, b + ld iyl, c + ld h, d + ld l, e + sbc hl, bc + ld c, a + jr ap_finishup2 +apbranch2: + call ap_getgamma ;use a gamma code * 256 for offset, another gamma code for length + dec c + ld a, c + sub ixh + jr z, ap_r0_gamma ;if gamma code is 2, use old r0 offset, + dec a + ;do I even need this code? + ;bc=bc*256+(hl), lazy 16bit way + ld b, a + ld c, (hl) + inc hl + ld iyh, b + ld iyl, c + + push bc + + call ap_getgamma + + ex (sp), hl ;bc = len, hl=offs + push de + ex de, hl + + ld a, #4 + cp d + jr nc, apskip2 + inc bc + or a +apskip2: + ld hl, #127 + sbc hl, de + jr c, apskip3 + inc bc + inc bc +apskip3: + pop hl ;bc = len, de = offs, hl=junk + push hl + or a +ap_finishup: + sbc hl, de + pop de ;hl=dest-offs, bc=len, de = dest +ap_finishup2: + ldir + pop hl + ld ixh, b + jr aploop + +ap_r0_gamma: + call ap_getgamma ;and a new gamma code for length + push hl + push de + ex de, hl + ld d, iyh + ld e, iyl + jr ap_finishup + +ap_getbit: + ld a, ixl + add a, a + ld ixl, a + ret nz + ld a, (hl) + inc hl + rla + ld ixl, a + ret + +ap_getgamma: + ld bc, #1 +ap_getgammaloop: + call ap_getbit + rl c + rl b + call ap_getbit + jr c, ap_getgammaloop + ret + diff --git a/lib/cpcrslib/GphStrStd.s b/lib/cpcrslib/GphStrStd.s new file mode 100644 index 0000000..08c19ec --- /dev/null +++ b/lib/cpcrslib/GphStrStd.s @@ -0,0 +1,412 @@ +; ****************************************************** +; ** Librería de rutinas SDCC para Amstrad CPC ** +; ** Raúl Simarro (Artaburu) - 2009, 2012 ** +; ****************************************************** + +cpc_GetScrAddress0: ;en HL están las coordenadas + + ;LD A,H + LD (#inc_ancho+1),A + LD A,L + SRL A + SRL A + SRL A + ; A indica el bloque a multiplicar x &50 + LD D,A ;D + SLA A + SLA A + SLA A + SUB L + NEG + ; A indica el desplazamiento a multiplicar x &800 + LD E,A ;E + LD L,D + LD H,#0 + ADD HL,HL + LD BC,#bloques + ADD HL,BC + ;HL APUNTA AL BLOQUE BUSCADO + LD C,(HL) + INC HL + LD H,(HL) + LD L,C + ;HL TIENE EL VALOR DEL BLOQUE DE 8 BUSCADO + PUSH HL + LD D,#0 + LD HL,#sub_bloques + ADD HL,DE + LD A,(HL) + POP HL + ADD H + LD H,A +inc_ancho: + LD E,#0 + ADD HL,DE + RET + +bloques: +.DW #0XC000,#0XC050,#0XC0A0,#0XC0F0,#0XC140,#0XC190,#0XC1E0,#0XC230,#0XC280,#0XC2D0,#0XC320,#0XC370,#0XC3C0,#0XC410,#0XC460,#0XC4B0,#0XC500,#0XC550,#0XC5A0,#0XC5F0,#0XC640,#0XC690,#0XC6E0,#0XC730,#0XC780 +sub_bloques: +.DB #0X00,#0X08,#0X10,#0X18,#0X20,#0X28,#0X30,#0X38 + + + + +.globl _cpc_PrintGphStrStd + +_cpc_PrintGphStrStd:: + ld ix,#2 + add ix,sp + ld l,3 (ix) + ld h,4 (ix) ;destino + ld e,1 (ix) + ld d,2 (ix) ;texto origen + ld a,0 (ix) ;color + ld (#color_uso+1),a + JP cpc_PrintGphStrStd0 + + +.globl _cpc_PrintGphStrStdXY + +_cpc_PrintGphStrStdXY:: +;preparación datos impresión. El ancho y alto son fijos! + ld ix,#2 + add ix,sp + ld L,4 (ix) + ld A,3 (ix) ;pantalla + call cpc_GetScrAddress0 + ld e,1 (ix) + ld d,2 (ix) ;texto origen + ld a,0 (ix) ;color + ld (#color_uso+1),a + JP cpc_PrintGphStrStd0 + +color0: + XOR A + CALL metecolor + JP sigue +color1: + LD A,#0B00001000 + CALL metecolor + JP sigue +color2: + LD A,#0B10000000 + CALL metecolor + JP sigue +color3: + LD A,#0b10001000 + CALL metecolor + JP sigue +metecolor: + LD (#cc0_gpstd-1),A + LD (#cc4_gpstd-1),A + SRL A + LD (#cc1_gpstd-1),A + LD (#cc5_gpstd-1),A + SRL A + LD (#cc2_gpstd-1),A + LD (#cc6_gpstd-1),A + SRL A + LD (#cc3_gpstd-1),A + LD (#cc7_gpstd-1),A + RET + +cpc_PrintGphStrStd0: +;; marcará el color con que se imprime +color_uso: + LD A,#1 + OR A + JP Z,color0 + CP #1 + JP Z,color1 + CP #2 + JP Z,color2 + CP #3 + JP Z,color3 +sigue: + + ;trabajo previo: Para tener una lista de trabajos de impresión. No se interrumpe + ;la impresión en curso. + LD A,(#imprimiendo) + CP #1 + JP Z,add_elemento + LD (#direcc_destino),HL + EX DE,HL + CALL bucle_texto0 + +;antes de terminar, se mira si hay algo en cola. +bucle_cola_impresion: + LD A,(#elementos_cola) + OR A + JP Z,terminar_impresion + CALL leer_elemento + JP bucle_cola_impresion + +terminar_impresion: + XOR A + LD (#imprimiendo),A + RET +entrar_cola_impresion: + ;si se está imprimiendo se mete el valor en la cola + RET +add_elemento: + DI + LD IX,(#pos_cola) + LD 0 (IX),L + LD 1 (IX),H + LD 2 (IX),E + LD 3 (IX),D + INC IX + INC IX + INC IX + INC IX + Ld (#pos_cola),IX + LD HL,#elementos_cola + INC (HL) + EI + RET +leer_elemento: + DI + LD IX,(#pos_cola) + LD L,0 (IX) + LD H,1 (IX) + LD E,2 (IX) + LD D,3 (IX) + DEC IX + DEC IX + DEC IX + DEC IX + LD (#pos_cola),IX + LD HL,#elementos_cola + DEC (HL) + EI + RET + +elementos_cola: + .DW #0 +pos_cola: + .DW cola_impresion +cola_impresion: + .DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; defs 12 +bucle_texto0: + LD A,#1 + LD (#imprimiendo),A + LD A,(#first_char8) + LD B,A ;resto 48 para saber el número del caracter (En ASCII 0=48) + LD A,(HL) + OR A ;CP 0 + RET Z + SUB B + LD BC,#cpc_Chars8 ;apunto a la primera letra + PUSH HL + LD L,A + LD H,#0 + ADD HL,HL + ADD HL,HL + ADD HL,HL + ADD HL,BC + CALL escribe_letra_gpstd + LD HL,(#direcc_destino) + + LD DE,#letra_decodificada + CALL cpc_PutSp0_gpstd + LD HL,(#direcc_destino) + INC HL + INC HL + LD (#direcc_destino),HL + POP HL + INC HL + JP bucle_texto0 + +imprimiendo: + .db #0 +direcc_destino: + .dw #0 + + +cpc_PutSp0_gpstd: + .DB #0XFD + LD H,#8 + LD B,#7 + LD C,B +loop_alto_2_gpstd: +loop_ancho_2_gpstd: + EX DE,HL + LDI + LDI + .DB #0XFD + DEC H + RET Z + EX DE,HL +salto_linea_gpstd: + LD C,#0XFE + ADD HL,BC + JP NC,loop_alto_2_gpstd + LD BC,#0XC050 + ADD HL,BC + LD B,#7 + JP loop_alto_2_gpstd + + + +escribe_letra_gpstd: ;; lee el byte y lo interpreta + LD IY,#letra_decodificada + LD B,#8 +bucle_alto_gpstd: + PUSH BC ;leo el byte... ahora se miran sus bits y se rellena el caracter a imprimir + XOR A + LD B,(HL) + BIT 7,B + JP Z,cc0_gpstd + OR #0b10001000 +cc0_gpstd: + BIT 6,B + JP Z,cc1_gpstd + OR #0b01000100 +cc1_gpstd: + BIT 5,B + JP Z,cc2_gpstd + OR #0b00100010 +cc2_gpstd: + BIT 4,B + JP Z,cc3_gpstd + OR #0b00010001 +cc3_gpstd: + ;primer byte + LD 0 (IY),A + INC IY + XOR A + BIT 3,B + JP Z,cc4_gpstd + OR #0b10001000 +cc4_gpstd: + BIT 2,B + JP Z,cc5_gpstd + OR #0b01000100 +cc5_gpstd: + BIT 1,B + JP Z,cc6_gpstd + OR #0b00100010 +cc6_gpstd: + BIT 0,B + JP Z,cc7_gpstd + OR #0b00010001 +cc7_gpstd: + ;segundo byte + LD 0 (IY),A + INC IY + INC HL + POP BC + DJNZ bucle_alto_gpstd + RET + + + +byte_tmp: ;DEFS 2 + .DB #0,#0 +letra_decodificada: + .DB #0,#0,#0,#0,#0,#0,#0,#0 ;DEFS 16 + .DB #0,#0,#0,#0,#0,#0,#0,#0 ;USO ESTE ESPACIO PARA GUARDAR LA LETRA QUE SE DECODIFICA + +;DEFC direcc_destino0s_m1 = direcc_destino + +first_char8: + .DB #32 ;first defined char number (ASCII) +cpc_Chars8: ;each bit of each byte is a pixel,#same way as SYMBOL function of Locomotive BASIC. + ;; KEY SET BY ANJUEL & NA_TH_AN FROM NANAKO CPC GAME. + .DB #0,#0,#0,#0,#0,#0,#0,#0 + .DB #28,#8,#8,#8,#28,#0,#8,#0 + .DB #10,#10,#0,#0,#0,#0,#0,#0 + .DB #36,#126,#36,#36,#36,#126,#36,#0 + .DB #16,#62,#32,#60,#4,#124,#8,#0 + .DB #0,#50,#52,#8,#22,#38,#0,#0 + .DB #0,#16,#40,#58,#68,#58,#0,#0 + .DB #16,#16,#0,#0,#0,#0,#0,#0 + .DB #16,#112,#80,#64,#80,#112,#16,#0 + .DB #8,#14,#10,#2,#10,#14,#8,#0 + .DB #0,#42,#28,#28,#42,#0,#0,#0 + .DB #0,#8,#8,#62,#8,#8,#0,#0 + .DB #0,#0,#0,#0,#12,#12,#0,#0 + .DB #0,#0,#0,#62,#0,#0,#0,#0 + .DB #0,#0,#0,#0,#12,#12,#16,#0 + .DB #0,#4,#8,#16,#32,#64,#0,#0 + .DB #62,#34,#34,#34,#34,#34,#62,#0 + .DB #12,#4,#4,#4,#4,#4,#4,#0 + .DB #62,#34,#2,#62,#32,#34,#62,#0 + .DB #62,#36,#4,#28,#4,#36,#62,#0 + .DB #32,#32,#36,#62,#4,#4,#14,#0 + .DB #62,#32,#32,#62,#2,#34,#62,#0 + .DB #62,#32,#32,#62,#34,#34,#62,#0 + .DB #62,#36,#4,#4,#4,#4,#14,#0 + .DB #62,#34,#34,#62,#34,#34,#62,#0 + .DB #62,#34,#34,#62,#2,#34,#62,#0 + .DB #0,#24,#24,#0,#0,#24,#24,#0 + .DB #0,#24,#24,#0,#0,#24,#24,#32 + .DB #4,#8,#16,#32,#16,#8,#4,#0 + .DB #0,#0,#126,#0,#0,#126,#0,#0 + .DB #32,#16,#8,#4,#8,#16,#32,#0 + .DB #64,#124,#68,#4,#28,#16,#0,#16 + .DB #0,#56,#84,#92,#64,#60,#0,#0 + .DB #126,#36,#36,#36,#60,#36,#102,#0 + .DB #124,#36,#36,#62,#34,#34,#126,#0 + .DB #2,#126,#66,#64,#66,#126,#2,#0 + .DB #126,#34,#34,#34,#34,#34,#126,#0 + .DB #2,#126,#66,#120,#66,#126,#2,#0 + .DB #2,#126,#34,#48,#32,#32,#112,#0 + .DB #2,#126,#34,#32,#46,#36,#124,#0 + .DB #102,#36,#36,#60,#36,#36,#102,#0 + .DB #56,#16,#16,#16,#16,#16,#56,#0 + .DB #28,#8,#8,#8,#8,#40,#56,#0 + .DB #108,#40,#40,#124,#36,#36,#102,#0 + .DB #112,#32,#32,#32,#34,#126,#2,#0 + .DB #127,#42,#42,#42,#42,#107,#8,#0 + .DB #126,#36,#36,#36,#36,#36,#102,#0 + .DB #126,#66,#66,#66,#66,#66,#126,#0 + .DB #126,#34,#34,#126,#32,#32,#112,#0 + .DB #126,#66,#66,#74,#126,#8,#28,#0 + .DB #126,#34,#34,#126,#36,#36,#114,#0 + .DB #126,#66,#64,#126,#2,#66,#126,#0 + .DB #34,#62,#42,#8,#8,#8,#28,#0 + .DB #102,#36,#36,#36,#36,#36,#126,#0 + .DB #102,#36,#36,#36,#36,#24,#0,#0 + .DB #107,#42,#42,#42,#42,#42,#62,#0 + .DB #102,#36,#36,#24,#36,#36,#102,#0 + .DB #102,#36,#36,#60,#8,#8,#28,#0 + .DB #126,#66,#4,#8,#16,#34,#126,#0 + .DB #4,#60,#36,#32,#36,#60,#4,#0 + .DB #0,#64,#32,#16,#8,#4,#0,#0 + .DB #32,#60,#36,#4,#36,#60,#32,#0 + .DB #0,#16,#40,#68,#0,#0,#0,#0 + .DB #0,#0,#0,#0,#0,#0,#0,#0 + .DB #0,#100,#104,#16,#44,#76,#0,#0 + .DB #126,#36,#36,#36,#60,#36,#102,#0 + .DB #124,#36,#36,#62,#34,#34,#126,#0 + .DB #2,#126,#66,#64,#66,#126,#2,#0 + .DB #126,#34,#34,#34,#34,#34,#126,#0 + .DB #2,#126,#66,#120,#66,#126,#2,#0 + .DB #2,#126,#34,#48,#32,#32,#112,#0 + .DB #2,#126,#34,#32,#46,#36,#124,#0 + .DB #102,#36,#36,#60,#36,#36,#102,#0 + .DB #56,#16,#16,#16,#16,#16,#56,#0 + .DB #28,#8,#8,#8,#8,#40,#56,#0 + .DB #108,#40,#40,#124,#36,#36,#102,#0 + .DB #112,#32,#32,#32,#34,#126,#2,#0 + .DB #127,#42,#42,#42,#42,#107,#8,#0 + .DB #126,#36,#36,#36,#36,#36,#102,#0 + .DB #126,#66,#66,#66,#66,#66,#126,#0 + .DB #126,#34,#34,#126,#32,#32,#112,#0 + .DB #126,#66,#66,#74,#126,#8,#28,#0 + .DB #126,#34,#34,#126,#36,#36,#114,#0 + .DB #126,#66,#64,#126,#2,#66,#126,#0 + .DB #34,#62,#42,#8,#8,#8,#28,#0 + .DB #102,#36,#36,#36,#36,#36,#126,#0 + .DB #102,#36,#36,#36,#36,#24,#0,#0 + .DB #107,#42,#42,#42,#42,#42,#62,#0 + .DB #102,#36,#36,#24,#36,#36,#102,#0 + .DB #102,#36,#36,#60,#8,#8,#28,#0 + .DB #126,#66,#4,#8,#16,#34,#126,#0 + .DB #4,#60,#36,#96,#96,#36,#60,#4 + .DB #0,#16,#16,#16,#16,#16,#16,#0 + .DB #32,#60,#36,#6,#6,#36,#60,#32 + .DB #0,#0,#16,#40,#68,#0,#0,#0 + .DB #126,#66,#90,#82,#90,#66,#126,#0 \ No newline at end of file diff --git a/lib/cpcrslib/LICENSE b/lib/cpcrslib/LICENSE new file mode 100644 index 0000000..04424c0 --- /dev/null +++ b/lib/cpcrslib/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2008-2015 Raúl Simarro + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/lib/cpcrslib/Makefile b/lib/cpcrslib/Makefile new file mode 100644 index 0000000..c440a28 --- /dev/null +++ b/lib/cpcrslib/Makefile @@ -0,0 +1,19 @@ +all: cpcrslib.lib + +AS=sdasz80 +AR=sdar + +cpcrslib_SRCS=$(wildcard cpc_*.s) +cpcrslib_OBJS=$(patsubst %.s,%.rel,$(cpcrslib_SRCS)) + +cpcrslib.lib: $(cpcrslib_OBJS) + $(AR) -rcD cpcrslib.lib $(cpcrslib_OBJS) + cp cpcrslib.lib .. + +%.rel: %.s + $(AS) -o $< + +.PHONY: clean +clean: + rm -f *.rel *.lib + diff --git a/lib/cpcrslib/Sprites.s b/lib/cpcrslib/Sprites.s new file mode 100644 index 0000000..20ed720 --- /dev/null +++ b/lib/cpcrslib/Sprites.s @@ -0,0 +1,37 @@ +; ****************************************************** +; ** Librería de rutinas SDCC para Amstrad CPC ** +; ** Raúl Simarro (Artaburu) - 2009, 2012 ** +; ****************************************************** + + +;************************************* +; SPRITES +;************************************* + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/cpcrslib/TileMap.h b/lib/cpcrslib/TileMap.h new file mode 100644 index 0000000..6240bad --- /dev/null +++ b/lib/cpcrslib/TileMap.h @@ -0,0 +1,304 @@ + +.globl _tiles +.globl _pantalla_juego +.globl _tiles_tocados +.globl _posiciones_pantalla +.globl _posiciones_super_buffer +.globl _tabla_y_ancho_pantalla + + +;.globl _posicion_inicial_area_visible +;.globl _posicion_inicial_superbuffer +;.globl _ancho_pantalla_bytes +;.globl _alto_pantalla_bytes +;.globl _ancho_pantalla_bytes_visible + + +; *************************************************** +; Transparent colour for cpc_PutTrSpTileMap2b routine +;.globl _mascara1 +;.globl _mascara2 +; *************************************************** + +;.globl _tiles_ocultos_ancho0 +;.globl _tiles_ocultos_alto0 +;.globl _tiles_ocultos_ancho1 +;.globl _tiles_ocultos_alto1 + + +;.globl _posicion_inicio_pantalla_visible +;.globl _posicion_inicio_pantalla_visible_sb + + + +;.globl _tile +; *************************************************** +; Scroll Left Addresses column +; not requiered if scroll not used +.globl _ColumnScr +; *************************************************** + + +; *************************************************** +; Transparent colour for cpc_PutTrSpTileMap2b routine +; For printing sprites using transparent color (mode 0) transparent color selection is requiered. +; Selección color transparente. Escribir las 2 máscaras que correspondan al color elegido. +;Example colour number 7: +mascara1 = #0 +mascara2 = #0 + + +;0: #0x00, #0x00 +;1: #0x80, #0x40 +;2: #0x04, #0x08 +;3: #0x44, #0x88 +;4: #0x10, #0x20 +;5: #0x50, #0xA0 +;6: #0x14, #0x28 +;7: #0x54, #0xA8 +;8: #0x01, #0x02 +;9: #0x41, #0x82 +;10: #0x05, #0x0A +;11: #0x45, #0x8A +;12: #0x11, #0x22 +;13: #0x51, #0xA2 +;14: #0x15, #0x2A +;15: #0x55, #0xAA +; *************************************************** + + + + +;------------------------------------------------------------------------------------ +; SCREEN AND BUFFER ADDRESSES +; VALORES QUE DEFINEN EL BUFFER Y LA PANTALLA +;------------------------------------------------------------------------------------ + +posicion_inicial_area_visible = #0xc0A4 +posicion_inicial_superbuffer = #0x100 + + +;------------------------------------------------------------------------------------ + +;------------------------------------------------------------------------------------ +; TILE MAP DIMENSIONS +;------------------------------------------------------------------------------------ + +T_WIDTH = 32 ;max=40 ;dimensiones de la pantalla en tiles +T_HEIGHT = 16 ;max=20 + + +;Invisible tile margins: +T_WH = 2 +T_HH = 0 +;------------------------------------------------------------------------------------ + + +tiles_ocultos_ancho0 = T_WH +tiles_ocultos_alto0 = T_HH +tiles_ocultos_ancho1 = T_WIDTH - T_WH - 1 +tiles_ocultos_alto1 = T_HEIGHT - T_HH - 1 + +;------------------------------------------------------------------------------------ +; Other parameters (internal use) +;------------------------------------------------------------------------------------ +;------------------------------------------------------------------------------------ + +ancho_pantalla_bytes = 2*T_WIDTH ; 2*T_WIDTH; ; El ancho de pantalla influye determinantemente en numerosas rutinas que hay que actualizar si se cambia + ; OJO con el modo +alto_pantalla_bytes = 8*T_HEIGHT; +ancho_pantalla_bytes_visible = 2*T_WIDTH ;32 ; 64; ;dentro del area definida, cuanto se debe mostrar. 2*T_WIDTH + +;El tamaño del buffer es ancho_pantalla_bytes*alto_pantalla_bytes + +_TileMapConf: +;------------------------------------------------------------------------------------ +;Con la definición del mapeado hay que tener en cuenta que las coordenadas son: +;ANCHO=64 bytes (128 pixels en modo 0) +;ALTO=128 pixels +;el máximo que entra en el CPC es 20 líneas +;SI NO SE VAN A USAR TODAS LAS LINEAS, PARA AHORRA MEMORIA ES INTERESANTE COMENTARLAS +_posiciones_pantalla: ;Posiciones en las que se dibujan los tiles +.DW #posicion_inicial_area_visible+#0x50*0 +.DW #posicion_inicial_area_visible+#0x50*1 +.DW #posicion_inicial_area_visible+#0x50*2 +.DW #posicion_inicial_area_visible+#0x50*3 +.DW #posicion_inicial_area_visible+#0x50*4 +.DW #posicion_inicial_area_visible+#0x50*5 +.DW #posicion_inicial_area_visible+#0x50*6 +.DW #posicion_inicial_area_visible+#0x50*7 +.DW #posicion_inicial_area_visible+#0x50*8 +.DW #posicion_inicial_area_visible+#0x50*9 +.DW #posicion_inicial_area_visible+#0x50*10 +.DW #posicion_inicial_area_visible+#0x50*11 +.DW #posicion_inicial_area_visible+#0x50*12 +.DW #posicion_inicial_area_visible+#0x50*13 +.DW #posicion_inicial_area_visible+#0x50*14 +.DW #posicion_inicial_area_visible+#0x50*15 +.DW #posicion_inicial_area_visible+#0x50*16 +.DW #posicion_inicial_area_visible+#0x50*17 +.DW #posicion_inicial_area_visible+#0x50*18 +.DW #posicion_inicial_area_visible+#0x50*19 + +_posiciones_super_buffer: ;muestra el inicio de cada línea (son 10 tiles de 8x16 de alto) +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*0 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*1 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*2 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*3 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*4 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*5 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*6 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*7 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*8 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*9 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*10 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*11 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*12 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*13 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*14 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*15 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*16 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*17 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*18 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*19 + + + + +; *************************************************** +; Scroll Left Addresses column. DECRAPTED +; not requiered if scroll not used comment it ;) +_ColumnScr: +; *************************************************** + + +_pantalla_actual: .DW #0 +_pantalla_juego: ;en tiles +;defs T_WIDTH*T_HEIGHT +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0xFF ;Este byte es importante, marca el fin de la pantalla. + + +_fondo_pantalla_juego: ;en tiles +;defs T_WIDTH*T_HEIGHT +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#13,#14,#17,#13,#14,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#15,#16,#17,#15,#16,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 + + +_tiles_tocados: +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF + ;defs 150 ;150 ;cuando un tile es tocado, se marca en esta tabla para luego restaurarlo. Es una tabla sin duplicados. + + +_tabla_y_ancho_pantalla: +.dw #_pantalla_juego + #0 +.dw #_pantalla_juego + #1*T_WIDTH +.dw #_pantalla_juego + #2*T_WIDTH +.dw #_pantalla_juego + #3*T_WIDTH +.dw #_pantalla_juego + #4*T_WIDTH +.dw #_pantalla_juego + #5*T_WIDTH +.dw #_pantalla_juego + #6*T_WIDTH +.dw #_pantalla_juego + #7*T_WIDTH +.dw #_pantalla_juego + #8*T_WIDTH +.dw #_pantalla_juego + #9*T_WIDTH +.dw #_pantalla_juego + #10*T_WIDTH +.dw #_pantalla_juego + #11*T_WIDTH +.dw #_pantalla_juego + #12*T_WIDTH +.dw #_pantalla_juego + #13*T_WIDTH +.dw #_pantalla_juego + #14*T_WIDTH +.dw #_pantalla_juego + #15*T_WIDTH +.dw #_pantalla_juego + #16*T_WIDTH +.dw #_pantalla_juego + #17*T_WIDTH +.dw #_pantalla_juego + #18*T_WIDTH +.dw #_pantalla_juego + #19*T_WIDTH + +;_tabla_y_x_ancho2: +;.dw #ancho_pantalla_bytes * 0 /2 +;.dw #ancho_pantalla_bytes * 1 /2 +;.dw #ancho_pantalla_bytes * 2 /2 +;.dw #ancho_pantalla_bytes * 3 /2 +;.dw #ancho_pantalla_bytes * 4 /2 +;.dw #ancho_pantalla_bytes * 5 /2 +;.dw #ancho_pantalla_bytes * 6 /2 +;.dw #ancho_pantalla_bytes * 7 /2 +;.dw #ancho_pantalla_bytes * 8 /2 +;.dw #ancho_pantalla_bytes * 9 /2 +;.dw #ancho_pantalla_bytes * 10 /2 +;.dw #ancho_pantalla_bytes * 11 /2 +;.dw #ancho_pantalla_bytes * 12 /2 +;.dw #ancho_pantalla_bytes * 13 /2 +;.dw #ancho_pantalla_bytes * 14 /2 +;.dw #ancho_pantalla_bytes * 15 /2 +;.dw #ancho_pantalla_bytes * 16 /2 +;.dw #ancho_pantalla_bytes * 17 /2 +;.dw #ancho_pantalla_bytes * 18 /2 +;.dw #ancho_pantalla_bytes * 19 /2 + + +;------------------------------------------------------------------------------------ +; TILE DATA. TILES MUST BE DEFINED HERE +;------------------------------------------------------------------------------------ + + +_tiles: ;Son de 2x8 bytes +;tile 0 +.db #0x00,#0x00 +.db #0x40,#0x00 +.db #0x40,#0x00 +.db #0x40,#0x00 +.db #0x40,#0x00 +.db #0x40,#0x00 +.db #0x40,#0xC0 +.db #0x00,#0x00 +;tile 1 +.db #0x3C,#0x00 +.db #0x3C,#0x00 +.db #0x00,#0x3C +.db #0x00,#0x3C +.db #0x3C,#0x00 +.db #0x3C,#0x00 +.db #0x00,#0x3C +.db #0x00,#0x3C +;tile 2 +.db #0x00,#0x00 +.db #0x15,#0x00 +.db #0x00,#0x2A +.db #0x15,#0x00 +.db #0x00,#0x2A +.db #0x15,#0x00 +.db #0x00,#0x00 +.db #0x00,#0x00 diff --git a/lib/cpcrslib/Wyz.s b/lib/cpcrslib/Wyz.s new file mode 100644 index 0000000..4724c3e --- /dev/null +++ b/lib/cpcrslib/Wyz.s @@ -0,0 +1,1414 @@ +; ****************************************************** +; ** Librería de rutinas para Amstrad CPC ** +; ** Raúl Simarro, Artaburu 2010 ** +; ** PLAYER programado por WYZ ** +; ****************************************************** + +;XLIB cpc_WyzPlayer + + + +;XDEF CARGA_CANCION_WYZ +;XDEF INICIA_EFECTO_WYZ +;XDEF cpc_WyzSetPlayerOn0 +;XDEF cpc_WyzSetPlayerOff0 + +;XDEF TABLA_SONG +;XDEF TABLA_EFECTOS +;XDEF TABLA_PAUTAS +;;XDEF TABLA_SONIDOS +;XDEF INTERRUPCION + +;XDEF BUFFER_MUSICA +;XDEF direcc_tempo + + + + +;DEFINE BUFFER_DEC = #0x100 + + + + + +; CPC PSG proPLAYER - WYZ 2010 +;XREF INTERRUPCION + + +.globl _cpc_WyzConfigurePlayer + +_cpc_WyzConfigurePlayer:: + + LD HL,#2 + ADD HL,SP + LD a,(HL) + + LD (#INTERR),A + RET + + +.globl _cpc_WyzInitPlayer + +_cpc_WyzInitPlayer:: + +; la entrada indica las tablas de canciones, pautas, efectos,... sólo hay que inicializar esos datos +; en la librería + PUSH IX + LD IX,#4 + ADD IX,SP + + LD L,6 (IX) + LD H,7 (IX) + LD (#TABLA_SONG0),HL + LD L,4 (IX) + LD H,5 (IX) + LD (#TABLA_EFECTOS0),HL + LD L,2 (IX) + LD H,3 (IX) + LD (#TABLA_PAUTAS0),HL + LD L,0 (IX) + LD H,1 (IX) + LD (#TABLA_SONIDOS0),HL + POP IX + RET + +.globl _cpc_WyzLoadSong + +_cpc_WyzLoadSong:: + LD HL,#2 + ADD HL,SP + LD A,(HL) + JP CARGA_CANCION_WYZ0 + + +.globl _cpc_WyzSetTempo + +_cpc_WyzSetTempo:: + LD HL,#2 + ADD HL,SP + LD A,(HL) + ld (#dir_tempo+1),a + ret + + +.globl _cpc_WyzStartEffect + +_cpc_WyzStartEffect:: + LD HL,#2 + ADD HL,SP + LD c,(HL) + INC HL + LD b,(HL) + ;AHORA TIENE 2 parámetros: C:canal, B:numero efecto + JP INICIA_EFECTO_WYZ0 + +;.globl _cpc_WyzStartSound + +;_cpc_WyzStartSound:: +; LD HL,#2 +; ADD HL,SP +; LD A,(HL) +; JP INICIA_SONIDO_WYZ + +.globl _cpc_WyzTestPlayer + +_cpc_WyzTestPlayer:: + LD HL,#INTERR + LD A,(HL) + LD L,A + LD H,#0 + RET + +_cpc_WyzPlayer:: + +;.globl _cpc_WyzSetPlayerOn +;.globl _cpc_WyzSetPlayerOn1 + +;_cpc_WyzSetPlayerOn:: +;_cpc_WyzSetPlayerOn1:: + ;El player funcionará por interrupciones. +; DI +; ld a,(#0x0038) +; ld (#datos_int),a +; ld (#salto_int),a +; ld a,(#0x0039) +; ld (#datos_int+1),a +; ld (#salto_int+1),a +; ld a,(#0x003a) +; ld (#datos_int+2),a +; ld (#salto_int+2),a +; +; ld a,#0xC3 +; ld (#0x0038),a +; ld HL,#INICIO +; ld (#0x0039),HL +; EI +; ret + +.globl _cpc_WyzSetPlayerOff +;.globl _cpc_WyzSetPlayerOff1 +_cpc_WyzSetPlayerOff:: +;_cpc_WyzSetPlayerOff1:: + + ;apago todos los sonidos poniendo los registros a 0 + call PLAYER_OFF + ret + + ;DI + ;Restaura salto original + ;ld a,(#datos_int) ;guardo el salto original + ;ld (#0x0038),A + ;ld a,(#datos_int+1) ;guardo el salto original + ;ld (#0x0039),A + ;ld a,(#datos_int+2) ;guardo el salto original + ;ld (#0x003a),A + + ;EI + ;ret + + + + + +;___________________________________________________________ + + ; .db "PSG PROPLAYER BY WYZ'10" + +;___________________________________________________________ + + +;___________________________________________________________ + +.globl _cpc_WyzPlayerISR + +_cpc_WyzPlayerISR:: + +INICIO: + + + ;primero mira si toca tocar :P + ;push af + LD A,(#contador) + DEC A + LD (#contador),A + OR #0 + JP NZ,termina_int +dir_tempo: + LD A,#6 + LD (#contador),A + + ;EXX -> by int6 + PUSH IX + PUSH IY + + + + CALL ROUT + LD HL,#PSG_REG + LD DE,#PSG_REG_SEC + LD BC,#14 + LDIR + + + + CALL PLAY + CALL REPRODUCE_SONIDO + + LD HL,#PSG_REG_SEC + LD DE,#PSG_REG_EF + LD BC,#14 + LDIR + + ;De este modo, prevalece el efecto + CALL REPRODUCE_EFECTO_A + CALL REPRODUCE_EFECTO_B + CALL REPRODUCE_EFECTO_C + CALL ROUT_EF + + +exit_no_loop: + POP IY + POP IX + ;EXX -> by int 6 + +termina_int: + ;pop af + ex af,af + ei + ret +;salto_int: +;.db #0,#0,#0 + + + +contador: .db #0 +;datos_int: .db #0,#0,#0 ; Se guardan 3 BYTES!!!! (Dedicado a Na_th_an, por los desvelos) + + + +;INICIA EL SONIDO Nº (A) + +;INICIA EL SONIDO Nº (A) + +INICIA_EFECTO_WYZ0: + +;INICIA EL SONIDO Nº (B) EN EL CANAL (C) + LD A,C + CP #0 + JP Z,INICIA_EFECTO_A + CP #1 + JP Z,INICIA_EFECTO_B + CP #2 + JP Z,INICIA_EFECTO_C + ;JP INICIA_EFECTO_A + RET + + +;REPRODUCE EFECTOS + + + + +;REPRODUCE EFECTOS CANAL A + + +REPRODUCE_EFECTO_A: + LD HL,#INTERR + BIT 3,(HL) ;ESTA ACTIVADO EL EFECTO? + RET Z + LD HL,(#PUNTERO_EFECTO_A) + LD A,(HL) + CP #0xFF + JR Z,FIN_EFECTO_A + CALL BLOQUE_COMUN + LD (#PUNTERO_EFECTO_A),HL + LD 0 (IX),B + LD 1 (IX),C + LD 8 (IX),A + RET +FIN_EFECTO_A: + LD HL,#INTERR + RES 3,(HL) + XOR A + LD (#PSG_REG_EF+0),A + LD (#PSG_REG_EF+1),A + LD (#PSG_REG_EF+8),A + RET + +REPRODUCE_EFECTO_B: + LD HL,#INTERR + BIT 5,(HL) ;ESTA ACTIVADO EL EFECTO? + RET Z + LD HL,(#PUNTERO_EFECTO_B) + LD A,(HL) + CP #0xFF + JR Z,FIN_EFECTO_B + CALL BLOQUE_COMUN + LD (#PUNTERO_EFECTO_B),HL + LD 2 (IX),B + LD 3 (IX),C + LD 9 (IX),A + RET +FIN_EFECTO_B: + LD HL,#INTERR + RES 5,(HL) + XOR A + LD (#PSG_REG_EF+2),A + LD (#PSG_REG_EF+3),A + LD (#PSG_REG_EF+9),A + RET + +REPRODUCE_EFECTO_C: + LD HL,#INTERR + BIT 6,(HL) ;ESTA ACTIVADO EL EFECTO? + RET Z + LD HL,(#PUNTERO_EFECTO_C) + LD A,(HL) + CP #0xFF + JR Z,FIN_EFECTO_C + CALL BLOQUE_COMUN + LD (#PUNTERO_EFECTO_C),HL + LD 4 (IX),B + LD 5 (IX),C + LD 10 (IX),A + RET +FIN_EFECTO_C: + LD HL,#INTERR + RES 6,(HL) + XOR A + LD (#PSG_REG_EF+4),A + LD (#PSG_REG_EF+5),A + LD (#PSG_REG_EF+10),A + RET + +BLOQUE_COMUN: + LD IX,#PSG_REG_EF + LD B,A + INC HL + LD A,(HL) + RRCA + RRCA + RRCA + RRCA + AND #0b00001111 + LD C,A + LD A,(HL) + AND #0b00001111 + INC HL + RET + +INICIA_EFECTO_A: + LD A,B + LD HL,(#TABLA_EFECTOS0) + CALL EXT_WORD + LD (#PUNTERO_EFECTO_A),HL + LD HL,#INTERR + SET 3,(HL) + RET + +INICIA_EFECTO_B: + LD A,B + LD HL,(#TABLA_EFECTOS0) + CALL EXT_WORD + LD (#PUNTERO_EFECTO_B),HL + LD HL,#INTERR + SET 5,(HL) + RET + +INICIA_EFECTO_C: + LD A,B + LD HL,(#TABLA_EFECTOS0) + CALL EXT_WORD + LD (#PUNTERO_EFECTO_C),HL + LD HL,#INTERR + SET 6,(HL) + RET + + + +INICIA_SONIDO: + LD HL,(#TABLA_SONIDOS0) + CALL EXT_WORD + LD (#PUNTERO_SONIDO),HL + LD HL,#INTERR + SET 2,(HL) + RET +;PLAYER OFF + +PLAYER_OFF: + LD HL,#INTERR + + XOR A + + LD (HL), A + + LD HL,#PSG_REG + LD DE,#PSG_REG+1 + LD BC,#14 + LD (HL),A + LDIR + + LD HL,#PSG_REG_SEC + LD DE,#PSG_REG_SEC+1 + LD BC,#14 + LD (HL),A + LDIR + + LD HL,#PSG_REG_EF + LD DE,#PSG_REG_EF+1 + LD BC,#14 + LD (HL),A + LDIR + + CALL ROUT + CALL ROUT_EF + CALL FIN_SONIDO + RET + + + + +CARGA_CANCION_WYZ0: + DI + push af + CALL PLAYER_OFF + pop af +; MUSICA DATOS INICIALES + + + + + LD DE,#0x0010 ; Nº BYTES RESERVADOS POR CANAL + LD HL,#BUFFER_DEC ;* RESERVAR MEMORIA PARA BUFFER DE SONIDO!!!!! + LD (#CANAL_A),HL + + ADD HL,DE + LD (#CANAL_B),HL + + ADD HL,DE + LD (#CANAL_C),HL + + ADD HL,DE + LD (#CANAL_P),HL + + ;LD A,#0 ;* CANCION Nº 0 + CALL CARGA_CANCION + + LD A,#6 + LD (#contador),A + +;PANTALLA + EI + ret + + + +;CARGA UNA CANCION +;IN:(A)=Nº DE CANCION + +CARGA_CANCION: + LD HL,#INTERR ;CARGA CANCION + + LD (HL), #0 ;RESETEA TODO + SET 1,(HL) ;REPRODUCE CANCION + LD HL,#SONG + LD (HL),A ;Nº A + + + +;DECODIFICAR +;IN-> INTERR 0 ON +; SONG + +;CARGA CANCION SI/NO + +DECODE_SONG: + LD A,(#SONG) + +;LEE CABECERA DE LA CANCION +;BYTE 0=TEMPO + + ;LD HL,TABLA_SONG + LD HL,(#TABLA_SONG0) + CALL EXT_WORD + LD A,(HL) + LD (#TEMPO),A + XOR A + LD (#TTEMPO),A + +;HEADER BYTE 1 +;(-|-|-|-|-|-|-|LOOP) + + INC HL ;LOOP 1=ON/0=OFF? + LD A,(HL) + BIT 0,A + JR Z,NPTJP0 + PUSH HL + LD HL,#INTERR + SET 4,(HL) + POP HL + + +NPTJP0: + INC HL ;2 BYTES RESERVADOS + INC HL + INC HL + +;BUSCA Y GUARDA INICIO DE LOS CANALES EN EL MODULO MUS + + + LD (#PUNTERO_P_DECA),HL + LD E,#0x3F ;CODIGO INTRUMENTO 0 + LD B,#0xFF ;EL MODULO DEBE TENER UNA LONGITUD MENOR DE #0xFF00 ... o_O! +BGICMODBC1: + XOR A ;BUSCA EL BYTE 0 + CPIR + DEC HL + DEC HL + LD A,E ;ES EL INSTRUMENTO 0?? + CP (HL) + INC HL + INC HL + JR Z,BGICMODBC1 + + LD (#PUNTERO_P_DECB),HL + +BGICMODBC2: + XOR A ;BUSCA EL BYTE 0 + CPIR + DEC HL + DEC HL + LD A,E + CP (HL) ;ES EL INSTRUMENTO 0?? + INC HL + INC HL + JR Z,BGICMODBC2 + + LD (#PUNTERO_P_DECC),HL + +BGICMODBC3: + XOR A ;BUSCA EL BYTE 0 + CPIR + DEC HL + DEC HL + LD A,E + CP (HL) ;ES EL INSTRUMENTO 0?? + INC HL + INC HL + JR Z,BGICMODBC3 + LD (#PUNTERO_P_DECP),HL + + +;LEE DATOS DE LAS NOTAS +;(|)(|||||) LONGITUD\NOTA + +INIT_DECODER: + LD DE,(#CANAL_A) + LD (#PUNTERO_A),DE + LD HL,(#PUNTERO_P_DECA) + CALL DECODE_CANAL ;CANAL A + LD (#PUNTERO_DECA),HL + + LD DE,(#CANAL_B) + LD (#PUNTERO_B),DE + LD HL,(#PUNTERO_P_DECB) + CALL DECODE_CANAL ;CANAL B + LD (#PUNTERO_DECB),HL + + LD DE,(#CANAL_C) + LD (#PUNTERO_C),DE + LD HL,(#PUNTERO_P_DECC) + CALL DECODE_CANAL ;CANAL C + LD (#PUNTERO_DECC),HL + + LD DE,(#CANAL_P) + LD (#PUNTERO_P),DE + LD HL,(#PUNTERO_P_DECP) + CALL DECODE_CANAL ;CANAL P + LD (#PUNTERO_DECP),HL + + RET + + +;DECODIFICA NOTAS DE UN CANAL +;IN (DE)=DIRECCION DESTINO +;NOTA=0 FIN CANAL +;NOTA=1 SILENCIO +;NOTA=2 PUNTILLO +;NOTA=3 COMANDO I + +DECODE_CANAL: + LD A,(HL) + AND A ;FIN DEL CANAL? + JR Z,FIN_DEC_CANAL + CALL GETLEN + + CP #0b00000001 ;ES SILENCIO? + JR NZ,NO_SILENCIO + SET 6,A + JR NO_MODIFICA + +NO_SILENCIO: + CP #0b00111110 ;ES PUNTILLO? + JR NZ,NO_PUNTILLO + OR A + RRC B + XOR A + JR NO_MODIFICA + +NO_PUNTILLO: + CP #0b00111111 ;ES COMANDO? + JR NZ,NO_MODIFICA + BIT 0,B ;COMADO=INSTRUMENTO? + JR Z,NO_INSTRUMENTO + LD A,#0b11000001 ;CODIGO DE INSTRUMENTO + LD (DE),A + INC HL + INC DE + LD A,(HL) ;Nº DE INSTRUMENTO + LD (DE),A + INC DE + INC HL + JR DECODE_CANAL + +NO_INSTRUMENTO: + BIT 2,B + JR Z,NO_ENVOLVENTE + LD A,#0b11000100 ;CODIGO ENVOLVENTE + LD (DE),A + INC DE + INC HL + JR DECODE_CANAL + +NO_ENVOLVENTE: + BIT 1,B + JR Z,NO_MODIFICA + LD A,#0b11000010 ;CODIGO EFECTO + LD (DE),A + INC HL + INC DE + LD A,(HL) + CALL GETLEN + +NO_MODIFICA: + LD (DE),A + INC DE + XOR A + DJNZ NO_MODIFICA + SET 7,A + SET 0,A + LD (DE),A + INC DE + INC HL + RET ;** JR DECODE_CANAL + +FIN_DEC_CANAL: + SET 7,A + LD (DE),A + INC DE + RET + +GETLEN: + LD B,A + AND #0b00111111 + PUSH AF + LD A,B + AND #0b11000000 + RLCA + RLCA + INC A + LD B,A + LD A,#0b10000000 +DCBC0: + RLCA + DJNZ DCBC0 + LD B,A + POP AF + RET + + + + + + +;PLAY __________________________________________________ + + +PLAY: + LD HL,#INTERR ;PLAY BIT 1 ON? + BIT 1,(HL) + RET Z +;TEMPO + LD HL,#TTEMPO ;CONTADOR TEMPO + INC (HL) + LD A,(#TEMPO) + CP (HL) + JR NZ,PAUTAS + LD (HL),#0 + +;INTERPRETA + LD IY,#PSG_REG + LD IX,#PUNTERO_A + LD BC,#PSG_REG+8 + CALL LOCALIZA_NOTA + LD IY,#PSG_REG+2 + LD IX,#PUNTERO_B + LD BC,#PSG_REG+9 + CALL LOCALIZA_NOTA + LD IY,#PSG_REG+4 + LD IX,#PUNTERO_C + LD BC,#PSG_REG+10 + CALL LOCALIZA_NOTA + LD IX,#PUNTERO_P ;EL CANAL DE EFECTOS ENMASCARA OTRO CANAL + CALL LOCALIZA_EFECTO + +;PAUTAS + +PAUTAS: + LD IY,#PSG_REG+0 + LD IX,#PUNTERO_P_A + LD HL,#PSG_REG+8 + CALL PAUTA ;PAUTA CANAL A + LD IY,#PSG_REG+2 + LD IX,#PUNTERO_P_B + LD HL,#PSG_REG+9 + CALL PAUTA ;PAUTA CANAL B + LD IY,#PSG_REG+4 + LD IX,#PUNTERO_P_C + LD HL,#PSG_REG+10 + CALL PAUTA ;PAUTA CANAL C + + RET + + + +;REPRODUCE EFECTOS DE SONIDO + +REPRODUCE_SONIDO: + + LD HL,#INTERR + BIT 2,(HL) ;ESTA ACTIVADO EL EFECTO? + RET Z + LD HL,(#PUNTERO_SONIDO) + LD A,(HL) + CP #0xFF + JR Z,FIN_SONIDO + LD (#PSG_REG_SEC+4),A + INC HL + LD A,(HL) + RRCA + RRCA + RRCA + RRCA + AND #0b00001111 + LD (#PSG_REG_SEC+5),A + LD A,(HL) + AND #0b00001111 + LD (#PSG_REG_SEC+10),A + INC HL + LD A,(HL) + AND A + JR Z,NO_RUIDO + LD (#PSG_REG_SEC+6),A + LD A,#0b10011000 + JR SI_RUIDO +NO_RUIDO: + LD A,#0b10111000 +SI_RUIDO: + LD (#PSG_REG_SEC+7),A + + INC HL + LD (#PUNTERO_SONIDO),HL + RET +FIN_SONIDO: + LD HL,#INTERR + RES 2,(HL) + +FIN_NOPLAYER: + LD A,#0b10111000 ;2 BITS ALTOS PARA MSX / AFECTA AL CPC??? + LD (#PSG_REG+7),A + RET + +;VUELCA BUFFER DE SONIDO AL PSG + +;VUELCA BUFFER DE SONIDO AL PSG + +ROUT: + XOR A + LD HL,#PSG_REG_SEC +LOUT: + CALL WRITEPSGHL + INC A + CP #13 + JR NZ,LOUT + LD A,(HL) + AND A + RET Z + LD A,#13 + CALL WRITEPSGHL + XOR A + LD (#PSG_REG+13),A + LD (#PSG_REG_SEC+13),A + RET + + +ROUT_EF: + XOR A + LD HL,#PSG_REG_EF +LOUT_EF: + CALL WRITEPSGHL + INC A + CP #13 + JR NZ,LOUT_EF + LD A,(HL) + AND A + RET Z + LD A,#13 + CALL WRITEPSGHL + XOR A + LD (#PSG_REG_EF+13),A + RET +;; A = REGISTER +;; (HL) = VALUE +WRITEPSGHL: + LD B,#0xF4 + OUT (C),A + LD BC,#0xF6C0 + OUT (C),C + .db #0xED + .db #0x71 + LD B,#0xF5 + OUTI + LD BC,#0xF680 + OUT (C),C + .db #0xED + .db #0x71 + RET + +;LOCALIZA NOTA CANAL A +;IN (PUNTERO_A) + +LOCALIZA_NOTA: + LD L,0 (IX) ;HL=(PUNTERO_A_C_B) + LD H,1 (IX) + LD A,(HL) + AND #0b11000000 ;COMANDO? + CP #0b11000000 + JR NZ,LNJP0 + +;BIT(0)=INSTRUMENTO + +COMANDOS: + LD A,(HL) + BIT 0,A ;INSTRUMENTO + JR Z,COM_EFECTO + + INC HL + LD A,(HL) ;Nº DE PAUTA + INC HL + LD 0 (IX),L + LD 1 (IX),H + ;LD HL,TABLA_PAUTAS + LD HL,(#TABLA_PAUTAS0) + CALL EXT_WORD + LD 18 (IX),L + LD 19 (IX),H + LD 12 (IX),L + LD 13 (IX),H + LD L,C + LD H,B + RES 4,(HL) ;APAGA EFECTO ENVOLVENTE + XOR A + LD (#PSG_REG_SEC+13),A + LD (#PSG_REG+13),A + JR LOCALIZA_NOTA + +COM_EFECTO: + BIT 1,A ;EFECTO DE SONIDO + JR Z,COM_ENVOLVENTE + + INC HL + LD A,(HL) + INC HL + LD 0 (IX),L + LD 1 (IX),H + CALL INICIA_SONIDO + RET + +COM_ENVOLVENTE: + BIT 2,A + RET Z ;IGNORA - ERROR + + INC HL + LD 0 (IX),L + LD 1 (IX),H + LD L,C + LD H,B + LD (HL),#0b00010000 ;ENCIENDE EFECTO ENVOLVENTE + JR LOCALIZA_NOTA + + +LNJP0: + LD A,(HL) + INC HL + BIT 7,A + JR Z,NO_FIN_CANAL_A ; + BIT 0,A + JR Z,FIN_CANAL_A + +FIN_NOTA_A: + LD E,6 (IX) + LD D,7 (IX) ;PUNTERO BUFFER AL INICIO + LD 0 (IX),E + LD 1 (IX),D + LD L,30 (IX) ;CARGA PUNTERO DECODER + LD H,31 (IX) + PUSH BC + CALL DECODE_CANAL ;DECODIFICA CANAL + POP BC + LD 30 (IX),L ;GUARDA PUNTERO DECODER + LD 31 (IX),H + JP LOCALIZA_NOTA + +FIN_CANAL_A: + LD HL,#INTERR ;LOOP? + BIT 4,(HL) + JR NZ,FCA_CONT + CALL PLAYER_OFF + POP AF + POP AF + JP exit_no_loop + +FCA_CONT: + LD L,24 (IX) ;CARGA PUNTERO INICIAL DECODER + LD H,25 (IX) + LD 30 (IX),L + LD 31 (IX),H + JR FIN_NOTA_A + +NO_FIN_CANAL_A: + LD 0 (IX),L ;(PUNTERO_A_B_C)=HL GUARDA PUNTERO + LD 1 (IX),H + AND A ;NO REPRODUCE NOTA SI NOTA=0 + JR Z,FIN_RUTINA + BIT 6,A ;SILENCIO? + JR Z,NO_SILENCIO_A + LD A,(BC) + AND #0b00010000 + JR NZ,SILENCIO_ENVOLVENTE + XOR A + LD (BC),A ;RESET VOLUMEN + LD 0 (IY),A + LD 1 (IY),A + RET + +SILENCIO_ENVOLVENTE: + LD A,#0xFF + LD (#PSG_REG+11),A + LD (#PSG_REG+12),A + XOR A + LD (#PSG_REG+13),A + LD 0 (IY),A + LD 1 (IY),A + RET + +NO_SILENCIO_A: + CALL NOTA ;REPRODUCE NOTA + LD L,18 (IX) ;HL=(PUNTERO_P_A0) RESETEA PAUTA + LD H,19 (IX) + LD 12 (IX),L ;(PUNTERO_P_A)=HL + LD 13 (IX),H +FIN_RUTINA: + RET + + +;LOCALIZA EFECTO +;IN HL=(PUNTERO_P) + +LOCALIZA_EFECTO: + LD L,0 (IX) ;HL=(PUNTERO_P) + LD H,1 (IX) + LD A,(HL) + CP #0b11000010 + JR NZ,LEJP0 + + INC HL + LD A,(HL) + INC HL + LD 0 (IX),L + LD 1 (IX),H + CALL INICIA_SONIDO + RET + + +LEJP0: + INC HL + BIT 7,A + JR Z,NO_FIN_CANAL_P ; + BIT 0,A + JR Z,FIN_CANAL_P +FIN_NOTA_P: + LD DE,(#CANAL_P) + LD 0 (IX),E + LD 1 (IX),D + LD HL,(#PUNTERO_DECP) ;CARGA PUNTERO DECODER + PUSH BC + CALL DECODE_CANAL ;DECODIFICA CANAL + POP BC + LD (#PUNTERO_DECP),HL ;GUARDA PUNTERO DECODER + JP LOCALIZA_EFECTO + +FIN_CANAL_P: + LD HL,(#PUNTERO_P_DECP) ;CARGA PUNTERO INICIAL DECODER + LD (#PUNTERO_DECP),HL + JR FIN_NOTA_P + +NO_FIN_CANAL_P: + LD 0 (IX),L ;(PUNTERO_A_B_C)=HL GUARDA PUNTERO + LD 1 (IX),H + RET + +; PAUTA DE LOS 3 CANALES +; IN:(IX):PUNTERO DE LA PAUTA +; (HL):REGISTRO DE VOLUMEN +; (IY):REGISTROS DE FRECUENCIA + +; FORMATO PAUTA +; 7 6 5 4 3-0 3-0 +; BYTE 1 (LOOP|OCT-1|OCT+1|SLIDE|VOL) - BYTE 2 ( | | | |PITCH) + +PAUTA: + BIT 4,(HL) ;SI LA ENVOLVENTE ESTA ACTIVADA NO ACTUA PAUTA + RET NZ + + LD A,0 (IY) + LD B,1 (IY) + OR B + RET Z + + + PUSH HL + ;LD L,(IX+0) + ;LD H,(IX+1) + + ;LD A,(HL) ;COMPRUEBA SLIDE BIT 4 + ;BIT 4,A + ;JR Z,PCAJP4 + ;LD L,(IY+0) ;FRECUENCIA FINAL + ;LD H,(IY+1) + ;SBC HL,DE + ;JR Z,PCAJP4 + ;JR C,SLIDE_POS + ;EX DE,HL + ;RRC D ;/4 + ;RR E + ;RRC D + ;RR E + + + ;ADC HL,DE + ;LD (IY+0),L + ;LD (IY+1),H +SLIDE_POS: + ;POP HL + ;RET + +PCAJP4: + LD L,0 (IX) + LD H,1 (IX) + LD A,(HL) + + BIT 7,A ;LOOP / EL RESTO DE BITS NO AFECTAN + JR Z,PCAJP0 + AND #0b00011111 ;LOOP PAUTA (0,32)X2!!!-> PARA ORNAMENTOS + RLCA ;X2 + LD D,#0 + LD E,A + SBC HL,DE + LD A,(HL) + +PCAJP0: + BIT 6,A ;OCTAVA -1 + JR Z,PCAJP1 + LD E,0 (IY) + LD D,1 (IY) + + AND A + RRC D + RR E + LD 0 (IY),E + LD 1 (IY),D + JR PCAJP2 + +PCAJP1: + BIT 5,A ;OCTAVA +1 + JR Z,PCAJP2 + LD E,0 (IY) + LD D,1 (IY) + + AND A + RLC E + RL D + LD 0 (IY),E + LD 1 (IY),D + + +PCAJP2: + INC HL + PUSH HL + LD E,A + LD A,(HL) ;PITCH DE FRECUENCIA + LD L,A + AND A + LD A,E + JR Z,ORNMJP1 + + LD A,0 (IY) ;SI LA FRECUENCIA ES 0 NO HAY PITCH + ADD A,1 (IY) + AND A + LD A,E + JR Z,ORNMJP1 + + + BIT 7,L + JR Z,ORNNEG + LD H,#0xFF + JR PCAJP3 +ORNNEG: + LD H,#0 + +PCAJP3: + LD E,0 (IY) + LD D,1 (IY) + ADC HL,DE + LD 0 (IY),L + LD 1 (IY),H +ORNMJP1: + POP HL + + INC HL + LD 0 (IX),L + LD 1 (IX),H +PCAJP5: + POP HL + AND #0b00001111 ;VOLUMEN FINAL + LD (HL),A + RET + + + +;NOTA : REPRODUCE UNA NOTA +;IN (A)=CODIGO DE LA NOTA +; (IY)=REGISTROS DE FRECUENCIA + + +NOTA: + ;ADD 6 ;************************* + LD L,C + LD H,B + BIT 4,(HL) + LD B,A + JR NZ,EVOLVENTES + LD A,B + LD HL,#DATOS_NOTAS + RLCA ;X2 + LD D,#0 + LD E,A + ADD HL,DE + LD A,(HL) + LD 0 (IY),A + INC HL + LD A,(HL) + LD 1 (IY),A + RET + +;IN (A)=CODIGO DE LA ENVOLVENTE +; (IY)=REGISTRO DE FRECUENCIA + +EVOLVENTES: + PUSH AF + CALL ENV_RUT1 + LD DE,#0x0000 + LD 0 (IY),E + LD 1 (IY),D + + POP AF + ADD A,#48 + CALL ENV_RUT1 + + + LD A,E + LD (#PSG_REG+11),A + LD A,D + LD (#PSG_REG+12),A + LD A,#0x0E + LD (#PSG_REG+13),A + RET + +;IN(A) NOTA +ENV_RUT1: + LD HL,#DATOS_NOTAS + RLCA ;X2 + LD D,#0 + LD E,A + ADD HL,DE + LD E,(HL) + INC HL + LD D,(HL) + RET + + + +EXT_WORD: + LD D,#0 + SLA A ;*2 + LD E,A + ADD HL,DE + LD E,(HL) + INC HL + LD D,(HL) + EX DE,HL + RET + +;BANCO DE INSTRUMENTOS 2 BYTES POR INT. + +;(0)(RET 2 OFFSET) +;(1)(+-PITCH) + + +;BANCO DE INSTRUMENTOS 2 BYTES POR INT. + +;(0)(RET 2 OFFSET) +;(1)(+-PITCH) + +;.TABLA_PAUTAS .dw PAUTA_1,PAUTA_2,PAUTA_3,PAUTA_4,PAUTA_5,PAUTA_6,PAUTA_7;,PAUTA_8,PAUTA_9,PAUTA_10,PAUTA_11,PAUTA_12,PAUTA_13,PAUTA_14,PAUTA_15,PAUTA_16,PAUTA_17,PAUTA_18 + + + + + + + + + + + +;DATOS DE LOS EFECTOS DE SONIDO + +;EFECTOS DE SONIDO + + + +;.TABLA_SONIDOS .dw SONIDO1,SONIDO2,SONIDO3,SONIDO4,SONIDO5;,SONIDO6,SONIDO7;,SONIDO8 + +TABLA_PAUTAS0: .dw 0 + +TABLA_SONIDOS0: .dw 0 + + +;DATOS MUSICA + + + +;TABLA_SONG: .dw SONG_0;,SONG_1,SONG_2;,SONG_3 ;******** TABLA DE DIRECCIONES DE ARCHIVOS MUS + +;DATOS_NOTAS: .INCBIN "C:/EM/BRMSX/PLAYER/NOTAS.DAT" ;DATOS DE LAS NOTAS + + +DATOS_NOTAS: + .dw #0x0000,#0x0000 + +; .dw #0x41D,#0x3E2,#0x3AA,#0x376,#0x344,#0x315,#0x2E9,#0x2BF,#0x297,#0x272,#0x24F,#0x22E,#0x20E,#0x1F1,#0x1D5,#0x1BB +; .dw #0x1A2,#0x18A,#0x174,#0x15F,#0x14B,#0x139,#0x127,#0x117,#0x107,#0xF8,#0xEA,#0xDD +; .dw #0xD1,#0xC5,#0xBA,#0xAF,#0xA5,#0x9C,#0x93,#0x8B,#0x83,#0x7C,#0x75,#0x6E +; .dw #0x68,#0x62,#0x5D,#0x57,#0x52,#0x4E,#0x49,#0x45,#0x41,#0x3E,#0x3A,#0x37 +; .dw #0x34,#0x31,#0x2E,#0x2B,#0x29,#0x27,#0x24,#0x22,#0x20,#0x1F,#0x1D,#0x1B +; .dw #0x1A,#0x18,#0x17,#0x15,#0x14,#0x13,#0x12,#0x11,#0x10,#0xF,#0xE,#0xD + + +.DW #1711,#1614,#1524,#1438,#1358,#1281,#1210,#1142,#1078,#1017 +.DW #960,#906,#855,#807,#762,#719,#679,#641,#605,#571 +.DW #539,#509,#480,#453,#428,#404,#381,#360,#339,#320 +.DW #302,#285,#269,#254,#240,#227,#214,#202,#190,#180 +.DW #170,#160,#151,#143,#135,#127,#120,#113,#107,#101 +.DW #95,#90,#85,#80,#76,#71,#67,#64,#60,#57 + + +;SONG_0: + ;INCBIN "WYAZOW.MUS" + + + +; VARIABLES__________________________ + + +INTERR: + .db #0 ;INTERRUPTORES 1=ON 0=OFF + ;BIT 0=CARGA CANCION ON/OFF + ;BIT 1=PLAYER ON/OFF + ;BIT 2=SONIDOS ON/OFF + ;BIT 3=EFECTOS ON/OFF + +;MUSICA **** EL ORDEN DE LAS VARIABLES ES FIJO ****** + +TABLA_SONG0: .dw #0 +TABLA_EFECTOS0: .dw #0 + +;.db 'P','S','G',' ','P','R','O','P','L','A','Y','E','R',' ','B','Y',' ','W','Y','Z','-','1','0' + + +SONG: .db #00 ;DBNº DE CANCION +TEMPO: .db #00 ;.dbTEMPO +TTEMPO: .db #00 ;.dbCONTADOR TEMPO +PUNTERO_A: .dw #00 ;DW PUNTERO DEL CANAL A +PUNTERO_B: .dw #00 ;DW PUNTERO DEL CANAL B +PUNTERO_C: .dw #00 ;DW PUNTERO DEL CANAL C + +BUFFER_MUSICA: +CANAL_A: .dw #00 ;DW DIRECION DE INICIO DE LA MUSICA A +CANAL_B: .dw #00 ;DW DIRECION DE INICIO DE LA MUSICA B +CANAL_C: .dw #00 ;DW DIRECION DE INICIO DE LA MUSICA C + +PUNTERO_P_A: .dw #00 ;DW PUNTERO PAUTA CANAL A +PUNTERO_P_B: .dw #00 ;DW PUNTERO PAUTA CANAL B +PUNTERO_P_C: .dw #00 ;DW PUNTERO PAUTA CANAL C + +PUNTERO_P_A0: .dw #00 ;DW INI PUNTERO PAUTA CANAL A +PUNTERO_P_B0: .dw #00 ;DW INI PUNTERO PAUTA CANAL B +PUNTERO_P_C0: .dw #00 ;DW INI PUNTERO PAUTA CANAL C + + +PUNTERO_P_DECA: .dw #00 ;DW PUNTERO DE INICIO DEL DECODER CANAL A +PUNTERO_P_DECB: .dw #00 ;DW PUNTERO DE INICIO DEL DECODER CANAL B +PUNTERO_P_DECC: .dw #00 ;DW PUNTERO DE INICIO DEL DECODER CANAL C + +PUNTERO_DECA: .dw #00 ;DW PUNTERO DECODER CANAL A +PUNTERO_DECB: .dw #00 ;DW PUNTERO DECODER CANAL B +PUNTERO_DECC: .dw #00 ;DW PUNTERO DECODER CANAL C + + +;CANAL DE EFECTOS - ENMASCARA OTRO CANAL + +PUNTERO_P: .dw #00 ;DW PUNTERO DEL CANAL EFECTOS +CANAL_P: .dw #00 ;DW DIRECION DE INICIO DE LOS EFECTOS +PUNTERO_P_DECP: .dw #00 ;DW PUNTERO DE INICIO DEL DECODER CANAL P +PUNTERO_DECP: .dw #00 ;DW PUNTERO DECODER CANAL P + +PSG_REG: .db #00,#00,#00,#00,#00,#00,#00,#0b10111000 ,#00,#00,#00,#00,#00,#00,#00 ;.db(11) BUFFER DE REGISTROS DEL PSG +PSG_REG_SEC: .db #00,#00,#00,#00,#00,#00,#00,#0b10111000 ,#00,#00,#00,#00,#00,#00,#00 ;.db(11) BUFFER SECUNDARIO DE REGISTROS DEL PSG + +PSG_REG_EF: .db #00,#00,#00,#00,#00,#00,#00,#0b10111000 ,#00,#00,#00,#00,#00,#00,#00 ;.db(11) BUFFER DE REGISTROS DEL PSG + +;ENVOLVENTE_A EQU #0xD033 ;DB +;ENVOLVENTE_B EQU #0xD034 ;DB +;ENVOLVENTE_C EQU #0xD035 ;DB + + + + +;EFECTOS DE SONIDO + +N_SONIDO: .db #0 ;.db NUMERO DE SONIDO +PUNTERO_SONIDO: .dw #0 ;.dw PUNTERO DEL SONIDO QUE SE REPRODUCE + +;EFECTOS + +N_EFECTO: .db #0 ;.db NUMERO DE SONIDO +;PUNTERO_EFECTO .dw 0 ;.dw PUNTERO DEL SONIDO QUE SE REPRODUCE + +PUNTERO_EFECTO_A: .dw #0 ;DW : PUNTERO DEL SONIDO QUE SE REPRODUCE +PUNTERO_EFECTO_B: .dw #0 ;DW : PUNTERO DEL SONIDO QUE SE REPRODUCE +PUNTERO_EFECTO_C: .dw #0 ;DW : PUNTERO DEL SONIDO QUE SE REPRODUCE + + + + + + + + + + + +BUFFER_DEC: ; defs #0x40 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; 16 bytes +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; 32 bytes +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; 48 bytes +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; 64 bytes + + +; .db #0x00 ;************************* mucha atencion!!!! +;.BUFFER_DEC defs 2048 ;space dinamically asigned in source code compilation!! + ; aqui se decodifica la cancion hay que dejar suficiente espacio libre. + ;************************* + +;DEFC CARGA_CANCION_WYZ = CARGA_CANCION_WYZ0 +;DEFC INICIA_EFECTO_WYZ = INICIA_EFECTO_WYZ0 +;DEFC cpc_WyzSetPlayerOn0 = cpc_WyzSetPlayerOn1 +;DEFC cpc_WyzSetPlayerOff0 = cpc_WyzSetPlayerOff1 +;DEFC TABLA_SONG = TABLA_SONG0 +;DEFC TABLA_EFECTOS = TABLA_EFECTOS0 +;DEFC TABLA_PAUTAS = TABLA_PAUTAS0 +;DEFC TABLA_SONIDOS = TABLA_SONIDOS0 +;DEFC INTERRUPCION = INTERR +;DEFC direcc_tempo = dir_tempo diff --git a/lib/cpcrslib/cpc_ClrScr.s b/lib/cpcrslib/cpc_ClrScr.s new file mode 100644 index 0000000..49f1d2d --- /dev/null +++ b/lib/cpcrslib/cpc_ClrScr.s @@ -0,0 +1,11 @@ +.globl _cpc_ClrScr + +_cpc_ClrScr:: + XOR A + LD HL,#0xC000 + LD DE,#0xC001 + LD BC,#16383 + LD (HL),A + LDIR + RET + diff --git a/lib/cpcrslib/cpc_CollSp.s b/lib/cpcrslib/cpc_CollSp.s new file mode 100644 index 0000000..08bd02a --- /dev/null +++ b/lib/cpcrslib/cpc_CollSp.s @@ -0,0 +1,126 @@ +.globl _cpc_CollSp + +_cpc_CollSp:: +;first parameter sprite +;second parameter value + ld hl,#2 + add hl,sp + + ;ld ix,#2 + ;add ix,sp +; ld e,2 (ix) +; ld d,3 (ix) + ;A=x value +; ld l,0 (ix) +; ld h,1 (ix) + + ld e,(hl) + inc hl + ld d,(hl) + push de + inc hl + ld e,(hl) + inc hl + ld d,(hl) + push de + + pop iy ;ix sprite2 data + + pop ix ;iy sprite1 data + + ;Sprite coords & sprite dims + +;COLISION_sprites + + + +;entran sprite1 y sprite 2 y se actualizan los datos +;ix apunta a sprite1 +;iy apunta a sprite2 + +;coordenadas + ld l,8 (ix) + ld h,9 (ix) + LD (#SPR2X),HL + + ld l,8 (iy) + ld h,9 (iy) + LD (#SPR1X),HL + +;dimensiones sprite 1 + ld l,0 (ix) + ld h,1 (ix) + ld b,(hl) + inc hl + ld c,(hl) +;dimensiones sprite 12 + ld l,0 (iy) + ld h,1 (iy) + ld d,(hl) + inc hl + ld e,(hl) + + + ;ld e,(ix+6) + ;ld d,(ix+7) + + + +;ld de,DIMENSIONES_SP_PPAL ;dimensiones sprite 2 +;ld bc,DIMENSIONES_SP_PPAL ;dimensiones sprite 1 +CALL TOCADO +;RET NC ;vuelve si no hay colision +ld h,#0 +JP nc,no_colision +;Aquí hay colisión +ld l,#1 +RET + +no_colision: +ld l,h +ret + +TOCADO: + LD HL,#SPR2X + LD A,(#SPR1X) + CP (HL) + jp C,C1 + LD A,(HL) + ADD A,B ;alto del sprite1 + LD B,A + LD A,(#SPR1X) + SUB B + RET NC + jp COMPROBAR +C1: + ADD A,D ;alto sprite2 + LD D,A + LD A,(HL) + SUB D + RET NC +COMPROBAR: + INC HL + LD A,(#SPR1Y) + CP (HL) + jp C,C2 + LD A,(HL) + ADD A,C + LD C,A + LD A,(#SPR1Y) + SUB C + RET +C2: + ADD A,E + LD E,A + LD A,(HL) + SUB E + RET + +SPR1X: +.db 0 +SPR1Y: +.db 0 +SPR2X: +.db 0 +SPR2Y: +.db 0 diff --git a/lib/cpcrslib/cpc_DisableEnableFirmware.s b/lib/cpcrslib/cpc_DisableEnableFirmware.s new file mode 100644 index 0000000..00a8710 --- /dev/null +++ b/lib/cpcrslib/cpc_DisableEnableFirmware.s @@ -0,0 +1,28 @@ +.globl _cpc_DisableFirmware + +_cpc_DisableFirmware:: + DI + LD HL,(#0X0038) + LD (backup_fw),HL + LD HL,#0X0038 + LD (HL),#0XFB ;EI + INC HL + LD (HL),#0XC9 ;RET + EI + RET + +backup_fw: + .DW #0 + +.globl _cpc_EnableFirmware + +_cpc_EnableFirmware:: + DI + LD DE,(backup_fw) + LD HL,#0X0038 + LD (HL),E ;EI + INC HL + LD (HL),D ;RET + EI + RET + diff --git a/lib/cpcrslib/cpc_GetScrAddress.s b/lib/cpcrslib/cpc_GetScrAddress.s new file mode 100644 index 0000000..42b17f7 --- /dev/null +++ b/lib/cpcrslib/cpc_GetScrAddress.s @@ -0,0 +1,65 @@ +.globl _cpc_GetScrAddress + +_cpc_GetScrAddress:: + +; LD IX,#2 +; ADD IX,SP +; LD A,0 (IX) +; LD L,1 (IX) ;pantalla + + + LD HL,#2 + ADD HL,SP + LD A,(HL) + INC HL + LD L,(HL) + ;LD L,E + ;JP cpc_GetScrAddress0 + + +cpc_GetScrAddress0: ;en HL están las coordenadas + + ;LD A,H + LD (#inc_ancho+1),A + LD A,L + SRL A + SRL A + SRL A + ; A indica el bloque a multiplicar x &50 + LD D,A ;D + SLA A + SLA A + SLA A + SUB L + NEG + ; A indica el desplazamiento a multiplicar x &800 + LD E,A ;E + LD L,D + LD H,#0 + ADD HL,HL + LD BC,#bloques + ADD HL,BC + ;HL APUNTA AL BLOQUE BUSCADO + LD C,(HL) + INC HL + LD H,(HL) + LD L,C + ;HL TIENE EL VALOR DEL BLOQUE DE 8 BUSCADO + PUSH HL + LD D,#0 + LD HL,#sub_bloques + ADD HL,DE + LD A,(HL) + POP HL + ADD H + LD H,A +inc_ancho: + LD E,#0 + ADD HL,DE + RET + +bloques: +.DW #0XC000,#0XC050,#0XC0A0,#0XC0F0,#0XC140,#0XC190,#0XC1E0,#0XC230,#0XC280,#0XC2D0,#0XC320,#0XC370,#0XC3C0,#0XC410,#0XC460,#0XC4B0,#0XC500,#0XC550,#0XC5A0,#0XC5F0,#0XC640,#0XC690,#0XC6E0,#0XC730,#0XC780 +sub_bloques: +.DB #0X00,#0X08,#0X10,#0X18,#0X20,#0X28,#0X30,#0X38 + diff --git a/lib/cpcrslib/cpc_GetSp.s b/lib/cpcrslib/cpc_GetSp.s new file mode 100644 index 0000000..cb19efc --- /dev/null +++ b/lib/cpcrslib/cpc_GetSp.s @@ -0,0 +1,49 @@ +.globl _cpc_GetSp + +_cpc_GetSp:: + + LD IX,#2 + ADD IX,SP + LD E,0 (IX) + LD D,1 (IX) + LD A,3 (IX) + LD L,4 (IX) + LD H,5 (IX) + + + + LD (#loop_alto_2x_GetSp0+1),A + + + SUB #1 + CPL + LD (#salto_lineax_GetSp0+1),A ;comparten los 2 los mismos valores. + + LD A,2 (IX) + ;JP cpc_GetSp0 + +cpc_GetSp0:: + .DB #0XFD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 +loop_alto_2x_GetSp0: + LD C,#0 +loop_ancho_2x_GetSp0: + LD A,(HL) + LD (DE),A + INC DE + INC HL + DEC C + JP NZ,loop_ancho_2x_GetSp0 + .DB #0XFD + DEC H + RET Z +salto_lineax_GetSp0: + LD C,#0XFF ;salto linea menos ancho + ADD HL,BC + JP NC,loop_alto_2x_GetSp0 ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + ADD HL,BC + LD B,#7 ;sólo se daría una de cada 8 veces en un sprite + JP loop_alto_2x_GetSp0 + diff --git a/lib/cpcrslib/cpc_GphStr.s b/lib/cpcrslib/cpc_GphStr.s new file mode 100644 index 0000000..3f656fa --- /dev/null +++ b/lib/cpcrslib/cpc_GphStr.s @@ -0,0 +1,700 @@ +; ****************************************************** +; ** Librería de rutinas SDCC para Amstrad CPC ** +; ** Raúl Simarro (Artaburu) - 2009, 2012 ** +; ****************************************************** + + + +cpc_GetScrAddress0: ;en HL están las coordenadas + + ;LD A,H + LD (#inc_ancho+1),A + LD A,L + SRL A + SRL A + SRL A + ; A indica el bloque a multiplicar x &50 + LD D,A ;D + SLA A + SLA A + SLA A + SUB L + NEG + ; A indica el desplazamiento a multiplicar x &800 + LD E,A ;E + LD L,D + LD H,#0 + ADD HL,HL + LD BC,#bloques + ADD HL,BC + ;HL APUNTA AL BLOQUE BUSCADO + LD C,(HL) + INC HL + LD H,(HL) + LD L,C + ;HL TIENE EL VALOR DEL BLOQUE DE 8 BUSCADO + PUSH HL + LD D,#0 + LD HL,#sub_bloques + ADD HL,DE + LD A,(HL) + POP HL + ADD H + LD H,A +inc_ancho: + LD E,#0 + ADD HL,DE + RET + +bloques: +.DW #0XC000,#0XC050,#0XC0A0,#0XC0F0,#0XC140,#0XC190,#0XC1E0,#0XC230,#0XC280,#0XC2D0,#0XC320,#0XC370,#0XC3C0,#0XC410,#0XC460,#0XC4B0,#0XC500,#0XC550,#0XC5A0,#0XC5F0,#0XC640,#0XC690,#0XC6E0,#0XC730,#0XC780 +sub_bloques: +.DB #0X00,#0X08,#0X10,#0X18,#0X20,#0X28,#0X30,#0X38 + + + + +;************************************* +; GRAPHIC TEXT +;************************************* + +.globl _cpc_PrintGphStr2X + +_cpc_PrintGphStr2X:: +;preparación datos impresión. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + LD L,2 (IX) + LD H,3 (IX) ;DESTINO + LD E,0 (IX) + LD D,1 (IX) ;TEXTO ORIGEN + LD A,#1 + JP cpc_PrintGphStr0 + + + +.globl _cpc_PrintGphStrXY2X + +_cpc_PrintGphStrXY2X:: +;preparación datos impresión. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + LD L,3 (IX) + LD A,2 (IX) ;pantalla + CALL cpc_GetScrAddress0 + LD E,0 (IX) + LD D,1 (IX) ;texto origen + LD A,#1 + JP cpc_PrintGphStr0 + +.globl _cpc_PrintGphStrXY + +_cpc_PrintGphStrXY:: +;preparación datos impresión. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + LD L,3 (IX) + LD A,2 (IX) ;pantalla + CALL cpc_GetScrAddress0 + LD E,0 (IX) + LD D,1 (IX) ;texto origen + JP cpc_PrintGphStr0 + + +.globl _cpc_PrintGphStr + +_cpc_PrintGphStr:: +;preparación datos impresión. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + LD L,2 (IX) + LD H,3 (IX) ;DESTINO + ;LD (CPC_PRINTGPHSTR0+DIRECC_DESTINO0),HL + LD E,0 (IX) + LD D,1 (IX) ;TEXTO ORIGEN + ;JP cpc_PrintGphStr0 + +cpc_PrintGphStr0: + + ;DE destino + ;HL origen + ;ex de,hl + LD (#doble),A + ;trabajo previo: Para tener una lista de trabajos de impresión. No se interrumpe + ;la impresión en curso. + LD A,(#imprimiendo) + CP #1 + JP Z,add_elemento + LD (#direcc_destino),HL + EX DE,HL + CALL bucle_texto0 + +;antes de terminar, se mira si hay algo en cola. +bucle_cola_impresion: + LD A,(#elementos_cola) + OR A + JP Z,terminar_impresion + CALL leer_elemento + JP bucle_cola_impresion + + +terminar_impresion: + XOR A + LD (#imprimiendo),A + RET +entrar_cola_impresion: +;si se está imprimiendo se mete el valor en la cola + RET +add_elemento: + DI + LD IX,(#pos_cola) + LD 0 (IX),L + LD 1 (IX),H + LD 2 (IX),E + LD 3 (IX),D + INC IX + INC IX + INC IX + INC IX + LD (#pos_cola),IX + + LD HL,#elementos_cola + INC (HL) + ;Se añaden los valores hl y de + EI + RET +leer_elemento: + DI + LD IX,(#pos_cola) + LD L,0 (IX) + LD H,1 (IX) + LD E,2 (IX) + LD D,4 (IX) + DEC IX + DEC IX + DEC IX + DEC IX + LD (#pos_cola),IX + LD HL,#elementos_cola + DEC (HL) + EI + RET + +elementos_cola: + .DW #0 ; defw 0 +pos_cola: + .DW #cola_impresion ;defw cola_impresion + ;pos_escritura_cola defw cola_impresion +cola_impresion: ; defs 12 + .DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +bucle_texto0: + LD A,#1 + LD (imprimiendo),A + + LD A,(first_char) + LD B,A ;resto 48 para saber el número del caracter (En ASCII 0=48) + + LD A,(HL) + OR A ;CP 0 + RET Z + SUB B + LD BC,(#cpc_Chars) ;apunto a la primera letra + PUSH HL + + LD L,A ;en A tengo la letra que sería + LD H,#0 + ADD HL,HL + ADD HL,HL + ADD HL,HL ;x8 porque cada letra son 8 bytes + ADD HL,BC ;ahora HL apunta a los datos de la letra correspondiente + CALL escribe_letra + LD A,(doble) + CP #1 +; ANTES DE IMPRIMIR SE CHEQUEA SI ES DE ALTURA EL DOBLE Y SE ACTÚA EN CONSECUENCIA + CALL Z, doblar_letra + LD HL,(#direcc_destino) + LD A,(doble) + CP #1 + ;alto + JR Z,cont_doble + LD DE,#letra_decodificada + .DB #0xfD + LD H,#8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + JR cont_tot + + +cont_doble: + LD DE,#letra_decodificada_tmp + .DB #0xfD + LD H,#16 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + +cont_tot: + CALL cpc_PutSp0 + LD HL,(#direcc_destino) + INC HL + INC HL + LD (#direcc_destino),HL + POP HL + INC HL + JP bucle_texto0 + + +doble: + .DB #0 +imprimiendo: + .DB #0 +direcc_destino: + .DW #0 + + +cpc_PutSp0: +; .DB #0xfD +; LD H,16 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 + LD C,B +loop_alto_2: + +loop_ancho_2: + EX DE,HL + LDI + LDI + .DB #0XFD + DEC H + RET Z + EX DE,HL +salto_linea: + LD C,#0XFE ;&07F6 ;SALTO LINEA MENOS ANCHO + ADD HL,BC + JP NC,loop_alto_2 ;SIG_LINEA_2ZZ ;SI NO DESBORDA VA A LA SIGUIENTE LINEA + LD BC,#0XC050 + ADD HL,BC + LD B,#7 ;SÓLO SE DARÍA UNA DE CADA 8 VECES EN UN SPRITE + JP loop_alto_2 + + + + +doblar_letra: + LD HL,#letra_decodificada + LD DE,#letra_decodificada_tmp + LD B,#8 +buc_doblar_letra: + LD A,(HL) + INC HL + LD (DE),A + INC DE + INC DE + LD (DE),A + DEC DE + LD A,(HL) + INC HL + LD (DE),A + INC DE + INC DE + LD (DE),A + INC DE + DJNZ buc_doblar_letra + RET + + +escribe_letra: ; Code by Kevin Thacker + PUSH DE + LD IY,#letra_decodificada + LD B,#8 +bucle_alto_letra: + PUSH BC + PUSH HL + LD E,(HL) + CALL op_colores + LD (IY),D + INC IY + CALL op_colores + LD (IY),D + INC IY + POP HL + INC HL + POP BC + DJNZ bucle_alto_letra + POP DE + RET + +op_colores: + ld d,#0 ;; initial byte at end will be result of 2 pixels combined + CALL op_colores_pixel ;; do pixel 0 + RLC D + CALL op_colores_pixel + RRC D + RET + +;; follow through to do pixel 1 + +op_colores_pixel: + ;; shift out pixel into bits 0 and 1 (source) + RLC E + RLC E + ;; isolate + LD A,E + AND #0X3 + LD HL,#colores_b0 + ADD A,L + LD L,A + LD A,H + ADC A,#0 + LD H,A + ;; READ IT AND COMBINE WITH PIXEL SO FAR + LD A,D + OR (HL) + LD D,A + RET + + +.globl _cpc_SetInkGphStr + +_cpc_SetInkGphStr:: +;preparación datos impresión. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + + ;LD A,H + ;LD C,L + LD A,1 (IX) ;VALOR + LD C,0 (IX) ;COLOR + + LD HL,#colores_b0 + LD B,#0 + ADD HL,BC + LD (HL),A + RET + + + + + +.globl _cpc_PrintGphStrXYM1 + +_cpc_PrintGphStrXYM1:: +;preparación datos impresión. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + LD L,3 (IX) + LD A,2 (IX) ;pantalla + CALL cpc_GetScrAddress0 + LD E,0 (IX) + LD D,1 (IX) ;texto origen + XOR A + JP cpc_PrintGphStr0M1 + + +.globl _cpc_PrintGphStrXYM12X + +_cpc_PrintGphStrXYM12X:: +;preparación datos impresión. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + LD L,3 (IX) + LD A,2 (IX) ;pantalla + CALL cpc_GetScrAddress0 + LD E,0 (IX) + LD D,1 (IX) ;texto origen + LD A,#1 + JP cpc_PrintGphStr0M1 + + + + +.globl _cpc_PrintGphStrM12X + +_cpc_PrintGphStrM12X:: + LD IX,#2 + ADD IX,SP + LD L,2 (IX) + LD H,3 (IX) ;DESTINO + LD E,0 (IX) + LD D,1 (IX) ;TEXTO ORIGEN + LD A,#1 + + JP cpc_PrintGphStr0M1 + + + +.globl _cpc_PrintGphStrM1 + +_cpc_PrintGphStrM1:: +;preparación datos impresión. El ancho y alto son fijos! + + LD IX,#2 + ADD IX,SP + LD L,2 (IX) + LD H,3 (IX) ;DESTINO + LD E,0 (IX) + LD D,1 (IX) ;TEXTO ORIGEN + XOR A + + ;JP cpc_PrintGphStr0M1 + +cpc_PrintGphStr0M1: + ;DE destino + ;HL origen + ;ex de,hl + LD (#dobleM1),A + ;trabajo previo: Para tener una lista de trabajos de impresión. No se interrumpe + ;la impresión en curso. + LD A,(#imprimiendo) + CP #1 + JP Z,add_elemento + LD (#direcc_destino),HL + EX DE,HL + CALL bucle_texto0M1 +;antes de terminar, se mira si hay algo en cola. +bucle_cola_impresionM1: + LD A,(#elementos_cola) + OR A + JP Z,terminar_impresion + CALL leer_elemento + JP bucle_cola_impresionM1 + + + + + +bucle_texto0M1: + LD A,#1 + LD (#imprimiendo),A + + LD A,(#first_char) + LD B,A ;resto 48 para saber el número del caracter (En ASCII 0=48) + LD A,(HL) + OR A ;CP 0 + RET Z + SUB B + LD BC,(#cpc_Chars) ;apunto a la primera letra + PUSH HL + LD L,A ;en A tengo la letra que sería + LD H,#0 + ADD HL,HL + ADD HL,HL + ADD HL,HL ;x8 porque cada letra son 8 bytes + ADD HL,BC ;ahora HL apunta a los datos de la letra correspondiente + CALL escribe_letraM1 + LD A,(dobleM1) + CP #1 + ; ANTES DE IMPRIMIR SE CHEQUEA SI ES DE ALTURA EL DOBLE Y SE ACTÚA EN CONSECUENCIA + CALL Z, doblar_letraM1 + LD HL,(direcc_destino) + LD A,(dobleM1) + CP #1 + ;alto + JR Z,cont_dobleM1 + LD DE,#letra_decodificada + .DB #0xfD + LD H,#8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + JR cont_totM1 + + +cont_dobleM1: + LD DE,#letra_decodificada_tmp + .DB #0XFD + LD H,#16 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE +cont_totM1: + CALL cpc_PutSp0M1 + LD HL,(#direcc_destino) + INC HL + LD (#direcc_destino),HL + POP HL + INC HL + JP bucle_texto0M1 + +dobleM1: + .DB #0 +;.imprimiendo defb 0 +;.direcc_destino defw 0 + +doblar_letraM1: + LD HL,#letra_decodificada + LD DE,#letra_decodificada_tmp + LD B,#8 +buc_doblar_letraM1: + LD A,(HL) + INC HL + LD (DE),A + INC DE + LD (DE),A + INC DE + DJNZ buc_doblar_letraM1 + RET + + +cpc_PutSp0M1: + ; defb #0xfD + ; LD H,8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 + LD C,B +loop_alto_2M1: +loop_ancho_2M1: + EX DE,HL + LDI + .DB #0XFD + DEC H + RET Z + EX DE,HL +salto_lineaM1: + LD C,#0XFF ;#0x07f6 ;salto linea menos ancho + ADD HL,BC + JP NC,loop_alto_2M1 ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + ADD HL,BC + LD B,#7 ;sólo se daría una de cada 8 veces en un sprite + JP loop_alto_2M1 + + + +escribe_letraM1: + LD IY,#letra_decodificada + LD B,#8 + LD IX,#byte_tmp +bucle_altoM1: + PUSH BC + PUSH HL + + LD A,(HL) + LD HL,#dato + LD (HL),A + ;me deja en ix los valores convertidos + ;HL tiene la dirección origen de los datos de la letra + ;LD DE,letra ;el destino es la posición de decodificación de la letra + ;Se analiza el byte por parejas de bits para saber el color de cada pixel. + LD (IX),#0 ;reset el byte + LD B,#4 ;son 4 pixels por byte. Los recorro en un bucle y miro qué color tiene cada byte. +bucle_coloresM1: + ;roto el byte en (HL) + PUSH HL + CALL op_colores_m1 ;voy a ver qué color es el byte. tengo un máximo de 4 colores posibles en modo 0. + POP HL + SRL (HL) + SRL (HL) ;voy rotando el byte para mirar los bits por pares. + DJNZ bucle_coloresM1 + LD A,(IX) + LD (IY),A + INC IY + POP HL + INC HL + POP BC + DJNZ bucle_altoM1 + RET + + +;.rutina +;HL tiene la dirección origen de los datos de la letra + +;Se analiza el byte por parejas de bits para saber el color de cada pixel. +;ld ix,byte_tmp +;ld (ix+0),0 + +;LD B,4 ;son 4 pixels por byte. Los recorro en un bucle y miro qué color tiene cada byte. +;.bucle_colores +;roto el byte en (HL) +;push hl +;call op_colores_m1 ;voy a ver qué color es el byte. tengo un máximo de 4 colores posibles en modo 0. +;pop hl +;sla (HL) +;sla (HL) ;voy rotando el byte para mirar los bits por pares. + +;djnz bucle_colores + +;ret +op_colores_m1: ;rutina en modo 1 + ;mira el color del bit a pintar + LD A,#3 ;hay 4 colores posibles. Me quedo con los 2 primeros bits + AND (HL) + ; EN A tengo el número de bytes a sumar!! + LD HL,#colores_m1 + LD E,A + LD D,#0 + ADD HL,DE + LD C,(HL) + ;EN C ESTÁ EL BYTE DEL COLOR + ;LD A,4 + ;SUB B + LD A,B + DEC A + OR A ;CP 0 + JP Z,_sin_rotar +rotando: + SRL C + DEC A + JP NZ, rotando +_sin_rotar: + LD A,C + OR (IX) + LD (IX),A + ;INC IX + RET + + +.globl _cpc_SetInkGphStrM1 + +_cpc_SetInkGphStrM1:: + LD IX,#2 + ADD IX,SP + LD A,1 (IX) ;VALOR + LD C,0 (IX) ;COLOR + LD HL,#colores_cambM1 + LD B,#0 + ADD HL,BC + LD (HL),A + RET + + + +colores_cambM1: +colores_m1: + .DB #0b00000000,#0b10001000,#0b10000000,#0b00001000 + +;defb @00000000, @01010100, @00010000, @00000101 ;@00000001, @00000101, @00010101, @00000000 + + + +;DEFC direcc_destino0_m1 = direcc_destino +;DEFC colores_cambM1 = colores_m1 + + +.globl _cpc_SetFont + +_cpc_SetFont:: + ld ix, #2 + add ix, sp + ld a, 0(ix) + ld (#first_char), a + ld l, 1(ix) + ld h, 2(ix) + ld (#cpc_Chars), hl + ret + +dato: + .DB #0b00011011 ;aquí dejo temporalmente el byte a tratar + +byte_tmp: + .DB #0 + .DB #0 + .DB #0 ;defs 3 +colores_b0: ;defino los 4 colores posibles para el byte. Los colores pueden ser cualesquiera. + ;Pero se tienen que poner bien, en la posición que le corresponda. + .DB #0b00001010,#0b00100000,#0b10100000,#0b00101000 + ;.DB #0b00000000, #0b01010100, #0b00010000, #0b00000101 ;#0b00000001, #0b00000101, #0b00010101, #0b00000000 + +letra_decodificada: ;. defs 16 ;16 ;uso este espacio para guardar la letra que se decodifica + .DB #0,#0,#0,#0,#0,#0,#0,#0 + .DB #0,#0,#0,#0,#0,#0,#0,#0 +letra_decodificada_tmp: ;defs 32 ;16 ;uso este espacio para guardar la letra que se decodifica para tamaño doble altura + .DB #0,#0,#0,#0,#0,#0,#0,#0 + .DB #0,#0,#0,#0,#0,#0,#0,#0 + .DB #0,#0,#0,#0,#0,#0,#0,#0 + .DB #0,#0,#0,#0,#0,#0,#0,#0 + + +first_char: + .DB #0 ;first defined char number (ASCII) + +cpc_Chars: ;cpc_Chars codificadas... cada pixel se define con 2 bits que definen el color. + .DW #0 + diff --git a/lib/cpcrslib/cpc_Keyboard.s b/lib/cpcrslib/cpc_Keyboard.s new file mode 100644 index 0000000..6008a50 --- /dev/null +++ b/lib/cpcrslib/cpc_Keyboard.s @@ -0,0 +1,344 @@ +; ****************************************************** +; ** Librería de rutinas SDCC para Amstrad CPC ** +; ** Raúl Simarro (Artaburu) - 2009, 2012 ** +; ****************************************************** + +;************************************* +; KEYBOARD +;************************************* + + +.globl _cpc_AnyKeyPressed + +MAX_KEYS = 12 + +_cpc_AnyKeyPressed:: + call hacer_tiempo + call hacer_tiempo + call hacer_tiempo + + + + LD A,#0x40 +bucle_deteccion_tecla: + PUSH AF + CALL cpc_TestKeyboard ;en A vuelve los valores de la linea + OR A + JP NZ, tecla_pulsada ; retorna si no se ha pulsado ninguna tecla + POP AF + INC A + CP #0x4a + JP NZ, bucle_deteccion_tecla + LD HL,#0 + + RET + +tecla_pulsada: + POP AF + LD HL,#1 + RET + +hacer_tiempo: + LD A,#254 +bucle_previo_deteccion_tecla: + PUSH AF + POP AF + dec A + Jr nZ, bucle_previo_deteccion_tecla + ret + + + +.globl _cpc_AssignKey + +_cpc_AssignKey:: + + LD HL,#2 + ADD HL,SP + LD E,(HL) ;E-> numero tecla + INC HL + ;INC HL + LD A,(HL) ;linea, byte + INC HL + LD B,(HL) ;DE tiene el valor de la tecla a escribir en la tabla + ; En A se tiene el valor de la tecla seleccionada a comprobar [0..11] + ;___________________________________________________________________ + ; ;En A viene la tecla a redefinir (0..11) + SLA E + LD D,#0 + LD HL, #tabla_teclas + ADD HL,DE ;Nos colocamos en la tecla a redefinir y la borramos + LD (HL),#0XFF + INC HL + LD (HL),#0XFF + DEC HL + PUSH HL + ;call ejecutar_deteccion_teclado ;A tiene el valor del teclado + ; A tiene el byte (<>0) + ; B tiene la linea + ;guardo linea y byte + POP HL + LD (HL),A ;byte + INC HL + LD (HL),B + RET + + +.globl _cpc_TestKey + +_cpc_TestKey:: + + LD HL,#2 + ADD HL,SP + LD L,(HL) ; En A se tiene el valor de la tecla seleccionada a comprobar [0..11] + SLA L + INC L + LD H,#0 + LD DE,#tabla_teclas + ADD HL,DE + LD A,(HL) + CALL cpc_TestKeyboard ; esta rutina lee la línea del teclado correspondiente + DEC HL ; pero sólo nos interesa una de las teclas. + and (HL) ;para filtrar por el bit de la tecla (puede haber varias pulsadas) + CP (HL) ;comprueba si el byte coincide + LD H,#0 + JP Z,pulsado + LD L,H + RET +pulsado: + LD L,#1 + RET + + + + + +.globl _cpc_RedefineKey + +_cpc_RedefineKey:: + + LD HL,#2 + ADD HL,SP + LD L,(HL) + SLA L + LD H,#0 + LD DE,#tabla_teclas + ADD HL,DE ;Nos colocamos en la tecla a redefinir + LD (HL),#0XFF ; y la borramos + INC HL + LD (HL),#0XFF + DEC HL + PUSH HL + CALL ejecutar_deteccion_teclado ;A tiene el valor del teclado + LD A,D + ; A tiene el byte (<>0) + ; B tiene la linea + ;guardo linea y byte + POP HL ;recupera posición leída + LD A,(linea) + LD (HL),A ;byte + INC HL + LD A,(bte) + LD (HL),A + RET + + +ejecutar_deteccion_teclado: + LD A,#0x40 +bucle_deteccion_tecla1: + PUSH AF + LD (bte),A + CALL cpc_TestKeyboard ;en A vuelve los valores de la linea + OR A + JR NZ, tecla_pulsada1 ; retorna si no se ha pulsado ninguna tecla + POP AF + INC A + CP #0x4A + JR NZ, bucle_deteccion_tecla1 + JR ejecutar_deteccion_teclado + +tecla_pulsada1: + LD (linea),A + POP AF + CALL comprobar_si_tecla_usada + RET NC + JR bucle_deteccion_tecla1 + +comprobar_si_tecla_usada: ; A tiene byte, B linea + LD B,#MAX_KEYS ;numero máximo de tecla redefinibles + LD IX,#tabla_teclas + LD C,(IX) +bucle_bd_teclas: ;comprobar byte + LD A,(linea) + LD C,(IX) + CP (IX) + JR Z, comprobar_linea + INC IX + INC IX + DJNZ bucle_bd_teclas + SCF + CCF + RET ; si vuelve después de comprobar, que sea NZ +comprobar_linea: ;si el byte es el mismo, mira la linea + LD A,(bte) + CP 1 (IX) ; esto es (ix+1) + JR Z, tecla_detectada ; Vuelve con Z si coincide el byte y la linea + INC IX + INC IX + DJNZ bucle_bd_teclas + SCF + CCF + RET ; si vuelve después de comprobar, que sea NZ +tecla_detectada: + SCF + RET + + +.globl _cpc_DeleteKeys + +_cpc_DeleteKeys:: ;borra la tabla de las teclas para poder redefinirlas todas + LD HL,#tabla_teclas + LD DE,#tabla_teclas+#1 + LD BC, #MAX_KEYS + LD (HL),#0xFF + LDIR + RET + + +.globl _cpc_TestKeyF + +_cpc_TestKeyF:: + LD HL,#2 + ADD HL,SP + LD L,(HL) + SLA L + INC L + LD H,#0 + LD DE,#tabla_teclas + ADD HL,DE + LD A,(HL) + SUB #0X40 + EX DE,HL + LD HL,#keymap ;; LEE LA LÍNEA BUSCADA DEL KEYMAP + LD C,A + LD B,#0 + ADD HL,BC + LD A,(HL) + EX DE,HL + DEC HL ; PERO SÓLO NOS INTERESA UNA DE LAS TECLAS. + AND (HL) ;PARA FILTRAR POR EL BIT DE LA TECLA (PUEDE HABER VARIAS PULSADAS) + CP (HL) ;COMPRUEBA SI EL BYTE COINCIDE + LD H,#0 + JP NZ,#pulsado_cpc_TestKeyF + LD L,H + RET +pulsado_cpc_TestKeyF: + LD L,#1 + RET + + +.globl _cpc_ScanKeyboard + +_cpc_ScanKeyboard:: + + DI ;1 #0X#0X%%#0X#0X C P C VERSION #0X#0X%%#0X#0X FROM CPCWIKI + LD HL,#keymap ;3 + LD BC,#0XF782 ;3 + OUT (C),C ;4 + LD BC,#0XF40E ;3 + LD E,B ;1 + OUT (C),C ;4 + LD BC,#0XF6C0 ;3 + LD D,B ;1 + OUT (C),C ;4 + .DB #0XED,#0X71 ; 4 OUT (C),0 + LD BC,#0XF792 ;3 + OUT (C),C ;4 + LD A,#0X40 ;2 + LD C,#10 ;2 44 +loop_cpc_scankeyboard: + LD B,D ;1 + OUT (C),A ;4 SELECT LINE + LD B,E ;1 + INI ;5 READ BITS AND WRITE INTO KEYMAP + INC A ;1 + DEC C ;1 + JR NZ,loop_cpc_scankeyboard ;2/3 9*16+1*15=159 + LD BC,#0XF782 ;3 + OUT (C),C ;4 + EI ;1 8 =209 MICROSECONDS + RET + + + +cpc_TestKeyboard:: ;Tomado de las rutinas básicas que aparecen + ;en los documentos de Kevin Thacker + + DI + LD BC,#0XF782 + OUT (C),C + LD BC, #0XF40E + OUT (C), C + LD BC, #0XF6C0 + OUT (C), C + .DB #0XED,#0X71 ; OUT (C),0 + LD BC, #0XF792 + OUT (C), C + DEC B + OUT (C), A + LD B, #0XF4 + IN A, (C) + LD BC, #0XF782 + OUT (C), C + DEC B + .DB #0XED,#0X71 ; OUT (C),0 + CPL + EI + RET + +linea: + .DB #0 +bte: + .DB #0 + +keymap: + .DB #0 + .DB #0 + .DB #0 + .DB #0 + .DB #0 + .DB #0 + .DB #0 + .DB #0 + .DB #0 + .DB #0 + +;teclado_usable ; teclas del cursor, cada tecla está definida por su bit y su línea. +.globl _cpc_keys_table +_cpc_keys_table: +tabla_teclas: +tecla_0_x: .DW #0xffff ; bit 0, línea 2 +tecla_1_x: .DW #0xffff ; bit 1, línea 1 +tecla_2_x: .DW #0xffff ; bit 0, línea 1 +tecla_3_x: .DW #0xffff ; bit 0, línea 4 +tecla_4_x: .DW #0xffff ; bit 0, línea 2 +tecla_5_x: .DW #0xffff ; bit 1, línea 1 +tecla_6_x: .DW #0xffff ; bit 0, línea 1 +tecla_7_x: .DW #0xffff ; bit 0, línea 4 +tecla_8_x: .DW #0xffff ; bit 0, línea 4 +tecla_9_x: .DW #0xffff ; bit 0, línea 4 +tecla_10_x: .DW #0xffff ; bit 0, línea 4 +tecla_11_x: .DW #0xffff ; bit 0, línea 4 +; For increasing keys available just increase this word table +.DB #0 + + + + + + + + + + + diff --git a/lib/cpcrslib/cpc_PrintStr.s b/lib/cpcrslib/cpc_PrintStr.s new file mode 100644 index 0000000..28e713a --- /dev/null +++ b/lib/cpcrslib/cpc_PrintStr.s @@ -0,0 +1,27 @@ +.globl _cpc_PrintStr + +_cpc_PrintStr:: + LD IX,#2 + ADD IX,SP + LD l,0 (IX) + LD h,1 (IX) ;TEXTO ORIGEN + +; LD HL,#2 + ; ADD HL,SP +; LD E,(HL) +; INC HL +; LD D,(HL) +; EX DE,HL +bucle_imp_cadena: + LD A,(HL) + OR A + JR Z,salir_bucle_imp_cadena + CALL #0XBB5A + INC HL + JR bucle_imp_cadena +salir_bucle_imp_cadena: + LD A,#0X0D ; PARA TERMINAR HACE UN SALTO DE LÃNEA + CALL #0XBB5A + LD A,#0X0A + JP 0XBB5A + diff --git a/lib/cpcrslib/cpc_PutMaskSp.s b/lib/cpcrslib/cpc_PutMaskSp.s new file mode 100644 index 0000000..e9683e4 --- /dev/null +++ b/lib/cpcrslib/cpc_PutMaskSp.s @@ -0,0 +1,79 @@ +;void cpc_PutMaskSprite(int *sprite, int *posicion); +;void cpc_PutMaskSp(int *sprite, char alto, char ancho, int *posicion); +.globl _cpc_PutMaskSp + +_cpc_PutMaskSp:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + + LD IX,#2 + ADD IX,SP + LD L,4 (IX) + LD H,5 (IX) + LD A,3 (IX) + LD E,0 (IX) + LD D,1 (IX) + ld (#loop_alto_2m_PutMaskSp0+#1),a ;actualizo rutina de captura + SUB #1 + CPL + LD (#salto_lineam_PutMaskSp0+#1),A ;comparten los 2 los mismos valores. + ld A,2(IX) + ;JP cpc_PutMaskSp0 + +cpc_PutMaskSp0: + .DB #0XFD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 +loop_alto_2m_PutMaskSp0: + LD C,#4 + EX DE,HL +loop_ancho_2m_PutMaskSp0: + LD A,(DE) ;LEO EL BYTE DEL FONDO + AND (HL) ;LO ENMASCARO + INC HL + OR (HL) ;LO ENMASCARO + LD (DE),A ;ACTUALIZO EL FONDO + INC DE + INC HL + DEC C + JP NZ,loop_ancho_2m_PutMaskSp0 + .DB #0XFD + DEC H + RET Z + EX DE,HL +salto_lineam_PutMaskSp0: + LD C,#0XFF + ADD HL,BC + JP nc,loop_alto_2m_PutMaskSp0 + LD BC,#0XC050 + ADD HL,BC + LD B,#7 + JP loop_alto_2m_PutMaskSp0 + +.globl _cpc_PutMaskSprite + +_cpc_PutMaskSprite:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + + POP AF + POP HL + POP DE + PUSH AF + LD A,(HL) ;ANCHO + INC HL + ld (#loop_alto_2m_PutMaskSp0+#1),a ;ACTUALIZO RUTINA DE CAPTURA + ;LD (ANCHOT+1),A ;ACTUALIZO RUTINA DE DIBUJO + SUB #1 + CPL + LD (#salto_lineam_PutMaskSp0+#1),A ;COMPARTEN LOS 2 LOS MISMOS VALORES. + LD A,(HL) ;ALTO + INC HL + EX DE,HL + jp cpc_PutMaskSp0 + + diff --git a/lib/cpcrslib/cpc_PutMaskSp2x8.s b/lib/cpcrslib/cpc_PutMaskSp2x8.s new file mode 100644 index 0000000..ac85f0e --- /dev/null +++ b/lib/cpcrslib/cpc_PutMaskSp2x8.s @@ -0,0 +1,45 @@ +.globl _cpc_PutMaskSp2x8 +; imprime un sprite de 8x8 en modo 1 +; El formato del sprite es el siguiente por cada línea: +; defb byte1,byte2,byte3,byte4 +; siendo byte1 y byte3 son las máscaras de los bytes 2 y 4 +; se recibe de entrada el sprite y la posición. +_cpc_PutMaskSp2x8:: + LD IX,#2 + ADD IX,SP + LD L,2 (IX) + LD H,3 (IX) + LD E,0 (IX) + LD D,1 (IX) + .DB #0XFD + LD H,#8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 +loop_alto_mask_2x8: + EX DE,HL + LD A,(DE) ;leo el byte del fondo + AND (HL) ;lo enmascaro + INC HL + OR (HL) ;lo enmascaro + LD (DE),A ;actualizo el fondo + INC DE + INC HL + ;COMO SOLO SON 2 BYTES, es más rápido y económico desplegar la rutina + LD A,(DE) + AND (HL) + INC HL + OR (HL) + LD (DE),A + INC DE + INC HL + .DB #0XFD + DEC H + RET Z + EX DE,HL + LD C,#0XFE + ADD HL,BC + JP NC,loop_alto_mask_2x8 + LD BC,#0XC050 + ADD HL,BC + LD B,#7 + JP loop_alto_mask_2x8 + diff --git a/lib/cpcrslib/cpc_PutMaskSp4x16.s b/lib/cpcrslib/cpc_PutMaskSp4x16.s new file mode 100644 index 0000000..4fbbd61 --- /dev/null +++ b/lib/cpcrslib/cpc_PutMaskSp4x16.s @@ -0,0 +1,56 @@ +.globl _cpc_PutMaskSp4x16 + +_cpc_PutMaskSp4x16:: + + LD IX,#2 + ADD IX,SP + LD L,2 (IX) + LD H,3 (IX) + LD E,0 (IX) + LD D,1 (IX) + .DB #0XFD + LD H,#16 + LD B,#7 +loop_alto_mask_4x16: + EX DE,HL + LD A,(DE) ;leo el byte del fondo + AND (HL) ;lo enmascaro + INC HL + OR (HL) ;lo enmascaro + LD (DE),A ;actualizo el fondo + INC DE + INC HL + ;COMO SOLO SON 4 BYTES, es más rápido y económico desplegar la rutina + LD A,(DE) ;leo el byte del fondo + AND (HL) ;lo enmascaro + INC HL + OR (HL) ;lo enmascaro + LD (DE),A ;actualizo el fondo + INC DE + INC HL + LD A,(DE) ;leo el byte del fondo + AND (HL) ;lo enmascaro + INC HL + OR (HL) ;lo enmascaro + LD (DE),A ;actualizo el fondo + INC DE + INC HL + LD A,(DE) ;leo el byte del fondo + AND (HL) ;lo enmascaro + INC HL + OR (HL) ;lo enmascaro + LD (DE),A ;actualizo el fondo + INC DE + INC HL + .DB #0XFD + DEC H + RET Z + EX DE,HL + LD C,#0XFC + ADD HL,BC + JP NC,loop_alto_mask_4x16 + LD BC,#0XC050 + ADD HL,BC + LD B,#7 + JP loop_alto_mask_4x16 + diff --git a/lib/cpcrslib/cpc_PutSp.s b/lib/cpcrslib/cpc_PutSp.s new file mode 100644 index 0000000..0ddbf10 --- /dev/null +++ b/lib/cpcrslib/cpc_PutSp.s @@ -0,0 +1,54 @@ +.globl _cpc_PutSp + +_cpc_PutSp:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + + LD IX,#2 + ADD IX,SP + LD E,0 (IX) + LD D,1 (IX) + LD A,3 (IX) + LD L,4 (IX) + LD H,5 (IX) + + LD (#ancho0+1),A ;actualizo rutina de captura + ;ld (anchot+1),a ;actualizo rutina de dibujo + SUB #1 + CPL + LD (#suma_siguiente_linea0+1),A ;COMPARTEN LOS 2 LOS MISMOS VALORES. + + LD A,2 (IX) + ;JP cpc_putsp0 + +pc_PutSp0: + .DB #0XFD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 +ancho0: +loop_alto_2_pc_PutSp0: + LD C,#4 +loop_ancho_2_pc_PutSp0: + LD A,(DE) + LD (HL),A + INC DE + INC HL + DEC C + JP NZ,loop_ancho_2_pc_PutSp0 + .DB #0XFD + DEC H + RET Z + +suma_siguiente_linea0: +salto_linea_pc_PutSp0: + LD C,#0XFF ;&07F6 ;SALTO LINEA MENOS ANCHO + ADD HL,BC + JP nc,loop_alto_2_pc_PutSp0 ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + + ADD HL,BC + LD B,#7 ;SÓLO SE DARÃA UNA DE CADA 8 VECES EN UN SPRITE + JP loop_alto_2_pc_PutSp0 + diff --git a/lib/cpcrslib/cpc_PutSp2x14.s b/lib/cpcrslib/cpc_PutSp2x14.s new file mode 100644 index 0000000..241d66b --- /dev/null +++ b/lib/cpcrslib/cpc_PutSp2x14.s @@ -0,0 +1,50 @@ +.globl _cpc_PutSp4x14 + +_cpc_PutSp4x14:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + + LD IX,#2 + ADD IX,SP + LD e,0 (IX) + LD d,1 (IX) ;sprite + LD l,2 (IX) + LD h,3 (IX) ;address + ld A,#14 + +pc_PutSp0X: + .DB #0XFD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 +ancho0X: +loop_alto_2_pc_PutSp0X: + LD C,#4 +loop_ancho_2_pc_PutSp0X: + EX DE,HL + LDI + LDI + LDI + LDI + EX DE,HL + ;LD A,(DE) + ;LD (HL),A + ;INC DE + ;INC HL + ;DEC C + ;JP NZ,loop_ancho_2_pc_PutSp0X + .DB #0XFD + DEC H + RET Z + +suma_siguiente_linea0X: +salto_linea_pc_PutSp0X: + LD C,#0XFC ;&07F6 ;SALTO LINEA MENOS ANCHO + ADD HL,BC + JP nc,loop_alto_2_pc_PutSp0X ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + ADD HL,BC + LD B,#7 ;SÓLO SE DARÃA UNA DE CADA 8 VECES EN UN SPRITE + JP loop_alto_2_pc_PutSp0X + diff --git a/lib/cpcrslib/cpc_PutSpTr.s b/lib/cpcrslib/cpc_PutSpTr.s new file mode 100644 index 0000000..e1d24fa --- /dev/null +++ b/lib/cpcrslib/cpc_PutSpTr.s @@ -0,0 +1,75 @@ +.globl _cpc_PutSpTr + +_cpc_PutSpTr:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + LD IX,#2 + ADD IX,SP + LD E,0 (IX) + LD D,1 (IX) + LD A,4 (IX) + LD L,6 (IX) + LD H,7 (IX) + + + LD (#anchot+1),A ;actualizo rutina de dibujo + SUB #1 + CPL + LD (#suma_siguiente_lineat+1),A ;comparten los 2 los mismos valores. + + LD A,2 (IX) + ;JP cpc_PutSpTr0 + +cpc_PutSpTr0: + .DB #0XFD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE +anchot: +loop_alto_2t: + LD B,#0 +loop_ancho_2t: + LD A,(DE) + AND #0XAA + JP Z,sig_pixn_der_2 + LD C,A ;B es el único registro libre + LD A,(HL) ;pixel actual donde pinto + AND #0X55 + OR C + LD (HL),A ;y lo pone en pantalla +sig_pixn_der_2: + LD A,(DE) ;pixel del sprite + AND #0X55 + JP Z,pon_buffer_der_2 + LD C,A ;B es el único registro libre + LD A,(HL) ;PIXEL ACTUAL DONDE PINTO + AND #0XAA + OR C + LD (HL),A +pon_buffer_der_2: + INC DE + INC HL + DEC B + JP NZ,loop_ancho_2t + .DB #0XFD + DEC H + RET Z +suma_siguiente_lineat: +salto_lineat: + LD BC,#0X07FF ;&07f6 ;salto linea menos ancho + ADD HL,BC + JP NC,loop_alto_2t ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + ADD HL,BC + ;ld b,7 ;sólo se daría una de cada 8 veces en un sprite + JP loop_alto_2t + + LD A,H + ADD #0X08 + LD H,A + SUB #0XC0 + JP NC,loop_alto_2t ;sig_linea_2 + LD BC,#0XC050 + ADD HL,BC + JP loop_alto_2t + diff --git a/lib/cpcrslib/cpc_PutSpXOR.s b/lib/cpcrslib/cpc_PutSpXOR.s new file mode 100644 index 0000000..f4e58f0 --- /dev/null +++ b/lib/cpcrslib/cpc_PutSpXOR.s @@ -0,0 +1,79 @@ +.globl _cpc_PutSpXOR + +_cpc_PutSpXOR:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + + LD IX,#2 + ADD IX,SP + LD E,0 (IX) + LD D,1 (IX) + LD A,3 (IX) + LD L,4 (IX) + LD H,5 (IX) + + LD (#anchox0+#1),A ;actualizo rutina de captura + SUB #1 + CPL + LD (#suma_siguiente_lineax0+#1),A ;comparten los 2 los mismos valores. + + LD A,2 (IX) + JP cpc_PutSpXOR0 + + +.globl _cpc_PutSpriteXOR + +_cpc_PutSpriteXOR:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + POP AF + POP HL + POP DE + PUSH AF + LD A,(HL) ;ANCHO + INC HL + LD (#anchox0+#1),A ;ACTUALIZO RUTINA DE CAPTURA + ;LD (ANCHOT+1),A ;ACTUALIZO RUTINA DE DIBUJO + SUB #1 + CPL + LD (#suma_siguiente_lineax0+1),A ;COMPARTEN LOS 2 LOS MISMOS VALORES. + LD A,(HL) ;ALTO + INC HL + EX DE,HL + ;LD A,(IX+4) + JP cpc_PutSpXOR0 + + +cpc_PutSpXOR0: + .DB #0XFD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 +anchox0: +loop_alto_2x: + LD C,#4 +loop_ancho_2x: + LD A,(DE) + XOR (HL) + LD (HL),A + INC DE + INC HL + DEC C + JP NZ,loop_ancho_2x + .DB #0XFD + DEC H + RET Z + +suma_siguiente_lineax0: +salto_lineax: + LD C,#0XFF ;&07F6 ;SALTO LINEA MENOS ANCHO + ADD HL,BC + JP NC,loop_alto_2x ;SIG_LINEA_2ZZ ;SI NO DESBORDA VA A LA SIGUIENTE LINEA + LD BC,#0XC050 + ADD HL,BC + LD B,#7 ;SÓLO SE DARÃA UNA DE CADA 8 VECES EN UN SPRITE + JP loop_alto_2x + diff --git a/lib/cpcrslib/cpc_PutSprite.s b/lib/cpcrslib/cpc_PutSprite.s new file mode 100644 index 0000000..a6d6dec --- /dev/null +++ b/lib/cpcrslib/cpc_PutSprite.s @@ -0,0 +1,108 @@ +.globl _cpc_PutSprite + +_cpc_PutSprite:: +;************************************* +; SPRITE ROUTINE WITHOUT TRANSPARENCY +; Supplied by Tim Riemann +; from a German forum +; DE = source address of the sprite +; (includes header with 1B width [64byte maximum!], 1B height) +; HL = destination address +;************************************* + + POP AF + POP HL ;DESTINATION ADDRESS + POP DE ;SPRITE DATA + PUSH AF + ;EX DE,HL + LD A,#64 + SUB (HL) + ADD A + LD (width1+1),A + XOR A + SUB (HL) + LD (width2+1),A + INC HL + LD A,(HL) + INC HL +width0: + ;ex de,hl +width1: + JR width1 ;cada LDI es un byte + LDI ;se hace el salto al byte correspondiente (64-ancho) + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI +width2: + LD BC,#0X700 + EX DE,HL + ADD HL,BC + JP NC,width3 + LD BC,#0XC050 + ADD HL,BC +width3: + EX DE,HL + DEC A + JP NZ, width1 + RET + diff --git a/lib/cpcrslib/cpc_RLI.s b/lib/cpcrslib/cpc_RLI.s new file mode 100644 index 0000000..92a9385 --- /dev/null +++ b/lib/cpcrslib/cpc_RLI.s @@ -0,0 +1,39 @@ +.globl _cpc_RLI ;rota las líneas que se le digan hacia la izq y mete lo rotado por la derecha. + +_cpc_RLI:: + LD IX,#2 + ADD IX,SP + LD L,0 (IX) + LD H,1 (IX) ;posición inicial + LD A,2 (IX) ;lineas + LD (alto_cpc_RLI+1),A + LD A,3 (IX) ;ancho + LD (ancho_cpc_RLI+1),A + DEC HL +alto_cpc_RLI: + LD A,#8 ;; parametro +ciclo0_cpc_RLI: + PUSH AF + PUSH HL + INC HL + LD A,(HL) + LD D,H + LD E,L + DEC HL + LD B, #0 +ancho_cpc_RLI: + LD C,#50 ; parametro + LDDR + INC HL + LD (HL),A + POP HL + POP AF + DEC A + RET Z + LD BC,#0X800 ;salto de línea, ojo salto caracter. + ADD HL,BC + JP NC,ciclo0_cpc_RLI ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + ADD HL,BC + JP ciclo0_cpc_RLI + diff --git a/lib/cpcrslib/cpc_RRI.s b/lib/cpcrslib/cpc_RRI.s new file mode 100644 index 0000000..d2f5b5d --- /dev/null +++ b/lib/cpcrslib/cpc_RRI.s @@ -0,0 +1,39 @@ +.globl _cpc_RRI +;cpc_RRI(unsigned int pos, unsigned char w, unsigned char h); +_cpc_RRI:: + LD IX,#2 + ADD IX,SP + LD L,0 (IX) + LD H,1 (IX) ;posición inicial + LD A,2 (IX) ;lineas + LD (alto_cpc_RRI+1),A + LD A,3 (IX) ;ancho + LD (ancho_cpc_RRI+1),A + INC HL +alto_cpc_RRI: + LD A,#8 ;; parametro +ciclo0_cpc_RRI: + PUSH AF + PUSH HL + DEC HL + LD A,(HL) + LD D,H + LD E,L + INC HL ; SOLO MUEVE 1 BYTE + LD B, #0 +ancho_cpc_RRI: + LD C,#50 ; PARAMETRO + LDIR + DEC HL + LD (HL),A + POP HL + POP AF + DEC A + RET Z + LD BC,#0X800 ;salto de línea, ojo salto caracter + ADD HL,BC + JP NC,ciclo0_cpc_RRI ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + ADD HL,BC + JP ciclo0_cpc_RRI + diff --git a/lib/cpcrslib/cpc_Random.s b/lib/cpcrslib/cpc_Random.s new file mode 100644 index 0000000..2f2916e --- /dev/null +++ b/lib/cpcrslib/cpc_Random.s @@ -0,0 +1,34 @@ +.globl _cpc_Random + +_cpc_Random:: + + + ; LD A,(#valor_previo) + ; LD C,A +; LD L,A +; LD A,R; +; ADD L +; AND #0xB8 +; SCF +; JP PO,NO_CLR +; CCF +;NO_CLR: LD A,C + ; RLA + ; LD C,A + ; LD A,R + ; ADD C + ; LD (#valor_previo),A + ; LD L,A +; RET + + LD A,(#valor_previo) + LD L,A + LD A,R + ADD L ;LOS 2 ÚLTIMOS BITS DE A DIRÃN SI ES 0,1,2,3 + LD (#valor_previo),A + LD L,A ;SE DEVUELVE L (CHAR) + LD H,#0 + RET +valor_previo: + .db #0xFF + diff --git a/lib/cpcrslib/cpc_SetBorder.s b/lib/cpcrslib/cpc_SetBorder.s new file mode 100644 index 0000000..b1939df --- /dev/null +++ b/lib/cpcrslib/cpc_SetBorder.s @@ -0,0 +1,10 @@ +.globl _cpc_SetBorder + +_cpc_SetBorder:: + LD HL,#2 + ADD HL,SP + LD B,(HL) + ;LD B,A + LD C,B + JP 0XBC38 + diff --git a/lib/cpcrslib/cpc_SetColour.s b/lib/cpcrslib/cpc_SetColour.s new file mode 100644 index 0000000..7fd6dc3 --- /dev/null +++ b/lib/cpcrslib/cpc_SetColour.s @@ -0,0 +1,16 @@ +.globl _cpc_SetColour + +_cpc_SetColour:: ;El número de tinta 17 es el borde + LD HL,#2 + ADD HL,SP + LD A,(HL) + INC HL + ;INC HL + LD E,(HL) + LD BC,#0x7F00 ;Gate Array + OUT (C),A ;Número de tinta + LD A,#64 ;@01000000 ;Color (y Gate Array) + ADD E + OUT (C),A + RET + diff --git a/lib/cpcrslib/cpc_SetInk.s b/lib/cpcrslib/cpc_SetInk.s new file mode 100644 index 0000000..2c29464 --- /dev/null +++ b/lib/cpcrslib/cpc_SetInk.s @@ -0,0 +1,12 @@ +.globl _cpc_SetInk + +_cpc_SetInk:: + LD HL,#2 + ADD HL,SP + LD A,(HL) + INC HL + + LD B,(HL) + LD C,B + JP 0XBC32 + diff --git a/lib/cpcrslib/cpc_SetMode.s b/lib/cpcrslib/cpc_SetMode.s new file mode 100644 index 0000000..f6877b4 --- /dev/null +++ b/lib/cpcrslib/cpc_SetMode.s @@ -0,0 +1,13 @@ +.globl _cpc_SetMode + +_cpc_SetMode:: + ;ld a,l + LD HL,#2 + ADD HL,SP + LD L,(HL) ; Comprobar que el valor vaya a L!! + LD BC,#0x7F00 ;Gate array port + LD D,#140 ;@10001100 ;Mode and rom selection (and Gate Array function) + ADD D + OUT (C),A + RET + diff --git a/lib/cpcrslib/cpc_SetModo.s b/lib/cpcrslib/cpc_SetModo.s new file mode 100644 index 0000000..8e96c3b --- /dev/null +++ b/lib/cpcrslib/cpc_SetModo.s @@ -0,0 +1,9 @@ +.globl _cpc_SetModo + +_cpc_SetModo:: + ;LD A,L + LD HL,#2 + ADD HL,SP + LD a,(HL) ; COMPROBAR QUE EL VALOR VAYA A L!! + JP 0XBC0E + diff --git a/lib/cpcrslib/cpc_TileMap.s b/lib/cpcrslib/cpc_TileMap.s new file mode 100644 index 0000000..501115b --- /dev/null +++ b/lib/cpcrslib/cpc_TileMap.s @@ -0,0 +1,1332 @@ +PEEPHOLE = 0 + +.include "TileMap.h" + + + +.globl _cpc_ResetTouchedTiles + +_cpc_ResetTouchedTiles:: + LD HL,#_tiles_tocados + LD (HL),#0xFF + RET + + +.globl _cpc_InitTileMap + +_cpc_InitTileMap:: + LD HL,#0 + LD (_tiles),HL + RET + + +.globl _cpc_SetTile + +_cpc_SetTile:: + +; ld ix,#2 +; add ix,sp + +; ld e,1 (ix) +; ld a,0 (ix) + + ld hl,#2 + add hl,sp + ld a,(hl) + inc hl + ld e,(hl) + inc hl + ld c,(hl) + + ;.include "multiplication2.asm" + ;LD H, #ancho_pantalla_bytes/2 + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 / 2 + LD D, L + LD B, #8 + +MULT: ADD HL, HL + JR NC, NOADD + ADD HL, DE +NOADD: DJNZ MULT + + ld e,a + ;ld d,#0 ; D ya es 0 + add hl,de + + ld de,#_pantalla_juego + add hl,de + ld (hl),c + + ret + + + + +; ****************************************************** +; ** Librería de rutinas para Amstrad CPC ** +; ** Raúl Simarro, Artaburu 2007 ** +; ****************************************************** + +.globl _cpc_ShowTileMap ; para una pantalla de 64x160 bytes. Superbuffer 8192bytes + + + +_cpc_ShowTileMap:: + +cont_normal: + xor a + ld (#contador_tiles),a +;Se busca el número de tiles en pantalla + ld hl,(#ntiles) + ld (#contador_tiles2),hl + ld hl,#_pantalla_juego + call transferir_pantalla_a_superbuffer + +;parte donde se transfiere el superbuffer completo a la pantalla + + ld de,#posicion_inicial_superbuffer + ld hl,#tiles_ocultos_ancho0*2 + add hl,de ;primero posiciona en ancho + + ; Posición inicial lectura datos superbuffer + ld de,#ancho_pantalla_bytes + ld b,#tiles_ocultos_alto0*8 + XOR A + CP B + JR Z, NO_SUMA +bucle_alto_visible: + add hl,de + djnz bucle_alto_visible +NO_SUMA: + push hl + ld (#posicion_inicio_pantalla_visible_sb+1),HL + + +;;.otro_ancho + ld b,#ancho_pantalla_bytes-4*(tiles_ocultos_ancho0) ;;nuevo ancho + ld c,#alto_pantalla_bytes-16*(tiles_ocultos_alto0) ;;nuevo alto + + +;; a HL tb se le suma una cantidad + ld de, #tiles_ocultos_alto0*2 + ld hl,#_posiciones_pantalla + add hl,de + ld e,(hl) + inc hl + ld d,(hl) + ld hl, #2*tiles_ocultos_ancho0 + add hl,de + ld (#posicion_inicio_pantalla_visible+1),HL + ld (#posicion_inicio_pantalla_visible2+1),HL + pop de ;origen + ;HL destino + ;DE origen + ;call cpc_PutSpTM ;cambiar la rutina por una que dibuje desde superbuffer + ;ret + jp creascanes +; A partir de la dirección del vector de bloques se dibuja el mapeado en pantalla + + +transferir_pantalla_a_superbuffer: + + + PUSH HL + POP IX ;IX lleva los datos de la pantalla + LD DE,(#_posiciones_super_buffer) +bucle_dibujado_fondo: + ;Leo en HL el tile a meter en el superbuffer + LD L,0 (IX) + LD H,#0 + ADD HL,HL ;x2 + ADD HL,HL ;x4 + ADD HL,HL ;x8 + ADD HL,HL ;x16 + LD BC,#_tiles + ADD HL,BC ;hl apunta al tile a transferir + ;me falta conocer el destino. IY apunta al destino + EX DE,HL + PUSH HL + call transferir_map_sbuffer ;DE origen HL destino + + ; Inicio Mod. 29.06.2009 +; Se cambia la forma de controlar el final de datos de tiles. El #0xFF ahora sí que se podrá utilizar. + ld HL,(#contador_tiles2) + dec HL + LD (#contador_tiles2),HL + LD A,H + OR L + ;ret z + jp z, ret2 +; Fin Mod. 29.06.2009 + POP HL + INC IX ;Siguiente byte + + + +; LD A,(IX+0) +; CP #0xFF ;El fin de los datos se marca con #0xFF, no hay un tile que sea #0xFF + ;RET Z + EX DE,HL + LD A,(#contador_tiles) + CP #ancho_pantalla_bytes/2-1 ;31 ;son 32 tiles de ancho + JP Z,incremento2 + INC A + LD (#contador_tiles),A + INC DE + INC DE ;para pasar a la siguiente posición + ;si ya se va por el 18 el salto es mayor, es + JP bucle_dibujado_fondo + +incremento2: + XOR A + LD (#contador_tiles),A + LD BC, #7*ancho_pantalla_bytes+2 ;450 ; 64x7+2 48x7+2 1084 ;72x15+4 + EX DE,HL + ADD HL,BC + EX DE,HL + JP bucle_dibujado_fondo + +contador_tiles: .DB 0 +contador_tiles2: .DW 0 +; Ahora se puede usar el tile 255 +ntiles: .DW ( alto_pantalla_bytes / 8 ) * ( ancho_pantalla_bytes / 2 ) + +ret2: +;Se busca el número de tiles en pantalla + ;ld hl,(ntiles) + ;ld (contador_tiles2),hl + pop hl +ret + + +transferir_map_sbuffer: + + ld bc,#ancho_pantalla_bytes-1 + + .DB #0xfD + LD H,#8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + +loop_alto_map_sbuffer: +loop_ancho_map_sbuffer: + ld A,(DE) + ld (HL),A + inc de + inc hl + ld A,(DE) + ld (HL),A + inc de + + .DB #0xfD + dec h + ret z +;hay que sumar el ancho de la pantalla en bytes para pasar a la siguiente línea + + add HL,BC + jp loop_alto_map_sbuffer + + +.globl _cpc_PutSpTM + +_cpc_PutSpTM:: ; dibujar en pantalla el sprite + +;di +ld a,b +ld b,c +ld c,a +loop_alto_2_cpc_PutSpTM: + push bc + ld b,c + push hl +loop_ancho_2_cpc_PutSpTM: + ld A,(DE) + ld (hl),a + inc de + inc hl + djnz loop_ancho_2_cpc_PutSpTM + + ;incremento DE con el ancho de la pantalla-el del sprite + ex de,hl +ancho_mostrable: + ld bc,#4*(tiles_ocultos_ancho0) + add hl,bc + ex de,hl + pop hl + ld A,H + add #0x08 + ld H,A + sub #0xC0 + jp nc,sig_linea_2_cpc_PutSpTM + ld bc,#0xc050 + add HL,BC +sig_linea_2_cpc_PutSpTM: + pop BC + djnz loop_alto_2_cpc_PutSpTM +;ei +ret + + + + + +.globl _cpc_ShowTileMap2 + +_cpc_ShowTileMap2:: + ld bc, #256*(ancho_pantalla_bytes-4*(tiles_ocultos_ancho0))+#alto_pantalla_bytes-16*(tiles_ocultos_alto0) + +posicion_inicio_pantalla_visible: + ld hl,#0000 + + +posicion_inicio_pantalla_visible_sb: + ld hl,#0000 +papa: ; código de Xilen Wars + di + ld (#auxsp),sp + ld sp,#tablascan + ld a,#alto_pantalla_bytes-16*(tiles_ocultos_alto0) ;16 alto +ppv0: + pop de ; va recogiendo de la pila!! +inicio_salto_ldi: + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + + ldi + ldi + + ldi + ldi + ldi + ldi + + + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi +CONT_salto_ldi: + ld de,#4*tiles_ocultos_ancho0 + add hl,de + +CONT_salto_ldi1: + dec a + jp nz, ppv0 + ld sp,(#auxsp) + ei + ret + +auxsp: .DW 0 + + + + + +creascanes: + ld ix,#tablascan +posicion_inicio_pantalla_visible2: + ld hl,#0000 + ld b, #alto_pantalla_bytes/8-2*tiles_ocultos_alto0 ; 20 ; num de filas. +cts0: + push bc + push hl + ld b,#8 + ld de,#2048 +cts1: + ld 0 (ix),l + inc ix + ld 0 (ix),h + inc ix + add hl,de + djnz cts1 + pop hl + ld bc,#80 + add hl,bc + pop bc + djnz cts0 +; jp prepara_salto_ldi +prepara_salto_ldi: ; para el ancho visible de la pantalla: + ld hl,#ancho_pantalla_bytes-4*tiles_ocultos_ancho0 + ld de,#inicio_salto_ldi + add hl,hl + add hl,de + ld (hl),#0xc3 + inc hl + ld de,#CONT_salto_ldi + ld (hl),e + inc hl + ld (hl),d + ret + + + + + +; MIRAR SUMA DE COORDENADAS PARA HACER SOLO UNA BUSQUEDA DE TILES +.globl _cpc_PutSpTileMap + +_cpc_PutSpTileMap:: + +.if PEEPHOLE-0 + ex de,hl +.else + ld hl,#2 ;3 + add hl,sp ;3 + + ld e,(hl) ;2 + inc hl ;1 + ld d,(hl) ;2 +.endif + + + +;según las coordenadas x,y que tenga el sprite, se dibuja en el buffer + +; ld hl,#2 ;3 +; add hl,sp ;3 +; ld e,(hl) ;2 +; inc hl ;1 +; ld d,(hl) ;2 + + .db #0xdd + ld l,e ;2 + .db #0xdd + ld h,d ;2 + ; --> 15 NOPS + + ;Obtencion de +;dimensiones, solo usadas para calcular iteraciones -> BC +ld l,0 (ix) +ld h,1 (ix) ;dimensiones del sprite +ld C,(hl) ;; ANCHO +inc hl +ld B,(hl) ;; ANCHO +Dec b +Dec c +;->BC coord -1 + + ld l,10 (ix) + ld h,11 (ix) ;recoje coordenadas anteriores + + ld e,8 (ix) + ld d,9 (ix) + ld 10 (ix),e + ld 11 (ix),d + + +;Obtencion x0y0 -> HL +PUSH HL +Srl l ; x0/2 +Srl h +Srl h +Srl h ; y0/8 +Ex de,hl ;-> Guarda de con origen de loops + +POP hl ;(recuperar coord xoyo) +Add hl,bc ;(Suma de dimensiones) +Srl l ; (x0+ancho)/2 +Srl h +Srl h +Srl h; (y0+alto)/2 + +xor a +SBC hl,de ;diferencia entre bloque inicial y bloque con dimensiones + +;Hl tiene iteraciones en i,j partiendo de origen loops +Ld a,h +Inc a +Ld (pasos_alto_xW+1),a +Ld a,l +Inc a +;Ld (pasos_ancho_x+1),a + +;Loop from d, i veces +;Loop from e, j veces +jp macario +.db 'r','a','u','l' +macario: +pasos_ancho_xW: ; *parametro + ld b,a +bucle_pasos_anchoW: + push de +pasos_alto_xW: ; *parametro + ld c,#0 +bucle_pasos_altoW: + ; Mete E y D + call _cpc_UpdTileTable + inc d + dec c + jp nz,bucle_pasos_altoW + + pop de + inc e + dec b + jp nz,bucle_pasos_anchoW + + ret + + + + +.globl _cpc_UpdTileTable + +_cpc_UpdTileTable:: +; En DE word a comprobar (fila/columna o al revés) + LD HL,#_tiles_tocados + ;incorporo el tile en su sitio, guardo x e y +bucle_recorrido_tiles_tocados: + LD A,(HL) + CP #0xFF + JP Z,incorporar_tile ;Solo se incorpora al llegar a un hueco +; INC HL +; PUSH HL +; LD H,(HL) +; LD L,A +; SBC HL,DE +; POP HL +; RET Z +; INC HL +; JP bucle_recorrido_tiles_tocados + CP E + JP Z, comprobar_segundo_byte + INC HL + INC HL + JP bucle_recorrido_tiles_tocados +comprobar_segundo_byte: + INC HL + LD A,(HL) + CP D + RET Z ;los dos bytes son iguales, es el mismo tile. No se añade + INC HL + JP bucle_recorrido_tiles_tocados + + + +incorporar_tile: + LD (HL),E + INC HL + LD (HL),D + INC HL + LD (HL),#0xFF ;End of data +contkaka: + RET + + +;_solo_tile0: +;LD HL,#_tiles +;jp _saltate + +.globl _cpc_UpdScr + +_cpc_UpdScr:: +;lee la tabla de tiles tocados y va restaurando cada uno en su sitio. + LD IX,#_tiles_tocados ;4 +bucle_cpc_UpdScr: + LD E, 0 (IX) ;5 + LD A,#0xFF ;2 + CP E ;1 + RET Z ;RETORNA SI NO HAY MÁS DATOS EN LA LISTA ;2/4 + LD D,1 (IX) ;5 + INC IX ;3 + INC IX ;3 + +posicionar_superbuffer: +;con la coordenada y nos situamos en la posición vertical y con x nos movemos a su sitio definitivo + LD C,D + SLA C ;x2 + LD B,#0 + + ; puedo usar BC para el siguiente cálculo + push bc + + LD HL,#_posiciones_super_buffer + ADD HL,BC + LD C,(HL) + INC HL + LD B,(HL) + + LD L,E + SLA L + LD H,#0 + + ADD HL,BC + + pop bc + ;HL apunta a la posición correspondiente en superbuffer + push hl + +posicionar_tile: + + LD HL,#_tabla_y_ancho_pantalla + ADD HL,BC + LD C,(HL) + INC HL + LD B,(HL) + LD L,E + LD H,#0 + ADD HL,BC +; LD DE,#_pantalla_juego +; ADD HL,DE + LD L,(HL) +; xor a +; cp l +; jp z, _solo_tile0 + + LD H,#0 + + ADD HL,HL + ADD HL,HL + ADD HL,HL + ADD HL,HL ;X16 + LD DE,#_tiles + ADD HL,DE + ;HL apunta a los datos del tile +;_saltate: + ;ex de,hl + pop de ;hl + ;RET + + + +; de: Posición buffer +; hl: datos tile + + +transferir_map_sbuffer1: ;; ENVIA EL TILE AL SUPERBUFFER + ;ld bc,ancho_pantalla_bytes-2 ;63 + ldi ;5 + ldi ;de<-hl ;5 + ex de,hl ;1 + ld bc,#ancho_pantalla_bytes-2 ;3 + ld a,c + add HL,BC ;3 + ex de,hl ;1 + ldi ;5 + ldi ;5 + ex de,hl ;1 + ld c,a ;ld c,#ancho_pantalla_bytes-2 ;2 + add HL,BC ;3 + ex de,hl ;1 + ldi + ldi + ex de,hl + ld c,a ;ld c,#ancho_pantalla_bytes-2 + add HL,BC + ex de,hl + ldi + ldi + ex de,hl + ld c,a ;ld c,#ancho_pantalla_bytes-2 + add HL,BC + ex de,hl + ldi + ldi + ex de,hl + ld c,a ;ld c,#ancho_pantalla_bytes-2 + add HL,BC + ex de,hl + ldi + ldi + ex de,hl + ld c,a ;ld c,#ancho_pantalla_bytes-2 + add HL,BC + ex de,hl + ldi + ldi + ex de,hl + ld c,a ;ld c,#ancho_pantalla_bytes-2 + add HL,BC + ex de,hl + ldi + ldi +jp bucle_cpc_UpdScr + + + +.globl _cpc_PutSpTileMap2b + +_cpc_PutSpTileMap2b:: + +;según las coordenadas x,y que tenga el sprite, se dibuja en el buffer + + ; ld ix,#2 + ; add ix,sp + + + ; ld l,0 (ix) + ; ld h,1 (ix) ;HL apunta al sprite + + ; push hl + ; pop ix + + + ld hl,#2 ;3 + add hl,sp ;3 + ld e,(hl) ;2 + inc hl ;1 + ld d,(hl) ;2 + + .db #0xdd + ld l,e ;2 + .db #0xdd + ld h,d ;2 + ; --> 15 NOPS + + + + ;lo cambio para la rutina de multiplicar + ld a,8 (ix) + ld e,9 (ix) + + +;include "multiplication1.asm" + + + ;ld h, #ancho_pantalla_bytes + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 + LD D, L + LD B, #8 + +MULT2: ADD HL, HL + JR NC, NOADD2 + ADD HL, DE +NOADD2: DJNZ MULT2 + + + + + + ;ld b,#0 + ld e,a + add hl,de + ld de,#posicion_inicial_superbuffer + add hl,de + ;hl apunta a la posición en buffer (destino) + + + ld 4 (ix),l ;update superbuffer address + ld 5 (ix),h + + + ld e,0 (ix) + ld d,1 (ix) ;HL apunta al sprite + + ;con el alto del sprite hago las actualizaciones necesarias a la rutina + ld a,(de) + ld (#loop_alto_map_sbuffer2+2),a + ld b,a + ld a,#ancho_pantalla_bytes + sub b + ;ld (#ancho_22+1),a + ld c,a + inc de + ld a,(de) + inc de + + ;ld a,16 ;necesito el alto del sprite + + + +sp_buffer_mask2: + ld b,#0 +ancho_22: + ;ld c,#ancho_pantalla_bytes-4 ;60 ;;DEPENDE DEL ANCHO + + .db #0xDD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + ;ld ixh,a +loop_alto_map_sbuffer2: + .db #0xDD + LD L,#4 ;ANCHO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + ;ld ixl,#4 + ex de,hl +loop_ancho_map_sbuffer2: + + + LD A,(hl) ;leo el byte del fondo + ;AND (HL) ;lo enmascaro + ;INC HL + ;OR (HL) ;lo enmascaro + LD (de),A ;actualizo el fondo + INC DE + INC HL + + + .db #0xDD + DEC L ;resta ancho + ;dec ixl + JP NZ,loop_ancho_map_sbuffer2 + + .db #0xDD + dec H + ;dec ixh + ret z + EX DE,HL +;hay que sumar 72 bytes para pasar a la siguiente línea + add HL,BC + jp loop_alto_map_sbuffer2 + + +.globl _cpc_PutMaskSpTileMap2b + +_cpc_PutMaskSpTileMap2b:: +;según las coordenadas x,y que tenga el sprite, se dibuja en el buffer + .if PEEPHOLE-0 + ex de,hl +.else + + ld hl,#2 ;3 + add hl,sp ;3 + ld e,(hl) ;2 + inc hl ;1 + ld d,(hl) ;2 +.endif + + +; ld hl,#2 ;3 +; add hl,sp ;3 +; ld e,(hl) ;2 +; inc hl ;1 +; ld d,(hl) ;2 + + .db #0xdd + ld l,e ;2 + .db #0xdd + ld h,d ;2 + ; --> 15 NOPS + + + ld a,8 (ix) + ld e,9 (ix) + +;include "multiplication1.asm" + ;ld h, #ancho_pantalla_bytes + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 + LD D, L + LD B, #8 + +MULT3: ADD HL, HL + JR NC, NOADD3 + ADD HL, DE +NOADD3: DJNZ MULT3 + + + + ;ld b,#0 + ld e,a + add hl,de + ;HL=E*H+D + + + + + + ld de,#posicion_inicial_superbuffer + add hl,de + ;hl apunta a la posición en buffer (destino) + + ld 4 (ix),l ;update superbuffer address + ld 5 (ix),h + + ld e,0 (ix) + ld d,1 (ix) ;HL apunta al sprite + + ;con el alto del sprite hago las actualizaciones necesarias a la rutina + ld a,(de) + ld (#loop_alto_map_sbuffer3+2),a + ld b,a + ld a,#ancho_pantalla_bytes + sub b + ;ld (#ancho_23+1),a + ld c,a + inc de + ld a,(de) + inc de + + ;ld a,16 ;necesito el alto del sprite + + + +sp_buffer_mask3: + ld b,#0 +ancho_23: + ;ld c,#ancho_pantalla_bytes-4 ;60 ;;DEPENDE DEL ANCHO + + .db #0xdd + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + ;ld ixh,a +loop_alto_map_sbuffer3: + .db #0xdd + LD L,#4 ;ANCHO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + ;ld ixl,4 + ex de,hl +loop_ancho_map_sbuffer3: + + + LD A,(DE) ;leo el byte del fondo + AND (HL) ;lo enmascaro + INC HL + OR (HL) ;lo enmascaro + LD (DE),A ;actualizo el fondo + INC DE + INC HL + + .db #0xdD + DEC L ;resta ancho + ;dec ixl + JP NZ,loop_ancho_map_sbuffer3 + + .db #0xdd + dec H + ;dec ixh + ret z + EX DE,HL +;hay que sumar 72 bytes para pasar a la siguiente línea + add HL,BC + jp loop_alto_map_sbuffer3 + + + + + + + + +.globl _cpc_PutMaskInkSpTileMap2b + +_cpc_PutMaskInkSpTileMap2b:: +;según las coordenadas x,y que tenga el sprite, se dibuja en el buffer + + ld hl,#2 ;3 + add hl,sp ;3 + ld e,(hl) ;2 + inc hl ;1 + ld d,(hl) ;2 + + .db #0xdd + ld l,e ;2 + .db #0xdd + ld h,d ;2 + ; --> 15 NOPS + + + ld a,8 (ix) + ld e,9 (ix) + +;include "multiplication1.asm" + ;ld h, #ancho_pantalla_bytes + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 + LD D, L + LD B, #8 + +MULT7: ADD HL, HL + JR NC, NOADD7 + ADD HL, DE +NOADD7: DJNZ MULT7 + + ld e,a + add hl,de + ;HL=E*H+D + + ld de,#posicion_inicial_superbuffer + add hl,de + ;hl apunta a la posición en buffer (destino) + + ld 4 (ix),l ;update superbuffer address + ld 5 (ix),h + + ld e,0 (ix) + ld d,1 (ix) ;HL apunta al sprite + + ;con el ancho del sprite hago las actualizaciones necesarias a la rutina + ld a,(de) + ld (#loop_alto_map_sbuffer7+2),a + ld b,a + ld a,#ancho_pantalla_bytes + sub b + ;ld (#ancho_27+1),a + ld c,a + inc de + ld a,(de) + inc de + + +sp_buffer_mask7: + ld b,#0 +ancho_27: + ;ld c,#ancho_pantalla_bytes-4 ;60 ;;DEPENDE DEL ANCHO + + .db #0xdd + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + ;ld ixh,a +loop_alto_map_sbuffer7: + .db #0xdd + LD L,#4 ;ANCHO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + ;ld ixl,4 + ex de,hl + +loop_ancho_map_sbuffer7: + + + LD A,(hl) ;leo el byte del fondo + or a + jp z, cont7 + + LD (DE),A ;actualizo el fondo +cont7: + INC DE + INC HL + + .db #0xdD + DEC L ;resta ancho + ;dec ixl + JP NZ,loop_ancho_map_sbuffer7 + + .db #0xdd + dec H + ;dec ixh + ret z + EX DE,HL +;hay que sumar 72 bytes para pasar a la siguiente línea + add HL,BC + jp loop_alto_map_sbuffer7 + + + +.globl _cpc_ScrollLeft00 + +_cpc_ScrollLeft00:: + + ;se decrementa cada posiciones_pantalla + LD HL,#_posiciones_pantalla + ld b,#20 + buc_suma1: + DEC (HL) + INC HL + INC HL + djnz buc_suma1 + + ld hl,(#posicion_inicio_pantalla_visible_sb+1) + inc HL + ld (#posicion_inicio_pantalla_visible_sb+1),HL + + RET + +.globl _cpc_ScrollLeft01 + +_cpc_ScrollLeft01:: + + ;se incrementa cada posiciones_pantalla + LD HL,#_posiciones_pantalla + ld b,#20 + buc_suma14: + INC (HL) + INC HL + INC HL + djnz buc_suma14 + + + ld hl,(#posicion_inicio_pantalla_visible_sb+1) + dec HL + ld (#posicion_inicio_pantalla_visible_sb+1),HL + + + ld hl,#_pantalla_juego+1 + ld de,#_pantalla_juego + ld bc,#alto_pantalla_bytes*ancho_pantalla_bytes/16 -1 + LDIR + + ld hl,#posicion_inicial_superbuffer+2 + ld de,#posicion_inicial_superbuffer + ld bc,#alto_pantalla_bytes*ancho_pantalla_bytes -1 + LDIR + + RET + + + + +.globl _cpc_ScrollRight00 + +_cpc_ScrollRight00:: ;;scrollea el area de pantalla de tiles + + ;se decrementa cada posiciones_pantalla + LD HL,#_posiciones_pantalla + ld b,#20 + buc_suma12: + INC (HL) + INC HL + INC HL + djnz buc_suma12 + + + ld hl,(#posicion_inicio_pantalla_visible_sb+1) + dec HL + ld (#posicion_inicio_pantalla_visible_sb+1),HL + + RET + + +.globl _cpc_ScrollRight01 + +_cpc_ScrollRight01:: ;;scrollea el area de pantalla de tiles + + ;se incrementa cada posiciones_pantalla + LD HL,#_posiciones_pantalla + ld b,#20 + buc_suma15: + DEC (HL) + INC HL + INC HL + djnz buc_suma15 + + + ld hl,(#posicion_inicio_pantalla_visible_sb+1) + inc HL + ld (#posicion_inicio_pantalla_visible_sb+1),HL + + ld hl,#_pantalla_juego+alto_pantalla_bytes*ancho_pantalla_bytes/16-1 + ld de,#_pantalla_juego+alto_pantalla_bytes*ancho_pantalla_bytes/16 + ld bc,#alto_pantalla_bytes*ancho_pantalla_bytes/16 -1 ;-1 + LDDR + + ;;scrollea el superbuffer + ld hl,#posicion_inicial_superbuffer+alto_pantalla_bytes*ancho_pantalla_bytes-2 ; pantalla_juego+alto_pantalla_bytes*ancho_pantalla_bytes/16-1 + ld de,#posicion_inicial_superbuffer+alto_pantalla_bytes*ancho_pantalla_bytes ;pantalla_juego+alto_pantalla_bytes*ancho_pantalla_bytes/16 + ld bc,#alto_pantalla_bytes*ancho_pantalla_bytes-1 ;-1 + LDDR + RET + +.globl _cpc_SetTouchTileXY + +_cpc_SetTouchTileXY:: + + ;ld ix,#2 + ;add ix,sp + + ;ld d,1 (ix) + ;ld e,0 (ix) + + + ld hl,#2 + add hl,sp + ld e,(hl) + inc hl + ld d,(hl) + inc hl + ld c,(hl) + + + ;ld d,e + ;ld e,c + call _cpc_UpdTileTable + + ;ld e,1 (ix) + ;ld a,0 (ix) + ld a,e + ld e,d +;include "multiplication2.asm" + ;ld h, #ancho_pantalla_bytes/2 + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 / 2 + LD D, L + LD B, #8 + +MULT4: ADD HL, HL + JR NC, NOADD4 + ADD HL, DE +NOADD4: DJNZ MULT4 + + + ld e,a + ;ld d,#0 + add hl,de + ld de,#_pantalla_juego + add hl,de + ;ld a,2 (ix) + ld (hl),c + ret + + +.globl _cpc_ReadTile + +_cpc_ReadTile:: + + +; ld ix,#2 +; add ix,sp +; ld e,1 (ix) +; ld a,0 (ix) + + ld hl,#2 + add hl,sp + ld a,(hl) + inc hl + ld e,(hl) + + + +; ld hl,2 +; add hl,sp ; ¿Es la forma de pasar parámetros? ¿Se pasan en SP+2? ¿en la pila? +; ld E,(hl) ;Y +; inc hl +; inc hl +; ld a,(hl) ;X + +; include "multiplication2.asm" + ;ld h, #ancho_pantalla_bytes/2 + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 / 2 + LD D, L + LD B, #8 + +MULT5: ADD HL, HL + JR NC, NOADD5 + ADD HL, DE +NOADD5: DJNZ MULT5 + + + + ld e,a + ;ld d,#0 + add hl,de ;SUMA X A LA DISTANCIA Y*ANCHO + ld de,#_pantalla_juego + add hl,de + ld l,(hl) + ld h,#0 + ret + + +.globl _cpc_SuperbufferAddress + +_cpc_SuperbufferAddress:: +; ld ix,#2 +; add ix,sp + +; ld l,0 (ix) +; ld h,1 (ix) ;HL apunta al sprite + +; push hl +; pop ix + + ld hl,#2 ;3 + add hl,sp ;3 + ld e,(hl) ;2 + inc hl ;1 + ld d,(hl) ;2 + + .db #0xdd + ld l,e ;2 + .db #0xdd + ld h,d ;2 + ; --> 15 NOPS + + + ;lo cambio para la rutina de multiplicar + ld a,8 (ix) + ld e,9 (ix) +; include "multiplication1.asm" + ;ld h, #ancho_pantalla_bytes + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 + LD D, L + LD B, #8 + +MULT6: ADD HL, HL + JR NC, NOADD6 + ADD HL, DE +NOADD6: DJNZ MULT6 + + + ;ld b,#0 + ld e,a + add hl,de + ld de,#posicion_inicial_superbuffer + add hl,de + ;hl apunta a la posición en buffer (destino) + ld 4 (ix),l + ld 5 (ix),h + ret + + + +tablascan: ;defs 20*16 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + diff --git a/lib/cpcrslib/cpc_UnExoOpt.s b/lib/cpcrslib/cpc_UnExoOpt.s new file mode 100644 index 0000000..14197cc --- /dev/null +++ b/lib/cpcrslib/cpc_UnExoOpt.s @@ -0,0 +1,183 @@ +; ****************************************************** +; ** Librería de rutinas SDCC para Amstrad CPC ** +; ** Raúl Simarro (Artaburu) - 2009, 2012 ** +; ****************************************************** + + +;************************************* +; UNEXO +;************************************* + + +; Exomizer 2 Z80 decoder +; by Metalbrain +; +; optimized by Antonio Villena +; +; compression algorithm by Magnus Lind + +;input: hl=compressed data start +; de=uncompressed destination start +; +; you may change exo_mapbasebits to point to any free buffer + + +.globl _cpc_UnExo + +_cpc_UnExo:: + +; POP AF +; POP HL ;DESTINATION ADDRESS +; POP DE ;SPRITE DATA +; PUSH AF + + LD IX,#2 + ADD IX,SP + LD e,2 (IX) + LD d,3 (IX) ;DESTINO + LD l,0 (IX) + LD h,1 (IX) ;TEXTO ORIGEN + + di + call deexo + ei + ret + +deexo: + ld iy, #exo_mapbasebits + ld a,#128 + ld b,#52 + push de +exo_initbits: + ex af,af' + ld a,b + sub #4 + and #15 + jr nz,exo_node1 + ld de,#1 ;DE=b2 +exo_node1: + ld c,#16 + ex af, af' +exo_get4bits: + call exo_getbit + rl c + jr nc,exo_get4bits + ld (iy),c ;bits[i]=b1 + push hl + ld hl,#1 + .db #210 ;3 bytes nop (JP NC) +exo_setbit: + add hl,hl + dec c + jr nz,exo_setbit + ld 52 (iy),e + ld 104 (iy),d ;base[i]=b2 + add hl,de + ex de,hl + inc iy + pop hl + djnz exo_initbits + inc c +exo_literalseq: + pop de +exo_literalcopy: + ldir ;copy literal(s) +exo_mainloop: + ld c,#1 + call exo_getbit ;literal? + jr c,exo_literalcopy + ld c,#255 +exo_getindex: + inc c + call exo_getbit + jr nc,exo_getindex + bit 4,c + jr z,exo_continue + bit 0, c + ret z + push de + ld d,#16 + call exo_getbits + jr exo_literalseq +exo_continue: + push de + call exo_getpair + push bc + pop ix + ld de,#560 ;512+48 ;1? + inc b + djnz exo_dontgo + dec c + jr z, exo_goforit + dec c ;2? +exo_dontgo: + ld de,#1056 ;1024+32 + jr z,exo_goforit + ld e,#16 +exo_goforit: + call exo_getbits + ex af, af' + ld a,e + add a,c + ld c,a + ex af, af' + call exo_getpair ;bc=offset + pop de ;de=destination + push hl + ld h,d + ld l,e + sbc hl,bc ;hl=origin + push ix + pop bc ;bc=lenght + ldir + pop hl ;Keep HL, DE is updated + jr exo_mainloop ;Next! + +exo_getpair: + ld iy,#exo_mapbasebits + ld b,#0 + add iy,bc + ld d,(iy) + call exo_getbits + push hl + ld l, 52 (iy) + ld h, 104 (iy) + add hl, bc ;Always clear C flag + ld b, h + ld c, l + pop hl + ret + +exo_getbits: + ld bc,#0 ;get D bits in BC +exo_gettingbits: + dec d + ret m + call exo_getbit + rl c + rl b + jr exo_gettingbits + +exo_getbit: + add a, a ;get one bit + ret nz + ld a, (hl) + inc hl + adc a, a + ret + +exo_mapbasebits: + ;defs 156 ;tables for bits, baseL, baseH + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 \ No newline at end of file diff --git a/lib/cpcrslib/cpc_Uncrunch.s b/lib/cpcrslib/cpc_Uncrunch.s new file mode 100644 index 0000000..7eba8c3 --- /dev/null +++ b/lib/cpcrslib/cpc_Uncrunch.s @@ -0,0 +1,308 @@ +; ****************************************************** +; ** Librería de rutinas SDCC para Amstrad CPC ** +; ** Raúl Simarro (Artaburu) - 2009, 2012 ** +; ****************************************************** + + +;************************************* +; UNCRUNCH +;************************************* + + +.globl _cpc_Uncrunch + +_cpc_Uncrunch:: +; datos necesarios que vienen en la pila: +; ORIGEN HL +; DESTINO DE + + ;Ojo, para que el pucrunch funcione hay que coger y quitar el salto de las interrupciones. + DI + LD HL,(#0X0038) + LD (#datos_int),HL + + LD HL,#0X00C9 + LD (#0x0038),HL + EI + +;POP AF +;POP HL +;POP DE +;PUSH AF + LD IX,#2 + ADD IX,SP + LD e,2 (IX) + LD d,3 (IX) ;DESTINO + LD l,0 (IX) + LD h,1 (IX) ;TEXTO ORIGEN + + +pucrunch: + PUSH DE ; destination pointer to 2nd register + EXX ; set + POP DE + + + PUSH HL + PUSH DE + PUSH BC + PUSH AF + + EXX + + ; read the header self-modifying the + ; parameters straight into the code + ; skip useless data + + + LD BC,#6 + ADD HL,BC + + LD A, (HL) ; starting escape + INC HL + LD (#esc+1), A + + INC HL ; skip useless data + INC HL + + LD A, (HL) ; number of escape bits + INC HL + LD (#escb0+1), A + LD (#escb1+1), A + + LD B, A ; 8 - escape bits + LD A, #8 + SUB B + LD (#noesc+1), A + + LD A, (HL) ; maxGamma + 1 + INC HL + LD (#mg+1), A + + LD B, A ; 8 - maxGamma + LD A, #9 + SUB B + LD (#longrle+1), A + + LD A, (HL) ; (1 << maxGamma) + INC HL + LD (#mg1+1), A + + ADD A, A ; (2 << maxGamma) - 1 + DEC A + LD (#mg21+1), A + + LD A, (HL) ; extra lz77_0 position bits + INC HL + LD (#elzpb+1), A + + INC HL ; skip useless data + INC HL + + LD E, (HL) ; RLE table length + LD (#rlet+1), HL ; RLE table pointer + INC HL + LD D, #0 + ADD HL, DE + + LD C, #0X80 ; start decompression + JP loop_u + +newesc: + ld a, (#esc+1) ; save old escape code + ld d, a + +escb0: + LD B, #2 ; ** parameter + XOR A ; get new escape code + CALL get_bits + LD (#esc+1), A + + LD A, D + +noesc: + LD B, #6 ; ** parameter + CALL get_bits ; get more bits to complete a byte + + EXX ; output the byte + LD (DE), A + INC DE + EXX + +loop_u: + XOR A +escb1: + LD B, #2 ; ** parameter + CALL get_bits ; get escape code +esc: + CP #0 ; ** PARAMETER + JP NZ, noesc + + CALL get_gamma ; get length + EXX + LD B, #0 + LD C, A + EXX + + CP #1 + JP NZ, lz77_0 ; lz77_0 + + XOR A + CALL get_bit + JP NC, lz77_0_2 ; 2-byte lz77_0 + + CALL get_bit + JP NC, newesc ; escaped literal byte + + CALL get_gamma ; get length + EXX + LD B, #1 + LD C, A + EXX + +mg1: + CP #64 ; ** parameter + JP C, chrcode ; short RLE, get bytecode + +longrle: + LD B, #2 ; ** parameter + CALL get_bits ; complete length LSB + EX AF, AF' + + CALL get_gamma ; length MSB + EXX + LD B, A + EX AF, AF' + LD C, A + EXX + +chrcode: + CALL get_gamma ; get byte to repeat + + PUSH HL +rlet: + LD HL, #0X0000 ; ** parameter + LD D, #0 + LD E, A + ADD HL, DE + + CP #32 + LD A, (HL) + POP HL + JP C, dorle + + LD A, E ; get 3 more bits to complete the + LD B, #3 ; byte + CALL get_bits + +dorle: + EXX ; output the byte n times + INC C +dorlei: + LD (DE), A + INC DE + DEC C + JP NZ, dorlei + DEC B + JP NZ, dorlei + EXX + JP loop_u + +lz77_0: + CALL get_gamma ; offset MSB +mg21: + CP #127 ; ** parameter + + ; ret z + + JP Z, fin ; EOF, return + + DEC A ; (1...126 -> 0...125) +elzpb: + LD B, #0 ; ** parameter + CALL get_bits ; complete offset MSB + +lz77_0_2: + EX AF, AF' + LD B, #8 ; offset LSB + CALL get_bits + CPL ; xor'ed by the compressor + + EXX ; combine them into offset + LD L, A + EX AF, AF' + LD H, A + INC HL + + XOR A ; CF = 0 + + PUSH DE ; (current output position) - (offset) + EX DE, HL + SBC HL, DE + POP DE + + INC BC + + LDIR ; copy + EXX + JP loop_u + +;## Get a bit from the source stream. +;## Return CF = result +get_bit: + SLA C ; shift next bit into CF + RET NZ + LD C, (HL) ; get next byte + INC HL ; increase source stream pointer + RL C ; shift next bit into CF, bit0 = 1 + RET + +;## Get multiple bits from the source stream. +;## In B = number of bits to get +;## Return A = result +get_bits: + DEC B + RET M + SLA C ; shift next bit into CF + JP NZ, gb1 + LD C, (HL) ; get next byte + INC HL ; increase source stream pointer + RL C ; shift next bit into CF, bit0 = 1 +gb1: + RLA ; rotate next bit into A + JP get_bits + +;## Get an Elias Gamma coded value from the source stream. +;## Return A = result +get_gamma: + LD B, #1 +mg: + LD A, #7 ; ** parameter +gg1: + CALL get_bit ; get bits until 0-bit or max + JR NC, gg2 + INC B + CP B + JP NZ, gg1 +gg2: + LD A, #1 ; GET THE ACTUAL VALUE + DEC B + JP get_bits + +fin: + ; Restauramos los registros dobles y vuelta limpia + EXX + POP AF + POP BC + POP DE + POP HL + EXX + + ;RET + DI + LD HL,(#datos_int) + LD (#0X0038),HL ;RESTAURO LA INTERRUPCIÓN ORIGINAL + EI + RET +datos_int: + .DW #0 \ No newline at end of file diff --git a/lib/cpcrslib/cpcrslib.h b/lib/cpcrslib/cpcrslib.h new file mode 100644 index 0000000..91bee0d --- /dev/null +++ b/lib/cpcrslib/cpcrslib.h @@ -0,0 +1,116 @@ + +#ifndef __cpcrslib_h__ +#define __cpcrslib_h__ + + + + + + + +void cpc_UnExo(char *origen, int destino); +void cpc_Uncrunch(char *origen, int destino); + + +void cpc_SetMode( char color); +void cpc_SetModo( char x); +void cpc_SetColour(unsigned char num, char color); +void cpc_SetInk(unsigned char num, unsigned char color); +void cpc_SetBorder( char color); +unsigned char cpc_Random(void); + +void cpc_ClrScr(void); + +void cpc_PutSprite(char *sprite, int posicion); +void cpc_PutSp(char *sprite, char height, char width, int address); +void cpc_PutSp4x14(char *sprite, int address); +void cpc_PutSpriteXOR(char *sprite, int posicion); +void cpc_PutSpXOR(char *sprite, char height, char width, int address); +void cpc_PutSpriteTr(char *sprite, int *posicion); +void cpc_PutSpTr(char *sprite, char height, char width, int address); +void cpc_GetSp(char *sprite, char alto, char ancho, int posicion); +void cpc_PutMaskSprite(char *sprite,unsigned int addr); +//void cpc_PutMaskSprite(struct sprite *spr,unsigned int *addr); +void cpc_PutMaskSp(char *sprite, char alto, char ancho, int posicion); +void cpc_PutMaskSp4x16(char *sprite,unsigned int addr); +void cpc_PutMaskSp2x8(char *sprite,unsigned int addr); + + +unsigned char cpc_CollSp(char *sprite, char *sprite2); + + +// TILE MAP: +void cpc_InitTileMap(void); +void cpc_SetTile(unsigned char x, unsigned char y, unsigned char b); +void cpc_ShowTileMap(); +void cpc_ShowTileMap2(void); +void cpc_ResetTouchedTiles(void); + +void cpc_PutSpTileMap(char *sprite); +void cpc_PutSpTileMapF(char *sprite); +void cpc_UpdScr(void); +void cpc_PutSpTileMap2b(char *sprite); +void cpc_PutMaskSpTileMap2b(char *sprite); +void cpc_PutMaskInkSpTileMap2b(char *sprite); +void cpc_PutTrSpTileMap2b(char *sprite); +void cpc_PutTrSpriteTileMap2b(char *sprite); + + +void cpc_SpUpdY(char *sprite, char valor); +void cpc_SpUpdX(char *sprite, char valor); + +void cpc_ScrollRight00(void); +void cpc_ScrollRight01(void); +void cpc_ScrollLeft00(void); +void cpc_ScrollLeft01(void); +void cpc_ScrollRight(void); +void cpc_ScrollLeft(void); + +void cpc_SetTouchTileXY(unsigned char x, unsigned char y, unsigned char t); +unsigned char cpc_ReadTile(unsigned char x, unsigned char y); +void cpc_SuperbufferAddress(char *sprite); + +// **************** + + + + + + +void cpc_RRI(unsigned int pos, unsigned char w, unsigned char h); +void cpc_RLI(unsigned int pos, unsigned char w, unsigned char h); + + +int cpc_AnyKeyPressed(void); +void cpc_ScanKeyboard(void); +char cpc_TestKeyF(char number); +void cpc_DeleteKeys(void); +void cpc_AssignKey(unsigned char tecla, int valor); +unsigned char cpc_TestKey(unsigned char tecla); +void cpc_RedefineKey(unsigned char tecla); + +int cpc_GetScrAddress(char x, char y); + +void cpc_PrintStr(char *text); + +void cpc_EnableFirmware(void); +void cpc_DisableFirmware(void); + +void cpc_SetFont(unsigned char first_char, unsigned char *font_def); + +void cpc_PrintGphStr(char *text, int destino); +void cpc_PrintGphStrM1(char *text, int destino); +void cpc_PrintGphStr2X(char *text, int destino); +void cpc_PrintGphStrM12X(char *text, int destino); + +void cpc_PrintGphStrXY(char *text, unsigned char a, unsigned char b); +void cpc_PrintGphStrXYM1(char *text, unsigned char a, unsigned char b); +void cpc_PrintGphStrXY2X(char *text, unsigned char a, unsigned char b); +void cpc_PrintGphStrXYM12X(char *text, unsigned char a, unsigned char b); +void cpc_SetInkGphStr(unsigned char a, unsigned char b); +void cpc_SetInkGphStrM1(unsigned char a, unsigned char b); + +void cpc_PrintGphStrStd(char color, char *cadena, int destino); +void cpc_PrintGphStrStdXY(char color, char *cadena, char x, char y); + +#endif /* __cpcrslib_h__ */ diff --git a/lib/cpcrslib/cpcwyzlib.h b/lib/cpcrslib/cpcwyzlib.h new file mode 100644 index 0000000..b0c04c4 --- /dev/null +++ b/lib/cpcrslib/cpcwyzlib.h @@ -0,0 +1,18 @@ + +#ifndef __cpcwyzlib_h__ +#define __cpcwyzlib_h__ + + + +extern void cpc_WyzLoadSong(unsigned char numero); +extern void cpc_WyzStartEffect(unsigned char canal, unsigned char efecto); +//extern void cpc_WyzSetPlayerOn(void); +// use WyzPlayerOn instead! +extern void cpc_WyzSetPlayerOff(void); +// WARNING: use WyzPlayerOff instead! +extern void cpc_WyzConfigurePlayer(unsigned char valor); +extern unsigned char cpc_WyzTestPlayer(void); +extern void cpc_WyzInitPlayer(unsigned char *sonidos[], unsigned char *pautas[], unsigned char *efectos[], unsigned char *canciones[]); +extern void cpc_WyzSetTempo(unsigned char tempo); + +#endif diff --git a/lib/cpcrslib/make.bat b/lib/cpcrslib/make.bat new file mode 100644 index 0000000..77a7e8c --- /dev/null +++ b/lib/cpcrslib/make.bat @@ -0,0 +1,19 @@ +del *.rel +del *.lib +sdasz80 -o cpcrslib.s +sdasz80 -o GphStr.s +sdasz80 -o Sprites.s +sdasz80 -o Keyboard.s +sdasz80 -o UnExoOpt.s +sdasz80 -o Uncrunch.s +sdasz80 -o GphStrStd.s +sdasz80 -o TileMap.s +sdasz80 -o Wyz.s + + + +sdar rc cpcrslib.lib cpcrslib.rel GphStr.rel Sprites.rel Keyboard.rel UnExoOpt.rel Uncrunch.rel GphStrStd.rel TileMap.rel + +sdar rc cpcwyzlib.lib Wyz.rel +copy cpcrslib.lib C:\sdcc\lib\z80 +copy cpcwyzlib.lib C:\sdcc\lib\z80 diff --git a/lib/plw.h b/lib/plw.h new file mode 100644 index 0000000..5d01172 --- /dev/null +++ b/lib/plw.h @@ -0,0 +1,19 @@ +#ifndef __PLW_H +#define __PLW_H + +#include + +void PLW_Init(uint8_t *song, uint8_t sub_song); +void PLW_Play(); +void PLW_Stop(); + +void PLW_InitSoundEffects(uint8_t *effects) __z88dk_fastcall; +void PLW_PlaySoundEffect(uint8_t effect_no, uint8_t chan, uint8_t inv_vol); +uint8_t PLW_IsSoundEffectOn(uint8_t chan) __z88dk_fastcall; + +// play sound effect with priority +void PLW_PlaySoundEffectP(uint8_t efx_no) __z88dk_fastcall; + +#define EFX_CHANNEL 2 + +#endif // __PLW_H diff --git a/lib/plw/Makefile b/lib/plw/Makefile new file mode 100644 index 0000000..ff6e632 --- /dev/null +++ b/lib/plw/Makefile @@ -0,0 +1,34 @@ +LIB=plw.lib + +all: $(LIB) + +CC=sdcc +AS=sdasz80 +AR=sdar +CFLAGS=-mz80 --Werror --fsigned-char --std-sdcc99 --opt-code-speed +LDFLAGS=--no-std-crt0 --fomit-frame-pointer + +lib_SRCS=$(wildcard *.z80) +lib_OBJS=$(patsubst %.z80,%.rel,$(lib_SRCS)) + +$(LIB): $(lib_OBJS) plw_player.rel + $(AR) -rcD $(LIB) $(lib_OBJS) + cp $(LIB) .. + cp plw_player.rel ../ + +plw_player.rel: plw_player.c player/plw_player.h + +player/plw_player.h: + make -C player + +%.rel: %.z80 + $(AS) -o $< + +%.rel: %.c + $(CC) $(CFLAGS) $(LDFLAGS) -c $< + +.PHONY: clean +clean: + make -C player clean + rm -f *.bin *.rel *.lk *.noi *.map *.ihx *.sym *.lst *.zx7 player.asm $(LIB) + diff --git a/lib/plw/README.md b/lib/plw/README.md new file mode 100644 index 0000000..174ae56 --- /dev/null +++ b/lib/plw/README.md @@ -0,0 +1,16 @@ +This is Arkos 2 lightweight player. + +It comes with two components: + + - A .rel module to load in 0x0b06 (just after the CRT0) + - A library with the functions to call the module + +This is so the player can be assembled by rasm and still use SDCC linker. + +IMPORTANT: if your CRT0 changes its size, you'll have to change the loading +address and the entry point for all the functions. + +For licensing information, PLW is just a wrapper that can be distributed +under the same license as Arkos Player 2 AKW player. + +Code by Juan J. Martinez diff --git a/lib/plw/player/Makefile b/lib/plw/player/Makefile new file mode 100644 index 0000000..53e0b23 --- /dev/null +++ b/lib/plw/player/Makefile @@ -0,0 +1,11 @@ +SOURCES=$(wildcard *.asm) + +all: plw_player.h + +plw_player.h: $(SOURCES) + rasm player.asm -ob plw_player.bin + bin2h.py plw_player.bin plw_player > plw_player.h + +.PHONY: clean all +clean: + rm -f *.bin plw_player.h diff --git a/lib/plw/player/PlayerLightWeight.asm b/lib/plw/player/PlayerLightWeight.asm new file mode 100644 index 0000000..5da830c --- /dev/null +++ b/lib/plw/player/PlayerLightWeight.asm @@ -0,0 +1,1694 @@ +; Arkos Tracker 2 Lightweight player (format V1 (used by AT2 since alpha4)). + +; ** This player has been superseded by the AKM format, more compact but also more powerful. Please use it instead. ** + +; This compiles with RASM. Check the compatibility page on the Arkos Tracker 2 website, it contains a source converter to any Z80 assembler! + +; This is a generic player, but much simpler and using only the most used features, so that the music and players are both +; lightweight. The player supports sound effects. + +; Though the player is optimized in speed, it is much slower than the generic one or the AKY player. +; With effects used at the same time, it may reach 35 scanlines on a CPC, plus some few more if you are using sound effects. + +; The player uses the stack for optimizations. Make sure the interruptions are disabled before it is called. +; The stack pointer is saved at the beginning and restored at the end. + +; Target harware: +; --------------- +; This code can target Amstrad CPC, MSX, Spectrum and Pentagon. By default, it targets Amstrad CPC. +; Simply use one of the follow line (BEFORE this player): +; PLY_LW_HARDWARE_CPC = 1 +; PLY_LW_HARDWARE_MSX = 1 +; PLY_LW_HARDWARE_SPECTRUM = 1 +; PLY_LW_HARDWARE_PENTAGON = 1 +; Note that the PRESENCE of this variable is tested, NOT its value. +; +; Some severe optimizations of CPU/memory can be performed: +; --------------------------------------------------------- +; - Use the Player Configuration of Arkos Tracker 2 to generate a configuration file to be included at the beginning of this player. +; It will disable useless features according to your songs! Check the manual for more details, or more simply the testers. +; +; Sound effects: +; -------------- +; Sound effects are disabled by default. Declare PLY_LW_MANAGE_SOUND_EFFECTS to enable it: +; PLY_LW_MANAGE_SOUND_EFFECTS = 1 +; Check the sound effect tester to see how it enables it. +; Note that the PRESENCE of this variable is tested, NOT its value. +; +; ROM +; ---------------------- +; No ROM player is available for this player. I suggest you try the AKM player, which is more powerful and more compact (albeit a bit slower). +; +; ------------------------------------------------------- + +PLY_LW_Start: + + ;Checks the hardware. Only one must be selected. +PLY_LW_HardwareCounter = 0 + IFDEF PLY_LW_HARDWARE_CPC + PLY_LW_HardwareCounter = PLY_LW_HardwareCounter + 1 + ENDIF + IFDEF PLY_LW_HARDWARE_MSX + PLY_LW_HardwareCounter = PLY_LW_HardwareCounter + 1 + PLY_LW_HARDWARE_SPECTRUM_OR_MSX = 1 + ENDIF + IFDEF PLY_LW_HARDWARE_SPECTRUM + PLY_LW_HardwareCounter = PLY_LW_HardwareCounter + 1 + PLY_LW_HARDWARE_SPECTRUM_OR_PENTAGON = 1 + PLY_LW_HARDWARE_SPECTRUM_OR_MSX = 1 + ENDIF + IFDEF PLY_LW_HARDWARE_PENTAGON + PLY_LW_HardwareCounter = PLY_LW_HardwareCounter + 1 + PLY_LW_HARDWARE_SPECTRUM_OR_PENTAGON = 1 + ENDIF + IF PLY_LW_HARDWARECounter > 1 + FAIL 'Only one hardware must be selected!' + ENDIF + ;By default, selects the Amstrad CPC. + IF PLY_LW_HARDWARECounter == 0 + PLY_LW_HARDWARE_CPC = 1 + ENDIF + +;PLY_LW_USE_HOOKS: equ 1 ;Use hooks for external calls? 0 if the Init/Play methods are directly called, will save a few bytes. +;PLY_LW_STOP_SOUNDS: equ 1 ;1 to have the "stop sounds" code. Set it to 0 if you never plan on stopping your music. + + ;Is there a loaded Player Configuration source? If no, use a default configuration. + IFNDEF PLY_CFG_ConfigurationIsPresent + PLY_CFG_UseTranspositions = 1 + PLY_CFG_UseSpeedTracks = 1 + PLY_CFG_UseEffects = 1 + PLY_CFG_UseHardwareSounds = 1 + PLY_CFG_NoSoftNoHard_Noise = 1 + PLY_CFG_SoftOnly_Noise = 1 + PLY_CFG_SoftOnly_SoftwareArpeggio = 1 + PLY_CFG_SoftOnly_SoftwarePitch = 1 + PLY_CFG_SoftToHard_SoftwarePitch = 1 + PLY_CFG_SoftToHard_SoftwareArpeggio = 1 + PLY_CFG_SoftAndHard_SoftwarePitch = 1 + PLY_CFG_SoftAndHard_SoftwareArpeggio = 1 + PLY_CFG_UseEffect_ArpeggioTable = 1 + PLY_CFG_UseEffect_PitchTable = 1 + PLY_CFG_UseEffect_PitchUp = 1 + PLY_CFG_UseEffect_PitchDown = 1 + PLY_CFG_UseEffect_SetVolume = 1 + PLY_CFG_UseEffect_Reset = 1 + ENDIF + + ;Agglomerates some flags, because they are treated the same way by this player. + ;-------------------------------------------------- + ;Creates a flag for pitch in instrument, and also pitch in hardware. + IFDEF PLY_CFG_SoftOnly_SoftwarePitch + PLY_LW_PitchInInstrument = 1 + ENDIF + IFDEF PLY_CFG_SoftToHard_SoftwarePitch + PLY_LW_PitchInInstrument = 1 + PLY_LW_PitchInHardwareInstrument = 1 + ENDIF + IFDEF PLY_CFG_SoftAndHard_SoftwarePitch + PLY_LW_PitchInInstrument = 1 + PLY_LW_PitchInHardwareInstrument = 1 + ENDIF + ;A flag for Arpeggios in Instrument, both in software and hardware. + IFDEF PLY_CFG_SoftOnly_SoftwareArpeggio + PLY_LW_ArpeggioInSoftwareOrHardwareInstrument = 1 + ENDIF + IFDEF PLY_CFG_SoftToHard_SoftwareArpeggio + PLY_LW_ArpeggioInSoftwareOrHardwareInstrument = 1 + PLY_LW_ArpeggioInHardwareInstrument = 1 + ENDIF + IFDEF PLY_CFG_SoftAndHard_SoftwareArpeggio + PLY_LW_ArpeggioInSoftwareOrHardwareInstrument = 1 + PLY_LW_ArpeggioInHardwareInstrument = 1 + ENDIF + + ;A flag if noise is used (noise in hardware not tested, not present in this format). + IFDEF PLY_CFG_NoSoftNoHard_Noise + PLY_LW_USE_Noise = 1 + ENDIF + IFDEF PLY_CFG_SoftOnly_Noise + PLY_LW_USE_Noise = 1 + ENDIF + ;The noise is managed? Then the noise register access must be compiled. + IFDEF PLY_LW_USE_Noise + PLY_LW_USE_NoiseRegister = 1 + ENDIF + + ;Mixing Pitch up/down effects. + IFDEF PLY_CFG_UseEffect_PitchUp + PLY_LW_USE_EffectPitchUpDown = 1 + ENDIF + IFDEF PLY_CFG_UseEffect_PitchDown + PLY_LW_USE_EffectPitchUpDown = 1 + ENDIF + ;Volume and Pitch up/down dual effects (if one exists, the other one too). + IFDEF PLY_CFG_UseEffect_SetVolume + PLY_LW_USE_Volume_And_PitchUpDown_Effects = 1 + PLY_LW_USE_EffectPitchUpDown = 1 + ENDIF + IFDEF PLY_LW_USE_EffectPitchUpDown + PLY_LW_USE_Volume_And_PitchUpDown_Effects = 1 + PLY_CFG_UseEffect_SetVolume = 1 + ENDIF + ;Volume and Arpeggio Table dual effect (if one exists, the other one too). + IFDEF PLY_CFG_UseEffect_SetVolume + PLY_LW_USE_Volume_And_ArpeggioTable_Effects = 1 + PLY_CFG_UseEffect_ArpeggioTable = 1 + ENDIF + IFDEF PLY_CFG_UseEffect_ArpeggioTable + PLY_LW_USE_Volume_And_ArpeggioTable_Effects = 1 + PLY_CFG_UseEffect_SetVolume = 1 + ENDIF + ;Reset and Arpeggio Table dual effect (if one exists, the other one too). + IFDEF PLY_CFG_UseEffect_Reset + PLY_LW_USE_Reset_And_ArpeggioTable_Effects = 1 + PLY_CFG_UseEffect_ArpeggioTable = 1 + ENDIF + IFDEF PLY_CFG_UseEffect_ArpeggioTable + PLY_LW_USE_Reset_And_ArpeggioTable_Effects = 1 + PLY_CFG_UseEffect_Reset = 1 + ENDIF + + + ;Disark macro: Word region Start. + disarkCounter = 0 + IFNDEF dkws + MACRO dkws +PLY_LW_DisarkWordRegionStart_{disarkCounter} + ENDM + ENDIF + ;Disark macro: Word region End. + IFNDEF dkwe + MACRO dkwe +PLY_LW_DisarkWordRegionEnd_{disarkCounter}: + disarkCounter = disarkCounter + 1 + ENDM + ENDIF + + ;Disark macro: Pointer region Start. + disarkCounter = 0 + IFNDEF dkps + MACRO dkps +PLY_LW_DisarkPointerRegionStart_{disarkCounter} + ENDM + ENDIF + ;Disark macro: Pointer region End. + IFNDEF dkpe + MACRO dkpe +PLY_LW_DisarkPointerRegionEnd_{disarkCounter}: + disarkCounter = disarkCounter + 1 + ENDM + ENDIF + + ;Disark macro: Byte region Start. + disarkCounter = 0 + IFNDEF dkbs + MACRO dkbs +PLY_LW_DisarkByteRegionStart_{disarkCounter} + ENDM + ENDIF + ;Disark macro: Byte region End. + IFNDEF dkbe + MACRO dkbe +PLY_LW_DisarkByteRegionEnd_{disarkCounter}: + disarkCounter = disarkCounter + 1 + ENDM + ENDIF + + ;Disark macro: Force "No Reference Area" for 3 bytes (ld hl,xxxx). + IFNDEF dknr3 + MACRO dknr3 +PLY_LW_DisarkForceNonReferenceDuring3_{disarkCounter}: + disarkCounter = disarkCounter + 1 + ENDM + ENDIF + + + + ;Hooks for external calls. Can be removed if not needed. + if PLY_LW_USE_HOOKS + assert PLY_LW_Start == $ ;Makes sure no extra byte were inserted before the hooks. + jp PLY_LW_Init ;Player + 0. + jp PLY_LW_Play ;Player + 3. + if PLY_LW_STOP_SOUNDS + jp PLY_LW_Stop ;Player + 6. + endif + endif + + ;Includes the sound effects player, if wanted. Important to do it as soon as possible, so that + ;its code can react to the Player Configuration and possibly alter it. + IFDEF PLY_LW_MANAGE_SOUND_EFFECTS + include "PlayerLightWeight_SoundEffects.asm" + ENDIF + ;[[INSERT_SOUND_EFFECT_SOURCE]] ;A tag for test units. Don't touch or you're dead. + + +;Initializes the song. MUST be called before actually playing the song. +;IN: HL = Address of the song. +; A = Index of the subsong to play (>=0). +PLY_LW_InitDisarkGenerateExternalLabel: +PLY_LW_Init: + ;Reads the Song data. + ;Skips the tag and format number. +dknr3: ld de,5 + add hl,de + + ;Reads the pointers to the various index tables. + ld de,PLY_LW_PtInstruments + 1 + ldi + ldi + IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC + IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC + ld de,PLY_LW_PtArpeggios + 1 + ldi + ldi + ELSE + inc hl + inc hl + ENDIF ;PLY_CFG_UseEffect_ArpeggioTable + IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC + ld de,PLY_LW_PtPitches + 1 + ldi + ldi + ELSE + inc hl + inc hl + ENDIF ;PLY_CFG_UseEffect_PitchTable + ELSE +dknr3: ld de,4 + add hl,de + ENDIF ;PLY_CFG_UseEffects + + ;Finds the address of the Subsong. + ;HL points on the table, adds A * 2. + ;Possible optimization: possible to set the Subsong directly. + ld e,a + ld d,0 + add hl,de + add hl,de + ld e,(hl) + inc hl + ld d,(hl) + + ;Reads the header of the Subsong. + ld a,(de) ;Gets the speed. + inc de + ld (PLY_LW_Linker + 1),de + ld (PLY_LW_Speed + 1),a + ;Forces a new line. + dec a + ld (PLY_LW_TickCounter + 1),a + + ;Can be removed if there is no need to reset the song. + xor a + ld (PLY_LW_PatternRemainingHeight + 1),a + + ;A big LDIR to erase all the data blocks. Optimization: can be removed if there is no need to reset the song. + ld hl,PLY_LW_Track1_Data + ld de,PLY_LW_Track1_Data + 1 +dknr3: ld bc,PLY_LW_Track3_Data_End - PLY_LW_Track3_Data - 1 + ld (hl),0 + ldir + + ;Reads the first instrument, the empty one, and set-ups the pointers to the instrument to read. + ;Optimization: needed if the song doesn't start with an instrument on all the channels. Else, it can be removed. + ld hl,(PLY_LW_PtInstruments + 1) + ld e,(hl) + inc hl + ld d,(hl) + inc de ;Skips the header. + ld (PLY_LW_Track1_PtInstrument),de + ld (PLY_LW_Track2_PtInstrument),de + ld (PLY_LW_Track3_PtInstrument),de + ret + + +;Cuts the channels, stopping all sounds. + if PLY_LW_STOP_SOUNDS +PLY_LW_StopDisarkGenerateExternalLabel: +PLY_LW_Stop: + ld (PLY_LW_SaveSP + 1),sp + + xor a + ld (PLY_LW_Track1_Volume),a + ld (PLY_LW_Track2_Volume),a + ld (PLY_LW_Track3_Volume),a + IFDEF PLY_LW_HARDWARE_MSX + ld a,%10111111 ;Bit 7/6 must be 10 on MSX! + ELSE + ld a,%00111111 ;On CPC, bit 6 must be 0! Other platforms don't care. + ENDIF + ld (PLY_LW_MixerRegister),a + jp PLY_LW_SendPsg + endif ;PLY_LW_STOP_SOUNDS + +;Plays one frame of the song. It MUST have been initialized before. +;The stack is saved and restored, but is diverted, so watch out for the interruptions. +PLY_LW_PlayDisarkGenerateExternalLabel: +PLY_LW_Play: + ld (PLY_LW_SaveSP + 1),sp + + ;Reads a new line? +PLY_LW_TickCounter: ld a,0 + inc a +PLY_LW_Speed: cp 1 ;Speed (>0). + jp nz,PLY_LW_TickCounterManaged + + ;A new line must be read. But have we reached the end of the Pattern? +PLY_LW_PatternRemainingHeight: ld a,0 ;Height. If 0, end of the pattern. + sub 1 + jr c,PLY_LW_Linker + ;Pattern not ended. No need to read the Linker. + ld (PLY_LW_PatternRemainingHeight + 1),a + jr PLY_LW_ReadLine + + ;New pattern. Reads the Linker. +dknr3: +PLY_LW_Linker: ld hl,0 +PLY_LW_LinkerPostPt: + ;Resets the possible empty cell counter of each Track. + xor a + ld (PLY_LW_Track1_WaitEmptyCell),a + ld (PLY_LW_Track2_WaitEmptyCell),a + ld (PLY_LW_Track3_WaitEmptyCell),a + + ;Reads the state byte of the pattern. + ld a,(hl) + inc hl + rra + jr c,PLY_LW_LinkerNotEndOfSongOk + ;End of song. + ld a,(hl) ;Reads where to loop in the Linker. + inc hl + ld h,(hl) + ld l,a + jr PLY_LW_LinkerPostPt + +PLY_LW_LinkerNotEndOfSongOk: + rra + ld b,a + IFDEF PLY_CFG_UseSpeedTracks ;CONFIG SPECIFIC + ;New speed? + jr nc,PLY_LW_LinkerAfterSpeed + ld a,(hl) + inc hl + ld (PLY_LW_Speed + 1),a +PLY_LW_LinkerAfterSpeed: + ENDIF ;PLY_CFG_UseSpeedTracks + + ;New height? + rr b + jr nc,PLY_LW_LinkerUsePreviousHeight + ld a,(hl) + inc hl + ld (PLY_LW_LinkerPreviousRemainingHeight + 1),a + jr PLY_LW_LinkerSetRemainingHeight + ;The same height is used. It was stored before. +PLY_LW_LinkerUsePreviousHeight: +PLY_LW_LinkerPreviousRemainingHeight: ld a,0 +PLY_LW_LinkerSetRemainingHeight: + ld (PLY_LW_PatternRemainingHeight + 1),a + + ;New transpositions? + rr b + IFDEF PLY_CFG_UseTranspositions ;CONFIG SPECIFIC + jr nc,PLY_LW_LinkerAfterNewTranspositions + ;New transpositions. + ld de,PLY_LW_Track1_Transposition + ldi + ld de,PLY_LW_Track2_Transposition + ldi + ld de,PLY_LW_Track3_Transposition + ldi +PLY_LW_LinkerAfterNewTranspositions: + ENDIF ;PLY_CFG_UseTranspositions + + ;Reads the 3 track pointers. + ld de,PLY_LW_Track1_PtTrack + ldi + ldi + ld de,PLY_LW_Track2_PtTrack + ldi + ldi + ld de,PLY_LW_Track3_PtTrack + ldi + ldi + ld (PLY_LW_Linker + 1),hl + +;Reads the Tracks. +;--------------------------------- +PLY_LW_ReadLine: +dknr3: +PLY_LW_PtInstruments: ld de,0 + exx + ld ix,PLY_LW_Track1_Data + call PLY_LW_ReadTrack + ld ix,PLY_LW_Track2_Data + call PLY_LW_ReadTrack + ld ix,PLY_LW_Track3_Data + call PLY_LW_ReadTrack + + xor a +PLY_LW_TickCounterManaged: + ld (PLY_LW_TickCounter + 1),a + + + +;Plays the sound stream. +;--------------------------------- + ld de,PLY_LW_PeriodTable + exx + + ld c,%11100000 ;Register 7, shifted of 2 to the left. Bits 2 and 5 will be possibly changed by each iteration. + + ld ix,PLY_LW_Track1_Data + IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC + call PLY_LW_ManageEffects + ENDIF ;PLY_CFG_UseEffects + ld iy,PLY_LW_Track1_Registers + call PLY_LW_PlaySoundStream + + srl c ;Not RR, because we have to make sure the b6 is 0, else no more keyboard (on CPC)! + ;Also, on MSX? bit 6 must be 0. + ld ix,PLY_LW_Track2_Data + IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC + call PLY_LW_ManageEffects + ENDIF ;PLY_CFG_UseEffects + ld iy,PLY_LW_Track2_Registers + call PLY_LW_PlaySoundStream + + IFDEF PLY_LW_HARDWARE_MSX + scf ;On MSX, bit 7 must be 1. + rr c + ELSE + rr c ;On other platforms, we don't care about b7. + ENDIF + ld ix,PLY_LW_Track3_Data + IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC + call PLY_LW_ManageEffects + ENDIF ;PLY_CFG_UseEffects + ld iy,PLY_LW_Track3_Registers + call PLY_LW_PlaySoundStream + + ld a,c + +;Plays the sound effects, if desired. +;------------------------------------------- + IFDEF PLY_LW_MANAGE_SOUND_EFFECTS + call PLY_LW_PlaySoundEffectsStream + ELSE + ld (PLY_LW_MixerRegister),a + ENDIF ;PLY_LW_MANAGE_SOUND_EFFECTS + + + +;Sends the values to the PSG. +;--------------------------------- +PLY_LW_SendPsg: + ld sp,PLY_LW_Registers_RetTable + + IFDEF PLY_LW_HARDWARE_CPC +dknr3: ld bc,#f680 + ld a,#c0 +dknr3: ld de,#f4f6 + out (c),a ;#f6c0 ;Madram's trick requires to start with this. out (c),b works, but will activate K7's relay! Not clean. + ENDIF + + IFDEF PLY_LW_HARDWARE_SPECTRUM_OR_PENTAGON +dknr3: ld de,#bfff +dknr3: ld bc,#fffd + ENDIF + +PLY_LW_SendPsgRegister: + pop hl ;H = value, L = register. +PLY_LW_SendPsgRegisterAfterPop: + + IFDEF PLY_LW_HARDWARE_CPC + ld b,d + out (c),l ;#f400 + register. + ld b,e + out (c),0 ;#f600 + ld b,d + out (c),h ;#f400 + value. + ld b,e + out (c),c ;#f680 + out (c),a ;#f6c0 + ENDIF + + IFDEF PLY_LW_HARDWARE_SPECTRUM_OR_PENTAGON + out (c),l ;#fffd + register. + ld b,d + out (c),h ;#bffd + value + ld b,e + ENDIF + + IFDEF PLY_LW_HARDWARE_MSX + ld a,l ;Register. + out (#a0),a + ld a,h ;Value. + out (#a1),a + ENDIF + + ret + + IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC +PLY_LW_SendPsgRegisterR13: + + ;Should the R13 be played? Yes only if different. No "force retrig" is managed by this player. +PLY_LW_SetReg13: ld a,0 +PLY_LW_SetReg13Old: cp 0 + jr z,PLY_LW_SendPsgRegisterEnd + ;Different. R13 must be played. Updates the old R13 value. + ld (PLY_LW_SetReg13Old + 1),a + + ld h,a + ld l,13 + IFDEF PLY_LW_HARDWARE_CPC + ld a,#c0 + ENDIF + ret ;Sends the 13th registers. + ENDIF ;PLY_CFG_UseHardwareSounds + +PLY_LW_SendPsgRegisterEnd: + +dknr3: +PLY_LW_SaveSP: ld sp,0 + ret + + + + + + + + + + +;Reads a Track. +;IN: IX = Data block of the Track. +; DE'= Instrument table. Do not modify! +PLY_LW_ReadTrack: + ;Are there any empty lines to wait? + ld a,(ix + PLY_LW_Data_OffsetWaitEmptyCell) + sub 1 + jr c,PLY_LW_RT_NoEmptyCell + ;Wait! + ld (ix + PLY_LW_Data_OffsetWaitEmptyCell),a + ret + +PLY_LW_RT_NoEmptyCell: + ;Reads the Track pointer. + ld l,(ix + PLY_LW_Data_OffsetPtTrack + 0) + ld h,(ix + PLY_LW_Data_OffsetPtTrack + 1) + ld a,(hl) + inc hl + ld b,a + and %111111 ;Keeps only the note. + sub 60 + jr c,PLY_LW_RT_NoteMaybeEffect + IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC + jr z,PLY_LW_RT_ReadEffect ;No note, but effect. + ENDIF ;PLY_CFG_UseEffects + dec a + jr z,PLY_LW_RT_WaitLong + dec a + jr z,PLY_LW_RT_WaitShort + ;63: Escape code for a note, because octave <2 or >5. + ;Reads the note. + ld a,(hl) + inc hl + ;The rest is exactly as the "note maybe effect", as B contains the flag to know about the possible + ;New Instrument and/or Effect?. + jr PLY_LW_RT_NMB_AfterOctaveCompensation + +PLY_LW_RT_NoteMaybeEffect: + ;A is the note from octave 2, and 60 to compensate the sub above. + ;Then adds the transposition. + add a,12 * 2 + 60 +PLY_LW_RT_NMB_AfterOctaveCompensation: + IFDEF PLY_CFG_UseTranspositions ;CONFIG SPECIFIC + add a,(ix + PLY_LW_Data_OffsetTransposition) + ENDIF ;PLY_CFG_UseTranspositions + ld (ix + PLY_LW_Data_OffsetBaseNote),a + + ;New Instrument? + rl b + jr c,PLY_LW_RT_NME_NewInstrument + ;Same Instrument. Retrieves the address previously stored. + ld a,(ix + PLY_LW_Data_OffsetPtBaseInstrument + 0) + ld (ix + PLY_LW_Data_OffsetPtInstrument + 0),a + ld a,(ix + PLY_LW_Data_OffsetPtBaseInstrument + 1) + ld (ix + PLY_LW_Data_OffsetPtInstrument + 1),a + jr PLY_LW_RT_NME_AfterInstrument + +PLY_LW_RT_NME_NewInstrument: + ;New Instrument, reads it. + ld a,(hl) + inc hl + exx + ;Gets the address of the Instrument. + ld l,a ;No need to *2, it is already encoded like that. + ld h,0 + add hl,de ;Adds to the Instrument Table. + ld c,(hl) + inc hl + ld b,(hl) + ;Reads the header of the Instrument. + ld a,(bc) ;Speed. + ld (ix + PLY_LW_Data_OffsetInstrumentSpeed),a + inc bc + ;Stores the pointer on the data of the Instrument. + ld (ix + PLY_LW_Data_OffsetPtInstrument + 0),c + ld (ix + PLY_LW_Data_OffsetPtInstrument + 1),b + ld (ix + PLY_LW_Data_OffsetPtBaseInstrument + 0),c ;Useful to store the base Instrument address to retrieve it when + ld (ix + PLY_LW_Data_OffsetPtBaseInstrument + 1),b ;there is a new instrument, without providing its number (optimization). + exx +PLY_LW_RT_NME_AfterInstrument: + ;Resets the step on the Instrument. + ld (ix + PLY_LW_Data_OffsetInstrumentCurrentStep),0 + + ;Resets the Track pitch. + IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC + xor a + IFDEF PLY_LW_USE_EffectPitchUpDown ;CONFIG SPECIFIC + ld (ix + PLY_LW_Data_OffsetIsPitchUpDownUsed),a + ld (ix + PLY_LW_Data_OffsetTrackPitchInteger + 0),a + ld (ix + PLY_LW_Data_OffsetTrackPitchInteger + 1),a + ENDIF ;PLY_LW_USE_EffectPitchUpDown + ;ld (ix + PLY_LW_Data_OffsetTrackPitchDecimal),a ;Shouldn't be needed, the difference shouldn't be noticeable. + ;Resets the offset on Arpeggio and Pitch tables. + IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC + ld (ix + PLY_LW_Data_OffsetPtArpeggioOffset),a + ENDIF ;PLY_CFG_UseEffect_ArpeggioTable + IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC + ld (ix + PLY_LW_Data_OffsetPtPitchOffset),a + ENDIF ;PLY_CFG_UseEffect_PitchTable + + ENDIF ;PLY_CFG_UseEffects + + ;Any effect? If no, stop. + rl b + jr nc,PLY_LW_RT_CellRead + ;Effect present. + ;jr PLY_LW_RT_ReadEffect + + IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC +PLY_LW_RT_ReadEffect: + ;Reads effect number and possible data. + ld a,(hl) + inc hl + ld b,a + exx + rra + rra + rra + rra + and %1110 + ld iy,PLY_LW_EffectTable + ld c,a + ld b,0 + add iy,bc + exx + jp (iy) + ENDIF ;PLY_CFG_UseEffects + +PLY_LW_RT_WaitLong: + ;A 8-bit byte is encoded just after. + ld a,(hl) + inc hl + ld (ix + PLY_LW_Data_OffsetWaitEmptyCell),a + jr PLY_LW_RT_CellRead +PLY_LW_RT_WaitShort: + ;Only a 2-bit value is encoded. + ld a,b + rla ;Transfers the bit 7/6 to 1/0. + rla + rla + and %11 + ;inc a + ld (ix + PLY_LW_Data_OffsetWaitEmptyCell),a + ;jr PLY_LW_RT_CellRead +;Jumped to after the Cell has been read. +;IN: HL = new value of the Track pointer. Must point after the read Cell. +PLY_LW_RT_CellRead: + ld (ix + PLY_LW_Data_OffsetPtTrack + 0),l + ld (ix + PLY_LW_Data_OffsetPtTrack + 1),h + ret + + +;Manages the effects, if any. For the activated effects, modifies the internal data for the Track which data block is given. +;IN: IX = data block of the Track. +;OUT: IX, IY = unmodified. +; C must NOT be modified! +; DE' must NOT be modified! + IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC +PLY_LW_ManageEffects: + IFDEF PLY_LW_USE_EffectPitchUpDown ;CONFIG SPECIFIC + ;Pitch up/down used? + ld a,(ix + PLY_LW_Data_OffsetIsPitchUpDownUsed) + or a + jr z,PLY_LW_ME_PitchUpDownFinished + + ;Adds the LSB of integer part and decimal part, using one 16 bits operation. + ld l,(ix + PLY_LW_Data_OffsetTrackPitchDecimal) + ld h,(ix + PLY_LW_Data_OffsetTrackPitchInteger + 0) + + ld e,(ix + PLY_LW_Data_OffsetTrackPitchSpeed + 0) + ld d,(ix + PLY_LW_Data_OffsetTrackPitchSpeed + 1) + + ld a,(ix + PLY_LW_Data_OffsetTrackPitchInteger + 1) + + ;Negative pitch? + bit 7,d + jr nz,PLY_LW_ME_PitchUpDown_NegativeSpeed + +PLY_LW_ME_PitchUpDown_PositiveSpeed: + ;Positive speed. Adds it to the LSB of the integer part, and decimal part. + add hl,de + + ;Carry? Transmits it to the MSB of the integer part. + adc 0 + jr PLY_LW_ME_PitchUpDown_Save +PLY_LW_ME_PitchUpDown_NegativeSpeed: + ;Negative speed. Resets the sign bit. The encoded pitch IS positive. + ;Subtracts it to the LSB of the integer part, and decimal part. + res 7,d + + or a + sbc hl,de + + ;Carry? Transmits it to the MSB of the integer part. + sbc 0 + +PLY_LW_ME_PitchUpDown_Save: + ld (ix + PLY_LW_Data_OffsetTrackPitchInteger + 1),a + + ld (ix + PLY_LW_Data_OffsetTrackPitchDecimal),l + ld (ix + PLY_LW_Data_OffsetTrackPitchInteger + 0),h + +PLY_LW_ME_PitchUpDownFinished: + ENDIF ;PLY_LW_USE_EffectPitchUpDown + + + ;Manages the Arpeggio Table effect, if any. + IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC + ld a,(ix + PLY_LW_Data_OffsetIsArpeggioTableUsed) + or a + jr z,PLY_LW_ME_ArpeggioTableFinished + ;Reads the Arpeggio Table. Adds the Arpeggio base address to an offset. + ld e,(ix + PLY_LW_Data_OffsetPtArpeggioTable + 0) + ld d,(ix + PLY_LW_Data_OffsetPtArpeggioTable + 1) + ld l,(ix + PLY_LW_Data_OffsetPtArpeggioOffset) +PLY_LW_ME_ArpeggioTableReadAgain: ld h,0 + add hl,de + ld a,(hl) + ;End of the Arpeggio? + sra a + jr nc,PLY_LW_ME_ArpeggioTableEndNotReached + ;End of the Arpeggio. The loop offset is now in A. + ld l,a ;And read the next value! + ld (ix + PLY_LW_Data_OffsetPtArpeggioOffset),a + jr PLY_LW_ME_ArpeggioTableReadAgain + +PLY_LW_ME_ArpeggioTableEndNotReached: + ;Not the end. A = arpeggio note. + ld (ix + PLY_LW_Data_OffsetCurrentArpeggioValue),a + ;Increases the offset for next time. + inc (ix + PLY_LW_Data_OffsetPtArpeggioOffset) +PLY_LW_ME_ArpeggioTableFinished: + ENDIF ;PLY_CFG_UseEffect_ArpeggioTable + + + ;Manages the Pitch Table effect, if any. + IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC + ld a,(ix + PLY_LW_Data_OffsetIsPitchTableUsed) + or a + ret z + ;Reads the Pitch Table. Adds the Pitch base address to an offset. + ld e,(ix + PLY_LW_Data_OffsetPtPitchTable + 0) + ld d,(ix + PLY_LW_Data_OffsetPtPitchTable + 1) + ld l,(ix + PLY_LW_Data_OffsetPtPitchOffset) +PLY_LW_ME_PitchTableReadAgain: ld h,0 + add hl,de + ld a,(hl) + ;End of the Pitch? + sra a + jr nc,PLY_LW_ME_PitchTableEndNotReached + ;End of the Pitch. The loop offset is now in A. + ld l,a ;And read the next value! + ld (ix + PLY_LW_Data_OffsetPtPitchOffset),a + jr PLY_LW_ME_PitchTableReadAgain + +PLY_LW_ME_PitchTableEndNotReached: + ;Not the end. A = pitch note. It is converted to 16 bits. + ld h,0 + or a + jp p,PLY_LW_ME_PitchTableEndNotReached_Positive + dec h +PLY_LW_ME_PitchTableEndNotReached_Positive: + ld (ix + PLY_LW_Data_OffsetCurrentPitchTableValue + 0),a + ld (ix + PLY_LW_Data_OffsetCurrentPitchTableValue + 1),h + ;Increases the offset for next time. + inc (ix + PLY_LW_Data_OffsetPtPitchOffset) + ENDIF ;PLY_CFG_UseEffect_PitchTable + ret + + ENDIF ;PLY_CFG_UseEffects + + + + + + + +;--------------------------------------------------------------------- +;Sound stream. +;--------------------------------------------------------------------- + +;Plays the sound stream, filling the PSG registers table (but not playing it). +;The Instrument pointer must be updated as it evolves inside the Instrument. +;IN: IX = Data block of the Track. +; IY = Points at the beginning of the register structure related to the channel. +; C = R7. Only bit 2 (sound) must be *set* to cut the sound if needed, and bit 5 (noise) must be *reset* if there is noise. +; DE' = Period table. Must not be modified. +PLY_LW_PlaySoundStream: + ;Gets the pointer on the Instrument, from its base address and the offset. + ld l,(ix + PLY_LW_Data_OffsetPtInstrument + 0) + ld h,(ix + PLY_LW_Data_OffsetPtInstrument + 1) + + ;Reads the first byte of the cell of the Instrument. What type? +PLY_LW_PSS_ReadFirstByte: + ld a,(hl) + ld b,a + inc hl + rra + jr c,PLY_LW_PSS_SoftOrSoftAndHard + + ;NoSoftNoHard or SoftwareToHardware + rra + IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC + jr c,PLY_LW_PSS_SoftwareToHardware + ENDIF ;PLY_CFG_UseHardwareSounds + + ;No software no hardware, or end of sound (loop)! + ;End of sound? + rra + jr nc,PLY_LW_PSS_NSNH_NotEndOfSound + ;The sound loops/ends. Where? + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + ;As a sound always has at least one cell, we should safely be able to read its bytes without storing the instrument pointer. + ;However, we do it anyway to remove the overhead of the Speed management: if looping, the same last line will be read, + ;if several channels do so, it will be costly. So... + ld (ix + PLY_LW_Data_OffsetPtInstrument + 0),l + ld (ix + PLY_LW_Data_OffsetPtInstrument + 1),h + jr PLY_LW_PSS_ReadFirstByte + +PLY_LW_PSS_NSNH_NotEndOfSound: + ;No software, no hardware. + ;------------------------- + ;Stops the sound. + set 2,c + + ;Volume. A now contains the volume on b0-3. + call PLY_LW_PSS_Shared_AdjustVolume + ld (iy + PLY_LW_Registers_OffsetVolume),a + + ;Read noise? + rl b + IFDEF PLY_CFG_NoSoftNoHard_Noise ;CONFIG SPECIFIC + call c,PLY_LW_PSS_ReadNoise + ENDIF ;PLY_CFG_NoSoftNoHard_Noise + jr PLY_LW_PSS_Shared_StoreInstrumentPointer + + ;Software sound, or Software and Hardware? +PLY_LW_PSS_SoftOrSoftAndHard: + rra + IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC + jr c,PLY_LW_PSS_SoftAndHard + ENDIF ;PLY_CFG_UseHardwareSounds + + ;Software sound. + ;----------------- + ;A is the volume. Already shifted twice, so it can be used directly. + call PLY_LW_PSS_Shared_AdjustVolume + ld (iy + PLY_LW_Registers_OffsetVolume),a + + ;Arp and/or noise? + ld d,0 ;Default arpeggio. + rl b + jr nc,PLY_LW_PSS_S_AfterArpAndOrNoise + ld a,(hl) + inc hl + ;Noise? + sra a + ;A is now the signed Arpeggio. It must be kept. + ld d,a + ;Now takes care of the noise, if there is a Carry. + IFDEF PLY_LW_USE_Noise ;CONFIG SPECIFIC + call c,PLY_LW_PSS_ReadNoise + ENDIF ;PLY_LW_USE_Noise +PLY_LW_PSS_S_AfterArpAndOrNoise: + + ld a,d ;Gets the instrument arpeggio, if any. + call PLY_LW_CalculatePeriodForBaseNote + + ;Read pitch? + rl b + IFDEF PLY_CFG_SoftOnly_SoftwarePitch ;CONFIG SPECIFIC + call c,PLY_LW_ReadPitchAndAddToPeriod + ENDIF ;PLY_CFG_SoftOnly_SoftwarePitch + + ;Stores the new period of this channel. + exx + ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodLSB),l + ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodMSB),h + exx + + ;The code below is mutualized! + ;Stores the new instrument pointer, if Speed allows it. + ;-------------------------------------------------- +PLY_LW_PSS_Shared_StoreInstrumentPointer: + ;Checks the Instrument speed, and only stores the Instrument new pointer if the speed is reached. + ld a,(ix + PLY_LW_Data_OffsetInstrumentCurrentStep) + cp (ix + PLY_LW_Data_OffsetInstrumentSpeed) + jr z,PLY_LW_PSS_S_SpeedReached + ;Increases the current step. + inc (ix + PLY_LW_Data_OffsetInstrumentCurrentStep) + ret +PLY_LW_PSS_S_SpeedReached: + ;Stores the Instrument new pointer, resets the speed counter. + ld (ix + PLY_LW_Data_OffsetPtInstrument + 0),l + ld (ix + PLY_LW_Data_OffsetPtInstrument + 1),h + ld (ix + PLY_LW_Data_OffsetInstrumentCurrentStep),0 + ret + + + IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC + + ;Software and Hardware. + ;---------------------------- +PLY_LW_PSS_SoftAndHard: + ;Reads the envelope bit, the possible pitch, and sets the software period accordingly. + call PLY_LW_PSS_Shared_ReadEnvBitPitchArp_SoftPeriod_HardVol_HardEnv + ;Reads the hardware period. + ld a,(hl) + ld (PLY_LW_Reg11),a + inc hl + ld a,(hl) + ld (PLY_LW_Reg12),a + inc hl + + jr PLY_LW_PSS_Shared_StoreInstrumentPointer + + + ;Software to Hardware. + ;------------------------- +PLY_LW_PSS_SoftwareToHardware: + call PLY_LW_PSS_Shared_ReadEnvBitPitchArp_SoftPeriod_HardVol_HardEnv + + ;Now we can calculate the hardware period thanks to the ratio. + ld a,b + rra + rra + and %11100 + ld (PLY_LW_PSS_STH_Jump + 1),a + exx +PLY_LW_PSS_STH_Jump: jr $ + 2 ;Automodified by the line above to jump to the right place. + srl h + rr l + srl h + rr l + srl h + rr l + srl h + rr l + srl h + rr l + srl h + rr l + srl h + rr l + jr nc,PLY_LW_PSS_STH_RatioEnd + inc hl +PLY_LW_PSS_STH_RatioEnd: + ld a,l + ld (PLY_LW_Reg11),a + ld a,h + ld (PLY_LW_Reg12),a + exx + + jr PLY_LW_PSS_Shared_StoreInstrumentPointer + +;A shared code for hardware sound. +;Reads the envelope bit in bit 1, arpeggio in bit 7 pitch in bit 2 from A. If pitch present, adds it to BC'. +;Converts the note to period, adds the instrument pitch, sets the software period of the channel. +;Also sets the hardware volume, and sets the hardware curve. +PLY_LW_PSS_Shared_ReadEnvBitPitchArp_SoftPeriod_HardVol_HardEnv: + ;Envelope bit? R13 = 8 + 2 * (envelope bit?). Allows to have hardware envelope to 8 or 0xa. + ;Shifted by 2 to the right, bit 1 is now envelope bit, which is perfect for us. + and %10 + add a,8 + ld (PLY_LW_SetReg13 + 1),a + + ;Volume to 16 to trigger the hardware envelope. + ld (iy + PLY_LW_Registers_OffsetVolume),16 + + ;Arpeggio? + xor a ;Default arpeggio. + IFDEF PLY_LW_ArpeggioInHardwareInstrument ;CONFIG SPECIFIC + bit 7,b ;Not shifted yet. + jr z,PLY_LW_PSS_Shared_REnvBAP_AfterArpeggio + ;Reads the Arpeggio. + ld a,(hl) + inc hl +PLY_LW_PSS_Shared_REnvBAP_AfterArpeggio: + ENDIF ;PLY_LW_ArpeggioInHardwareInstrument + ;Calculates the software period. + call PLY_LW_CalculatePeriodForBaseNote + + ;Pitch? + IFDEF PLY_LW_PitchInHardwareInstrument ;CONFIG SPECIFIC + bit 2,b ;Not shifted yet. + call nz,PLY_LW_ReadPitchAndAddToPeriod + ENDIF ;PLY_LW_PitchInHardwareInstrument + + ;Stores the new period of this channel. + exx + ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodLSB),l + ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodMSB),h + exx + ret + + ENDIF ;PLY_CFG_UseHardwareSounds + +;Decreases the given volume (encoded in possibly more then 4 bits). If <0, forced to 0. +;IN: A = volume, not ANDed. +;OUT: A = new volume. +PLY_LW_PSS_Shared_AdjustVolume: + and %1111 + sub (ix + PLY_LW_Data_OffsetTrackInvertedVolume) + ret nc + xor a + ret + +;Reads and stores the noise pointed by HL, opens the noise channel. +;IN: HL = instrument data where the noise is. +;OUT: HL = HL++. +;MOD: A. + IFDEF PLY_LW_USE_Noise ;CONFIG SPECIFIC +PLY_LW_PSS_ReadNoise: + ld a,(hl) + inc hl + ld (PLY_LW_NoiseRegister),a + res 5,c ;Opens the noise channel. + ret + ENDIF ;PLY_LW_USE_Noise + +;Calculates the period according to the base note and put it in BC'. Used by both software and hardware codes. +;IN: DE' = period table. +; A = instrument arpeggio (0 if not used). +;OUT: HL' = period. +;MOD: A +PLY_LW_CalculatePeriodForBaseNote: + ;Gets the period from the current note. + exx + ld h,0 + add a,(ix + PLY_LW_Data_OffsetBaseNote) ;Adds the instrument Arp to the base note (including the transposition). + IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC + add (ix + PLY_LW_Data_OffsetCurrentArpeggioValue) ;Adds the Arpeggio Table effect. + ENDIF ;PLY_CFG_UseEffect_ArpeggioTable + ld l,a + sla l ;Note encoded on 7 bits, so should be fine. + add hl,de + ld a,(hl) + inc hl + ld h,(hl) + ld l,a ;HL' = period. + + ;Adds the Pitch Table value, if used. + IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC + ld a,(ix + PLY_LW_Data_OffsetIsPitchTableUsed) + or a + jr z,PLY_LW_CalculatePeriodForBaseNote_NoPitchTable + ld c,(ix + PLY_LW_Data_OffsetCurrentPitchTableValue + 0) + ld b,(ix + PLY_LW_Data_OffsetCurrentPitchTableValue + 1) + add hl,bc +PLY_LW_CalculatePeriodForBaseNote_NoPitchTable: + ENDIF ;PLY_CFG_UseEffect_PitchTable + ;Adds the Track Pitch. + IFDEF PLY_LW_USE_EffectPitchUpDown + ld c,(ix + PLY_LW_Data_OffsetTrackPitchInteger + 0) + ld b,(ix + PLY_LW_Data_OffsetTrackPitchInteger + 1) + add hl,bc + ENDIF ;PLY_LW_USE_EffectPitchUpDown + exx + ret + + IFDEF PLY_LW_PitchInInstrument ;CONFIG SPECIFIC +;Reads the pitch in the Instruments (16 bits) and adds it to HL', which should contain the software period. +;IN: HL = points on the pitch value. +;OUT: HL = points after the pitch. +;MOD: A, BC', HL' updated. +PLY_LW_ReadPitchAndAddToPeriod: + ;Reads 2 * 8 bits for the pitch. Slow... + ld a,(hl) + inc hl + exx + ld c,a ;Adds the read pitch to the note period. + exx + ld a,(hl) + inc hl + exx + ld b,a + add hl,bc + exx + ret + ENDIF ;PLY_LW_PitchInInstrument + + + + + + + + + + + + + +;--------------------------------------------------------------------- +;Effect management. +;--------------------------------------------------------------------- + + IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC + +;IN: HL = points after the first byte. +; B = data of the first byte on bits 0-4 (will probably needed to be ANDed, as bits 5-7 are undetermined). +; DE'= Instrument Table (not useful here). Do not modify! +; IX = data block of the Track. +;OUT: HL = points after the data of the effect (maybe nothing to do). +; Each effect must jump to PLY_LW_RT_CellRead. + +;Clears all the effects (volume, pitch table, arpeggio table). + IFDEF PLY_CFG_UseEffect_Reset ;CONFIG SPECIFIC. +PLY_LW_EffectReset: + ;Inverted volume. + call PLY_LW_ReadInvertedVolumeFromB + + xor a + ;The inverted volume is managed above, so don't change it. + IFDEF PLY_LW_USE_EffectPitchUpDown ;CONFIG SPECIFIC + ld (ix + PLY_LW_Data_OffsetIsPitchUpDownUsed),a + ENDIF ;PLY_LW_USE_EffectPitchUpDown + IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC + ld (ix + PLY_LW_Data_OffsetIsArpeggioTableUsed),a + ld (ix + PLY_LW_Data_OffsetCurrentArpeggioValue),a ;Contrary to the Pitch, the value must be reset. + ENDIF ;PLY_CFG_UseEffect_ArpeggioTable + IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC + ld (ix + PLY_LW_Data_OffsetIsPitchTableUsed),a + ENDIF ;PLY_CFG_UseEffect_PitchTable + jp PLY_LW_RT_CellRead + ENDIF ;PLY_CFG_UseEffect_Reset + +;Changes the volume. Possibly changes the Track pitch. + IFDEF PLY_LW_USE_Volume_And_PitchUpDown_Effects ;CONFIG SPECIFIC. +PLY_LW_EffectVolumeAndPitchUpDown: + ;Stores the new inverted volume. + call PLY_LW_ReadInvertedVolumeFromB + + ;Pitch? Warning, the code below is shared with the PitchUp/Down effect. + bit 4,b + jp z,PLY_LW_RT_CellRead + ;Pitch present. Reads and stores its 16 bits value (integer/decimal). +PLY_LW_EffectPitchUpDown_Activated: + ;Code shared with the effect above. + ;Activates the effect. + ld (ix + PLY_LW_Data_OffsetIsPitchUpDownUsed),255 + ld a,(hl) + inc hl + ld (ix + PLY_LW_Data_OffsetTrackPitchSpeed + 0),a + ld a,(hl) + inc hl + ld (ix + PLY_LW_Data_OffsetTrackPitchSpeed + 1),a + + jp PLY_LW_RT_CellRead + ENDIF ;PLY_LW_USE_Volume_And_PitchUpDown_Effects + + +;Effect table. Each entry jumps to an effect management code. +;Put after the code above so that the JR are within bound. +PLY_LW_EffectTable: + IFDEF PLY_LW_EffectReset ;CONFIG SPECIFIC + jr PLY_LW_EffectReset ;000 + ELSE + jr $ + ENDIF + + IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC + jr PLY_LW_EffectArpeggioTable ;001 + ELSE + jr $ + ENDIF + + IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC + jr PLY_LW_EffectPitchTable ;010 + ELSE + jr $ + ENDIF + + IFDEF PLY_LW_USE_EffectPitchUpDown ;CONFIG SPECIFIC + jr PLY_LW_EffectPitchUpDown ;011 + ELSE + jr $ + ENDIF + + IFDEF PLY_LW_USE_Volume_And_PitchUpDown_Effects ;CONFIG SPECIFIC + jr PLY_LW_EffectVolumeAndPitchUpDown ;100 + ELSE + jr $ + ENDIF + + IFDEF PLY_LW_USE_Volume_And_ArpeggioTable_Effects ;CONFIG SPECIFIC + jr PLY_LW_EffectVolumeArpeggioTable ;101 + ELSE + jr $ + ENDIF + + IFDEF PLY_LW_USE_Reset_And_ArpeggioTable_Effects ;CONFIG SPECIFIC + jr PLY_LW_EffectResetArpeggioTable ;110 + ELSE + jr $ + ENDIF + + ;111 Unused. + + + +;Pitch up/down effect, activation or stop. + IFDEF PLY_LW_USE_EffectPitchUpDown ;CONFIG SPECIFIC +PLY_LW_EffectPitchUpDown: + rr b ;Pitch present or pitch stop? + jr c,PLY_LW_EffectPitchUpDown_Activated + ;Pitch stop. + ld (ix + PLY_LW_Data_OffsetIsPitchUpDownUsed),0 + jp PLY_LW_RT_CellRead + ENDIF ;PLY_LW_USE_EffectPitchUpDown + +;Arpeggio table effect, activation or stop. + IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC +PLY_LW_EffectArpeggioTable: + ld a,b + and %11111 +PLY_LW_EffectArpeggioTable_AfterMask: + ld (ix + PLY_LW_Data_OffsetIsArpeggioTableUsed),a ;Sets to 0 if the Arpeggio is stopped, or any other value if it starts. + jr z,PLY_LW_EffectArpeggioTable_Stop + + ;Gets the Arpeggio address. + add a,a + exx + ld l,a + ld h,0 +dknr3: +PLY_LW_PtArpeggios: ld bc,0 + add hl,bc + ld a,(hl) + inc hl + ld (ix + PLY_LW_Data_OffsetPtArpeggioTable + 0),a + ld a,(hl) + ld (ix + PLY_LW_Data_OffsetPtArpeggioTable + 1),a + exx + + ;Resets the offset of the Arpeggio, to force a restart. + xor a + ld (ix + PLY_LW_Data_OffsetPtArpeggioOffset),a + jp PLY_LW_RT_CellRead +PLY_LW_EffectArpeggioTable_Stop: + ;Contrary to the Pitch, the Arpeggio must also be set to 0 when stopped. + ld (ix + PLY_LW_Data_OffsetCurrentArpeggioValue),a + jp PLY_LW_RT_CellRead + ENDIF ;PLY_CFG_UseEffect_ArpeggioTable + +;Pitch table effect, activation or stop. +;This is exactly the same code as for the Arpeggio, but I can't find a way to share it... + IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC +PLY_LW_EffectPitchTable: + ld a,b + and %11111 +PLY_LW_EffectPitchTable_AfterMask: + ld (ix + PLY_LW_Data_OffsetIsPitchTableUsed),a ;Sets to 0 if the Pitch is stopped, or any other value if it starts. + jp z,PLY_LW_RT_CellRead + + ;Gets the Pitch address. + add a,a + exx + ld l,a + ld h,0 +dknr3: +PLY_LW_PtPitches: ld bc,0 + add hl,bc + ld a,(hl) + inc hl + ld (ix + PLY_LW_Data_OffsetPtPitchTable + 0),a + ld a,(hl) + inc hl + ld (ix + PLY_LW_Data_OffsetPtPitchTable + 1),a + exx + + ;Resets the offset of the Pitch, to force a restart. + xor a + ld (ix + PLY_LW_Data_OffsetPtPitchOffset),a + + jp PLY_LW_RT_CellRead + ENDIF ;PLY_CFG_UseEffect_PitchTable + + + +;Volume, and Arpeggio Table, activation or stop. + IFDEF PLY_LW_USE_Volume_And_ArpeggioTable_Effects ;CONFIG SPECIFIC +PLY_LW_EffectVolumeArpeggioTable: + ;Stores the new inverted volume. + call PLY_LW_ReadInvertedVolumeFromB + + ;Manages the Arpeggio, encoded just after. + ld a,(hl) + inc hl + or a ;Required, else a volume of 0 will disturb the flag test after the jump! + jr PLY_LW_EffectArpeggioTable_AfterMask + ENDIF ;PLY_LW_USE_Volume_And_ArpeggioTable_Effects + +;Reset, and Arpeggio Table (activation only). + IFDEF PLY_LW_USE_Reset_And_ArpeggioTable_Effects ;CONFIG SPECIFIC +PLY_LW_EffectResetArpeggioTable: + ;Resets effects and read volume. + ;A bit of loss of CPU because we're going to set the Arpeggio just after, AND the effect pointer is stored! + ;Oh well, less memory taken this way. + call PLY_LW_EffectReset + + ;Reads the Arpeggio. + ld a,(hl) + inc hl + or a ;Required, else a volume of 0 will disturb the flag test after the jump! + jp PLY_LW_EffectArpeggioTable_AfterMask ;No need to use the mask, the value is clean. + ENDIF ;PLY_LW_USE_Reset_And_ArpeggioTable_Effects + + +;Reads the inverted volume from B, stored it after masking the bits in A. +PLY_LW_ReadInvertedVolumeFromB: + ld a,b + and %1111 + ld (ix + PLY_LW_Data_OffsetTrackInvertedVolume),a + ret + + ENDIF ;PLY_CFG_UseEffects + + + + + + + + +;--------------------------------------------------------------------- +;Data blocks for the three channels. Make sure NOTHING is added between, as the init clears everything! +;--------------------------------------------------------------------- + +;Data block for channel 1. +PLY_LW_Track1_Data: +dkbs: +PLY_LW_Track1_WaitEmptyCell: db 0 ;How many empty cells have to be waited. 0 = none. + IFDEF PLY_CFG_UseTranspositions ;CONFIG SPECIFIC +PLY_LW_Track1_Transposition: db 0 + ENDIF ;PLY_CFG_UseTranspositions +PLY_LW_Track1_BaseNote: db 0 ;Base note, such as the note played. The transposition IS included. +PLY_LW_Track1_InstrumentCurrentStep: db 0 ;The current step on the Instrument (>=0, till it reaches the Speed). +PLY_LW_Track1_InstrumentSpeed: db 0 ;The Instrument speed (>=0). +PLY_LW_Track1_TrackInvertedVolume: db 0 +dkbe: +dkws: +PLY_LW_Track1_PtTrack: dw 0 ;Points on the next Cell of the Track to read. Evolves. +PLY_LW_Track1_PtInstrument: dw 0 ;Points on the Instrument, evolves. +PLY_LW_Track1_PtBaseInstrument: dw 0 ;Points on the base of the Instrument, does not evolve. +dkwe: + IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC +dkbs: +PLY_LW_Track1_IsPitchUpDownUsed: db 0 ;>0 if a Pitch Up/Down is currently in use. +PLY_LW_Track1_TrackPitchDecimal: db 0 ;The decimal part of the Track pitch. Evolves as the pitch goes up/down. +dkbe: +dkws: +PLY_LW_Track1_TrackPitchSpeed: dw 0 ;The integer and decimal part of the Track pitch speed. Is added to the Track Pitch every frame. +PLY_LW_Track1_TrackPitchInteger: dw 0 ;The integer part of the Track pitch. Evolves as the pitch goes up/down. +dkwe: +dkbs: +PLY_LW_Track1_IsArpeggioTableUsed: db 0 ;>0 if an Arpeggio Table is currently in use. +PLY_LW_Track1_PtArpeggioOffset: db 0 ;Increases over the Arpeggio. +PLY_LW_Track1_CurrentArpeggioValue: db 0 ;Value from the Arpeggio to add to the base note. Read even if the Arpeggio effect is deactivated. +dkbe: +dkws: +PLY_LW_Track1_PtArpeggioTable: dw 0 ;Point on the base of the Arpeggio table, does not evolve. +dkwe: +dkbs: +PLY_LW_Track1_IsPitchTableUsed: db 0 ;>0 if a Pitch Table is currently in use. +PLY_LW_Track1_PtPitchOffset: db 0 ;Increases over the Pitch. +dkbe: +dkws: +PLY_LW_Track1_CurrentPitchTableValue: dw 0 ;16 bit value from the Pitch to add to the base note. Not read if the Pitch effect is deactivated. +PLY_LW_Track1_PtPitchTable: dw 0 ;Points on the base of the Pitch table, does not evolve. +dkwe: + ENDIF ;PLY_CFG_UseEffects +PLY_LW_Track1_Data_End: + +PLY_LW_Track1_Data_Size: equ PLY_LW_Track1_Data_End - PLY_LW_Track1_Data + +PLY_LW_Data_OffsetWaitEmptyCell: equ PLY_LW_Track1_WaitEmptyCell - PLY_LW_Track1_Data + IFDEF PLY_CFG_UseTranspositions ;CONFIG SPECIFIC +PLY_LW_Data_OffsetTransposition: equ PLY_LW_Track1_Transposition - PLY_LW_Track1_Data + ENDIF ;PLY_CFG_UseTranspositions + +PLY_LW_Data_OffsetPtTrack: equ PLY_LW_Track1_PtTrack - PLY_LW_Track1_Data +PLY_LW_Data_OffsetBaseNote: equ PLY_LW_Track1_BaseNote - PLY_LW_Track1_Data +PLY_LW_Data_OffsetPtInstrument: equ PLY_LW_Track1_PtInstrument - PLY_LW_Track1_Data +PLY_LW_Data_OffsetPtBaseInstrument: equ PLY_LW_Track1_PtBaseInstrument - PLY_LW_Track1_Data +PLY_LW_Data_OffsetInstrumentCurrentStep: equ PLY_LW_Track1_InstrumentCurrentStep - PLY_LW_Track1_Data +PLY_LW_Data_OffsetInstrumentSpeed: equ PLY_LW_Track1_InstrumentSpeed - PLY_LW_Track1_Data +PLY_LW_Data_OffsetTrackInvertedVolume: equ PLY_LW_Track1_TrackInvertedVolume - PLY_LW_Track1_Data + IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC + IFDEF PLY_LW_USE_EffectPitchUpDown ;CONFIG SPECIFIC +PLY_LW_Data_OffsetIsPitchUpDownUsed: equ PLY_LW_Track1_IsPitchUpDownUsed - PLY_LW_Track1_Data +PLY_LW_Data_OffsetTrackPitchInteger: equ PLY_LW_Track1_TrackPitchInteger - PLY_LW_Track1_Data +PLY_LW_Data_OffsetTrackPitchDecimal: equ PLY_LW_Track1_TrackPitchDecimal - PLY_LW_Track1_Data +PLY_LW_Data_OffsetTrackPitchSpeed: equ PLY_LW_Track1_TrackPitchSpeed - PLY_LW_Track1_Data + ENDIF ;PLY_LW_USE_EffectPitchUpDown + IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC +PLY_LW_Data_OffsetIsArpeggioTableUsed: equ PLY_LW_Track1_IsArpeggioTableUsed - PLY_LW_Track1_Data +PLY_LW_Data_OffsetPtArpeggioTable: equ PLY_LW_Track1_PtArpeggioTable - PLY_LW_Track1_Data +PLY_LW_Data_OffsetPtArpeggioOffset: equ PLY_LW_Track1_PtArpeggioOffset - PLY_LW_Track1_Data +PLY_LW_Data_OffsetCurrentArpeggioValue: equ PLY_LW_Track1_CurrentArpeggioValue - PLY_LW_Track1_Data + ENDIF ;PLY_CFG_UseEffect_ArpeggioTable + IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC +PLY_LW_Data_OffsetIsPitchTableUsed: equ PLY_LW_Track1_IsPitchTableUsed - PLY_LW_Track1_Data +PLY_LW_Data_OffsetPtPitchTable: equ PLY_LW_Track1_PtPitchTable - PLY_LW_Track1_Data +PLY_LW_Data_OffsetCurrentPitchTableValue: equ PLY_LW_Track1_CurrentPitchTableValue - PLY_LW_Track1_Data +PLY_LW_Data_OffsetPtPitchOffset: equ PLY_LW_Track1_PtPitchOffset - PLY_LW_Track1_Data + ENDIF ;PLY_CFG_UseEffect_PitchTable + ENDIF ;PLY_CFG_UseEffects + +;Data block for channel 2. +PLY_LW_Track2_Data: +dkbs: + ds PLY_LW_Track1_Data_Size, 0 +dkbe: +PLY_LW_Track2_Data_End: +PLY_LW_Track2_WaitEmptyCell: equ PLY_LW_Track2_Data + PLY_LW_Data_OffsetWaitEmptyCell + IFDEF PLY_CFG_UseTranspositions ;CONFIG SPECIFIC +PLY_LW_Track2_Transposition: equ PLY_LW_Track2_Data + PLY_LW_Data_OffsetTransposition + ENDIF ;PLY_CFG_UseTranspositions + +PLY_LW_Track2_PtTrack: equ PLY_LW_Track2_Data + PLY_LW_Data_OffsetPtTrack +PLY_LW_Track2_PtInstrument: equ PLY_LW_Track2_Data + PLY_LW_Data_OffsetPtInstrument + +;Data block for channel 3. +PLY_LW_Track3_Data: +dkbs: + ds PLY_LW_Track1_Data_Size, 0 +dkbe: +PLY_LW_Track3_Data_End: +PLY_LW_Track3_WaitEmptyCell: equ PLY_LW_Track3_Data + PLY_LW_Data_OffsetWaitEmptyCell + IFDEF PLY_CFG_UseTranspositions ;CONFIG SPECIFIC +PLY_LW_Track3_Transposition: equ PLY_LW_Track3_Data + PLY_LW_Data_OffsetTransposition + ENDIF ;PLY_CFG_UseTranspositions +PLY_LW_Track3_PtTrack: equ PLY_LW_Track3_Data + PLY_LW_Data_OffsetPtTrack +PLY_LW_Track3_PtInstrument: equ PLY_LW_Track3_Data + PLY_LW_Data_OffsetPtInstrument + + ;Makes sure the structure all have the same size! + ASSERT (PLY_LW_Track1_Data_End - PLY_LW_Track1_Data) == (PLY_LW_Track2_Data_End - PLY_LW_Track2_Data) + ASSERT (PLY_LW_Track1_Data_End - PLY_LW_Track1_Data) == (PLY_LW_Track3_Data_End - PLY_LW_Track3_Data) + ;No holes between the blocks, the init makes a LDIR to clear everything! + ASSERT PLY_LW_Track1_Data_End == PLY_LW_Track2_Data + ASSERT PLY_LW_Track2_Data_End == PLY_LW_Track3_Data + + + +;--------------------------------------------------------------------- +;Register block for all the channels. They are "polluted" with pointers to code because all this +;is actually a RET table! +;--------------------------------------------------------------------- +;DB register, DB value then DW code to jump to once the value is read. +PLY_LW_Registers_RetTable: +PLY_LW_Track1_Registers: +dkbs: db 8 +PLY_LW_Track1_Volume: db 0 +dkbe: +dkps: dw PLY_LW_SendPsgRegister +dkpe: + +dkbs: db 0 +PLY_LW_Track1_SoftwarePeriodLSB: db 0 +dkbe: +dkps: dw PLY_LW_SendPsgRegister +dkpe: + +dkbs: db 1 +PLY_LW_Track1_SoftwarePeriodMSB: db 0 +dkbe: +dkps: dw PLY_LW_SendPsgRegister +dkpe: + +PLY_LW_Track2_Registers: +dkbs: db 9 +PLY_LW_Track2_Volume: db 0 +dkbe: +dkps: dw PLY_LW_SendPsgRegister +dkpe: + +dkbs: db 2 +PLY_LW_Track2_SoftwarePeriodLSB: db 0 +dkbe: +dkps: dw PLY_LW_SendPsgRegister +dkpe: + +dkbs: db 3 +PLY_LW_Track2_SoftwarePeriodMSB: db 0 +dkbe: +dkps: dw PLY_LW_SendPsgRegister +dkpe: + + +PLY_LW_Track3_Registers: +dkbs: db 10 +PLY_LW_Track3_Volume: db 0 +dkbe: +dkps: dw PLY_LW_SendPsgRegister +dkpe: + +dkbs: db 4 +PLY_LW_Track3_SoftwarePeriodLSB: db 0 +dkbe: +dkps: dw PLY_LW_SendPsgRegister +dkpe: + +dkbs: db 5 +PLY_LW_Track3_SoftwarePeriodMSB: db 0 +dkbe: +dkps: dw PLY_LW_SendPsgRegister +dkpe: + +;Generic registers. + IFDEF PLY_LW_USE_NoiseRegister ;CONFIG SPECIFIC +dkbs: db 6 +PLY_LW_NoiseRegister: db 0 +dkbe: +dkps: dw PLY_LW_SendPsgRegister +dkpe: + ENDIF ;PLY_LW_USE_NoiseRegister + +dkbs: db 7 +PLY_LW_MixerRegister: db 0 +dkbe: + IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC +dkps: dw PLY_LW_SendPsgRegister +dkpe: + + +dkbs: db 11 +PLY_LW_Reg11: db 0 +dkbe: +dkps: dw PLY_LW_SendPsgRegister +dkpe: + +dkbs: db 12 +PLY_LW_Reg12: db 0 +dkbe: +dkps: + dw PLY_LW_SendPsgRegisterR13 + ;This one is a trick to send the register after R13 is managed. + dw PLY_LW_SendPsgRegisterAfterPop + + dw PLY_LW_SendPsgRegisterEnd +dkpe: + ELSE +dkps: + dw PLY_LW_SendPsgRegisterEnd +dkpe: + ENDIF ;PLY_CFG_UseHardwareSounds + + + +PLY_LW_Registers_OffsetVolume: equ PLY_LW_Track1_Volume - PLY_LW_Track1_Registers +PLY_LW_Registers_OffsetSoftwarePeriodLSB: equ PLY_LW_Track1_SoftwarePeriodLSB - PLY_LW_Track1_Registers +PLY_LW_Registers_OffsetSoftwarePeriodMSB: equ PLY_LW_Track1_SoftwarePeriodMSB - PLY_LW_Track1_Registers + +;The period table for each note (from 0 to 127 included). +PLY_LW_PeriodTable: +dkws + IFDEF PLY_LW_HARDWARE_CPC + ;PSG running to 1000000 Hz. + dw 3822,3608,3405,3214,3034,2863,2703,2551,2408,2273,2145,2025 ;0 + dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012 ;12 + dw 956,902,851,804,758,716,676,638,602,568,536,506 ;24 + dw 478,451,426,402,379,358,338,319,301,284,268,253 ;36 + dw 239,225,213,201,190,179,169,159,150,142,134,127 ;48 + dw 119,113,106,100,95,89,84,80,75,71,67,63 ;60 + dw 60,56,53,50,47,45,42,40,38,36,34,32 ;72 + dw 30,28,27,25,24,22,21,20,19,18,17,16 ;84 + dw 15,14,13,13,12,11,11,10,9,9,8,8 ;96 + dw 7,7,7,6,6,6,5,5,5,4,4,4 ;108 + dw 4,4,3,3,3,3,3,2 ;,2,2,2,2 ;120 -> 127 + ENDIF + + IFDEF PLY_LW_HARDWARE_SPECTRUM_OR_MSX + ;PSG running to 1773400 Hz. + dw 6778, 6398, 6039, 5700, 5380, 5078, 4793, 4524, 4270, 4030, 3804, 3591 ; Octave 0 + dw 3389, 3199, 3019, 2850, 2690, 2539, 2397, 2262, 2135, 2015, 1902, 1795 ; Octave 1 + dw 1695, 1599, 1510, 1425, 1345, 1270, 1198, 1131, 1068, 1008, 951, 898 ; Octave 2 + dw 847, 800, 755, 712, 673, 635, 599, 566, 534, 504, 476, 449 ; Octave 3 + dw 424, 400, 377, 356, 336, 317, 300, 283, 267, 252, 238, 224 ; Octave 4 + dw 212, 200, 189, 178, 168, 159, 150, 141, 133, 126, 119, 112 ; Octave 5 + dw 106, 100, 94, 89, 84, 79, 75, 71, 67, 63, 59, 56 ; Octave 6 + dw 53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28 ; Octave 7 + dw 26, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 14 ; Octave 8 + dw 13, 12, 12, 11, 11, 10, 9, 9, 8, 8, 7, 7 ; Octave 9 + dw 7, 6, 6, 6, 5, 5, 5, 4 ; Octave 10 + ENDIF + + IFDEF PLY_LW_HARDWARE_PENTAGON + ;PSG running to 1750000 Hz. + dw 6689, 6314, 5959, 5625, 5309, 5011, 4730, 4464, 4214, 3977, 3754, 3543 ; Octave 0 + dw 3344, 3157, 2980, 2812, 2655, 2506, 2365, 2232, 2107, 1989, 1877, 1772 ; Octave 1 + dw 1672, 1578, 1490, 1406, 1327, 1253, 1182, 1116, 1053, 994, 939, 886 ; Octave 2 + dw 836, 789, 745, 703, 664, 626, 591, 558, 527, 497, 469, 443 ; Octave 3 + dw 418, 395, 372, 352, 332, 313, 296, 279, 263, 249, 235, 221 ; Octave 4 + dw 209, 197, 186, 176, 166, 157, 148, 140, 132, 124, 117, 111 ; Octave 5 + dw 105, 99, 93, 88, 83, 78, 74, 70, 66, 62, 59, 55 ; Octave 6 + dw 52, 49, 47, 44, 41, 39, 37, 35, 33, 31, 29, 28 ; Octave 7 + dw 26, 25, 23, 22, 21, 20, 18, 17, 16, 16, 15, 14 ; Octave 8 + dw 13, 12, 12, 11, 10, 10, 9, 9, 8, 8, 7, 7 ; Octave 9 + dw 7, 6, 6, 5, 5, 5, 5, 4 ; Octave 10 + ENDIF +dkwe +PLY_LW_End: + + + diff --git a/lib/plw/player/PlayerLightWeight_SoundEffects.asm b/lib/plw/player/PlayerLightWeight_SoundEffects.asm new file mode 100644 index 0000000..cd15cb8 --- /dev/null +++ b/lib/plw/player/PlayerLightWeight_SoundEffects.asm @@ -0,0 +1,458 @@ +; Player of sound effects, for the Lightweight player. + + ;Is there a loaded Player Configuration source? If no, use a default configuration. + IFNDEF PLY_CFG_SFX_ConfigurationIsPresent + PLY_CFG_UseHardwareSounds = 1 + PLY_CFG_SFX_LoopTo = 1 + PLY_CFG_SFX_NoSoftNoHard = 1 + PLY_CFG_SFX_NoSoftNoHard_Noise = 1 + PLY_CFG_SFX_SoftOnly = 1 + PLY_CFG_SFX_SoftOnly_Noise = 1 + PLY_CFG_SFX_HardOnly = 1 + PLY_CFG_SFX_HardOnly_Noise = 1 + PLY_CFG_SFX_HardOnly_Retrig = 1 + PLY_CFG_SFX_SoftAndHard = 1 + PLY_CFG_SFX_SoftAndHard_Noise = 1 + PLY_CFG_SFX_SoftAndHard_Retrig = 1 + ENDIF + +; Agglomerates some Player Configuration flags. +; -------------------------------------------- +; Mixes the Hardware flags into one. + IFDEF PLY_CFG_SFX_HardOnly + PLY_LW_SE_HardwareSounds = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftAndHard + PLY_LW_SE_HardwareSounds = 1 + ENDIF +; Mixes the Hardware Noise flags into one. + IFDEF PLY_CFG_SFX_HardOnly_Noise + PLY_LW_SE_HardwareNoise = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftAndHard_Noise + PLY_LW_SE_HardwareNoise = 1 + ENDIF +; Mixes the Noise flags into one. + IFDEF PLY_LW_SE_HardwareNoise + PLY_LW_SE_Noise = 1 + ENDIF + IFDEF PLY_CFG_SFX_NoSoftNoHard_Noise + PLY_LW_SE_Noise = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftOnly + PLY_LW_SE_Noise = 1 + ENDIF +; Noise in Sound Effects? Then noise register code must be compiled. + IFDEF PLY_LW_SE_Noise + PLY_LW_USE_NoiseRegister = 1 + ENDIF +; Mixes the Software Volume flags into one. + IFDEF PLY_CFG_SFX_NoSoftNoHard + PLY_LW_SE_VolumeSoft = 1 + PLY_LW_SE_VolumeSoftOrHard = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftOnly + PLY_LW_SE_VolumeSoft = 1 + PLY_LW_SE_VolumeSoftOrHard = 1 + ENDIF +; Mixes the volume (soft/hard) into one. + IFDEF PLY_CFG_UseHardwareSounds + PLY_LW_SE_VolumeSoftOrHard = 1 + ENDIF +; Mixes the retrig flags into one. + IFDEF PLY_CFG_SFX_HardOnly_Retrig + PLY_LW_SE_Retrig = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftAndHard_Retrig + PLY_LW_SE_Retrig = 1 + ENDIF + + +;Initializes the sound effects. It MUST be called at any times before a first sound effect is triggered. +;It doesn't matter whether the song is playing or not, or if it has been initialized or not. +;IN: HL = Address to the sound effects data. +PLY_LW_InitSoundEffectsDisarkGenerateExternalLabel: +PLY_LW_InitSoundEffects: + ld (PLY_LW_SE_PtSoundEffectTable + 1),hl + ret + + +;Plays a sound effect. If a previous one was already playing on the same channel, it is replaced. +;This does not actually plays the sound effect, but programs its playing. +;The music player, when called, will call the PLY_LW_PlaySoundEffectsStream method below. +;IN: A = Sound effect number (>0!). +; C = The channel where to play the sound effect (0, 1, 2). +; B = Inverted volume (0 = full volume, 16 = no sound). Hardware sounds are also lowered. +PLY_LW_PlaySoundEffectDisarkGenerateExternalLabel: +PLY_LW_PlaySoundEffect: + ;Gets the address to the sound effect. + dec a ;The 0th is not encoded. +dknr3: +PLY_LW_SE_PtSoundEffectTable: ld hl,0 + ld e,a + ld d,0 + add hl,de + add hl,de + ld e,(hl) + inc hl + ld d,(hl) + ;Reads the header of the sound effect to get the speed. + ld a,(de) + inc de + + push af + ;ex af,af' + + ld a,b + + ;Finds the pointer to the sound effect of the desired channel. + ld hl,PLY_LW_Channel1_SoundEffectData + ld b,0 + sla c + sla c + sla c + add hl,bc + ld (hl),e + inc hl + ld (hl),d + inc hl + + ;Now stores the inverted volume. + ld (hl),a + inc hl + + ;Resets the current speed, stores the instrument speed. + ld (hl),0 + inc hl + + ;ex af,af' + pop af + + ld (hl),a + + ret + +;Stops a sound effect. Nothing happens if there was no sound effect. +;IN: A = The channel where to stop the sound effect (0, 1, 2). +PLY_LW_StopSoundEffectFromChannelDisarkGenerateExternalLabel: +PLY_LW_StopSoundEffectFromChannel: + ;Puts 0 to the pointer of the sound effect. + add a,a + add a,a + add a,a + ld e,a + ld d,0 + ld hl,PLY_LW_Channel1_SoundEffectData + add hl,de + ld (hl),d ;0 means "no sound". + inc hl + ld (hl),d + ret + +;Plays the sound effects, if any has been triggered by the user. +;This does not actually send registers to the PSG, it only overwrite the required values of the registers of the player. +;The sound effects initialization method must have been called before! +;As R7 is required, this must be called after the music has been played, but BEFORE the registers are sent to the PSG. +;IN: A = R7. +PLY_LW_PlaySoundEffectsStream: + ;Shifts the R7 to the left twice, so that bit 2 and 5 only can be set for each track, below. + rla + rla + + ;Plays the sound effects on every track. + ld ix,PLY_LW_Channel1_SoundEffectData + ld iy,PLY_LW_Track1_Registers + ld c,a + call PLY_LW_PSES_Play + ld ix,PLY_LW_Channel2_SoundEffectData + ld iy,PLY_LW_Track2_Registers + srl c ;Not RR, because we have to make sure the b6 is 0, else no more keyboard (on CPC)! + ;Also, on MSX, bit 6 must be 0. + call PLY_LW_PSES_Play + ld ix,PLY_LW_Channel3_SoundEffectData + ld iy,PLY_LW_Track3_Registers + IFDEF PLY_LW_HARDWARE_MSX + scf ;On MSX, bit 7 must be 1. + rr c + ELSE + rr c ;On other platforms, we don't care about b7. + ENDIF + call PLY_LW_PSES_Play + + ld a,c + ld (PLY_LW_MixerRegister),a + ret + + +;Plays the sound stream from the given pointer to the sound effect. If 0, no sound is played. +;The given R7 is given shift twice to the left, so that this code MUST set/reset the bit 2 (sound), and maybe reset bit 5 (noise). +;This code MUST overwrite these bits because sound effects have priority over the music. +;IN: IX = Points on the sound effect pointer. If the sound effect pointer is 0, nothing must be played. +; IY = Points at the beginning of the register structure related to the channel. +; C = R7, shifted twice to the left. +;OUT: The pointed pointer by IX may be modified as the sound advances. +; C = R7, MUST be modified if there is a sound effect. +PLY_LW_PSES_Play: + ;Reads the pointer pointed by IX. + ld l,(ix + 0) + ld h,(ix + 1) + ld a,l + or h + ret z ;No sound to be played? Returns immediately. + + ;Reads the first byte. What type of sound is it? +PLY_LW_PSES_ReadFirstByte: + ld a,(hl) + inc hl + ld b,a + rra + jr c,PLY_LW_PSES_SoftwareOrSoftwareAndHardware + rra + IFDEF PLY_CFG_SFX_HardOnly ;CONFIG SPECIFIC + jr c,PLY_LW_PSES_HardwareOnly + ENDIF ;PLY_CFG_SFX_HardOnly + + ;No software, no hardware, or end/loop. + ;------------------------------------------- + ;End or loop? + rra + IFDEF PLY_CFG_SFX_NoSoftNoHard ;CONFIG SPECIFIC. If not present, the jump is not needed, the method is just below. + jr c,PLY_LW_PSES_S_EndOrLoop + + ;No software, no hardware. + ;------------------------------------------- + ;Gets the volume. + call PLY_LW_PSES_ManageVolumeFromA_Filter4Bits + + ;Noise? + IFDEF PLY_CFG_SFX_NoSoftNoHard_Noise ;CONFIG SPECIFIC + rl b + call c,PLY_LW_PSES_ReadNoiseAndOpenNoiseChannel + ENDIF ;PLY_CFG_SFX_NoSoftNoHard_Noise + + jr PLY_LW_PSES_SavePointerAndExit + ENDIF ;PLY_CFG_SFX_NoSoftNoHard + + ;**Warning!** Do not put any instruction between EndOrLoop and NoSoftNoHard. + +PLY_LW_PSES_S_EndOrLoop: + IFDEF PLY_CFG_SFX_LoopTo ;CONFIG SPECIFIC. If no "loop to", the sounds always end, no need to test. + ;Is it an end? + rra + jr c,PLY_LW_PSES_S_Loop + ENDIF ;PLY_CFG_SFX_LoopTo + ;End of the sound. Marks the sound pointer with 0, meaning "no sound". + xor a + ld (ix + 0),a + ld (ix + 1),a + ret + IFDEF PLY_CFG_SFX_LoopTo ;CONFIG SPECIFIC. +PLY_LW_PSES_S_Loop: + ;Loops. Reads the pointer and directly uses it. + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + jr PLY_LW_PSES_ReadFirstByte + ENDIF ;PLY_CFG_SFX_LoopTo + + +;Saves HL into IX, and exits. This must be called at the end of each Cell. +;If the speed has not been reached, it is not saved. +PLY_LW_PSES_SavePointerAndExit: + ;Speed reached? + ld a,(ix + PLY_LW_SoundEffectData_OffsetCurrentStep) + cp (ix + PLY_LW_SoundEffectData_OffsetSpeed) + jr c,PLY_LW_PSES_NotReached + ;The speed has been reached, so resets it and saves the pointer to the next cell to read. + ld (ix + PLY_LW_SoundEffectData_OffsetCurrentStep),0 + ld (ix + 0),l + ld (ix + 1),h + ret +PLY_LW_PSES_NotReached: + ;Speed not reached. Increases it, that's all. The same cell will be read next time. + inc (ix + PLY_LW_SoundEffectData_OffsetCurrentStep) + ret + + IFDEF PLY_CFG_SFX_HardOnly ;CONFIG SPECIFIC + ;Hardware only. + ;------------------------------------------- +PLY_LW_PSES_HardwareOnly: + ;Calls the shared code that manages everything. + call PLY_LW_PSES_Shared_ReadRetrigHardwareEnvPeriodNoise + ;Cuts the sound. + set 2,c + + jr PLY_LW_PSES_SavePointerAndExit + ENDIF ;PLY_CFG_SFX_HardOnly + + + +PLY_LW_PSES_SoftwareOrSoftwareAndHardware: + ;Software only? + rra + IFDEF PLY_CFG_SFX_SoftAndHard ;CONFIG SPECIFIC + jr c,PLY_LW_PSES_SoftwareAndHardware + ENDIF ;PLY_CFG_SFX_SoftAndHard + + ;Software. + ;------------------------------------------- + IFDEF PLY_CFG_SFX_SoftOnly ;CONFIG SPECIFIC + ;Volume. + call PLY_LW_PSES_ManageVolumeFromA_Filter4Bits + + ;Noise? + rl b + IFDEF PLY_CFG_SFX_SoftOnly_Noise ;CONFIG SPECIFIC + call c,PLY_LW_PSES_ReadNoiseAndOpenNoiseChannel + ENDIF ;PLY_CFG_SFX_SoftOnly_Noise + + ;Opens the "sound" channel. + res 2,c + + ;Reads the software period. + call PLY_LW_PSES_ReadSoftwarePeriod + + jr PLY_LW_PSES_SavePointerAndExit + ENDIF ;PLY_CFG_SFX_SoftOnly + + + ;Software and Hardware. + ;------------------------------------------- + IFDEF PLY_LW_SE_HardwareSounds ;CONFIG SPECIFIC +PLY_LW_PSES_SoftwareAndHardware: + ;Calls the shared code that manages everything. + call PLY_LW_PSES_Shared_ReadRetrigHardwareEnvPeriodNoise + + ;Reads the software period. + call PLY_LW_PSES_ReadSoftwarePeriod + + ;Opens the sound. + res 2,c + + jr PLY_LW_PSES_SavePointerAndExit + ENDIF ;PLY_LW_SE_HardwareSounds + + + IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC + ;Shared code used by the "hardware only" and "software and hardware" part. + ;Reads the Retrig flag, the Hardware Envelope, the possible noise, the hardware period, + ;and sets the volume to 16. The R7 sound channel is NOT modified. +PLY_LW_PSES_Shared_ReadRetrigHardwareEnvPeriodNoise: + ;Retrig? + rra + IFDEF PLY_LW_SE_Retrig ;CONFIG SPECIFIC + jr nc,PLY_LW_PSES_H_AfterRetrig + ld d,a + ld a,255 + ld (PLY_LW_SetReg13Old + 1),a + ld a,d +PLY_LW_PSES_H_AfterRetrig: + ENDIF ;PLY_LW_SE_Retrig + + ;The hardware envelope can be set (8-15). + and %111 + add a,8 + ld (PLY_LW_SetReg13 + 1),a + + ;Noise? + IFDEF PLY_LW_SE_HardwareNoise ;CONFIG SPECIFIC. B not needed after, we can put it in the condition too. + rl b + call c,PLY_LW_PSES_ReadNoiseAndOpenNoiseChannel + ENDIF ;PLY_LW_SE_HardwareNoise + + ;Reads the hardware period. + call PLY_LW_PSES_ReadHardwarePeriod + + ;Sets the volume to "hardware". It still may be decreased. + ld a,16 + jp PLY_LW_PSES_ManageVolumeFromA_Hard + ENDIF ;PLY_CFG_UseHardwareSounds + + + IFDEF PLY_LW_SE_Noise +;Reads the noise pointed by HL, increases HL, and opens the noise channel. +PLY_LW_PSES_ReadNoiseAndOpenNoiseChannel: + ;Reads the noise. + ld a,(hl) + ld (PLY_LW_NoiseRegister),a + inc hl + + ;Opens noise channel. + res 5,c + ret + ENDIF ;PLY_LW_SE_Noise + + IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC +;Reads the hardware period from HL and sets the R11/R12 registers. HL is incremented of 2. +PLY_LW_PSES_ReadHardwarePeriod: + ld a,(hl) + ld (PLY_LW_Reg11),a + inc hl + ld a,(hl) + ld (PLY_LW_Reg12),a + inc hl + ret + ENDIF ;PLY_CFG_UseHardwareSounds + +;Reads the software period from HL and sets the period registers thanks to IY. HL is incremented of 2. +PLY_LW_PSES_ReadSoftwarePeriod: + ld a,(hl) + ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodLSB),a + inc hl + ld a,(hl) + ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodMSB),a + inc hl + ret + + IFDEF PLY_LW_SE_VolumeSoft ;CONFIG SPECIFIC +;Reads the volume in A, decreases it from the inverted volume of the channel, and sets the volume via IY. +;IN: A = volume, from 0 to 15 (no hardware envelope). +PLY_LW_PSES_ManageVolumeFromA_Filter4Bits: + and %1111 + ENDIF ;PLY_LW_SE_VolumeSoft + IFDEF PLY_LW_SE_VolumeSoftOrHard ;CONFIG SPECIFIC +;After the filtering. Useful for hardware sound (volume has been forced to 16). +PLY_LW_PSES_ManageVolumeFromA_Hard: + ;Decreases the volume, checks the limit. + sub (ix + PLY_LW_SoundEffectData_OffsetInvertedVolume) + jr nc,PLY_LW_PSES_MVFA_NoOverflow + xor a +PLY_LW_PSES_MVFA_NoOverflow: + ld (iy + PLY_LW_Registers_OffsetVolume),a + ret + ENDIF ;PLY_LW_SE_VolumeSoftOrHard + + +;The data of the Channels MUST be consecutive. +PLY_LW_Channel1_SoundEffectData: +dkws + dw 0 ;Points to the sound effect for the track 1, or 0 if not playing. +PLY_LW_Channel1_SoundEffectInvertedVolume: +dkwe +dkbs + db 0 ;Inverted volume. +PLY_LW_Channel1_SoundEffectCurrentStep: + db 0 ;Current step (>=0). +PLY_LW_Channel1_SoundEffectSpeed: + db 0 ;Speed (>=0). + ds 3,0 ;Padding. +dkbe +PLY_LW_Channel_SoundEffectDataSize: equ $ - PLY_LW_Channel1_SoundEffectData + +dkbs +PLY_LW_Channel2_SoundEffectData: + ds PLY_LW_Channel_SoundEffectDataSize, 0 +PLY_LW_Channel3_SoundEffectData: + ds PLY_LW_Channel_SoundEffectDataSize, 0 +dkbe + +;Offset from the beginning of the data, to reach the inverted volume. +PLY_LW_SoundEffectData_OffsetInvertedVolume: equ PLY_LW_Channel1_SoundEffectInvertedVolume - PLY_LW_Channel1_SoundEffectData +PLY_LW_SoundEffectData_OffsetCurrentStep: equ PLY_LW_Channel1_SoundEffectCurrentStep - PLY_LW_Channel1_SoundEffectData +PLY_LW_SoundEffectData_OffsetSpeed: equ PLY_LW_Channel1_SoundEffectSpeed - PLY_LW_Channel1_SoundEffectData + + ;Checks that the pointers are consecutive. + assert (PLY_LW_Channel1_SoundEffectData + PLY_LW_Channel_SoundEffectDataSize) == PLY_LW_Channel2_SoundEffectData + assert (PLY_LW_Channel2_SoundEffectData + PLY_LW_Channel_SoundEffectDataSize) == PLY_LW_Channel3_SoundEffectData + diff --git a/lib/plw/player/player.asm b/lib/plw/player/player.asm new file mode 100644 index 0000000..3c2d137 --- /dev/null +++ b/lib/plw/player/player.asm @@ -0,0 +1,43 @@ +org #0b06 + +PLY_LW_HARDWARE_CPC = 1 +PLY_LW_MANAGE_SOUND_EFFECTS = 1 +PLY_LW_USE_HOOKS = 0 +PLY_LW_STOP_SOUNDS = 1 + +PLY_CFG_ConfigurationIsPresent = 1 +PLY_CFG_SFX_ConfigurationIsPresent = 1 +PLY_CFG_SFX_SoftOnly = 1 +PLY_CFG_SFX_SoftOnly_Noise = 1 +PLY_CFG_NoSoftNoHard = 1 +PLY_CFG_SoftOnly = 1 +PLY_CFG_SoftOnly_Noise = 1 +PLY_CFG_SoftOnly_SoftwarePitch = 1 + + ; my hook table + + jp PLY_LW_Init + jp PLY_LW_Play + jp PLY_LW_Stop + jp PLY_LW_InitSoundEffects + jp PLY_LW_PlaySoundEffect + jp PLW_LW_IsSoundEffectOn + +include "PlayerLightWeight.asm" + +; IN: L = channel +; OUT: L = 0 if is not on +PLW_LW_IsSoundEffectOn: + ld a,l + add a,a + add a,a + add a,a + ld c,a + ld b,0 + ld hl,PLY_LW_Channel1_SoundEffectData + add hl,bc + ld a,(hl) + inc hl + or (hl) + ld l,a + ret diff --git a/lib/plw/plw_init.z80 b/lib/plw/plw_init.z80 new file mode 100644 index 0000000..aaa6ba5 --- /dev/null +++ b/lib/plw/plw_init.z80 @@ -0,0 +1,14 @@ +.globl _PLW_Init +.globl _plw_player + +PLY_LW_INIT = 0x0b06 + +_PLW_Init:: + ld ix,#2 + add ix,sp + + ld l,0 (ix) + ld h,1 (ix) + ld a,2 (ix) + + jp PLY_LW_INIT diff --git a/lib/plw/plw_init_sound_effects.z80 b/lib/plw/plw_init_sound_effects.z80 new file mode 100644 index 0000000..a82cfdc --- /dev/null +++ b/lib/plw/plw_init_sound_effects.z80 @@ -0,0 +1,9 @@ +.globl _PLW_InitSoundEffects +.globl plw_current_efx + +PLY_LW_INIT_SOUND_EFFECTS = 0x0b06 + 0x9 + +_PLW_InitSoundEffects:: + xor a + ld (plw_current_efx), a + jp PLY_LW_INIT_SOUND_EFFECTS diff --git a/lib/plw/plw_is_sound_effect_on.z80 b/lib/plw/plw_is_sound_effect_on.z80 new file mode 100644 index 0000000..5953cce --- /dev/null +++ b/lib/plw/plw_is_sound_effect_on.z80 @@ -0,0 +1,7 @@ +.globl _PLW_IsSoundEffectOn + +PLY_LW_IS_SOUND_EFFECT_ON = 0x0b06 + 0xf + +_PLW_IsSoundEffectOn:: + jp PLY_LW_IS_SOUND_EFFECT_ON + diff --git a/lib/plw/plw_play.z80 b/lib/plw/plw_play.z80 new file mode 100644 index 0000000..a1f0ac8 --- /dev/null +++ b/lib/plw/plw_play.z80 @@ -0,0 +1,6 @@ +.globl _PLW_Play + +PLY_LW_PLAY = 0x0b06 + 0x3 + +_PLW_Play:: + jp PLY_LW_PLAY diff --git a/lib/plw/plw_play_sound_effect.z80 b/lib/plw/plw_play_sound_effect.z80 new file mode 100644 index 0000000..a20fcfe --- /dev/null +++ b/lib/plw/plw_play_sound_effect.z80 @@ -0,0 +1,48 @@ +.globl _PLW_PlaySoundEffect +.globl _PLW_IsSoundEffectOn +.globl _PLW_PlaySoundEffectP +.globl plw_current_efx + +PLY_LW_PLAY_SOUND_EFFECT = 0x0b06 + 0xc + +_PLW_PlaySoundEffect:: + ld hl,#2 + add hl,sp + + ld a, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + + jp PLY_LW_PLAY_SOUND_EFFECT + +_PLW_PlaySoundEffectP:: + ; check if current is over + ; de is not used + ld e, l + ; fixed channel 2 + ld l, #2 + call _PLW_IsSoundEffectOn + ld a, l + or a + jr z, play_efx + + ld a, (plw_current_efx) + cp e + ret nc + +play_efx: + ; all good, play the effect + ld a, e + ld (plw_current_efx), a + + ; fixed channel 2, full volume + ld bc, #0x0002 + + jp PLY_LW_PLAY_SOUND_EFFECT + +.area _DATA + +plw_current_efx: .ds 1 + diff --git a/lib/plw/plw_player.asm b/lib/plw/plw_player.asm new file mode 100644 index 0000000..f47a9bf --- /dev/null +++ b/lib/plw/plw_player.asm @@ -0,0 +1,1193 @@ +;-------------------------------------------------------- +; File Created by SDCC : free open source ANSI-C Compiler +; Version 4.0.0 #11528 (Linux) +;-------------------------------------------------------- + .module plw_player + .optsdcc -mz80 + +;-------------------------------------------------------- +; Public variables in this module +;-------------------------------------------------------- + .globl _plw_player +;-------------------------------------------------------- +; special function registers +;-------------------------------------------------------- +;-------------------------------------------------------- +; ram data +;-------------------------------------------------------- + .area _DATA +;-------------------------------------------------------- +; ram data +;-------------------------------------------------------- + .area _INITIALIZED +;-------------------------------------------------------- +; absolute external ram data +;-------------------------------------------------------- + .area _DABS (ABS) +;-------------------------------------------------------- +; global & static initialisations +;-------------------------------------------------------- + .area _HOME + .area _GSINIT + .area _GSFINAL + .area _GSINIT +;-------------------------------------------------------- +; Home +;-------------------------------------------------------- + .area _HOME + .area _HOME +;-------------------------------------------------------- +; code +;-------------------------------------------------------- + .area _CODE + .area _CODE +_plw_player: + .db #0xc3 ; 195 + .db #0xf6 ; 246 + .db #0x0b ; 11 + .db #0xc3 ; 195 + .db #0x55 ; 85 'U' + .db #0x0c ; 12 + .db #0xc3 ; 195 + .db #0x3f ; 63 + .db #0x0c ; 12 + .db #0xc3 ; 195 + .db #0x18 ; 24 + .db #0x0b ; 11 + .db #0xc3 ; 195 + .db #0x1c ; 28 + .db #0x0b ; 11 + .db #0xc3 ; 195 + .db #0x71 ; 113 'q' + .db #0x0f ; 15 + .db #0x22 ; 34 + .db #0x1e ; 30 + .db #0x0b ; 11 + .db #0xc9 ; 201 + .db #0x3d ; 61 + .db #0x21 ; 33 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x5f ; 95 + .db #0x16 ; 22 + .db #0x00 ; 0 + .db #0x19 ; 25 + .db #0x19 ; 25 + .db #0x5e ; 94 + .db #0x23 ; 35 + .db #0x56 ; 86 'V' + .db #0x1a ; 26 + .db #0x13 ; 19 + .db #0xf5 ; 245 + .db #0x78 ; 120 'x' + .db #0x21 ; 33 + .db #0xde ; 222 + .db #0x0b ; 11 + .db #0x06 ; 6 + .db #0x00 ; 0 + .db #0xcb ; 203 + .db #0x21 ; 33 + .db #0xcb ; 203 + .db #0x21 ; 33 + .db #0xcb ; 203 + .db #0x21 ; 33 + .db #0x09 ; 9 + .db #0x73 ; 115 's' + .db #0x23 ; 35 + .db #0x72 ; 114 'r' + .db #0x23 ; 35 + .db #0x77 ; 119 'w' + .db #0x23 ; 35 + .db #0x36 ; 54 '6' + .db #0x00 ; 0 + .db #0x23 ; 35 + .db #0xf1 ; 241 + .db #0x77 ; 119 'w' + .db #0xc9 ; 201 + .db #0x87 ; 135 + .db #0x87 ; 135 + .db #0x87 ; 135 + .db #0x5f ; 95 + .db #0x16 ; 22 + .db #0x00 ; 0 + .db #0x21 ; 33 + .db #0xde ; 222 + .db #0x0b ; 11 + .db #0x19 ; 25 + .db #0x72 ; 114 'r' + .db #0x23 ; 35 + .db #0x72 ; 114 'r' + .db #0xc9 ; 201 + .db #0x17 ; 23 + .db #0x17 ; 23 + .db #0xdd ; 221 + .db #0x21 ; 33 + .db #0xde ; 222 + .db #0x0b ; 11 + .db #0xfd ; 253 + .db #0x21 ; 33 + .db #0x45 ; 69 'E' + .db #0x0e ; 14 + .db #0x4f ; 79 'O' + .db #0xcd ; 205 + .db #0x7f ; 127 + .db #0x0b ; 11 + .db #0xdd ; 221 + .db #0x21 ; 33 + .db #0xe6 ; 230 + .db #0x0b ; 11 + .db #0xfd ; 253 + .db #0x21 ; 33 + .db #0x51 ; 81 'Q' + .db #0x0e ; 14 + .db #0xcb ; 203 + .db #0x39 ; 57 '9' + .db #0xcd ; 205 + .db #0x7f ; 127 + .db #0x0b ; 11 + .db #0xdd ; 221 + .db #0x21 ; 33 + .db #0xee ; 238 + .db #0x0b ; 11 + .db #0xfd ; 253 + .db #0x21 ; 33 + .db #0x5d ; 93 + .db #0x0e ; 14 + .db #0xcb ; 203 + .db #0x19 ; 25 + .db #0xcd ; 205 + .db #0x7f ; 127 + .db #0x0b ; 11 + .db #0x79 ; 121 'y' + .db #0x32 ; 50 '2' + .db #0x6e ; 110 'n' + .db #0x0e ; 14 + .db #0xc9 ; 201 + .db #0xdd ; 221 + .db #0x6e ; 110 'n' + .db #0x00 ; 0 + .db #0xdd ; 221 + .db #0x66 ; 102 'f' + .db #0x01 ; 1 + .db #0x7d ; 125 + .db #0xb4 ; 180 + .db #0xc8 ; 200 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0x47 ; 71 'G' + .db #0x1f ; 31 + .db #0x38 ; 56 '8' + .db #0x21 ; 33 + .db #0x1f ; 31 + .db #0x1f ; 31 + .db #0xaf ; 175 + .db #0xdd ; 221 + .db #0x77 ; 119 'w' + .db #0x00 ; 0 + .db #0xdd ; 221 + .db #0x77 ; 119 'w' + .db #0x01 ; 1 + .db #0xc9 ; 201 + .db #0xdd ; 221 + .db #0x7e ; 126 + .db #0x03 ; 3 + .db #0xdd ; 221 + .db #0xbe ; 190 + .db #0x04 ; 4 + .db #0x38 ; 56 '8' + .db #0x0b ; 11 + .db #0xdd ; 221 + .db #0x36 ; 54 '6' + .db #0x03 ; 3 + .db #0x00 ; 0 + .db #0xdd ; 221 + .db #0x75 ; 117 'u' + .db #0x00 ; 0 + .db #0xdd ; 221 + .db #0x74 ; 116 't' + .db #0x01 ; 1 + .db #0xc9 ; 201 + .db #0xdd ; 221 + .db #0x34 ; 52 '4' + .db #0x03 ; 3 + .db #0xc9 ; 201 + .db #0x1f ; 31 + .db #0xcd ; 205 + .db #0xd2 ; 210 + .db #0x0b ; 11 + .db #0xcb ; 203 + .db #0x10 ; 16 + .db #0xdc ; 220 + .db #0xbf ; 191 + .db #0x0b ; 11 + .db #0xcb ; 203 + .db #0x91 ; 145 + .db #0xcd ; 205 + .db #0xc7 ; 199 + .db #0x0b ; 11 + .db #0x18 ; 24 + .db #0xd9 ; 217 + .db #0x7e ; 126 + .db #0x32 ; 50 '2' + .db #0x6a ; 106 'j' + .db #0x0e ; 14 + .db #0x23 ; 35 + .db #0xcb ; 203 + .db #0xa9 ; 169 + .db #0xc9 ; 201 + .db #0x7e ; 126 + .db #0xfd ; 253 + .db #0x77 ; 119 'w' + .db #0x05 ; 5 + .db #0x23 ; 35 + .db #0x7e ; 126 + .db #0xfd ; 253 + .db #0x77 ; 119 'w' + .db #0x09 ; 9 + .db #0x23 ; 35 + .db #0xc9 ; 201 + .db #0xe6 ; 230 + .db #0x0f ; 15 + .db #0xdd ; 221 + .db #0x96 ; 150 + .db #0x02 ; 2 + .db #0x30 ; 48 '0' + .db #0x01 ; 1 + .db #0xaf ; 175 + .db #0xfd ; 253 + .db #0x77 ; 119 'w' + .db #0x01 ; 1 + .db #0xc9 ; 201 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x11 ; 17 + .db #0x05 ; 5 + .db #0x00 ; 0 + .db #0x19 ; 25 + .db #0x11 ; 17 + .db #0xb1 ; 177 + .db #0x0c ; 12 + .db #0xed ; 237 + .db #0xa0 ; 160 + .db #0xed ; 237 + .db #0xa0 ; 160 + .db #0x11 ; 17 + .db #0x04 ; 4 + .db #0x00 ; 0 + .db #0x19 ; 25 + .db #0x5f ; 95 + .db #0x16 ; 22 + .db #0x00 ; 0 + .db #0x19 ; 25 + .db #0x19 ; 25 + .db #0x5e ; 94 + .db #0x23 ; 35 + .db #0x56 ; 86 'V' + .db #0x1a ; 26 + .db #0x13 ; 19 + .db #0xed ; 237 + .db #0x53 ; 83 'S' + .db #0x6d ; 109 'm' + .db #0x0c ; 12 + .db #0x32 ; 50 '2' + .db #0x5d ; 93 + .db #0x0c ; 12 + .db #0x3d ; 61 + .db #0x32 ; 50 '2' + .db #0x5a ; 90 'Z' + .db #0x0c ; 12 + .db #0xaf ; 175 + .db #0x32 ; 50 '2' + .db #0x62 ; 98 'b' + .db #0x0c ; 12 + .db #0x21 ; 33 + .db #0x24 ; 36 + .db #0x0e ; 14 + .db #0x11 ; 17 + .db #0x25 ; 37 + .db #0x0e ; 14 + .db #0x01 ; 1 + .db #0x0a ; 10 + .db #0x00 ; 0 + .db #0x36 ; 54 '6' + .db #0x00 ; 0 + .db #0xed ; 237 + .db #0xb0 ; 176 + .db #0x2a ; 42 + .db #0xb1 ; 177 + .db #0x0c ; 12 + .db #0x5e ; 94 + .db #0x23 ; 35 + .db #0x56 ; 86 'V' + .db #0x13 ; 19 + .db #0xed ; 237 + .db #0x53 ; 83 'S' + .db #0x2b ; 43 + .db #0x0e ; 14 + .db #0xed ; 237 + .db #0x53 ; 83 'S' + .db #0x36 ; 54 '6' + .db #0x0e ; 14 + .db #0xed ; 237 + .db #0x53 ; 83 'S' + .db #0x41 ; 65 'A' + .db #0x0e ; 14 + .db #0xc9 ; 201 + .db #0xed ; 237 + .db #0x73 ; 115 's' + .db #0x1a ; 26 + .db #0x0d ; 13 + .db #0xaf ; 175 + .db #0x32 ; 50 '2' + .db #0x46 ; 70 'F' + .db #0x0e ; 14 + .db #0x32 ; 50 '2' + .db #0x52 ; 82 'R' + .db #0x0e ; 14 + .db #0x32 ; 50 '2' + .db #0x5e ; 94 + .db #0x0e ; 14 + .db #0x3e ; 62 + .db #0x3f ; 63 + .db #0x32 ; 50 '2' + .db #0x6e ; 110 'n' + .db #0x0e ; 14 + .db #0xc3 ; 195 + .db #0xfc ; 252 + .db #0x0c ; 12 + .db #0xed ; 237 + .db #0x73 ; 115 's' + .db #0x1a ; 26 + .db #0x0d ; 13 + .db #0x3e ; 62 + .db #0x00 ; 0 + .db #0x3c ; 60 + .db #0xfe ; 254 + .db #0x01 ; 1 + .db #0xc2 ; 194 + .db #0xca ; 202 + .db #0x0c ; 12 + .db #0x3e ; 62 + .db #0x00 ; 0 + .db #0xd6 ; 214 + .db #0x01 ; 1 + .db #0x38 ; 56 '8' + .db #0x05 ; 5 + .db #0x32 ; 50 '2' + .db #0x62 ; 98 'b' + .db #0x0c ; 12 + .db #0x18 ; 24 + .db #0x44 ; 68 'D' + .db #0x21 ; 33 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0xaf ; 175 + .db #0x32 ; 50 '2' + .db #0x24 ; 36 + .db #0x0e ; 14 + .db #0x32 ; 50 '2' + .db #0x2f ; 47 + .db #0x0e ; 14 + .db #0x32 ; 50 '2' + .db #0x3a ; 58 + .db #0x0e ; 14 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0x1f ; 31 + .db #0x38 ; 56 '8' + .db #0x06 ; 6 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0x66 ; 102 'f' + .db #0x6f ; 111 'o' + .db #0x18 ; 24 + .db #0xeb ; 235 + .db #0x1f ; 31 + .db #0x47 ; 71 'G' + .db #0xcb ; 203 + .db #0x18 ; 24 + .db #0x30 ; 48 '0' + .db #0x07 ; 7 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0x32 ; 50 '2' + .db #0x92 ; 146 + .db #0x0c ; 12 + .db #0x18 ; 24 + .db #0x02 ; 2 + .db #0x3e ; 62 + .db #0x00 ; 0 + .db #0x32 ; 50 '2' + .db #0x62 ; 98 'b' + .db #0x0c ; 12 + .db #0xcb ; 203 + .db #0x18 ; 24 + .db #0x11 ; 17 + .db #0x29 ; 41 + .db #0x0e ; 14 + .db #0xed ; 237 + .db #0xa0 ; 160 + .db #0xed ; 237 + .db #0xa0 ; 160 + .db #0x11 ; 17 + .db #0x34 ; 52 '4' + .db #0x0e ; 14 + .db #0xed ; 237 + .db #0xa0 ; 160 + .db #0xed ; 237 + .db #0xa0 ; 160 + .db #0x11 ; 17 + .db #0x3f ; 63 + .db #0x0e ; 14 + .db #0xed ; 237 + .db #0xa0 ; 160 + .db #0xed ; 237 + .db #0xa0 ; 160 + .db #0x22 ; 34 + .db #0x6d ; 109 'm' + .db #0x0c ; 12 + .db #0x11 ; 17 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0xd9 ; 217 + .db #0xdd ; 221 + .db #0x21 ; 33 + .db #0x24 ; 36 + .db #0x0e ; 14 + .db #0xcd ; 205 + .db #0x1d ; 29 + .db #0x0d ; 13 + .db #0xdd ; 221 + .db #0x21 ; 33 + .db #0x2f ; 47 + .db #0x0e ; 14 + .db #0xcd ; 205 + .db #0x1d ; 29 + .db #0x0d ; 13 + .db #0xdd ; 221 + .db #0x21 ; 33 + .db #0x3a ; 58 + .db #0x0e ; 14 + .db #0xcd ; 205 + .db #0x1d ; 29 + .db #0x0d ; 13 + .db #0xaf ; 175 + .db #0x32 ; 50 '2' + .db #0x5a ; 90 'Z' + .db #0x0c ; 12 + .db #0x11 ; 17 + .db #0x71 ; 113 'q' + .db #0x0e ; 14 + .db #0xd9 ; 217 + .db #0x0e ; 14 + .db #0xe0 ; 224 + .db #0xdd ; 221 + .db #0x21 ; 33 + .db #0x24 ; 36 + .db #0x0e ; 14 + .db #0xfd ; 253 + .db #0x21 ; 33 + .db #0x45 ; 69 'E' + .db #0x0e ; 14 + .db #0xcd ; 205 + .db #0x93 ; 147 + .db #0x0d ; 13 + .db #0xcb ; 203 + .db #0x39 ; 57 '9' + .db #0xdd ; 221 + .db #0x21 ; 33 + .db #0x2f ; 47 + .db #0x0e ; 14 + .db #0xfd ; 253 + .db #0x21 ; 33 + .db #0x51 ; 81 'Q' + .db #0x0e ; 14 + .db #0xcd ; 205 + .db #0x93 ; 147 + .db #0x0d ; 13 + .db #0xcb ; 203 + .db #0x19 ; 25 + .db #0xdd ; 221 + .db #0x21 ; 33 + .db #0x3a ; 58 + .db #0x0e ; 14 + .db #0xfd ; 253 + .db #0x21 ; 33 + .db #0x5d ; 93 + .db #0x0e ; 14 + .db #0xcd ; 205 + .db #0x93 ; 147 + .db #0x0d ; 13 + .db #0x79 ; 121 'y' + .db #0xcd ; 205 + .db #0x52 ; 82 'R' + .db #0x0b ; 11 + .db #0x31 ; 49 '1' + .db #0x45 ; 69 'E' + .db #0x0e ; 14 + .db #0x01 ; 1 + .db #0x80 ; 128 + .db #0xf6 ; 246 + .db #0x3e ; 62 + .db #0xc0 ; 192 + .db #0x11 ; 17 + .db #0xf6 ; 246 + .db #0xf4 ; 244 + .db #0xed ; 237 + .db #0x79 ; 121 'y' + .db #0xe1 ; 225 + .db #0x42 ; 66 'B' + .db #0xed ; 237 + .db #0x69 ; 105 'i' + .db #0x43 ; 67 'C' + .db #0xed ; 237 + .db #0x71 ; 113 'q' + .db #0x42 ; 66 'B' + .db #0xed ; 237 + .db #0x61 ; 97 'a' + .db #0x43 ; 67 'C' + .db #0xed ; 237 + .db #0x49 ; 73 'I' + .db #0xed ; 237 + .db #0x79 ; 121 'y' + .db #0xc9 ; 201 + .db #0x31 ; 49 '1' + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0xc9 ; 201 + .db #0xdd ; 221 + .db #0x7e ; 126 + .db #0x00 ; 0 + .db #0xd6 ; 214 + .db #0x01 ; 1 + .db #0x38 ; 56 '8' + .db #0x04 ; 4 + .db #0xdd ; 221 + .db #0x77 ; 119 'w' + .db #0x00 ; 0 + .db #0xc9 ; 201 + .db #0xdd ; 221 + .db #0x6e ; 110 'n' + .db #0x05 ; 5 + .db #0xdd ; 221 + .db #0x66 ; 102 'f' + .db #0x06 ; 6 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0x47 ; 71 'G' + .db #0xe6 ; 230 + .db #0x3f ; 63 + .db #0xd6 ; 214 + .db #0x3c ; 60 + .db #0x38 ; 56 '8' + .db #0x0a ; 10 + .db #0x3d ; 61 + .db #0x28 ; 40 + .db #0x42 ; 66 'B' + .db #0x3d ; 61 + .db #0x28 ; 40 + .db #0x46 ; 70 'F' + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0x18 ; 24 + .db #0x02 ; 2 + .db #0xc6 ; 198 + .db #0x54 ; 84 'T' + .db #0xdd ; 221 + .db #0x77 ; 119 'w' + .db #0x01 ; 1 + .db #0xcb ; 203 + .db #0x10 ; 16 + .db #0x38 ; 56 '8' + .db #0x0e ; 14 + .db #0xdd ; 221 + .db #0x7e ; 126 + .db #0x09 ; 9 + .db #0xdd ; 221 + .db #0x77 ; 119 'w' + .db #0x07 ; 7 + .db #0xdd ; 221 + .db #0x7e ; 126 + .db #0x0a ; 10 + .db #0xdd ; 221 + .db #0x77 ; 119 'w' + .db #0x08 ; 8 + .db #0x18 ; 24 + .db #0x1c ; 28 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0xd9 ; 217 + .db #0x6f ; 111 'o' + .db #0x26 ; 38 + .db #0x00 ; 0 + .db #0x19 ; 25 + .db #0x4e ; 78 'N' + .db #0x23 ; 35 + .db #0x46 ; 70 'F' + .db #0x0a ; 10 + .db #0xdd ; 221 + .db #0x77 ; 119 'w' + .db #0x03 ; 3 + .db #0x03 ; 3 + .db #0xdd ; 221 + .db #0x71 ; 113 'q' + .db #0x07 ; 7 + .db #0xdd ; 221 + .db #0x70 ; 112 'p' + .db #0x08 ; 8 + .db #0xdd ; 221 + .db #0x71 ; 113 'q' + .db #0x09 ; 9 + .db #0xdd ; 221 + .db #0x70 ; 112 'p' + .db #0x0a ; 10 + .db #0xd9 ; 217 + .db #0xdd ; 221 + .db #0x36 ; 54 '6' + .db #0x02 ; 2 + .db #0x00 ; 0 + .db #0xcb ; 203 + .db #0x10 ; 16 + .db #0x30 ; 48 '0' + .db #0x10 ; 16 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0xdd ; 221 + .db #0x77 ; 119 'w' + .db #0x00 ; 0 + .db #0x18 ; 24 + .db #0x09 ; 9 + .db #0x78 ; 120 'x' + .db #0x17 ; 23 + .db #0x17 ; 23 + .db #0x17 ; 23 + .db #0xe6 ; 230 + .db #0x03 ; 3 + .db #0xdd ; 221 + .db #0x77 ; 119 'w' + .db #0x00 ; 0 + .db #0xdd ; 221 + .db #0x75 ; 117 'u' + .db #0x05 ; 5 + .db #0xdd ; 221 + .db #0x74 ; 116 't' + .db #0x06 ; 6 + .db #0xc9 ; 201 + .db #0xdd ; 221 + .db #0x6e ; 110 'n' + .db #0x07 ; 7 + .db #0xdd ; 221 + .db #0x66 ; 102 'f' + .db #0x08 ; 8 + .db #0x7e ; 126 + .db #0x47 ; 71 'G' + .db #0x23 ; 35 + .db #0x1f ; 31 + .db #0x38 ; 56 '8' + .db #0x1c ; 28 + .db #0x1f ; 31 + .db #0x1f ; 31 + .db #0x30 ; 48 '0' + .db #0x0c ; 12 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0x66 ; 102 'f' + .db #0x6f ; 111 'o' + .db #0xdd ; 221 + .db #0x75 ; 117 'u' + .db #0x07 ; 7 + .db #0xdd ; 221 + .db #0x74 ; 116 't' + .db #0x08 ; 8 + .db #0x18 ; 24 + .db #0xea ; 234 + .db #0xcb ; 203 + .db #0xd1 ; 209 + .db #0xcd ; 205 + .db #0xf8 ; 248 + .db #0x0d ; 13 + .db #0xfd ; 253 + .db #0x77 ; 119 'w' + .db #0x01 ; 1 + .db #0xcb ; 203 + .db #0x10 ; 16 + .db #0x18 ; 24 + .db #0x26 ; 38 + .db #0x1f ; 31 + .db #0xcd ; 205 + .db #0xf8 ; 248 + .db #0x0d ; 13 + .db #0xfd ; 253 + .db #0x77 ; 119 'w' + .db #0x01 ; 1 + .db #0x16 ; 22 + .db #0x00 ; 0 + .db #0xcb ; 203 + .db #0x10 ; 16 + .db #0x30 ; 48 '0' + .db #0x08 ; 8 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0xcb ; 203 + .db #0x2f ; 47 + .db #0x57 ; 87 'W' + .db #0xdc ; 220 + .db #0x00 ; 0 + .db #0x0e ; 14 + .db #0x7a ; 122 'z' + .db #0xcd ; 205 + .db #0x08 ; 8 + .db #0x0e ; 14 + .db #0xcb ; 203 + .db #0x10 ; 16 + .db #0xdc ; 220 + .db #0x18 ; 24 + .db #0x0e ; 14 + .db #0xd9 ; 217 + .db #0xfd ; 253 + .db #0x75 ; 117 'u' + .db #0x05 ; 5 + .db #0xfd ; 253 + .db #0x74 ; 116 't' + .db #0x09 ; 9 + .db #0xd9 ; 217 + .db #0xdd ; 221 + .db #0x7e ; 126 + .db #0x02 ; 2 + .db #0xdd ; 221 + .db #0xbe ; 190 + .db #0x03 ; 3 + .db #0x28 ; 40 + .db #0x04 ; 4 + .db #0xdd ; 221 + .db #0x34 ; 52 '4' + .db #0x02 ; 2 + .db #0xc9 ; 201 + .db #0xdd ; 221 + .db #0x75 ; 117 'u' + .db #0x07 ; 7 + .db #0xdd ; 221 + .db #0x74 ; 116 't' + .db #0x08 ; 8 + .db #0xdd ; 221 + .db #0x36 ; 54 '6' + .db #0x02 ; 2 + .db #0x00 ; 0 + .db #0xc9 ; 201 + .db #0xe6 ; 230 + .db #0x0f ; 15 + .db #0xdd ; 221 + .db #0x96 ; 150 + .db #0x04 ; 4 + .db #0xd0 ; 208 + .db #0xaf ; 175 + .db #0xc9 ; 201 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0x32 ; 50 '2' + .db #0x6a ; 106 'j' + .db #0x0e ; 14 + .db #0xcb ; 203 + .db #0xa9 ; 169 + .db #0xc9 ; 201 + .db #0xd9 ; 217 + .db #0x26 ; 38 + .db #0x00 ; 0 + .db #0xdd ; 221 + .db #0x86 ; 134 + .db #0x01 ; 1 + .db #0x6f ; 111 'o' + .db #0xcb ; 203 + .db #0x25 ; 37 + .db #0x19 ; 25 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0x66 ; 102 'f' + .db #0x6f ; 111 'o' + .db #0xd9 ; 217 + .db #0xc9 ; 201 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0xd9 ; 217 + .db #0x4f ; 79 'O' + .db #0xd9 ; 217 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0xd9 ; 217 + .db #0x47 ; 71 'G' + .db #0x09 ; 9 + .db #0xd9 ; 217 + .db #0xc9 ; 201 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x08 ; 8 + .db #0x00 ; 0 + .db #0x09 ; 9 + .db #0x0d ; 13 + .db #0x00 ; 0 + .db #0x00 ; 0 + .db #0x09 ; 9 + .db #0x0d ; 13 + .db #0x01 ; 1 + .db #0x00 ; 0 + .db #0x09 ; 9 + .db #0x0d ; 13 + .db #0x09 ; 9 + .db #0x00 ; 0 + .db #0x09 ; 9 + .db #0x0d ; 13 + .db #0x02 ; 2 + .db #0x00 ; 0 + .db #0x09 ; 9 + .db #0x0d ; 13 + .db #0x03 ; 3 + .db #0x00 ; 0 + .db #0x09 ; 9 + .db #0x0d ; 13 + .db #0x0a ; 10 + .db #0x00 ; 0 + .db #0x09 ; 9 + .db #0x0d ; 13 + .db #0x04 ; 4 + .db #0x00 ; 0 + .db #0x09 ; 9 + .db #0x0d ; 13 + .db #0x05 ; 5 + .db #0x00 ; 0 + .db #0x09 ; 9 + .db #0x0d ; 13 + .db #0x06 ; 6 + .db #0x00 ; 0 + .db #0x09 ; 9 + .db #0x0d ; 13 + .db #0x07 ; 7 + .db #0x00 ; 0 + .db #0x19 ; 25 + .db #0x0d ; 13 + .db #0xee ; 238 + .db #0x0e ; 14 + .db #0x18 ; 24 + .db #0x0e ; 14 + .db #0x4d ; 77 'M' + .db #0x0d ; 13 + .db #0x8e ; 142 + .db #0x0c ; 12 + .db #0xda ; 218 + .db #0x0b ; 11 + .db #0x2f ; 47 + .db #0x0b ; 11 + .db #0x8f ; 143 + .db #0x0a ; 10 + .db #0xf7 ; 247 + .db #0x09 ; 9 + .db #0x68 ; 104 'h' + .db #0x09 ; 9 + .db #0xe1 ; 225 + .db #0x08 ; 8 + .db #0x61 ; 97 'a' + .db #0x08 ; 8 + .db #0xe9 ; 233 + .db #0x07 ; 7 + .db #0x77 ; 119 'w' + .db #0x07 ; 7 + .db #0x0c ; 12 + .db #0x07 ; 7 + .db #0xa7 ; 167 + .db #0x06 ; 6 + .db #0x47 ; 71 'G' + .db #0x06 ; 6 + .db #0xed ; 237 + .db #0x05 ; 5 + .db #0x98 ; 152 + .db #0x05 ; 5 + .db #0x47 ; 71 'G' + .db #0x05 ; 5 + .db #0xfc ; 252 + .db #0x04 ; 4 + .db #0xb4 ; 180 + .db #0x04 ; 4 + .db #0x70 ; 112 'p' + .db #0x04 ; 4 + .db #0x31 ; 49 '1' + .db #0x04 ; 4 + .db #0xf4 ; 244 + .db #0x03 ; 3 + .db #0xbc ; 188 + .db #0x03 ; 3 + .db #0x86 ; 134 + .db #0x03 ; 3 + .db #0x53 ; 83 'S' + .db #0x03 ; 3 + .db #0x24 ; 36 + .db #0x03 ; 3 + .db #0xf6 ; 246 + .db #0x02 ; 2 + .db #0xcc ; 204 + .db #0x02 ; 2 + .db #0xa4 ; 164 + .db #0x02 ; 2 + .db #0x7e ; 126 + .db #0x02 ; 2 + .db #0x5a ; 90 'Z' + .db #0x02 ; 2 + .db #0x38 ; 56 '8' + .db #0x02 ; 2 + .db #0x18 ; 24 + .db #0x02 ; 2 + .db #0xfa ; 250 + .db #0x01 ; 1 + .db #0xde ; 222 + .db #0x01 ; 1 + .db #0xc3 ; 195 + .db #0x01 ; 1 + .db #0xaa ; 170 + .db #0x01 ; 1 + .db #0x92 ; 146 + .db #0x01 ; 1 + .db #0x7b ; 123 + .db #0x01 ; 1 + .db #0x66 ; 102 'f' + .db #0x01 ; 1 + .db #0x52 ; 82 'R' + .db #0x01 ; 1 + .db #0x3f ; 63 + .db #0x01 ; 1 + .db #0x2d ; 45 + .db #0x01 ; 1 + .db #0x1c ; 28 + .db #0x01 ; 1 + .db #0x0c ; 12 + .db #0x01 ; 1 + .db #0xfd ; 253 + .db #0x00 ; 0 + .db #0xef ; 239 + .db #0x00 ; 0 + .db #0xe1 ; 225 + .db #0x00 ; 0 + .db #0xd5 ; 213 + .db #0x00 ; 0 + .db #0xc9 ; 201 + .db #0x00 ; 0 + .db #0xbe ; 190 + .db #0x00 ; 0 + .db #0xb3 ; 179 + .db #0x00 ; 0 + .db #0xa9 ; 169 + .db #0x00 ; 0 + .db #0x9f ; 159 + .db #0x00 ; 0 + .db #0x96 ; 150 + .db #0x00 ; 0 + .db #0x8e ; 142 + .db #0x00 ; 0 + .db #0x86 ; 134 + .db #0x00 ; 0 + .db #0x7f ; 127 + .db #0x00 ; 0 + .db #0x77 ; 119 'w' + .db #0x00 ; 0 + .db #0x71 ; 113 'q' + .db #0x00 ; 0 + .db #0x6a ; 106 'j' + .db #0x00 ; 0 + .db #0x64 ; 100 'd' + .db #0x00 ; 0 + .db #0x5f ; 95 + .db #0x00 ; 0 + .db #0x59 ; 89 'Y' + .db #0x00 ; 0 + .db #0x54 ; 84 'T' + .db #0x00 ; 0 + .db #0x50 ; 80 'P' + .db #0x00 ; 0 + .db #0x4b ; 75 'K' + .db #0x00 ; 0 + .db #0x47 ; 71 'G' + .db #0x00 ; 0 + .db #0x43 ; 67 'C' + .db #0x00 ; 0 + .db #0x3f ; 63 + .db #0x00 ; 0 + .db #0x3c ; 60 + .db #0x00 ; 0 + .db #0x38 ; 56 '8' + .db #0x00 ; 0 + .db #0x35 ; 53 '5' + .db #0x00 ; 0 + .db #0x32 ; 50 '2' + .db #0x00 ; 0 + .db #0x2f ; 47 + .db #0x00 ; 0 + .db #0x2d ; 45 + .db #0x00 ; 0 + .db #0x2a ; 42 + .db #0x00 ; 0 + .db #0x28 ; 40 + .db #0x00 ; 0 + .db #0x26 ; 38 + .db #0x00 ; 0 + .db #0x24 ; 36 + .db #0x00 ; 0 + .db #0x22 ; 34 + .db #0x00 ; 0 + .db #0x20 ; 32 + .db #0x00 ; 0 + .db #0x1e ; 30 + .db #0x00 ; 0 + .db #0x1c ; 28 + .db #0x00 ; 0 + .db #0x1b ; 27 + .db #0x00 ; 0 + .db #0x19 ; 25 + .db #0x00 ; 0 + .db #0x18 ; 24 + .db #0x00 ; 0 + .db #0x16 ; 22 + .db #0x00 ; 0 + .db #0x15 ; 21 + .db #0x00 ; 0 + .db #0x14 ; 20 + .db #0x00 ; 0 + .db #0x13 ; 19 + .db #0x00 ; 0 + .db #0x12 ; 18 + .db #0x00 ; 0 + .db #0x11 ; 17 + .db #0x00 ; 0 + .db #0x10 ; 16 + .db #0x00 ; 0 + .db #0x0f ; 15 + .db #0x00 ; 0 + .db #0x0e ; 14 + .db #0x00 ; 0 + .db #0x0d ; 13 + .db #0x00 ; 0 + .db #0x0d ; 13 + .db #0x00 ; 0 + .db #0x0c ; 12 + .db #0x00 ; 0 + .db #0x0b ; 11 + .db #0x00 ; 0 + .db #0x0b ; 11 + .db #0x00 ; 0 + .db #0x0a ; 10 + .db #0x00 ; 0 + .db #0x09 ; 9 + .db #0x00 ; 0 + .db #0x09 ; 9 + .db #0x00 ; 0 + .db #0x08 ; 8 + .db #0x00 ; 0 + .db #0x08 ; 8 + .db #0x00 ; 0 + .db #0x07 ; 7 + .db #0x00 ; 0 + .db #0x07 ; 7 + .db #0x00 ; 0 + .db #0x07 ; 7 + .db #0x00 ; 0 + .db #0x06 ; 6 + .db #0x00 ; 0 + .db #0x06 ; 6 + .db #0x00 ; 0 + .db #0x06 ; 6 + .db #0x00 ; 0 + .db #0x05 ; 5 + .db #0x00 ; 0 + .db #0x05 ; 5 + .db #0x00 ; 0 + .db #0x05 ; 5 + .db #0x00 ; 0 + .db #0x04 ; 4 + .db #0x00 ; 0 + .db #0x04 ; 4 + .db #0x00 ; 0 + .db #0x04 ; 4 + .db #0x00 ; 0 + .db #0x04 ; 4 + .db #0x00 ; 0 + .db #0x04 ; 4 + .db #0x00 ; 0 + .db #0x03 ; 3 + .db #0x00 ; 0 + .db #0x03 ; 3 + .db #0x00 ; 0 + .db #0x03 ; 3 + .db #0x00 ; 0 + .db #0x03 ; 3 + .db #0x00 ; 0 + .db #0x03 ; 3 + .db #0x00 ; 0 + .db #0x02 ; 2 + .db #0x00 ; 0 + .db #0x7d ; 125 + .db #0x87 ; 135 + .db #0x87 ; 135 + .db #0x87 ; 135 + .db #0x4f ; 79 'O' + .db #0x06 ; 6 + .db #0x00 ; 0 + .db #0x21 ; 33 + .db #0xde ; 222 + .db #0x0b ; 11 + .db #0x09 ; 9 + .db #0x7e ; 126 + .db #0x23 ; 35 + .db #0xb6 ; 182 + .db #0x6f ; 111 'o' + .db #0xc9 ; 201 + .area _INITIALIZER + .area _CABS (ABS) diff --git a/lib/plw/plw_player.c b/lib/plw/plw_player.c new file mode 100644 index 0000000..4ab2598 --- /dev/null +++ b/lib/plw/plw_player.c @@ -0,0 +1,3 @@ +#define LOCAL +#include "player/plw_player.h" + diff --git a/lib/plw/plw_stop.z80 b/lib/plw/plw_stop.z80 new file mode 100644 index 0000000..6bb3daf --- /dev/null +++ b/lib/plw/plw_stop.z80 @@ -0,0 +1,6 @@ +.globl _PLW_Stop + +PLY_LW_STOP = 0x0b06 + 0x6 + +_PLW_Stop:: + jp PLY_LW_STOP -- cgit v1.2.3