Não tem um chipset para fazer controle complexo de som. O som é apenas gerado por 1 bit. O altifalante é activado com o bit a 0, e desactivado com o bit a 1. É necessário alternar o bit a 0 e 1 para gerar frequências (sons).
Enquanto se fala com o altifalante (ou se conta ciclos T), a CPU fica "presa", por o ZX Spectrum não ter um chipset dedicado para controlar o som.
Um OUT para a porta da ULA $FE controla o altifalante no bit 4.
Saliente-se que no carregamento de cassetes, o som que se ouve é por ao nível de hardware, quer o EAR, quer o MIC, estarem conectados ao speaker. O som não é enviado ao speaker por software.
Ao nível de código máquina, ou se pode falar directamente com o altifalante, ou invocar a rotina da ROM para gerar frequências 03B5: THE 'BEEPER' SUBROUTINE
A rotina da ROM, monopoliza a CPU enquanto gera som, e desliga os interrupts.
As frequências em Hz de notas musicais são as seguintes:
Para usar a rotina BEEPER, sendo f em Hz e t segundos, a rotina BEEPER da ROM espera como argumentos:
HL = atraso do loop
DE = número de iterações para o ciclo de geração de som
HL = INT (( t * 6689 / 4 ) - 30.125 )
DE = INT ( f * t )
Portanto, para tocar a nota C, durante 1 seg:
HL = INT (( 1 * 6689 / 4 ) - 30.125 ) = 1642
DE = INT ( 216.63 * 1 ) = 262
Sendo assim:
LD HL,1462
LD DE, 262
CALL $03B5
RET
A própria rotina da ROM, é um bom exemplo como se controla directamente o BEEPER:
|
|||||||||
BEEPER |
03B5
|
DI
|
Disable
the interrupt for the duration of a 'beep'.
|
||||||
03B6
|
LD A,L
|
Save L temporarily.
|
|||||||
03B7
|
SRL L
|
Each '1'
in the L register is to count 4 T states, but take INT (L/4) and
count 16 T states instead.
|
|||||||
03B9
|
SRL L
|
||||||||
03BB
|
CPL
|
Go back to
the original value in L and find how many were lost by taking
3-(A mod 4).
|
|||||||
03BC
|
AND $03
|
||||||||
03BE
|
LD C,A
|
||||||||
03BF
|
LD B,$00
|
||||||||
03C1
|
LD
IX,$03D1
|
The base
address of the timing loop.
|
|||||||
03C5
|
ADD IX,BC
|
Alter the
length of the timing loop. Use an earlier starting point for each '1' lost by
taking INT (L/4).
|
|||||||
03C7
|
LD
A,($5C48)
|
Fetch the
present border colour from BORDCR and
move it to bits 2, 1 and 0 of the A register.
|
|||||||
03CA
|
AND $38
|
||||||||
03CC
|
RRCA
|
||||||||
03CD
|
RRCA
|
||||||||
03CE
|
RRCA
|
||||||||
03CF
|
OR $08
|
Ensure the
MIC output is 'off'.
|
|||||||
Now enter
the sound generation loop. DE complete passes are made, i.e. a pass
for each cycle of the note.
The HL register
holds the 'length of the timing loop' with 16 T states being used for each
'1' in the L register and 1024 T states for each '1' in
the H register.
|
|||||||||
03D1
|
NOP
|
Add 4 T states
for each earlier entry point that is used.
|
|||||||
03D2
|
NOP
|
||||||||
03D3
|
NOP
|
||||||||
03D4
|
INC B
|
The values
in the B and C registers will come from
the H and L registers - see below.
|
|||||||
03D5
|
INC C
|
||||||||
BE_H_L_LP
|
03D6
|
DEC C
|
The
'timing loop', i.e. BC*4 T states. (But note that at the half-cycle
point, C will be equal to L+1.)
|
||||||
03D7
|
JR NZ,BE_H_L_LP
|
||||||||
03D9
|
LD C,$3F
|
||||||||
03DB
|
DEC B
|
||||||||
03DC
|
JP NZ,BE_H_L_LP
|
||||||||
The
loudspeaker is now alternately activated and deactivated.
|
|||||||||
03DF
|
XOR $10
|
Flip bit
4.
|
|||||||
03E1
|
OUT
($FE),A
|
Perform
the 'OUT' operation, leaving the border unchanged.
|
|||||||
03E3
|
LD B,H
|
Reset
the B register.
|
|||||||
03E4
|
LD C,A
|
Save
the A register.
|
|||||||
03E5
|
BIT 4,A
|
Jump if at
the half-cycle point.
|
|||||||
03E7
|
JR NZ,BE_AGAIN
|
||||||||
After a
full cycle the DE register pair is tested.
|
|||||||||
03E9
|
LD A,D
|
Jump
forward if the last complete pass has been made already.
|
|||||||
03EA
|
OR E
|
||||||||
03EB
|
JR Z,BE_END
|
||||||||
03ED
|
LD A,C
|
Fetch the
saved value.
|
|||||||
03EE
|
LD C,L
|
Reset
the C register.
|
|||||||
03EF
|
DEC DE
|
Decrease
the pass counter.
|
|||||||
03F0
|
JP (IX)
|
Jump back
to the required starting location of the loop.
|
|||||||
The
parameters for the second half-cycle are set up.
|
|||||||||
BE_AGAIN
|
03F2
|
LD C,L
|
Reset
the C register.
|
||||||
03F3
|
INC C
|
Add 16 T
states as this path is shorter.
|
|||||||
03F4
|
JP (IX)
|
Jump back.
|
|||||||
Upon
completion of the 'beep' the maskable interrupt has to be enabled.
|
|||||||||
BE_END
|
03F6
|
EI
|
Enable
interrupt.
|
||||||
03F7
|
RET
|
Finally
return.
|
Nota: embora se use $FE para controlar a ULA, a ULA responde a todos as portas de I/O pares. (i.e. a ULA é activada com portas de I/O com o bit 0 a 0).
O chipset AY só foi introduzido no modelo 128K.
Hz são Hertzs (ciclos por segundo).
Note-se que devido à contenção nos primeiros 16KB de RAM, rotinas que controlem directamente o beeper não devem estar nesta àrea de RAM.
Para rotinas de assembly para gerar som, ver Short beeper routines , Beep the ZX Spectrum e Loudspeaker Sound Effects.
Sem comentários:
Enviar um comentário