;XX!! WYZPLAYER START  

; CONSTANTES PARA EL PLAYER.

; DATOS POR CANAL:

; PUNTERO_CANAL                 EQU 0
; PUNTERO_BUFFER_DEC            EQU 2
; PUNTERO_PAUTA                 EQU 4
; PUNTERO_INICIO_PAUTA          EQU 6
; PUNTERO_POS_DEC               EQU 8
; PUNTERO_INICIO_DEC_CANAL      EQU 10
; REG_NOTA_CANAL                EQU 12
; VOL_INST_CANAL                EQU 13
; PUNTERO_LOOP_DEC_CANAL        EQU 14

; CANAL_STRUCT_SIZE             EQU 16

; EL DESARROLLADOR DEBE DECLARAR EL SIMBOLO WYZ_PLAYER_BUFFER, CON UN BUFFER DE
; TAMAÑO SUFICIENTE. (ver RAM.ASM)

HYBRID          EQU     $cc00   ;WYZ_PLAYER_BUFFER  ;TEMPO HIBRIDO
                                            ;BIT 7 = HYBRID ON/OFF
                                            ;BIT 6 = ALTERNADOR

INTERR          EQU     $cc01          ;INTERRUPTORES 1=ON 0=OFF
                                            ;BIT 0=CARGA CANCION ON/OFF
                                            ;BIT 1=PLAYER ON/OFF
                                            ;BIT 2=EFECTOS ON/OFF
                                            ;BIT 3=SFX ON/OFF
                                            ;BIT 4=LOOP

SONG            EQU     $cc02          ;DB NUM DE CANCION
TEMPO           EQU     $cc03           ;DB TEMPO
TTEMPO          EQU     $cc04           ;DB CONTADOR TEMPO

PUNTERO_A       EQU     $cc05          ;DW PUNTERO DEL CANAL A
PUNTERO_B       EQU     $cc07       ;DW PUNTERO DEL CANAL B
PUNTERO_C       EQU     $cc09       ;DW PUNTERO DEL CANAL C

CANAL_A         EQU     $cc0b      ;DW DIRECION DE INICIO DE LA MUSICA A
CANAL_B         EQU     $cc0d         ;DW DIRECION DE INICIO DE LA MUSICA B
CANAL_C         EQU     $cc0f         ;DW DIRECION DE INICIO DE LA MUSICA C

PUNTERO_P_A     EQU     $cc11        ;DW PUNTERO PAUTA CANAL A
PUNTERO_P_B     EQU     $cc13     ;DW PUNTERO PAUTA CANAL B
PUNTERO_P_C     EQU     $cc15     ;DW PUNTERO PAUTA CANAL C

PUNTERO_P_A0    EQU     $cc17     ;DW INI PUNTERO PAUTA CANAL A
PUNTERO_P_B0    EQU     $cc19    ;DW INI PUNTERO PAUTA CANAL B
PUNTERO_P_C0    EQU     $cc1b    ;DW INI PUNTERO PAUTA CANAL C

PUNTERO_P_DECA  EQU     $cc1d    ;DW PUNTERO DE INICIO DEL DECODER CANAL A
PUNTERO_P_DECB  EQU     $cc1f  ;DW PUNTERO DE INICIO DEL DECODER CANAL B
PUNTERO_P_DECC  EQU     $cc21  ;DW PUNTERO DE INICIO DEL DECODER CANAL C

PUNTERO_DECA    EQU     $cc23  ;DW PUNTERO DECODER CANAL A
PUNTERO_DECB    EQU     $cc25    ;DW PUNTERO DECODER CANAL B
PUNTERO_DECC    EQU     $cc27    ;DW PUNTERO DECODER CANAL C

REG_NOTA_A      EQU     $cc29    ;DB REGISTRO DE LA NOTA EN EL CANAL A
VOL_INST_A      EQU     $cc2a      ;DB VOLUMEN RELATIVO DEL INSTRUMENTO DEL CANAL A
REG_NOTA_B      EQU     $cc2b      ;DB REGISTRO DE LA NOTA EN EL CANAL B
VOL_INST_B      EQU     $cc2c      ;DB VOLUMEN RELATIVO DEL INSTRUMENTO DEL CANAL B          ;VACIO
REG_NOTA_C      EQU     $cc2d      ;DB REGISTRO DE LA NOTA EN EL CANAL C
VOL_INST_C      EQU     $cc2e      ;DB VOLUMEN RELATIVO DEL INSTRUMENTO DEL CANAL C

PUNTERO_L_DECA  EQU     $cc2f      ;DW PUNTERO DE INICIO DEL LOOP DEL DECODER CANAL A
PUNTERO_L_DECB  EQU     $cc31  ;DW PUNTERO DE INICIO DEL LOOP DEL DECODER CANAL B
PUNTERO_L_DECC  EQU     $cc33  ;DW PUNTERO DE INICIO DEL LOOP DEL DECODER CANAL C

;CANAL DE EFECTOS DE RITMO - ENMASCARA OTRO CANAL
PUNTERO_P       EQU     $cc35  ;DW PUNTERO DEL CANAL EFECTOS
CANAL_P         EQU     $cc37       ;DW DIRECION DE INICIO DE LOS EFECTOS
PUNTERO_P_DECP  EQU     $cc39         ;DW PUNTERO DE INICIO DEL DECODER CANAL P
PUNTERO_DECP    EQU     $cc3b  ;DW PUNTERO DECODER CANAL P
PUNTERO_L_DECP  EQU     $cc3d    ;DW PUNTERO DE INICIO DEL LOOP DEL DECODER CANAL P
;SELECT_CANAL_P  EQU      WYZ_PLAYER_BUFFER + $36    ;DB SELECCION DE CANAL DE EFECTOS DE RITMO

SFX_L           EQU     $cc3f  ;DW DIRECCION BUFFER EFECTOS DE RITMO REGISTRO BAJO
SFX_H           EQU     $cc41          ;DW DIRECCION BUFFER EFECTOS DE RITMO REGISTRO ALTO
SFX_V           EQU     $cc43           ;DW DIRECCION BUFFER EFECTOS DE RITMO REGISTRO VOLUMEN
SFX_MIX         EQU     $cc45           ;DW DIRECCION BUFFER EFECTOS DE RITMO REGISTRO MIXER

;EFECTOS DE SONIDO
N_SONIDO        EQU     $cc47         ;DB NUMERO DE SONIDO
PUNTERO_SONIDO  EQU     $cc48        ;DW PUNTERO DEL SONIDO QUE SE REPRODUCE

; DB [13] BUFFERs DE REGISTROS DEL PSG 
; NOTA AUGUSTO: EL BUFFER ES REALMENTE DE 16 BYTES, 
; Y SE USAN 14 EN EL PLAYER. DOS BYTES RESERVADOS.

PSG_REG         EQU     $cc4a
PSG_REG_SEC     EQU     $cc5a
ENVOLVENTE      EQU     $cc6a    ; DB : FORMA DE LA ENVOLVENTE
                                            ; BIT 0  : FRECUENCIA CANAL ON/OFF
                                            ; BIT 1-2  : RATIO 
                                            ; BIT 3-3  : FORMA

ENVOLVENTE_BACK EQU     $cc6b      ; DB:  BACKUP DE LA FORMA DE LA ENVOLENTE
BUFFER_DEC      EQU     $cc6c ; 128 BYTES. BUFFER DE DECODIFICACIÓN

; TAMAÑO TOTAL DEL BUFFER
WYZ_PLAYER_BUFFER_SIZE  EQU     $ec ;BUFFER_DEC + 128 - WYZ_PLAYER_BUFFER





; CODIGO ESPECIFICO PARA MSX.
; ESTE DEBERIA SER EL CÓDIGO A COMPILAR



; VUELCA BUFFER DE SONIDO AL AY.
ROUT:
    ;; COMPRUEBA SI ESTÁ LA ENVOLVENTE ACTIVA, Y SI HAY QUE ALMACENARLA
    LD      A, (PSG_REG + 13)
    AND     A                                   ; ES CERO?
    JR      Z, NO_BACKUP_ENVOLVENTE
    LD      (ENVOLVENTE_BACK), A	              ; 08.13 / GUARDA LA ENVOLVENTE EN EL BACKUP

NO_BACKUP_ENVOLVENTE:
    XOR     A                                   ; INDICE DEL REGISTRO DEL PSG A ESCRIBIR
    LD      C, $A0                              ; PUERTO DE SELECCION DE REGISTRO
    LD      HL, PSG_REG_SEC                     ; DIRECCION DE LOS DATOS A ENVIAR AL PSG
LOUT:
    OUT     (C), A                              ; SELECCIONA EL REGISTRO DEL PSG
    INC     C                                   ; APUNTA AL PUERTO DE ESCRITURA
    OUTI                                        ; ESCRIBE EL DATO UBICADO EN (HL) EN EL REGISTRO SELECCIONADO, INCREMENTA HL
    DEC     C                                   ; APUNTA AL PUERTO DE SELECCION DE REGISTRO
    INC     A                                   ; SIGUIENTE REGISTRO
    CP      13                                  ; COMPRUEBA SI YA HEMOS ENVIADO TODOS LOS DATOS
    JR      NZ, LOUT                            ; SI NO ES ASÍ, ESCRIBIMOS EL SIGUIENTE

    OUT     (C), A                              ; SELECCIONAMOS EL REGISTRO 13
    LD      A, (HL)                             ; LEEMOS EL DATO DEL REGISTRO 13 (FRECUENCIA DE ENVOLVENTE)
    AND     A
    RET     Z                                   ; PERO SOLO SE ESCRIBE SI NO ES 0.
    INC     C                                   ; SELECCIONAMOS EL PUERTO DE ESCRITURA
    OUT     (C), A                              ; ENVIAMOS EL DATO
    XOR     A
    LD      (PSG_REG_SEC+13), A                 ; RESETEAMOS EL DATO DEL REGISTRO 13 EN LOS BUFFER
    LD      (PSG_REG+13), A
    RET






;VARIABLES DEL SISTEMA


VERSION         EQU     $002B           ;NACIONALIDAD DEL MSX

;CLICKSW      	EQU	$F3DB		;KEYCLICK
;HOOK_A          EQU     $FD9A		;CONTROL DE LAS INTERRUPCIONES
;HOOK_F          EQU     $FD9F		;CONTROL DE LAS INTERRUPCIONES



; MSX PSG proPLAYER V 0.50 - WYZ 03.06.2022
; ADAPTADO A MULTISISTEMA POR AugustoRuiz
; ENSAMBLAR CON AsMSX o GENERAR PARA OTROS ENSAMBLADORES USANDO genasm.py

; CARACTERISTICAS
; 5 OCTAVAS:            O(2-6)=60 NOTAS
; 4 LONGITUDES DE NOTA: L(0-3)+PUNTILLO 

; LOS DATOS QUE HAY QUE VARIAR :
; * NUM DE CANCION. 
; * TABLA DE CANCIONES

; MUSICA 
; **** EL ORDEN DE LAS VARIABLES ES FIJO ******

; EL CODIGO ES REUBICABLE, Y EL BUFFER DE DECODIFICACIÓN TAMBIÉN.

