diff --git a/Source/Doc/Architecture.md b/Source/Doc/Architecture.md index 6260d673..f786448e 100644 --- a/Source/Doc/Architecture.md +++ b/Source/Doc/Architecture.md @@ -1429,23 +1429,32 @@ Increase by steps of 48 to select the same note in next octave. If the driver is able to generate the requested note, a success (0) is returned, otherwise a non-zero error state will be returned. +The sound chip resolution and its oscillator limit the range and +accuracy of the notes played. The typically range of the AY-3-8910 +is six octaves, Bb2/A#2-A7, where each value is a unique tone. Values +above and below can still be played but each quarter tone step may not +result in a note change. + The following table shows the mapping of the input value in HL to the corresponding octave and note. -| Note | Octave 0 | Octave 1 | Octave 2 | Octave 3 | Octave 4 | Octave 5 | Octave 6 | -|-------|----------|----------|----------|----------|----------|----------|----------| -| Bb/A# | 0 | 48 | 96 | 144 | 192 | 240 | 288 | -| B | 4 | 52 | 100 | 148 | 196 | 244 | 292 | -| C | 8 | 56 | 104 | 152 | 200 | 248 | 296 | -| C#/Db | 12 | 60 | 108 | 156 | 204 | 252 | 300 | -| D | 16 | 64 | 112 | 160 | 208 | 256 | 304 | -| Eb/D# | 20 | 68 | 116 | 164 | 212 | 260 | 308 | -| E | 24 | 72 | 120 | 168 | 216 | 264 | 312 | -| F | 28 | 76 | 124 | 172 | 220 | 268 | 316 | -| F#/Gb | 32 | 80 | 128 | 176 | 224 | 272 | 320 | -| G | 36 | 84 | 132 | 180 | 228 | 276 | 324 | -| Ab/G# | 40 | 88 | 136 | 184 | 232 | 280 | 328 | -| A | 44 | 92 | 140 | 188 | 236 | 284 | 332 | ++-------------------------------------------------------+ +| | OCTAVE | +| Note |-----------------------------------------------+ +| | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | +|-------|-----|-----|-----|-----|-----|-----|-----|-----+ +| Bb/A# | 0 | 48 | 96 | 144 | 192 | 240 | 288 | 336 | +| B | 4 | 52 | 100 | 148 | 196 | 244 | 292 | 340 | +| C | 8 | 56 | 104 | 152 | 200 | 248 | 296 | 344 | +| C#/Db | 12 | 60 | 108 | 156 | 204 | 252 | 300 | 348 | +| D | 16 | 64 | 112 | 160 | 208 | 256 | 304 | 352 | +| Eb/D# | 20 | 68 | 116 | 164 | 212 | 260 | 308 | 356 | +| E | 24 | 72 | 120 | 168 | 216 | 264 | 312 | 360 | +| F | 28 | 76 | 124 | 172 | 220 | 268 | 316 | 364 | +| F#/Gb | 32 | 80 | 128 | 176 | 224 | 272 | 320 | 368 | +| G | 36 | 84 | 132 | 180 | 228 | 276 | 324 | 372 | +| Ab/G# | 40 | 88 | 136 | 184 | 232 | 280 | 328 | 376 | +| A | 44 | 92 | 140 | 188 | 236 | 284 | 332 | 380 | ### Function 0x54 -- Sound Play (SNDPLAY) @@ -1529,9 +1538,6 @@ key aspects of the specific Audio Device. Reports information about the audio device unit specified. -At this stage, only one driver type is supported (SN76489), but is -envisaged that more will be added in the future. - Register B reports the audio device type (see below). Registers HL and DE contain relevant port addresses for the hardware @@ -1543,7 +1549,7 @@ AUDIO ID | Value | Device | Returned registers -------------- | ----- | ---------- | -------------------------------------------- SND_SN76489 | 0x01 | SN76489 | E: Left channel port, L: Right channel port SND_AY38910 | 0x02 | AY-3-8910 | D: Address port, E: Data port - +SND_BITMODE | 0x03 | I/O PORT | D: Address port, E: Bit mask `\clearpage`{=latex} diff --git a/Source/HBIOS/ay38910.asm b/Source/HBIOS/ay38910.asm index 81c41223..f0315f77 100644 --- a/Source/HBIOS/ay38910.asm +++ b/Source/HBIOS/ay38910.asm @@ -4,10 +4,11 @@ ; ;====================================================================== ; - +; @3.579545 OCTAVE RANGE IS 2 - 7 (Bb2/A#2 .. A7) +; @4.000000 OCTAVE RANGE IS 2 - 7 (B2 .. A7) +; ;#include "cfg_state.inc" - - +; AY_RCSND .EQU 0 ; 0 = EB MODULE, 1=MF MODULE ; #IF (AYMODE == AYMODE_SCG) @@ -15,6 +16,7 @@ AY_RSEL .EQU $9A AY_RDAT .EQU $9B AY_RIN .EQU AY_RSEL AY_ACR .EQU $9C +AY_CLK .SET 3579545 ; MSX NTSC COLOUR BURST FREQ = 315/88 #ENDIF ; #IF (AYMODE == AYMODE_N8) @@ -73,10 +75,13 @@ SBCV2004 .EQU 0 ; USE SBC-V2-004 HALF CLOCK DIVIDER AY_TONECNT .EQU 3 ; COUNT NUMBER OF TONE CHANNELS AY_NOISECNT .EQU 1 ; COUNT NUMBER OF NOISE CHANNELS ; -AY_PHICLK .EQU 3579545 ; MSX NTSC COLOUR BURST FREQ = 315/88 -;AY_PHICLK .EQU 3500000 ; ZX SPECTRUM 3.5MHZ -;AY_PHICLK .EQU 4000000 ; RETROBREW SCB-SCG -AY_RATIO .EQU AY_CLK * 100 / 16 +#IF (AY_CLK > 3579545) ; DEPENDING ON THE +AY_SCALE .EQU 2 ; INPUT CLOCK FREQUENCY +#ELSE ; PRESCALE THE TONE PERIOD +AY_SCALE .EQU 3 ; DATA TO MAINTAIN MAXIMUM +#ENDIF ; RANGE AND ACCURACY +; +AY_RATIO .EQU (AY_CLK * 100) / (16 >> AY_SCALE) ; #INCLUDE "audio.inc" ; @@ -96,7 +101,7 @@ AY38910_INIT: CALL PRTHEXBYTE ; #IF ((AYMODE == AYMODE_SCG) | (AYMODE == AYMODE_N8)) - LD A,$FF ; ACTIVATE DEVICEBIT 4 IS AY RESET CONTROL, BIT 3 IS ACTIVE LED + LD A,$FF ; ACTIVATE DEVICE BIT 4 IS AY RESET CONTROL, BIT 3 IS ACTIVE LED OUT (AY_ACR),A ; SET INIT AUX CONTROL REG #ENDIF ; @@ -127,55 +132,50 @@ AY_FND: LD IY, AY_IDAT ; SETUP FUNCTION TABLE LD DE,(AY_R3CHBP*256)+$00 CALL AY_WRTPSG ; R03 = $00 = XXXX0000 ; - #IF (SYSTIM != TM_NONE) LD A, TICKFREQ / 3 ; SCHEDULE IN 1/3 SECOND TO TURN OFF SOUND LD (AY_TIMTIK), A - +; LD HL, (VEC_TICK + 1) ; GET CUR TICKS VECTOR LD (AY_TIMHOOK), HL ; SAVE IT INTERNALLY LD HL, AY_TIMER ; INSTALL TIMER HOOK HANDLER LD (VEC_TICK + 1), HL - +; LD A, $02 ; NOT READY & IN INTERUPT HANDLER LD (AY_READY), A - #ELSE CALL LDELAY ; HALF SECOND DELAY LD E,$00 ; SET VOLUME OFF CALL AY_SETV ; ON ALL CHANNELS LD A, $01 ; READY & NOT IN INTERUPT HANDLER LD (AY_READY), A - #ENDIF ; XOR A ; SUCCESSFULL INIT RET - +; #IF (SYSTIM != TM_NONE) - AY_TIMER: LD A, (AY_TIMTIK) DEC A LD (AY_TIMTIK), A JR NZ, AY_TIMER1 - +; LD E,$00 ; SET VOLUME OFF CALL AY_SETV ; ON ALL CHANNELS LD A, $01 ; READY & NOT IN INTERUPT HANDLER LD (AY_READY), A - +; LD DE, AY_TIMER ; MAKE AY_TIMER A NO_OP HANDLER LD HL, AY_TIMER1 LD BC, 3 LDIR - +; AY_TIMER1: JP 0 ; OVERWRITTEN WITH NEXT HANDLER AY_TIMHOOK: .EQU $ - 2 AY_TIMTIK .DB 0 ; COUNT DOWN TO FINISH BOOT BEEP - #ENDIF ; ;====================================================================== @@ -185,7 +185,7 @@ AY_TIMTIK .DB 0 ; COUNT DOWN TO FINISH BOOT BEEP AY_INIT: LD DE,(AY_R7ENAB*256)+$F8 ; SET MIXER CONTROL / IO ENABLE. $F8 - 11 111 000 JP AY_WRTPSG ; I/O PORTS = OUTPUT, NOISE CHANNEL C, B, A DISABLE, TONE CHANNEL C, B, A ENABLE - +; AY_CHKREDY: LD A, (AY_READY) BIT 0, A @@ -219,7 +219,7 @@ AY_SV: CALL AY_WRTPSG ; CYCLING THROUGH ALL CHANNELS AY_RESET: AUDTRACE(AYT_INIT) CALL AY_CHKREDY ; RETURNS TO OUR CALLER IF NOT READY - +; PUSH DE PUSH HL CALL AY_INIT ; SET DEFAULT CHIP CONFIGURATION @@ -261,10 +261,34 @@ AY_NOTE: AUDTRACE(AYT_NOTE) AUDTRACE_HL AUDTRACE_CR - - LD DE, AY3NOTETBL - CALL AUD_NOTE ; RETURNS PERIOD IN HL, FALL THRU - ; TO SET THIS PERIOD +; +; CALL PRTHEXWORDHL +; CALL PC_COLON +; + LD DE, AY3NOTETBL ; ON ENTRY HL IS THE NOTE TO PLAY + PUSH DE ; AND DE IS THE START OF NOTE TABLE + LD DE, 48 ; LOAD DE WITH NOTE TABLE SIZE + CALL DIV16 ; AND CALCULATE OCTAVE COUNT IN BC +; + ADD HL, HL ; HL IS THE REMAINDER FROM ABOVE DIVISION (0-47) AND THE NOTE + POP DE ; TO PLAY IN THE OCTAVE. ADD IT TO THE START OF THE NOTE TABLE + ADD HL, DE ; TO POINT TO THE PERIOD FOR THE NOTE WE WANT TO PLAY. +; + LD A, (HL) ; HL POINT TO CURRENT PERIOD COUNT WE WANT TO PLAY + INC HL ; SO LOAD PERIOD COUNT FROM NOTE TABLE INTO HL + LD H, (HL) ; SO WE CAN UPDATE IT FOR THE REQUIRED OCTAVE + LD L, A +; + LD A,AY_SCALE-1 ; THE NOTE TABLE PERIOD DATA HAS BEEN + ADD A,C ; PRESCALED TO MAINTAIN RANGE SO ALLOW + LD B,A ; FOR THIS WHEN CHANGING OCTAVE +AY_NOTE1: + SRL H ; ADJUST THE PERIOD DATA + RR L ; FOR THE DESIRED OCTAVE + DJNZ AY_NOTE1 ; FALL THROUGH TO SET PERIOD AND RANGE CHECK +; +; CALL PRTHEXWORDHL +; CALL NEWLINE ; ;====================================================================== ; SOUND DRIVER FUNCTION - PERIOD @@ -278,7 +302,7 @@ AY_PERIOD: LD A, H ; IF ZERO - ERROR OR L JR Z, AY_PERIOD1 - +; LD A, H ; MAXIMUM TONE PERIOD IS 12-BITS AND 11110000B ; ALLOWED RANGE IS 0001-0FFF (4095) JR NZ, AY_PERIOD1 ; RETURN NZ IF NUMBER TOO LARGE @@ -304,7 +328,6 @@ AY_PLAY: AUDTRACE_D AUDTRACE_CR CALL AY_CHKREDY ; RETURNS TO OUR CALLER IF NOT READY - ; LD A, (AY_PENDING_PERIOD + 1) ; CHECK THE HIGH BYTE OF THE PERIOD INC A @@ -412,21 +435,20 @@ AY_QUERY_DEV: LD DE, (AY_RSEL*256)+AY_RDAT ; AND ADDRESS AND DATA PORT XOR A RET - +; AY_DI: LD A, (AY_READY) BIT 1, A RET NZ HB_DI RET - +; AY_EI: LD A, (AY_READY) BIT 1, A RET NZ HB_EI RET - ; ;====================================================================== ; @@ -460,7 +482,6 @@ AY_WRTPSG: OUT (112),A ; NORMAL CLOCK SPEED #ENDIF JP AY_EI - ; ;====================================================================== ; @@ -510,13 +531,14 @@ AYT_REGWR .DB "\r\nOUT AY-3-8910 $" #ENDIF ; ;====================================================================== -; BBC MICRO QUARTER TONE FREQUENCY TABLE +; QUARTER TONE FREQUENCY TABLE ;====================================================================== ; -; THE FREQUENCY BY QUARTER TONE STARTING AT A0# OCATVE 0 +; THE FREQUENCY BY QUARTER TONE STARTING AT A0# OCTAVE 0 ; USED TO MAP EACH OCTAVE (DIV BY 2 TO JUMP AN OCTAVE UP) ; FIRST PLAYABLE NOTE WILL BE 0 ; ASSUMING A CLOCK OF 1843200 THIS MAPS TO A0# +; AY3NOTETBL: .DW AY_RATIO / 2913 .DW AY_RATIO / 2956 diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index 2e017e0f..8b8c116e 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -1628,6 +1628,7 @@ HB_INIT_REC: #IF (PLATFORM == PLT_SBC) .DW UART_INIT .DW MD_INIT + .DW PPIDE_INIT #ENDIF HB_INITRLEN .EQU (($ - HB_INIT_REC) / 2) ; @@ -1673,14 +1674,14 @@ HB_INITTBL: #IF (CTCENABLE) .DW CTC_INIT #ENDIF -#IF (SPKENABLE) - .DW SP_INIT ; AUDIBLE INDICATOR OF BOOT START +#IF (AY38910ENABLE) + .DW AY38910_INIT ; AUDIBLE INDICATOR OF BOOT START #ENDIF #IF (SN76489ENABLE) .DW SN76489_INIT #ENDIF -#IF (AY38910ENABLE) - .DW AY38910_INIT ; AUDIBLE INDICATOR OF BOOT START +#IF (SPKENABLE) + .DW SP_INIT ; AUDIBLE INDICATOR OF BOOT START #ENDIF #IF (ASCIENABLE) .DW ASCI_INIT @@ -3680,10 +3681,14 @@ PRTSUM: LD C,BF_SYSGET_DIOCNT ; DISK DRIVES LD HL,PS_DISK CALL PRT_ALLD - +; LD C,BF_SYSGET_VDACNT ; VIDEO DEVICES LD HL,PS_VIDEO CALL PRT_ALLD +; + LD C,BF_SYSGET_SNDCNT ; SOUND DEVICES + LD HL,PS_SOUND + CALL PRT_ALLD RET ; PRT_ALLD: @@ -4026,6 +4031,68 @@ PS_PRTVC: CALL PRTDECB RET ; +; PRINT SOUND CONFIG +; +PS_SOUND: + PUSH BC + + ; UNIT COLUMN + PRTS("Sound $") + LD A,C ; MOVE UNIT NUM TO A + CALL PRTDECB ; PRINT IT + CP 10 ; CHECK FOR MULTIPLE DIGITS + CALL C,PC_SPACE ; EXTRA SPACE IF NEEDED + PRTS(" $") ; PAD TO NEXT COLUMN + + ; DEVICE COLUMN + + PUSH BC ; + LD E,C + XOR A + LD DE,PS_SDSND ; POINT TO DEVICE TYPE NAME TABLE + CALL PRTIDXDEA ; PRINT DEVICE NMEMONIC PADDED TO FIELD WIDTH + LD A,C ; MOVE UNIT NUM TO A + CALL PRTDECB ; PRINT IT + CALL PC_COLON + CP 10 ; CHECK FOR MULTIPLE DIGITS + CALL C,PC_SPACE ; EXTRA SPACE IF NEEDED + LD A,(PRTIDXCNT) + SUB 9+1 + CPL + CALL PS_PAD + POP BC + + ; DEVICE TYPE +; + LD B,BF_SNDQUERY ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C + LD E,BF_SNDQ_DEV + RST 08 + LD A,B + DEC A + LD DE,PS_SDSN76489 + CALL PRTIDXDEA + LD A,(PRTIDXCNT) + SUB 18+1 + CPL + CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) + + ; DEVICE CHARACTERISTICS +; + LD B,BF_SNDQUERY ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C + LD E,BF_SNDQ_CHCNT + RST 08 + LD A,B + CALL PRTDECB + LD A,'+' + CALL COUT + LD A,C + CALL PRTDECB + PRTS(" CHANNELS$") + CALL NEWLINE +; + POP BC + RET +; ; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE ; PS_PRTDEV: @@ -4182,6 +4249,16 @@ PS_VDVGA .TEXT "VGA$" ; PS_VTCRT .TEXT "CRT$" ; +; SOUND DEVICE STRINGS +; +PS_SDSND .TEXT "SND$" +; +; SOUND TYPE STRINGS +; +PS_SDSN76489 .TEXT "SN76489$" +PS_SDAY38910 .TEXT "AY-3-8910$" +PS_SDBITMODE .TEXT "I/O PORT$" +; ; 0 1 2 3 4 5 6 7 ; 01234567890123456789012345678901234567890123456789012345678901234567890123456789 PS_STRHDR .TEXT "Unit Device Type Capacity/Mode\r\n" diff --git a/Source/HBIOS/spk.asm b/Source/HBIOS/spk.asm index 6fe58a44..168693ce 100644 --- a/Source/HBIOS/spk.asm +++ b/Source/HBIOS/spk.asm @@ -24,6 +24,8 @@ SP_IDAT .EQU 0 ; NO INSTANCE DATA ASSOCIATED WITH THIS DEVICE SP_TONECNT .EQU 1 ; COUNT NUMBER OF TONE CHANNELS SP_NOISECNT .EQU 0 ; COUNT NUMBER OF NOISE CHANNELS ; +SP_RTCIOMSK .EQU 00000100B +; ; FOR OTHER DRIVERS, THE PERIOD VALUE FOR THE TONE IS STORED AT PENDING_PERIOD ; FOR THE SPK DRIVER THE ADDRESS IN THE TONE TABLE IS STORED IN PENDING_PERIOD ; @@ -139,8 +141,8 @@ SP_QUERY_VOLUME: RET ; SP_QUERY_DEV: - LD B, BF_SND_BITMODE ; RETURN DEVICE IDENTIFIER - LD DE, 0 ; AND ADDRESS AND DATA PORT + LD B, BF_SND_BITMODE ; RETURN DEVICE IDENTIFIER + LD DE, (RTCIO*256)+SP_RTCIOMSK ; AND ADDRESS AND DATA PORT XOR A RET ; @@ -273,7 +275,7 @@ BE_H_L_LP: ; ; The loudspeaker is now alternately activated and deactivated. ; - XOR %00000100 ; Flip bit 2. + XOR SP_RTCIOMSK ; Flip bit 2. OUT (RTCIO),A ; Perform the 'OUT' operation, leaving other bits unchanged. LD B,H ; Reset the B register. LD C,A ; Save the A register.