You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

102 lines
3.4 KiB

#IF AUDIOTRACE
;
#DEFINE AUDTRACE(STR) PUSH DE \ LD DE, STR \ CALL WRITESTR \ POP DE
#DEFINE AUDTRACE_A CALL PRTHEXBYTE
#DEFINE AUDTRACE_B PUSH AF \ LD A, B \ CALL PRTHEXBYTE \ POP AF
#DEFINE AUDTRACE_D PUSH AF \ LD A, D \ CALL PRTHEXBYTE \ POP AF
#DEFINE AUDTRACE_E PUSH AF \ LD A, E \ CALL PRTHEXBYTE \ POP AF
#DEFINE AUDTRACE_L PUSH AF \ LD A, L \ CALL PRTHEXBYTE \ POP AF
#DEFINE AUDTRACE_HL CALL PRTHEXWORDHL
#DEFINE AUDTRACE_BC PUSH HL \ PUSH BC \ POP HL \ CALL PRTHEXWORDHL \ POP HL
#DEFINE AUDTRACE_DE PUSH HL \ PUSH DE \ POP HL \ CALL PRTHEXWORDHL \ POP HL
#DEFINE AUDTRACE_IY PUSH HL \ PUSH IY \ POP HL \ CALL PRTHEXWORDHL \ POP HL
;
#DEFINE AUDDEBUG(S) push hl \ CALL PRTSTRD \ .TEXT S \ .TEXT "$" \ pop hl ; $$$$$$ PRINT STRING S TO CONSOLE - PRTD("HELLO") - NO TRAILING $ REQUIRED
;
#DEFINE AUDTRACE_CR AUDDEBUG("\r\n$")
;
#ELSE
;
#DEFINE AUDTRACE(S)
#DEFINE AUDTRACE_A
#DEFINE AUDTRACE_B
#DEFINE AUDTRACE_D
#DEFINE AUDTRACE_E
#DEFINE AUDTRACE_L
#DEFINE AUDTRACE_BC
#DEFINE AUDTRACE_HL
#DEFINE AUDTRACE_DE
#DEFINE AUDTRACE_IY
;
#DEFINE AUDDEBUG(STR)
;
#DEFINE AUDTRACE_CR
;
#ENDIF
;
#IFNDEF AUDIO_INC
#DEFINE AUDIO_INC
;
; NOTE TABLE VALUES ARE SHIFTED A FEW EXTRA BITS TO MAKE THE
; DIVISION AS ACCURATE AS POSSIBLE.
;
AUD_SCALE .EQU 3
;
; ON ENTRY, DE IS ADDRESS OF NOTE TABLE, HL IS NOTE TO PLAY
; NOTE VALUE 0 MEANS B0b/A0# IN OCTAVE 0 WHICH IS THE FIRST ENTRY
; OF THE NOTE TABLE. THE NOTE TABLE REPRESENTS THE FREQUENCIES
; FOR 1 FULL OCTAVE IN QUARTER NOTES. SINCE THERE ARE 12 NOTES
; IN AN OCTAVE, THE TABLE HAS 48 ENTRIES FOR ALL QUARTER NOTES.
;
; ON EXIT, HL CONTAINS THE PERIOD VALUE TO PROGRAM INTO THE PSG
; DERIVED FROM THE NOTE TABLE SCALED TO THE REQUESTED OCTAVE.
;
AUD_NOTE:
AUDDEBUG("AUDNOTE ")
AUDTRACE_HL
AUDTRACE_CR
AUDTRACE_DE
AUDTRACE_CR
;
; START BY SEPARATING THE NOTE AND OCTAVE PORTION
; OF THE INCOMING TONE VALUE IN HL
PUSH DE ; SAVE NOTE TABLE ADR
LD DE,48 ; 48 QUARTERNOTES PER OCTAVE
CALL DIV16 ; SEPARATE OCTAVE AND NOTE
;
; THE QUOTIENT (BC) IS THE OCTAVE NUMBER REQUESTED
; THE REMAINDER (HL) IS THE QUARTER NOTE WITHIN THE OCTAVE.
;
; NOW USE THE QUARTER NOTE VALUE TO LOOKUP THE CORRESPONDING
; PSG PERIOD VALUE IN THE NOTE TABLE.
ADD HL,HL ; SCALE FOR 2 BYTE TABLE ENTRY SIZE
POP DE ; RECOVER THE TABLE ADR
ADD HL,DE ; HL := DESIRED TABLE ENTRY ADR
LD A,(HL) ; GET LOW BYTE OF PERIOD TO A
INC HL ; POINT TO HIGH BYTE VALUE
LD H,(HL) ; GET HIGH BYTE OF PERIOD TO H
LD L,A ; PUT LOW BYTE INTO L
;
; NOW WE SCALE THE PERIOD VALUE DOWN BASED ON THE OCTAVE VALUE IN C
; AND BY THE AUD_SCALE VALUE THAT WAS USED IN THE NOTE TABLE.
; FOR EACH OCTAVE, THE PERIOD IS HALVED WHICH DOUBLES THE FREQUENCY
; THAT WILL BE PRODUCED BY THE PSG. SINCE MOVING UP AN OCTAVE
; SHOULD PRODUCE A FREQUENCY THAT IS TWICE THE LOWER OCTIAVE, THIS
; WORKS NICELY, ALTHOUGH SOME ERROR MAY BE INTRODUCED.
;
LD A,AUD_SCALE ; SHIFT BY AUD_SCALE BITS
ADD A,C ; ... AND OCTAVE
LD B,A ; USE AS LOOP COUNTER
AUD_NOTE1:
SRL H ; RIGHT SHIFT HL
RR L ; ... BY ONE BIT
DJNZ AUD_NOTE1 ; LOOP UNTIL DONE
;
; IF THE RESULTANT PERIOD IS ZERO, IT MEANS THAT THE REQUESTED
; PERIOD IS TOO LOW (FREQUENCY TOO HIGH) FOR THE PSG TO PRODUCE.
LD A, L ; CHECK FOR ZERO
OR H ; ... MEANING PSG CAN'T DO IT
RET NZ ; IF NOT ZERO, RETURN THE CALCULATED PERIOD
DEC HL ; OTHERWISE RETURN -1 PERIOD (ERROR)
RET
#ENDIF