; EL DESARROLLADOR DEBE DETERMINAR LA UBICACIÓN DEL BUFFER EN RAM.
; PARA QUE ESTE CODIGO VALGA PARA CARTUCHOS, SE USAN CONSTANTES QUE APUNTAN 
; A LA UBICACION DE DICHAS VARIABLES.

;TABLA DE DATOS DEL SELECTOR DEL CANAL DE EFECTOS DE RITMO
TABLA_DATOS_CANAL_SFX:
    DW  SELECT_CANAL_A,SELECT_CANAL_B,SELECT_CANAL_C

; BYTE 0: SFX_L
; BYTE 1: SFX_H
; BYTE 2: SFX_V
; BYTE 3: SFX_MIX
SELECT_CANAL_A:  DW  PSG_REG_SEC+0,PSG_REG_SEC+1,PSG_REG_SEC+8
    DB  10110001B
    ;DB  10110000B
    
SELECT_CANAL_B:  DW  PSG_REG_SEC+2,PSG_REG_SEC+3,PSG_REG_SEC+9
    DB  10101010B
    ;DB  10101000B
    
SELECT_CANAL_C:  DW  PSG_REG_SEC+4,PSG_REG_SEC+5,PSG_REG_SEC+10
    DB  10011100B
    ;DB  10011000B

;; INICIALIZA EL PLAYER. PARA EL PLAYER SI ESTABA EJECUTÁNDOSE, 
;; Y HACE QUE LOS PUNTEROS DE DECODIFICACIÓN SE INICIALICEN
;; PARA Y HABILITA LAS INTERRUPCIONES.

;XX!! WYZPLAYER OFF

WYZ_PLAYER_INIT:
    DI
    CALL    PLAYER_OFF          ;; PARA EL REPRODUCTOR.

; MUSICA DATOS INICIALES
    LD      HL, BUFFER_DEC      ;; INICIALIZA EL BUFFER DE DECODIFICACION
    LD      DE, $20             ;; TAMAÑO DEL BUFFER PARA CADA CANAL (32 BYTES)
    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
    EI
    RET

;; FUNCION A LLAMAR EN CADA INTERRUPCION PARA QUE AVANCE UN PASO.
WYZ_PLAYER_TICK:

;XX!! WYZPLAYER LOOP  

INICIO:
    ; VUELCA A LOS REGISTROS DEL PSG
    CALL    ROUT
    ; REPRODUCE UN PASO DE LOS CANALES
    CALL    PLAY
    ; HACE COPIA DEL RESULTADO DE LA REPRODUCCION
    LD      HL, PSG_REG
    LD      DE, PSG_REG_SEC
    LD      BC, 14
    LDIR
    ; REPRODUCE LA PERCUSION, MACHACANDO UN CANAL
    CALL    REPRODUCE_PERCUSION
    ;; REPRODUCE SFX (SI LOS HAY)
    ;CALL   REPRODUCE_EFECTO
    RET

; REPRODUCE EFECTOS DE SONIDO. 
; EL FORMATO DE PERCUSIÓN SON GRUPOS DE TRES BYTES:
; BYTE 1: 
;   BYTE BAJO DE LA FRECUENCIA (O FIN SI ES $FF)
; BYTE 2: 
;   BITS 4-7: BYTE ALTO DE LA FRECUENCIA (0-15).
;   BITS 0-3: VOLUMEN (0-15)
; BYTE 3:
;   BIT 7: INDICA QUE SE USARÁ ENVOLVENTE.
;   BITS 0-6: RUIDO
; SI HAY ENVOLVENTE EN EL BYTE 3, SE LEEN 3 BYTES MÁS
; BYTE 4:
;   BYTE BAJO DE LA FRECUENCIA DE ENVOLVENTE.
; BYTE 5:
;   BITS 4-7: BYTE ALTO DE LA FRECUENCIA DE ENVOLVENTE (0-15).
; BYTE 6:
;   TIPO DE ENVOLVENTE A UTILIZAR.
REPRODUCE_PERCUSION:
    LD      HL, INTERR   
    BIT     2, (HL)                   ; ESTA ACTIVADA LA PERCUSION?
    RET     Z
    LD      HL, (PUNTERO_SONIDO)
    LD      A, (HL)                   ; LEEMOS EL SIGUIENTE BYTE DEL CANAL DE PERCUSION (FREC. BAJA O FIN)
    CP      $FF                       ; SI ES $FF, ES EL FIN DE LA PERCUSION
    JR      Z, FIN_SONIDO
    LD      DE, (SFX_L)               ; SI NO, LEEMOS LA DIRECCION DE MEMORIA DONDE CARGAR LA FRECUENCIA BAJA
    LD      (DE), A                   ; Y GUARDAMOS LA FRECUENCIA QUE ACABAMOS DE LEER
    INC     HL                        ; APUNTAMOS AL SIGUIENTE BYTE
    LD      A, (HL)                   ; Y LO LEEMOS
    RRCA                              ; ROTAMOS 4 BITS (CAMBIAMOS LOS NIBBLES DE SITIO)
    RRCA
    RRCA
    RRCA
    AND     00001111B                 ; NOS QUEDAMOS CON EL NIBBLE BAJO 
    LD      DE, (SFX_H)
    LD      (DE), A                   ; Y LO GUARDAMOS EN LA FRECUENCIA ALTA
    LD      A, (HL)                   ; VOLVEMOS A LEER EL MISMO BYTE
    AND     00001111B                 ; Y NOS QUEDAMOS CON EL NIBBLE BAJO
    LD      DE, (SFX_V)
    LD      (DE),A                    ; Y LO GUARDAMOS EN EL VOLUMEN
    INC     HL                        ; APUNTAMOS AL SIGUIENTE BYTE
    LD      A, (HL)                   ; Y LO LEEMOS
    LD      B, A                      ; COPIAMOS EL BYTE 3 EN B
    BIT     7, A                      ; 09.08.13 BIT MAS SIGINIFICATIVO ACTIVA ENVOLVENTES
    JR      Z, NO_ENVOLVENTES_SONIDO  ; COMPROBAMOS SI HAY ENVOLVENTE
    LD      A, $12                    ; SI HAY ENVOLVENTE, FIJAMOS EL VOLUMEN EN $12
    LD      (DE), A
    INC     HL                        ; Y LEEMOS LOS SIGUIENTES TRES BYTES.
    LD      A, (HL)                   ; 
    LD      (PSG_REG_SEC+11), A       ; FRECUENCIA BAJA DE LA ENVOLVENTE
    INC     HL                        ; 
    LD      A, (HL)                   ; 
    LD      (PSG_REG_SEC+12), A       ; FRECUENCIA ALTA DE LA ENVOLVENTE
    INC     HL                        ; 
    LD      A, (HL)                   ;
    CP      1                         ; SI EL TERCER VALOR ES 1, ES QUE HAY QUE CONTINUAR 
    JR      Z, NO_ENVOLVENTES_SONIDO  ; CON EL VALOR PREVIO DE TIPO DE ENVOLVENTE
    LD      (PSG_REG_SEC+13), A       ; SI ES OTRO VALOR, CAMBIA EL TIPO DE ENVOLVENTE.

NO_ENVOLVENTES_SONIDO:
    LD      A, B                      ; RECUPERAMOS EL VALOR DEL RUIDO, Y
    AND     $7F                       ; LIMPIAMOS EL BIT MAS ALTO
    LD      (PSG_REG_SEC+6), A        ; GUARDAMOS EL VALOR EN EL REGISTRO 6
    JR      Z, NO_RUIDO               ; 
    LD      A, (SFX_MIX)              ; LEEMOS EL VALOR DE LA MEZCLA DE EFECTOS
    JR      SI_RUIDO
NO_RUIDO:
    LD      A, 10111000B              ; DESHABILITAMOS EL RUIDO PARA QUE DEJE DE SONAR
SI_RUIDO:
    LD      (PSG_REG_SEC+7), A        ; GUARDAMOS EL VALOR DE LA MEZCLA DE EFECTOS
    INC     HL                        ; APUNTAMOS AL SIGUIENTE BYTE
    LD      (PUNTERO_SONIDO),HL       ; Y LO GUARDAMOS EN EL PUNTERO DEL CANAL DE PERCUSION PARA LA SIGUIENTE.
    RET                               ; Y TERMINAMOS

FIN_SONIDO:                           ; SI HA TERMINADO LA PERCUSION
    LD      HL, INTERR                ; LIMPIAMOS EL BIT DE PERCUSION ACTIVA
    RES     2, (HL)
    LD      A, (ENVOLVENTE_BACK)      ; COMPROBAMOS SI LA ENVOLVENTE ESTABA ACTIVA EN EL RESTO DE CANALES
    AND     A
    JR      Z, FIN_NOPLAYER
    LD      (PSG_REG_SEC+13), A       ; Y SI ESTABA ACTIVA, LA RESTAURAMOS
FIN_NOPLAYER:
    LD      A, 10111000B              ; HA TERMINADO LA PERCUSION
    LD      (PSG_REG_SEC+7),A         ; QUITAMOS EL RUIDO DEL MIXER
    RET                               ; Y TERMINAMOS

;INICIA EL SONIDO NUM (A)
INICIA_PERCUSION:  
    ; CP  19    ;SFX SPEECH
    ; JP  NC,SET_SAMPLE_P  

    LD      HL, ($CD02) ;TABLA_SONIDOS         ; BUSCAMOS LA PERCUSION A EN LA TABA DE SONIDOS
    CALL    EXT_WORD
    LD      (PUNTERO_SONIDO), HL      ; INICIALIZAMOS EL PUNTERO A PERCUSION
    LD      HL, INTERR
    SET     2, (HL)                   ; Y MARCAMOS EL BIT DE PERCUSION ACTIVA
    RET

;PLAYER OFF
PLAYER_OFF:
    XOR     A                         ; ***** IMPORTANTE SI NO HAY MUSICA ****
    LD      (INTERR),A                ; PONE TODOS LOS BITS DE ESTADO A 0
    ;LD     (FADE),A                  ; SOLO SI HAY FADE OUT

CLEAR_PSG_BUFFER:                     ; LIMPIAMOS EL BUFFER DE REGISTROS DEL PSG
    LD      HL, PSG_REG               ; A SIGUE SIENDO 0
    LD      DE, PSG_REG+1
    LD      BC, 14
    LD      (HL), A                   ; PONEMOS EL PRIMER BYTE A 0
    LDIR                              ; Y LO COPIAMOS AL RESTO DEL BUFFER
    
    LD      A, 10111000B              ; **** POR SI ACASO ****
    LD      (PSG_REG+7), A            ; DESACTIVAMOS EL RUIDO EN EL MIXER
    
    LD      HL, PSG_REG               ; COPIAMOS LOS REGISTROS A LOS SECUNDARIOS
    LD      DE, PSG_REG_SEC
    LD      BC, 14
    LDIR

    CALL    ROUT                      ; ESCRIBIMOS EL BUFFER AL PSG
    RET

;CARGA UNA CANCION
;IN:(A)=NUM. DE CANCION
WYZ_PLAYER_LOAD_SONG:
CARGA_CANCION:
    LD      HL, INTERR                ;
    SET     1, (HL)                   ; PONEMOS A 1 EL BIT DE CARGA DE CANCION
    LD      HL, SONG
    LD      (HL), A                   ; GUARDAMOS QUE CANCION ESTAMOS TOCANDO
    LD      HL, TABLA_SONG            ; OBTENEMOS LA DIRECCION DE LA CANCION DE LA TABLA DE CANCIONES
    CALL    EXT_WORD

