; SPECTRUM PSG proPLAYER V 0.2 - WYZ 07.09.2011 ; VER AL FINAL PARA DATOS PROPIOS: ; ISR LLAMA A: inicio: ld (vari+2), ix call rout ld hl, psg_reg ld de, psg_reg_sec ld bc, 14 ldir ld hl, interr bit 2, (hl) ;esta activado el efecto? jr z, finop2 ld hl,(PUNTERO_SONIDO) ld a,(hl) cp $ff jr z, finson ld (psg_reg_sec+2),a inc hl ld a,(hl) rrca rrca rrca rrca and 00001111b ld (psg_reg_sec+3),a ld a,(hl) and 00001111b ld (psg_reg_sec+9),a inc hl ld a,(hl) and a jr z, noruid ld (psg_reg_sec+6),a ld a, 10101000b jr siruid noruid ld a, 10111000b siruid ld (psg_reg_sec+7),a inc hl ld (PUNTERO_SONIDO),hl jr finopla finson ld hl, interr res 2, (hl) ld a, 10111000b ld (psg_reg+7), a ;play __________________________________________________ finopla ld hl, interr ;play bit 1 on? finop2 bit 1, (hl) ret z ;tempo inc l ; ld hl, ttempo ;contador tempo inc (hl) ld a, (tempo) sub (hl) jr nz, pautas ld (hl), a ;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 ;pauta canal c ; 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|ORNMT|VOL) - BYTE 2 ( | | | |PITCH/NOTA) pauta: bit 4, (hl) ;si la envolvente esta activada no actua pauta ret nz ld a, (iy+0) ld b, (iy+1) or b ret z push hl pcajp4: ld l, (ix+0) ld h, (ix+1) ld a, (hl) bit 7, a ;loop / el resto de bits no afectan jr z, pcajp0 and 00011111B ;máximo 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, (iy+0) ld d, (iy+1) and a rrc d rr e ld (iy+0), e ld (iy+1), d jr pcajp2 pcajp1: bit 5, a ;octava +1 jr z, pcajp2 ld e, (iy+0) ld d, (iy+1) and a rlc e rl d ld (iy+0), e ld (iy+1), d pcajp2: ld a, (hl) bit 4, a jr nz, pcajp6 ;ornamentos seleccionados inc hl ;funcion pitch de frecuencia push hl ld e, a ld a, (hl) ;pitch de frecuencia ld l, a and a ld a, e jr z, ornmj1 ld a, (iy+0) ;si la frecuencia es 0 no hay pitch add a, (iy+1) and a ld a, e jr z, ornmj1 bit 7, l jr z, ornneg ld h, $ff jr pcajp3 ornneg: ld h, 0 pcajp3: ld e, (iy+0) ld d, (iy+1) adc hl, de ld (iy+0), l ld (iy+1), h jr ornmj1 pcajp6: inc hl ;funcion ornamentos push hl push af ld a, (ix+24) ;recupera registro de nota en el canal ld e, (hl) adc a, e ;+- nota call tabla_notas pop af ornmj1: pop hl inc hl ld (ix+0), l ld (ix+1), h pcajp5: pop hl and 00001111B ;volumen final ld (hl), a ret ;carga una cancion ;in:(a)=nº de cancion cancio: ld hl, interr ;carga cancion set 1, (hl) ;reproduce cancion ld hl, song_1 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, $3f ;codigo intrumento 0 ld b, $ff ;el modulo debe tener una longitud menor de $ff00 ... o_o! bgicm1: 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, bgicm1 ld (puntero_p_decb), hl bgicm2: 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, bgicm2 ld (puntero_p_decc), hl bgicm3: 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, bgicm3 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 00000001B ;ES SILENCIO? JR NZ,NO_SILENCIO SET 6,A JR NO_MODIFICA NO_SILENCIO: CP 00111110B ;ES PUNTILLO? JR NZ,NO_PUNTILLO OR A RRC B XOR A JR NO_MODIFICA NO_PUNTILLO: CP 00111111B ;ES COMANDO? JR NZ,NO_MODIFICA BIT 0,B ;COMADO=INSTRUMENTO? JR Z,NO_INSTRUMENTO LD A,11000001B ;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,11000100B ;CODIGO ENVOLVENTE LD (DE),A INC DE INC HL LD A,(HL) LD (DE),A INC DE INC HL JR decode_canal NO_ENVOLVENTE: BIT 1,B JR Z,NO_MODIFICA LD A,11000010B ;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 00111111B PUSH AF LD A,B AND 11000000B RLCA RLCA INC A LD B,A LD A,10000000B DCBC0: RLCA DJNZ DCBC0 LD B,A POP AF RET ;LOCALIZA NOTA CANAL A ;IN (puntero_a) localiza_nota: LD L,(IX) ;HL=(PUNTERO_A_C_B) LD H,(IX+1) LD A,(HL) AND 11000000B ;COMANDO? CP 11000000B 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 (IX),L LD (IX+1),H LD HL,TABLA_PAUTAS CALL ext_word LD (IX+PUNTERO_P_A0-puntero_a),L LD (IX+PUNTERO_P_A0-puntero_a+1),H LD (IX+puntero_p_a-puntero_a),L LD (IX+puntero_p_a-puntero_a+1),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 (IX),L LD (IX+1),H ;INICIA EL SONIDO Nº (A) INICIA_SONIDO: LD HL,TABLA_SONIDOS CALL ext_word LD (PUNTERO_SONIDO),HL LD HL,interr SET 2,(HL) RET COM_ENVOLVENTE: BIT 2,A RET Z ;IGNORA - ERROR INC HL LD A,(HL) ;CARGA CODIGO DE ENVOLVENTE LD (ENVOLVENTE),A INC HL LD (IX),L LD (IX+1),H LD L,C LD H,B LD (HL),00010000B ;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,(IX+canal_a-puntero_a) LD D,(IX+canal_a-puntero_a+1) ;PUNTERO BUFFER AL INICIO LD (IX),E LD (IX+1),D LD L,(IX+puntero_deca-puntero_a) ;CARGA PUNTERO DECODER LD H,(IX+puntero_deca-puntero_a+1) PUSH BC CALL decode_canal ;DECODIFICA CANAL POP BC LD (IX+puntero_deca-puntero_a),L ;GUARDA PUNTERO DECODER LD (IX+puntero_deca-puntero_a+1),H JP localiza_nota FIN_CANAL_A: LD HL,interr ;LOOP? BIT 4,(HL) JR NZ,FCA_CONT poff: xor a ld (interr), a ld hl, psg_reg ld de, psg_reg+1 ld bc, 14*2-1 ld (hl), a ldir rout: ld de, $ffc0 ld bc, $fffe ld hl, psg_reg_sec+13 xor a cpd jr nz, qout sout: ld a, 12 lout: out (c), a ld b, e outd ld b, d dec a jp p, lout ret qout: ld a, 13 out (c), a inc l ld b, e outd xor a ld (psg_reg_sec+13), a ld (psg_reg+13), a jr sout FCA_CONT: LD L,(IX+puntero_p_deca-puntero_a) ;CARGA PUNTERO INICIAL DECODER LD H,(IX+puntero_p_deca-puntero_a+1) LD (IX+puntero_deca-puntero_a),L LD (IX+puntero_deca-puntero_a+1),H JR FIN_NOTA_A NO_FIN_CANAL_A: LD (IX),L ;(PUNTERO_A_B_C)=HL GUARDA PUNTERO LD (IX+1),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 00010000B JR NZ,SILENCIO_ENVOLVENTE XOR A LD (BC),A ;RESET VOLUMEN DEL CORRESPODIENTE CHIP LD (IY+0),A LD (IY+1),A RET SILENCIO_ENVOLVENTE: LD A,$FF LD (psg_reg+11),A LD (psg_reg+12),A XOR A LD (psg_reg+13),A LD (IY+0),A LD (IY+1),A RET NO_SILENCIO_A: LD (IX+REG_NOTA_A-puntero_a),A ;REGISTRO DE LA NOTA DEL CANAL CALL NOTA ;REPRODUCE NOTA LD L,(IX+PUNTERO_P_A0-puntero_a) ;HL=(PUNTERO_P_A0) RESETEA PAUTA LD H,(IX+PUNTERO_P_A0-puntero_a+1) LD (IX+puntero_p_a-puntero_a),L ;(PUNTERO_P_A)=HL LD (IX+puntero_p_a-puntero_a+1),H FIN_RUTINA: RET ;LOCALIZA EFECTO ;IN HL=(PUNTERO_P) localiza_efecto: LD L,(IX+0) ;HL=(PUNTERO_P) LD H,(IX+1) LD A,(HL) CP 11000010B JR NZ,LEJP0 INC HL LD A,(HL) INC HL LD (IX+00),L LD (IX+01),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 (IX+0),E LD (IX+1),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 (IX+0),L ;(PUNTERO_A_B_C)=HL GUARDA PUNTERO LD (IX+1),H RET ;NOTA : REPRODUCE UNA NOTA ;IN (A)=CODIGO DE LA NOTA ; (IY)=REGISTROS DE FRECUENCIA NOTA: LD L,C LD H,B BIT 4,(HL) LD B,A JR NZ,ENVOLVENTES LD A,B tabla_notas: LD HL,DATOS_NOTAS ;BUSCA FRECUENCIA CALL ext_word LD (IY+0),L LD (IY+1),H RET ;IN (A)=CODIGO DE LA ENVOLVENTE ; (IY)=REGISTRO DE FRECUENCIA ENVOLVENTES: LD HL,DATOS_NOTAS ;BUSCA FRECUENCIA CALL ext_word LD A,(ENVOLVENTE) ;FRECUENCIA DEL CANAL ON/OFF LOCALIZA_ENV: RRA JR FRECUENCIA_OFF LD (IY+0),L LD (IY+1),H JR CONT_ENV FRECUENCIA_OFF: LD HL,$0000 LD (IY+0),L LD (IY+1),H ;CALCULO DEL RATIO (OCTAVA ARRIBA) CONT_ENV: PUSH AF PUSH BC AND 00000011B LD B,A INC B XOR A OCTBC01: ADD A,12 ;INCREMENTA OCTAVAS DJNZ OCTBC01 POP BC ;RECUPERA CODIGO DE LA NOTA ADD A,B ;EN REGISTRO A CODIGO NOTA LD HL,DATOS_NOTAS ;BUSCA FRECUENCIA CALL ext_word LD A,L LD (psg_reg+11),A LD A,H AND 00000011B LD (psg_reg+12),A POP AF ;SELECCION FORMA DE ENVOLVENTE RRA AND 00000110B ;$08,$0A,$0C,$0E ADD A,8 LD (psg_reg+13),A RET ;EXTRAE UN WORD DE UNA TABLA ;IN:(HL)=DIRECCION TABLA ; (A)= POSICION ;OUT(HL)=WORD ext_word: LD D,0 RLCA LD E,A ADD HL,DE LD E,(HL) INC HL LD D,(HL) EX DE,HL RET ; VARIABLES__________________________ interr: defb 00 ;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 ttempo: defb 00 ;DB CONTADOR TEMPO tempo: defb 00 ;DB TEMPO puntero_a: defw 00 ;DW PUNTERO DEL CANAL A puntero_b: defw 00 ;DW PUNTERO DEL CANAL B puntero_c: defw 00 ;DW PUNTERO DEL CANAL C canal_a: defw buffers_canales ;DW DIRECION DE INICIO DE LA MUSICA A canal_b: defw buffers_canales+$30 ;DW DIRECION DE INICIO DE LA MUSICA B canal_c: defw buffers_canales+$60 ;DW DIRECION DE INICIO DE LA MUSICA C puntero_p_a: defw 00 ;DW PUNTERO PAUTA CANAL A puntero_p_b: defw 00 ;DW PUNTERO PAUTA CANAL B puntero_p_c: defw 00 ;DW PUNTERO PAUTA CANAL C PUNTERO_P_A0: defw 00 ;DW INI PUNTERO PAUTA CANAL A PUNTERO_P_B0: defw 00 ;DW INI PUNTERO PAUTA CANAL B PUNTERO_P_C0: defw 00 ;DW INI PUNTERO PAUTA CANAL C puntero_p_deca: defw 00 ;DW PUNTERO DE INICIO DEL DECODER CANAL A puntero_p_decb: defw 00 ;DW PUNTERO DE INICIO DEL DECODER CANAL B puntero_p_decc: defw 00 ;DW PUNTERO DE INICIO DEL DECODER CANAL C puntero_deca: defw 00 ;DW PUNTERO DECODER CANAL A puntero_decb: defw 00 ;DW PUNTERO DECODER CANAL B puntero_decc: defw 00 ;DW PUNTERO DECODER CANAL C REG_NOTA_A: defb 00 ;DB REGISTRO DE LA NOTA EN EL CANAL A defb 00 ;VACIO REG_NOTA_B: defb 00 ;DB REGISTRO DE LA NOTA EN EL CANAL B defb 00 ;VACIO REG_NOTA_C: defb 00 ;DB REGISTRO DE LA NOTA EN EL CANAL C defb 00 ;VACIO ;CANAL DE EFECTOS - ENMASCARA OTRO CANAL puntero_p: defw 00 ;DW PUNTERO DEL CANAL EFECTOS canal_p: defw buffers_canales+$90 ;DW DIRECION DE INICIO DE LOS EFECTOS puntero_p_decp: defw 00 ;DW PUNTERO DE INICIO DEL DECODER CANAL P puntero_decp: defw 00 ;DW PUNTERO DECODER CANAL P psg_reg: defs 14 ;DB (11) BUFFER DE REGISTROS DEL PSG psg_reg_sec: defs 14 ;DB (11) BUFFER SECUNDARIO DE REGISTROS DEL PSG ;ENVOLVENTE_A EQU $D033 ;DB ;ENVOLVENTE_B EQU $D034 ;DB ;ENVOLVENTE_C EQU $D035 ;DB ;EFECTOS DE SONIDO N_SONIDO: defb 0 ;DB : NUMERO DE SONIDO PUNTERO_SONIDO: defw 0 ;DW : PUNTERO DEL SONIDO QUE SE REPRODUCE ;EFECTOS N_EFECTO: defb 0 ;DB : NUMERO DE SONIDO PUNTERO_EFECTO: defw 0 ;DW : PUNTERO DEL SONIDO QUE SE REPRODUCE CANAL_EFECTOS: defb 1 ; CANAL DE SFX ENVOLVENTE: defb 0 ;DB : FORMA DE LA ENVOLVENTE ;BIT 0 : FRECUENCIA CANAL ON/OFF ;BIT 1-2 : RATIO ;BIT 3-3 : FORMA ;BUFFER_DEC: defb $00 ;************************* mucha atencion!!!! ; aqui se decodifica la cancion hay que dejar suficiente espacio libre. ;************************* ;; INCLUIR LOS DATOS DE LA MUSICA (PATTERNS/EFFECTS) include song.mus.asm song_1 incbin song1.mus ;; NADA A PARTIR DE AQUI!!! buffers_canales: