VOC.H
///////////////////////
// Variables globales //
///////////////////////
WORD BPORT=0x210; WORD XPORT=0x216; WORD WPORT=0x21c;
WORD RPORT=0x21a; WORD APORT=0x21e; BYTE READY=0xaa;
WORD longitud=0; WORD alojado; WORD frecuencia;
// Rutinas de E/S
// puerto,valor
void EscribeEnPuerto(WORD,BYTE);
// puerto
BYTE LeeDePuerto(WORD);
// valor
void EscribeEnDSP(BYTE);
// Rutinas de la Sound Blaster
void ResetearSB(void);
BOOL DetectarSB(void);
void ErrorSB(void);
void SpeakerOn(void);
void SpeakerOff(void);
// Rutinas de los ficheros .VOC y .SMP
void CargaVoc(char [12]);
void CargaSmp(char [12]);
// frecuencia
void VocOn(WORD);
VOC.C
#include "voc.h"
void EscribeEnPuerto(WORD puerto,BYTE valor)
{
asm{
mov al,valor
mov dx,puerto
out dx,al
}
}
BYTE LeeDePuerto(WORD puerto)
{
BYTE result;
asm{
mov dx,puerto
in al,dx
mov byte ptr result,al
}
return result;
}
void EscribeEnDSP(BYTE valor)
{
test1:
asm{
mov dx,WPORT
in al,dx
and al,0x80
cmp al,0
jnz test1
mov al,byte ptr valor
out dx,al
}
}
void ResetearSB(void)
{
EscribeEnPuerto(XPORT,1);
delay(5);
EscribeEnPuerto(XPORT,0);
}
// Si se encuentra la Sound Blaster, devuelve un 1. Un 0 si no se encuentra
BOOL DetectarSB(void)
{
BYTE estado,cont;
estado=0;
while ((estado!=READY)&&(BPORT<0x270))
{
// Reseteo de la Sound Blaster
EscribeEnPuerto(XPORT,1);
// Como m¡nimo hay que esperar 3,3 milisegundos.5 para
asegurarnos
delay(5);
EscribeEnPuerto(XPORT,0);
cont=0;
while ((estado!=READY)&&(cont<100))
{
estado=LeeDePuerto(RPORT);
cont++;
}
// Se buscan los puertos de la Sound Blaster
if (estado!=READY)
{
BPORT+=0x10;
XPORT+=0x10;
WPORT+=0x10;
RPORT+=0x10;
APORT+=0x10;
}
}
if (BPORT!=0x270)
{
while ((LeeDePuerto(WPORT)&128)!=0);
EscribeEnPuerto(WPORT,0xd1);
// Activa la salida digital mediante el DAC
SpeakerOn();
return (1);
}
return (0);
}
void SpeakerOn(void)
{
EscribeEnDSP(0xd1);
}
void SpeakerOff(void)
{
EscribeEnDSP(0xd3);
}
void ErrorSB(void)
{
printf("\nNo se ha encontrado la Sound Blaster\n");
exit (0);
}
void CargaVoc(char nombre[12])
{
FILE *ficherovoc;
ficherovoc=fopen(nombre,"rb");
if (!ficherovoc)
{
printf("\nNo se encuentra el fichero %s",nombre);
exit (0);
}
fseek(ficherovoc,0L,SEEK_END);
// 32:20 de cabecera global,12 de cabecera de bloque.100 para
evitar el
// chasquido del final
longitud=ftell(ficherovoc)-32-100;
fseek(ficherovoc,30,0);
frecuencia=getc(ficherovoc);
frecuencia=1000000L/(256l-(frecuencia));
fseek(ficherovoc,32L,SEEK_SET);
fread(zona5,longitud,1,ficherovoc);
fclose(ficherovoc);
}
void VocOn(WORD voc)
{
WORD dmaoffset,pagina,segmento,desplazamiento;
BYTE tamanoalta,tamanobaja,canaldma=1;
WORD tiempo;
segmento=FP_SEG(zona5);
desplazamiento=FP_OFF(zona5);
asm{
// Transforma la direcci¢n
mov ax,word ptr segmento
mov cl,4
shl ax,cl
add ax,word ptr desplazamiento
mov word ptr dmaoffset,ax
mov ax,word ptr desplazamiento
mov cl,4
shr ax,cl
add ax,word ptr segmento
mov cl,12
shr ax,cl
mov word ptr pagina,ax
mov dx,0xa
// Configura el DMA
mov al,5
out dx,al
mov dx,0xc
xor al,al
out dx,al
mov dx,0xb
mov al,0x49
out dx,al
mov ax,word ptr dmaoffset
mov dx,2
out dx,al
xchg ah,al
out dx,al
mov dx,0x83
mov al,byte ptr pagina
out dx,al
mov dx,3
mov ax,word ptr longitud
// Se indica al DMA cu ntos bytes debe transmitir
dec ax
out dx,al
xchg ah,al
out dx,al
mov dx,0xa
mov al,byte ptr canaldma
out dx,al
// Habilita el canal de DMA
mov bx,word ptr longitud
mov byte ptr tamanobaja,bl
mov byte ptr tamanoalta,bh
}
if (voc==0) tiempo=256-(1000000/8000);
else tiempo=256-(1000000/voc);
// Espera para que la SB se reajuste a lo indicado en Ensamblador,
arriba
delay(100);
// Establece la frecuencia del DSP
EscribeEnDSP(0x40);
EscribeEnDSP(tiempo);
EscribeEnDSP(0x14);
// Empieza la transferencia
EscribeEnDSP(tamanobaja);
EscribeEnDSP(tamanoalta);
}
EJEMPLO DE USO
void main(void)
{
if ((zona5=malloc(65535))==NULL) printf("\nNo hay memoria base
suficiente");
if (!DetectarSB())
{
exit (0);
}
printf("\nSound Blaster detectada e inicializada. Pulse una tecla
para la reproducci¢n");
getch();
CargaVoc("1.voc");
VocOn(0);
getch();
CargaVoc("1.smp");
VocOn(5000);
getch();
CargaVoc("jd1.voc");
VocOn(0);
getch();
CargaVoc("jd2.voc");
VocOn(0);
getch();
CargaVoc("jd3.voc");
VocOn(0);
getch();
CargaVoc("jd4.voc");
VocOn(0);
getch();
free(zona5);
}
SBMOD.H
// Detecta e inicializa la interrupción y el puerto DMA de la
Sound Blaster.
// Si no hay una tarjeta Sound Blaster instalada devuelve
0 (error), en
// caso contrario devuelve -1.
extern int far SBMOD_DetectSB(void);
// Carga en memoria el módulo <fileName>.
// Si no encuentra el fichero o no hay memoria suficiente
para ubicarlo
// devuelve 0 (error), en caso contrario devuelve -1.
extern int far SBMOD_LoadModule(char far *fileName);
// Descarga de la memoria el módulo actual.
extern void far SBMOD_FreeModule(void);
// Comienza la ejecución background (de fondo) del módulo
actual.
extern void far SBMOD_Play(void);
// Detiene la ejecución del m¢dulo actual.
extern void far SBMOD_Stop(void);
CARGAMOD.ASM
SBMOD_FreeModule EndP
ClearModInfo Proc Near
pusha
push es
mov ax,ds
mov es,ax
lea di,[ModInfo]
mov cx,Size ModInfoRec
cld
xor ax,ax
rep stosb
pop es
popa
ret
ClearModInfo EndP
End
SB.ASM
DosSeg
; Ordenaci¢n de segmentos DOS
Jumps
; Para resolver los saltos
; fuera de rango
.Model large,C
; Modelo de memoria Large de C
.286
; Instrucciones 80286
.Stack 0400h
; Pila de 1Kb
;--------------------------------------------------------------------------
;
Variables y procedimientos globales
;--------------------------------------------------------------------------
Global SBMOD_DetectSB:Proc
Global SBMOD_Play:Proc, SBMOD_Stop:Proc
Global SbPoll:Proc, StartPlaying:Proc,
StopPlaying:Proc
Global SbAddr:Word, SbIrq:Word,
DmaBuffer:Word
Global GetSamples:Proc, MixSpeed:Word
DmaBufSize equ
2048
;--------------------------------------------------------------------------
;
Datos
;--------------------------------------------------------------------------
.Data
SbAddr dw
220h
SbIrq dw
7
DmaFlag dw
?
DmaBuffer dw
?
DmaHandler dd
?
TimerHandler dd ?
DoubleBuffer db 2*DmaBufSize
dup (?)
;--------------------------------------------------------------------------
;
C¢digo
;--------------------------------------------------------------------------
.Code
;--------------------------------------------------------------------------
; SbOut: Env¡a un byte a la Sound Blaster
; In:
; DX - Puerto de escritura de la Sound Blaster
;--------------------------------------------------------------------------
SbOut Macro
Data
Local Esperar
Esperar: in
al,dx
or al,al
js Esperar
mov al,Data
out dx,al
EndM
;--------------------------------------------------------------------------
; SbIrqHandler: Manejador de la interruci¢n de la Sound
Blaster
;--------------------------------------------------------------------------
SbIrqHandler Proc
push ax
push dx
push ds
mov ax,@Data
mov ds,ax
mov dx,[SbAddr]
add dx,0Eh
in al,dx
sub dx,02h
SbOut 14h
SbOut 0FFh
SbOut 0FFh
mov al,20h
out 20h,al
pop ds
pop dx
pop ax
iret
SbIrqHandler EndP
;--------------------------------------------------------------------------
; SbPoll: Polling de la Sound Blaster
;--------------------------------------------------------------------------
SbPoll Proc
pusha
push ds
push es
mov ax,@Data
mov ds,ax
in al,03h
mov cl,al
in al,03h
mov ch,al
mov ax,[DmaFlag]
;Hacemos la primera parte del proceso
test ax,ax
jne SegundaParte
cmp cx,DmaBufSize/2
jae Fin
mov si,[DmaBuffer]
mov cx,DmaBufSize/2
call GetSamples Pascal,ds,si,cx
inc [DmaFlag]
jmp Fin
SegundaParte: cmp cx,DmaBufSize/2
;Ahora la segunda
jb Fin
mov si,[DmaBuffer]
mov cx,DmaBufSize/2
add si,cx
call GetSamples Pascal,ds,si,cx
dec [DmaFlag]
Fin:
pop es
pop ds
popa
iret ;<====
IRET
SbPoll EndP
;--------------------------------------------------------------------------
; SbInit: Inicializa el Driver de la Sound Blaster
;--------------------------------------------------------------------------
SBMOD_Play Proc Far
pusha
push ds
push es
mov ax,@Data
mov ds,ax
mov [MixSpeed],18000
call StartPlaying
cli
in al,21h
push ax
mov al,11111111b
out 21h,al
mov [DmaFlag],0
;Establecemos el buffer
mov ax,offset
DoubleBuffer
mov [DmaBuffer],ax
mov dx,ds
mov bx,dx
shr dh,4
shl bx,4
add ax,bx
adc dh,0
mov cx,ax
neg cx
cmp cx,DmaBufSize
jae PonerDma
add [DmaBuffer],cx
add ax,cx
adc dh,0
PonerDma: mov
bx,ax
mov cx,DmaBufSize
dec cx
mov al,05h
out 0Ah,al
xor al,al
out 0Ch,al
mov al,bl
out 02h,al
mov al,bh
out 02h,al
mov al,dh
out 83h,al
mov al,cl
out 03h,al
mov al,ch
out 03h,al
mov al,59h
out 0Bh,al
mov al,01h
out 0Ah,al
mov di,[DmaBuffer]
; Se borra el buffer
mov cx,DmaBufSize
mov ax,ds
mov es,ax
mov al,80h
cld
rep stosb
xor ax,ax
; Se establece la IRQ
mov es,ax
mov bx,[SbIrq]
add bx,08h
shl bx,2
mov ax,es:[bx]
mov dx,es:[bx+2]
mov Word Ptr
[DmaHandler],ax
mov Word Ptr
[DmaHandler+2],dx
mov ax,offset
SbIrqHandler
mov dx,seg SbIrqHandler
mov es:[bx],ax
mov es:[bx+2],dx
mov ax,es:[70h]
; Ahora se configura el Timer
mov dx,es:[72h]
mov Word Ptr
[TimerHandler],ax
mov Word Ptr
[TimerHandler+2],dx
mov ax,offset
SbPoll
mov dx,seg SbPoll
mov es:[70h],ax
mov es:[72h],dx
mov dx,[SbAddr]
; Reseteamos el DSP
add dx,06h
mov al,1
out dx,al
in al,dx
in al,dx
in al,dx
in al,dx
xor al,al
out dx,al
mov cx,100
Esperar: mov
dx,[SbAddr] ; Se espera hasta que la SB conteste
add dx,0Eh
in al,dx
or al,al
js GetID
loop Esperar
jmp Exit
GetId: mov dx,[SbAddr]
; Ya sabemos que est la SB
add dx,0Ah
; Ahora hay que encontrar el puerto BASE
in al,dx
cmp al,0AAh
SbOk: je SbOk
loop Esperar
jmp Exit
mov dx,[SbAddr]
; Ya se ha detectado el hardware
add dx,0Ch
SbOut 0D1h
mov ax,1000
mul ax
div [MixSpeed]
neg al
mov ah,al
mov dx,[SbAddr]
; Convertimos la Frecuencia de Muestreo
add dx,0Ch
; para que la SB la entienda
SbOut 40h
; Aqu¡ se establece
SbOut ah
SbOut 14h
; Se comienza la transferencia y se deja
SbOut 0FFh
; al DMA y al DSP que se comuniquen ellos
Sbout 0FFh
; solos sin mediaci¢n de la CPU
Exit: pop ax
mov cx,[SbIrq]
mov ah,1
shl ah,cl
not ah
and al,ah
out 21h,al
sti
pop es
pop ds
popa
ret
SBMOD_Play EndP
;--------------------------------------------------------------------------
; SbDone: Descarga el Driver de la Sound Blaster
;--------------------------------------------------------------------------
SBMOD_Stop Proc Far
pusha
push ds
push es
mov ax,@Data
mov ds,ax
cli
in al,21h
push ax
mov al,11111111b
out 21h,al
xor ax,ax
mov es,ax
mov bx,[SbIrq]
add bx,08h
shl bx,2
mov ax,Word Ptr
[DmaHandler]
mov dx,Word
ptr [DmaHandler+2]
mov es:[bx],ax
mov es:[bx+2],dx
mov ax,Word Ptr
[TimerHandler]
mov dx,Word
ptr [TimerHandler+2]
mov es:[70h],ax
mov es:[72h],dx
mov dx,[SbAddr]
add dx,0Ch
SbOut 0D0h
SbOut 0D3h
pop ax
mov cx,[SbIrq]
mov ah,1
shl ah,cl
or al,ah
out 21h,al
sti
call StopPlaying
pop es
pop ds
popa
ret
SBMOD_Stop EndP
;--------------------------------------------------------------------------
; DetectSB: Para detectar
la presencia de la SB
;--------------------------------------------------------------------------
SBMOD_DetectSB Proc Far
; Al salir: AX=0 si error, -1 si no error.
push ds
push es
mov ax,@Data
; DS apunta a mi segmento de datos
mov ds,ax
mov bx,210h
; Scaneo de puerto
; 210h, 220h, .. 260h
ReseteaDSP: mov dx,bx
; Intento resetear el DSP.
add dx,06h
mov al,1
out dx,al
in al,dx
in al,dx
in al,dx
in al,dx
xor al,al
out dx,al
add dx,08h
mov cx,100
EsperarIdentif: in al,dx
or al,al
js GetID2
loop EsperarIdentif
jmp SiguientPuerto
GetId2: sub dx,04h
in al,dx
cmp al,0AAh
je Encontrado
add dx,04h
loop EsperarIdentif
SiguientPuerto: add bx,10h
; Si no hay respuesta,
cmp bx,260h
; se intenta con el siguiente puerto
jbe ReseteaDSP
jmp Fallo
Encontrado: mov [SbAddr],bx
; Se encontr¢ la SB
cli
; Ahora se busca la IRQ de la SB
in al,21h
; Salvamos el IMR.
mov bl,al
mov al,11111111b
; Desactivamos todas las IRQ
out 21h,al
xor ax,ax
; Las provamos IRQ:2,3,5,7.
mov es,ax
; Primero las guardamos para luego
mov ax,es:[28h]
; IRQ2
mov dx,es:[2Ah]
push ax
push dx
mov ax,es:[2Ch]
; IRQ3
mov dx,es:[2Eh]
push ax
push dx
mov ax,es:[34h]
; IRQ5
mov dx,es:[36h]
push ax
push dx
mov ax,es:[3Ch]
; IRQ7
mov dx,es:[3Eh]
push ax
push dx
; Ahora las cambiamos
mov ax,offset
TrapIrq2 ; IRQ2
mov es:[28h],ax
mov es:[2Ah],cs
mov ax,offset
TrapIrq3 ; IRQ3
mov es:[2Ch],ax
mov es:[2Eh],cs
mov ax,offset
TrapIrq5 ; IRQ5
mov es:[34h],ax
mov es:[36h],cs
mov ax,offset
TrapIrq7 ; IRQ7
mov es:[3Ch],ax
mov es:[3Eh],cs
mov al,bl
; Y habilitamos las IRQs 2,3,5,7.
and al,01010011b
out 21h,al
sti
mov [SbIrq],0
; Borramos el nivel de la IRQ
mov dx,[SbAddr]
; Le decimos a la SB que genere
add dx,0Ch
; una IRQ
EsperarSb: in
al,dx
or al,al
js EsperarSb
mov al,0F2h
out dx,al
xor cx,cx
; Esperamos hasta que el nivel IRQ
EsperarIRQ: cmp [SbIrq],0
; cambie, o se acabe el tiempo
jne IrqOk
loop EsperarIRQ
IrqOk: mov al,bl
; La IRQ est bien y restauramos el IMR
out 21h,al
cli
; Se restauran los vectores IRQ
xor ax,ax
mov es,ax
pop dx
; IRQ7
pop ax
mov es:[3Ch],ax
mov es:[3Eh],dx
pop dx
; IRQ5
pop ax
mov es:[34h],ax
mov es:[36h],dx
pop dx
; IRQ3
pop ax
mov es:[2Ch],ax
mov es:[2Eh],dx
pop dx
; IRQ2
pop ax
mov es:[28h],ax
mov es:[2Ah],dx
cli
cmp [SbIrq],0
; Se pregunta si el nive de IRQ
je Fallo
; ha cambiado, si no, falla
mov ax,-1
; Ha habido ‚xito, devolveremos -1
jmp DetectSalir
Fallo: mov
ax,0
DetectSalir: pop es
pop ds
ret
SBMOD_DetectSB EndP
;---------------------------------------------------------------------------
; TrapIrq Para detectar las IRQ
;---------------------------------------------------------------------------
TrapIrq Proc
Far
push dx
; General IRQ "trapper"
push ds
; Usado para la autodetecci¢n
; de las IRQ
mov dx,@Data
mov ds,dx
mov [SbIrq],ax
; Salva el nivel IRQ
mov dx,[SbAddr]
add dx,0Eh
in al,dx
; SB reconocida
mov al,20h
out 20h,al
; Hardware reconocido
pop ds
pop dx
pop ax
iret
; Fin
IRP Level,<2,3,5,7>
TrapIrq&Level: push ax
mov ax,Level
jmp TrapIrq
EndM
TrapIrq EndP
End
PONERMOD.ASM
Jumps
.Model large,C
.286
;--------------------------------------------------------------------------
;
Publico
;--------------------------------------------------------------------------
Global StartPlaying: Proc, StopPlaying:
Proc
Global GetSamples: Proc
Global MixSpeed: Word, ModInfo:Byte
;--------------------------------------------------------------------------
;
Constantes
;--------------------------------------------------------------------------
NumTracks equ
4
DefTempo equ
6
DefBpm equ
125
MidCRate equ
8448
MixBufSize equ
4096
;--------------------------------------------------------------------------
;
Estructuras
;--------------------------------------------------------------------------
TrackInfo Struc
Samples dd
?
Position dw
?
Len
dw ?
Repeat dw
?
RepLen dw
?
Volume db
?
Error db
?
Period dw
?
Pitch dw
?
Effect dw
?
PortTo dw
?
PortParm db
?
VibPos db
?
VibParm db
?
OldSampOfs db
?
Arp
dw ?,?,?
ArpIndex dw
?
TrackInfo EndS
;--------------------------------------------------------------------------
;
Datos
;--------------------------------------------------------------------------
.Data
SinTable db
0,25,50,74,98,120,142,162,180,197,212,225
db 236,244,250,254,255,254,250,244,236,225
db 212,197,180,162,142,120,98,74,50,25
PeriodTable dw
856,808,762,720,678,640,604,570,538,508,480,453
dw 428,404,381,360,339,320,302,285,269,254,240,226
dw 214,202,190,180,170,160,151,143,135,127,120,113
MixSpeed dw
?
ModInfo Label
Byte
OrderLen db
?
ReStart db
?
Order db
128 dup (?)
Patterns dd
?
SampOfs dw
31 dup (?)
SampSeg dw
31 dup (?)
SampLen dw
31 dup (?)
SampRep dw
31 dup (?)
SampRepLen dw
31 dup (?)
SampVol dw
31 dup (?)
OrderPos db
?
Tempo db
?
TempoWait db
?
Bpm
db ?
Row
db ?
BreakRow db
?
BpmSamples dw
?
BufPtr dw
?
BufLen dw
?
BufRep dw
?
Note
dd ?
Tracks TrackInfo
NumTracks dup (?)
PitchTable dw
857 dup (?)
VolTable db
16640 dup (?)
MixBuffer db
MixBufSize dup (?)
;--------------------------------------------------------------------------
;
C¢digo.
;--------------------------------------------------------------------------
.Code
;--------------------------------------------------------------------------
; BeatTrack: Procesa el nuevo "beat" en un track
; In:
; ds:di - Informaci¢n de la direcci¢n
del Track
;--------------------------------------------------------------------------
BeatTrack Proc
Near
mov dx,[di+Effect]
test dx,dx
je None
cmp dh,00h
je Arpeggio
cmp dh,01h
je PortUp
cmp dh,02h
je PortDown
cmp dh,03h
je TonePort
cmp dh,04h
je Vibrato
cmp dh,05h
je PortSlide
cmp dh,06h
je VibSlide
cmp dh,0Ah
je VolSlide
None: ret
Arpeggio: mov
bx,[di+ArpIndex]
mov ax,[di+Arp+bx]
mov [di+Pitch],ax
add bx,2
cmp bx,6
jb SetArpIndex
xor bx,bx
SetArpIndex: mov [di+ArpIndex],bx
ret
PortUp: xor
dh,dh
mov bx,[di+Period]
sub bx,dx
cmp bx,113
jge NotSmall
mov bx,113
NotSmall: mov
[di+Period],bx
add bx,bx
mov ax,[PitchTable+bx]
mov [di+Pitch],ax
ret
PortDown: xor
dh,dh
mov bx,[di+Period]
add bx,dx
cmp bx,856
jle NotBig
mov bx,856
NotBig: mov
[di+Period],bx
add bx,bx
mov ax,[PitchTable+bx]
mov [di+Pitch],ax
ret
TonePort: xor
dh,dh
mov ax,[di+PortTo]
mov bx,[di+Period]
cmp bx,ax
je NoPort
jg PortToUp
PortToDown: add bx,dx
cmp bx,ax
jle SetPort
FixPort: mov
bx,ax
jmp SetPort
PortToUp: sub
bx,dx
cmp bx,ax
jl FixPort
SetPort: mov
[di+Period],bx
add bx,bx
mov ax,[PitchTable+bx]
mov [di+Pitch],ax
NoPort: ret
Vibrato: mov
dh,dl
and dl,0Fh
shr dh,4
shl dh,2
add [di+VibPos],dh
mov dh,[di+VibPos]
mov bl,dh
shr bl,2
and bx,1Fh
mov al,[SinTable+bx]
mul dl
rol ax,1
xchg al,ah
and ah,1
test dh,dh
jns VibUp
neg ax
VibUp: add
ax,[di+Period]
mov bx,ax
cmp bx,113
jge NoLoVib
mov bx,113
NoLoVib: cmp
bx,856
jle NoHiVib
mov bx,856
NoHiVib: add
bx,bx
mov ax,[PitchTable+bx]
mov [di+Pitch],ax
ret
PortSlide: call VolSlide
mov dl,[di+PortParm]
jmp TonePort
VibSlide: call
VolSlide
mov dl,[di+VibParm]
jmp Vibrato
VolSlide: mov
dh,dl
and dl,0Fh
shr dh,4
mov al,[di+Volume]
sub al,dl
jge NoLoVol
xor al,al
NoLoVol: add
al,dh
cmp al,64
jbe NoHiVol
mov al,64
NoHiVol: mov
[di+Volume],al
ret
BeatTrack EndP
;--------------------------------------------------------------------------
; GetTrack: Coge la siguiente nota del patr¢n
; In:
; ds:di - Direcci¢n de la informaci¢n
del track
; es:si - Direcci¢n de la nota el patr¢n
; Out:
; es:si - La nueve direcci¢n de la nota
del patr¢n
;--------------------------------------------------------------------------
GetTrack Proc
Near
seges lodsw
xchg al,ah
mov bl,ah
and ah,0Fh
mov cx,ax
seges lodsw
xchg al,ah
mov bh,ah
and ah,0Fh
mov dx,ax
mov [di+Effect],dx
and bl,0F0h
shr bh,4
or bl,bh
je SetPeriod
SetSample: xor
bh,bh
dec bx
add bx,bx
mov ax,[SampVol+bx]
mov [di+Volume],al
mov ax,[SampOfs+bx]
mov Word Ptr [di+Samples],ax
mov ax,[SampSeg+bx]
mov Word Ptr [di+Samples+2],ax
mov ax,[SampLen+bx]
mov [di+Len],ax
mov ax,[SampRep+bx]
mov [di+Repeat],ax
mov ax,[SampRepLen+bx]
mov [di+RepLen],ax
SetPeriod: test cx,cx
je SetEffect
mov [di+PortTo],cx
cmp dh,03h
je SetEffect
mov [di+Period],cx
mov bx,cx
add bx,bx
mov ax,[PitchTable+bx]
mov [di+Pitch],ax
mov [di+Position],0
SetEffect: test dx,dx
je InitNone
cmp dh,00h
je InitArpeggio
cmp dh,03h
je InitTonePort
cmp dh,04h
je InitVibrato
cmp dh,09h
je SampleOfs
cmp dh,0Bh
je PosJump
cmp dh,0Ch
je SetVolume
cmp dh,0Dh
je Break
cmp dh,0Fh
je SetSpeed
InitNone: ret
InitTonePort: test dl,dl
jne SetPortParm
mov dl,[di+PortParm]
SetPortParm: mov [di+PortParm],dl
mov [di+Effect],dx
ret
InitVibrato: mov al,[di+VibParm]
mov ah,al
and al,0Fh
and ah,0F0h
test dl,0Fh
jne OkDepth
or dl,al
OkDepth: test
dl,0F0h
jne OkRate
or dl,ah
OkRate: mov
[di+VibParm],dl
mov [di+Effect],dx
test cx,cx
je OkPos
mov [di+VibPos],0
OkPos: ret
SampleOfs: test dl,dl
jne SetSampleOfs
mov dl,[di+OldSampOfs]
SetSampleOfs: mov [di+OldSampOfs],dl
mov dh,dl
xor dl,dl
mov [di+Position],dx
ret
PosJump: mov
[OrderPos],dl
mov [Row],64
ret
SetVolume: cmp
dl,64
jbe OkVol
mov dl,64
OkVol: mov
[di+Volume],dl
ret
Break: mov
dh,dl
and dl,0Fh
shr dh,4
add dh,dh
add dl,dh
shl dh,2
add dl,dh
mov [BreakRow],dl
mov [Row],64
ret
SetSpeed: test
dl,dl
je Skip
cmp dl,31
ja SetBpm
SetTempo: mov
[Tempo],dl
mov [TempoWait],dl
ret
SetBpm: mov
[Bpm],dl
mov al,103
mul dl
mov bl,ah
xor bh,bh
mov ax,[MixSpeed]
xor dx,dx
div bx
mov [BpmSamples],ax
Skip: ret
InitArpeggio: mov dh,dl
and dl,0Fh
shr dh,4
mov cx,36
xor bx,bx
mov ax,[di+Period]
ScanPeriod: cmp ax,[PeriodTable+bx]
jae SetArp
add bx,2
loop ScanPeriod
SetArp: add
dx,dx
add dh,bl
add dl,bl
mov bx,[PeriodTable+bx]
add bx,bx
mov ax,[PitchTable+bx]
mov [di+Arp],ax
mov bl,dh
xor bh,bh
mov bx,[PeriodTable+bx]
add bx,bx
mov ax,[PitchTable+bx]
mov [di+Arp+2],ax
mov bl,dl
xor bh,bh
mov bx,[PeriodTable+bx]
add bx,bx
mov ax,[PitchTable+bx]
mov [di+Arp+4],ax
mov [di+ArpIndex],0
ret
GetTrack EndP
;--------------------------------------------------------------------------
; UpdateTracks: C¢digo principal para procesar el nuevo
"tick"
;--------------------------------------------------------------------------
UpdateTracks Proc Near
dec [TempoWait]
je GetTracks
BeatTracks: Ofs = offset Tracks
Rept NumTracks
mov di,Ofs
call BeatTrack
Ofs = Ofs + Size TrackInfo
EndM
ret
GetTracks: mov
al,[Tempo]
mov [TempoWait],al
les si,[Note]
cmp [Row],64
jb NoPattWrap
les si,[Patterns]
mov bl,[OrderPos]
cmp bl,[OrderLen]
jb NoOrderWrap
mov bl,[ReStart]
mov [OrderPos],bl
cmp bl,[OrderLen]
jae NoUpdate
NoOrderWrap: xor bh,bh
mov bl,[Order+bx]
shl bx,10
add si,bx
mov bl,[BreakRow]
mov [Row],bl
xor bh,bh
mov [BreakRow],bh
shl bx,4
add si,bx
mov Word Ptr [Note],si
mov Word Ptr [Note+2],es
inc [OrderPos]
NoPattWrap: inc [Row]
cld
Ofs = offset Tracks
Rept NumTracks
mov di,Ofs
call GetTrack
Ofs = Ofs + Size TrackInfo
EndM
mov Word Ptr
[Note],si
NoUpdate: ret
UpdateTracks EndP
;--------------------------------------------------------------------------
; MixTrack: Mezcla un track en un buffer limpio
; In:
; ds:si - Direcci¢n de la informaci¢n del
track
; ds:di - Direcci¢n del buffer
; cx - Tama¤o del Buffer
;--------------------------------------------------------------------------
MixTrack Proc
Near
cmp [si+RepLen],2
ja MixLooped
MixNonLooped: les dx,[si+Samples]
mov bx,[si+Position]
mov bp,[si+Len]
push dx
push si
add bx,dx
add bp,dx
mov dx,[si+Pitch]
mov al,[si+Volume]
mov ah,[si+Error]
mov si,bx
mov bh,al
mov al,dl
mov dl,dh
xor dh,dh
nlMixSamp: cmp
si,bp
jae nlMixBye
mov bl,es:[si]
mov bl,[VolTable+bx]
add [di],bl
inc di
add ah,al
adc si,dx
loop nlMixSamp
nlMixBye: mov
bx,si
pop si
pop dx
sub bx,dx
mov [si+Position],bx
mov [si+Error],ah
ret
MixLooped: les
dx,[si+Samples]
mov bx,[si+Position]
mov bp,[si+RepLen]
mov [BufRep],bp
add bp,[si+Repeat]
push dx
push si
add bx,dx
add bp,dx
mov dx,[si+Pitch]
mov al,[si+Volume]
mov ah,[si+Error]
mov si,bx
mov bh,al
mov al,dl
mov dl,dh
xor dh,dh
lpMixSamp: cmp
si,bp
jb lpMixNow
sub si,[BufRep]
lpMixNow: mov
bl,es:[si]
mov bl,[VolTable+bx]
add [di],bl
inc di
add ah,al
adc si,dx
loop lpMixSamp
lpMixBye: mov
bx,si
pop si
pop dx
sub bx,dx
mov [si+Position],bx
mov [si+Error],ah
ret
MixTrack EndP
;--------------------------------------------------------------------------
; GetSamples: Devueve el siguiente trozo del sample que se va
a tocar
; In:
; Buffer - Direcci¢n del Buffer
; Count - Tama¤o del Buffer
;--------------------------------------------------------------------------
GetSamples Proc Pascal Buffer:DWord, Count:Word
pusha
push ds
push es
cld
les di,[Buffer]
mov bx,[Count]
NextChunk: cmp
[BufLen],0
jne CopyChunk
push bx
push di
push es
MixChunk: lea
di,[MixBuffer]
mov cx,[BpmSamples]
mov [BufPtr],di
mov [BufLen],cx
mov ax,ds
mov es,ax
mov al,80h
rep stosb
Ofs = offset Tracks
Rept NumTracks
mov si,Ofs
mov di,[BufPtr]
mov cx,[BufLen]
call MixTrack
Ofs = Ofs + Size TrackInfo
EndM
call UpdateTracks
pop es
pop di
pop bx
CopyChunk: mov
cx,[BufLen]
cmp cx,bx
jbe MoveChunk
mov cx,bx
MoveChunk: mov
si,[BufPtr]
add [BufPtr],cx
sub [BufLen],cx
sub bx,cx
rep movsb
test bx,bx
jne NextChunk
pop es
pop ds
popa
ret
GetSamples EndP
;--------------------------------------------------------------------------
; StartPlaying: Inicializa el sistema de sonido
; In:
; Informaci¢n del m¢dulo
;--------------------------------------------------------------------------
StartPlaying Proc
pusha
push ds
push es
SetModParms: mov [OrderPos],0
mov [Tempo],DefTempo
mov [TempoWait],DefTempo
mov [Bpm],DefBpm
mov [Row],64
mov [BreakRow],0
mov ax,[MixSpeed]
xor dx,dx
mov bx,24*DefBpm/60
div bx
mov [BpmSamples],ax
ClearTracks: mov di,offset
Tracks
mov ax,ds
mov es,ax
mov cx,NumTracks * (Size TrackInfo)
xor ax,ax
cld
rep stosb
mov [BufPtr],ax
mov [BufLen],ax
MakePitch: mov
ax,MidCRate
mov bx,428
mul bx
div [MixSpeed]
xor dh,dh
mov dl,ah
mov ah,al
xor al,al
mov cx,857
xor bx,bx
mov di,offset PitchTable
PitchLoop: push ax
push dx
cmp dx,bx
jae NoDiv
div bx
NoDiv: stosw
pop dx
pop ax
inc bx
loop PitchLoop
MakeVolume: mov cx,16640
mov bx,cx
VolLoop: dec
bx
mov al,bl
imul bh
mov [VolTable+bx],ah
loop VolLoop
pop es
pop ds
popa
ret
StartPlaying EndP
;--------------------------------------------------------------------------
; StopPlaying: Descarga todo
;--------------------------------------------------------------------------
StopPlaying Proc
ret
StopPlaying EndP
End