; HEADER BYTE 0
; (      7       |  6-0  )
; ( HYBRID TEMPO | TEMPO )
    LD      A, (HL)                   ; BYTE 0: TEMPO
    AND     01111111B                 ; QUITAMOS EL BIT MAS ALTO
    LD      (TEMPO), A                ; GUARDAMOS EL TEMPO DE LA CANCION
    DEC     A
    LD      (TTEMPO), A               ; INICIALIZAMOS EL CONTADOR DE TICKS
    LD      A, (HL)                   ; VOLVEMOS A LEER EL TEMPO
    AND     10000000B                 ; SI TIENE EL BIT MAS ALTO ACTIVO, USA TEMPO HIBRIDO
    LD      (HYBRID), A               ; LO ALMACENAMOS

;HEADER BYTE 1
;(-|-|-|-|  2-1 | 0  )
;(-|-|-|-|FX CHN|LOOP)
    INC     HL
    LD      A, (HL)                   ; LEEMOS EL BYTE 1 (LOOP, FX CHANNEL)
    BIT     0, A
    JR      Z, DECOD_CANAL_PERCUSION  ; SI NO HAY LOOP, PASAMOS A LA SELECCION DEL CANAL
    EX      DE, HL                    ; AHORA TENEMOS EN DE EL PUNTERO A LA CANCION, Y EN HL LA DIRECCION DE INTERR
    LD      HL, INTERR                ;
    SET     4, (HL)                   ; ESTABLECEMOS EL BIT DE LOOP
    EX      DE, HL                    ; AHORA TENEMOS EN DE LA DIRECCIÓN DE INTERR, Y EN HL EL PUNTERO A LA CANCION

;SELECCION DEL CANAL DE EFECTOS DE RITMO
DECOD_CANAL_PERCUSION:
    AND     00000110B                 ; NOS QUEDAMOS CON LOS BITS DE SELECCION DE CANAL DE PERCUSION
    RRA                               ; LOS PONEMOS EN LOS BITS MAS BAJOS

    PUSH    HL                        ; GUARDAMOS POR DONDE VAMOS EN LA CANCION
    LD      HL,TABLA_DATOS_CANAL_SFX
    CALL    EXT_WORD                  ; SACAMOS LA CONFIGURACION DE REGISTROS PARA EL CANAL SELECCIONADO
    PUSH    HL                        ; GUARDAMOS LA DIRECCION DE LA CONFIGURACIÓN
    POP     IX                        ; Y LA PONEMOS EN IX
    LD      E,(IX + 0)                ; LEEMOS LA DIRECCION DE MEMORIA DEL REGISTRO DONDE GUARDAR SFX_L
    LD      D,(IX + 1)                ; DE LA TABLA DE CONFIGURACIÓN DE PERCUSIONES
    LD      (SFX_L),DE                ; Y LO ALMACENAMOS

    LD      E, (IX + 2)               ; LEEMOS LA DIRECCION DE MEMORIA DEL REGISTRO DONDE GUARDAR SFX_H
    LD      D, (IX + 3)               ; DE LA TABLA DE CONFIGURACIÓN DE PERCUSIONES
    LD      (SFX_H), DE               ; Y LO ALMACENAMOS

    LD      E, (IX + 4)               ; LEEMOS LA DIRECCION DE MEMORIA DEL REGISTRO DONDE GUARDAR SFX_V
    LD      D, (IX + 5)               ; DE LA TABLA DE CONFIGURACION DE PERCUSIONES
    LD      (SFX_V), DE               ; Y LO ALMACENAMOS

    LD      A,(IX + 6)                ; LEEMOS EL BYTE DEL MIXER
    LD      (SFX_MIX), A              ; Y LO ALMACENAMOS
    POP     HL                        ; RECUPERAMOS POR DONDE VAMOS EN LA CANCION (SEGUIMOS EN EL BYTE DE LOOP)
    
    INC     HL                        ; 2 BYTES RESERVADOS
    INC     HL
    INC     HL

    ;BUSCA Y GUARDA INICIO DE LOS CANALES EN EL MODULO MUS (OPTIMIZAR****************)
    ;AÑADE OFFSET DEL LOOP
    PUSH    HL                        ; IX = INICIO OFFSETS LOOP POR CANAL
    POP     IX
    LD      DE, $0008                 ; LOS LOOPS POR CANAL OCUPAN 8 BYTES
    ADD     HL, DE                    ; HL APUNTA AL INICIO DEL CANAL A
    LD      (PUNTERO_P_DECA),HL       ; GUARDA PUNTERO INICIO CANAL A
    LD      E, (IX + 0)               ; OBTIENE OFFSET DEL LOOP DEL CANAL A
    LD      D, (IX + 1)
    ADD     HL, DE                    ; LO SUMA AL INICIO DEL CANAL A
    LD      (PUNTERO_L_DECA),HL       ; GUARDA PUNTERO INICIO LOOP A

    CALL    BUSCA_FIN_CANAL           ; HL = INICIO DEL CANAL B
    LD      (PUNTERO_P_DECB), HL      ; GUARDA PUNTERO INICIO CANAL B
    LD      E, (IX + 2)               ; OBTIENE OFFSET DEL LOOP DEL CANAL B
    LD      D, (IX + 3)
    ADD     HL, DE                    ; LO SUMA AL INICIO DEL CANAL B
    LD      (PUNTERO_L_DECB), HL      ; GUARDA PUNTERO INICIO LOOP B

    CALL    BUSCA_FIN_CANAL           ; HL = INICIO DEL CANAL C
    LD      (PUNTERO_P_DECC), HL      ; GUARDA PUNTERO INICIO CANAL C
    LD      E, (IX + 4)               ; OBTIENE OFFSET DEL LOOP DEL CANAL C
    LD      D, (IX + 5)
    ADD     HL, DE                    ; LO SUMA AL INICIO DEL CANAL C
    LD      (PUNTERO_L_DECC), HL      ; GUARDA PUNTERO INICIO LOOP C
    
    CALL    BUSCA_FIN_CANAL
    LD      (PUNTERO_P_DECP), HL      ; HL = INICIO DEL CANAL DE PERCUSION
    LD      E, (IX + 6)               ; OBTIENE OFFSET DEL LOOP DEL CANAL DE PERCUSION
    LD      D, (IX + 7)
    ADD     HL, DE                    ; LO SUMA AL INICIO DEL CANAL DE PERCUSION
    LD      (PUNTERO_L_DECP),HL       ; GUARDA PUNTERO AL INICIO LOOP DE PERCUSION

;LEE DATOS DE LAS NOTAS
;(   7 - 6   |  5 - 0  )
;  LONGITUD  -   NOTA
INIT_DECODER:                         ; LEEMOS LA PRIMERA NOTA DE CADA CANAL PARA DEJAR EL ESTADO LISTO
    LD      DE, (CANAL_A)             ; DE = PUNTERO AL BUFFER DE DECODIFICACION DEL CANAL A
    LD      (PUNTERO_A), DE           ; LO GUARDAMOS EN PUNTERO_A
    LD      HL, (PUNTERO_P_DECA)      ; HL = PUNTERO A LA PRIMERA NOTA DEL CANAL A
    CALL    DECODE_CANAL              ; HL = POSICION DE LA NOTA SIGUIENTE
    LD      (PUNTERO_DECA), HL        ; GUARDA LA POSICIÓN DE LA SIGUIENTE EN PUNTERO_DECA
                
    LD      DE, (CANAL_B)             ; DE = PUNTERO AL BUFFER DE DECODIFICACION DEL CANAL B
    LD      (PUNTERO_B), DE           ; LO GUARDAMOS EN PUNTERO_B
    LD      HL, (PUNTERO_P_DECB)      ; HL = PUNTERO A LA PRIMERA NOTA DEL CANAL B
    CALL    DECODE_CANAL              ; HL = POSICION DE LA NOTA SIGUIENTE
    LD      (PUNTERO_DECB), HL        ; GUARDA LA POSICIÓN DE LA SIGUIENTE NOTA EN PUNTERO_DECB
    
    LD      DE, (CANAL_C)             ; DE = PUNTERO AL BUFFER DE DECODIFICACION DEL CANAL C
    LD      (PUNTERO_C), DE           ; LO GUARDAMOS EN PUNTERO_C
    LD      HL, (PUNTERO_P_DECC)      ; HL = PUNTERO A LA PRIMERA NOTA DEL CANAL C
    CALL    DECODE_CANAL              ; HL = POSICION DE LA NOTA SIGUIENTE
    LD      (PUNTERO_DECC), HL        ; GUARDA LA POSICIÓN DE LA SIGUIENTE NOTA EN PUNTERO_DECC
    
    LD      DE, (CANAL_P)             ; DE = PUNTERO AL BUFFER DE DECODIFICACION DEL CANAL P
    LD      (PUNTERO_P), DE           ; LO GUARDAMOS EN PUNTERO_P
    LD      HL, (PUNTERO_P_DECP)      ; HL = PUNTERO A LA PRIMERA NOTA DEL CANAL P
    CALL    DECODE_CANAL              ; HL = POSICION DE LA NOTA SIGUIENTE
    LD      (PUNTERO_DECP), HL        ; GUARDA LA POSICIÓN DE LA SIGUIENTE NOTA EN PUNTERO_DECP
    RET                               ; FIN DE CARGA_CANCION

; BUSCA EL FINAL DEL CANAL.
; DEVUELVE EN HL EL BYTE SIGUIENTE AL FINAL DEL CANAL (ES EL INICIO DEL SIGUIENTE O EL FINAL DEL MODULO)
BUSCA_FIN_CANAL:
    XOR     A                         ; BUSCA EL BYTE 0
    LD      E, $3F                    ; CODIGO INSTRUMENTO
    LD      B, $FF                    ; EL MODULO DEBE TENER UNA LONGITUD MENOR DE $FF00 ... o_O!
    CPIR                              ; BUSCA EL PRIMER BYTE 0

    DEC     HL                        ; HEMOS ENCONTRADO UN 0, PUEDE SER UN INSTRUMENTO, QUE VIENE PRECEDIDO 
    DEC     HL                        ; POR UN COMANDO 3F. VAMOS AL BYTE ANTERIOR (CPIR YA HA INCREMENTADO HL,
    LD      A, E                      ; ASI QUE HAY QUE IR DOS ATRAS).
    CP      (HL)                      ; MIRAMOS A VER SI ES 3F.
    INC     HL                        ; RESTAURANDO HL, APUNTANDO AL BYTE SIGUIENTE AL 0 ENCONTRADO
    INC     HL
    JR      Z, BUSCA_FIN_CANAL        ; SI ES 3F, ERA UN INSTRUMENTO, SEGUIMOS BUSCANDO

    DEC     HL                        ; SI NO ERA UN INSTRUMENTO, PUEDE SER UN MODIFICADOR DE VOLUMEN, QUE 
    DEC     HL                        ; ES EL BYTE SIGUIENTE, ASI QUE HAY QUE IR 3 ATRAS PARA VER SI ES UN 
    DEC     HL                        ; 3F.
    LD      A, E                      ; MIRAMOS A VER SI ES 3F
    CP      (HL)                      ; Y SI LO ES, HAY QUE SEGUIR BUSCANDO, PORQUE EL 0 ERA UN MODIFICADOR
    INC     HL                        ; DE VOLUMEN
    INC     HL
    INC     HL
    JR      Z, BUSCA_FIN_CANAL        ; RESTAURAMOS EL PUNTERO, Y SEGUIMOS BUSCANDO SI ERA 3F. SI NO, 
    RET                               ; HEMOS ENCONTRADO EL FINAL DEL CANAL

; LEE LOS DATOS DE UN CANAL Y LO ALMACENA EN EL BUFFER DE DECODIFICACION DEL CANAL
; HL = PUNTERO A LAS NOTAS DEL CANAL CODIFICADAS
; DE = BUFFER DONDE DECODIFICAR LAS NOTAS
; EL FORMATO DE LA NOTA ES:
; (   7 - 6   | 5 - 0  )
; ( LONGITUD  |  NOTA  )
; VALORES ESPECIALES DEL BYTE COMPLETO:
; NOTA = 0 FIN CANAL (DEBE SER 0 INCLUYENDO LOS BITS DE LONGITUD)
; NOTA = 0x01 SILENCIO
; NOTA = 0x3E PUNTILLO
; NOTA = 0x3F INSTRUMENTO           (0011 1111) -> LONGITUD = 1  -> 00000001
; NOTA = 0x7F PERCUSION             (0111 1111) -> LONGITUD = 2  -> 00000010
; NOTA = 0xBF USO DE INSTRUMENTO R  (1011 1111) -> LONGITUD = 4  -> 00000100
DECODE_CANAL:
    LD      A, (HL)                   ; LEEMOS EL SIGUIENTE BYTE DEL CANAL
    AND     A
    JR      Z, FIN_DEC_CANAL          ; SI ES CERO, HEMOS LLEGADO AL FIN DEL CANAL.
    CALL    GETLEN                    ; OBTENEMOS LA LONGITUD DE LA NOTA (EN B).
                                      ; EN A QUEDA EL VALOR DE LA NOTA CON LOS BITS 6-7 = 0
    CP      00000001B                 ; SI EL VALOR DE A ES 1, SILENCIO.
    JR      NZ, NO_SILENCIO           ; SI NO, SEGUIMOS DECODIFICANDO.
    SET     6, A                      ; ESTABLECEMOS EL BIT 6 EN A, PARA MARCAR EL SILENCIO.
    JR      NO_MODIFICA               ; NO COMPROBAMOS MAS VALORES.
    
NO_SILENCIO:    
    CP      00111110B                 ; EL PUNTILLO SE REPRESENTA CON EL VALOR 0x3E
    JR      NZ, NO_PUNTILLO           ; SI ES PUNTILLO, LO QUE ESTAMOS HACIENDO ES CONTINUAR LA NOTA ANTERIOR
    OR      A                         ; CON LA MITAD DE LONGITUD DE LO ESPECIFICADO EN LA NOTA.
    RRC     B                         ; DIVIDIMOS LA LONGITUD QUE OBTUVIMOS POR DOS.
    XOR     A                         ; Y ELIMINAMOS LA INFORMACION DE LA NOTA
    JR      NO_MODIFICA               ; NO COMPROBAMOS MAS VALORES.

NO_PUNTILLO:    
    CP      00111111B                 ; ES COMANDO? (0x3F)
    JR      NZ,NO_MODIFICA            ; NO, ES NOTA, Y NO COMPROBAMOS MÁS
    BIT     0, B                      ; SI LA LONGITUD ES 1, LA NOTA ORIGINAL ERA 0x3F
    JR      Z, NO_INSTRUMENTO         ; SI NO, ERA OTRO COMANDO.
    LD      A, 11000001B              ; CODIGO DE INSTRUMENTO
    LD      (DE), A                   ; GUARDAMOS EN EL BUFFER DE DECODIFICACION EL CODIGO DE INSTRUMENTO
    INC     HL                        ; Y APUNTAMOS AL SIGUIENTE BYTE EN AMBOS BUFFERS
    INC     DE
    LD      A, (HL)                   ; LEEMOS EL NUM DE INSTRUMENTO
    LD      (DE), A                   ; LO GUARDAMOS EN EL BUFFER DE DECODIFICACION
    INC     DE                        ; Y APUNTAMOS AL SIGUIENTE BYTE EN AMBOS BUFFERS
    INC     HL
    LD      A,(HL)                    ; VOLUMEN RELATIVO DEL INSTRUMENTO Y MODIFICADORES DE TEMPO
    LD      (DE),A                    ; LO GUARDAMOS EN EL BUFFER DE DECODIFICACION
    INC     DE                        ; Y APUNTAMOS AL SIGUIENTE BYTE EN AMBOS BUFFERS
    INC     HL
    JR      DECODE_CANAL              ; SEGUIMOS DECODIFICANDO
                
NO_INSTRUMENTO: 
    BIT     2, B
    JR      Z, NO_ENVOLVENTE          ; SI EL BIT 2 ESTA MARCADO, SE USA EL INSTRUMENTO R (LA NOTA ERA 0xBF)
    LD      A, 11000100B              ; CODIGO ENVOLVENTE
    LD      (DE), A                   ; LO GUARDAMOS EN EL BUFFER DE DECODIFICACION
    INC     DE                        ; Y APUNTAMOS AL SIGUIENTE BYTE EN AMBOS BUFFERS
    INC     HL
    LD      A, (HL)                   ; LEEMOS LOS PARAMETROS DE LA ENVOLVENTE
    LD      (DE), A                   ; LOS GUARDAMOS EN EL BUFFER DE DECODIFICACION
    INC     DE                        ; Y APUNTAMOS AL SIGUIENTE BYTE EN AMBOS BUFFERS
    INC     HL
    JR      DECODE_CANAL              ; SEGUIMOS DECODIFICANDO
     
NO_ENVOLVENTE:
    BIT     1, B
    JR      Z, NO_MODIFICA            ; SI ESTA EL BIT 1 MARCADO, ES UNA PERCUSION (LA NOTA ERA 0x7F)
    LD      A, 11000010B              ; CODIGO PERCUSION
    LD      (DE), A                   ; LO GUARDAMOS EN EL BUFFER DE DECODIFICACION
    INC     HL                        ; Y APUNTAMOS AL SIGUIENTE BYTE EN AMBOS BUFFERS
    INC     DE
    LD      A, (HL)                   ; OBTENEMOS QUE PERCUSION Y SU LONGITUD EN A
    CALL    GETLEN                    ; AHORA TENEMOS EN A LA PERCUSION, Y EN B SU LONGITUD

NO_MODIFICA:                          ; HEMOS LEIDO UNA NOTA O UNA PERCUSION, EN B ESTÁ LA LONGITUD
    LD      (DE), A                   ; LA GUARDAMOS EN EL BUFFER DE DECODIFICACION
    INC     DE                        ; Y APUNTAMOS AL SIGUIENTE BYTE EN EL BUFFER DE DECODIFICACION
    XOR     A                         ; LIMPIAMOS A (POR LO TANTO LA NOTA SE ESCRIBE UNA VEZ Y EL RESTO
    DJNZ    NO_MODIFICA               ; SON CEROS HASTA LLEGAR A LA LONGITUD)
    LD      A, $81                    ; A = 0x81 - FIN DE LA NOTA
    LD      (DE), A                   ; GUARDAMOS A EN EL BUFFER DE DECODIFICACION.
    INC     DE                        ; Y APUNTAMOS AL SIGUIENTE BYTE EN AMBOS BUFFERS
    INC     HL
    RET      ;** JR      DECODE_CANAL

FIN_DEC_CANAL:  
    LD      A, $80                    ; MARCAMOS EN EL BUFFER DE DECODIFICACION QUE NO HAY MAS COMANDOS 
                                      ; Y HA TERMINADO EL CANAL (0X80)
    LD      (DE), A                   ; GUARDAMOS EL VALOR EN EL BUFFER DE DECODIFICACION
    INC     DE                        ; Y APUNTAMOS AL SIGUIENTE BYTE EN AMBOS BUFFERS
    RET

; LA LONGITUD DE LA NOTA SE CODIFICA EN POTENCIAS DE 2, Y SI SON VALORES NO REPRESENTABLES 
; SE UTILIZAN "PUNTILLOS", QUE REPRESENTAN LA MITAD DEL VALOR CODIFICADO.
; SE INDICAN EN LOS DOS BITS MAS SIGNIFICATIVOS DE LA NOTA:
; 00 -> LONGITUD 1 = 2^0
; 01 -> LONGITUD 2 = 2^1
; 10 -> LONGITUD 4 = 2^2
; 11 -> LONGITUD 8 = 2^3
; POR LO TANTO EL VALOR CODIFICADO ES L, Y LA LONGITUD ES=2^L

; GETLEN: OBTIENE LA LONGITUD DE LA NOTA ACTUAL
; A: PRIMER BYTE DE LA NOTA
; DEVUELVE LA LONGITUD EN B, Y EN A QUEDA LA NOTA SIN LA INFORMACION DE LONGITUD
GETLEN:
    LD      B, A                      ; GUARDA EN B LA NOTA ACTUAL
    AND     00111111B                 ; LIMPIAMOS LOS DOS BITS MAS SIGNIFICATIVOS
    PUSH    AF                        ; Y GUARDAMOS EL RESULTADO EN LA PILA
    LD      A, B                      ; RECUPERAMOS EL VALOR ORIGINAL 
    AND     11000000B                 ; Y NOS QUEDAMOS CON LOS DOS BITS MAS SIGNIFICATIVOS
    RLCA                              ; Y LOS ROTAMOS A LA IZQUIERDA PARA QUEDARNOS CON 
    RLCA                              ; EL VALOR CODIFICADO.
    INC     A                         ; SUMAMOS 1. CON ESO TENEMOS EL EXPONENTE DE LA LONGITUD
    LD      B, A                      ; LO GUARDAMOS EN B (CONTADOR DE DJNZ)
    LD      A, 10000000B              ; PREPARAMOS A PARA QUE INDIQUE LA LONGITUD
DCBC0:
    RLCA                              ; ROTAMOS A
    DJNZ    DCBC0                     ; RESTAMOS 1 A B, Y SI NO HEMOS ACABADO, SEGUIMOS ROTANDO
    LD      B, A                      ; GUARDAMOS LA LONGITUD EN B
    POP     AF                        ; Y RESTAURAMOS EL VALOR DE LA NOTA EN A
    RET

; PLAY __________________________________________________
; REPRODUCE UN PASO DEL PLAYER. PROCESA LOS CANALES, Y GENERA LOS VALORES ADECUADOS PARA 
; ENVIAR AL CHIP AY PARA QUE SUENE LA CANCION DURANTE UNA INTERRUPCIÓN (O UN FRAME).
PLAY:
    LD      HL, INTERR                ; EL BIT 1 DE INTERR INDICA SI EL REPRODUCTOR ESTÁ ACTIVO
    BIT     1, (HL)                   ; COMPROBAMOS SI ESTÁ ACTIVO
    RET     Z                         ; Y SI NO ES ASÍ, SALIMOS.
    LD      HL, HYBRID                ; COMPROBAMOS SI ESTÁ ACTIVO EL TEMPO HIBRIDO
    BIT     7, (HL)                   ; EL BIT 7 INDICA SI ESTÁ ACTIVO
    JR      Z, TEMPO_ENTERO           ; SI NO ESTÁ ACTIVO, GESTIONAMOS EL TEMPO TAL CUAL
    BIT     6, (HL)                   ; EL BIT 6 ES UN ALTERNADOR, SE ACTIVA Y DESACTIVA EN CADA REPRODUCCION
    JR      Z, TEMPO_ENTERO           ; SI NO ESTÁ ACTIVO, EL TEMPO SE GESTIONA DE FORMA NORMAL

TEMPO_SEMI:
    LD      HL, TTEMPO                ; SI ESTAMOS EN TEMPO HIBRIDO, LO QUE HACEMOS ES REDUCIR EL TEMPO
    INC     (HL)                      ; DURANTE UN CICLO DE TEMPO, Y LUEGO RESTAURARLO, ASÍ QUE 
    LD      A, (TEMPO)                ; COMPROBAMOS EL VALOR DE TTEMPO CON ((TEMPO)-1)
    DEC     A
    CP      (HL)
    JR      NZ, PAUTAS                ; NO CAMBIAMOS DE NOTA? ENTONCES REPRODUCIMOS LOS INSTRUMENTOS Y PERCUSIONES TAL CUAL
    LD      (HL), 0                   ; ASEGURAMOS QUE DEJAMOS EL TEMPO EN 0
    LD      HL, HYBRID                ; Y COMO HEMOS CERRADO EL CICLO DE TEMPO, ALTERNAMOS EL BIT 6
    RES     6, (HL)                   ; QUE ESTABA ACTIVADO, ASÍ QUE LO DESACTIVAMOS.
    JR      INTERPRETA                ; Y SEGUIMOS.

TEMPO_ENTERO:
    LD      HL, TTEMPO                ; PROCESAMOS EL TEMPO DE MANERA NORMAL. VAMOS INCREMENTANDO EL 
    INC     (HL)                      ; CONTADOR (TTEMPO)
    LD      A, (TEMPO)                ; Y CUANDO LLEGUEMOS AL VALOR DE (TEMPO) 
    CP      (HL)                      ; IMPLICA QUE HEMOS COMPLETADO EL CICLO DE TEMPO
    JR      NZ, PAUTAS                ; SI NO LLEGAMOS, SEGUIMOS REPRODUCIENDO INSTRUMENTOS Y PERCUSIONES
    LD      (HL), 0                   ; SI LLEGAMOS, PONEMOS EL CONTADOR A 0
    LD      HL, HYBRID                ; Y ACTIVAMOS EL BIT DE TEMPO HIBRIDO (QUE SOLO APLICA SI ESTA ACTIVO)
    SET     6, (HL)

; SI LLEGAMOS AQUÍ, HEMOS TERMINADO UN CICLO DE TEMPO, Y POR LO TANTO, TENEMOS QUE PASAR
; A LA SIGUIENTE NOTA DE CADA CANAL.
INTERPRETA:
    ; CANAL A
    LD      IY, PSG_REG               ; IY = DIRECCION DEL REGISTRO DE FRECUENCIA PARA EL CANAL A
    LD      IX, PUNTERO_A             ; IX = DIRECCION AL BUFFER DE DECODIFICACION DEL CANAL A
    LD      BC, PSG_REG + 8           ; BC = DIRECCION DEL REGISTRO DEL VOLUMEN DEL CANAL A
    CALL    LOCALIZA_NOTA

    ; CANAL B
    LD      IY, PSG_REG + 2           ; IY = DIRECCION DEL REGISTRO DE FRECUENCIA PARA EL CANAL B
    LD      IX, PUNTERO_B             ; IX = DIRECCION AL BUFFER DE DECODIFICACION DEL CANAL B
    LD      BC, PSG_REG + 9           ; BC = DIRECCION DEL REGISTRO DEL VOLUMEN DEL CANAL B
    CALL    LOCALIZA_NOTA

    ; CANAL C
    LD      IY, PSG_REG + 4           ; IY = DIRECCION DEL REGISTRO DE FRECUENCIA PARA EL CANAL C
    LD      IX, PUNTERO_C             ; IX = DIRECCION AL BUFFER DE DECODIFICACION DEL CANAL C
    LD      BC, PSG_REG + 10          ; BC = DIRECCION DEL REGISTRO DEL VOLUMEN DEL CANAL C
    CALL    LOCALIZA_NOTA

    ; CANAL PERCUSIONES
    LD      IX, PUNTERO_P             ; IX = DIRECCION AL BUFFER DE DECODIFICACION DEL CANAL P
    CALL    LOCALIZA_EFECTO           ; LOS REGISTROS DEL PSG A USAR DEPENDEN DEL CANAL QUE INDICA EL .MUS

; TANTO SI LLEGAMOS A UNA NOTA NUEVA COMO SI CONTINUAMOS UNA NOTA ACTUAL, TENEMOS QUE 
; PROCESAR LAS PAUTAS (INSTRUMENTOS O PERCUSIONES) ACTIVAS.
PAUTAS:
    LD      IY, PSG_REG + 0           ; IY = DIRECCION DEL REGISTRO DE FRECUENCIA PARA EL CANAL A
    LD      IX, PUNTERO_P_A           ; IX = PUNTERO A LA UBICACION ACTUAL DE LA PAUTA DEL CANAL A
    LD      HL, PSG_REG + 8           ; HL = DIRECCION DEL REGISTRO DEL VOLUMEN DEL CANAL A
    CALL    PAUTA                     ; PAUTA CANAL A

    LD      IY, PSG_REG + 2           ; IY = DIRECCION DEL REGISTRO DE FRECUENCIA PARA EL CANAL B
    LD      IX, PUNTERO_P_B           ; IX = PUNTERO A LA UBICACION ACTUAL DE LA PAUTA DEL CANAL B
    LD      HL, PSG_REG+9             ; HL = DIRECCION DEL REGISTRO DEL VOLUMEN DEL CANAL B
    CALL    PAUTA                     ; PAUTA CANAL B

    LD      IY, PSG_REG + 4           ; IY = DIRECCION DEL REGISTRO DE FRECUENCIA PARA EL CANAL C
    LD      IX, PUNTERO_P_C           ; IX = PUNTERO A LA UBICACION ACTUAL DE LA PAUTA DEL CANAL C
    LD      HL, PSG_REG+10            ; HL = DIRECCION DEL REGISTRO DEL VOLUMEN DEL CANAL C
    CALL    PAUTA                     ; PAUTA CANAL C
    ; NO SE PROCESA LA PAUTA DE LA PERCUSION AQUI.
RET

; LOCALIZA LA SIGUIENTE NOTA DEL CANAL ESPECIFICADO. SE BUSCA EN EL BUFFER YA DECODIFICADO.
; SI SE ACABAN LOS ELEMENTOS DECODIFICADOS, SE ENCARGA DE RELLENAR EL BUFFER PARA LA SIGUIENTE VEZ.

; IX: PUNTERO AL CANAL PARA EL QUE HAY QUE BUSCAR LA SIGUIENTE NOTA
; IY: PUNTERO AL REGISTRO DE FRECUENCIA DEL PSG PARA EL CANAL
; BC: PUNTERO AL REGISTRO DE VOLUMEN DEL PSG PARA EL CANAL

; RECORDAMOS, AL DECODIFICAR EL CANAL HEMOS METIDO LOS SIGUIENTES COMANDOS EN EL BUFFER DE 
; DECODIFICACIÓN:

;     11000001 -> INSTRUMENTO. EL SIGUIENTE BYTE INDICA EL NUMERO DE INSTRUMENTO, Y EL SIGUIENTE 
;                 EL VOLUMEN RELATIVO DEL INSTRUMENTO Y MODIFICADORES DE TEMPO.
;     11000010 -> PERCUSION. EL SIGUIENTE BYTE INDICA QUÉ PERCUSION ES.
;     11000100 -> ENVOLVENTE. EL SIGUIENTE BYTE LLEVA LOS PARÁMETROS DE LA ENVOLVENTE.

LOCALIZA_NOTA:  
    LD      L, (IX + 0)     ; HL = DIRECCION DE MEMORIA DEL BUFFER DECODIFICADO DEL CANAL
    LD      H, (IX + 1)
    LD      A, (HL)                       ; CARGA EL BYTE DEL CANAL ACTUAL
    LD      E, A                          ; GUARDAMOS EL VALOR EN E
    AND     11000000B                     ; NOS QUEDAMOS CON LOS DOS BITS MAS SIGNIFICATIVOS PARA VER SI 
    CP      11000000B                     ; ES UN COMANDO O UNA NOTA.
    JR      NZ, LOCALIZA_NOTA_NO_COMANDO  ; SI NO ESTÁN AMBOS ACTIVOS, NO ES UN COMANDO.

COMANDOS:
; 11000001 -> INSTRUMENTO
    LD      A, E                          ; RESTAURAMOS EL VALOR ORIGINAL DE A
    BIT     0, A                          ; EL BIT 0 MARCA EL COMANDO INSTRUMENTO
    JR      Z, COM_EFECTO                 ; SI NO ESTA ACTIVADO, COMPROBAMOS SI ES UN EFECTO

    INC     HL                            ; ES UN INSTRUMENTO. EL SIGUIENTE BYTE INDICA QUÉ INSTRUMENTO ES
    LD      A, (HL)                       ; A = NUMERO DE INSTRUMENTO
    INC     HL                            ; EL SIGUIENTE BYTE SON LOS MODIFICADORES DE VOLUMEN Y TEMPO
    LD      E, (HL)                       ; Y LO GUARDAMOS EN E.

    PUSH    HL                            ; VALIDAMOS LOS MODIFICADORES DE TEMPO. GUARDAMOS EL PUNTERO AL CANAL
    LD      HL, TEMPO                     ; Y APUNTAMOS CON HL A TEMPO
    BIT     5, E                          ; SI ESTÁ ACTIVO EL BIT 5, HAY QUE BAJAR EL TEMPO
    JR      Z, NO_DEC_TEMPO
    DEC     (HL)                          ; LO MODIFICAMOS
NO_DEC_TEMPO:
    BIT     6, E                          ; SI ESTA ACTIVO EL BIT 6, HAY QUE SUBIR EL TEMPO
    JR      Z, NO_INC_TEMPO
    INC     (HL)                          ; LO MODIFICAMOS
NO_INC_TEMPO:
    RES     5, E                          ; Y RESETEAMOS AMBOS BITS PARA QUEDARNOS CON EL MODIFICADOR DE
    RES     6, E                          ; VOLUMEN EN E
    POP     HL                            ; RECUPERAMOS EL PUNTERO AL CANAL

    LD      (IX + 37), E      ; GUARDAMOS EL MODIFICADOR DEL VOLUMEN
    INC     HL                                    ; Y LEEMOS EL SIGUIENTE BYTE (QUE ES LA SIGUIENTE NOTA)
    LD      (IX + 0), L       ; ALMACENAMOS LA DIRECCIÓN DE LA SIGUIENTE NOTA EN EL PUNTERO
    LD      (IX + 1), H   ; DEL CANAL
    LD      HL, ($CD00) ;TABLA_PAUTAS                      ; OBTENEMOS EL PUNTERO AL INSTRUMENTO QUE TENEMOS EN A
    CALL    EXT_WORD
    LD      (IX + 18), L      ; Y GUARDAMOS SU UBICACION EN EL PUNTERO AL INICIO DE 
    LD      (IX + 19), H    ; LA PAUTA
    LD      (IX + 12), L       ; Y EN EL PUNTERO A LA PAUTA ACTUAL.
    LD      (IX + 13), H
    LD      L, C                                  ; PONEMOS EN HL EL PUNTERO AL REGISTRO DE VOLUMEN
    LD      H, B
    RES     4, (HL)                               ; APAGA EFECTO ENVOLVENTE EN EL REGISTRO DE VOLUMEN
    XOR     A
    LD      (PSG_REG_SEC + 13), A                 ; Y APAGA EL EFECTO ENVOLVENTE EN EL REGISTRO 13
    LD      (PSG_REG+13) , A
    ;LD  (ENVOLVENTE_BACK),A                      ; 08.13 / RESETEA EL BACKUP DE LA ENVOLVENTE
    JR      LOCALIZA_NOTA                         ; SEGUIMOS, HAY BYTES PENDIENTES

COM_EFECTO:
; 11000010 -> PERCUSION
    BIT     1, A                          ; SI ESTÁ ACTIVADO EL BIT 1, HAY QUE REPRODUCIR UNA PERCUSION.
    JR      Z, COM_ENVOLVENTE             ; SI NO, COMPROBAMOS UNA ENVOLVENTE.

    INC     HL                            ; EL SIGUIENTE BYTE ES QUE PERCUSION HAY QUE REPRODUCIR
    LD      A, (HL)                       ; ASI QUE LO LEEMOS EN A
    INC     HL                            ; Y APUNTAMOS AL SIGUIENTE BYTE EN EL BUFFER DE DECODIFICACION
    LD      (IX+0), L   ; GUARDAMOS POR DONDE VAMOS EN EL PUNTERO DEL CANAL
    LD      (IX+1), H
    CALL    INICIA_PERCUSION              ; E INICIAMOS LA REPRODUCCION DE LA PERCUSION
    RET                                   ; SALIENDO DE LA REPRODUCCION

COM_ENVOLVENTE: 
; 11000100 -> ENVOLVENTE
    BIT     2, A                          ; SI ESTÁ ACTIVADO EL BIT 2, ES UN COMANDO DE ENVOLVENTE.
    RET     Z                             ; Y SI NO LO ESTÁ, HAY UN ERROR EN EL CANAL Y LO IGNORAMOS.

    INC     HL                            ; EL SIGUIENTE BYTE ES EL CODIGO DE ENVOLVENTE
    LD      A, (HL)                       ; LO LEEMOS EN A
    LD      (ENVOLVENTE), A               ; LO ALMACENAMOS EN ENVOLVENTE
    INC     HL                            ; Y APUNTAMOS AL SIGUIENTE BYTE DEL BUFFER DE DECODIFICACION
    LD      (IX+0), L   ; GUARDAMOS POR DONDE VAMOS EN EL PUNTERO DEL CANAL
    LD      (IX+1), H
    LD      L, C                          ; APUNTAMOS AL REGISTRO DEL VOLUMEN EN HL
    LD      H, B
    LD      (HL), 00010000B               ; Y ENCENDEMOS EL EFECTO ENVOLVENTE
    JR      LOCALIZA_NOTA                 ; SEGUIMOS, YA QUE HAY BYTES PENDIENTES

; NO ES UN COMANDO, ES UNA NOTA.
LOCALIZA_NOTA_NO_COMANDO:
    LD      A, (HL)                       ; RECUPERAMOS EL BYTE ACTUAL
    INC     HL                            ; Y APUNTAMOS AL SIGUIENTE
    BIT     7, A                          ; SI EL BIT 7 ESTA A CERO, HAY MAS DATOS EN EL BUFFER DE 
    JR      Z, NO_FIN_CANAL_A             ; DECODIFICACION.
    BIT     0, A                          ; COMPROBAMOS SI EL BIT 0 ESTÁ A CERO, QUE INDICA QUE EL CANAL
    JR      Z, FIN_CANAL_A                ; HA LLEGADO AL FINAL.

; SI LLEGAMOS AQUÍ, LA NOTA HA FINALIZADO, PERO HAY MÁS NOTAS EN EL CANAL,
; ASI QUE DECODIFICAMOS LA SIGUIENTE NOTA.
FIN_NOTA_A:
    LD      E, (IX + 6)
    LD      D, (IX + 7)   ; LEEMOS EL INICIO DEL BUFFER DE DECODIFICACION EN DE
    LD      (IX + 0), E 
    LD      (IX + 1), D ; PUNTERO BUFFER AL INICIO.

    LD      L, (IX + 30)      ; CARGAMOS EL PUNTERO DE DECODIFICACION EN HL
    LD      H, (IX + 31)
    PUSH    BC                                  ; GUARDAMOS EL PUNTERO AL REGISTRO DEL VOLUMEN DEL CANAL
    CALL    DECODE_CANAL                        ; DECODIFICA CANAL PARA LLENAR EL BUFFER DE DECODIFICACION
    POP     BC                                  ; RESTAURAMOS EL PUNTERO AL REGISTRO DEL VOLUMEN DEL CANAL
    LD      (IX+30), L      ; GUARDA EL PUNTERO DECODER
    LD      (IX+31), H
    JP      LOCALIZA_NOTA                       ; Y BUSCAMOS LA SIGUIENTE NOTA

; SI LLEGAMOS AQUÍ, EL CANAL HA FINALIZADO. SI TENEMOS LOOP DEBERÍAMOS SALTAR A LA UBICACIÓN 
; DEL LOOP.
FIN_CANAL_A:    
    LD      HL, INTERR                          ; COMPROBAMOS SI ESTÁ EL LOOP ACTIVADO
    BIT     4, (HL)
    JR      NZ, FCA_CONT                        ; Y SI LO ESTÁ VAMOS A SALTAR A LA UBICACIÓN DEL LOOP
    POP     AF                                  ; SI ESTÁ DESACTIVADO, RESTAURAMOS EL VALOR DE AF
    JP      PLAYER_OFF                          ; Y PARAMOS EL REPRODUCTOR, PORQUE HEMOS LLEGADO AL FINAL.

; HEMOS LLEGADO AL FINAL DEL CANAL, Y ESTÁ ACTIVADO EL LOOP.
FCA_CONT:
    LD      L, (IX + 42)      ; CARGAMOS EN HL LA UBICACION DEL SALTO DEL LOOP
    LD      H, (IX + 43)  ; (LA CALCULAMOS AL CARGAR LA CANCIÓN)
    LD      (IX + 30), L        ; Y LA ESTABLECEMOS COMO PUNTERO DE DECODIFICACIÓN
    LD      (IX + 31), H    
    JR      FIN_NOTA_A                                ; COMO HAY MAS NOTAS EN EL CANAL, AVANZAMOS

; EL CANAL NO HA FINALIZADO. COMPROBAMOS SI HAY UN SILENCIO O UNA NOTA
NO_FIN_CANAL_A: 
    LD      (IX+0), 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                                ; COMPRUEBA SI ES UN SILENCIO (BIT 6)
    JR      Z, NO_SILENCIO_A
    ; HAY SILENCIO
    LD      A, (BC)                             ; SI ES SILENCIO, COMPRUEBA SI ESTÁ LA ENVOLVENTE ACTIVADA
    AND     00010000B
    JR      NZ, SILENCIO_ENVOLVENTE

    ; HAY SILENCIO Y NO ESTÁ LA ENVOLVENTE ACTIVADA
    XOR     A                                   ; SI NO ESTÁ ACTIVADA LA ENVOLVENTE,
    LD      (BC), A                             ; PONE A 0 EL VOLUMEN DEL CANAL EN EL REGISTRO CORRESPONDIENTE
    LD      (IY + 0), A                         ; ASÍ COMO EL TONO, AQUÍ LA FRECUENCIA FINA
    LD      (IY + 1), A                         ; Y AQUÍ LA FRECUENCIA GRUESA
    RET

    ; HAY SILENCIO Y LA ENVOLVENTE ESTÁ ACTIVADA
SILENCIO_ENVOLVENTE:
    LD      A, $FF                              ; HAY UN SILENCIO Y LA ENVOLVENTE ESTA ACTIVADA
    LD      (PSG_REG + 11), A                   ; ESTABLECEMOS LA FRECUENCIA DE LAS ENVOLVENTES EN 65535
    LD      (PSG_REG + 12), A
    XOR     A                                   
    LD      (PSG_REG + 13), A                   ; Y EL REGISTRO DE CONTROL DE LA ENVOLVENTE A 0
    LD      (IY + 0), A                         ; ASÍ COMO EL TONO, AQUÍ LA FRECUENCIA FINA
    LD      (IY + 1), A                         ; Y AQUÍ LA FRECUENCIA GRUESA
    RET

    ; NO HAY SILENCIO, REPRODUCIMOS UNA NOTA
NO_SILENCIO_A:
    LD      (IX + 36), A        ; APUNTAMOS AL REGISTRO DE LA NOTA DEL CANAL
    CALL    NOTA                                    ; Y REPRODUCE LA NOTA
    LD      L, (IX + 18)      ; HL=(PUNTERO_P_A0) RESETEA PAUTA 
    LD      H, (IX + 19) 
    LD      (IX + 12), L       ; (PUNTERO_P_A)=HL
    LD      (IX + 13), H
FIN_RUTINA:
    RET


; LOCALIZA EFECTO
; IX = (PUNTERO_P). PUNTERO AL BUFFER DE DECODIFICACION DEL CANAL DE PERCUSION

; DECODE_CANAL METE EN EL BUFFER DE DECODIFICACION LO SIGUIENTE CUANDO ES UN INSTRUMENTO:
; BYTE 0:           $C2 -> INICIO DE PERCUSION
; BYTE 1:           ID DE INSTRUMENTO
; BYTE 2-L+2:       $00 -> HAY TANTOS CEROS COMO LONGITUD DE LA PERCUSION.
; BYTE L+3:         $81 -> FIN DE PERCUSION
; EL FINAL DEL CANAL SE MARCA CON $80
LOCALIZA_EFECTO:
    LD      L, (IX + 0)                         ; HL=(PUNTERO_P)
    LD      H, (IX + 1)
    LD      A, (HL)                             ; LEEMOS EL SIGUIENTE BYTE DE LA PERCUSION
    CP      11000010B                           ; COMPARAMOS CON $C2 (LO METE DECODE_CANAL PARA MARCAR EL INICIO DE UNA PERCUSION)
    JR      NZ, CONTINUA_PERCUSION

    INC     HL                                  ; ES $C2, HAY QUE INICIAR UNA PERCUSION
    LD      A, (HL)                             ; LEEMOS CUAL
    INC     HL
    LD      (IX + 0), L                         ; ALMACENAMOS EN EL PUNTERO AL BUFFER DE PERCUSION
    LD      (IX + 1), H                         ; POR DONDE NOS LLEGAMOS.
    CALL    INICIA_PERCUSION                    ; INICIAMOS LA REPRODUCCION DE LA PERCUSION
    RET                                         ; Y SALIMOS

CONTINUA_PERCUSION:                                          ; ESTAMOS CONTINUANDO
    INC     HL                                  ; APUNTAMOS A LA SIGUIENTE POSICION DEL BUFFER
    BIT     7, A                                ; SI ESTÁ ACTIVO EL BIT MÁS SIGNIFICATIVO ESTAMOS EN EL FINAL
    JR      Z, NO_FIN_CANAL_P                   ;
    BIT     0, A                                ; SI ESTÁ ACTIVO EL BIT MENOS SIGNIFICATIVO, ES EL FINAL DE LA PERCUSION ($81)
    JR      Z, FIN_CANAL_P                      ; Y SI NO, ES FINAL DEL CANAL DE PERCUSION ($80)
FIN_NOTA_P:
    LD      DE, (CANAL_P)                       ; HA TERMINADO LA PERCUSION. 
    LD      (IX + 0), E                         ; RESETEAMOS EL PUNTERO AL INICIO DEL BUFFER DE DECODIFICACION
    LD      (IX + 1), D
    LD      HL, (PUNTERO_DECP)                  ; CARGA PUNTERO DECODER (PUNTERO POR DONDE VAMOS DEL CANAL P)
    PUSH    BC
    CALL    DECODE_CANAL                        ; Y DECODIFICAMOS EL CANAL EN EL BUFFER DE DECODIFICACION
    POP     BC
    LD      (PUNTERO_DECP), HL                  ; GUARDAMOS POR DONDE VAMOS DEL CANAL P
    JP      LOCALIZA_EFECTO                     ; Y SEGUIMOS LEYENDO DEL BUFFER DE DECODIFICACION.

FIN_CANAL_P:                                    ; HEMOS LLEGADO AL FINAL DEL CANAL.
    LD      HL, (PUNTERO_L_DECP)                ; HL = DIRECCION DE LOOP DEL CANAL P
    LD      (PUNTERO_DECP), HL                  ; LO GUARDAMOS COMO PUNTERO POR DONDE VAMOS DEL CANAL P
    JR      FIN_NOTA_P                          ; Y SEGUIMOS DECODIFICANDO

NO_FIN_CANAL_P: 
    LD      (IX + 0), L                         ; GUARDAMOS POR DONDE VAMOS EN EL BUFFER DE DECODIFICACION (PUNTERO_P)
    LD      (IX + 1), H
    RET                                         ; Y TERMINAMOS

; REPRODUCE LA PAUTA (INSTRUMENTO) PARA UN CANAL ESPECIFICADO.
; IX: PUNTERO A LA PAUTA A REPRODUCIR
; IY: PUNTERO AL REGISTRO DE FRECUENCIA DEL PSG PARA EL CANAL
; HL: PUNTERO AL REGISTRO DE VOLUMEN DEL PSG PARA EL CANAL

; FORMATO PAUTA (INSTRUMENTO):
;            7     6     5     4        3-0
; BYTE 1 (LOOP|OCT-1|OCT+1|ORNMT|   VOL    )
;                                       3-0
; BYTE 2 (    |     |     |     |PITCH/NOTA)
PAUTA:
    BIT     4, (HL)                             ; SI LA ENVOLVENTE ESTA ACTIVADA NO ACTUA PAUTA
    RET     NZ

    LD      A, (IY + 0)                         ; LEEMOS LA DIRECCION AL REGISTRO DE FRECUENCIA
    LD      B, (IY + 1)
    OR      B                                   ; SI ESTA A 0, TERMINAMOS.
    RET     Z

    PUSH    HL                                  ; GUARDAMOS EL PUNTERO AL REGISTRO DEL VOLUMEN DEL PSG
           
PAUTA_CHECK_LOOP:
    LD      L, (IX+0)                           ; HL = PUNTERO A LA POSICION DENTRO DE LA PAUTA
    LD      H, (IX+1)
    LD      A, (HL)                             ; LEEMOS EL PRIMER BYTE DE LA POSICION ACTUAL DE LA PAUTA
    
    BIT     7, A                                ; LOOP / EL RESTO DE BITS NO AFECTAN
    JR      Z, PAUTA_CHECK_MOD_OCTAVE_DOWN      ; SI NO HAY LOOP, CONTINUAMOS PROCESANDO LA PAUTA
    AND     00011111B                           ; MAXIMO LOOP PAUTA (0,32)X2!!!-> PARA ORNAMENTOS
    RLCA    ;X2                                 ; EL RESTO DEL BYTE INDICA EL OFFSET PARA ATRAS, TENIENDO EN CUENTA QUE SE INDICA EN WORDS
    LD      D, 0                                ; DE = OFFSET DEL LOOP
    LD      E, A
    SBC     HL, DE                              ; NOS COLOCAMOS EN LA POSICION DEL LOOP
    LD      A, (HL)                             ; Y LEEMOS EL BYTE (QUE NO PUEDE TENER LOOP!)

PAUTA_CHECK_MOD_OCTAVE_DOWN:
    BIT     6, A                                ; EL BIT 6 INDICA QUE HAY QUE BAJAR UNA OCTAVA (OCTAVA -1)
    JR      Z, PAUTA_CHECK_MOD_OCTAVE_UP        ; SI NO ESTÁ ACTIVO, PASAMOS A COMPROBAR EL SIGUIENTE BIT
    LD      E, (IY + 0)                         ; TENEMOS QUE BAJAR UNA OCTAVA
    LD      D, (IY + 1)                         ; DE = FRECUENCIA ACTUAL DEL PSG

    AND     A                                   ; LIMPIAMOS EL BIT DE ACARREO MANTENIENDO EL VALOR DE A
    ;RRC     D                                  ; DE = DE/2. ROTAMOS D A LA DERECHA, EL BIT SALIENTE SE METE EN C
    SRL     D                                   ; DE = DE/2. USO DESPLAZAMIENTO LOGICO PORQUE SON NUMEROS POSITIVOS. EL BIT 0 VA A CARRY
    RR      E                                   ; ROTAMOS A LA DERECHA E, METIENDO EL BIT DE ACARREO EN EL BIT 7
    LD      (IY + 0), E                         ; GUARDAMOS EL RESULTADO EN EL REGISTRO DE FRECUENCIA DEL PSG
    LD      (IY + 1), D
    JR      PAUTA_CHECK_PITCH_MODIFIERS         ; NO COMPROBAMOS SI HAY OTRO MODIFICADOR DE OCTAVA (NO DEBERIA HABERLO)
    
PAUTA_CHECK_MOD_OCTAVE_UP:
    BIT     5, A                                ; EL BIT 5 INDICA QUE HAY QUE SUBIR UNA OCTAVA (OCTAVA +1)
    JR      Z, PAUTA_CHECK_PITCH_MODIFIERS      ; SI NO ESTÁ ACTIVO, COMPROBAMOS SI HAY ORNAMENTOS.
    LD      E, (IY + 0)                         ; TENEMOS QUE SUBIR UNA OCTAVA
    LD      D, (IY + 1)                         ; DE = FRECUENCIA ACTUAL DEL PSG

    AND     A                                   ; LIMPIAMOS EL BIT DE ACARREO
    ;RLC     E
    SLA     E                                   ; DE = DE * 2. SHIFT ARITMETICO A LA DERECHA. C = bit 7
    RL      D                                   ; DE = DE * 2. METEMOS EL BIT 7 DE E EN EL BIT 0 DE D, ROTANDO A LA IZQUIERDA
    LD      (IY + 0), E                         ; GUARDAMOS EL RESULTADO EN EL REGISTRO DE FRECUENCIA DEL PSG
    LD      (IY + 1), D

PAUTA_CHECK_PITCH_MODIFIERS:
    LD      A, (HL)                             ; EN LOS MODIFICADORES PUEDE QUE HAYAMOS MODIFICADO A, ASI QUE LO VOLVEMOS A LEER
    BIT     4, A                                ; EL BIT 4 INDICA SI HAY QUE APLICAR PITCH (SLIDE)
    JR      NZ, PAUTA_APPLY_SEMITONES           ; SI NO ESTÁ SELECCIONADO ES QUE SUMAMOS SEMITONOS (ORNAMENTO / ARPEGIO)

    ; ______________________ FUNCION PITCH DE FRECUENCIA__________________
    INC     HL                                  ; APUNTAMOS AL SIGUIENTE BYTE (PITCH)
    PUSH    HL                                  ; GUARDAMOS LA POSICION ACTUAL DE LA PAUTA
    LD      E, A                                ; GUARDAMOS EL BYTE ORIGINAL EN E
    LD      A, (HL)                             ; LEEMOS EL PITCH DE FRECUENCIA
    LD      L, A                                ; GUARDAMOS EL PITCH EN L
    AND     A                                   ; COMPROBAMOS SI ES CERO EL PITCH
    LD      A, E                                ; RESTAURAMOS EL BYTE ORIGINAL DE LA PAUTA EN A
    JR      Z, PAUTA_UPDATE_POSITION           ; Y SI EL PITCH ERA CERO, SALTAMOS

    LD      A, (IY + 0)                         ; SI LA FRECUENCIA ES 0 NO HAY PITCH
    ADD     A, (IY + 1)
    AND     A
    LD      A, E                                ; VOLVEMOS A METER EN A EL BYTE ORIGINAL
    JR      Z, PAUTA_UPDATE_POSITION            ; SI LA FRECUENCIA ACTUAL ES 0 NO APLICAMOS PITCH

    BIT     7, L                                ; COMPROBAMOS SI EL PITCH ES NEGATIVO
    JR      Z, PAUTA_POSITIVE_PITCH             ; SI ES POSITIVO COMPLETAR CON 0
    LD      H, $FF                              ; NEGATIVO, COMPLETAMOS CON 0xFF EL BYTE ALTO (SIGNO)
    JR      PAUTA_APPLY_PITCH                  ; Y A APLICAR EL PITCH

PAUTA_POSITIVE_PITCH:
    LD      H, 0                                ; EL PITCH ES POSITIVO, COMPLETAMOS EL BYTE ALTO CON 0x00 (SIGNO)

PAUTA_APPLY_PITCH:
    LD      E, (IY + 0)                         ; CARGAMOS LA FRECUENCIA ACTUAL EN DE
    LD      D, (IY + 1)
    ADC     HL, DE                              ; SUMAMOS EL PITCH
    LD      (IY + 0), L                         ; GUARDAMOS EL RESULTADO
    LD      (IY + 1), H
    JR      PAUTA_UPDATE_POSITION

;______________________ FUNCION ORNAMENTOS__________________  
PAUTA_APPLY_SEMITONES:
    INC     HL                                  ; APUNTAMOS AL SIGUIENTE BYTE DE LA PAUTA (SEMITONOS)
    PUSH    HL                                  ; GUARDAMOS LA POSICION
    PUSH    AF                                  ; Y EL VALOR DEL BYTE ANTERIOR
    LD      A, (IX + 24)  ; A = NOTA ACTUAL DEL CANAL
    LD      E, (HL)    ;                        ; E = INCREMENTO/DECREMENTO EN SEMITONOS
    ADC     A,E    ;+- NOTA                       ; A = NOTA ACTUAL + INCREMENTO
    CALL    TABLA_NOTAS                         ; EXTRAE LA FRECUENCIA DE LA NOTA CON INCREMENTO, Y LA PONE EN (IY)
    POP     AF                                  ; RESTAURA EL VALOR PREVIO DE A
    
PAUTA_UPDATE_POSITION:
    POP     HL                                  ; RECUPERA DE LA PILA LA POSICION ACTUAL DE LA PAUTA
    INC     HL                                  ; APUNTA AL SIGUIENTE BYTE
    LD      (IX + 0), L                         ; Y LO GUARDA EN EL PUNTERO A LA PAUTA
    LD      (IX + 1), H

PAUTA_CHECK_MOD_VOLUME:
    POP     HL                                  ; RECUPERAMOS EL VOLUMEN DEL PSG
    AND     15                                  ; NOS QUEDAMOS CON LOS CUATRO PRIMEROS BITS
    LD      C, A                                ; CARGAMOS EL VOLUMEN EN C
    LD      A, (IX + 25)  ; CARGAMOS EL PUNTERO AL VOLUMEN ACTUAL (VOLUMEN RELATIVO)
    BIT     4, A                                ; COMPROBAMOS SI ES NEGATIVO
    JR      Z, PAUTA_ADD_VOLUME_MODIFIER
    OR      $F0                                 ; SI LO ES, PONEMOS EL SIGNO
PAUTA_ADD_VOLUME_MODIFIER:
    ADD     A, C                                ; SUMAMOS EL MODIFICADOR DEL VOLUMEN CON EL VOLUMEN ACTUAL
    JP      P, PAUTA_RES_VOLUME_POSITIVE        ; SI EL RESULTADO ES MAYOR QUE CERO VEMOS QUE NO NOS HAYAMOS PASADO
    LD      A, 1                                ; SI EL VOLUMEN ES NEGATIVO, LO PONEMOS A 1
PAUTA_RES_VOLUME_POSITIVE:
    CP      15                                  ; COMPARAMOS A VER SI EL VOLUMEN ES MENOR O IGUAL A 15
    JP      M, PCAJP8                           ; SI ES MENOR, PASAMOS A GUARDAR EL VALOR
    LD      A, 15                               ; SI NO ES ASI, FIJAMOS EL VALOR A 15
PCAJP8:
    LD      (HL), A                             ; GUARDAMOS EL VOLUMEN RESULTADO
    RET

;NOTA : BUSCA LA ENVOLVENTE O LA FRECUENCIA DE LA NOTA Y LA ALMACENA EN (IY).
;IN (A)  = CODIGO DE LA NOTA
;   (IY) = REGISTROS DE FRECUENCIA
;   BC   = VOLUMEN DE LA NOTA
NOTA:
    LD      L, C                                ; PONEMOS EL VOLUMEN EN HL
    LD      H, B
    BIT     4, (HL)                             ; COMPARAMOS SI EL BIT 4 ESTA ACTIVADO
    LD      B, A                                ; Y GUARDAMOS EL CODIGO DE LA NOTA EN B
    JR      NZ, EVOLVENTES                      ; SI EL BIT 4 ESTA ACTIVO, TENEMOS QUE REPRODUCIR UNA ENVOLVENTE

;; CREO QUE SOBRA...
;;    LD      A, B                              ; RESTAURAMOS EL CODIGO DE LA NOTA

; TABLA NOTAS
; IN:  (A)  = NOTA
; OUT: (IY) = FRECUENCIA DE LA NOTA
TABLA_NOTAS:
    LD      HL, ($CD04) ;DATOS_NOTAS                     ; DATOS_NOTAS ES UN PUNTERO EXTERNO A LAS FRECUENCIAS POR CADA NOTA
    CALL    EXT_WORD                            ; OBTENEMOS EL VALOR APUNTADO POR A
    LD      (IY + 0), L                         ; Y GUARDAMOS EL RESULTADO (16 BIT) EN (IY)
    LD      (IY + 1), H
    RET

;IN (A)  = CODIGO DE LA ENVOLVENTE
;   (IY) = REGISTRO DE FRECUENCIA
;   BC   = VOLUMEN DE LA NOTA
EVOLVENTES:
    LD      HL, ($CD04) ;DATOS_NOTAS                     ; APUNTAMOS A DATOS_NOTAS CON HL
    CALL    EXT_WORD
    
    PUSH    HL                                  ; GUARDAMOS EL RESULTADO EN LA PILA
    LD      A, (ENVOLVENTE)                     ; OBTENEMOS EL CODIGO DE LA ENVOLVENTE
    RRA                                         ; DIVIDIMOS POR 2, Y PONEMOS EN ACARREO EL BIT 0
    JR      C, ENV_ALMACENA_FRECUENCIA          ; SI EL BIT 0 ERA 0, PONEMOS LA FRECUENCIA A CERO
    LD      HL, $0000                           ; PONEMOS LA FRECUENCIA A 0

ENV_ALMACENA_FRECUENCIA:
    LD      (IY + 0), L                         ; GUARDAMOS LA FRECUENCIA EN IY
    LD      (IY + 1), H

;CALCULO DEL RATIO (OCTAVA ARRIBA)
    POP     DE                                  ; LA FRECUENCIA ORIGINAL ESTA AHORA EN DE
    PUSH    AF                                  ; GUARDAMOS EL CODIGO DE LA ENVOLVENTE
    PUSH    BC                                  ; GUARDAMOS EL VOLUMEN
    AND     00000011B                           ; NOS QUEDAMOS CON LOS DOS BITS INFERIORES DE LA ENVOLVENTE
    LD      B, A                                ; Y LO GUARDAMOS EN B
    ;INC  B
    
    ;AND  A      ;1/2
    SRL     D                                   ; DE = DE/2. USO DESPLAZAMIENTO LOGICO PORQUE SON NUMEROS POSITIVOS. EL BIT 0 VA A CARRY
    RR      E                                   ; ROTAMOS A LA DERECHA E, METIENDO EL BIT DE ACARREO EN EL BIT 7
ENV_DIVIDE_FREQ:
    ;AND  A      ;1/4 - 1/8 - 1/16              ; DIVIDIMOS LA FRECUENCIA SEGUN EL VALOR DE B; B=1, DE=DE/4. B=2, DE=DE/8. B=3, DE=DE/16
    SRL     D                                   ; DE = DE/2
    RR      E
    DJNZ    ENV_DIVIDE_FREQ                     ; SI AUN NO HEMOS TERMINADO, SIGUE DIVIDIENDO
    LD      A, E                                ; GUARDAMOS EL RESULTADO EN LOS REGISTROS PSG 11 y 12.
    LD      (PSG_REG + 11), A
    LD      A, D
    AND     00000011B                           ; EL BYTE ALTO PUEDE VALER ENTRE 0 y 3
    LD      (PSG_REG + 12), A
    POP     BC                                  ; RESTAURAMOS EL VOLUMEN
    POP     AF                                  ; RESTAURAMOS EL CODIGO DE ENVOLVENTE ($08, $0A, $0C, $0E)

    SRA     A                                   ; DIVIDIMOS EL CODIGO ENTRE DOS
    AND     00000110B                           ; NOS QUEDAMOS CON LOS BITS 1 y 2. 
    ADD A,8                                   ; SUMAMOS 8
    LD      (PSG_REG + 13), A                   ; Y GUARDAMOS EL CODIGO DE LA ENVOLVENTE EN EL REGISTRO 13
    LD      (ENVOLVENTE_BACK), A                ; Y EN EL BACKUP DE LA ENVOLVENTE
    RET

;EXTRAE UN WORD DE UNA TABLA
;IN:(HL)=DIRECCION TABLA
;   (A)= POSICION
;OUT(HL)=WORD
EXT_WORD:
    LD      D, 0                                ; D = 0
    RLCA                                        ; A = A x 2
    LD      E, A                                ; DE = A x 2
    ADD     HL, DE                              ; HL = HL + 2 x A
    LD      E, (HL)                             ; CARGAMOS EN DE EL WORD EN LA POSICION A
    INC     HL
    LD      D, (HL)
    EX      DE, HL                              ; PONEMOS EL WORD EN HL
    RET







;.filename "phantis"	;NOMBRE DEL ARCHIVO ROM / ENSAMBLADO CON ASMSX
;.page   1
;.ROM

; VARIABLES DEL SISTEMA
CLIKSW	        EQU     $F3DB
HOOK            EQU     $FD9A

;RETARDO DE LAS INTERRUPCIONES
;DLAY60H         EQU     $cd00
;DLAYFX          EQU     $cd01

;#INCLUDE "C:\Dany\App\WYZplayer\PLAYER_CONSTS.ASM"
;#INCLUDE "C:\Dany\App\WYZplayer\PLAYER_MSX.ASM"
;#INCLUDE "C:\Dany\App\WYZplayer\SYSVAR.ASM"
;archivo de instrumentos
;#INCLUDE "C:\Dany\App\WYZplayer\n2_cell3.mus.asm"

;#INCLUDE "C:\Dany\App\WYZplayer\PLAYER.ASM"

WYZ_PLAYER_BUFFER EQU   $cc00

;XX!! WYZPLAYER MAIN

; AJUSTES INICIALES
SPOINT:
;***

AJUSTES:
        push af
        CALL    WYZ_PLAYER_INIT
        DI
        ;LD      A,0                     ;REPRODUCIR LA CANCION N� 0
        pop af
        CALL    CARGA_CANCION

;INICIA INTERRUPCIONES*****
        ;CALL   SET_INTERR
        ;LD      HL, WYZ_PLAYER_TICK
        ;LD      (HOOK + 1), HL
        ;LD      A, $C3
        ;LD      (HOOK), A
        EI

LOOP:   RET 

        ;JP      LOOPXXX ;*********

; SET_INTERR:
;         LD      A, $C9           ;INT OFF
;         LD      (HOOK_F), A
;         LD      A, (VERSION)     ;NACIONALIDAD DEL MSX
;         AND     A                ;=0 JAPONES =1 KOREANO =2 INTERNACIONAL
;         LD      HL, INICIO       ;GANCHO PARA 50 Hz
;         JP      M, NO_JAPO
;         LD      HL, F60HZ        ;GANCHO PARA 60 Hz
;         LD      A, $06           ;RETARDO PARA 60 HZ
;         LD      (DLAY60H), A
;         LD      (DLAYFX), A
; NO_JAPO:
;         LD      (HOOK_F+1), HL
;         LD      A, $C3
;         LD      (HOOK_F), A      ;INT ON 
;         IM      1
;         EI
;         RET
; F60HZ:
;         LD      HL, DLAY60H
;         DEC     (HL)
;         JP      NZ, INICIO
;         LD      A, (DLAYFX)
;         LD      (HL), A
;         RET


  

;SONG_0:
;#INCLUDE "C:\Dany\App\WYZplayer\phantis.mus" ;MÓDULO GENERADO POR WYZTRACKER****

TABLA_SONG:
       ; DW      SONG_0,SONG_1,SONG_2,SONG_3

DW *DWSONGS*

;Código del player1
		
;XX!! WYZPLAYER END  

