From 1a437f6ed671fe0c4bc12192f30951a35869347d Mon Sep 17 00:00:00 2001 From: Erdogan Tan <124918396+turkishrational@users.noreply.github.com> Date: Thu, 19 Dec 2024 19:13:23 +0300 Subject: [PATCH] Add files via upload --- trdos386/programs/16bit/AC97PLAY.COM | Bin 0 -> 13312 bytes trdos386/programs/16bit/PLAYMOD4.ASM | 3822 ++++++++++ trdos386/programs/16bit/PLAYWAV8.COM | Bin 0 -> 12956 bytes trdos386/programs/16bit/PLAYWAV9.COM | Bin 0 -> 7343 bytes trdos386/programs/16bit/PLAYWAVX.COM | Bin 0 -> 7291 bytes trdos386/programs/16bit/SB16PLAY.COM | Bin 0 -> 7680 bytes trdos386/programs/16bit/ac97play.asm | 6763 +++++++++++++++++ trdos386/programs/16bit/ac97play_com_2024.zip | Bin 0 -> 132087 bytes trdos386/programs/16bit/playmod4.com | Bin 0 -> 4070 bytes .../programs/16bit/playmod4_com_fasm_2024.zip | Bin 0 -> 26242 bytes trdos386/programs/16bit/playwav7.asm | 5214 +++++++++++++ trdos386/programs/16bit/playwav7.com | Bin 0 -> 7954 bytes .../programs/16bit/playwav7_com_fasm_2024.zip | Bin 0 -> 27483 bytes trdos386/programs/16bit/playwav8.asm | 6503 ++++++++++++++++ trdos386/programs/16bit/playwav8_com_2024.zip | Bin 0 -> 35031 bytes trdos386/programs/16bit/playwav9.asm | 2626 +++++++ .../programs/16bit/playwav9_com_sb16_2024.zip | Bin 0 -> 32316 bytes trdos386/programs/16bit/playwavx.asm | 2628 +++++++ trdos386/programs/16bit/sb16play.asm | 2880 +++++++ trdos386/programs/16bit/sb16play_com_2024.zip | Bin 0 -> 113294 bytes 20 files changed, 30436 insertions(+) create mode 100644 trdos386/programs/16bit/AC97PLAY.COM create mode 100644 trdos386/programs/16bit/PLAYMOD4.ASM create mode 100644 trdos386/programs/16bit/PLAYWAV8.COM create mode 100644 trdos386/programs/16bit/PLAYWAV9.COM create mode 100644 trdos386/programs/16bit/PLAYWAVX.COM create mode 100644 trdos386/programs/16bit/SB16PLAY.COM create mode 100644 trdos386/programs/16bit/ac97play.asm create mode 100644 trdos386/programs/16bit/ac97play_com_2024.zip create mode 100644 trdos386/programs/16bit/playmod4.com create mode 100644 trdos386/programs/16bit/playmod4_com_fasm_2024.zip create mode 100644 trdos386/programs/16bit/playwav7.asm create mode 100644 trdos386/programs/16bit/playwav7.com create mode 100644 trdos386/programs/16bit/playwav7_com_fasm_2024.zip create mode 100644 trdos386/programs/16bit/playwav8.asm create mode 100644 trdos386/programs/16bit/playwav8_com_2024.zip create mode 100644 trdos386/programs/16bit/playwav9.asm create mode 100644 trdos386/programs/16bit/playwav9_com_sb16_2024.zip create mode 100644 trdos386/programs/16bit/playwavx.asm create mode 100644 trdos386/programs/16bit/sb16play.asm create mode 100644 trdos386/programs/16bit/sb16play_com_2024.zip diff --git a/trdos386/programs/16bit/AC97PLAY.COM b/trdos386/programs/16bit/AC97PLAY.COM new file mode 100644 index 0000000000000000000000000000000000000000..d99f0c4f9dc9980d98639e3e67c79a95ca02d62c GIT binary patch literal 13312 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 'if' conversion for FASM) +; 12/05/2024 (tuneloop version) +;%if 0 +if 0 + ; 28/11/2016 + ;mov bx, 1 ; 08/05/2024 + xor dh, dh ; 17/02/2017 + ; 10/11/2023 + ;mov cx, dx + ;shl bx, cl + + ; 04/11/2023 + cli + + ;not bx + in al, 0A1h ; irq 8-15 + mov ah, al + in al, 21h ; irq 0-7 + + ; 04/11/2023 + ; save IRQ status + mov [IRQ_status], ax + + ; 08/05/2024 + ;mov dx, 4D1h ;8259 ELCR1 + ;in al, dx + ;mov ah, al + ;mov dx, 4D0h + ;in al, dx + ;;or ax, bx + ;bts ax, cx + ;mov dx, 4D0h + ;out dx, al ;set level-triggered mode + ;mov al, ah + ;mov dx, 4D1h + ;out dx, al ;set level-triggered mode + + ; 24/11/2016 - Erdogan Tan + ;mov bx, cx + ; 10/11/2023 + mov bx, dx + mov bl, [bx+irq_int] + shl bx, 2 ; * 4 + + ; set up interrupt vector + ; 30/11/2016 + push es + xor ax, ax + mov es, ax + ; 04/11/2023 + ; save interrupt vector + mov ax, [es:bx] + mov [IRQ_vector], ax + mov ax, [es:bx+2] + mov [IRQ_vector+2], ax + + mov word [es:bx], ac97_int_handler + mov ax, cs + mov [es:bx+2], ax + pop es + + ; 04/11/2023 + sti +;%endif +end if + retn + +; 12/05/2024 (tuneloop version) +;%if 0 +if 0 ; 13/11/2024 + +ac97_int_handler: + ; 11/05/2024 + ; 11/11/2023 + ; 10/11/2023 + ; 17/02/2016 + push eax ; 11/11/2023 + push dx + ; 05/11/2023 + ;push cx + ;push bx + ;push si + ;push di + + ; 10/11/2023 + ; EOI at first + mov al, 20h + test byte [ac97_int_ln_reg], 8 + jz short _ih_0 + out 0A0h, al ; 20h ; EOI +_ih_0: + out 20h, al ; 20h ; EOI + + ; 11/11/2023 + ; 09/11/2023 + mov dx, GLOB_STS_REG + add dx, [NABMBAR] + in eax, dx + + ; 12/05/2024 + ; 09/11/2023, + ;cmp eax, 0FFFFFFFFh ; -1 + ;je short _ih_2 + + ; 12/05/2024 + ;test al, 40h ; PCM Out Interrupt + ;jnz short _ih_1 + + ;test eax, eax + ;jz short _ih_2 + ; 12/05/2024 + test ax, PCM_OUT_IRQ+BCIS + jnz short _ih_1 + + ;mov dx, GLOB_STS_REG + ;add dx, [NABMBAR] + out dx, eax + jmp short _ih_2 + + ; ..... + ;mov al, 1 + ; 10/11/2023 + ;mov [tLoop], al ; 1 + + ;cmp [inside], al ; 1 + ;jnb short _ih_3 ; busy + + ;mov [inside], al ; 1 + ; + ;; 09/11/2023 + ;mov dx, [NABMBAR] + ;add dx, PO_SR_REG ; set pointer to Status reg + ;in al, dx + ;; 10/11/2023 + ;;;out dx, eax + ;;out dx, al ; clear interrupt event + ; ; (by writing 1 to same bits) + ; + ;;mov [pcm_irq_status], al ; 05/11/2023 + ;test al, BCIS ; Buffer Completion Interrupt Status (Bit 3) + ;jz short _ih_2 + ; ..... + +_ih_1: + ; 11/11/2023 + push eax + + ;mov ax, 1Ch ; FIFOE(=16)+BCIS(=8)+LVBCI(=4) + ;mov dx, PO_SR_REG + ;add dx, [NABMBAR] + ;out dx, ax + + ; 10/11/2023 + ; 28/11/2016 - Erdogan Tan + call tuneLoop + + ; 11/11/2023 + pop eax + mov dx, GLOB_STS_REG + add dx, [NABMBAR] + out dx, eax +_ih_2: + ; 11/11/2023 + mov dx, [NABMBAR] + add dx, PO_SR_REG ; set pointer to Status reg + mov ax, 1Ch + out dx, ax + +; ; 10/11/2023 +; mov al, 20h +; test byte [ac97_int_ln_reg], 8 +; jz short _ih_3 +; out 0A0h, al ; 20h ; EOI +;_ih_3: +; out 20h, al ; 20h ; EOI +;_ih_4: + ;mov byte [inside], 0 + ;pop di + ;pop si + ;pop bx + ;pop cx + pop dx + pop eax ; 11/11/2023 + iret + +;%endif +end if + +;============================================================================= +; PCI.ASM +;============================================================================= + +; EQUATES + +;constants of stuff that seem hard to remember at times. + +TRUE EQU 1 +FALSE EQU 0 + +ENABLED EQU 1 +DISABLED EQU 0 + +BIT0 EQU 1 +BIT1 EQU 2 +BIT2 EQU 4 +BIT3 EQU 8 +BIT4 EQU 10h +BIT5 EQU 20h +BIT6 EQU 40h +BIT7 EQU 80h +BIT8 EQU 100h +BIT9 EQU 200h +BIT10 EQU 400h +BIT11 EQU 800h +BIT12 EQU 1000h +BIT13 EQU 2000h +BIT14 EQU 4000h +BIT15 EQU 8000h +BIT16 EQU 10000h +BIT17 EQU 20000h +BIT18 EQU 40000h +BIT19 EQU 80000h +BIT20 EQU 100000h +BIT21 EQU 200000h +BIT22 EQU 400000h +BIT23 EQU 800000h +BIT24 EQU 1000000h +BIT25 EQU 2000000h +BIT26 EQU 4000000h +BIT27 EQU 8000000h +BIT28 EQU 10000000h +BIT29 EQU 20000000h +BIT30 EQU 40000000h +BIT31 EQU 80000000h + +;special characters +NUL EQU 0 +NULL EQU 0 +BELL EQU 07 +BS EQU 08 +TAB EQU 09 +; 13/11/2024 +LF = 10 +CR = 13 +ESCAPE EQU 27 ;ESC is a reserved word.... + + +;file stuff +READONLY EQU BIT0 +HIDDEN EQU BIT1 +SYSTEM EQU BIT2 +VOLUME EQU BIT3 ;ignored for file access +DIRECTORY EQU BIT4 ;must be 0 for file access +ARCHIVE EQU BIT5 +SHAREABLE EQU BIT7 ;for novell networks +OPEN EQU 2 ; open existing file +CREATE EQU 1 ; create new file + + +; PCI equates +; PCI function address (PFA) +; bit 31 = 1 +; bit 23:16 = bus number (0-255) +; bit 15:11 = device number (0-31) +; bit 10:8 = function number (0-7) +; bit 7:0 = register number (0-255) + +IO_ADDR_MASK EQU 0FFFEh ; mask off bit 0 for reading BARs +PCI_INDEX_PORT EQU 0CF8h +PCI_DATA_PORT EQU 0CFCh +PCI32 EQU BIT31 ; bitflag to signal 32bit access +PCI16 EQU BIT30 ; bitflag for 16bit access + +PCI_FN0 EQU 0 << 8 +PCI_FN1 EQU 1 << 8 +PCI_FN2 EQU 2 << 8 +PCI_FN3 EQU 3 << 8 +PCI_FN4 EQU 4 << 8 +PCI_FN5 EQU 5 << 8 +PCI_FN6 EQU 6 << 8 +PCI_FN7 EQU 7 << 8 + +PCI_CMD_REG EQU 04h ; reg 04, command reg + IO_ENA EQU BIT0 ; i/o decode enable + MEM_ENA EQU BIT1 ; memory decode enable + BM_ENA EQU BIT2 ; bus master enable + +; CODE + +; AC97.ASM +; PCI device register reader/writers. +; NASM version: Erdogan Tan (29/11/2016) +; Last Update: 17/02/2017 + +;=============================================================== +; 8/16/32bit PCI reader +; +; Entry: EAX=PCI Bus/Device/fn/register number +; BIT30 set if 32 bit access requested +; BIT29 set if 16 bit access requested +; otherwise defaults to 8bit read +; +; Exit: DL,DX,EDX register data depending on requested read size +; +; Note: this routine is meant to be called via pciRegRead8, pciRegread16, +; or pciRegRead32, listed below. +; +; Note2: don't attempt to read 32bits of data from a non dword aligned reg +; number. Likewise, don't do 16bit reads from non word aligned reg # +; +pciRegRead: + push ebx + push cx + mov ebx, eax ; save eax, dh + mov cl, dh + ; 13/11/2024 ('~' to 'NOT' conversion for FASM) + and eax, (NOT PCI32)+PCI16 ; clear out data size request + or eax, BIT31 ; make a PCI access request + and al, NOT 3 ; force index to be dword + + mov dx, PCI_INDEX_PORT + out dx, eax ; write PCI selector + + mov dx, PCI_DATA_PORT + mov al, bl + and al, 3 ; figure out which port to + add dl, al ; read to + + in eax, dx ; do 32bit read + test ebx, PCI32 + jz short _pregr1 + + mov edx, eax ; return 32bits of data +_pregr1: + mov dx, ax ; return 16bits of data + test ebx, PCI32+PCI16 + jnz short _pregr2 + mov dh, cl ; restore dh for 8 bit read +_pregr2: + mov eax, ebx ; restore eax + and eax, (NOT PCI32)+PCI16 ; clear out data size request + pop cx + pop ebx + retn + +pciRegRead8: + and eax, (NOT PCI16)+PCI32 ; set up 8 bit read size + jmp short pciRegRead ; call generic PCI access + +pciRegRead16: + and eax, (NOT PCI16)+PCI32 ; set up 16 bit read size + or eax, PCI16 ; call generic PCI access + jmp short pciRegRead + +pciRegRead32: + and eax, (NOT PCI16)+PCI32 ; set up 32 bit read size + or eax, PCI32 ; call generic PCI access + jmp short pciRegRead + +;=============================================================== +; 8/16/32bit PCI writer +; +; Entry: EAX=PCI Bus/Device/fn/register number +; BIT31 set if 32 bit access requested +; BIT30 set if 16 bit access requested +; otherwise defaults to 8bit read +; DL/DX/EDX data to write depending on size +; +; +; note: this routine is meant to be called via pciRegWrite8, pciRegWrite16, +; or pciRegWrite32 as detailed below. +; +; Note2: don't attempt to write 32bits of data from a non dword aligned reg +; number. Likewise, don't do 16bit writes from non word aligned reg # +; +pciRegWrite: + push ebx + push cx + mov ebx, eax ; save eax, dx + mov cx, dx + or eax, BIT31 ; make a PCI access request + ; 13/11/2024 ('~' to 'NOT' conversion for FASM) + and eax, NOT PCI16 ; clear out data size request + and al, NOT 3 ; force index to be dword + + mov dx, PCI_INDEX_PORT + out dx, eax ; write PCI selector + + mov dx, PCI_DATA_PORT + mov al, bl + and al, 3 ; figure out which port to + add dl, al ; write to + + mov eax, edx ; put data into eax + mov ax, cx + + out dx, al + test ebx, PCI16+PCI32 ; only 8bit access? bail + jz short _pregw1 + + out dx, ax ; write 16 bit value + test ebx, PCI16 ; 16bit requested? bail + jnz short _pregw1 + + out dx, eax ; write full 32bit +_pregw1: + mov eax, ebx ; restore eax + and eax, (NOt PCI32)+PCI16 ; clear out data size request + mov dx, cx ; restore dx + pop cx + pop ebx + ret + +pciRegWrite8: + and eax, (NOT PCI16)+PCI32 ; set up 8 bit write size + jmp short pciRegWrite ; call generic PCI access + +pciRegWrite16: + and eax, (NOT PCI16)+PCI32 ; set up 16 bit write size + or eax, PCI16 ; call generic PCI access + jmp short pciRegWrite + +pciRegWrite32: + and eax, (NOT PCI16)+PCI32 ; set up 32 bit write size + or eax, PCI32 ; call generic PCI access + jmp short pciRegWrite + +; AC97.ASM (PLAYWAV.COM) +; 17/02/2017 (Modifed by Erdogan Tan for various ICH device IDs) +;=============================================================== +; PCIFindDevice: scan through PCI space looking for a device+vendor ID +; +; ENTRY: none +;; Entry: EAX=Device+Vendor ID +; +; Exit: EAX=PCI address if device found +; EDX=Device+Vendor ID +; CY clear if found, set if not found. EAX invalid if CY set. +; +; [old stackless] Destroys: ebx, esi, edi, cl +; +pciFindDevice: + ;push cx + ;push eax ; * + ;push esi + ;push edi + + ;mov esi, eax ; save off vend+device ID + + ; 17/02/2017 + mov si, valid_ids ; address of Valid ICH (AC97) Device IDs + mov cx, valid_id_count +pfd_0: + mov edi, (80000000h - 100h) ; start with bus 0, dev 0 func 0 +nextPCIdevice: + add edi, 100h + cmp edi, 80FFF800h ; scanned all devices? + ;stc + ;je short PCIScanExit ; not found + jb short pfd_1 + mov edi, 80000000h + add si, 4 ; scan for next device ID + loop pfd_1 + stc + ;jmp short PCIScanExit + retn +pfd_1: + mov eax, edi ; read PCI registers + call pciRegRead32 + ;cmp edx, esi ; found device? + cmp edx, dword [si] + jne short nextPCIdevice + ;clc +PCIScanExit: + ;pushf + mov eax, BIT31 + not eax + and eax, edi ; return only bus/dev/fn # + ;popf + + ;pop edi + ;pop esi + ;pop edx ; * + ;pop cx + retn + +;============================================================================= +; CODEC.ASM +;============================================================================= + +; EQUATES + +;Codec registers. +; +;Not all codecs are created equal. Refer to the spec for your specific codec. +; +;All registers are 16bits wide. Access to codec registers over the AC97 link +;is defined by the OEM. +; +;Secondary codec's are accessed by ORing in BIT7 of all register accesses. +; + +; each codec/mixer register is 16bits + +CODEC_RESET_REG equ 00 ; reset codec +CODEC_MASTER_VOL_REG equ 02 ; master volume +CODEC_HP_VOL_REG equ 04 ; headphone volume +CODEC_MASTER_MONO_VOL_REG equ 06 ; master mono volume +CODEC_MASTER_TONE_REG equ 08 ; master tone (R+L) +CODEC_PCBEEP_VOL_REG equ 0ah ; PC beep volume +CODEC_PHONE_VOL_REG equ 0bh ; phone volume +CODEC_MIC_VOL_REG equ 0eh ; MIC volume +CODEC_LINE_IN_VOL_REG equ 10h ; line input volume +CODEC_CD_VOL_REG equ 12h ; CD volume +CODEC_VID_VOL_REG equ 14h ; video volume +CODEC_AUX_VOL_REG equ 16h ; aux volume +CODEC_PCM_OUT_REG equ 18h ; PCM output volume +CODEC_RECORD_SELECT_REG equ 1ah ; record select input +CODEC_RECORD_VOL_REG equ 1ch ; record volume +CODEC_RECORD_MIC_VOL_REG equ 1eh ; record mic volume +CODEC_GP_REG equ 20h ; general purpose +CODEC_3D_CONTROL_REG equ 22h ; 3D control +; 24h is reserved +CODEC_POWER_CTRL_REG equ 26h ; powerdown control +CODEC_EXT_AUDIO_REG equ 28h ; extended audio +CODEC_EXT_AUDIO_CTRL_REG equ 2ah ; extended audio control +CODEC_PCM_FRONT_DACRATE_REG equ 2ch ; PCM out sample rate +CODEC_PCM_SURND_DACRATE_REG equ 2eh ; surround sound sample rate +CODEC_PCM_LFE_DACRATE_REG equ 30h ; LFE sample rate +CODEC_LR_ADCRATE_REG equ 32h ; PCM in sample rate +CODEC_MIC_ADCRATE_REG equ 34h ; mic in sample rate + +; registers 36-7a are reserved on the ICH + +CODEC_VENDORID1_REG equ 7ch ; codec vendor ID 1 +CODEC_VENDORID2_REG equ 7eh ; codec vendor ID 2 + +; Mixer registers 0 through 51h reside in the ICH and are not forwarded over +; the AC97 link to the codec, which I think is a little weird. Looks like +; the ICH makes it so you don't need a fully functional codec to play audio? +; +; whenever 2 codecs are present in the system, use BIT7 to access the 2nd +; set of registers, ie 80h-feh + +PRIMARY_CODEC equ 0 ; 0-7F for primary codec +SECONDARY_CODEC equ BIT7 ; 80-8f registers for 2ndary + +SAMPLE_RATE_441khz equ 44100 ; 44.1Khz (cd quality) rate + +; ---------------------------------------------------------------------------- +; 17/02/2017 +PCI_IO_BASE equ 10h ; = NAMBAR register offset +; 13/11/2024 ('equ' to '=' conversion for FASM) +AC97_INT_LINE = 3Ch ; AC97 Interrupt Line register offset + +; ---------------------------------------------------------------------------- +; ICH2AC97.INC +; ---------------------------------------------------------------------------- + +; PCI stuff + +; Intel ICH2 equates. It is assumed that ICH0 and plain ole ICH are compatible. + +INTEL_VID equ 8086h ; Intel's PCI vendor ID + +; 08/05/2024 +; 03/11/2023 - Erdogan Tan (Ref: MenuetOS AC97 WAV Player source code, 2004) +SIS_VID equ 1039h +NVIDIA_VID equ 10DEh ; Ref: MPXPLAY/SBEMU/KOLIBRIOS AC97 source c. +AMD_VID equ 1022h + +ICH_DID equ 2415h ; ICH device ID +ICH0_DID equ 2425h ; ICH0 +ICH2_DID equ 2445h ; ICH2 I think there are more ICHes. + ; they all should be compatible. +; 08/05/2024 +; 17/02/2017 (Erdogan Tan, ref: ALSA Device IDs, ALSA project) +ICH3_DID equ 2485h ; ICH3 +ICH4_DID equ 24C5h ; ICH4 +ICH5_DID equ 24D5h ; ICH5 +ICH6_DID equ 266Eh ; ICH6 +ESB6300_DID equ 25A6h ; 6300ESB +ESB631X_DID equ 2698h ; 631XESB +ICH7_DID equ 27DEh ; ICH7 +; 03/11/2023 - Erdogan Tan (Ref: MenuetOS AC97 WAV Player source code, 2004) +MX82440_DID equ 7195h +SI7012_DID equ 7012h +NFORCE_DID equ 01B1h +NFORCE2_DID equ 006Ah +AMD8111_DID equ 746Dh +AMD768_DID equ 7445h +; 03/11/2023 - Erdogan Tan - Ref: MPXPLAY/SBEMU/KOLIBRIOS AC97 source code +CK804_DID equ 0059h +MCP04_DID equ 003Ah +CK8_DID equ 008Ah +NFORCE3_DID equ 00DAh +CK8S_DID equ 00EAh + +; 13/11/2024 ('equ' to '=' conversion for FASM) +NAMBAR_REG = 10h ; native audio mixer BAR + NAM_SIZE equ 256 ; 256 bytes required. + +NABMBAR_REG = 14h ; native audio bus mastering BAR + NABM_SIZE equ 64 ; 64 bytes + +; BUS master registers, accessed via NABMBAR+offset + +; ICH supports 3 different types of register sets for three types of things +; it can do, thus: +; +; PCM in (for recording) aka PI +; PCM out (for playback) aka PO +; MIC in (for recording) aka MC + +PI_BDBAR_REG equ 0 ; PCM in buffer descriptor BAR +PO_BDBAR_REG equ 10h ; PCM out buffer descriptor BAR +MC_BDBAR_REG equ 20h ; MIC in buffer descriptor BAR + +; each buffer descriptor BAR holds a pointer which has entries to the buffer +; contents of the .WAV file we're going to play. Each entry is 8 bytes long +; (more on that later) and can contain 32 entries total, so each BAR is +; 256 bytes in length, thus: + +BDL_SIZE equ 32*8 ; Buffer Descriptor List size +INDEX_MASK equ 31 ; indexes must be 0-31 + + + +PI_CIV_REG equ 4 ; PCM in current Index value (RO) +PO_CIV_REG equ 14h ; PCM out current Index value (RO) +MC_CIV_REG equ 24h ; MIC in current Index value (RO) +;8bit read only +; each current index value is simply a pointer showing us which buffer +; (0-31) the codec is currently processing. Once this counter hits 31, it +; wraps back to 0. +; this can be handy to know, as once it hits 31, we're almost out of data to +; play back or room to record! + + +PI_LVI_REG equ 5 ; PCM in Last Valid Index +PO_LVI_REG equ 15h ; PCM out Last Valid Index +MC_LVI_REG equ 25h ; MIC in Last Valid Index +;8bit read/write +; The Last Valid Index is a number (0-31) to let the codec know what buffer +; number to stop on after processing. It could be very nasty to play audio +; from buffers that aren't filled with the audio we want to play. + + +PI_SR_REG equ 6 ; PCM in Status register +PO_SR_REG equ 16h ; PCM out Status register +MC_SR_REG equ 26h ; MIC in Status register +;16bit read/write +; status registers. Bitfields follow: + +FIFO_ERR equ BIT4 ; FIFO Over/Underrun W1TC. + +BCIS equ BIT3 ; buffer completion interrupt status. + ; Set whenever the last sample in ANY + ; buffer is finished. Bit is only + ; set when the Interrupt on Complete + ; (BIT4 of control reg) is set. + +LVBCI equ BIT2 ; Set whenever the codec has processed + ; the last buffer in the buffer list. + ; Will fire an interrupt if IOC bit is + ; set. Probably set after the last + ; sample in the last buffer is + ; processed. W1TC + + ; +CELV equ BIT1 ; Current buffer == last valid. + ; Bit is RO and remains set until LVI is + ; cleared. Probably set up the start + ; of processing for the last buffer. + + +DCH equ BIT0 ; DMA controller halted. + ; set whenever audio stream is stopped + ; or something else goes wrong. + +PI_PICB_REG equ 8 ; PCM in position in current buffer(RO) +PO_PICB_REG equ 18h ; PCM out position in current buffer(RO) +MC_PICB_REG equ 28h ; MIC in position in current buffer (RO) +;16bit read only +; position in current buffer regs show the number of dwords left to be +; processed in the current buffer. +; + +PI_PIV_REG equ 0ah ; PCM in Prefected index value +PO_PIV_REG equ 1ah ; PCM out Prefected index value +MC_PIV_REG equ 2ah ; MIC in Prefected index value +;8bit, read only +; Prefetched index value register. +; tells which buffer number (0-31) has be prefetched. I'd imagine this +; value follows the current index value fairly closely. (CIV+1) +; + +PI_CR_REG equ 0bh ; PCM in Control Register +PO_CR_REG equ 1bh ; PCM out Control Register +MC_CR_REG equ 2bh ; MIC in Control Register +; 8bit +; Control register *MUST* only be accessed as an 8bit value. +; Control register. See bitfields below. +; + +IOCE equ BIT4 ; interrupt on complete enable. + ; set this bit if you want an intrtpt + ; to fire whenever LVBCI is set. +FEIFE equ BIT3 ; set if you want an interrupt to fire + ; whenever there is a FIFO (over or + ; under) error. +LVBIE equ BIT2 ; last valid buffer interrupt enable. + ; set if you want an interrupt to fire + ; whenever the completion of the last + ; valid buffer. +RR equ BIT1 ; reset registers. Nukes all regs + ; except bits 4:2 of this register. + ; Only set this bit if BIT 0 is 0 +RPBM equ BIT0 ; Run/Pause + ; set this bit to start the codec! + + +GLOB_CNT_REG equ 2ch ; Global control register +SEC_RES_EN equ BIT5 ; secondary codec resume event + ; interrupt enable. Not used here. +PRI_RES_EN equ BIT4 ; ditto for primary. Not used here. +ACLINK_OFF equ BIT3 ; Turn off the AC97 link +ACWARM_RESET equ BIT2 ; Awaken the AC97 link from sleep. + ; registers preserved, bit self clears +ACCOLD_RESET equ BIT1 ; Reset everything in the AC97 and + ; reset all registers. Not self clearing + +GPIIE equ BIT0 ; GPI Interrupt enable. + ; set if you want an interrupt to + ; fire upon ANY of the bits in the + ; GPI (general pursose inputs?) not used. + +GLOB_STS_REG equ 30h ; Global Status register (RO) + +MD3 equ BIT17 ; modem powerdown status (yawn) +AD3 equ BIT16 ; Audio powerdown status (yawn) +RD_COMPLETE_STS equ BIT15 ; Codec read timed out. 0=normal +BIT3SLOT12 equ BIT14 ; shadowed status of bit 3 in slot 12 +BIT2SLOT12 equ BIT13 ; shadowed status of bit 2 in slot 12 +BIT1SLOT12 equ BIT12 ; shadowed status of bit 1 in slot 12 +SEC_RESUME_STS equ BIT11 ; secondary codec has resumed (and irqed) +PRI_RESUME_STS equ BIT10 ; primary codec has resumed (and irqed) +SEC_CODEC_RDY equ BIT9 ; secondary codec is ready for action +PRI_CODEC_RDY equ BIT8 ; Primary codec is ready for action + ; software must check these bits before + ; starting the codec! +MIC_IN_IRQ equ BIT7 ; MIC in caused an interrupt +PCM_OUT_IRQ equ BIT6 ; One of the PCM out channels IRQed +PCM_IN_IRQ equ BIT5 ; One of the PCM in channels IRQed +MODEM_OUT_IRQ equ BIT2 ; modem out channel IRQed +MODEM_IN_IRQ equ BIT1 ; modem in channel IRQed +GPI_STS_CHANGE equ BIT0 ; set whenever GPI's have changed. + ; BIT0 of slot 12 also reflects this. + + +ACC_SEMA_REG equ 34h ; Codec write semiphore register +CODEC_BUSY equ BIT0 ; codec register I/O is happening + ; self clearing +; +; Buffer Descriptors List +; As stated earlier, each buffer descriptor list is a set of (up to) 32 +; descriptors, each 8 bytes in length. Bytes 0-3 of a descriptor entry point +; to a chunk of memory to either play from or record to. Bytes 4-7 of an +; entry describe various control things detailed below. +; +; Buffer pointers must always be aligned on a Dword boundry. +; +; + +IOC equ BIT31 ; Fire an interrupt whenever this + ; buffer is complete. + +BUP equ BIT30 ; Buffer Underrun Policy. + ; if this buffer is the last buffer + ; in a playback, fill the remaining + ; samples with 0 (silence) or not. + ; It's a good idea to set this to 1 + ; for the last buffer in playback, + ; otherwise you're likely to get a lot + ; of noise at the end of the sound. + +; +; Bits 15:0 contain the length of the buffer, in number of samples, which +; are 16 bits each, coupled in left and right pairs, or 32bits each. +; Luckily for us, that's the same format as .wav files. +; +; A value of FFFF is 65536 samples. Running at 44.1Khz, that's just about +; 1.5 seconds of sample time. FFFF * 32bits is 1FFFFh bytes or 128k of data. +; +; A value of 0 in these bits means play no samples. +; + +; CODE + +; AC97.ASM + +; codec configuration code. Not much here really. +; NASM version: Erdogan Tan (29/11/2016) + +; enable codec, unmute stuff, set output rate to 44.1 +; entry: ax = desired sample rate +; + +; 13/11/2024 ('%if' to 'if' conversion for FASM) +; 08/04/2024 +;%if 0 +if 0 + +codecConfig: + ; 17/02/2017 + ; 07/11/2016 (Erdogan Tan) + PORT_NABM_GLB_CTRL_STAT equ 60h + + ;mov dx, [NAMBAR] ; mixer base address + ;add dx, CODEC_EXT_AUDIO_REG ; 28h + ;in ax, dx + ;and ax, 1 + ;jnz short _ssr + ;pop ax + ;jmp short cconf_1 + +_ssr: + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + in ax, dx + or ax, 1 + out dx, ax ; Enable variable rate audio + + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + + mov ax, [sample_rate] ; 17/02/2017 (Erdogan Tan) + + mov dx, [NAMBAR] + add dx, CODEC_PCM_FRONT_DACRATE_REG ; 2Ch + out dx, ax ; out sample rate + + ;mov dx, [NAMBAR] + ;add dx, CODEC_LR_ADCRATE_REG ; 32h + ;out dx, ax + + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + +;cconf_1: + mov dx, [NAMBAR] ; mixer base address + add dx, CODEC_RESET_REG ; reset register + mov ax, 42 + out dx, ax ; reset + + mov dx, [NABMBAR] ; bus master base address + add dx, PORT_NABM_GLB_CTRL_STAT + mov ax, 2 + out dx, ax + + mov cx, 7 +_100ms: + push cx + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + pop cx + loop _100ms + + mov dx, [NAMBAR] + add dx, CODEC_MASTER_VOL_REG ;02h + xor ax, ax ; ; volume attenuation = 0 (max. volume) + out dx, ax + + mov dx, [NAMBAR] + add dx, CODEC_MASTER_MONO_VOL_REG ;06h + ;xor ax, ax + out dx, ax + + mov dx, [NAMBAR] + add dx, CODEC_PCBEEP_VOL_REG ;0Ah + ;xor ax, ax + out dx, ax + + mov dx, [NAMBAR] + add dx, CODEC_PCM_OUT_REG ;18h + ;xor ax, ax + out dx, ax + + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + + retn +;%else +else + ; 12/05/2024 + ; 08/05/2024 + ; (ac97_vra.asm, 19/11/2023, Erdogan Tan, playwav3.asm) +codecConfig: + ; 02/12/2023 + ; 26/11/2023 + ; 21/11/2023 + ; 20/11/2023 + ; 19/11/2023 (TRDOS 386 v2.0.7) + ; 15/11/2023 + ; 04/11/2023 + ; 17/02/2017 + ; 07/11/2016 (Erdogan Tan) + ;PORT_NABM_GLB_CTRL_STAT equ 60h + + ; 03/11/2023 (MPXPLAY, 'SC_ICH.C', ac97_init) + ; 'AC97_DEF.H' + ;AC97_EXTENDED_STATUS equ 002Ah + AC97_EA_SPDIF equ 0002h + AC97_EA_VRA equ 0001h + ; 04/11/2023 + ICH_PO_CR_RESET equ 0002h ; reset codec + ICH_PCM_20BIT equ 400000h ; 20-bit samples (ICH4) + ICH_PCM_246_MASK equ 300000h ; 6 channels + + ; 08/05/2024 + ; 11/11/2023 + CTRL_ST_CREADY equ BIT8+BIT9+BIT28 ; Primary Codec Ready + CODEC_REG_POWERDOWN equ 26h + + ; 04/11/2023 +init_ac97_controller: + mov eax, [bus_dev_fn] + mov al, PCI_CMD_REG + call pciRegRead16 ; read PCI command register + or dl, IO_ENA+BM_ENA ; enable IO and bus master + call pciRegWrite16 + + ; 14/05/2024 + ; 02/12/2023 + call delay_100ms ; 29/05/2017 + + ; 02/12/2023 + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + +init_ac97_codec: + ; 18/11/2023 + mov bp, 40 + ; 14/05/2024 + ;mov bp, 100 +_initc_1: + ; 11/11/2023 + ; (TRDOS 386 v2.0.5, 'audio.s') + mov dx, GLOB_CNT_REG ; 2Ch + add dx, [NABMBAR] + in eax, dx + + ; 14/05/2024 + ; 02/12/2023 + call delay1_4ms + + ; ? + ;; 15/11/2023 + ;;mov cx, 40 + ;mov bp, 40 ; 18/11/2023 +;_initc_1: + mov dx, GLOB_STS_REG ; 30h + add dx, [NABMBAR] + in eax, dx + + ; 14/05/2024 + ; 02/12/2023 + call delay1_4ms + + cmp eax, 0FFFFFFFFh ; -1 + ;je short init_ac97_codec_err1 + ; 15/11/2023 + jne short _initc_3 +_initc_2: + ;dec cx + dec bp ; 18/11/2023 + ;jz short init_ac97_codec_err1 + ; 19/11/2023 + jz short _ac97_codec_ready + + call delay_100ms + jmp short _initc_1 +_initc_3: + test eax, CTRL_ST_CREADY + jnz short _ac97_codec_ready + + call reset_ac97_codec + ; 11/11/2023 + ;jc short init_ac97_codec_err2 + ; 15/11/2023 + ;jc short _initc_2 + ; 26/11/2023 + jmp short _initc_2 + +_ac97_codec_ready: + mov dx, [NAMBAR] + ;add dx, 0 ; ac_reg_0 ; reset register + out dx, ax + + call delay_100ms + + ; 19/11/2023 + or bp, bp + jnz short _ac97_codec_init_ok + + xor eax, eax ; 0 + mov dx, [NAMBAR] + add dx, CODEC_REG_POWERDOWN + out dx, ax + + ; 19/11/2023 + ; wait for 1 second + ; 14/05/2024 + ;mov ecx, 1000 ; 1000*4*0.25ms = 1s + ;mov cx, 10 + ; 20/05/2024 + ;mov cx, 40 ; 19/05/2024 + mov ecx, 40 +_ac97_codec_rloop: + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + call delay_100ms + + mov dx, [NAMBAR] + add dx, CODEC_REG_POWERDOWN + in ax, dx + + ; 14/05/2024 + ; 02/12/2023 + call delay1_4ms + + and ax, 0Fh + cmp al, 0Fh + je short _ac97_codec_init_ok + loop _ac97_codec_rloop + + ; 12/05/2024 + ; cf = 1 +init_ac97_codec_err1: + ;stc ; 12/05/2024 +init_ac97_codec_err2: + retn + +_ac97_codec_init_ok: + ; 11/11/2023 + ;mov al, 2 ; force set 16-bit 2-channel PCM + ;mov dx, GLOB_CNT_REG ; 2Ch + ;add dx, [NABMBAR] + ;out dx, eax + + ;;call delay1_4ms + + call reset_ac97_controller + + ; 11/11/2023 + ;call delay1_4ms + ; 21/11/2023 - temporary + call delay_100ms + + ;call setup_ac97_codec + +setup_ac97_codec: + ; 08/05/2028 + ; [sample_rate] = 22050 + ; 12/11/2023 + ;cmp word [sample_rate], 48000 + ;je short skip_rate + +; 11/11/2023 +; 05/11/2023 +;%if 1 + AC97_EA_VRA equ BIT0 ; 11/11/2023 + + ; 18/05/2024 + call delay1_4ms + + ; 16/05/2024 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_REG ; 28h + in ax, dx + + ; 18/05/2024 + ; 16/05/2024 + call delay1_4ms + ; 17/05/2024 + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + + ; 17/05/2024 + ;call delay_100ms + + ; 14/05/2024 + test al, 1 ; BIT0 ; Variable Rate Audio bit + jz short vra_not_supported + + ; 11/11/2023 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + in ax, dx + + ; 14/05/2024 + ; 02/12/2023 + call delay1_4ms + + ; 13/11/2024 ('~' to 'NOT' conversion for FASM) + and al, NOT BIT1 ; Clear DRA + or al, AC97_EA_VRA ; 1 ; 04/11/2023 + out dx, ax ; Enable variable rate audio + + mov cx, 10 +check_vra: + call delay_100ms + + ; 11/11/2023 + in ax, dx + test al, AC97_EA_VRA ; 1 + jnz short set_rate + + ; 11/11/2023 + loop check_vra + + ; 13/11/2023 + ;mov byte [VRA], 0 + ; 14/05/2024 +vra_not_supported: + ; 08/05/2024 + mov word [sample_rate], 48000 + jmp short skip_rate + + ; 12/11/2023 + ;pop ax ; discard return address to the caller + ;mov dx, msg_no_vra + ;jmp vra_err + +set_rate: + mov ax, [sample_rate] ; 17/02/2017 (Erdogan Tan) + ; 08/05/2024 + ; ax = 22050 (Hz) + + mov dx, [NAMBAR] + add dx, CODEC_PCM_FRONT_DACRATE_REG ; 2Ch + out dx, ax ; PCM Front/Center Output Sample Rate + + call delay_100ms + + ; 12/11/2023 +skip_rate: + ; 11/11/2023 (temporary) + + ;mov dx, [NAMBAR] + ;add dx, CODEC_PCM_SURND_DACRATE_REG ; 2Eh + ;out dx, ax ; PCM Surround Output Sample Rate + + ;call delay_100ms + + ;mov dx, [NAMBAR] + ;add dx, CODEC_PCM_LFE_DACRATE_REG ; 30h + ;out dx, ax ; PCM LFE Output Sample Rate + + ;call delay_100ms + + ; 05/11/2023 (temporary) + ;mov dx, [NAMBAR] + ;add dx, CODEC_LR_ADCRATE_REG ; 32h + ;out dx, ax ; PCM Input Sample Rate + ; + ;call delay_100ms + + mov ax, 0202h + mov [volume], al ; 29 + mov dx, [NAMBAR] + add dx, CODEC_MASTER_VOL_REG ; 02h + out dx, ax + + ; 11/11/2023 + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + ; + ;mov dx, [NAMBAR] + ;add dx, CODEC_MASTER_MONO_VOL_REG ; 06h + ;out dx, ax + + ; 11/11/2023 + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + ; + ;mov ax, 02h + ;mov dx, [NAMBAR] + ;add dx, CODEC_PCBEEP_VOL_REG ; 0Ah + ;out dx, ax + + ; 14/05/2024 + ; 20/11/2023 + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + + ; 21/11/2023 temporary + ;call delay_100ms + + ;mov ax, 0202h + mov dx, [NAMBAR] + add dx, CODEC_PCM_OUT_REG ; 18h + out dx, ax + + ; 14/05/2024 + ; 20/11/2023 + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + + ; 14/05/2024 + ; 21/11/2023 - temporary + ;call delay_100ms + + ; 11/11/2023 + ;mov ax, 8008h ; Mute + ;mov dx, [NAMBAR] + ;add dx, CODEC_PHONE_VOL_REG ; 0Ch + ; ; AC97_PHONE_VOL ; TAD Input (Mono) + ;out dx, ax + ; + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + + ;mov ax, 0808h + ;mov dx, [NAMBAR] + ;add dx, CODEC_LINE_IN_VOL_REG ;10h ; Line Input (Stereo) + ;out dx, ax + ; + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + + ;mov dx, [NAMBAR] + ;add dx, CODEC_CD_VOL_REG ;12h ; CD Input (Stereo) + ;out dx, ax + ; + ;mov dx, [NAMBAR] + ;add dx, CODEC_AUX_VOL_REG ;16h ; Aux Input (Stereo) + ;out dx, ax + ; + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + + ; 14/05/2024 + ;call delay_100ms + + ; 14/05/2024 + clc + +;detect_ac97_codec: + retn + +reset_ac97_controller: + ; 11/11/2023 + ; 10/06/2017 + ; 29/05/2017 + ; 28/05/2017 + ; reset AC97 audio controller registers + xor ax, ax + mov dx, PI_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 14/05/2024 + call delay1_4ms + + mov dx, PO_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 14/05/2024 + call delay1_4ms + + mov dx, MC_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 14/05/2024 + call delay1_4ms + + mov al, RR + mov dx, PI_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 14/05/2024 + call delay1_4ms + + mov dx, PO_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 14/05/2024 + call delay1_4ms + + mov dx, MC_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 14/05/2024 + call delay1_4ms + + retn + +reset_ac97_codec: + ; 11/11/2023 + ; 28/05/2017 - Erdogan Tan (Ref: KolibriOS, intelac97.asm) + mov dx, GLOB_CNT_REG ; 2Ch + add dx, [NABMBAR] + in eax, dx + + ;test eax, 2 + ; 06/08/2022 + test al, 2 + jz short _r_ac97codec_cold + + call warm_ac97codec_reset + jnc short _r_ac97codec_ok +_r_ac97codec_cold: + call cold_ac97codec_reset + jnc short _r_ac97codec_ok + + ; 16/04/2017 + ;xor eax, eax ; timeout error + ;stc + retn + +_r_ac97codec_ok: + xor eax, eax + ;mov al, VIA_ACLINK_C00_READY ; 1 + inc al + retn + +warm_ac97codec_reset: + ; 11/11/2023 + ; 06/08/2022 - TRDOS 386 v2.0.5 + ; 28/05/2017 - Erdogan Tan (Ref: KolibriOS, intelac97.asm) + mov eax, 6 + mov dx, GLOB_CNT_REG ; 2Ch + add dx, [NABMBAR] + out dx, eax + + mov cx, 10 ; total 1s +_warm_ac97c_rst_wait: + call delay_100ms + + mov dx, GLOB_STS_REG ; 30h + add dx, [NABMBAR] + in eax, dx + + test eax, CTRL_ST_CREADY + jnz short _warm_ac97c_rst_ok + + dec cx + jnz short _warm_ac97c_rst_wait + +_warm_ac97c_rst_fail: + stc +_warm_ac97c_rst_ok: + retn + +cold_ac97codec_reset: + ; 11/11/2023 + ; 06/08/2022 - TRDOS 386 v2.0.5 + ; 28/05/2017 - Erdogan Tan (Ref: KolibriOS, intelac97.asm) + mov eax, 2 + mov dx, GLOB_CNT_REG ; 2Ch + add dx, [NABMBAR] + out dx, eax + + call delay_100ms ; wait 100 ms + call delay_100ms ; wait 100 ms + call delay_100ms ; wait 100 ms + call delay_100ms ; wait 100 ms + + mov cx, 16 ; total 20*100 ms = 2s + +_cold_ac97c_rst_wait: + mov dx, GLOB_STS_REG ; 30h + add dx, [NABMBAR] + in eax, dx + + test eax, CTRL_ST_CREADY + jnz short _cold_ac97c_rst_ok + + call delay_100ms + + dec cx + jnz short _cold_ac97c_rst_wait + +_cold_ac97c_rst_fail: + stc +_cold_ac97c_rst_ok: + retn + +delay_100ms: + ; 11/11/2023 + ; 29/05/2017 + ; 24/03/2017 ('codec.asm') + ; wait 100 ms + push cx + mov cx, 400 ; 400*0.25ms +_delay_x_ms: + call delay1_4ms + loop _delay_x_ms + pop cx + retn + +;%endif +end if + +;============================================================================= +; ICH_WAV.ASM +;============================================================================= + +; DOS based .WAV player using AC'97 and codec interface. +; --------------------------------------------------------------- +; NASM version: Erdogan Tan (29/11/2016) +; Last Update: 17/02/2017 (by Erdogan Tan) + +; ICHWAV.ASM +; PLAYMOD.ASM +; player internal variables and other equates. +;BUFFERSIZE equ 2048*4 ; 8K half buffer size. 18/02/2017 +; 13/11/2024 ('equ' to '=' conversion for FASM) +; 14/05/2024 +BUFFERSIZE = 2560*4 +ENDOFFILE equ BIT0 ; flag for knowing end of file + +;=========================================================================== +; entry: none. File is already open and [filehandle] filled. +; exit: not until the song is finished or the user aborts. +; +; 18/02/2017 +ModPlay: ; 13/02/2017 ; ModPlay Polling! + ;cld + ; clear (half) buffer 2 + ;mov di, [DMA_BUFFER2] + ;sub ax, ax + ;mov cx, (BUFFERSIZE/2) + ;rep stosw + + ; 15/05/2024 + push es + push ds + pop es + mov cx, 320 + mov di, MOD_BUFFER + mov ax, 8080h + rep stosw + mov cx, 0A000h + mov es, cx + call ScopeLoop + pop es + + ; load 2048 bytes into buffer 1 + mov si, [DMA_BUFFER1] + ; 11/05/2024 + ;mov cx, BUFFERSIZE + ;push ds ; segment + ;push si ; offset + ;push cx ; count + call GetSamples_ICH ; 18/02/2017 + + ; load 2048 bytes into buffer 2 + mov si, [DMA_BUFFER2] + ; 11/05/2024 + ;mov cx, BUFFERSIZE + ;push ds ; segment + ;push si ; offset + ;push cx ; count + call GetSamples_ICH ; 18/02/2017 + +; register reset the DMA engine. This may cause a pop noise on the output +; lines when the device is reset. Prolly a better idea to mute output, then +; reset. + + ; 08/05/2024 + ;mov dx, [NABMBAR] + ;add dx, PO_CR_REG ; set pointer to Ctrl reg + ;mov al, RR ; set reset + ;out dx, al ; self clearing bit + +; write last valid index to 31 to start with. +; The Last Valid Index register tells the DMA engine when to stop playing. +; +; As we progress through the song we change the last valid index to always be +; something other than the index we're currently playing. +; + ;;mov al, 1 + ;mov al, 31 + ;call setLastValidIndex + +; create Buffer Descriptor List +; +; A buffer descriptor list is a list of pointers and control bits that the +; DMA engine uses to know where to get the .wav data and how to play it. +; +; I set it up to use only 2 buffers of .wav data, and whenever 1 buffer is +; playing, I refresh the other one with good data. +; +; +; For the control bits, you can specify that the DMA engine fire an interrupt +; after a buffer has been processed, but I poll the current index register +; to know when it's safe to update the other buffer. +; +; I set the BUP bit, which tells the DMA engine to just play 0's (silence) +; if it ever runs out of data to play. Good for safety. +; + ; 14/02/2017 + mov di, [BDL_BUFFER] ; get BDL address + mov cx, 32 / 2 ; make 32 entries in BDL + xor edx, edx + mov dx, ds + shl edx, 4 ; segment*16 (linear/physical address of the segment) +_0: + +; set buffer descriptor 0 to start of data file in memory + ; 14/02/2017 + movzx eax, word [DMA_BUFFER1] + add eax, edx ; linear/physical address of the buffer (seg*16+off) + stosd ; store dmabuffer1 address + +; +; set length to 32k samples. 1 sample is 16bits or 2bytes. +; Set control (bits 31:16) to BUP, bits 15:0=number of samples. +; + +; 17/02/2017 (Erdogan Tan) +; Intel® 82801AA (ICH) & Intel® 82801AB (ICH0) I/O Controller Hub AC ’97 +; Programmer’s Reference Manual + +; 2.2.1 Buffer Descriptor List (on Page 13) + ; + ; Generic Form of Buffer Descriptor + ; --------------------------------- + ; 63 62 61-48 47-32 31-0 + ; --- --- -------- ------- ----- + ; IOC BUP -reserved- Buffer Buffer + ; Length Pointer + ; [15:0] [31:0] + ; + ; IOC: Interrupt On Completion. + ; 1 = Enabled. + ; When this is set, it means that the controller should + ; issue an interrupt upon completion of this buffer. + ; It should also set the IOC bit in the status register + ; 0 = Disabled + ; + ; BUP: Buffer Underrun Policy. + ; 0 = When this buffer is complete, + ; if the next buffer is not yet ready + ; (i.e., the last valid buffer has been processed), + ; then continue to transmit the last valid sample. + ; 1 = When this buffer is complete, + ; if this is the last valid buffer, transmit zeros after + ; this buffer has been processed completely. + ; This bit typically is set only if this is the last + ; buffer in the current stream. + ; + ; [31:0]: Buffer pointer. This field points to the location of + ; the data buffer. Since samples can be as wide as one + ; word, the buffer must be aligned with word boundaries, + ; to prevent samples from straddling DWord boundaries. + ; + ; [15:0]: Buffer Length: This is the length of the data buffer, + ; in number of samples. The controller uses this data + ; to determine the length of the buffer, in bytes. + ; "0" indicates no sample to process. + +; ICH2AC97.INC + +; IOC equ BIT31 ; Fire an interrupt whenever this + ; buffer is complete. + +; BUP equ BIT30 ; Buffer Underrun Policy. + ; if this buffer is the last buffer + ; in a playback, fill the remaining + ; samples with 0 (silence) or not. + ; It's a good idea to set this to 1 + ; for the last buffer in playback, + ; otherwise you're likely to get a lot + ; of noise at the end of the sound. +; +; Bits 15:0 contain the length of the buffer, in number of samples, which +; are 16 bits each, coupled in left and right pairs, or 32bits each. +; Luckily for us, that's the same format as .wav files. +; +; A value of FFFF is 65536 samples. Running at 44.1Khz, that's just about +; 1.5 seconds of sample time. FFFF * 32bits is 1FFFFh bytes or 128k of data. +; +; A value of 0 in these bits means play no samples. +; + ; 08/12/2016 - Erdogan Tan + ;mov eax, BUFFERSIZE + ;or eax, IOC + BUP + ; 12/05/2024 + mov eax, BUFFERSIZE/2 + or eax, BUP ; (tuneloop without interrupt) + stosd + +; 2nd buffer: + ; 14/02/2017 + movzx eax, word [DMA_BUFFER2] + add eax, edx ; linear/physical address of the buffer (seg*16+off) + stosd ; store dmabuffer2 address + +; set length to 64k (32k of two 16 bit samples) +; Set control (bits 31:16) to BUP, bits 15:0=number of samples +; + ; 08/12/2016 - Erdogan Tan + ;mov eax, BUFFERSIZE + ;or eax, IOC + BUP + ; 12/05/2024 + mov eax, BUFFERSIZE/2 + ; 12/05/2024 + or eax, BUP ; (tuneloop without interrupt) + stosd + loop _0 + +; +; tell the DMA engine where to find our list of Buffer Descriptors. +; this 32bit value is a flat mode memory offset (ie no segment:offset) +; +; write NABMBAR+10h with offset of buffer descriptor list +; + movzx eax, word [BDL_BUFFER] + ; 14/02/2017 + add eax, edx ; linear/physical address of the BDL + ; 18/02/2017 + mov dx, [NABMBAR] + add dx, PO_BDBAR_REG ; set pointer to BDL + out dx, eax ; write to AC97 controller + +; +; All set. Let's play some music. +; + ; 08/12/2016 + ; 07/10/2016 + ;mov al, 1 + mov al, 31 + ; 08/05/2024 + mov [LVI], al ; 10/11/2023 + + call setLastValidIndex + + mov byte [tLoop], 1 ; 30/11/2016 + +; 13/11/2024 ('%if' -> 'if' conversion for FASM) +; 12/05/2024 (tuneloop, without interrupt) +;%if 0 +if 0 + ; 12/05/2024 + ; 17/02/2017 + ;mov dx, [NABMBAR] + ;add dx, PO_CR_REG ; PCM out Control Register + ;mov al, IOCE + RPBM ; Enable 'Interrupt On Completion' + run + ; ; (LVBI interrupt will not be enabled) + ;out dx, al ; Start bus master operation. + +; while DMA engine is running, examine current index and wait until it hits 1 +; as soon as it's 1, we need to refresh the data in wavbuffer1 with another +; 64k. Likewise when it's playing buffer 2, refresh buffer 1 and repeat. + + ; 18/02/2017 + ; 14/02/2017 + ; 13/02/2017 + ; 08/12/2016 + ; 28/11/2016 + + push es + mov ax, 0A000h + mov es, ax + ;mov bp, DmaBuffer ; 14/02/2017 +p_loop: + mov ah, 1 ; any key pressed? + int 16h ; no, Loop. + jz short q_loop + + mov ah, 0 ; flush key buffer... + int 16h +p_return: + mov byte [tLoop], 0 ; 13/02/2017 + pop es + retn +q_loop: + ; 10/05/2024 + xor ax, ax + xchg al, [tBuff] ; AL = [tBuff], [tBuff] = 0 + cmp al, 1 + ja short r_loop + jb short ScopeLoop + ; + mov si, [DMA_BUFFER1] ; [tBuff]=1 (from tuneLoop) + jmp short s_loop +r_loop: + ; 13/02/2017 + mov si, [DMA_BUFFER2] ; [tBuff]=2 (from tuneLoop) +s_loop: + ; 14/02/2017 + ;mov bp, si ; save current buffer addres in bp register + ; 11/05/2024 + ;mov cx, BUFFERSIZE ; 2048*4 byte + ;push ds ; segment + ;push si ; offset + ;push cx ; count + call GetSamples_ICH ; 18/02/2017 + ; +ScopeLoop: + ;mov si, bp ; get current samples + mov si, MOD_BUFFER ; 18/02/2017 + xor cx, cx ; to be drawed ... + xor dx, dx +DrawLoop: + mov bx, dx ; (save Index) + mov di, [Scope+bx] ; get old SCOPE pixel address + mov byte [es:di], 0 ; erase it! + lodsb ; get a sample (8-bit) + mov bl, al ; calc new pixel address... + xor bh, bh + shl bx, 1 + mov di, [RowOfs+bx] + add di, cx + mov bx, dx ; (restore Index) + mov [Scope+bx], di ; save new address... + mov byte [es:di], 10 ; 0Ah ; and DRAW. + add dx, 2 ; the next pixel... + inc cx + cmp cx, 320 ; 320 pixels drawed? + jb short DrawLoop + jmp short p_loop + +tuneLoop: + ; 11/05/2024 + ; 11/11/2023 + ; 10/11/2023 + ; 18/02/2017 + ; 08/12/2016 + ; 28/11/2016 - Erdogan Tan + + ; 11/05/2024 + cmp byte [tLoop], 1 + jb short tL3 + + call getCurrentIndex + + ; 10/11/2023 + cmp al, [LVI] + jne short tL1 + + dec ax + and al, 1Fh + call setLastValidIndex + xchg al, [LVI] +tL1: + test al, BIT0 + jz short tL2 + + ; 11/05/2024 + mov byte [tBuff], 1 + retn +tL2: + mov byte [tBuff], 2 +tL3: + retn + +; returns AL = current index value +getCurrentIndex: + ;push dx + mov dx, [NABMBAR] + add dx, PO_CIV_REG + in al, dx + ;pop dx + retn + +;input AL = index # to stop on +setLastValidIndex: + ;push dx + mov dx, [NABMBAR] + add dx, PO_LVI_REG + out dx, al + ;pop dx + retn +;%else +else + ; 12/05/2024 + ; 17/02/2017 + mov dx, [NABMBAR] + add dx, PO_CR_REG ; PCM out Control Register + ;mov al, IOCE + RPBM ; Enable 'Interrupt On Completion' + run + ; ; (LVBI interrupt will not be enabled) + ; 06/11/2023 (TUNELOOP version, without interrupt) + mov al, RPBM + out dx, al ; Start bus master operation. + + push es + mov ax, 0A000h + mov es, ax + + ; 12/05/2024 +;p_loop: +; call tuneLoop +; cmp byte [tLoop], 0 +; ja short p_loop +; pop es +; retn + +p_loop: + mov ah, 1 ; any key pressed? + ;mov ah, 11h + int 16h ; no, Loop. + jz short q_loop + + mov ah, 0 + ;mov ah, 10h ; flush key buffer... + int 16h + + ; 12/05/2024 (change PCM out volume) + cmp al, '+' + jne short p_1 + + mov al, [volume] + cmp al, 0 + jna short q_loop + dec al + jmp short p_2 +p_1: + cmp al, '-' + jne short p_return + + mov al, [volume] + cmp al, 31 + jnb short q_loop + inc al +p_2: + mov [volume], al + mov ah, al + mov dx, [NAMBAR] + ;add dx, CODEC_MASTER_VOL_REG + add dx, CODEC_PCM_OUT_REG + out dx, ax + + ; 12/05/2024 + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + + jmp short q_loop + +p_return: + pop es + retn +q_loop: +tuneLoop: + ; 12/05/2024 + ; 18/11/2023 (ich_wav4.asm, Erdogan Tan) +tL1: + call updateLVI ; /set LVI != CIV/ + ;call check4keyboardstop + ;jc short _exit_ + call getCurrentIndex + test al, BIT0 + jz short tL1 ; loop if buffer 2 is not playing + + mov si, [DMA_BUFFER1] + call GetSamples_ICH + + call ScopeLoop +tL2: + call updateLVI + ;call check4keyboardstop + ;jc short _exit_ + call getCurrentIndex + test al, BIT0 + jnz short tL2 ; loop if buffer 1 is not playing + + mov si, [DMA_BUFFER2] + call GetSamples_ICH + + call ScopeLoop + jmp short p_loop + +ScopeLoop: + ;mov si, bp ; get current samples + mov si, MOD_BUFFER ; 18/02/2017 + xor cx, cx ; to be drawed ... + xor dx, dx +DrawLoop: + mov bx, dx ; (save Index) + mov di, [Scope+bx] ; get old SCOPE pixel address + mov byte [es:di], 0 ; erase it! + ;lodsb ; get a sample (8-bit) + ; 14/05/2024 + lodsw + mov bl, al ; calc new pixel address... + xor bh, bh + shl bx, 1 + mov di, [RowOfs+bx] + add di, cx + mov bx, dx ; (restore Index) + mov [Scope+bx], di ; save new address... + mov byte [es:di], 10 ; 0Ah ; and DRAW. + add dx, 2 ; the next pixel... + inc cx + cmp cx, 320 ; 320 pixels drawed? + jb short DrawLoop + retn + +;_exit_: + ;mov byte [tLoop], 0 + ;retn + + ; 12/05/2024 +updateLVI: + ; 06/11/2023 + mov dx, [NABMBAR] + add dx, PO_CIV_REG + ; (Current Index Value and Last Valid Index value) + in ax, dx + + cmp al, ah ; is current index = last index ? + jne short uLVI_exit ; 12/05/2024 + + ; 08/11/2023 + call getCurrentIndex + + dec al + and al, 1Fh + +;input AL = index # to stop on +setLastValidIndex: + ; 08/11/2023 + ;push dx + mov dx, [NABMBAR] + add dx, PO_LVI_REG + out dx, al + ;pop dx +uLVI_exit: ; 12/05/2024 + retn + +; returns AL = current index value +getCurrentIndex: + ;push dx + mov dx, [NABMBAR] + add dx, PO_CIV_REG + in al, dx + ;pop dx + retn + + ; 12/05/2024 +check4keyboardstop: + ; 08/11/2023 + ; 04/11/2023 + mov ah, 1 + int 16h + jz short _cksr + xor ah, ah + int 16h + stc +_cksr: + retn +;%endif +end if + +;============================================================================= +; MODLOAD.ASM +;============================================================================= + +; Amiga Module Loader v0.1b by Carlos Hasan. +; July 10th, 1993. + +; STRUCTURES + +; 13/11/2024 ('resb','resw,'resd' to 'rb','rw','rd' conversions for FASM) + +;struc ModSample +struc _ModSample +{ +.msName rb 22 +.msLength: rw 1 +.msFinetune: rb 1 +.msVolume: rb 1 +.msRepeat: rw 1 +.msRepLen: rw 1 +.size: +;endstruc +} + +; 13/11/2024 +virtual at 0 + ModSample _ModSample + sizeof.ModSample = $ +end virtual + +;struc ModHeader +struc _ModHeader +{ +.mhName: rb 20 +.mhSamples: rb sizeof.ModSample*31 +.mhOrderLen: rb 1 +.mhReStart: rb 1 +.mhOrder: rb 128 +.mhSign: rw 2 +.size: +;endstruc +} + +; 13/11/2024 +virtual at 0 + ModHeader _ModHeader + sizeof.ModHeader = $ +end virtual + +;struc ModInfoRec +struc _ModInfoRec +{ +.OrderLen: rb 1 +.ReStart: rb 1 +.Order: rb 128 +.Patterns: rd 1 +.SampOfs: rw 31 +.SampSeg: rw 31 +.SampLen: rw 31 +.SampRep: rw 31 +.SampRepLen: rw 31 +.SampVol: rw 31 +.size: +;endstruc +} + +; 13/11/2024 +virtual at 0 + ModInfoRec _ModInfoRec + sizeof.ModInfoRec = $ +end virtual + +; CODE + +LoadModule: + ;es:di = filename + + ;[sp+4] = es + ;[sp+2] = di + + FileName equ 4 + + push bp + mov bp, sp + pusha + push ds + push es + + mov word [ErrorInfo], 1 + + call ClearModInfo +OpenFile: + push ds + mov ax, 3D00h + lds dx, [bp+FileName] + int 21h + pop ds + jc Failed + mov [FileHandle], ax + +ReadHeader: + mov ax, 3F00h + mov bx, [FileHandle] + ;mov cx, ModHeader.size + ; 13/11/2024 + mov cx, sizeof.ModHeader + ;lea dx, [Header] + mov dx, Header + int 21h + jc CloseFile +CheckMK: + cmp word [Header+ModHeader.mhSign], 'M.' + jne short CheckFLT4 + cmp word [Header+ModHeader.mhSign+2], 'K.' + je short IsModFile +CheckFLT4: + cmp word [Header+ModHeader.mhSign], 'FL' + jne short Is15Inst + cmp word [Header+ModHeader.mhSign+2], 'T4' + je short IsModFile +Is15Inst: + ;mov si, (Header+ModHeader.mhSamples) + (15*ModSample.size) + ; 13/11/2024 + mov si, (Header+ModHeader.mhSamples) + (15*sizeof.ModSample) + mov di, Header+ModHeader.mhOrderLen + mov ax, ds + mov es, ax + cld + mov cx, 130 + rep movsb + ;mov di, Header+ModHeader.mhSamples + (15*ModSample.size) + ; 13/11/2024 + mov di, Header+ModHeader.mhSamples + (15*sizeof.ModSample) + xor ax, ax + ;mov cx, 16*ModSample.size + ; 13/11/2024 + mov cx, 16*sizeof.ModSample + rep stosb +SeekPatterns: + mov ax, 4200h + mov bx, [FileHandle] + mov cx, 0 + mov dx, 600 + int 21h +IsModFile: + mov al, [Header+ModHeader.mhOrderLen] + mov [ModInfo.OrderLen], al + + mov al, [Header+ModHeader.mhReStart] + cmp al, [Header+ModHeader.mhOrderLen] + jb short SetReStart + mov al, 7Fh +SetReStart: + mov [ModInfo.ReStart], al + + mov cx, 128 + xor ax, ax + xor bx, bx +CopyOrder: + mov ah, [Header+ModHeader.mhOrder+bx] + mov [ModInfo.Order+bx], ah + cmp ah, al + jb short NextOrder + mov al, ah +NextOrder: + inc bx + loop CopyOrder +AllocPatterns: + ; Erdogan Tan (13/02/2017) + xor ah, ah + inc al + ; al = count of 1024 bytes + mov bx, ax + ; count of paragraphs = al*64 + shl ax, 6 ; *64 + mov bp, ax + mov dx, cs ; current (code) segment + add dx, 1000h ; next 64K (4096*16) + ; + mov word [ModInfo.Patterns], 0 + mov [ModInfo.Patterns+2], dx + ; + add bp, dx ; next segment for samples +ReadPatterns: + push ds + mov ax, 3F00h + mov cx, bx ; count of 1024 bytes + shl cx, 10 ; byte count (cx*1024) + mov bx, [FileHandle] + ;lds dx, [ModInfo.Patterns] + mov ds, dx + xor dx, dx + int 21h + pop ds + jc CloseFile + + ;lea si, [Header+ModHeader.mhSamples] + mov si, Header+ModHeader.mhSamples + xor di, di +CopySamples: + mov ax, [si+ModSample.msLength] + xchg al, ah + shl ax, 1 + mov [ModInfo.SampLen+di], ax + mov al, [si+ModSample.msVolume] + xor ah, ah + mov [ModInfo.SampVol+di], ax + mov ax, [si+ModSample.msRepeat] + xchg al, ah + shl ax, 1 + mov [ModInfo.SampRep+di], ax + mov ax, [si+ModSample.msRepLen] + xchg al, ah + shl ax, 1 + mov [ModInfo.SampRepLen+di], ax + ;add si, ModSample.size + ; 13/11/2024 + add si, sizeof.ModSample + add di, 2 + cmp di, 2*31 + jb short CopySamples + + xor si, si +AllocSamples: + ; Erdogan Tan (13/02/2017) + ;mov bx, [ModInfo.SampLen+si] + mov cx, [ModInfo.SampLen+si] + mov bx, cx + shr bx, 4 ; byte count / 16 + jz short NextSample + inc bx ; number of paragraphs + mov word [ModInfo.SampOfs+si], 0 + mov [ModInfo.SampSeg+si], bp + mov dx, bp + add bp, bx ; next segment for sample +ReadSample: + push ds + mov ax, 3F00h + mov bx, [FileHandle] + ;mov cx, [ModInfo.SampLen+si] + ;mov dx, [ModInfo.SampOfs+si] + ;mov ds, [ModInfo.SampSeg+si] + mov ds, dx + xor dx, dx + int 21h + pop ds + jc short CloseFile +NextSample: + add si, 2 + cmp si, 2*31 + jb short AllocSamples + + mov word [ErrorInfo], 0 +CloseFile: + mov ax, 3E00h + mov bx, [FileHandle] + int 21h +Failed: + pop es + pop ds + popa + pop bp + ret 4 + +FreeModule: + ; Erdogan Tan (13/02/2017) + ; nothing to do here for memory de-allocation +ClearModInfo: + pusha + push es + mov ax, ds + mov es, ax + ;lea di, [ModInfo] + mov di, ModInfo + ;mov cx, ModInfoRec.size + ; 13/11/2024 + mov cx, sizeof.ModInfoRec + cld + xor ax, ax + rep stosb + pop es + popa + retn + +;============================================================================= +; MODPLAY.ASM +;============================================================================= + +; Amiga Module Player v0.3b by Carlos Hasan. +; July 23th, 1993. + +; EQUATES + +NumTracks equ 4 +DefTempo equ 6 +DefBpm equ 125 +MidCRate equ 8448 +MixBufSize equ 4096 + +; STRUCTURES + +; 13/11/2024 ('resb','resw','resd' to 'rb','rw','rd' conversions for FASM) + +;struc TrackInfo +struc _TrackInfo +{ +.Samples: rd 1 +.Position: rw 1 +.Len: rw 1 +.Repeat: rw 1 +.RepLen: rw 1 +.Volume: rb 1 +.Error: rb 1 +.Period: rw 1 +.Pitch: rw 1 +.Effect: rw 1 +.PortTo: rw 1 +.PortParm: rb 1 +.VibPos: rb 1 +.VibParm: rb 1 +.OldSampOfs: rb 1 +.Arp: rw 3 +.ArpIndex: rw 1 +.size: +;endstruc +} + +; 13/11/2024 +virtual at 0 + TrackInfo _TrackInfo + sizeof.TrackInfo = $ +end virtual + +; CODE + +;-------------------------------------------------------------------------- +; BeatTrack: Process the next beat in one track. +; In: +; ds:di - Track info Address. +;-------------------------------------------------------------------------- + +BeatTrack: + mov dx, [di+TrackInfo.Effect] + test dx, dx + je short None + cmp dh, 00h + je short Arpeggio + cmp dh, 01h + je short PortUp + cmp dh, 02h + je short PortDown + cmp dh, 03h + je short TonePort + cmp dh, 04h + je Vibrato + cmp dh, 05h + je PortSlide + cmp dh, 06h + je VibSlide + cmp dh, 0Ah + je VolSlide +None: + retn +Arpeggio: + mov bx, [di+TrackInfo.ArpIndex] + mov ax, [di+TrackInfo.Arp+bx] + mov [di+TrackInfo.Pitch], ax + add bx, 2 + cmp bx, 6 + jb short SetArpIndex + xor bx,bx +SetArpIndex: + mov [di+TrackInfo.ArpIndex], bx + retn +PortUp: + xor dh, dh + mov bx, [di+TrackInfo.Period] + sub bx, dx + cmp bx, 113 + jge short NotSmall + mov bx, 113 +NotSmall: + mov [di+TrackInfo.Period], bx + add bx, bx + mov ax, [PitchTable+bx] + mov [di+TrackInfo.Pitch], ax + retn +PortDown: + xor dh, dh + mov bx, [di+TrackInfo.Period] + add bx, dx + cmp bx, 856 + jle short NotBig + mov bx, 856 +NotBig: mov [di+TrackInfo.Period], bx + add bx, bx + mov ax, [PitchTable+bx] + mov [di+TrackInfo.Pitch], ax + retn +TonePort: + xor dh, dh + mov ax, [di+TrackInfo.PortTo] + mov bx, [di+TrackInfo.Period] + cmp bx, ax + je short NoPort + jg short PortToUp +PortToDown: + add bx, dx + cmp bx, ax + jle short SetPort +FixPort: + mov bx, ax + jmp short SetPort +PortToUp: + sub bx, dx + cmp bx, ax + jl short FixPort +SetPort: + mov [di+TrackInfo.Period], bx + add bx, bx + mov ax, [PitchTable+bx] + mov [di+TrackInfo.Pitch], ax +NoPort: + retn +Vibrato: + mov dh, dl + and dl, 0Fh + shr dh, 4 + shl dh, 2 + add [di+TrackInfo.VibPos], dh + mov dh, [di+TrackInfo.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 short VibUp + neg ax +VibUp: + add ax, [di+TrackInfo.Period] + mov bx, ax + cmp bx, 113 + jge short NoLoVib + mov bx, 113 +NoLoVib: + cmp bx, 856 + jle short NoHiVib + mov bx, 856 +NoHiVib: + add bx, bx + mov ax, [PitchTable+bx] + mov [di+TrackInfo.Pitch], ax + retn +PortSlide: + call VolSlide + mov dl, [di+TrackInfo.PortParm] + jmp short TonePort +VibSlide: + call VolSlide + mov dl, [di+TrackInfo.VibParm] + jmp short Vibrato +VolSlide: + mov dh, dl + and dl, 0Fh + shr dh, 4 + mov al, [di+TrackInfo.Volume] + sub al, dl + jge short NoLoVol + xor al, al +NoLoVol: + add al, dh + cmp al, 64 + jbe short NoHiVol + mov al, 64 +NoHiVol: + mov [di+TrackInfo.Volume], al + retn + +;-------------------------------------------------------------------------- +; GetTrack: Get the next Note from a pattern. +; In: +; ds:di - Track info Address. +; es:si - Pattern Note Address. +; Out: +; es:si - The Next Pattern Note address. +;-------------------------------------------------------------------------- + +GetTrack: + es lodsw + xchg al, ah + mov bl, ah + and ah, 0Fh + mov cx, ax + es lodsw + xchg al, ah + mov bh, ah + and ah, 0Fh + mov dx, ax + mov [di+TrackInfo.Effect], dx + and bl, 0F0h + shr bh, 4 + or bl, bh + je short SetPeriod +SetSample: + xor bh, bh + dec bx + add bx, bx + mov ax, [ModInfo.SampVol+bx] + mov [di+TrackInfo.Volume], al + mov ax, [ModInfo.SampOfs+bx] + mov [di+TrackInfo.Samples], ax + mov ax, [ModInfo.SampSeg+bx] + mov [di+TrackInfo.Samples+2], ax + mov ax, [ModInfo.SampLen+bx] + mov [di+TrackInfo.Len], ax + mov ax, [ModInfo.SampRep+bx] + mov [di+TrackInfo.Repeat], ax + mov ax, [ModInfo.SampRepLen+bx] + mov [di+TrackInfo.RepLen], ax +SetPeriod: + test cx, cx + je short SetEffect + + mov [di+TrackInfo.PortTo], cx + cmp dh, 03h + je short SetEffect + + mov [di+TrackInfo.Period], cx + mov bx, cx + add bx, bx + mov ax, [PitchTable+bx] + mov [di+TrackInfo.Pitch], ax + mov word [di+TrackInfo.Position], 0 +SetEffect: + test dx, dx + je short InitNone + cmp dh, 00h + je InitArpeggio + cmp dh, 03h + je short InitTonePort + cmp dh, 04h + je short InitVibrato + cmp dh, 09h + je short SampleOfs + cmp dh, 0Bh + je short PosJump + cmp dh, 0Ch + je short SetVolume + cmp dh, 0Dh + ;je short Break + je short _Break ; 13/11/2024 (FASM modification) + cmp dh, 0Fh + je short SetSpeed +InitNone: + retn +InitTonePort: + test dl, dl + jne short SetPortParm + mov dl, [di+TrackInfo.PortParm] +SetPortParm: + mov [di+TrackInfo.PortParm], dl + mov [di+TrackInfo.Effect], dx + retn +InitVibrato: + mov al, [di+TrackInfo.VibParm] + mov ah, al + and al, 0Fh + and ah, 0F0h + test dl, 0Fh + jne short OkDepth + or dl, al +OkDepth: + test dl, 0F0h + jne short OkRate + or dl, ah +OkRate: + mov [di+TrackInfo.VibParm], dl + mov [di+TrackInfo.Effect], dx + test cx, cx + je short OkPos + mov byte [di+TrackInfo.VibPos], 0 +OkPos: + retn +SampleOfs: + test dl, dl + jne short SetSampleOfs + mov dl, [di+TrackInfo.OldSampOfs] +SetSampleOfs: + mov [di+TrackInfo.OldSampOfs], dl + mov dh, dl + xor dl, dl + mov [di+TrackInfo.Position], dx + retn +PosJump: + mov [OrderPos], dl + mov byte [Row], 64 + retn +SetVolume: + cmp dl, 64 + jbe short OkVol + mov dl, 64 +OkVol: + mov [di+TrackInfo.Volume], dl + retn +;Break: + ; 13/11/2024 +_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 byte [Row], 64 + retn +SetSpeed: + test dl,dl + je Skip + cmp dl,31 + ja short SetBpm +SetTempo: + mov [Tempo], dl + mov [TempoWait], dl + retn +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: + retn +InitArpeggio: + mov dh, dl + and dl, 0Fh + shr dh, 4 + mov cx, 36 + xor bx, bx + mov ax, [di+TrackInfo.Period] +gt_ScanPeriod: + cmp ax, [PeriodTable+bx] + jae short SetArp + add bx, 2 + loop gt_ScanPeriod +SetArp: + add dx, dx + add dh, bl + add dl, bl + mov bx, [PeriodTable+bx] + add bx, bx + mov ax, [PitchTable+bx] + mov [di+TrackInfo.Arp], ax + mov bl, dh + xor bh, bh + mov bx, [PeriodTable+bx] + add bx, bx + mov ax, [PitchTable+bx] + mov [di+TrackInfo.Arp+2], ax + mov bl, dl + xor bh, bh + mov bx, [PeriodTable+bx] + add bx, bx + mov ax, [PitchTable+bx] + mov [di+TrackInfo.Arp+4], ax + mov word [di+TrackInfo.ArpIndex], 0 + retn + +;-------------------------------------------------------------------------- +; UpdateTracks: Main code to process the next tick to be played. +;-------------------------------------------------------------------------- + +UpdateTracks: + dec byte [TempoWait] + jz short GetTracks + + mov cx, NumTracks + mov di, Tracks +BeatTracks: + call BeatTrack + ;add di, TrackInfo.size + ; 13/11/2024 + add di, sizeof.TrackInfo + loop BeatTracks + retn +GetTracks: + mov al, [Tempo] + mov [TempoWait], al + + les si, [Note] + cmp byte [Row], 64 + jb short NoPattWrap + + les si, [ModInfo.Patterns] + mov bl, [OrderPos] + cmp bl, [ModInfo.OrderLen] + jb short NoOrderWrap + mov bl, [ModInfo.ReStart] + mov [OrderPos], bl + cmp bl, [ModInfo.OrderLen] + jae short NoUpdate +NoOrderWrap: + xor bh, bh + mov bl, [ModInfo.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 [Note], si + mov [Note+2], es + inc byte [OrderPos] +NoPattWrap: + inc byte [Row] + + cld + mov cx, NumTracks + mov di, Tracks +GetTracks_next: + push cx + call GetTrack + pop cx + ;add di, TrackInfo.size + ; 13/11/2024 + add di, sizeof.TrackInfo + loop GetTracks_next + + mov [Note], si +NoUpdate: + retn + +;-------------------------------------------------------------------------- +; MixTrack: Mixes one track into a CLEAN buffer. +; In: +; ds:si - Track Info Address. +; ds:di - Buffer Address. +; cx - Buffer Size. +;-------------------------------------------------------------------------- + +MixTrack: + cmp word [si+TrackInfo.RepLen], 2 + ja short MixLooped +MixNonLooped: + les dx, [si+TrackInfo.Samples] + mov bx, [si+TrackInfo.Position] + mov bp, [si+TrackInfo.Len] + push dx + push si + add bx, dx + add bp, dx + mov dx, [si+TrackInfo.Pitch] + mov al, [si+TrackInfo.Volume] + mov ah, [si+TrackInfo.Error] + mov si, bx + mov bh, al + mov al, dl + mov dl, dh + xor dh, dh +nlMixSamp: + cmp si, bp + jae short 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+TrackInfo.Position], bx + mov [si+TrackInfo.Error], ah + retn +MixLooped: + les dx, [si+TrackInfo.Samples] + mov bx, [si+TrackInfo.Position] + mov bp, [si+TrackInfo.RepLen] + mov [BufRep], bp + add bp, [si+TrackInfo.Repeat] + push dx + push si + add bx, dx + add bp, dx + mov dx, [si+TrackInfo.Pitch] + mov al, [si+TrackInfo.Volume] + mov ah, [si+TrackInfo.Error] + mov si, bx + mov bh, al + mov al, dl + mov dl, dh + xor dh, dh +lpMixSamp: + cmp si, bp + jb short 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+TrackInfo.Position], bx + mov [si+TrackInfo.Error], ah + retn + +GetSamples_ICH: + ; 11/05/2024 + ; 18/02/2017 + ; 8 bit mono samples + ; must be converted to 16 bit, stereo samples (for ICH) ! + ; (ICH AC97 Modification by Erdogan Tan) + mov [_si_], si ; DMA Buff Addr, [DMA_BUFFER1] or [DMA_BUFFER2] + ; 11/05/2024 + ;mov si, MOD_BUFFER + ;shr cx, 2 ; mod buffer size = dma (half) buffer size / 4 (*) + +;-------------------------------------------------------------------------- +; GetSamples: Returns the next chunk of samples to be played. +; In: +; Buffer - Buffer Address. +; Count - Buffer Size. +;-------------------------------------------------------------------------- + +GetSamples: + ;ds:si = buffer address + ;cx = count + + ; 11/05/2024 + ; + ;;[sp+6] = ds + ;;[sp+4] = si + ;;[sp+2] = count + ; + ;Count equ 4 + ;Buffer equ 6 + ; + ;push bp + ;mov bp, sp + ; + ;push es + ;;;push ds + ;;;pusha + ; + ;cld + ; + ;les di, [bp+Buffer] + ;mov bx, [bp+Count] + + ; 11/05/2024 + ; ds = cs + push es ; + + + push ds + pop es + + ; 11/05/2024 + mov di, MOD_BUFFER + mov bx, (BUFFERSIZE/4) ; (*) ; 2048 +NextChunk: + cmp word [BufLen], 0 + jne short CopyChunk + + ; 11/05/2024 + push es + push bx + push di +MixChunk: + ;lea di, [MixBuffer] + mov di, MixBuffer + mov cx, [BpmSamples] + mov [BufPtr], di + mov [BufLen], cx + + ; 12/05/2024 + ; es = ds + ;mov ax, ds + ;mov es, ax + + mov al, 80h + rep stosb + + mov cx, NumTracks + ;mov si, Tracks - TrackInfo.size + ; 13/11/2024 + mov si, Tracks - sizeof.TrackInfo +GetSamples_next: + push cx + ;add si, TrackInfo.size + ; 13/11/2024 + add si, sizeof.TrackInfo + mov cx, [BufLen] + mov di, [BufPtr] + call MixTrack + pop cx + loop GetSamples_next + + call UpdateTracks + + pop di + pop bx + pop es ; es = ds ; 12/05/2024 +CopyChunk: + mov cx, [BufLen] + cmp cx, bx + jbe short MoveChunk + mov cx, bx +MoveChunk: + mov si, [BufPtr] + add [BufPtr], cx + sub [BufLen], cx + sub bx, cx + rep movsb + test bx, bx + jnz short NextChunk + + ;;popa + ;;pop ds + ;pop es + ;pop bp + ;ret 6 + +; GetSamples_ICH_convert_samples: + ; 11/05/2024 + ; es = ds = cs + ; 18/02/2017 + ;mov di, ds + ;mov es, di + mov di, [_si_] ; DMA Buffer Address (16 bit, stereo) + mov si, MOD_BUFFER - 1 ; buffer for 8 bit mono samples + mov cx, (BUFFERSIZE/4) ; (*) ; 2048 ; 11/04/2024 + xor al, al +gscs_loop: + inc si + mov ah, [si] ; convert 8 bit sample to 16 bit sample + ; 11/05/2024 + sub ah, 80h + + stosw ; left channel + stosw ; right channel + loop gscs_loop + + ; 11/05/2024 + pop es ; + + ;pop bp + ;ret 6 + retn + +;-------------------------------------------------------------------------- +; StartPlaying: Initializes the Sound System. +; In: +; Module Information Resources. +;-------------------------------------------------------------------------- + +StartPlaying: + pusha + push ds + push es +SetModParms: + mov byte [OrderPos], 0 + mov byte [Tempo], DefTempo + mov byte [TempoWait], DefTempo + mov byte [Bpm], DefBpm + mov byte [Row], 64 + mov byte [BreakRow], 0 + mov ax, [MixSpeed] + xor dx, dx + mov bx, 24*DefBpm/60 + div bx + mov [BpmSamples], ax +ClearTracks: + mov di, Tracks + mov ax, ds + mov es, ax + ;mov cx, NumTracks*TrackInfo.size + ; 13/11/2024 + mov cx, NumTracks*sizeof.TrackInfo + xor ax, ax + cld + rep stosb + + mov [BufPtr], ax + mov [BufLen], ax +MakePitch: + mov ax, MidCRate + mov bx, 428 + mul bx + div word [MixSpeed] + xor dh, dh + mov dl, ah + mov ah, al + xor al, al + mov cx, 857 + xor bx, bx + mov di, PitchTable +PitchLoop: + push ax + push dx + cmp dx, bx + jae short 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 + retn ; 12/05/2024 + +;-------------------------------------------------------------------------- +; StopPlaying: ShutDown the Sound System. +;-------------------------------------------------------------------------- + +StopPlaying: + ; 08/05/2024 + ; 04/11/2023 + ; finished with song, stop everything + call ac97_stop + +; 13/11/2024 ('%if' -> 'if' conversion for FASM) +; 12/05/2024 (tuneloop version) +;%if 0 +if 0 + ; 11/11/2023 +irq_restore: + ; restore previous interrupt vector and interrupt_status + cli + in al, 0A1h ; irq 8-15 + mov al, [IRQ_status+1] + out 0A1h, al + in al, 021h ; irq 0-7 + mov al, [IRQ_status] + out 21h, al + ; ... + push es + xor ax, ax + mov es, ax + mov ax, [IRQ_vector] + mov [es:bx], ax + mov ax, [IRQ_vector+2] + mov [es:bx+2], ax + pop es + + sti +;%endif +end if + retn + +;============================================================================= +; PLAYER.ASM +;============================================================================= + +; UTILS.ASM +;---------------------------------------------------------------------------- +; delay1_4ms - Delay for 1/4 millisecond. +; 1mS = 1000us +; Entry: +; None +; Exit: +; None +; +; Modified: +; None +; +PORTB EQU 061h + REFRESH_STATUS EQU 010h ; Refresh signal status + +delay1_4ms: + push ax + push cx + mov cx, 16 ; close enough. + in al,PORTB + and al,REFRESH_STATUS + mov ah,al ; Start toggle state + or cx, cx + jz short _d4ms1 + inc cx ; Throwaway first toggle +_d4ms1: + in al,PORTB ; Read system control port + and al,REFRESH_STATUS ; Refresh toggles 15.085 microseconds + cmp ah,al + je short _d4ms1 ; Wait for state change + + mov ah,al ; Update with new state + dec cx + jnz short _d4ms1 + + pop cx + pop ax + retn + +print_msg: + ; 13/11/2016 - Erdogan Tan + ; esi = ASCIIZ text address + ; + mov bx, 7h + mov ah, 0Eh +pm_next_char: + lodsb + and al, al + jz short pm_retn + int 10h + jmp short pm_next_char +pm_retn: + retn + +dword2str: + ; 13/11/2016 - Erdogan Tan + ; eax = dword value + ; + call dwordtohex + mov [dword_str], edx + mov [dword_str+4], eax + mov si, dword_str + retn + + ; trdos386.s (unix386.s) - 10/05/2015 + ; Convert binary number to hexadecimal string + +bytetohex: + ; INPUT -> + ; AL = byte (binary number) + ; OUTPUT -> + ; AX = hexadecimal string + ; + push bx + xor bh, bh + mov bl, al + shr bl, 4 + mov bl, [bx+hex_chars] + xchg bl, al + and bl, 0Fh + mov ah, [bx+hex_chars] + pop bx + retn + +wordtohex: + ; INPUT -> + ; AX = word (binary number) + ; OUTPUT -> + ; EAX = hexadecimal string + ; + push bx + xor bh, bh + xchg ah, al + push ax + mov bl, ah + shr bl, 4 + mov al, [bx+hex_chars] + mov bl, ah + and bl, 0Fh + mov ah, [bx+hex_chars] + shl eax, 16 + pop ax + pop bx + jmp short bytetohex + +dwordtohex: + ; INPUT -> + ; EAX = dword (binary number) + ; OUTPUT -> + ; EDX:EAX = hexadecimal string + ; + push eax + shr eax, 16 + call wordtohex + mov edx, eax + pop eax + call wordtohex + retn + + ; 13/11/2016 - Erdogan Tan +write_ac97_dev_info: + ; BUS/DEV/FN + ; 00000000BBBBBBBBDDDDDFFF00000000 + ; DEV/VENDOR + ; DDDDDDDDDDDDDDDDVVVVVVVVVVVVVVVV + + xor bh, bh + mov esi, [dev_vendor] + mov ax, si + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgVendorId+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgVendorId+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgVendorId+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgVendorId], al + shr esi, 16 + mov ax, si + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgDevId+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgDevId+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgDevId+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgDevId], al + + mov esi, [bus_dev_fn] + shr esi, 8 + mov ax, si + mov bl, al + mov dl, bl + and bl, 7 ; bit 0,1,2 + mov al, [bx+hex_chars] + mov [msgFncNo+1], al + mov bl, dl + shr bl, 3 + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgDevNo+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgDevNo], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgBusNo+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgBusNo], al + + ;mov ax, [ac97_io_base] + ; 08/05/2024 + mov ax, [NABMBAR] + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgIOBaseAddr+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgIOBaseAddr+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgIOBaseAddr+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgIOBaseAddr], al + + ; 24/11/2016 + xor ah, ah + mov al, [ac97_int_ln_reg] + mov cl, 10 + div cl + add [msgIRQ], ax + and al, al + jnz short _pmi + mov al, byte [msgIRQ+1] ; 13/11/2024 + mov ah, ' ' + mov [msgIRQ], ax +_pmi: + mov dx, msgAC97Info + mov ah, 9 + int 21h + + retn + + ; 08/05/2024 +ac97_stop: + ; 11/11/2023 + ; 09/11/2023 + ; 05/11/2023 + ; 04/11/2023 + ; 28/05/2017 (TRDOS 386 v2, 'audio.s') + ;mov byte [tLoop], 0 ; stop ! ; 05/11/2023 +;_ac97_stop: + + ; 11/11/2023 + mov dx, [NAMBAR] + ;add dx, 0 ; ac_reg_0 ; reset register + out dx, ax + + ; 04/11/2023 + ; 09/10/2017 (TRDOS 386 v2, 'audio.s') + ; 11/06/2017 + xor al, al ; 0 + call ac97_po_cmd + + ; (Ref: KolibriOS, intelac97.asm, 'stop:') + ; Clear FIFOE, BCIS, LVBCI (Ref: Intel ICH hub manual) + mov ax, 1Ch + mov dx, [NABMBAR] + add dx, PO_SR_REG + out dx, ax + + ; 11/06/2017 + mov al, RR +ac97_po_cmd: + ; 11/06/2017 + ; 29/05/2017 + mov dx, [NABMBAR] + add dx, PO_CR_REG ; PCM out control register + out dx, al + retn + +;============================================================================= +; preinitialized data +;============================================================================= + +;============================================================================= +; PLAY.ASM - DATA +;============================================================================= + +msg_2017: + db 'Tiny MOD Player by Erdogan Tan. November 2024.',10,13 + db 'usage: playmod4 filename.mod', 10, 13, '$' + db '18/02/2017',0 + db '20/05/2024',0 + db '13/11/2024',0 + +Credits: db 'Tiny MOD Player v0.1b by Carlos Hasan. July 1993.' +CRLF: ; 13/05/2024 + db 10,13,'$' +ErrorMesg: db 'Error loading Module file.',10,13,'$' + db 0 ; 13/11/2024 (4070 bytes) + +;============================================================================= +; MODPLAY.ASM - DATA +;============================================================================= + +;Credits: db 'Amiga Module Player v0.3b by Carlos Hasan.' + +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 + +;============================================================================= +; PLAYWAV.ASM / PLAYER.ASM - DATA +;============================================================================= + +; 24/11/2016 +; IRQ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +irq_int: db 08h,09h,0Ah,0Bh,0Ch,0Dh,0Eh,0Fh,70h,71h,72h,73h,74h,75h,76h,77h + +; 13/11/2024 +; ('<<' to 'shl' conversion for FASM) + +; 17/02/2017 +; Valid ICH device IDs + +valid_ids: +;dd (ICH_DID << 16) + INTEL_VID ; 8086h:2415h +dd (ICH_DID shl 16) + INTEL_VID ; 8086h:2415h +dd (ICH0_DID shl 16) + INTEL_VID ; 8086h:2425h +dd (ICH2_DID shl 16) + INTEL_VID ; 8086h:2445h +dd (ICH3_DID shl 16) + INTEL_VID ; 8086h:2485h +dd (ICH4_DID shl 16) + INTEL_VID ; 8086h:24C5h +dd (ICH5_DID shl 16) + INTEL_VID ; 8086h:24D5h +dd (ICH6_DID shl 16) + INTEL_VID ; 8086h:266Eh +dd (ESB6300_DID shl 16) + INTEL_VID ; 8086h:25A6h +dd (ESB631X_DID shl 16) + INTEL_VID ; 8086h:2698h +dd (ICH7_DID shl 16) + INTEL_VID ; 8086h:27DEh +; 03/11/2023 - Erdogan Tan +dd (MX82440_DID shl 16) + INTEL_VID ; 8086h:7195h +dd (SI7012_DID shl 16) + SIS_VID ; 1039h:7012h +dd (NFORCE_DID shl 16) + NVIDIA_VID ; 10DEh:01B1h +dd (NFORCE2_DID shl 16) + NVIDIA_VID ; 10DEh:006Ah +dd (AMD8111_DID shl 16) + AMD_VID ; 1022h:746Dh +dd (AMD768_DID shl 16) + AMD_VID ; 1022h:7445h +dd (CK804_DID shl 16) + NVIDIA_VID ; 10DEh:0059h +dd (MCP04_DID shl 16) + NVIDIA_VID ; 10DEh:003Ah +dd (CK8_DID shl 16) + NVIDIA_VID ; 1022h:008Ah +dd (NFORCE3_DID shl 16) + NVIDIA_VID ; 10DEh:00DAh +dd (CK8S_DID shl 16) + NVIDIA_VID ; 10DEh:00EAh + +;valid_id_count equ ($ - valid_ids)>>2 ; 05/11/2023 +; 13/11/2024 +valid_id_count = ($ - valid_ids) shr 2 ; 05/11/2023 + +; 13/11/2016 +hex_chars db "0123456789ABCDEF", 0 +msgAC97Info db "AC97 Audio Controller & Codec Info", 0Dh, 0Ah + db "Vendor ID: " +msgVendorId db "0000h Device ID: " +msgDevId db "0000h", 0Dh, 0Ah + db "Bus: " +msgBusNo db "00h Device: " +msgDevNo db "00h Function: " +msgFncNo db "00h" + db 0Dh, 0Ah + db "I/O Base Address: " +msgIOBaseAddr db "0000h IRQ: " +msgIRQ dw 3030h + db 0Dh, 0Ah, "$" + +;msgSampleRate db "Sample Rate: " +;msgHertz db "00000 Hz ", "$" +;msg8Bits db "8 bits ", "$" +;msgMono db "Mono", 0Dh, 0Ah, "$" +;msg16Bits db "16 bits ", "$" +;msgStereo db "Stereo", 0Dh, 0Ah, "$" + +;; 13/11/2016 - Erdogan Tan (Ref: KolibriOS, codec.inc) +;codec_id dd 0 +;codec_chip_id dd 0 +;codec_vendor_ids dw 0 +;codec_chip_ids dw 0 + +dword_str dd 30303030h, 30303030h + db 'h', 0Dh, 0Ah, 0 + +;============================================================================= +; uninitialized data +;============================================================================= + +bss_start: + +; 13/11/2024 +; ('resb','resw','resd' to 'rb','rw','rd' conversions for FASM) + +align 4 ; alignb 4 (NASM) + +; 17/02/2017 +; NAMBAR: Native Audio Mixer Base Address Register +; (ICH, Audio D31:F5, PCI Config Space) Address offset: 10h-13h +; NABMBAR: Native Audio Bus Mastering Base Address register +; (ICH, Audio D31:F5, PCI Config Space) Address offset: 14h-17h +NAMBAR: rw 1 ; BAR for mixer +NABMBAR rw 1 ; BAR for bus master regs + +tBuff: rb 1 +;irq_status: rb 1 +pcm_irq_status: rb 1 ; 08/05/2024 + +inside: rb 1 +tLoop: rb 1 + +; 08/05/2024 +IRQ_status: rw 1 ; IRQ status before enabling audio interrupt +IRQ_vector: rd 1 ; Previous interrupt handler address + +; 256 byte buffer for descriptor list +BDL_BUFFER: rw 1 ; segment of our 256byte BDL buffer +DMA_BUFFER1: rw 1 ; Pointer to 1st half of DMA Buffer +DMA_BUFFER2: rw 1 ; Pointer to 2nd half of DMA Buffer + +; 12/11/2016 - Erdogan Tan + +ac97_int_ln_reg: rb 1 +err_num: rb 1 + +bus_dev_fn: rd 1 +dev_vendor: rd 1 +; 08/05/2024 +;stats_cmd: rd 1 +;ac97_io_base: rw 1 +LVI: rb 1 +; 12/05/2024 +volume: rb 1 + +align 4 ; alignb 4 (NASM) + +BdlBuffer: rb BDL_SIZE ; 13/02/2017 +DmaBuffer: rb 2*BUFFERSIZE ; 13/02/2017 + +; MODLOAD.ASM +FileHandle: rw 1 +ErrorInfo: rw 1 +Header: rb sizeof.ModHeader + +sample_rate: ; PLAYER.ASM (22050Hz) +; MODPLAY.ASM +MixSpeed: rw 1 + +ModInfo: +ModInfo.OrderLen: rb 1 +ModInfo.ReStart: rb 1 +ModInfo.Order: rb 128 +ModInfo.Patterns: rd 1 + +ModInfo.SampOfs: rw 31 +ModInfo.SampSeg: rw 31 +ModInfo.SampLen: rw 31 +ModInfo.SampRep: rw 31 +ModInfo.SampRepLen: rw 31 +ModInfo.SampVol: rw 31 + +; MODPLAY.ASM +PitchTable: rw 857 +VolTable: rb 16640 +MixBuffer rb MixBufSize + +; MODPLAY.ASM +OrderPos: rb 1 +Tempo: rb 1 +TempoWait: rb 1 +Bpm: rb 1 +Row: rb 1 +BreakRow: rb 1 +BpmSamples: rw 1 +BufPtr: rw 1 +BufLen: rw 1 +BufRep: rw 1 +Note: rd 1 +;Tracks: rb TrackInfo.size*NumTracks +; 13/11/2024 +Tracks: rb sizeof.TrackInfo*NumTracks + +align 16 ; alignb 16 (NASM) + +; PLAY.ASM +Scope: rw 320 +RowOfs: rw 256 + +; 18/02/2017 +_si_: rw 1 +MOD_BUFFER: rb BUFFERSIZE/4 ; 2048 ; 11/05/2024 +EOF: \ No newline at end of file diff --git a/trdos386/programs/16bit/PLAYWAV8.COM b/trdos386/programs/16bit/PLAYWAV8.COM new file mode 100644 index 0000000000000000000000000000000000000000..36d94c86ed08805fe474c29ba6a6d5099244ecae GIT binary patch literal 12956 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 X4%dn$i^vy+i7_K0BBR5jVn+Noyq2>I literal 0 HcmV?d00001 diff --git a/trdos386/programs/16bit/PLAYWAV9.COM b/trdos386/programs/16bit/PLAYWAV9.COM new file mode 100644 index 0000000000000000000000000000000000000000..2a2ccc039620b5eca3ee2de8cc7e4b0436e64251 GIT binary patch literal 7343 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 literal 0 HcmV?d00001 diff --git a/trdos386/programs/16bit/PLAYWAVX.COM b/trdos386/programs/16bit/PLAYWAVX.COM new file mode 100644 index 0000000000000000000000000000000000000000..1487f53962a2d28fd7dca5be30bac2f7e5b6e823 GIT binary patch literal 7291 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 literal 0 HcmV?d00001 diff --git a/trdos386/programs/16bit/ac97play.asm b/trdos386/programs/16bit/ac97play.asm new file mode 100644 index 0000000..171084f --- /dev/null +++ b/trdos386/programs/16bit/ac97play.asm @@ -0,0 +1,6763 @@ +; **************************************************************************** +; ac97play.asm (for Retro DOS) +; ---------------------------------------------------------------------------- +; AC97PLAY.COM ! AC'97 (ICH) .WAV PLAYER program by Erdogan TAN +; +; 28/11/2024 +; +; [ Last Modification: 18/12/2024 ] +; +; Modified from PLAYWAV8.COM .wav player program by Erdogan Tan, 25/11/2024 +; +; Assembler: FASM 1.73 +; fasm ac97play.asm AC97PLAY.COM +; ---------------------------------------------------------------------------- +; In the visualization part of the code, the source code of Matan Alfasi's +; (Ami-Asaf) player.exe program was partially used. +; ---------------------------------------------------------------------------- +; Previous versions of this Wav Player were based in part on .wav file player +; (for DOS) source code written by Jeff Leyla in 2002. + +; playwav8.asm (25/11/2024) + +; TUNELOOP version (playing without AC97 interrupt) - 06/11/2023 - Erdogan Tan +; sample rate conversion version - 18/11/2023 - Erdogan Tan + +; CODE + + ; 13/11/2024 +macro sys_msg op1,op2 +{ ; 30/05/2024 + mov si, op1 ; message + mov bl, op2 ; text color + xor bh, bh ; video page 0 + mov ah, 0Eh + call p_msg +} + +; player internal variables and other equates. +;BUFFERSIZE equ 64 * 1024 ; 64k file buffer size. +; 17/11/2024 +BUFFERSIZE equ 65520 +ENDOFFILE equ 1 ; flag for knowing end of file + +use16 + +org 100h + + include 'ac97.inc' ; 17/02/2017 + +_STARTUP: + ; 30/05/2024 + ; Prints the Credits Text. + sys_msg Credits, 0Bh + + ; 30/05/2024 + call setFree ; deallocate unused DOS mem + + ; 17/02/2017 + ; Clear BSS (uninitialized data) area + xor ax, ax ; 0 + mov cx, (bss_end - bss_start)/2 + mov di, bss_start + rep stosw + + ; Detect (& Enable) AC'97 Audio Device + call DetectAC97 + ;jnc short GetFileName + ; 30/05/2024 + jnc short allocate_memory + + ; 30/05/2024 +_dev_not_ready: + ; couldn't find the audio device! + sys_msg noDevMsg, 0Fh + jmp Exit + + ; 30/05/2024 +allocate_memory: + +; allocate 256 bytes of data for DCM_OUT Buffer Descriptor List. (BDL) + + mov ax, BDL_SIZE / 16 + call memAlloc + mov [BDL_BUFFER], ax ; segment + +; allocate 2 buffers, 64k each for now. + + mov ax, BUFFERSIZE / 16 ; 64k for .WAV file + call memAlloc + mov [WAV_BUFFER1], ax ; segment + + mov ax, BUFFERSIZE / 16 + call memAlloc + mov [WAV_BUFFER2], ax + + ;;; + ; 28/11/2024 +Player_InitalizePSP: + mov si, 81h + mov [PSP_CurrentOffset], si + cmp byte [si], 0Dh ; "CR": No command line parameters + ja short Player_ParseParameters + jmp pmsg_usage + +Player_ParseParameters: + ; 29/11/2024 + ; 18/12/2024 + ;mov dx, wav_file_name + cmp byte [IsInSplash], 0 + jna short check_p_command + + call write_audio_dev_info + + mov dx, SplashFileName + jmp short _1 + +check_p_command: + cmp byte [command], 'P' + je short Player_ParsePreviousParameter + + mov si, [PSP_CurrentOffset] + cmp byte [si], 0Dh + ja short Player_ParseNextParameter +jmp_Player_Quit: + jmp Player_Quit + +Player_ParsePreviousParameter: + ; 29/11/2024 + ;mov byte [command], 0 + + mov si, [PSP_CurrentOffset] + + cmp si, 81h + je short Player_ParseNextParameter + + ;; Search for previous space character + dec si + mov cx, 2 +PSPParsePrev_Search: + dec si + mov al, [si] + cmp al, 20h + jne short PSPParsePrev_Search + + cmp si, 81h + jna PSPParsePrev_Copy + loop PSPParsePrev_Search + +PSPParsePrev_Copy: + mov [PSP_CurrentOffset], si + +Player_ParseNextParameter: + ; 29/11/2024 + call GetFileName + jcxz jmp_Player_Quit + + ; 28/11/2024 + mov dx, wav_file_name + ;;; +_1: + +; open the file + ; open existing file + ; 14/11/2024 + ;mov al, OPEN ; open existing file + ; 28/11/2024 + ;mov dx, wav_file_name + call openFile ; no error? ok. + jnc getwavparms ; 14/11/2024 + + ; 28/11/2024 + cmp byte [IsInSplash], 0 + ja Player_SplashScreen + + ; 29/11/2024 + cmp byte [filecount], 0 + ja short check_p_command + + call ClearScreen + sys_msg Credits, 0Bh + call write_audio_dev_info + +wav_file_open_error: +; file not found! + sys_msg noFileErrMsg, 0Ch +_exit_: + jmp Exit + + ; 29/11/2024 + ; 30/05/2024 +GetFileName: + mov di, wav_file_name + mov si, [PSP_CurrentOffset] + xor cx, cx ; 0 +ScanName: + lodsb + ;test al, al + ;jz short a_4 + ; 29/11/2024 + cmp al, 0Dh + jna short a_4 + cmp al, 20h + je short ScanName ; scan start of name. + stosb + mov ah, 0FFh + ;;; + ; 14/11/2024 + ; (max. path length = 64 bytes for MSDOS ?) (*) + ;xor cx, cx ; 0 + ;;; +a_0: + inc ah +a_1: + ;;; + ; 14/11/2024 + inc cx + ;;; + lodsb + stosb + cmp al, '.' + je short a_0 + ; 29/11/2024 + cmp al, 20h + ;and al, al + ;jnz short a_1 + ;;; + ; 14/11/2024 + jna short a_3 + and ah, ah + jz short a_2 + cmp al, '\' + jne short a_2 + mov ah, 0 +a_2: + cmp cl, 75 ; 64+8+'.'+3 -> offset 75 is the last chr + jb short a_1 + ; 29/11/2024 + sub cx, cx + jmp short a_4 +a_3: + ; 29/11/2024 + dec di + ;;; + or ah, ah ; if period NOT found, + jnz short a_4 ; then add a .WAV extension. +SetExt: + ; 29/11/2024 + ;dec di + mov dword [di], '.WAV' ; ! 64+12 is DOS limit + ; but writing +4 must not + ; destroy the following data + ;mov byte [di+4], 0 ; so, 80 bytes path + 0 is possible here + ; 29/11/2024 + add cx, 4 + add di, 4 +a_4: + mov byte [di], 0 + dec si + mov [PSP_CurrentOffset], si + retn + +getwavparms: + ; 14/11/2024 + call getWAVParameters + jc short _exit_ ; nothing to do + + ; 17/11/2024 + mov bl, 4 + sub bl, byte [WAVE_BlockAlign] + ; = 0 for 16 bit stereo + ; = 2 for 8 bit stereo or 16 bit mono + ; = 3 for 8 bit mono + + shr bl, 1 ; 0 --> 0, 2 --> 1, 3 --> 1 + ; 15/11/2024 + adc bl, 0 ; 3 --> 1 --> 2 + mov byte [fbs_shift], bl ; = 2 mono and 8 bit + ; = 0 stereo and 16 bit + ; = 1 mono or 8 bit + ; 30/05/2024 + call codecConfig ; unmute codec, set rates. + jc init_err + + ; 28/11/2024 + cmp byte [IsInSplash], 0 + jna short Player_Template + + ; 28/11/2024 +Player_SplashScreen: + ; 15/11/2024 + ;; Set video mode to 03h (not necessary) + mov ax, 03h + int 10h + + ; 15/11/2024 + ;; Get the cursor type + mov ah, 03h + int 10h + mov [cursortype], cx ; save + + ; 15/11/2024 + ;; Set the cursor to invisible + mov ah, 01h + mov cx, 2607h + int 10h + + ; 15/11/2024 + ;xor dx, dx + ;call setCursorPosition + + ;; Print the splash screen in white + mov ax, 1300h + mov bx, 000Fh + mov cx, 1999 + mov dx, 0 + + mov bp, SplashScreen + int 10h + ;;; + + ;;; + ; 22/11/2024 + ; set wave volume led addresses + mov bx, 13*80*2 + mov bp, 80 + mov di, wleds_addr +wleds_sa_1: + mov cx, 7 +wleds_sa_2: + mov ax, 80*2 + mul cx + add ax, bx + stosw + loop wleds_sa_2 + mov ax, bx + stosw + inc bx + inc bx + dec bp + jnz short wleds_sa_1 + ;;; + + ; 28/11/2024 + cmp word [filehandle], -1 + jne short StartPlay + + ;;; wait for 3 seconds + mov cx, 002Dh + mov dx, 0C6C0h + mov ah, 86h + int 15h + ;;; + + ; 28/11/2024 + mov byte [IsInSplash], 0 + ;mov dx, wav_file_name + ;jmp _1 + ; 29/11/2024 + jmp Player_ParseNextParameter + + ; 28/11/2024 +Player_Template: + ;;; + ; 09/12/2024 + ; 29/11/2024 + inc byte [filecount] + mov byte [command], 0 + ;;; + + xor dx, dx + call setCursorPosition + + ;; Print the splash screen in white + mov ax, 1300h + mov bx, 000Fh + mov cx, 1999 + ; 09/12/2024 + ; dx = 0 + ;mov dx, 0 + + mov bp, Template + int 10h + ;;; + + ; 14/11/2024 + call SetTotalTime + call UpdateFileInfo + + ; 28/11/2024 +StartPlay: + ; 25/11/2023 + ; ------------------------------------------ + + ; 18/11/2023 (ich_wav4.asm) + ; 13/11/2023 (ich_wav3.asm) + + cmp byte [VRA], 1 + jb short chk_sample_rate + +playwav_48_khz: + mov word [loadfromwavfile], loadFromFile + ;mov word [loadsize], 0 ; 65536 + ;;; + ; 17/11/2024 + ;mov word [buffersize], 32768 + mov ax, BUFFERSIZE/2 ; 32760 + mov [buffersize], ax ; 16 bit samples + shl ax, 1 ; bytes + mov cl, [fbs_shift] + shr ax, cl + mov [loadsize], ax ; 16380 or 32760 or 65520 + ;;; + jmp PlayNow ; 30/05/2024 + +chk_sample_rate: + ; set conversion parameters + ; (for 8, 11.025, 16, 22.050, 24, 32 kHZ) + mov ax, [WAVE_SampleRate] + cmp ax, 48000 + je short playwav_48_khz +chk_22khz: + cmp ax, 22050 + jne short chk_11khz + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_22khz_1 + mov bx, load_22khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_22khz_2 + mov bx, load_22khz_mono_16_bit + jmp short chk_22khz_2 +chk_22khz_1: + mov bx, load_22khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_22khz_2 + mov bx, load_22khz_mono_8_bit +chk_22khz_2: + mov ax, 7514 ; (442*17) + mov dx, 37 + mov cx, 17 + jmp set_sizes +chk_11khz: + cmp ax, 11025 + jne short chk_44khz + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_11khz_1 + mov bx, load_11khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_11khz_2 + mov bx, load_11khz_mono_16_bit + jmp short chk_11khz_2 +chk_11khz_1: + mov bx, load_11khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_11khz_2 + mov bx, load_11khz_mono_8_bit +chk_11khz_2: + mov ax, 3757 ; (221*17) + mov dx, 74 + mov cx, 17 + jmp set_sizes +chk_44khz: + cmp ax, 44100 + jne short chk_16khz + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_44khz_1 + mov bx, load_44khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_44khz_2 + mov bx, load_44khz_mono_16_bit + jmp short chk_44khz_2 +chk_44khz_1: + mov bx, load_44khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_44khz_2 + mov bx, load_44khz_mono_8_bit +chk_44khz_2: + ;mov ax, 15065 ; (655*23) + ; 18/11/2023 ((file size + bss + stack) <= 64KB) + ;mov ax, 14076 ; (612*23) + ; 17/11/2024 + mov ax, 12650 ; (550*23) + mov dx, 25 + mov cx, 23 + jmp set_sizes +chk_16khz: + cmp ax, 16000 + jne short chk_8khz + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_16khz_1 + mov bx, load_16khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_16khz_2 + mov bx, load_16khz_mono_16_bit + jmp short chk_16khz_2 +chk_16khz_1: + mov bx, load_16khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_16khz_2 + mov bx, load_16khz_mono_8_bit +chk_16khz_2: + ;mov ax, 5461 + ; 17/11/2024 + mov ax, 5460 + mov dx, 3 + mov cx, 1 + jmp set_sizes +chk_8khz: + cmp ax, 8000 + jne short chk_24khz + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_8khz_1 + mov bx, load_8khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_8khz_2 + mov bx, load_8khz_mono_16_bit + jmp short chk_8khz_2 +chk_8khz_1: + mov bx, load_8khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_8khz_2 + mov bx, load_8khz_mono_8_bit +chk_8khz_2: + mov ax, 2730 + mov dx, 6 + mov cx, 1 + jmp short set_sizes +chk_24khz: + cmp ax, 24000 + jne short chk_32khz + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_24khz_1 + mov bx, load_24khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_24khz_2 + mov bx, load_24khz_mono_16_bit + jmp short chk_24khz_2 +chk_24khz_1: + mov bx, load_24khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_24khz_2 + mov bx, load_24khz_mono_8_bit +chk_24khz_2: + ;mov ax, 8192 + ; 17/11/2024 + mov ax, 8190 + mov dx, 2 + mov cx, 1 + jmp short set_sizes +chk_32khz: + cmp ax, 32000 + jne short vra_needed + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_32khz_1 + mov bx, load_32khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_32khz_2 + mov bx, load_32khz_mono_16_bit + jmp short chk_32khz_2 +chk_32khz_1: + mov bx, load_32khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_32khz_2 + mov bx, load_32khz_mono_8_bit +chk_32khz_2: + ;mov ax, 10922 + ; 17/11/2024 + mov ax, 10920 + mov dx, 3 + mov cx, 2 + ;jmp short set_sizes +set_sizes: + ;;; + ; 17/11/2024 + push cx + mov cl, 2 + sub cl, [fbs_shift] + ; = 2 for 16 bit stereo + ; = 1 for 16 bit mono or 8 bit stereo + ; = 0 for 8 bit mono + shl ax, cl + pop cx + mov [loadsize], ax ; (one) read count in bytes + ;;; + mul dx + cmp cx, 1 + je short s_2 +s_1: + div cx +s_2: + ;;; + ; ax = byte count of (to be) converted samples + + ; 17/11/2024 + ;;; + mov cl, [fbs_shift] + + shl ax, cl + ; *1 for 16 bit stereo + ; *2 for 16 bit mono or 8 bit stereo + ; *4 for for 8 bit mono + ;;; + + ; ax = 16 bit stereo byte count (target buffer size) + + shr ax, 1 ; buffer size is 16 bit sample count + mov [buffersize], ax + mov [loadfromwavfile], bx + jmp short PlayNow + +vra_needed: + ; 13/11/2023 + pop ax ; discard return address to the caller + ; 30/05/2024 +vra_err: + sys_msg msg_no_vra, 0Fh + jmp Exit + + ; 15/11/2024 + ; 30/05/2024 + ; 13/11/2023 (ich_wav4.asm) +;loadfromwavfile: +; dw loadFromFile +;loadsize: ; read from wav file +; dw 0 +;buffersize: ; write to DMA buffer +; dd 32768 ; 16 bit samples (not bytes) + +PlayNow: + ;;; + ; 14/11/2024 + ;mov al, 3 ; 0 = max, 31 = min + ; 14/12/2024 + mov al, [volume] + call SetPCMOutVolume@ + ; 15/11/2024 + ;;call SetMasterVolume + ;call SetPCMOutVolume + + ; 29/11/2024 + cmp byte [IsInSplash], 0 + ;ja short PlayNow@ + ; 02/12/2024 + jna short PlayNow@ + +;PlayNow@: + ; 28/11/2024 + ;cmp byte [IsInSplash], 0 + ;ja short _3 + ; + ;call UpdateVolume + ; + ; 02/12/2024 + jmp short _3 + + ; 02/12/2024 +PlayNow@: + ; reset file loading and EOF parameters + ;mov word [count], 0 + mov word [LoadedDataBytes], 0 + mov word [LoadedDataBytes+2], 0 + mov byte [flags], 0 + mov byte [stopped], 0 + ;jmp short PlayNow@@ + +PlayNow@@: + ;;; + ; + ; 14/11/2024 + call UpdateProgressBar + ;;; + + ; 30/05/2024 + ; playwav4.asm +_2: + call check4keyboardstop ; flush keyboard buffer + jc short _2 ; 07/11/2023 + +; play the .wav file. Most of the good stuff is in here. + +_3: + call PlayWav + + ; 29/11/2024 + ; 28/11/2024 + call closeFile + ;mov dx, wav_file_name + cmp byte [IsInSplash], 0 + ;jna short Exit + jna short _4 ; 29/11/2024 + mov byte [IsInSplash], 0 + ;jmp _1 + ; 29/11/2024 + jmp Player_ParseNextParameter + + ; 29/11/2024 +_4: + cmp byte [command], 'Q' + je short Exit + jmp check_p_command + +; close the .wav file and exit. + +Exit: + ; 15/11/2024 + ;; Restore Cursor Type + mov cx, [cursortype] + cmp cx, 0 + jz short Exit@ + mov ah, 01h + int 10h +Exit@: + ; 29/11/2024 + ;call closeFile +Exit@@: + mov ax, 4C00h ; bye ! + int 21h +here: + jmp short here ; do not come here ! + + ; 30/05/2024 +pmsg_usage: + sys_msg msg_usage, 0Fh ; 14/11/2024 + jmp short Exit + + ; 30/05/2024 +init_err: + sys_msg msg_init_err, 0Fh + jmp short Exit + + ; 29/11/2024 +Player_Quit: + call ClearScreen + jmp short Exit@@ +ClearScreen: + mov ax, 03h + int 10h + retn + + ; -------------------------------------------- + + ; 29/05/2024 (TRDOS 386, playwav7.s) + ; ((Modified from playwav4.asm, ich_wav4.asm)) + ; ------------------ +;playwav_vra: +PlayWav: + ; create Buffer Descriptor List + + ; Generic Form of Buffer Descriptor + ; --------------------------------- + ; 63 62 61-48 47-32 31-0 + ; --- --- -------- ------- ----- + ; IOC BUP -reserved- Buffer Buffer + ; Length Pointer + ; [15:0] [31:0] + + push es + mov ax, [BDL_BUFFER] ; get segment # for BDL + mov es, ax + + mov cx, 32 / 2 ; make 32 entries in BDL + xor di, di +_0: + movzx eax, word [WAV_BUFFER1] + shl eax, 4 ; convert seg:off ->0:offset + stosd ; store pointer to wavbuffer1 + + ;mov eax, BUFFERSIZE / 2 ; size of buffer (32K) in (16bit) words + ; 13/11/2023 (ich_wav3.asm) - 18/11/2023 (ich_wav4.asm) + mov eax, [buffersize] + + ;or eax, IOC + BUP + ; 06/11/2023 (TUNELOOP version, without interrupt) + or eax, BUP + stosd + + movzx eax, word [WAV_BUFFER2] + shl eax, 4 ; convert seg:off ->0:offset + stosd ; store pointer to wavbuffer2 + + ;mov eax, BUFFERSIZE / 2 ; size of half buffer (32K) + ; 13/11/2023 (ich_wav3.asm) - 18/11/2023 (ich_wav4.asm) + mov eax, [buffersize] + + ;or eax, IOC + BUP + ; 06/11/2023 (TUNELOOP version, without interrupt) + or eax, BUP + stosd + + loop _0 + pop es + + ; 18/12/2024 + mov word [count], cx ; 0 + ; 14/11/2024 + ;mov dword [LoadedDataBytes], 0 + + ; 19/11/2024 +RePlayWav: + + ; load 64k into buffer 1 + mov ax, [WAV_BUFFER1] + ;call loadFromFile + ; 13/11/2023 + call word [loadfromwavfile] + ; 14/11/2024 + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + ; and 64k into buffer 2 + mov ax, [WAV_BUFFER2] + ;call loadFromFile + ; 13/11/2023 + call word [loadfromwavfile] + ; 14/11/2024 + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + ; write NABMBAR+10h with offset of buffer descriptor list + + movzx eax, word [BDL_BUFFER] + shl eax, 4 ; convert seg:off to 0:off + mov dx, [NABMBAR] + add dx, PO_BDBAR_REG ; set pointer to BDL + out dx, eax ; write to AC97 controller + + ; 19/05/2024 + call delay1_4ms + + mov al, 31 + call setLastValidIndex + + ; 19/05/2024 + ;call delay1_4ms + + ; 17/02/2017 + mov dx, [NABMBAR] + add dx, PO_CR_REG ; PCM out Control Register + ;mov al, IOCE + RPBM ; Enable 'Interrupt On Completion' + run + ; ; (LVBI interrupt will not be enabled) + ; 06/11/2023 (TUNELOOP version, without interrupt) + mov al, RPBM + out dx, al ; Start bus master operation. + + ; 19/05/2024 + ; 06/11/2023 + call delay1_4ms ; 30/05/2024 + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + +; while DMA engine is running, examine current index and wait until it hits 1 +; as soon as it's 1, we need to refresh the data in wavbuffer1 with another +; 64k. Likewise when it's playing buffer 2, refresh buffer 1 and repeat. + +; 18/11/2023 +; 08/11/2023 +; 07/11/2023 + + ; 19/11/2024 + mov byte [wleds], 1 + + ;;; + ; 09/12/2024 + mov ax, 10548 ; (48000*10/182)*4 + cmp byte [VRA], 0 + jna short sL0 ; 48kHZ (interpolation) + ; + mov ax, [WAVE_SampleRate] + mov cx, 10 + mul cx + mov cl, 182 + div cx + ; ax = samples per 1/18.2 second + ;mov cl, byte [WAVE_BlockAlign] + ; 09/12/2024 + ;mov cl, 4 ; 16 bit, stereo + ;mul cx + shl ax, 2 ; * 4 +sL0: + mov [wleds_dif], ax ; buffer read differential (distance) + ; for wave volume leds update + ; (byte stream per 1/18.2 second) + ;;; + ; 28/11/2024 + cmp byte [IsInSplash], 0 + jna short tuneLoop + +sL1: + call updateLVI ; /set LVI != CIV/ + jz short sL3 + call getCurrentIndex + test al, BIT0 + jz short sL1 ; loop if buffer 2 is not playing + + ; load buffer 1 + mov ax, [WAV_BUFFER1] + call word [loadfromwavfile] + jc short sL3 +sL2: + call updateLVI + jz short sL3 + call getCurrentIndex + test al, BIT0 + jnz short sL2 ; loop if buffer 1 is not playing + + ; load buffer 2 + mov ax, [WAV_BUFFER2] + call word [loadfromwavfile] + jnc short sL1 +sL3: + mov dx, [NABMBAR] + add dx, PO_CR_REG ; PCM out Control Register + mov al, 0 + out dx, al ; stop player + + ; 29/11/2024 + ;; reset file loading and EOF parameters + ;;mov word [count], 0 + ;mov word [LoadedDataBytes], 0 + ;mov word [LoadedDataBytes+2], 0 + ;mov byte [flags], 0 + + retn + + ; 29/11/2024 +tuneLoop: + ; 30/05/2024 + ; 18/11/2023 (ich_wav4.asm) + ; 08/11/2023 + ; 06/11/2023 + +tLWait: + ; 18/11/2024 + cmp byte [stopped], 0 + ;jna short tL@ + ; 21/11/2024 + ja short tLWait@ + mov al, [tLP] + cmp al, '1' + ja short tL2@ + je short tL1@ + mov al, '1' + mov [tLP], al + jmp short tL1@ +tLWait@: ; 21/11/2024 + ;;; + ; 09/12/2024 + cmp byte [stopped], 3 + jnb _exitt_ + ;;; + call checkUpdateEvents + jc _exitt_ + ;;; + ; 29/11/2024 + cmp byte [command], 'N' + je _exitt_ + cmp byte [command], 'P' + je _exitt_ + ;;; + cmp byte [tLO], '0' + je short tLWait + call tLZ + mov byte [tLO], '0' + jmp short tLWait + +;tLO: db 0 + +tL1@: + ;mov al, '1' + ; 19/11/2024 + mov [tLO], al + call tL0 +tL1: + call updateLVI ; /set LVI != CIV/ + jz short _exitt_ ; 08/11/2023 + ;;; + ;call check4keyboardstop + ; 14/11/2024 + call checkUpdateEvents + jc short _exitt_ + ; 18/11/2024 + cmp byte [stopped], 0 + ja short tLWait@ ; 21/11/2024 + ;;; + call getCurrentIndex + test al, BIT0 + jz short tL1 ; loop if buffer 2 is not playing + + ; load buffer 1 + mov ax, [WAV_BUFFER1] + ;call loadFromFile + ; 18/11/2023 + call word [loadfromwavfile] + jc short _exitt_ ; end of file + + ; 14/11/2024 + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + mov al, '2' + ; 21/11/2024 + mov [tLP], al +tL2@: + ; 19/11/2024 + mov [tLO], al + call tL0 +tL2: + call updateLVI + jz short _exitt_ ; 08/11/2023 + ;;; + ;call check4keyboardstop + ; 14/11/2024 + call checkUpdateEvents + jc short _exitt_ + ; 18/11/2024 + cmp byte [stopped], 0 + ja tLWait@ ; 21/11/2024 + ;;; + call getCurrentIndex + test al, BIT0 + jnz short tL2 ; loop if buffer 1 is not playing + + ; load buffer 2 + mov ax, [WAV_BUFFER2] + ;call loadFromFile + ; 18/11/2023 + call word [loadfromwavfile] + ;jnc short tuneLoop + jc short _exitt_ + + ; 14/11/2024 + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + ; 21/11/2024 + mov byte [tLP], '1' + jmp tuneLoop +_exitt_: + mov dx, [NABMBAR] + add dx, PO_CR_REG ; PCM out Control Register + mov al, 0 + out dx, al ; stop player + + ;;; + ; 14/11/2024 + call UpdateProgressBar + ;;; + + ; 18/11/2024 +tLZ: + ; 30/05/2024 + mov al, '0' + + ;add al, '0' + ;call tL0 + ; + ;retn + ; 06/11/2023 + ;jmp short tL0 + ;retn + + ; 06/11/2023 +tL0: + ; 08/11/2023 + ; 05/11/2023 + ; 17/02/2017 - Buffer switch test (temporary) + ; 06/11/2023 + ; al = buffer indicator ('1', '2' or '0' -stop- ) + + push ds + ;push bx + mov bx, 0B800h ; video display page segment + mov ds, bx + sub bx, bx ; 0 + mov ah, 4Eh + mov [bx], ax ; show current play buffer (1, 2) + ;pop bx + pop ds + + retn + +; ------------------------------------------- + + ; 14/11/2024 +;SetMasterVolume: + ; 15/11/2024 +SetPCMOutVolume: + ;cmp al, 31 + ;ja short setvolume_ok + mov [volume], al ; max = 0, min = 31 +SetPCMOutVolume@: ; 19/11/2024 + mov ah, al + mov dx, [NAMBAR] + ; 15/11/2024 (QEMU) + ;add dx, CODEC_MASTER_VOL_REG + add dx, CODEC_PCM_OUT_REG + out dx, ax +;setvolume_ok: + retn + +; ------------------------------------------- + + ; 30/05/2024 +DetectAC97: +DetectICH: + ; 22/11/2023 + ; 19/11/2023 + ; 01/11/2023 - TRDOS 386 Kernel v2.0.7 + ;; 10/06/2017 + ;; 05/06/2017 + ;; 29/05/2017 + ;; 28/05/2017 + + ; 19/11/2023 + mov si, valid_ids ; address of Valid ICH (AC97) Device IDs + mov cx, valid_id_count +pfd_1: + lodsd + call pciFindDevice + jnc short d_ac97_1 + loop pfd_1 + + ;stc + retn + +d_ac97_1: + ; eax = BUS/DEV/FN + ; 00000000BBBBBBBBDDDDDFFF00000000 + ; edx = DEV/VENDOR + ; DDDDDDDDDDDDDDDDVVVVVVVVVVVVVVVV + + ; playwav4.asm - 19/05/2024 + + mov [bus_dev_fn], eax + mov [dev_vendor], edx + + ; get ICH base address regs for mixer and bus master + + mov al, NAMBAR_REG + call pciRegRead16 ; read PCI registers 10-11 + ;and dx, IO_ADDR_MASK ; mask off BIT0 + ; 19/05/2024 + and dl, 0FEh + + mov [NAMBAR], dx ; save audio mixer base addr + + mov al, NABMBAR_REG + call pciRegRead16 + ;and dx, IO_ADDR_MASK + ; 19/05/2024 + and dl, 0C0h + + mov [NABMBAR], dx ; save bus master base addr + + mov al, AC97_INT_LINE ; Interrupt line register (3Ch) + call pciRegRead8 ; 17/02/2017 + + mov [ac97_int_ln_reg], dl + + ;clc + + retn + +; ---------------------------------- + + ; 14/11/2024 + ; INPUT: ds:dx = file name address + ; OUTPUT: [filehandle] = ; -1 = not open +openFile: + mov ax, 3D00h ; open File for read + int 21h + jnc short _of1 + mov ax, -1 + ; cf = 1 -> not found or access error +_of1: + mov [filehandle], ax + retn + +; ---------------------------------- + +; close the currently open file + + ; 14/11/2024 + ; INPUT: [filehandle] ; -1 = not open + ; OUTPUT: none +closeFile: + cmp word [filehandle], -1 + jz short _cf1 + mov bx, [filehandle] + mov ax, 3E00h + int 21h ; close file +_cf1: + retn + +; ---------------------------------- + + ; 14/11/2024 - Erdogan Tan +getWAVParameters: +; reads WAV file header(s) (44 bytes) from the .wav file. +; entry: none - assumes file is already open +; exit: ax = sample rate (11025, 22050, 44100, 48000) +; cx = number of channels (mono=1, stereo=2) +; dx = bits per sample (8, 16) +; bx = number of bytes per sample (1 to 4) + + mov dx, WAVFILEHEADERbuff + mov bx, [filehandle] + mov cx, 44 ; 44 bytes + mov ah, 3Fh + int 21h + jc short gwavp_retn + + cmp ax, 44 + jb short gwavp_retn + + cmp dword [RIFF_Format], 'WAVE' + jne short gwavp_stc_retn + + cmp word [WAVE_AudioFormat], 1 ; Offset 20, must be 1 (= PCM) + ;jne short gwavp_stc_retn + je short gwavp_retn ; 15/11/2024 + + ; 15/11/2024 + ;mov cx, [WAVE_NumChannels] ; return num of channels in CX + ;mov ax, [WAVE_SampleRate] ; return sample rate in AX + ;mov dx, [WAVE_BitsPerSample] + ; return bits per sample value in DX + ;mov bx, [WAVE_BlockAlign] ; return bytes per sample in BX +;gwavp_retn: + ;retn + +gwavp_stc_retn: + stc +gwavp_retn: + retn + +; ---- 30/05/2024 (playwav4.asm, 19/05/2024) + +; MEMALLOC.ASM +;-- SETFREE: Release memory not used ---------------- +;-- Input : ES = address of PSP +;-- Output : none +;-- Register : AX, BX, CL and FLAGS are changed +;-- Info : Since the stack-segment is always the last segment in an +; EXE-file, ES:0000 points to the beginning and SS:SP +; to the end of the program in memory. Through this the +; length of the program can be calculated +; call this routine once at the beginning of the program to free up memory +; assigned to it by DOS. + +setFree: + mov bx, 65536/16 ; 4K paragraphs ; 17/02/2017 (Erdogan Tan) + + mov ah, 4Ah ; pass new length to DOS + int 21h + + retn ; back to caller + ; new size (allocated memory) = 64KB + +memAlloc: +; input: AX = # of paragraphs required +; output: AX = segment of block to use + + push bx + mov bx, ax + mov ah, 48h + int 21h + pop bx + retn + +; ---- + +; ///// + + ; 30/05/2024 (ich_wav4.asm, 19/05/2024) +loadFromFile: + ; 07/11/2023 + + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff_0 ; no + stc + retn + +lff_0: + ; 08/11/2023 + mov bp, ax ; save buffer segment + + ; 17/11/2024 + mov bx, [filehandle] + + ; 17/11/2024 + mov cx, [loadsize] + xor di, di ; 0 + + ;mov cl, [fbs_shift] + ;and cl, cl + ;jz short lff_1 ; stereo, 16 bit + ; 17/11/2024 + cmp byte [fbs_shift], 0 + jna short lff_1 ; stereo, 16 bit + + ;mov di, BUFFERSIZE - 1 ; 65535 + + ;; fbs_shift = + ;; 2 for mono and 8 bit sample (multiplier = 4) + ;; 1 for mono or 8 bit sample (multiplier = 2) + ;shr di, cl + ;inc di ; 16384 for 8 bit and mono + ; ; 32768 for 8 bit or mono + + ; 17/11/2024 + ;mov cx, [loadsize] ; 16380 or 32760 + + ;mov ax, cs + mov dx, temp_buffer ; temporary buffer for wav data + + ; 17/02/2017 (stereo/mono, 8bit/16bit corrections) + ; load file into memory + ;mov cx, di ; 17/11/2024 + ;mov bx, [filehandle] ; 17/11/2024 + ;mov ds, ax + mov ah, 3Fh + int 21h + + ;mov bx, cs + ;mov ds, bx + ; 17/11/2024 + ;push cs + ;pop ds + + jc lff_4 ; error ! + + ; 14/11/2024 + mov [count], ax + + ; 17/11/2024 + ; 08/11/2023 + ;xor dx, dx ; 0 + + and ax, ax + jz short lff_3 + + mov bl, [fbs_shift] + + push es + ;mov di, dx ; 0 ; [fbs_off] + ; 17/11/2024 + ; di = 0 + ;mov bp, [fbs_seg] ; buffer segment + mov es, bp + mov si, temp_buffer ; temporary buffer address + mov cx, ax ; byte count + cmp byte [WAVE_BitsPerSample], 8 ; bits per sample (8 or 16) + jne short lff_7 ; 16 bit samples + ; 8 bit samples + dec bl ; shift count, 1 = stereo, 2 = mono + jz short lff_6 ; 8 bit, stereo +lff_5: + ; mono & 8 bit + lodsb + sub al, 80h ; 08/11/2023 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; left channel + stosw ; right channel + loop lff_5 + jmp short lff_9 +lff_6: + ; stereo & 8 bit + lodsb + sub al, 80h ; 08/11/2023 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw + loop lff_6 + jmp short lff_9 +lff_7: + shr cx, 1 ; word count +lff_8: + lodsw + stosw ; left channel + stosw ; right channel + loop lff_8 +lff_9: + pop es + + ;or di, di + ;jz short endLFF ; 64KB ok + ;mov ax, di ; [fbs_off] + ;dec ax + ; 17/11/2024 + mov ax, di + ;cmp ax, BUFFERSIZE ; 65520 + ;jnb short endLFF + + ;mov cx, BUFFERSIZE - 1 ; 65535 + ; 17/11/2024 + mov cx, BUFFERSIZE + ; 17/11/2024 + ; ax = di + cmp ax, cx + ;jnb short endLFF + ;jmp short lff_3 + jb short lff_3 + retn + +lff_1: + ;mov bp, ax ; save buffer segment + xor dx, dx + ; load file into memory + ;mov cx, (BUFFERSIZE / 2) ; 32k chunk + + ; 17/11/2024 + ;mov cx, [buffersize] ; BUFFERSIZE / 2 + ; 17/11/2024 (*) + ; cx = [loadsize] = 2*[buffersize] + + ;mov bx, [filehandle] ; 17/11/2024 + mov ds, ax ; mov ds, bp + mov ah, 3Fh + int 21h + + ;mov di, cs + ;mov ds, di + ; 17/11/2024 + push cs + pop ds + + ; 07/11/2023 + jc short lff_4 ; error ! + + ; 14/11/2024 + mov [count], ax + ; 17/11/2024 + ; di = 0 + +; 17/11/2024 (*) +if 0 + cmp ax, cx + jne short lff_3 +lff_2: + ; 08/11/2023 + add dx, ax + ;;mov cx, (BUFFERSIZE / 2) ; 32k chunk + ;mov cx, [buffersize] ; BUFFERSIZE / 2 + ;mov bx, [filehandle] + mov ds, bp + mov ah, 3Fh + int 21h + + ;;mov di, cs + ;mov ds, di + ; 17/11/2024 + push cs + pop ds + + jc short lff_4 ; error ! + + ; 17/11/2024 + ; 14/11/2024 + add [count], ax +end if + + cmp ax, cx + je short endLFF + ; 17/11/2024 + ; di = 0 + mov di, ax +lff_3: + call padfill ; blank pad the remainder + ;clc ; don't exit with CY yet. + or byte [flags], ENDOFFILE ; end of file flag +endLFF: + retn +lff_4: + ; 08/11/2023 + mov al, '!' ; error + call tL0 + + xor ax, ax + jmp short lff_3 + +; entry ds:ax points to last byte in file +; cx = target size +; note: must do byte size fill +; destroys bx, cx +; +padfill: + ; 14/12/2024 + ; 17/11/2024 + ; di = offset (to be filled with ZEROs) + ; bp = buffer segment + ; ax = di = number of bytes loaded + ; cx = buffer size (> loaded bytes) + ; 07/11/2023 + ; 06/11/2023 + ; 17/02/2017 + push es + ;push di + ;mov di, [fbs_seg] + ;mov es, di + mov es, bp + sub cx, ax + ; 08/11/2023 + ;mov di, ax ; (wrong) + ; 17/11/2024 + ;mov di, dx ; buffer offset + ;add di, ax + ; 07/11/2023 + ;add di, [fbs_off] + ; 25/11/2024 + xor ax, ax + ; 14/12/2024 + rep stosb + ;mov [fbs_off], di + ;pop di + pop es + retn +; ///// + +write_audio_dev_info: + ; 30/05/2024 + sys_msg msgAudioCardInfo, 0Fh + retn + +write_ac97_pci_dev_info: + ; 19/11/2024 + ; 30/05/2024 + ; 06/06/2017 + ; 03/06/2017 + ; BUS/DEV/FN + ; 00000000BBBBBBBBDDDDDFFF00000000 + ; DEV/VENDOR + ; DDDDDDDDDDDDDDDDVVVVVVVVVVVVVVVV + + mov eax, [dev_vendor] + xor bh, bh + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgVendorId+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgVendorId+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgVendorId+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgVendorId], al + shr eax, 16 + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgDevId+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgDevId+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgDevId+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgDevId], al + + mov eax, [bus_dev_fn] + shr eax, 8 + mov bl, al + mov dl, bl + and bl, 7 ; bit 0,1,2 + mov al, [bx+hex_chars] + mov [msgFncNo+1], al + mov bl, dl + shr bl, 3 + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgDevNo+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgDevNo], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgBusNo+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgBusNo], al + + ;mov ax, [ac97_NamBar] + mov ax, [NAMBAR] + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgNamBar+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgNamBar+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgNamBar+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgNamBar], al + + ;mov ax, [ac97_NabmBar] + mov ax, [NABMBAR] + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgNabmBar+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgNabmBar+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgNabmBar+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgNabmBar], al + + xor eax, eax + mov al, [ac97_int_ln_reg] + mov cl, 10 + div cl + ; 23/11/2024 + ;add [msgIRQ], ax + add ax, 3030h + mov [msgIRQ], ax + ;and al, al + cmp al, 30h + jnz short _w_ac97imsg_ + mov al, byte [msgIRQ+1] + mov ah, ' ' + mov [msgIRQ], ax +_w_ac97imsg_: + ; 19/11/2024 + call clear_window + mov dh, 13 + mov dl, 0 + call setCursorPosition + ;;; + ; 30/05/2024 + sys_msg msgAC97Info, 07h + + ; 19/11/2024 + ;retn + + ; 30/05/2024 +write_VRA_info: + sys_msg msgVRAheader, 07h + cmp byte [VRA], 0 + jna short _w_VRAi_no +_w_VRAi_yes: + sys_msg msgVRAyes, 07h + retn +_w_VRAi_no: + sys_msg msgVRAno, 07h + retn + +; 30/05/2024 (playwav6.asm) +; 18/11/2023 (ich_wav3.asm & ich_wav4.asm) +; 15/11/2023 (ich_wav3.asm) +; 14/11/2023 +; 13/11/2023 - Erdogan Tan - (VRA, sample rate conversion) +; -------------------------------------------------------- + +;;Note: At the end of every buffer load, +;; during buffer switch/swap, there will be discontinuity +;; between the last converted sample and the 1st sample +;; of the next buffer. +;; (like as a dot noises vaguely between normal sound samples) +;; -To avoid this defect, the 1st sample of +;; the next buffer may be read from the wav file but +;; the file pointer would need to be set to 1 sample back +;; again via seek system call. Time comsumption problem! - +;; +;; Erdogan Tan - 15/11/2023 +;; +;; ((If entire wav data would be loaded at once.. conversion +;; defect/noise would disappear.. but for DOS, to keep +;; 64KB buffer limit is important also it is important +;; for running under 1MB barrier without HIMEM.SYS or DPMI. +;; I have tested this program by using 2-30MB wav files.)) +;; +;; Test Computer: ASUS desktop/mainboard, M2N4-SLI, 2010. +;; AMD Athlon 64 X2 2200 MHZ CPU. +;; NFORCE4 (CK804) AC97 audio hardware. +;; Realtek ALC850 codec. +;; Retro DOS v4.2 (MSDOS 6.22) operating system. + +load_8khz_mono_8_bit: + ; 15/11/2023 + ; 14/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff8m_0 ; no + stc + retn + +lff8m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + ;jc short lff8m_5 ; error ! + ; 14/11/2023 + jnc short lff8m_6 + jmp lff8m_5 + +lff8m_6: + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + and ax, ax + ;jz short lff8m_3 + ; 15/11/2023 + jz short lff8_eof + + mov cx, ax ; byte count +lff8m_1: + lodsb + mov [previous_val], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (left channel) + stosw ; original sample (right channel) + ;xor ax, ax + ; 14/11/2023 + mov al, 80h + dec cx + jz short lff8m_2 + mov al, [si] +lff8m_2: + ;mov [next_val], ax + mov bh, al ; [next_val] + mov ah, [previous_val] + add al, ah ; [previous_val] + rcr al, 1 + mov dl, al ; this is interpolated middle (3th) sample + add al, ah ; [previous_val] + rcr al, 1 + mov bl, al ; this is temporary interpolation value + add al, ah ; [previous_val] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (L) + stosw ; this is 1st interpolated sample (R) + mov al, bl + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (L) + stosw ; this is 2nd interpolated sample (R) + mov al, dl + sub al, 80h + shl ax, 8 + stosw ; this is middle (3th) interpolated sample (L) + stosw ; this is middle (3th) interpolated sample (R) + ;mov al, [next_val] + mov al, bh + add al, dl + rcr al, 1 + mov bl, al ; this is temporary interpolation value + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 4th interpolated sample (L) + stosw ; this is 4th interpolated sample (R) + ;mov al, [next_val] + mov al, bh + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 5th interpolated sample (L) + stosw ; this is 5th interpolated sample (R) + ; 8 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff8m_1 + + ; -------------- + +lff8s_3: +lff8m_3: +lff8s2_3: +lff8m2_3: +lff16s_3: +lff16m_3: +lff16s2_3: +lff16m2_3: +lff24_3: +lff32_3: +lff44_3: +lff22_3: +lff11_3: + mov cx, [buffersize] ; 16 bit (48 kHZ, stereo) sample size + shl cx, 1 ; byte count + sub cx, di + jna short lff8m_4 + ;inc cx + shr cx, 1 + xor ax, ax ; fill (remain part of) buffer with zeros + rep stosw +lff8m_4: + push cs + pop es + retn + +lff8_eof: +lff16_eof: +lff24_eof: +lff32_eof: +lff44_eof: +lff22_eof: +lff11_eof: + ; 15/11/2023 + mov byte [flags], ENDOFFILE + jmp short lff8m_3 + +lff8s_5: +lff8m_5: +lff8s2_5: +lff8m2_5: +lff16s_5: +lff16m_5: +lff16s2_5: +lff16m2_5: +lff24_5: +lff32_5: +lff44_5: +lff22_5: +lff11_5: + mov al, '!' ; error + call tL0 + + ;jmp short lff8m_3 + ; 15/11/2023 + jmp lff8_eof + + ; -------------- + +load_8khz_stereo_8_bit: + ; 15/11/2023 + ; 14/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff8s_0 ; no + stc + retn + +lff8s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff8s_5 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;;and ax, ax + ;jz short lff8s_3 + ; 15/11/2023 + jz short lff8_eof + + mov cx, ax ; word count +lff8s_1: + lodsb + mov [previous_val_l], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + lodsb + mov [previous_val_r], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + + ;xor ax, ax + ; 14/11/2023 + mov ax, 8080h + dec cx + jz short lff8s_2 + ; convert 8 bit sample to 16 bit sample + mov ax, [si] +lff8s_2: + mov [next_val_l], al + mov [next_val_r], ah + mov ah, [previous_val_l] + add al, ah + rcr al, 1 + mov dl, al ; this is interpolated middle (3th) sample (L) + add al, ah + rcr al, 1 + mov bl, al ; this is temporary interpolation value (L) + add al, ah + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (L) + mov al, [next_val_r] + mov ah, [previous_val_r] + add al, ah + rcr al, 1 + mov dh, al ; this is interpolated middle (3th) sample (R) + add al, ah + rcr al, 1 + mov bh, al ; this is temporary interpolation value (R) + add al, ah + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (R) + mov al, bl + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (L) + mov al, bh + add al, dh + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (R) + mov al, dl + sub al, 80h + shl ax, 8 + stosw ; this is middle (3th) interpolated sample (L) + mov al, dh + sub al, 80h + shl ax, 8 + stosw ; this is middle (3th) interpolated sample (R) + mov al, [next_val_l] + add al, dl + rcr al, 1 + mov bl, al ; this is temporary interpolation value (L) + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 4th interpolated sample (L) + mov al, [next_val_r] + add al, dh + rcr al, 1 + mov bh, al ; this is temporary interpolation value (R) + add al, dh + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 4th interpolated sample (R) + mov al, [next_val_l] + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 5th interpolated sample (L) + mov al, [next_val_r] + add al, bh + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 5th interpolated sample (R) + ; 8 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + jcxz lff8s_6 + jmp lff8s_1 +lff8s_6: + jmp lff8s_3 + +load_8khz_mono_16_bit: + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff8m2_0 ; no + stc + retn + +lff8m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff8m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff8m2_8 + ;jmp lff8m2_3 + ; 15/11/2023 + jmp lff8_eof + +lff8m2_8: + mov cx, ax ; word count +lff8m2_1: + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + add ah, 80h ; convert sound level to 0-65535 format + mov [previous_val], ax + xor ax, ax + dec cx + jz short lff8m2_2 + mov ax, [si] +lff8m2_2: + add ah, 80h ; convert sound level to 0-65535 format + mov bp, ax ; [next_val] + add ax, [previous_val] + rcr ax, 1 + mov dx, ax ; this is interpolated middle (3th) sample + add ax, [previous_val] + rcr ax, 1 ; this is temporary interpolation value + mov bx, ax + add ax, [previous_val] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (L) + stosw ; this is 1st interpolated sample (R) + mov ax, bx + add ax, dx + rcr ax, 1 + sub ah, 80h + stosw ; this is 2nd interpolated sample (L) + stosw ; this is 2nd interpolated sample (R) + mov ax, dx + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is middle (3th) interpolated sample (L) + stosw ; this is middle (3th) interpolated sample (R) + mov ax, bp + add ax, dx + rcr ax, 1 + mov bx, ax ; this is temporary interpolation value + add ax, dx + rcr ax, 1 + sub ah, 80h + stosw ; this is 4th interpolated sample (L) + stosw ; this is 4th interpolated sample (R) + mov ax, bp + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 5th interpolated sample (L) + stosw ; this is 5th interpolated sample (R) + ; 8 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff8m2_1 + jmp lff8m2_3 + +lff8m2_7: +lff8s2_7: + jmp lff8m2_5 ; error + +load_8khz_stereo_16_bit: + ; 16/11/2023 + ; 15/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff8s2_0 ; no + stc + retn + +lff8s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff8s2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; 16/11/2023 + ;and ax, ax + jnz short lff8s2_8 + ;jmp lff8s2_3 + ; 15/11/2023 + jmp lff8_eof + +lff8s2_8: + mov cx, ax ; dword count +lff8s2_1: + lodsw + stosw ; original sample (L) + ; 15/11/2023 + add ah, 80h ; convert sound level to 0-65535 format + mov [previous_val_l], ax + lodsw + stosw ; original sample (R) + add ah, 80h ; convert sound level to 0-65535 format + mov [previous_val_r], ax + xor dx, dx + xor ax, ax + ; 16/11/2023 + dec cx + jz short lff8s2_2 + mov ax, [si] + mov dx, [si+2] +lff8s2_2: + add ah, 80h ; convert sound level to 0-65535 format + mov [next_val_l], ax + add dh, 80h ; convert sound level to 0-65535 format + mov [next_val_r], dx + add ax, [previous_val_l] + rcr ax, 1 + mov dx, ax ; this is interpolated middle (3th) sample (L) + add ax, [previous_val_l] + rcr ax, 1 + mov bx, ax ; this is temporary interpolation value (L) + add ax, [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (L) + mov ax, [next_val_r] + add ax, [previous_val_r] + rcr ax, 1 + mov bp, ax ; this is interpolated middle (3th) sample (R) + add ax, [previous_val_r] + rcr ax, 1 + push ax ; * ; this is temporary interpolation value (R) + add ax, [previous_val_r] + rcr ax, 1 + sub ah, 80h + stosw ; this is 1st interpolated sample (R) + mov ax, bx + add ax, dx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 2nd interpolated sample (L) + pop ax ; * + add ax, bp + rcr ax, 1 + sub ah, 80h + stosw ; this is 2nd interpolated sample (R) + mov ax, dx + sub ah, 80h + stosw ; this is middle (3th) interpolated sample (L) + mov ax, bp + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is middle (3th) interpolated sample (R) + mov ax, [next_val_l] + add ax, dx + rcr ax, 1 + mov bx, ax ; this is temporary interpolation value (L) + add ax, dx + rcr ax, 1 + sub ah, 80h + stosw ; this is 4th interpolated sample (L) + mov ax, [next_val_r] + add ax, bp + rcr ax, 1 + push ax ; ** ; this is temporary interpolation value (R) + add ax, bp + rcr ax, 1 + sub ah, 80h + stosw ; this is 4th interpolated sample (R) + mov ax, [next_val_l] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 5th interpolated sample (L) + pop ax ; ** + add ax, [next_val_r] + rcr ax, 1 + sub ah, 80h + stosw ; this is 5th interpolated sample (R) + ; 8 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + jcxz lff8_s2_9 + jmp lff8s2_1 +lff8_s2_9: + jmp lff8s2_3 + +; ..................... + +load_16khz_mono_8_bit: + ; 14/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff16m_0 ; no + stc + retn + +lff16m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff16m_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff16m_8 + ;jmp lff16m_3 + ; 15/11/2023 + jmp lff16_eof + +lff16m_8: + mov cx, ax ; byte count +lff16m_1: + lodsb + ;mov [previous_val], al + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (left channel) + stosw ; original sample (right channel) + ;xor ax, ax + ; 14/11/22023 + mov al, 80h + dec cx + jz short lff16m_2 + mov al, [si] +lff16m_2: + ;mov [next_val], al + mov bh, al + ;add al, [previous_val] + add al, bl + rcr al, 1 + mov dl, al ; this is interpolated middle (temp) sample + ;add al, [previous_val] + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (L) + stosw ; this is 1st interpolated sample (R) + ;mov al, [next_val] + mov al, bh + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (L) + stosw ; this is 2nd interpolated sample (R) + + ; 16 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff16m_1 + jmp lff16m_3 + +lff16m_7: +lff16s_7: + jmp lff16m_5 ; error + +load_16khz_stereo_8_bit: + ; 14/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff16s_0 ; no + stc + retn + +lff16s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff16s_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff16s_8 + ;jmp lff16s_3 + ; 15/11/2023 + jmp lff16_eof + +lff16s_8: + mov cx, ax ; word count +lff16s_1: + lodsb + mov [previous_val_l], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + lodsb + mov [previous_val_r], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + + ;xor ax, ax + ; 14/11/2023 + mov ax, 8080h + dec cx + jz short lff16s_2 + ; convert 8 bit sample to 16 bit sample + mov ax, [si] +lff16s_2: + ;mov [next_val_l], al + ;mov [next_val_r], ah + mov bx, ax + add al, [previous_val_l] + rcr al, 1 + mov dl, al ; this is temporary interpolation value (L) + add al, [previous_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (L) + mov al, bh ; [next_val_r] + add al, [previous_val_r] + rcr al, 1 + mov dh, al ; this is temporary interpolation value (R) + add al, [previous_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (R) + mov al, dl + add al, bl ; [next_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (L) + mov al, dh + add al, bh ; [next_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (R) + + ; 16 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff16s_1 + jmp lff16s_3 + +load_16khz_mono_16_bit: + ; 15/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff16m2_0 ; no + stc + retn + +lff16m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff16m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff16m2_8 + ;jmp lff16m2_3 + ; 15/11/2023 + jmp lff16_eof + +lff16m2_8: + mov cx, ax ; word count +lff16m2_1: + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val], ax + mov bx, ax + xor ax, ax + dec cx + jz short lff16m2_2 + mov ax, [si] +lff16m2_2: + add ah, 80h ; convert sound level 0 to 65535 format + mov bp, ax ; [next_val] + ;add ax, [previous_val] + add ax, bx + rcr ax, 1 + mov dx, ax ; this is temporary interpolation value + ;add ax, [previous_val] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (L) + stosw ; this is 1st interpolated sample (R) + mov ax, bp + add ax, dx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 2nd interpolated sample (L) + stosw ; this is 2nd interpolated sample (R) + ; 16 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff16m2_1 + jmp lff16m2_3 + +lff16m2_7: +lff16s2_7: + jmp lff16m2_5 ; error + +load_16khz_stereo_16_bit: + ; 16/11/2023 + ; 15/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff16s2_0 ; no + stc + retn + +lff16s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff16s2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + ;shr ax, 1 + shr ax, 2 ; 16/11/2023 + ;and ax, ax + jnz short lff16s2_8 + ;jmp lff16s2_3 + ; 15/11/2023 + jmp lff16_eof + +lff16s2_8: + mov cx, ax ; dword count +lff16s2_1: + lodsw + stosw ; original sample (L) + add ah, 80h ; convert sound level 0 to 65535 format + mov [previous_val_l], ax + lodsw + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + mov [previous_val_r], ax + xor dx, dx + xor ax, ax + ; 16/11/2023 + dec cx + jz short lff16s2_2 + mov ax, [si] + mov dx, [si+2] +lff16s2_2: + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [next_val_l], ax + mov bp, ax + add dh, 80h ; convert sound level 0 to 65535 format + mov [next_val_r], dx + add ax, [previous_val_l] + rcr ax, 1 + mov dx, ax ; this is temporary interpolation value (L) + add ax, [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (L) + mov ax, [next_val_r] + add ax, [previous_val_r] + rcr ax, 1 + mov bx, ax ; this is temporary interpolation value (R) + add ax, [previous_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (R) + ;mov ax, [next_val_l] + mov ax, bp + add ax, dx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 2nd interpolated sample (L) + mov ax, [next_val_r] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 2nd interpolated sample (R) + + ; 16 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff16s2_1 + jmp lff16s2_3 + +; ..................... + +load_24khz_mono_8_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff24m_0 ; no + stc + retn + +lff24m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff24m_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff24m_8 + jmp lff24_eof + +lff24m_8: + mov cx, ax ; byte count +lff24m_1: + lodsb + ;mov [previous_val], al + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (left channel) + stosw ; original sample (right channel) + ;xor ax, ax + mov al, 80h + dec cx + jz short lff24m_2 + mov al, [si] +lff24m_2: + ;;mov [next_val], al + ;mov bh, al + ;add al, [previous_val] + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (L) + stosw ; this is interpolated sample (R) + + ; 24 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff24m_1 + jmp lff24_3 + +lff24m_7: +lff24s_7: + jmp lff24_5 ; error + +load_24khz_stereo_8_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff24s_0 ; no + stc + retn + +lff24s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff24s_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff24s_8 + jmp lff24_eof + +lff24s_8: + mov cx, ax ; word count +lff24s_1: + lodsb + mov [previous_val_l], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + lodsb + mov [previous_val_r], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + + ;xor ax, ax + mov ax, 8080h + dec cx + jz short lff24s_2 + ; convert 8 bit sample to 16 bit sample + mov ax, [si] +lff24s_2: + ;;mov [next_val_l], al + ;;mov [next_val_r], ah + ;mov bx, ax + mov bh, ah + add al, [previous_val_l] + rcr al, 1 + ;mov dl, al + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (L) + mov al, bh ; [next_val_r] + add al, [previous_val_r] + rcr al, 1 + ;mov dh, al + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (R) + + ; 24 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff24s_1 + jmp lff24_3 + +load_24khz_mono_16_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff24m2_0 ; no + stc + retn + +lff24m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff24m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff24m2_8 + jmp lff24_eof + +lff24m2_8: + mov cx, ax ; word count +lff24m2_1: + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val], ax + ;mov bx, ax + ;xor ax, ax + xor bx, bx + dec cx + jz short lff24m2_2 + ;mov ax, [si + mov bx, [si] +lff24m2_2: + ;add ah, 80h ; convert sound level 0 to 65535 format + ;mov bp, ax ; [next_val] + ;add ax, [previous_val] + ; ax = [previous_val] + ; bx = [next_val] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (L) + stosw ; this is interpolated sample (R) + ; 24 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff24m2_1 + jmp lff24_3 + +lff24m2_7: +lff24s2_7: + jmp lff24_5 ; error + +load_24khz_stereo_16_bit: + ; 16/11/2023 + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff24s2_0 ; no + stc + retn + +lff24s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff24s2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + ;shr ax, 1 + shr ax, 2 ; 16/11/2023 + ;and ax, ax + jnz short lff24s2_8 + jmp lff24_eof + +lff24s2_8: + mov cx, ax ; dword count +lff24s2_1: + lodsw + stosw ; original sample (L) + add ah, 80h ; convert sound level 0 to 65535 format + mov [previous_val_l], ax + lodsw + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val_r], ax + mov bx, ax + xor dx, dx + xor ax, ax + ; 16/11/2023 + dec cx + jz short lff24s2_2 + mov ax, [si] + mov dx, [si+2] +lff24s2_2: + add ah, 80h ; convert sound level 0 to 65535 format + ;;mov [next_val_l], ax + ;mov bp, ax + add dh, 80h ; convert sound level 0 to 65535 format + ;mov [next_val_r], dx + add ax, [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (L) + ;mov ax, [next_val_r] + mov ax, dx + ;add ax, [previous_val_r] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (R) + + ; 24 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff24s2_1 + jmp lff24_3 + +; ..................... + +load_32khz_mono_8_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff32m_0 ; no + stc + retn + +lff32m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff32m_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff32m_8 + jmp lff32_eof + +lff32m_8: + mov cx, ax ; byte count +lff32m_1: + lodsb + ;mov [previous_val], al + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (left channel) + stosw ; original sample (right channel) + ;xor ax, ax + mov al, 80h + dec cx + jz short lff32m_2 + mov al, [si] +lff32m_2: + ;;mov [next_val], al + ;mov bh, al + ;add al, [previous_val] + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (L) + stosw ; this is interpolated sample (R) + + ; different than 8-16-24 kHZ ! + ; 'original-interpolated-original' trio samples + jcxz lff32m_3 + + lodsb + sub al, 80h + shl ax, 8 + stosw ; original sample (left channel) + stosw ; original sample (right channel) + + ; 32 kHZ mono to 48 kHZ stereo conversion of the sample is OK + dec cx + jnz short lff32m_1 +lff32m_3: + jmp lff32_3 + +lff32m_7: +lff32s_7: + jmp lff32_5 ; error + +load_32khz_stereo_8_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff32s_0 ; no + stc + retn + +lff32s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff32s_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff32s_8 + jmp lff32_eof + +lff32s_8: + mov cx, ax ; word count +lff32s_1: + lodsb + mov [previous_val_l], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + lodsb + mov [previous_val_r], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + + ;xor ax, ax + mov ax, 8080h + dec cx + jz short lff32s_2 + ; convert 8 bit sample to 16 bit sample + mov ax, [si] +lff32s_2: + ;;mov [next_val_l], al + ;;mov [next_val_r], ah + ;mov bx, ax + mov bh, ah + add al, [previous_val_l] + rcr al, 1 + ;mov dl, al + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (L) + mov al, bh ; [next_val_r] + add al, [previous_val_r] + rcr al, 1 + ;mov dh, al + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (R) + + ; different than 8-16-24 kHZ ! + ; 'original-interpolated-original' trio samples + jcxz lff32s_3 + + lodsb + sub al, 80h + shl ax, 8 + stosw ; original sample (left channel) + + lodsb + sub al, 80h + shl ax, 8 + stosw ; original sample (right channel) + + ; 32 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + dec cx + jnz short lff32s_1 +lff32s_3: + jmp lff32_3 + +load_32khz_mono_16_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff32m2_0 ; no + stc + retn + +lff32m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff32m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff32m2_8 + jmp lff32_eof + +lff32m2_8: + mov cx, ax ; word count +lff32m2_1: + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val], ax + ;mov bx, ax + ;xor ax, ax + xor bx, bx + dec cx + jz short lff32m2_2 + ;mov ax, [si + mov bx, [si] +lff32m2_2: + ;add ah, 80h ; convert sound level 0 to 65535 format + ;mov bp, ax ; [next_val] + ;add ax, [previous_val] + ; ax = [previous_val] + ; bx = [next_val] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (L) + stosw ; this is interpolated sample (R) + + ; different than 8-16-24 kHZ ! + ; 'original-interpolated-original' trio samples + jcxz lff32m2_3 + + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + + ; 32 kHZ mono to 48 kHZ stereo conversion of the sample is OK + dec cx + jnz short lff32m2_1 +lff32m2_3: + jmp lff32_3 + +lff32m2_7: +lff32s2_7: + jmp lff32_5 ; error + +load_32khz_stereo_16_bit: + ;16/11/2023 + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff32s2_0 ; no + stc + retn + +lff32s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff32s2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; 16/11/2023 (word left ch + word right ch) + ;and ax, ax + jnz short lff32s2_8 + jmp lff32_eof + +lff32s2_8: + mov cx, ax ; dword count +lff32s2_1: + lodsw + stosw ; original sample (L) + add ah, 80h ; convert sound level 0 to 65535 format + mov [previous_val_l], ax + lodsw + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val_r], ax + mov bx, ax + xor dx, dx + xor ax, ax + ; 16/11/2023 + dec cx + jz short lff32s2_2 + mov ax, [si] + mov dx, [si+2] +lff32s2_2: + add ah, 80h ; convert sound level 0 to 65535 format + ;;mov [next_val_l], ax + ;mov bp, ax + add dh, 80h ; convert sound level 0 to 65535 format + ;mov [next_val_r], dx + add ax, [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (L) + ;mov ax, [next_val_r] + mov ax, dx + ;add ax, [previous_val_r] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (R) + + ; different than 8-16-24 kHZ ! + ; 'original-interpolated-original' trio samples + jcxz lff32s2_3 + + lodsw + stosw ; original sample (L) + lodsw + stosw ; original sample (R) + + ; 32 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + dec cx + jnz short lff32s2_1 +lff32s2_3: + jmp lff32_3 + +; ..................... + +load_22khz_mono_8_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff22m_0 ; no + stc + retn + +lff22m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff22m_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff22m_8 + jmp lff22_eof + +lff22m_8: + mov cx, ax ; byte count +lff22m_9: + mov bp, 5 ; interpolation (one step) loop count + mov byte [faz], 3 ; 3 steps/phases +lff22m_1: + ; 3:2:2:2:2:2::3:2:2:2:2::3:2:2:2:2:2 ; 37/17 + lodsb + mov dl, 80h + dec cx + jz short lff22m_2_1 + mov dl, [si] +lff22m_2_1: + ; al = [previous_val] + ; dl = [next_val] + call interpolating_3_8bit_mono ; 1 of 17 + jcxz lff22m_3 +lff22m_2_2: + lodsb + mov dl, 80h + dec cx + jz short lff22m_2_3 + mov dl, [si] +lff22m_2_3: + call interpolating_2_8bit_mono ; 2 of 17 .. 6 of 17 + jcxz lff22m_3 + dec bp + jnz short lff22m_2_2 + + mov al, [faz] + dec al + jz short lff22m_9 + dec byte [faz] + mov bp, 4 + dec al + jnz short lff22m_1 ; 3:2:2:2:2 ; 7-11 of 17 + inc bp ; 5 + jmp short lff22m_1 ; 3:2:2:2:2:2 ; 12-17 of 17 + +lff22m_3: +lff22s_3: + jmp lff22_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff22m_7: +lff22s_7: + jmp lff22_5 ; error + +load_22khz_stereo_8_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff22s_0 ; no + stc + retn + +lff22s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff22s_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff22s_8 + jmp lff22_eof + +lff22s_8: + mov cx, ax ; word count +lff22s_9: + mov bp, 5 ; interpolation (one step) loop count + mov byte [faz], 3 ; 3 steps/phase +lff22s_1: + ; 3:2:2:2:2:2::3:2:2:2:2::3:2:2:2:2:2 ; 37/17 + lodsw + mov dx, 8080h + dec cx + jz short lff22s_2_1 + mov dx, [si] +lff22s_2_1: + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dl = [next_val_r] + call interpolating_3_8bit_stereo ; 1 of 17 + jcxz lff22s_3 +lff22s_2_2: + lodsw + mov dx, 8080h + dec cx + jz short lff22s_2_3 + mov dx, [si] +lff22s_2_3: + call interpolating_2_8bit_stereo ; 2 of 17 .. 6 of 17 + jcxz lff22s_3 + dec bp + jnz short lff22s_2_2 + + mov al, [faz] + dec al + jz short lff22s_9 + dec byte [faz] + mov bp, 4 + dec al + jnz short lff22s_1 ; 3:2:2:2:2 ; 7-11 of 17 + inc bp ; 5 + jmp short lff22s_1 ; 3:2:2:2:2:2 ; 12-17 of 17 + +load_22khz_mono_16_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff22m2_0 ; no + stc + retn + +lff22m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff22m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff22m2_8 + jmp lff22_eof + +lff22m2_8: + mov cx, ax ; word count +lff22m2_9: + mov bp, 5 ; interpolation (one step) loop count + mov byte [faz], 3 ; 3 steps/phases +lff22m2_1: + ; 3:2:2:2:2:2::3:2:2:2:2::3:2:2:2:2:2 ; 37/17 + lodsw + xor dx, dx + dec cx + jz short lff22m2_2_1 + mov dx, [si] +lff22m2_2_1: + ; ax = [previous_val] + ; dx = [next_val] + call interpolating_3_16bit_mono ; 1 of 17 + jcxz lff22m2_3 +lff22m2_2_2: + lodsw + xor dx, dx + dec cx + jz short lff22m2_2_3 + mov dx, [si] +lff22m2_2_3: + call interpolating_2_16bit_mono ; 2 of 17 .. 6 of 17 + jcxz lff22m2_3 + dec bp + jnz short lff22m2_2_2 + + mov al, [faz] + dec al + jz short lff22m2_9 + dec byte [faz] + mov bp, 4 + dec al + jnz short lff22m2_1 ; 3:2:2:2:2 ; 7-11 of 17 + inc bp ; 5 + jmp short lff22m2_1 ; 3:2:2:2:2:2 ; 12-17 of 17 + +lff22m2_3: +lff22s2_3: + jmp lff22_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff22m2_7: +lff22s2_7: + jmp lff22_5 ; error + +load_22khz_stereo_16_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff22s2_0 ; no + stc + retn + +lff22s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff22s2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; dword (left chan word + right chan word) + ;and ax, ax + jnz short lff22s2_8 + jmp lff22_eof + +lff22s2_8: + mov cx, ax ; dword count +lff22s2_9: + mov bp, 5 ; interpolation (one step) loop count + mov byte [faz], 3 ; 3 steps/phase +lff22s2_1: + ; 3:2:2:2:2:2::3:2:2:2:2::3:2:2:2:2:2 ; 37/17 + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + dec cx + jnz short lff22s2_2_1 + xor dx, dx ; 0 + mov [next_val_l], dx +lff22s2_2_1: + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + call interpolating_3_16bit_stereo ; 1 of 17 + jcxz lff22s2_3 +lff22s2_2_2: + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + dec cx + jnz short lff22s2_2_3 + xor dx, dx ; 0 + mov [next_val_l], dx +lff22s2_2_3: + call interpolating_2_16bit_stereo ; 2 of 17 .. 6 of 17 + jcxz lff22s2_3 + dec bp + jnz short lff22s2_2_2 + + mov al, [faz] + dec al + jz short lff22s2_9 + dec byte [faz] + mov bp, 4 + dec al + jnz short lff22s2_1 ; 3:2:2:2:2 ; 7-11 of 17 + inc bp ; 5 + jmp short lff22s2_1 ; 3:2:2:2:2:2 ; 12-17 of 17 + +; ..................... + +load_11khz_mono_8_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff11m_0 ; no + stc + retn + +lff11m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff11m_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff11m_8 + jmp lff11_eof + +lff11m_8: + mov cx, ax ; byte count +lff11m_9: + mov bp, 6 ; interpolation (one step) loop count +lff11m_1: + ; 5:4:4::5:4:4::5:4:4::5:4:4::5:4:4::5:4 ; 74/17 + lodsb + mov dl, 80h + dec cx + jz short lff11m_2_1 + mov dl, [si] +lff11m_2_1: + ; al = [previous_val] + ; dl = [next_val] + call interpolating_5_8bit_mono + jcxz lff11m_3 +lff11m_2_2: + lodsb + mov dl, 80h + dec cx + jz short lff11m_2_3 + mov dl, [si] +lff11m_2_3: + call interpolating_4_8bit_mono + jcxz lff11m_3 + + dec bp + jz short lff11m_9 + + lodsb + mov dl, 80h + dec cx + jz short lff11m_2_4 + mov dl, [si] +lff11m_2_4: + call interpolating_4_8bit_mono + jcxz lff11m_3 + jmp short lff11m_1 + +lff11m_3: +lff11s_3: + jmp lff11_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff11m_7: +lff11s_7: + jmp lff11_5 ; error + +load_11khz_stereo_8_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff11s_0 ; no + stc + retn + +lff11s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff11s_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff11s_8 + jmp lff11_eof + +lff11s_8: + mov cx, ax ; word count +lff11s_9: + mov bp, 6 ; interpolation (one step) loop count +lff11s_1: + ; 5:4:4::5:4:4::5:4:4::5:4:4::5:4:4::5:4 ; 74/17 + lodsw + mov dx, 8080h + dec cx + jz short lff11s_2_1 + mov dx, [si] +lff11s_2_1: + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dl = [next_val_r] + call interpolating_5_8bit_stereo + jcxz lff11s_3 +lff11s_2_2: + lodsw + mov dx, 8080h + dec cx + jz short lff11s_2_3 + mov dx, [si] +lff11s_2_3: + call interpolating_4_8bit_stereo + jcxz lff11s_3 + + dec bp + jz short lff11s_9 + + lodsw + mov dx, 8080h + dec cx + jz short lff11s_2_4 + mov dx, [si] +lff11s_2_4: + call interpolating_4_8bit_stereo + jcxz lff11s_3 + jmp short lff11s_1 + +load_11khz_mono_16_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff11m2_0 ; no + stc + retn + +lff11m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff11m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff11m2_8 + jmp lff11_eof + +lff11m2_8: + mov cx, ax ; word count +lff11m2_9: + mov bp, 6 ; interpolation (one step) loop count +lff11m2_1: + ; 5:4:4::5:4:4::5:4:4::5:4:4::5:4:4::5:4 ; 74/17 + lodsw + xor dx, dx + dec cx + jz short lff11m2_2_1 + mov dx, [si] +lff11m2_2_1: + ; ax = [previous_val] + ; dx = [next_val] + call interpolating_5_16bit_mono + jcxz lff11m2_3 +lff11m2_2_2: + lodsw + xor dx, dx + dec cx + jz short lff11m2_2_3 + mov dx, [si] +lff11m2_2_3: + call interpolating_4_16bit_mono + jcxz lff11m2_3 + + dec bp + jz short lff11m2_9 + + lodsw + xor dx, dx + dec cx + jz short lff11m2_2_4 + mov dx, [si] +lff11m2_2_4: + call interpolating_4_16bit_mono + jcxz lff11m2_3 + jmp short lff11m2_1 + +lff11m2_7: +lff11s2_7: + jmp lff11_5 ; error + +load_11khz_stereo_16_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff11s2_0 ; no + stc + retn + +lff11s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff11s2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; dword (left chan word + right chan word) + ;and ax, ax + jnz short lff11s2_8 + jmp lff11_eof + +lff11m2_3: +lff11s2_3: + jmp lff11_3 ; padfill + ; (put zeros in the remain words of the buffer) + +lff11s2_8: + mov cx, ax ; dword count +lff11s2_9: + mov bp, 6 ; interpolation (one step) loop count +lff11s2_1: + ; 5:4:4::5:4:4::5:4:4::5:4:4::5:4:4::5:4 ; 74/17 + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + mov [next_val_r], dx + dec cx + jnz short lff11s2_2_1 + xor dx, dx ; 0 + mov [next_val_l], dx + mov [next_val_r], dx +lff11s2_2_1: + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + call interpolating_5_16bit_stereo + jcxz lff11s2_3 +lff11s2_2_2: + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + mov [next_val_r], dx + dec cx + jnz short lff11s2_2_3 + xor dx, dx ; 0 + mov [next_val_l], dx + mov [next_val_r], dx +lff11s2_2_3: + call interpolating_4_16bit_stereo + jcxz lff11s2_3 + + dec bp + jz short lff11s2_9 + + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + mov [next_val_r], dx + dec cx + jnz short lff11s2_2_4 + xor dx, dx ; 0 + mov [next_val_l], dx + mov [next_val_r], dx +lff11s2_2_4: + call interpolating_4_16bit_stereo + jcxz lff11s2_3 + jmp short lff11s2_1 + +; ..................... + +load_44khz_mono_8_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff44m_0 ; no + stc + retn + +lff44m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff44m_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff44m_8 + jmp lff44_eof + +lff44m_8: + mov cx, ax ; byte count +lff44m_9: + mov bp, 10 ; interpolation (one step) loop count + mov byte [faz], 2 ; 2 steps/phases +lff44m_1: + ; 2:1:1:1:1:1:1:1:1:1:1:: ; 25/23 + ; 2:1:1:1:1:1:1:1:1:1:1:1 + lodsb + mov dl, 80h + dec cx + jz short lff44m_2_1 + mov dl, [si] +lff44m_2_1: + ; al = [previous_val] + ; dl = [next_val] + call interpolating_2_8bit_mono + jcxz lff44m_3 +lff44m_2_2: + lodsb + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; (L) + stosw ; (R) + + dec cx + jz short lff44m_3 + dec bp + jnz short lff44m_2_2 + + dec byte [faz] + jz short lff44m_9 + mov bp, 11 + jmp short lff44m_1 + +lff44m_3: +lff44s_3: + jmp lff44_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff44m_7: +lff44s_7: + jmp lff44_5 ; error + +load_44khz_stereo_8_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff44s_0 ; no + stc + retn + +lff44s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff44s_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff44s_8 + jmp lff44_eof + +lff44s_8: + mov cx, ax ; word count +lff44s_9: + mov bp, 10 ; interpolation (one step) loop count + mov byte [faz], 2 ; 2 steps/phase +lff44s_1: + ; 2:1:1:1:1:1:1:1:1:1:1:: ; 25/23 + ; 2:1:1:1:1:1:1:1:1:1:1:1 + lodsw + mov dx, 8080h + dec cx + jz short lff44s_2_1 + mov dx, [si] +lff44s_2_1: + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dl = [next_val_r] + call interpolating_2_8bit_stereo + jcxz lff44s_3 +lff44s_2_2: + lodsb + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; (L) + lodsb + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; (R) + + dec cx + jz short lff44s_3 + dec bp + jnz short lff44s_2_2 + + dec byte [faz] + jz short lff44s_9 + mov bp, 11 + jmp short lff44s_1 + +load_44khz_mono_16_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff44m2_0 ; no + stc + retn + +lff44m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff44m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff44m2_8 + jmp lff44_eof + +lff44m2_8: + mov cx, ax ; word count +lff44m2_9: + mov bp, 10 ; interpolation (one step) loop count + mov byte [faz], 2 ; 2 steps/phases +lff44m2_1: + ; 2:1:1:1:1:1:1:1:1:1:1:: ; 25/23 + ; 2:1:1:1:1:1:1:1:1:1:1:1 + lodsw + xor dx, dx + dec cx + jz short lff44m2_2_1 + mov dx, [si] +lff44m2_2_1: + ; ax = [previous_val] + ; dx = [next_val] + call interpolating_2_16bit_mono + jcxz lff44m2_3 +lff44m2_2_2: + lodsw + stosw ; (L)eft Channel + stosw ; (R)ight Channel + + dec cx + jz short lff44m2_3 + dec bp + jnz short lff44m2_2_2 + + dec byte [faz] + jz short lff44m2_9 + mov bp, 11 + jmp short lff44m2_1 + +lff44m2_3: +lff44s2_3: + jmp lff44_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff44m2_7: +lff44s2_7: + jmp lff44_5 ; error + +load_44khz_stereo_16_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff44s2_0 ; no + stc + retn + +lff44s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff44s2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; dword (left chan word + right chan word) + ;and ax, ax + jnz short lff44s2_8 + jmp lff44_eof + +lff44s2_8: + mov cx, ax ; dword count +lff44s2_9: + mov bp, 10 ; interpolation (one step) loop count + mov byte [faz], 2 ; 2 steps/phase +lff44s2_1: + ; 2:1:1:1:1:1:1:1:1:1:1:: ; 25/23 + ; 2:1:1:1:1:1:1:1:1:1:1:1 + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + dec cx + jnz short lff44s2_2_1 + xor dx, dx ; 0 + mov [next_val_l], dx +lff44s2_2_1: + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + call interpolating_2_16bit_stereo + jcxz lff44s2_3 +lff44s2_2_2: + ;lodsw + ;stosw ; (L) + ;lodsw + ;stosw ; (R) + movsw ; (L)eft Channel + movsw ; (R)ight Channel + + dec cx + jz short lff44s2_3 + dec bp + jnz short lff44s2_2_2 + + dec byte [faz] + jz short lff44s2_9 + mov bp, 11 + jmp short lff44s2_1 + +; ..................... + +interpolating_3_8bit_mono: + ; 16/11/2023 + ; al = [previous_val] + ; dl = [next_val] + ; original-interpolated-interpolated + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + stosw ; original sample (R) + mov al, bl + add al, dl + rcr al, 1 + mov bh, al ; interpolated middle (temporary) + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov al, bh + add al, dl ; [next_val] + rcr al, 1 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + retn + +interpolating_3_8bit_stereo: + ; 16/11/2023 + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dh = [next_val_r] + ; original-interpolated-interpolated + mov bx, ax + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + mov al, bh + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + push ax ; * ; al = interpolated middle (L) (temporary) + add al, bl ; [previous_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + push ax ; ** ; al = interpolated middle (R) (temporary) + add al, bh ; [previous_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (R) + pop bx ; ** + pop ax ; * + add al, dl ; [next_val_l] + rcr al, 1 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + mov al, bl + add al, dh ; [next_val_r] + rcr al, 1 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (R) + retn + +interpolating_2_8bit_mono: + ; 16/11/2023 + ; al = [previous_val] + ; dl = [next_val] + ; original-interpolated + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + stosw ; original sample (R) + mov al, bl + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample (L) + stosw ; interpolated sample (R) + retn + +interpolating_2_8bit_stereo: + ; 16/11/2023 + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dh = [next_val_r] + ; original-interpolated + mov bx, ax + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + mov al, bh + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + mov al, bl ; [previous_val_l] + add al, dl ; [next_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample (R) + retn + +interpolating_3_16bit_mono: + ; 16/11/2023 + ; ax = [previous_val] + ; dx = [next_val] + ; original-interpolated-interpolated + + stosw ; original sample (L) + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + push ax ; * ; [previous_val] + add dh, 80h + add ax, dx + rcr ax, 1 + pop bx ; * + xchg bx, ax ; bx = interpolated middle (temporary) + add ax, bx ; [previous_val] + interpolated middle + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov ax, bx + add ax, dx ;interpolated middle + [next_val] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + retn + +interpolating_3_16bit_stereo: + ; 16/11/2023 + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + ; original-interpolated-interpolated + + xchg ax, bx + stosw ; original sample (L) + xchg ax, bx + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + push ax ; * ; [previous_val_r] + add bh, 80h + add byte [next_val_l+1], 80h + mov ax, [next_val_l] + add ax, bx ; [previous_val_l] + rcr ax, 1 + xchg ax, bx ; ax = [previous_val_l] + add ax, bx ; bx = interpolated middle (L) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + pop ax ; * + add dh, 80h ; convert sound level 0 to 65535 format + push dx ; * ; [next_val_r] + xchg ax, dx + add ax, dx ; [next_val_r] + [previous_val_r] + rcr ax, 1 ; / 2 + push ax ; ** ; interpolated middle (R) + add ax, dx ; + [previous_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (R) + mov ax, [next_val_l] + add ax, bx ; + interpolated middle (L) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + pop ax ; ** + pop dx ; * + add ax, dx ; interpolated middle + [next_val_r] + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + retn + + +interpolating_2_16bit_mono: + ; 16/11/2023 + ; ax = [previous_val] + ; dx = [next_val] + ; original-interpolated + + stosw ; original sample (L) + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + add dh, 80h + add ax, dx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample (L) + stosw ; interpolated sample (R) + retn + +interpolating_2_16bit_stereo: + ; 16/11/2023 + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + ; original-interpolated + + xchg ax, bx + stosw ; original sample (L) + xchg ax, bx + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + add dh, 80h + add ax, dx ; [previous_val_r] + [next_val_r] + rcr ax, 1 ; / 2 + push ax ; * ; interpolated sample (R) + mov ax, [next_val_l] + add ah, 80h + add bh, 80h + add ax, bx ; [next_val_l] + [previous_val_l] + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample (L) + pop ax ; * + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample (R) + retn + +interpolating_5_8bit_mono: + ; 17/11/2023 + ; al = [previous_val] + ; dl = [next_val] + ; original-interpltd-interpltd-interpltd-interpltd + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + stosw ; original sample (R) + mov al, bl + add al, dl + rcr al, 1 + mov bh, al ; interpolated middle (temporary) + add al, bl ; [previous_val] + rcr al, 1 + mov dh, al ; interpolated 1st quarter (temporary) + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov al, bh + add al, dh + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + mov al, bh + add al, dl ; [next_val] + rcr al, 1 + mov dh, al ; interpolated 3rd quarter (temporary) + add al, bh + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (L) + stosw ; interpolated sample 3 (R) + mov al, dh + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 4 (L) + stosw ; interpolated sample 4 (R) + retn + +interpolating_5_8bit_stereo: + ; 17/11/2023 + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dh = [next_val_r] + ; original-interpltd-interpltd-interpltd-interpltd + mov bx, ax + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + mov al, bh + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + push dx ; * + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + push ax ; ** ; al = interpolated middle (L) (temporary) + add al, bl ; [previous_val_l] + rcr al, 1 + xchg al, bl + add al, bl ; bl = interpolated 1st quarter (L) (temp) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + push ax ; *** ; al = interpolated middle (R) (temporary) + add al, bh ; [previous_val_r] + rcr al, 1 + xchg al, bh + add al, bh ; bh = interpolated 1st quarter (R) (temp) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (R) + pop dx ; *** + pop ax ; ** ; al = interpolated middle (L) (temporary) + xchg al, bl ; al = interpolated 1st quarter (L) (temp) + add al, bl ; bl = interpolated middle (L) (temporary) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + mov al, dl ; interpolated middle (R) (temporary) + xchg al, bh ; al = interpolated 1st quarter (R) (temp) + add al, bh ; bh = interpolated middle (R) (temporary) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (R) + pop dx ; * + mov al, bl ; interpolated middle (L) (temporary) + add al, dl ; [next_val_l] + rcr al, 1 + xchg al, bl ; al = interpolated middle (R) (temporary) + add al, bl ; bl = interpolated 3rd quarter (L) (temp) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (L) + mov al, bh + add al, dh ; interpolated middle (R) + [next_val_r] + rcr al, 1 + xchg al, bh ; al = interpolated middle (R) + add al, bh ; bh = interpolated 3rd quarter (R) (temp) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (R) + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 4 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 4 (R) + retn + +interpolating_4_8bit_mono: + ; 17/11/2023 + ; al = [previous_val] + ; dl = [next_val] + ; original-interpolated-interpolated-interpolated + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + stosw ; original sample (R) + mov al, bl + add al, dl + rcr al, 1 + xchg al, bl ; al = [previous_val] + add al, bl ; bl = interpolated middle (sample 2) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov al, bl ; interpolated middle (sample 2) + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + mov al, bl + add al, dl ; [next_val] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (L) + stosw ; interpolated sample 3 (R) + retn + +interpolating_4_8bit_stereo: + ; 17/11/2023 + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dh = [next_val_r] + ; original-interpolated-interpolated-interpolated + mov bx, ax + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + mov al, bh + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + xchg al, bl ; al = [previous_val_l] + add al, bl ; bl = interpolated middle (L) (sample 2) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + xchg al, bh ; al = [previous_val_h] + add al, bh ; bh = interpolated middle (R) (sample 2) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (R) + mov al, bl ; interpolated middle (L) (sample 2) + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + mov al, bh ; interpolated middle (L) (sample 2) + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (R) + retn + +interpolating_5_16bit_mono: + ; 18/11/2023 + ; ax = [previous_val] + ; dx = [next_val] + ; original-interpltd-interpltd-interpltd-interpltd + stosw ; original sample (L) + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + mov bx, ax ; [previous_val] + add dh, 80h + add ax, dx + rcr ax, 1 + push ax ; * ; interpolated middle (temporary) + add ax, bx ; interpolated middle + [previous_val] + rcr ax, 1 + push ax ; ** ; interpolated 1st quarter (temporary) + add ax, bx ; 1st quarter + [previous_val] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + pop ax ; ** + pop bx ; * + add ax, bx ; 1st quarter + middle + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + mov ax, bx + add ax, dx ; interpolated middle + [next_val] + rcr ax, 1 + push ax ; * ; interpolated 3rd quarter (temporary) + add ax, bx ; + interpolated middle + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (L) + stosw ; interpolated sample 3 (R) + pop ax ; * + add ax, dx ; 3rd quarter + [next_val] + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 4 (L) + stosw ; interpolated sample 4 (R) + retn + +interpolating_5_16bit_stereo: + ; 18/11/2023 + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; [next_val_r] + ; original-interpltd-interpltd-interpltd-interpltd + push cx ; ! + xchg ax, bx + stosw ; original sample (L) + xchg ax, bx + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + push ax ; * ; [previous_val_r] + add bh, 80h + add byte [next_val_l+1], 80h + mov ax, [next_val_l] + add ax, bx ; [previous_val_l] + rcr ax, 1 + mov cx, ax ; interpolated middle (L) + add ax, bx + rcr ax, 1 + mov dx, ax ; interpolated 1st quarter (L) + add ax, bx ; [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + mov ax, cx + add ax, dx ; middle (L) + 1st quarter (L) + rcr ax, 1 ; / 2 + mov bx, ax ; interpolated sample 2 (L) + pop dx ; * ; [previous_val_r] + mov ax, dx + add byte [next_val_r+1], 80h + add ax, [next_val_r] + rcr ax, 1 + push ax ; * ; interpolated middle (R) + add ax, dx + rcr ax, 1 + push ax ; ** ; interpolated 1st quarter (R) + add ax, dx ; [previous_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (R) + mov ax, bx + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + pop ax ; ** + pop dx ; * + add ax, dx ; 1st quarter (R) + middle (R) + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (R) + mov ax, cx + add ax, [next_val_l] + rcr ax, 1 + push ax ; * ; interpolated 3rd quarter (L) + add ax, cx ; interpolated middle (L) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (L) + mov ax, dx + add ax, [next_val_r] + rcr ax, 1 + push ax ; ** ; interpolated 3rd quarter (R) + add ax, dx ; interpolated middle (R) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (R) + pop bx ; ** + pop ax ; * + add ax, [next_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 4 (L) + mov ax, bx + add ax, [next_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 4 (R) + pop cx ; ! + retn + +interpolating_4_16bit_mono: + ; 18/11/2023 + ; ax = [previous_val] + ; dx = [next_val] + ; original-interpolated + + stosw ; original sample (L) + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + mov bx, ax ; [previous_val] + add dh, 80h + add ax, dx ; [previous_val] + [next_val] + rcr ax, 1 + xchg ax, bx + add ax, bx ; [previous_val] + interpolated middle + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov ax, bx ; interpolated middle + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + mov ax, bx + add ax, dx ; interpolated middle + [next_val] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (L) + stosw ; interpolated sample 3 (R) + retn + +interpolating_4_16bit_stereo: + ; 18/11/2023 + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; [next_val_r] + ; original-interpolated-interpolated-interpolated + xchg ax, bx + stosw ; original sample (L) + xchg ax, bx + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + mov dx, ax ; [previous_val_r] + add bh, 80h + add byte [next_val_l+1], 80h + mov ax, [next_val_l] + add ax, bx ; [previous_val_l] + rcr ax, 1 + xchg ax, bx + add ax, bx ; bx = interpolated middle (L) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + add byte [next_val_r+1], 80h + mov ax, dx ; [previous_val_r] + add ax, [next_val_r] + rcr ax, 1 + xchg ax, dx + add ax, dx ; dx = interpolated middle (R) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (R) + mov ax, bx + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + mov ax, dx + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (R) + mov ax, bx + add ax, [next_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (L) + mov ax, dx + add ax, [next_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (R) + retn + +; 13/11/2023 +previous_val: +previous_val_l: dw 0 +previous_val_r: dw 0 +next_val: +next_val_l: dw 0 +next_val_r: dw 0 + +; 16/11/2023 +faz: db 0 + +; -------------------------------------------------------- +; 27/05/2024 - (TRDOS 386 Kernel) audio.s +; -------------------------------------------------------- + +NOT_PCI32_PCI16 EQU 03FFFFFFFh ; NOT BIT31+BIT30 ; 19/03/2017 +NOT_BIT31 EQU 7FFFFFFFh + +pciFindDevice: + ; 19/11/2023 + ; 03/04/2017 ('pci.asm', 20/03/2017) + ; + ; scan through PCI space looking for a device+vendor ID + ; + ; Entry: EAX=Device+Vendor ID + ; + ; Exit: EAX=PCI address if device found + ; EDX=Device+Vendor ID + ; CY clear if found, set if not found. EAX invalid if CY set. + ; + ; Destroys: ebx, edi ; 19/11/2023 + + ; 19/11/2023 + mov ebx, eax + mov edi, 80000000h +nextPCIdevice: + mov eax, edi ; read PCI registers + call pciRegRead32 + ; 19/11/2023 + cmp edx, ebx + je short PCIScanExit ; found + ; 19/11/2023 + cmp edi, 80FFF800h + jnb short pfd_nf ; not found + add edi, 100h + jmp short nextPCIdevice +pfd_nf: + stc + retn +PCIScanExit: + ;pushf + mov eax, NOT_BIT31 ; 19/03/2017 + and eax, edi ; return only bus/dev/fn # + retn + +pciRegRead: + ; 30/05/2024 + ; 03/04/2017 ('pci.asm', 20/03/2017) + ; + ; 8/16/32bit PCI reader + ; + ; Entry: EAX=PCI Bus/Device/fn/register number + ; BIT30 set if 32 bit access requested + ; BIT29 set if 16 bit access requested + ; otherwise defaults to 8 bit read + ; + ; Exit: DL,DX,EDX register data depending on requested read size + ; + ; Note1: this routine is meant to be called via pciRegRead8, + ; pciRegread16 or pciRegRead32, listed below. + ; + ; Note2: don't attempt to read 32 bits of data from a non dword + ; aligned reg number. Likewise, don't do 16 bit reads from + ; non word aligned reg # + + push ebx + push cx + mov ebx, eax ; save eax, dh + mov cl, dh + + and eax, NOT_PCI32_PCI16 ; clear out data size request + or eax, BIT31 ; make a PCI access request + and al, NOT 3 ; 13/11/2024 ; force index to be dword + + mov dx, PCI_INDEX_PORT + out dx, eax ; write PCI selector + + mov dx, PCI_DATA_PORT + mov al, bl + and al, 3 ; figure out which port to + add dl, al ; read to + + test ebx, PCI32+PCI16 + jnz short _pregr0 + + in al, dx ; return 8 bits of data + + mov dl, al + mov dh, cl ; restore dh for 8 bit read + jmp short _pregr2 +_pregr0: + test ebx, PCI32 + jnz short _pregr1 + + in ax, dx + + mov dx, ax ; return 16 bits of data + jmp short _pregr2 +_pregr1: + in eax, dx ; return 32 bits of data + + mov edx, eax +_pregr2: + mov eax, ebx ; restore eax + and eax, NOT_PCI32_PCI16 ; clear out data size request + pop cx + pop ebx + retn + +pciRegRead8: + and eax, NOT_PCI32_PCI16 ; set up 8 bit read size + jmp short pciRegRead ; call generic PCI access + +pciRegRead16: + and eax, NOT_PCI32_PCI16 ; set up 16 bit read size + or eax, PCI16 ; call generic PCI access + jmp short pciRegRead + +pciRegRead32: + and eax, NOT_PCI32_PCI16 ; set up 32 bit read size + or eax, PCI32 ; call generic PCI access + jmp pciRegRead + +pciRegWrite: + ; 30/05/2024 + ; 03/04/2017 ('pci.asm', 29/11/2016) + ; + ; 8/16/32bit PCI writer + ; + ; Entry: EAX=PCI Bus/Device/fn/register number + ; BIT31 set if 32 bit access requested + ; BIT30 set if 16 bit access requested + ; otherwise defaults to 8bit read + ; DL/DX/EDX data to write depending on size + ; + ; Note1: this routine is meant to be called via pciRegWrite8, + ; pciRegWrite16 or pciRegWrite32 as detailed below. + ; + ; Note2: don't attempt to write 32bits of data from a non dword + ; aligned reg number. Likewise, don't do 16 bit writes from + ; non word aligned reg # + + push ebx + push ecx + mov ebx, eax ; save eax, edx + mov ecx, edx + and eax, NOT_PCI32_PCI16 ; clear out data size request + or eax, BIT31 ; make a PCI access request + and al, NOT 3 ; 13/11/2024 ; force index to be dword + + mov dx, PCI_INDEX_PORT + out dx, eax ; write PCI selector + + mov dx, PCI_DATA_PORT + mov al, bl + and al, 3 ; figure out which port to + add dl, al ; write to + + test ebx, PCI32+PCI16 + jnz short _pregw0 + + mov al, cl ; put data into al + out dx, al + + jmp short _pregw2 +_pregw0: + test ebx, PCI32 + jnz short _pregw1 + + mov ax, cx ; put data into ax + out dx, ax + + jmp short _pregw2 +_pregw1: + mov eax, ecx ; put data into eax + out dx, eax +_pregw2: + mov eax, ebx ; restore eax + and eax, NOT_PCI32_PCI16 ; clear out data size request + mov edx, ecx ; restore dx + pop ecx + pop ebx + retn + +pciRegWrite8: + and eax, NOT_PCI32_PCI16 ; set up 8 bit write size + jmp short pciRegWrite ; call generic PCI access + +pciRegWrite16: + and eax, NOT_PCI32_PCI16 ; set up 16 bit write size + or eax, PCI16 ; call generic PCI access + jmp short pciRegWrite + +pciRegWrite32: + and eax, NOT_PCI32_PCI16 ; set up 32 bit write size + or eax, PCI32 ; call generic PCI access + jmp pciRegWrite + +; -------------------------------------------------------- +; 19/05/2024 - (playwav4.asm) ac97_vra.asm +; -------------------------------------------------------- + + ; 13/11/2023 + +;VRA: db 1 + +codecConfig: + ; 30/05/2024 + ; 19/05/2024 + ; 19/11/2023 + ; 15/11/2023 + ; 04/11/2023 + ; 17/02/2017 + ; 07/11/2016 (Erdogan Tan) + + ;AC97_EA_VRA equ 1 + AC97_EA_VRA equ BIT0 + + ; 04/11/2023 +init_ac97_controller: + mov eax, [bus_dev_fn] + mov al, PCI_CMD_REG + call pciRegRead16 ; read PCI command register + or dl, IO_ENA+BM_ENA ; enable IO and bus master + call pciRegWrite16 + + ;call delay_100ms + + ; 19/05/2024 + ; ('PLAYMOD3.ASM', Erdogan Tan, 18/05/2024) + +init_ac97_codec: + ; 18/11/2023 + mov bp, 40 + ; 29/05/2024 + ;mov bp, 1000 +_initc_1: + ; 30/05/2024 + mov dx, GLOB_STS_REG ; 30h + add dx, [NABMBAR] + in eax, dx + + ; 19/05/2024 + call delay1_4ms + + cmp eax, 0FFFFFFFFh ; -1 + jne short _initc_3 +_initc_2: + dec bp + jz short _ac97_codec_ready + + call delay_100ms + jmp short _initc_1 +_initc_3: + test eax, CTRL_ST_CREADY + jnz short _ac97_codec_ready + + ; 30/05/2024 + cmp byte [reset], 1 + jnb short _initc_2 + + call reset_ac97_codec + ; 30/05/2024 + mov byte [reset], 1 + ; 19/05/2024 + jmp short _initc_2 + +_ac97_codec_ready: + mov dx, [NAMBAR] + ;add dx, 0 ; ac_reg_0 ; reset register + out dx, ax + + call delay_100ms + + ; 19/11/2023 + or bp, bp + jnz short _ac97_codec_init_ok + + xor ax, ax ; 0 + mov dx, [NAMBAR] + add dx, CODEC_REG_POWERDOWN + out dx, ax + + ; 30/05/2024 + call delay1_4ms + + ; 19/11/2023 + ; wait for 1 second + ; 19/05/2024 + mov cx, 1000 ; 1000*4*0.25ms = 1s + ;;mov cx, 10 + ; 30/05/2024 + ;mov cx, 40 +_ac97_codec_rloop: + ;call delay_100ms + + ; 30/05/2024 + mov dx, [NAMBAR] + add dx, CODEC_REG_POWERDOWN + in ax, dx + + call delay1_4ms + + and ax, 0Fh + cmp al, 0Fh + je short _ac97_codec_init_ok + loop _ac97_codec_rloop + +init_ac97_codec_err1: + ;stc ; cf = 1 ; 19/05/2024 +init_ac97_codec_err2: + retn + +_ac97_codec_init_ok: + call reset_ac97_controller + + ; 30/05/2024 + ; 19/05/2024 + ;call delay_100ms + + ; 30/05/2024 + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + +setup_ac97_codec: + ; 12/11/2023 + cmp word [WAVE_SampleRate], 48000 + je short skip_rate + + ; 30/05/2024 + ; 19/05/2024 + ;call delay1_4ms + + ; 30/05/2024 + ;cmp byte [VRA], 0 + ;jna short skip_rate + + ; 11/11/2023 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + in ax, dx + + ; 30/05/2024 + ; 19/05/2024 + call delay1_4ms + + ; 13/11/2024 + ;and al, NOT BIT1 ; Clear DRA + ;;; + ; 30/05/2024 + and al, NOT (BIT1+BIT0) ; Clear DRA+VRA + out dx, ax + + call check_vra + + cmp byte [VRA], 0 + jna short skip_rate + + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + in ax, dx + ;and al, ~BIT1 ; Clear DRA + ;;; + + or al, AC97_EA_VRA ; 1 ; 04/11/2023 + ; 30/05/2024 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + + out dx, ax ; Enable variable rate audio + + mov cx, 10 +check_vra_loop: + call delay_100ms + ; 30/05/2024 + ;call delay1_4ms + + ; 30/05/2024 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + ; 11/11/2023 + in ax, dx + + test al, AC97_EA_VRA ; 1 + jnz short set_rate + + ; 11/11/2023 + loop check_vra_loop + +;vra_not_supported: ; 19/05/2024 + mov byte [VRA], 0 + jmp short skip_rate + +set_rate: + mov ax, [WAVE_SampleRate] ; 17/02/2017 (Erdogan Tan) + + mov dx, [NAMBAR] + add dx, CODEC_PCM_FRONT_DACRATE_REG ; 2Ch + out dx, ax ; PCM Front/Center Output Sample Rate + + ;call delay_100ms + ; 30/05/2024 + call delay1_4ms + + ; 12/11/2023 +skip_rate: + mov ax, 0202h + mov dx, [NAMBAR] + add dx, CODEC_MASTER_VOL_REG ;02h + out dx, ax + + ; 11/11/2023 + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + + mov ax, 0202h + mov dx, [NAMBAR] + add dx, CODEC_PCM_OUT_REG ;18h + out dx, ax + + ; 11/11/2023 + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + + ; 30/05/2024 + ; 19/05/2024 + ;clc + + retn + +reset_ac97_controller: + ; 19/05/2024 + ; 11/11/2023 + ; 10/06/2017 + ; 29/05/2017 + ; 28/05/2017 + ; reset AC97 audio controller registers + xor ax, ax + mov dx, PI_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov dx, PO_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov dx, MC_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov al, RR + mov dx, PI_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov dx, PO_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov dx, MC_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + retn + +reset_ac97_codec: + ; 11/11/2023 + ; 28/05/2017 - Erdogan Tan (Ref: KolibriOS, intelac97.asm) + mov dx, GLOB_CNT_REG ; 2Ch + add dx, [NABMBAR] + in eax, dx + + ;test eax, 2 + ; 06/08/2022 + test al, 2 + jz short _r_ac97codec_cold + + call warm_ac97codec_reset + jnc short _r_ac97codec_ok +_r_ac97codec_cold: + call cold_ac97codec_reset + jnc short _r_ac97codec_ok + + ; 16/04/2017 + ;xor eax, eax ; timeout error + ;stc + retn + +_r_ac97codec_ok: + xor eax, eax + ;mov al, VIA_ACLINK_C00_READY ; 1 + inc al + retn + +warm_ac97codec_reset: + ; 11/11/2023 + ; 06/08/2022 - TRDOS 386 v2.0.5 + ; 28/05/2017 - Erdogan Tan (Ref: KolibriOS, intelac97.asm) + mov eax, 6 + mov dx, GLOB_CNT_REG ; 2Ch + add dx, [NABMBAR] + out dx, eax + + mov cx, 10 ; total 1s +_warm_ac97c_rst_wait: + call delay_100ms + + mov dx, GLOB_STS_REG ; 30h + add dx, [NABMBAR] + in eax, dx + + test eax, CTRL_ST_CREADY + jnz short _warm_ac97c_rst_ok + + dec cx + jnz short _warm_ac97c_rst_wait + +_warm_ac97c_rst_fail: + stc +_warm_ac97c_rst_ok: + retn + +cold_ac97codec_reset: + ; 11/11/2023 + ; 06/08/2022 - TRDOS 386 v2.0.5 + ; 28/05/2017 - Erdogan Tan (Ref: KolibriOS, intelac97.asm) + mov eax, 2 + mov dx, GLOB_CNT_REG ; 2Ch + add dx, [NABMBAR] + out dx, eax + + call delay_100ms ; wait 100 ms + call delay_100ms ; wait 100 ms + call delay_100ms ; wait 100 ms + call delay_100ms ; wait 100 ms + + mov cx, 16 ; total 20*100 ms = 2s + +_cold_ac97c_rst_wait: + mov dx, GLOB_STS_REG ; 30h + add dx, [NABMBAR] + in eax, dx + + test eax, CTRL_ST_CREADY + jnz short _cold_ac97c_rst_ok + + call delay_100ms + + dec cx + jnz short _cold_ac97c_rst_wait + +_cold_ac97c_rst_fail: + stc +_cold_ac97c_rst_ok: + retn + +; 13/11/2024 +; 30/05/2024 +if 1 +check_vra: + ; 30/05/2024 + mov byte [VRA], 1 + + ; 29/05/2024 - audio.s (TRDOS 386 Kernel) - 27/05/2024 + ; 24/05/2024 + ; 23/05/2024 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_REG ; 28h + in ax, dx + + ; 30/05/2024 + ; 23/05/2024 + call delay1_4ms + + ; 30/05/2024 + test al, BIT0 + ;test al, 1 ; BIT0 ; Variable Rate Audio bit + jnz short check_vra_ok + +vra_not_supported: + ; 13/11/2023 + mov byte [VRA], 0 +check_vra_ok: + retn +end if + +; -------------------------------------------------------- + +; 18/11/2024 +; Ref: TRDOS 386 v2.0.9, audio.s, Erdogan Tan, 06/06/2024 + +ac97_stop: + ; 18/11/2024 + mov byte [stopped], 2 + +ac97_po_cmd@: + xor al, al ; 0 +ac97_po_cmd: + mov dx, [NABMBAR] + add dx, PO_CR_REG ; PCM out control register + out dx, al + retn + +ac97_pause: + mov byte [stopped], 1 ; paused + ;mov al, 0 + ;jmp short ac97_po_cmd + jmp short ac97_po_cmd@ + +ac97_play: ; continue to play (after pause) + mov byte [stopped], 0 + mov al, RPBM + jmp short ac97_po_cmd + +; -------------------------------------------------------- + +PORTB EQU 061h +REFRESH_STATUS EQU 010h ; Refresh signal status + +delay_100ms: + ; 11/11/2023 + ; 29/05/2017 + ; 24/03/2017 ('codec.asm') + ; wait 100 ms + push cx + mov cx, 400 ; 400*0.25ms +_delay_x_ms: + call delay1_4ms + loop _delay_x_ms + pop cx + retn + +delay1_4ms: + push ax + push cx + mov cx, 16 ; close enough. + in al,PORTB + and al,REFRESH_STATUS + mov ah,al ; Start toggle state + or cx, cx + jz short _d4ms1 + inc cx ; Throwaway first toggle +_d4ms1: + in al,PORTB ; Read system control port + and al,REFRESH_STATUS ; Refresh toggles 15.085 microseconds + cmp ah,al + je short _d4ms1 ; Wait for state change + + mov ah,al ; Update with new state + dec cx + jnz short _d4ms1 + + ; 30/05/2024 + clc + + pop cx + pop ax + retn + +; -------------------------------------------------------- +; 14/11/2024 - Erdogan Tan +; -------------------------------------------------------- + + ; 29/11/2024 +checkUpdateEvents: + call check4keyboardstop + jc short c4ue_ok + + ; 18/11/2024 + push ax ; * + or ax, ax + jz c4ue_cpt + + ; 18/11/2024 + cmp al, 20h ; SPACE (spacebar) ; pause/play + jne short ch4ue_chk_s + cmp byte [stopped], 0 + ja short c4ue_chk_ps + ; pause + call ac97_pause + ; 21/11/2024 + mov al, [tLO] + mov byte [tLP], al + jmp c4ue_cpt +c4ue_chk_ps: + cmp byte [stopped], 1 + ja short c4ue_replay + ; continue to play (after a pause) + call ac97_play + jmp c4ue_cpt +c4ue_replay: + ; 19/11/2024 + pop ax ; * + pop ax ; return address + call codecConfig + mov al, [volume] + call SetPCMOutVolume@ + mov byte [stopped], 0 + call move_to_beginning + jmp PlayWav + +ch4ue_chk_s: + cmp al, 'S' ; stop + jne short ch4ue_chk_fb + cmp byte [stopped], 0 + ja short c4ue_cpt ; Already stopped/paused + call ac97_stop + ; 19/11/2024 + mov byte [tLO], 0 + ; 21/11/2024 + mov byte [tLP], '0' + jmp short c4ue_cpt + +ch4ue_chk_fb: + ; 17/11/2024 + cmp al, 'F' + jne short c4ue_chk_b + call Player_ProcessKey_Forwards + jmp short c4ue_cpt + + ; 18/11/2024 +c4ue_ok: + retn + +c4ue_chk_b: + cmp al, 'B' + ;;jne short c4ue_cpt + ; 19/11/2024 + ;jne short c4ue_chk_h + ; 29/11/2024 + jne short c4ue_chk_n + call Player_ProcessKey_Backwards + jmp short c4ue_cpt + + ;;; + ; 29/11/2024 +c4ue_chk_n: + cmp al, 'N' + je short c4ue_nps +c4ue_chk_p: + cmp al, 'P' + jne short c4ue_chk_h +c4ue_nps: + mov byte [stopped], 3 + jmp short c4ue_cpt + ;;; + +c4ue_chk_h: + ; 19/11/2024 + cmp al, 'H' + jne short c4ue_chk_cr + mov byte [wleds], 0 + call write_ac97_pci_dev_info + mov dh, 24 + mov dl, 79 + call setCursorPosition +c4ue_chk_cr: + ; 19/11/2024 + cmp al, 0Dh ; ENTER/CR key + jne short c4ue_cpt + ;inc byte [wleds] + ;jnz short c4ue_cpt + ;inc byte [wleds] + ;;; + ; 23/11/2024 + xor bx, bx + mov bl, [wleds] + inc bl + and bl, 0Fh + jnz short c4ue_sc + inc bx +c4ue_sc: + mov [wleds], bl + shr bl, 1 + mov al, [bx+colors] + jnc short c4ue_sc_@ + or al, 10h ; blue (dark) background +c4ue_sc_@: + mov [ccolor], al + ;;; +c4ue_cpt: + push ds + mov bx, 40h + mov ds, bx + mov bx, 6Ch ; counter (INT 08h, 18.2 ticks per sec) + ;cli + mov ax, [bx] + mov dx, [bx+2] + ;sti + pop ds + ; 18/11/2024 + pop cx ; * + cmp dx, [timerticks+2] + jne short c4ue_utt + cmp ax, [timerticks] + ;je short c4ue_ok + ; 18/11/2024 + je short c4ue_skip_utt +c4ue_utt: + mov [timerticks], ax + mov [timerticks+2], dx + jmp short c4ue_cpt_@ +c4ue_skip_utt: + ; 18/11/2024 + and cx, cx + jz short c4ue_ok +c4ue_cpt_@: + ; 18/11/2024 + cmp byte [stopped], 0 + ja short c4ue_ok + + call CalcProgressTime + + cmp ax, [ProgressTime] + ;je short c4ue_ok + ; same second, no need to update + ; 23/11/2024 + je short c4ue_uvb + + ;call UpdateProgressTime + ;call UpdateProgressBar@ + call UpdateProgressBar + + ; 23/11/2024 +c4ue_uvb: + cmp byte [wleds], 0 + jna short c4ue_vb_ok + + call UpdateWaveLeds + +c4ue_vb_ok: + retn + + ;clc +;c4ue_ok: +; retn + +; -------------------------------------------------------- +; 19/05/2024 - (playwav4.asm) ich_wav4.asm +; -------------------------------------------------------- + + ; 29/11/2024 +check4keyboardstop: + ; 19/05/2024 + ; 08/11/2023 + ; 04/11/2023 + mov ah, 1 + int 16h + ;clc + jz short _cksr + + xor ah, ah + int 16h + + ; 29/11/2024 + mov [command], al + + ;;; + ; 19/05/2024 (change PCM out volume) + cmp al, '+' + jne short p_1 + + mov al, [volume] + cmp al, 0 + jna short p_3 + dec al + jmp short p_2 +p_1: + cmp al, '-' + jne short p_4 + + mov al, [volume] + cmp al, 31 + jnb short p_3 + inc al +p_2: + mov [volume], al + ; 14/11/2024 + call SetPCMOutVolume + ; 15/11/2024 (QEMU) + ;call SetMasterVolume + ;call UpdateVolume + ;;clc + ;retn + jmp UpdateVolume + ;mov ah, al + ;mov dx, [NAMBAR] + ;;add dx, CODEC_MASTER_VOL_REG + ;add dx, CODEC_PCM_OUT_REG + ;out dx, ax + ; + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms +_cksr: ; 19/05/2024 + ; 18/11/2024 + xor ax, ax + ;clc +p_3: + retn +p_4: + ; 17/11/2024 + cmp ah, 01h ; ESC + je short p_q + cmp al, 03h ; CTRL+C + je short p_q + + ; 18/11/2024 + cmp al, 20h + je short p_r + + ; 19/11/2024 + cmp al, 0Dh ; CR/ENTER + je short p_r + + and al, 0DFh + + ; 29/11/2024 + mov [command], al + + ;cmp al, 'B' + ;je short p_r + ;cmp al, 'F' + ;je short p_r + + ; 29/11/2024 + ;cmp al, 'N' + ;je short p_r + ;cmp al, 'P' + ;je short p_r + + cmp al, 'Q' + ;je short p_q + je short p_quit ; 29/11/2024 + + clc + retn + + ;;; +;_cskr: +p_q: + ; 29/11/2024 + mov byte [command], 'Q' +p_quit: + stc +p_r: + retn + +; returns AL = current index value +getCurrentIndex: + ; 08/11/2023 + ;push dx + mov dx, [NABMBAR] + add dx, PO_CIV_REG + in al, dx + ;pop dx +uLVI2: ; 06/11/2023 + retn + +updateLVI: + ; 06/11/2023 + mov dx, [NABMBAR] + add dx, PO_CIV_REG + ; (Current Index Value and Last Valid Index value) + in ax, dx + + cmp al, ah ; is current index = last index ? + jne short uLVI2 + + ; 08/11/2023 + call getCurrentIndex + + test byte [flags], ENDOFFILE + ;jnz short uLVI1 + jz short uLVI0 ; 08/11/2023 + + ; 08/11/2023 + push ax + mov dx, [NABMBAR] + add dx, PO_SR_REG ; PCM out status register + in ax, dx + + test al, 3 ; bit 1 = Current Equals Last Valid (CELV) + ; (has been processed) + ; bit 0 = 1 -> DMA Controller Halted (DCH) + pop ax + jz short uLVI1 +uLVI3: + xor ax, ax + ; zf = 1 + retn +uLVI0: + ; not at the end of the file yet. + dec al + and al, 1Fh +uLVI1: + ;call setLastValidIndex +;uLVI2: + ;retn + +;input AL = index # to stop on +setLastValidIndex: + ; 08/11/2023 + ;push dx + mov dx, [NABMBAR] + add dx, PO_LVI_REG + out dx, al + ;pop dx + retn + +; 29/05/2024 +; 19/05/2024 +volume: ;db 02h + db 03h ; 14/12/2024 + +; -------------------------------------------------------- + + ; 14/11/2024 +setCursorPosition: + ; dh = Row + ; dl = Column + mov ax, 0500h + int 10h + mov ah, 02h + mov bh, 00h + ;mov dh, setCursorPosition_Row + ;mov dl, setCursorPosition_Column + int 10h + retn + +; -------------------------------------------------------- +; 14/11/2024 +; (Ref: player.asm, out_cs.asm, Matan Alfasi, 2017) + +;; NAME: SetTotalTime +;; DESCRIPTION: Calculates the total time in seconds in file +;; INPUT: DATA_SubchunkSize, WAVE_SampleRate, WAVE_BlockAlign +;; OUTPUT: CurrentTotalTime=Total time in seconds in file, +;; Output on the screen of the total time in seconds + +SetTotalTime: + ;; Calculate total seconds in file + mov ax, [DATA_SubchunkSize] + mov dx, [DATA_SubchunkSize + 2] + mov bx, [WAVE_SampleRate] + div bx + xor dx, dx + + mov bx, [WAVE_BlockAlign] + + div bx + + mov [TotalTime], ax + + mov bl, 60 + div bl + + ;; al = minutes, ah = seconds + push ax ; ** + push ax ; * + + mov dh, 24 + mov dl, 42 + call setCursorPosition + + pop ax ; * + xor ah, ah + mov bp, 2 + call PrintNumber + + mov dh, 24 + mov dl, 45 + call setCursorPosition + + pop ax ; ** + mov al, ah + xor ah, ah + ;mov bp, 2 + ;jmp short PrintNumber + +; -------------------------------------------------------- + +PrintNumber: + ; bp = digits + ; ax = binary number + mov bx, 10 + xor cx, cx +printNumber_CutNumber: + inc cx + xor dx, dx + div bx + push dx + cmp cx, bp + je short printNumber_printloop + jmp printNumber_CutNumber + +printNumber_printloop: + pop ax + mov dl, '0' + add dl, al + mov ah, 02h + int 21h + loop printNumber_printloop + + retn + +; -------------------------------------------------------- + + ; 14/11/2024 - Erdogan Tan +SetProgressTime: + ;; Calculate playing/progress seconds in file + call CalcProgressTime + +UpdateProgressTime: + ; ax = (new) progress time + + mov [ProgressTime], ax + + mov bl, 60 + div bl + + ;; al = minutes, ah = seconds + push ax ; ** + push ax ; * + + mov dh, 24 + mov dl, 33 + call setCursorPosition + + pop ax ; * + xor ah, ah + mov bp, 2 + call PrintNumber + + mov dh, 24 + mov dl, 36 + call setCursorPosition + + pop ax ; ** + mov al, ah + xor ah, ah + ;mov bp, 2 + jmp short PrintNumber + +; -------------------------------------------------------- + + ; 17/11/2024 + ; 14/11/2024 +CalcProgressTime: + mov ax, [LoadedDataBytes] + mov dx, [LoadedDataBytes+2] + mov bx, ax + or bx, dx + jz short cpt_ok + + mov bx, [WAVE_SampleRate] + div bx + xor dx, dx + mov bx, [WAVE_BlockAlign] + div bx +cpt_ok: + ; ax = (new) progress time + retn + +; -------------------------------------------------------- +; 14/11/2024 +; (Ref: player.asm, out_cs.asm, Matan Alfasi, 2017) + +;; DESCRIPTION: Update file information on template +;; PARAMS: WAVE parameters and other variables +;; REGS: AX(RW) +;; VARS: CurrentFileName, WAVE_SampleRate, +;; RETURNS: On-screen file info is updated. + +UpdateFileInfo: + ;; Print File Name + mov dh, 9 + mov dl, 23 + call setCursorPosition + + mov si, wav_file_name + + ;;; + ; 14/11/2024 + ; skip directory separators + ; (note: asciiz string, max. 79 bytes except zero tail) + mov bx, si +chk4_nxt_sep: + lodsb + cmp al, '\' + je short chg_fpos + and al, al + jz short chg_fpos_ok + jmp short chk4_nxt_sep +chg_fpos: + mov bx, si + jmp short chk4_nxt_sep +chg_fpos_ok: + mov si, bx ; file name (without its path/directory) + ;;; + + call PrintString + + ;; Print Frequency + mov dh, 10 + mov dl, 23 + call setCursorPosition + mov ax, [WAVE_SampleRate] + mov bp, 5 + call PrintNumber + + ;; Print BitRate + mov dh, 9 + mov dl, 57 + call setCursorPosition + mov ax, [WAVE_BitsPerSample] + mov bp, 2 + call PrintNumber + + ;; Print Channel Number + mov dh, 10 + mov dl, 57 + call setCursorPosition + mov ax, [WAVE_NumChannels] + mov bp, 1 + call PrintNumber + + ;call UpdateVolume + ;retn + +; -------------------------------------------------------- + + ; 14/11/2024 +UpdateVolume: + ;; Print Volume + mov dh, 24 + mov dl, 75 + call setCursorPosition + + mov al, [volume] + + mov bl, 100 + mul bl + + mov bl, 31 + div bl + + neg ax + add ax, 100 + + xor ah, ah + mov bp, 3 + ;call PrintNumber + ;retn + jmp PrintNumber + +; -------------------------------------------------------- + + ; 14/11/2024 +PrintString: + ; si = string address + mov bx, 0Fh ; white + mov ah, 0Eh ; write as tty +printstr_loop: + lodsb + or al, al + jz short printstr_ok + int 10h + jmp short printstr_loop +printstr_ok: + retn + +; -------------------------------------------------------- + + ; 14/11/2024 + ; (Ref: player.asm , Matan Alfasi, 2017) + ; (Modification: Erdogan Tan, 14/11/2024) + + PROGRESSBAR_ROW equ 23 + +UpdateProgressBar: + call SetProgressTime ; 14/11/2024 + + mov ax, [ProgressTime] +UpdateProgressBar@: + mov dx, 80 + mul dx + mov bx, [TotalTime] + div bx + + ;; Push for the 'Clean' part + push ax ; ** + push ax ; * + + ;; Set cursor position + mov dh, PROGRESSBAR_ROW + mov dl, 0 + call setCursorPosition + + pop ax ; * + or ax, ax + jz short UpdateProgressBar_Clean + +UpdateProgressBar_DrawProgress: + mov cx, ax + mov ah, 09h + mov al, 223 + mov bx, 0Fh + int 10h + +UpdateProgressBar_DrawCursor: + ;mov ax, cx + mov dh, PROGRESSBAR_ROW + ;mov dl, al + dec cx + mov dl, cl + call setCursorPosition + + mov ah, 09h + mov al, 223 + mov bx, 0Ch + mov cx, 1 + int 10h + +UpdateProgressBar_Clean: + pop ax ; ** + mov cx, ax + mov dh, PROGRESSBAR_ROW + mov dl, al + call setCursorPosition + + neg cx + add cx, 80 ; cf = 1 ; + + ;; CX = No. of times to print a clean character + ;mov cx, 80 + ;sub cx, ax + ;; 09h = Write character multiple times + mov ah, 09h + ;; 32 = Space ASCII code + ;mov al, 32 + ;mov bx, 0 + ; 15/11/2024 + mov al, 223 + mov bx, 8 + int 10h + ; 14/11/2024 + clc ; + + + retn + +; -------------------------------------------------------- +; 17/11/2024 + +Player_ProcessKey_Backwards: + ;; In order to go backwards 5 seconds: + ;; Update file pointer to the beginning, skip headers + mov cl, 'B' + jmp short Player_ProcessKey_B_or_F + +Player_ProcessKey_Forwards: + ;; In order to fast-forward 5 seconds, set the file pointer + ;; to CUR_SEEK + 5 * Freq + + mov cl, 'F' + ;jmp short Player_ProcessKey_B_or_F + +Player_ProcessKey_B_or_F: + ; 17/11/2024 + ; 04/11/2024 + ; (Ref: player.asm, Matan Alfasi, 2017) + + ; 04/11/2024 + mov ax, 5 + mov bx, [WAVE_BlockAlign] + mul bx + mov bx, [WAVE_SampleRate] + mul bx + ; dx:ax = transfer byte count for 5 seconds + + ; 17/11/2024 + cmp cl, 'B' + mov bx, [LoadedDataBytes] + mov cx, [LoadedDataBytes+2] + jne short move_forward ; cl = 'F' +move_backward: + sub bx, ax + sbb cx, dx + jnc short move_file_pointer +move_to_beginning: + xor cx, cx ; 0 + xor bx, bx ; 0 + jmp short move_file_pointer +move_forward: + add bx, ax + adc cx, dx + jc short move_to_end + cmp cx, [DATA_SubchunkSize+2] + ja short move_to_end + jb short move_file_pointer + cmp bx, [DATA_SubchunkSize] + jna short move_file_pointer +move_to_end: + mov bx, [DATA_SubchunkSize] + mov cx, [DATA_SubchunkSize+2] +move_file_pointer: + mov dx, bx + mov [LoadedDataBytes], dx + mov [LoadedDataBytes+2], cx + add dx, 44 ; + header + adc cx, 0 + + ; seek + mov bx, [filehandle] + mov ax, 4200h + int 21h + + retn + +; -------------------------------------------------------- + + ; 23/11/2024 + ; 19/11/2024 +clear_window: + xor ax, ax + jmp short clear_window_@ + +reset_wave_leds: + ; 23/11/2024 + ;mov al, 254 + ;mov ah, 8 ; gray (dark) + mov ax, 08FEh +clear_window_@: + push es + mov di, 0B800h + mov es, di + mov di, 2080 ; 13*80*2 + mov cx, 8*80 ; 8 rows + rep stosw + pop es + retn + +; -------------------------------------------------------- + + ; 09/12/2024 + ; 19/11/2024 +UpdateWaveLeds: + ; 23/11/2024 + call reset_wave_leds + ; 09/12/2024 + ;jmp short turn_on_leds + +; -------------------------------------------------------- + + ; 09/12/2024 +turn_on_leds: + ; 19/11/2024 +;turn_on_leds_stereo_16bit: + push es + push ds + + cmp byte [tLO],'2' + jne short tol_buffer_1 + +tol_buffer_2: + ; 21/11/2024 + mov si, [WAV_BUFFER2] + jmp short tol_@ + +tol_buffer_1: + cmp byte [tLO],'1' + ;jne short tol_retn + ; 23/11/2024 + jne short tol_clc_retn + + mov si, [WAV_BUFFER1] +tol_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + mov cx, [buffersize] ; word + shl cx, 1 ; byte + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol_o_@ + cmp si, cx + jna short tol_s_buf +tol_o_@: + mov si, cx + jmp short tol_s_buf + +tol_clc_retn: + ; 23/11/2024 + clc +tol_retn: + pop ds + pop es + retn + +tol_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol_s_buf: + mov [pbuf_o], si + +tol_buf_@: + ; 21/11/2024 + mov ds, [pbuf_s] + mov di, 0B800h + mov es, di + ;mov di, (20*80*2)-2 + + ; 23/11/2024 + mov cx, 80 + + ; 22/11/2024 + mov bx, wleds_addr + +tol_fill_c: + ; 22/11/2024 + ;inc di + ;inc di + ;push di + lodsw ; left + ;shr ax, 8 + mov dx, ax + lodsw ; right + ;shr ax, 8 + ;;; + ; 23/11/2024 + add ax, dx + ; 09/12/2024 + ;shr ax, 8 + ;;shr ax, 9 + ;add al, 80h + ;shr ax, 5 + add ah, 80h + shr ax, 13 + ;;; + ;;shr ax, 6 + + push bx + shl ax, 1 + add bx, ax + mov di, [cs:bx] + ; 23/11/2024 + mov ah, [cs:ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol_fill_c + + jmp short tol_retn + +; -------------------------------------------------------- + +; 30/05/2024 +print_msg: + mov bx, 07h +p_msg: + push es + push bp + push cx + push dx + + push ds + pop es + mov bp, si + mov ah, 03h ; Return cursor position (in DX) + ; bh = video page number + int 10h + xor cx, cx +p_msg_0: + lodsb + or al, al + jz short p_msg_1 + inc cx + jmp short p_msg_0 +p_msg_1: + or cx, cx + jz short p_msg_x + ; cx = number of chars + ; dx = screen (cursor) position + ; bl = color/attribute + ; bh = video page number + ; es:bp = string buffer + ;mov al, 1 ; attribute in BL, update cursor pos + ;mov ah, 13h ; write character string + mov ax, 1301h + int 10h +p_msg_x: + pop dx + pop cx + pop bp + pop es + retn + +; -------------------------------------------------------- +; -------------------------------------------------------- + +; DATA + +; 30/05/2024 +;reset: db 0 + +Credits: + db 'Tiny WAV Player for Retro DOS by Erdogan Tan. ' + db 'December 2024.',10,13,0 + db '18/12/2024', 10,13 +; 15/11/2024 +reset: + db 0 + +msgAudioCardInfo: + db 'for Intel AC97 (ICH) Audio Controller.', 10,13,0 + +msg_usage: + db 'usage: AC97PLAY <...>',10,13,0 ; 28/11/2024 + +noDevMsg: + db 'Error: Unable to find AC97 audio device!' + db 10,13,0 + +noFileErrMsg: + db 'Error: file not found.',10,13,0 + +msg_error: ; 30/05/2024 + +; 29/05/2024 +; 11/11/2023 +msg_init_err: + db CR, LF + db "AC97 Controller/Codec initialization error !" + db CR, LF, 0 ; 07/12/2024 + +; 25/11/2023 +msg_no_vra: + db 10,13 + db "No VRA support ! Only 48 kHZ sample rate supported !" + db 10,13,0 + +; 13/11/2024 +; ('<<' to 'shl' conversion for FASM) +; +; 29/05/2024 (TRDOS 386) +; 17/02/2017 +; Valid ICH device IDs + +valid_ids: +;dd (ICH_DID << 16) + INTEL_VID ; 8086h:2415h +dd (ICH_DID shl 16) + INTEL_VID ; 8086h:2415h +dd (ICH0_DID shl 16) + INTEL_VID ; 8086h:2425h +dd (ICH2_DID shl 16) + INTEL_VID ; 8086h:2445h +dd (ICH3_DID shl 16) + INTEL_VID ; 8086h:2485h +dd (ICH4_DID shl 16) + INTEL_VID ; 8086h:24C5h +dd (ICH5_DID shl 16) + INTEL_VID ; 8086h:24D5h +dd (ICH6_DID shl 16) + INTEL_VID ; 8086h:266Eh +dd (ESB6300_DID shl 16) + INTEL_VID ; 8086h:25A6h +dd (ESB631X_DID shl 16) + INTEL_VID ; 8086h:2698h +dd (ICH7_DID shl 16) + INTEL_VID ; 8086h:27DEh +; 03/11/2023 - Erdogan Tan +dd (MX82440_DID shl 16) + INTEL_VID ; 8086h:7195h +dd (SI7012_DID shl 16) + SIS_VID ; 1039h:7012h +dd (NFORCE_DID shl 16) + NVIDIA_VID ; 10DEh:01B1h +dd (NFORCE2_DID shl 16) + NVIDIA_VID ; 10DEh:006Ah +dd (AMD8111_DID shl 16) + AMD_VID ; 1022h:746Dh +dd (AMD768_DID shl 16) + AMD_VID ; 1022h:7445h +dd (CK804_DID shl 16) + NVIDIA_VID ; 10DEh:0059h +dd (MCP04_DID shl 16) + NVIDIA_VID ; 10DEh:003Ah +dd (CK8_DID shl 16) + NVIDIA_VID ; 1022h:008Ah +dd (NFORCE3_DID shl 16) + NVIDIA_VID ; 10DEh:00DAh +dd (CK8S_DID shl 16) + NVIDIA_VID ; 10DEh:00EAh + +;valid_id_count equ ($ - valid_ids)>>2 ; 05/11/2023 +; 13/11/2024 +valid_id_count = ($ - valid_ids) shr 2 ; 05/11/2023 + +; 19/11/2024 +; 03/06/2017 +hex_chars db "0123456789ABCDEF", 0 +msgAC97Info db 0Dh, 0Ah + db " AC97 Audio Controller & Codec Info", 0Dh, 0Ah + db " Vendor ID: " +msgVendorId db "0000h Device ID: " +msgDevId db "0000h", 0Dh, 0Ah + db " Bus: " +msgBusNo db "00h Device: " +msgDevNo db "00h Function: " +msgFncNo db "00h" + db 0Dh, 0Ah + db " NAMBAR: " +msgNamBar db "0000h " + db "NABMBAR: " +msgNabmBar db "0000h IRQ: " +msgIRQ dw 3030h + db 0Dh, 0Ah, 0 +; 25/11/2023 +msgVRAheader db " VRA support: " + db 0 +msgVRAyes db "YES", 0Dh, 0Ah, 0 +msgVRAno db "NO ", 0Dh, 0Ah + db " (Interpolated sample rate playing method)" + db 0Dh, 0Ah, 0 + +; -------------------------------------------------------- +; 14/11/2024 (Ref: player.asm, Matan Alfasi, 2017) + +; 23/11/2024 (overwrite splashscreen, a method to solve 64KB limit problem) +; wave volume leds address array +wleds_addr: ; 80*16 bytes + +SplashScreen: + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " _______ ______ _______. ", 221, 219, 222 + db 221, 219, 222, " | \ / __ \ / | ", 221, 219, 222 + db 221, 219, 222, " | .--. | | | | | (----` ", 221, 219, 222 + db 221, 219, 222, " | | | | | | | \ \ ", 221, 219, 222 + db 221, 219, 222, " | '--' | `--' | .----) | ", 221, 219, 222 + db 221, 219, 222, " |_______/ \______/ |_______/ ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " .______ __ ___ ____ ____ _______ .______ ", 221, 219, 222 + db 221, 219, 222, " | _ \ | | / \ \ \ / / | ____|| _ \ ", 221, 219, 222 + db 221, 219, 222, " | |_) | | | / ^ \ \ \/ / | |__ | |_) | ", 221, 219, 222 + db 221, 219, 222, " | ___/ | | / /_\ \ \_ _/ | __| | / ", 221, 219, 222 + db 221, 219, 222, " | | | `----./ _____ \ | | | |____ | |\ \----. ", 221, 219, 222 + db 221, 219, 222, " | _| |_______/__/ \__\ |__| |_______|| _| `._____| ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " WELCOME TO ", 221, 219, 222 + db 221, 219, 222, " DOS PLAYER ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db " " +Template: + db 201, 78 dup(205), 187 + db 186, 33 dup(219), " DOS Player ", 33 dup(219), 186 + db 204, 78 dup(205), 185 + db 186, 33 dup(32), " User Guide ", 33 dup(32), 186 + ; 29/11/2024 + db 186, 6 dup(32), " Play/Pause ", 4 dup(32), "/

Next/Previous", 9 dup(32), 186 + db 186, 6 dup(32), " Stop ", 4 dup(32), " Wave Lighting", 9 dup(32), 186 + db 186, 6 dup(32), " Forwards ", 4 dup(32), "<+>/<-> Inc/Dec Volume", 8 dup(32), 186 + db 186, 6 dup(32), " Backwards ", 4 dup(32), " Quit Program ", 9 dup(32), 186 + db 204, 78 dup(205), 185 + db 186, 6 dup(32), "File Name : ", 4 dup(32), "Bit-Rate : 0 Bits ", 9 dup(32), 186 + db 186, 6 dup(32), "Frequency : 0 Hz ", 4 dup(32), "#-Channels: 0 ", 9 dup(32), 186 + db 200, 78 dup(205), 188 + db 80 dup(32) +improper_samplerate_txt: ; 03/11/2024 +read_error_txt: + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(205) + db 80 dup(32) + db 33 dup(32), "00:00 ", 174, 175, " 00:00", 24 dup(32), "VOL 000%" +; 29/11/2024 +IsInSplash: db 1 +SplashFileName: db "SPLASH.WAV", 0 + +; 23/11/2024 +colors: db 0Fh, 0Bh, 0Ah, 0Ch, 0Eh, 09h, 0Dh, 0Fh + ; white, cyan, green, red, yellow, blue, magenta +ccolor: db 0Bh ; cyan + +; 24/11/2024 +half_buffer: db 1 ; dma half buffer 1 or 2 (0 or 1) + ; (initial value = 1 -> after xor in TuneLoop -> 0) +EOF: + +; BSS + +align 2 + +; 24/11/2024 +; 22/11/2024 +; wave volume leds address array +wleds_addr: rw 80*8 ; rb 2*80*8 + +; 24/11/2024 (SB16 version of playwav8.com -> playwav9.com) +; 14/11/2024 +; 17/02/2017 +bss_start: + +; 13/11/2024 +; ('resb','resw','resd' to 'rb','rw','rd' conversions for FASM) + +; 24/11/2024 +old_irq5v_o: rw 1 +old_irq5v_s: rw 1 +old_irq7v_o: rw 1 +old_irq7v_s: rw 1 +; +IRQnum: rb 1 +; 27/11/2024 +audio_intr: rb 1 +; 25/11/2024 +IRQstatus: rb 1 + +; 18/11/2024 +stopped: rb 1 +tLO: rb 1 +; 19/11/2024 +wleds: rb 1 +wleds_dif: rw 1 +pbuf_s: rw 1 +pbuf_o: rw 1 + +; 25/11/2024 +align 4 + +;;;;;;;;;;;;;; +; 14/11/2024 +; (Ref: player.asm, Matan Alfasi, 2017) +WAVFILEHEADERbuff: +RIFF_ChunkID: rd 1 ; Must be equal to "RIFF" - big-endian + ; 0x52494646 +RIFF_ChunkSize: + rd 1 ; Represents total file size, not + ; including the first 2 fields + ; (Total_File_Size - 8), little-endian +RIFF_Format: + rd 1 ; Must be equal to "WAVE" - big-endian + ; 0x57415645 + +;; WAVE header parameters ("Sub-chunk") +WAVE_SubchunkID: + rd 1 ; Must be equal to "fmt " - big-endian + ; 0x666d7420 +WAVE_SubchunkSize: + rd 1 ; Represents total chunk size +WAVE_AudioFormat: + rw 1 ; PCM (Raw) - is 1, other - is a form + ; of compression, not supported. +WAVE_NumChannels: + rw 1 ; Number of channels, Mono-1, Stereo-2 +WAVE_SampleRate: + rd 1 ; Frequency rate, in Hz (8000, 44100 ...) +WAVE_ByteRate: rd 1 ; SampleRate * NumChannels * BytesPerSample +WAVE_BlockAlign: + rw 1 ; NumChannels * BytesPerSample + ; Number of bytes for one sample. +WAVE_BitsPerSample: + rw 1 ; 8 = 8 bits, 16 = 16 bits, etc. + +;; DATA header parameters +DATA_SubchunkID: + rd 1 ; Must be equal to "data" - big-endian + ; 0x64617461 +DATA_SubchunkSize: + rd 1 ; NumSamples * NumChannels * BytesPerSample + ; Number of bytes in the data. +;;;;;;;;;;;;;; + +; 15/11/2024 +cursortype: rw 1 + +filehandle: rw 1 + +flags: rb 1 ; (END_OF_FILE flag) + rb 1 + +audio_io_base: rw 1 ; Sound Blaster 16 base port address (220h) + +; 29/11/2024 +command: rb 1 +filecount: rb 1 +PSP_CurrentOffset: rw 1 + +; 30/05/2024 +wav_file_name: + rb 80 ; wave file, path name (<= 80 bytes) + + rw 1 +; 24/11/2024 +align 4 + +; 23/11/2024 +turn_on_leds: rw 1 ; turn_on_leds procedure pointer (m8,m16,s8,s16) + +; 14/11/2024 +TotalTime: rw 1 ; Total (WAV File) Playing Time in seconds +ProgressTime: rw 1 +count: rw 1 ; byte count of one (wav file) read +LoadedDataBytes: + rd 1 ; total read/load count + +timerticks: rd 1 ; (to eliminate excessive lookup of events in TuneLoop) + ; (in order to get the emulator/qemu to run correctly) +align 16 + +; 24/11/2024 +dma_buffer: ; 32768 bytes +wav_buffer1: rb dma_buffer_size/2 ; 16384 +wav_buffer2: rb dma_buffer_size/2 ; 16384 + +bss_end: diff --git a/trdos386/programs/16bit/sb16play_com_2024.zip b/trdos386/programs/16bit/sb16play_com_2024.zip new file mode 100644 index 0000000000000000000000000000000000000000..de6fce3039422a649734615865f8c1ca06437b82 GIT binary patch literal 113294 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 IzOew-0 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 Lzft}6|4jKWI7uSZ literal 0 HcmV?d00001

Next/Previous", 9 dup(32), 186 + db 186, 6 dup(32), " Stop ", 4 dup(32), " Wave Lighting", 9 dup(32), 186 + db 186, 6 dup(32), " Forwards ", 4 dup(32), "<+>/<-> Inc/Dec Volume", 8 dup(32), 186 + db 186, 6 dup(32), " Backwards ", 4 dup(32), " Quit Program ", 9 dup(32), 186 + db 204, 78 dup(205), 185 + db 186, 6 dup(32), "File Name : ", 4 dup(32), "Bit-Rate : 0 Bits ", 9 dup(32), 186 + db 186, 6 dup(32), "Frequency : 0 Hz ", 4 dup(32), "#-Channels: 0 ", 9 dup(32), 186 + db 200, 78 dup(205), 188 + db 80 dup(32) +improper_samplerate_txt: ; 03/11/2024 +read_error_txt: + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(205) + db 80 dup(32) + db 33 dup(32), "00:00 ", 174, 175, " 00:00", 24 dup(32), "VOL 000%" +; 28/11/2024 +IsInSplash: db 1 +SplashFileName: db "SPLASH.WAV", 0 + +; 23/11/2024 +colors: db 0Fh, 0Bh, 0Ah, 0Ch, 0Eh, 09h, 0Dh, 0Fh + ; white, cyan, green, red, yellow, blue, magenta +ccolor: db 0Bh ; cyan + +EOF: + +; BSS + +align 2 + +; 22/11/2024 +; wave volume leds address array +;wleds_addr: rw 80*8 ; rb 2*80*8 + +; 14/11/2024 +; 17/02/2017 +bss_start: + +; 13/11/2024 +; ('resb','resw','resd' to 'rb','rw','rd' conversions for FASM) + +; 18/11/2024 +stopped: rb 1 +tLO: rb 1 +; 21/11/2024 +tLP: rb 1 +; 19/11/2024 +wleds: rb 1 +wleds_dif: rw 1 +pbuf_s: rw 1 +pbuf_o: rw 1 + +; 29/11/2024 +command: rb 1 + +; 30/05/2024 +VRA: rb 1 ; Variable Rate Audio Support Status + +;;;;;;;;;;;;;; +; 14/11/2024 +; (Ref: player.asm, Matan Alfasi, 2017) +WAVFILEHEADERbuff: +RIFF_ChunkID: rd 1 ; Must be equal to "RIFF" - big-endian + ; 0x52494646 +RIFF_ChunkSize: + rd 1 ; Represents total file size, not + ; including the first 2 fields + ; (Total_File_Size - 8), little-endian +RIFF_Format: + rd 1 ; Must be equal to "WAVE" - big-endian + ; 0x57415645 + +;; WAVE header parameters ("Sub-chunk") +WAVE_SubchunkID: + rd 1 ; Must be equal to "fmt " - big-endian + ; 0x666d7420 +WAVE_SubchunkSize: + rd 1 ; Represents total chunk size +WAVE_AudioFormat: + rw 1 ; PCM (Raw) - is 1, other - is a form + ; of compression, not supported. +WAVE_NumChannels: + rw 1 ; Number of channels, Mono-1, Stereo-2 +WAVE_SampleRate: + rd 1 ; Frequency rate, in Hz (8000, 44100 ...) +WAVE_ByteRate: rd 1 ; SampleRate * NumChannels * BytesPerSample +WAVE_BlockAlign: + rw 1 ; NumChannels * BytesPerSample + ; Number of bytes for one sample. +WAVE_BitsPerSample: + rw 1 ; 8 = 8 bits, 16 = 16 bits, etc. + +;; DATA header parameters +DATA_SubchunkID: + rd 1 ; Must be equal to "data" - big-endian + ; 0x64617461 +DATA_SubchunkSize: + rd 1 ; NumSamples * NumChannels * BytesPerSample + ; Number of bytes in the data. +;;;;;;;;;;;;;; + +; 15/11/2024 +cursortype: rw 1 + +filehandle: rw 1 + +flags: rb 1 +; 06/11/2023 +ac97_int_ln_reg: rb 1 + +; 28/11/2024 +PSP_CurrentOffset: rw 1 + +; 30/05/2024 +wav_file_name: + rb 80 ; wave file, path name (<= 80 bytes) + + rw 1 + +; 12/11/2016 - Erdogan Tan +bus_dev_fn: rd 1 +dev_vendor: rd 1 + +; 17/02/2017 +; NAMBAR: Native Audio Mixer Base Address Register +; (ICH, Audio D31:F5, PCI Config Space) Address offset: 10h-13h +; NABMBAR: Native Audio Bus Mastering Base Address register +; (ICH, Audio D31:F5, PCI Config Space) Address offset: 14h-17h +NAMBAR: rw 1 ; BAR for mixer +NABMBAR: rw 1 ; BAR for bus master regs + +; 256 byte buffer for descriptor list +BDL_BUFFER: rw 1 ; segment of our 256byte BDL buffer +WAV_BUFFER1: rw 1 ; segment of our WAV storage +; 64k buffers for wav file storage +WAV_BUFFER2: rw 1 ; segment of 2nd wav buffer + +; 09/12/2024 +; 23/11/2024 +;turn_on_leds: rw 1 ; turn_on_leds procedure pointer (m8,m16,s8,s16) + +; 08/11/2023 +; 07/11/2023 +fbs_shift: rb 1 +; 29/11/2024 +filecount: rb 1 + +; 15/11/2024 +loadfromwavfile: + rw 1 ; 'loadfromfile' or load+conversion proc address +loadsize: rw 1 ; (.wav file) read count (bytes) per one time +buffersize: rd 1 ; 16 bit samples (not bytes) + +; 14/11/2024 +TotalTime: rw 1 ; Total (WAV File) Playing Time in seconds +ProgressTime: rw 1 +count: rw 1 ; byte count of one (wav file) read +LoadedDataBytes: + rd 1 ; total read/load count + +timerticks: rd 1 ; (to eliminate excessive lookup of events in tuneloop) + ; (in order to get the emulator/qemu to run correctly) +; 14/11/2024 +bss_end: + +;alignb 2 + +; 32 kilo bytes for temporay buffer +; (for stereo-mono, 8bit/16bit corrections) +; 14/11/2024 +;temp_buffer: rb 32768 +; 17/11/2024 +temp_buffer: rb 50600 ; (44.1 kHZ stereo 12650 samples) +; 18/11/2023 +;temp_buffer: rb 56304 ; (44.1 kHZ stereo 14076 samples) + +;alignb 16 +;bss_end: \ No newline at end of file diff --git a/trdos386/programs/16bit/ac97play_com_2024.zip b/trdos386/programs/16bit/ac97play_com_2024.zip new file mode 100644 index 0000000000000000000000000000000000000000..f8fa189d59d7d8e482a1536cfa53bcd5d9c7897a GIT binary patch literal 132087 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 IzOew-0(WY`7uq+^>Z;+UH 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 kXXuqDmLZ$nuyo!gKXJP{K0D@1rBLDyZ literal 0 HcmV?d00001 diff --git a/trdos386/programs/16bit/playmod4.com b/trdos386/programs/16bit/playmod4.com new file mode 100644 index 0000000000000000000000000000000000000000..bb63317369c4bc899d0b373b985a9242255dab17 GIT binary patch literal 4070 zcmaJ^4NwzT9)G(DONfxH)~0F|RtG(8Ehf}bu^a^f&o8Q|RH)h(B#Yi5XtJ?7Q|r}EadO?%ht-OWkCtDYZMdc({mIL9t5AAZpyRBLg{V6eScBg9G#2$+9J+_hL0Xr%k- zL0J(nDw=QP8$%<>hI60O{I!r}F1=X}QZIW>hx(we6whBLj9AZ+5FURygcP#<86Mxx zpX(n(VIsXDD#eD=-iLVng$al!Ct##_{xV_2dJfk^z3WLpiy#mH|C}7iMGE-nV=INsU4pe}&g~9v4;}K92ys!j|=(8=LO_DOS zH_r3YuK5TIZoxaAEzhR8#l#7`aDN_v{$?8%+)VQ04VUDjOcDtkB30BXt62 z!k`XV3Ah+oF&TxxFUho%K&v0u2`(cOJPhbq{M0LL-=q9E@rkN%E`W0Yi~(>aaFIW= z35Q`IXqM$VfL;60eV5WkT68TKNCU%`gA`agk&Fy z{L!Y4LtS)(TTSc#MGTQN)=r;7Wib_1kMfbEpb-)b|1W|2k|OdcA_3Kiy^*B7H8EAh zWOxp=5MB~xTH!ujgY^?mGzqB|YcnvvtOad`q-SlDD#Iryfjx2lbDpTA=WMacFvc3= zmr(M!riZEOC!mLbkbvJ39z0xzuK{QUs4{%P)wG2{1Axl`d;{@ph=-Qu3WGTCyk9@1 z*>v92!FLMc5ouma7&ybp#=zxXK_q4D3%-*Nv9s>H#OmuHENv|RIR3!ometmcN}jr zbH~@vOPVY=*OTV<8gKd~UT)|i_~t_wN*e*$N?f7=;0>SC*cCMEm-(+7ZfF(nhr3K2 zX#N&kJ(X_?2B(rH~Ge+&CY!I}u8v$x=Of3l@bi6KBIR&KX6){isUtY5|KWc_M=+3x`B57U=j zMIE6p`wDehec3f23tK56bq1e7+GX56LRfIqb$%-)8-2o7-GWa0$nO2Bv%3MmRfk;{ zD$=(j#gGi^EFH;Fy`wstqxz{ZV=A&ul$q!QTC6isen-p89%2Ea-u6AF%3WpMdZ}M6 zeTM_vQx4lx+<@f4?Y%LMid}l2`?6Ht#NNcpeEaahYpM(#FOSdWA@ZX+p}KTr8$6}x zvv*`q^Bf!Z?Z}9n-@YF=O5jdX${xHXh0BPP=bb5U;(FPedcGk@{zoAj`Rpld?;Xjj z){HQ5#=vUDIk6q-3l;4&A0||wTxH-w1xjKDAyha}rx7a7p-y}7Jo7Z4IaP`F6MUwQ zzxZ%str=j`te(Aj$JeO0;hIKY;~mtwx$J33jF8nW8Bc*Rqv>4sbndFLgU?pW zoWUoy5W`}M%nqZa|1*Wlj+Dpa0({`E68F2DVPs6Jtb>VVhhyG~;0%KzXBZNZhx=kp zq0i0r8UyGsF?9?MRF5L|Sl(Q*=z=3;=w7NgqPK>j`f=aGIzTt*5{@3xk4InzH((4* zWX$9`A7@0jW>5gge%+AB=v`_cY9wfUU~iq{9+E2u#i}8(DM2l<$!H~(tDq>u`9wx(vcqND2U>_xmK>7yKD3% z_FKt$j+u_5zG5)zSD^2vUY*8!=99XN^BRR5irWp9}yAdY|} zaA6?V-484MZ)^@%c!^){!TGO+1iy&s{Ne({S#WXS*um?z<3cjoTtB(l1++$Kxg(an z&7L~t_Jzx6D{nzDLuc2Zh^Qgu@4mP{SXwQ_hzNqEaW)_E*_>P)+Hyw+PFDNH zY9Kkm?6aq_!QR1y6|~XExw$5z>?wZfb z9rqQx@1Y$}h9@w2T^2f&Z|234TvNn(21`}QB~8o_*R;|$keef)4F|Ql)0D)h+epu# z4ATL+0e6vfbvIexMammcA;^+P?Kql5mS1Cg^^W67 z%-QTYPp_jJAPK(;po=e^1HTBMqmmX9@X7ogPUgB4ZDdw;faE&ITvWY-ygZWZpCEag zq#OFl$1RUckiYks<>3jE-;xLv-RT?pHRI;tLEze;lIjuOCljpx_L#pvO^|#o*Aco7pi8b%Lc6hZ zCJ0>;4Bi@i?8ehCZ`@J5k3#P-YF$y@KC^|&--ljO1to=f#ni^U;yCJ+l0D{~`A86N zj9(n5jj~zu3e8KYT}XRpNx@?D{wXpS=j}Adp^-K!*0f}iF@90J(exsSH!d>1fXMj8 z!1VkglPN_06mO3)&Xlj9rsY|RO03k1JgWk`%2u?GG9@NHk04`%k1ndHB(GpcaUqpi zQeZ=GF9lc;0x&&(RsPub8?Y2C4x5EVVSaE2xWQF$0n~$9a1vC455aq&0vrH) z!ET_5&`yes(&=~Ywpbb4p0~=`Cu7Umxu|8Jb`Z5@)UKdbJg=PnWNtb8N7Q%!qMZHx z?nH9Ru5R)(tegBbm_zPl=8zdoH<=5%$)%_{Q0qeN7BHIPpI`h!!i!51Q5?eztLEZ@5(~95eJN!`zwK0d@ZtH05v5&b zvns-IQHWk{E8fQJC@Bt(qO>a)t)-Ts=PQ+3P+&1zg9eJp%Jo@_271OS-j(0>C@uIe DW3lW- literal 0 HcmV?d00001 diff --git a/trdos386/programs/16bit/playmod4_com_fasm_2024.zip b/trdos386/programs/16bit/playmod4_com_fasm_2024.zip new file mode 100644 index 0000000000000000000000000000000000000000..1caaea4696baa82ea11d9d8fa09f52c734ad5a47 GIT binary patch literal 26242 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ƶ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 UIyl6CJq7Y_cK(aC#{aeZUqn5QwEzGB literal 0 HcmV?d00001 diff --git a/trdos386/programs/16bit/playwav7.asm b/trdos386/programs/16bit/playwav7.asm new file mode 100644 index 0000000..35e2793 --- /dev/null +++ b/trdos386/programs/16bit/playwav7.asm @@ -0,0 +1,5214 @@ +; **************************************************************************** +; playwav7.asm (for Retro DOS) +; ---------------------------------------------------------------------------- +; PLAYWAV7.COM ! AC'97 (ICH) .WAV PLAYER program by Erdogan TAN +; +; 13/11/2024 +; +; [ Last Modification: 13/11/2024 ] +; +; Modified from PLAYWAV6.COM .wav player program by Erdogan Tan, 30/05/2024 +; (Assembler: NASM 2.15) +; +; Assembler: FASM 1.73 +; fasm playwav7.asm PLAYWAV7.COM +; ---------------------------------------------------------------------------- + +; playwav6.asm (30/05/2024) + +; TUNELOOP version (playing without AC97 interrupt) - 06/11/2023 - Erdogan Tan +; sample rate conversion version - 18/11/2023 - Erdogan Tan + +; CODE + + ; 13/11/2024 +macro sys_msg op1,op2 +{ ; 30/05/2024 + mov si, op1 ; message + mov bl, op2 ; text color + xor bh, bh ; video page 0 + mov ah, 0Eh + call p_msg +} + +; player internal variables and other equates. +BUFFERSIZE equ 64 * 1024 ; 64k file buffer size. +ENDOFFILE equ 1 ; flag for knowing end of file + +use16 + +org 100h + + include 'ac97.inc' ; 17/02/2017 + +_STARTUP: + ; 30/05/2024 + ; Prints the Credits Text. + sys_msg Credits, 0Bh + + ; 30/05/2024 + call setFree ; deallocate unused DOS mem + + ; 17/02/2017 + ; Clear BSS (uninitialized data) area + xor ax, ax ; 0 + mov cx, (bss_end - bss_start)/2 + mov di, bss_start + rep stosw + + ; Detect (& Enable) AC'97 Audio Device + call DetectAC97 + ;jnc short GetFileName + ; 30/05/2024 + jnc short allocate_memory + + ; 30/05/2024 +_dev_not_ready: + ; couldn't find the audio device! + sys_msg noDevMsg, 0Fh + jmp Exit + + ; 30/05/2024 +allocate_memory: + +; allocate 256 bytes of data for DCM_OUT Buffer Descriptor List. (BDL) + + mov ax, BDL_SIZE / 16 + call memAlloc + mov [BDL_BUFFER], ax ; segment + +; allocate 2 buffers, 64k each for now. + + mov ax, BUFFERSIZE / 16 ; 64k for .WAV file + call memAlloc + mov [WAV_BUFFER1], ax ; segment + + mov ax, BUFFERSIZE / 16 + call memAlloc + mov [WAV_BUFFER2], ax + + ; 30/05/2024 +GetFileName: + mov di, wav_file_name + mov si, 80h + mov bl, [si] + xor bh, bh + inc bx + mov byte [si+bx], 0 ; make AsciiZ filename. + inc si +ScanName: + lodsb + test al, al + jz pmsg_usage + cmp al, 20h + je short ScanName ; scan start of name. + stosb + mov ah, 0FFh +a_0: + inc ah +a_1: + lodsb + stosb + cmp al, '.' + je short a_0 + and al, al + jnz short a_1 + + or ah, ah ; if period NOT found, + jnz short _1 ; then add a .WAV extension. +SetExt: + dec di + mov dword [di], '.WAV' + mov byte [di+4], 0 + +_1: + call write_audio_dev_info + +; open the file + ; open existing file + mov al, OPEN ; open existing file + mov dx, wav_file_name + call openFile ; no error? ok. + jnc short _gsr + +; file not found! + sys_msg noFileErrMsg, 0Fh +_exit_: + jmp Exit + +_gsr: + call getSampleRate ; read the sample rate + ; pass it onto codec. + ; 25/11/2023 + jc short _exit_ ; nothing to do + + mov [sample_rate], ax + mov [stmo], cl + mov [bps], dl + + ; 26/11/2023 + mov byte [fbs_shift], 0 ; 0 = stereo and 16 bit + dec cl + jnz short _gsr_1 ; stereo + inc byte [fbs_shift] ; 1 = mono or 8 bit +_gsr_1: + cmp dl, 8 + ja short _gsr_2 ; 16 bit samples + inc byte [fbs_shift] ; 2 = mono and 8 bit +_gsr_2: + ; 29/05/2024 + call write_ac97_pci_dev_info + + ; 30/05/2024 + ; 29/05/2024 + ;call check_vra + + ; 30/05/2024 + call codecConfig ; unmute codec, set rates. + jc init_err + + ; 25/11/2023 + call write_VRA_info + + ; 01/05/2017 + call write_wav_file_info + + ; 25/11/2023 + ; ------------------------------------------ + + ; 18/11/2023 (ich_wav4.asm) + ; 13/11/2023 (ich_wav3.asm) + + cmp byte [VRA], 1 + jb short chk_sample_rate +playwav_48_khz: + mov word [loadfromwavfile], loadFromFile + ;mov word [loadsize], 0 ; 65536 + mov word [buffersize], 32768 ; samples + jmp PlayNow ; 30/05/2024 + +chk_sample_rate: + ; set conversion parameters + ; (for 8, 11.025, 16, 22.050, 24, 32 kHZ) + mov ax, [sample_rate] + cmp ax, 48000 + je short playwav_48_khz +chk_22khz: + cmp ax, 22050 + jne short chk_11khz + cmp byte [bps], 8 + jna short chk_22khz_1 + mov bx, load_22khz_stereo_16_bit + cmp byte [stmo], 1 + jne short chk_22khz_2 + mov bx, load_22khz_mono_16_bit + jmp short chk_22khz_2 +chk_22khz_1: + mov bx, load_22khz_stereo_8_bit + cmp byte [stmo], 1 + jne short chk_22khz_2 + mov bx, load_22khz_mono_8_bit +chk_22khz_2: + mov ax, 7514 ; (442*17) + mov dx, 37 + mov cx, 17 + jmp set_sizes +chk_11khz: + cmp ax, 11025 + jne short chk_44khz + cmp byte [bps], 8 + jna short chk_11khz_1 + mov bx, load_11khz_stereo_16_bit + cmp byte [stmo], 1 + jne short chk_11khz_2 + mov bx, load_11khz_mono_16_bit + jmp short chk_11khz_2 +chk_11khz_1: + mov bx, load_11khz_stereo_8_bit + cmp byte [stmo], 1 + jne short chk_11khz_2 + mov bx, load_11khz_mono_8_bit +chk_11khz_2: + mov ax, 3757 ; (221*17) + mov dx, 74 + mov cx, 17 + jmp set_sizes +chk_44khz: + cmp ax, 44100 + jne short chk_16khz + cmp byte [bps], 8 + jna short chk_44khz_1 + mov bx, load_44khz_stereo_16_bit + cmp byte [stmo], 1 + jne short chk_44khz_2 + mov bx, load_44khz_mono_16_bit + jmp short chk_44khz_2 +chk_44khz_1: + mov bx, load_44khz_stereo_8_bit + cmp byte [stmo], 1 + jne short chk_44khz_2 + mov bx, load_44khz_mono_8_bit +chk_44khz_2: + ;mov ax, 15065 ; (655*23) + ; 18/11/2023 ((file size + bss + stack) <= 64KB) + mov ax, 14076 ; (612 *23) + mov dx, 25 + mov cx, 23 + jmp set_sizes +chk_16khz: + cmp ax, 16000 + jne short chk_8khz + cmp byte [bps], 8 + jna short chk_16khz_1 + mov bx, load_16khz_stereo_16_bit + cmp byte [stmo], 1 + jne short chk_16khz_2 + mov bx, load_16khz_mono_16_bit + jmp short chk_16khz_2 +chk_16khz_1: + mov bx, load_16khz_stereo_8_bit + cmp byte [stmo], 1 + jne short chk_16khz_2 + mov bx, load_16khz_mono_8_bit +chk_16khz_2: + mov ax, 5461 + mov dx, 3 + mov cx, 1 + jmp set_sizes +chk_8khz: + cmp ax, 8000 + jne short chk_24khz + cmp byte [bps], 8 + jna short chk_8khz_1 + mov bx, load_8khz_stereo_16_bit + cmp byte [stmo], 1 + jne short chk_8khz_2 + mov bx, load_8khz_mono_16_bit + jmp short chk_8khz_2 +chk_8khz_1: + mov bx, load_8khz_stereo_8_bit + cmp byte [stmo], 1 + jne short chk_8khz_2 + mov bx, load_8khz_mono_8_bit +chk_8khz_2: + mov ax, 2730 + mov dx, 6 + mov cx, 1 + jmp short set_sizes +chk_24khz: + cmp ax, 24000 + jne short chk_32khz + cmp byte [bps], 8 + jna short chk_24khz_1 + mov bx, load_24khz_stereo_16_bit + cmp byte [stmo], 1 + jne short chk_24khz_2 + mov bx, load_24khz_mono_16_bit + jmp short chk_24khz_2 +chk_24khz_1: + mov bx, load_24khz_stereo_8_bit + cmp byte [stmo], 1 + jne short chk_24khz_2 + mov bx, load_24khz_mono_8_bit +chk_24khz_2: + mov ax, 8192 + mov dx, 2 + mov cx, 1 + jmp short set_sizes +chk_32khz: + cmp ax, 32000 + jne short vra_needed + cmp byte [bps], 8 + jna short chk_32khz_1 + mov bx, load_32khz_stereo_16_bit + cmp byte [stmo], 1 + jne short chk_32khz_2 + mov bx, load_32khz_mono_16_bit + jmp short chk_32khz_2 +chk_32khz_1: + mov bx, load_32khz_stereo_8_bit + cmp byte [stmo], 1 + jne short chk_32khz_2 + mov bx, load_32khz_mono_8_bit +chk_32khz_2: + mov ax, 10922 + mov dx, 3 + mov cx, 2 + ;jmp short set_sizes +set_sizes: + cmp byte [stmo], 1 + je short ss_1 + shl ax, 1 +ss_1: + cmp byte [bps], 8 + jna short ss_2 + ; 16 bit samples + shl ax, 1 +ss_2: + mov [loadsize], ax + mul dx + ;cmp cx, 1 + ;je short ss_3 +;ss_3: + div cx + mov cl, [fbs_shift] + shl ax, cl + shr ax, 1 ; buffer size is 16 bit sample count + mov [buffersize], ax + mov [loadfromwavfile], bx + jmp short PlayNow + +vra_needed: + ; 13/11/2023 + pop ax ; discard return address to the caller + ; 30/05/2024 +vra_err: + sys_msg msg_no_vra, 0Fh + jmp Exit + + ; 30/05/2024 + ; 13/11/2023 (ich_wav4.asm) +loadfromwavfile: + dw loadFromFile +loadsize: ; read from wav file + dw 0 +buffersize: ; write to DMA buffer + dd 32768 ; 16 bit samples (not bytes) + +PlayNow: + ; 30/05/2024 + ; playwav4.asm +_2: + call check4keyboardstop ; flush keyboard buffer + jc short _2 ; 07/11/2023 + + ;call codecConfig ; unmute codec, set rates. + ; 11/11/2023 + ;jc short init_err + +; position file pointer to start in actual wav data +; MUCH improvement should really be done here to check if sample size is +; supported, make sure there are 2 channels, etc. +; + mov ah, 42h + mov al, 0 ; from start of file + mov bx, [filehandle] + xor cx, cx + mov dx, 44 ; jump past .wav/riff header + int 21h + + ; 30/05/2024 + sys_msg nextline, 07h + +; play the .wav file. Most of the good stuff is in here. + + call PlayWav + +; close the .wav file and exit. + +Exit: + call closeFile + + mov ax, 4c00h ; bye ! + int 21h +here: + jmp short here ; do not come here ! + + ; 30/05/2024 +pmsg_usage: + sys_msg msg_usage, 0Bh + jmp short Exit + + ; 30/05/2024 +init_err: + sys_msg msg_init_err, 0Fh + jmp short Exit + + ; 30/05/2024 +error_exit: + sys_msg msg_error, 0Eh + jmp short Exit + + ; -------------------------------------------- + + ; 29/05/2024 (TYRDOS 386, playwav7.s) + ; ((Modified from playwav4.asm, ich_wav4.asm)) + ; ------------------ +;playwav_vra: +PlayWav: + ; create Buffer Descriptor List + + ; Generic Form of Buffer Descriptor + ; --------------------------------- + ; 63 62 61-48 47-32 31-0 + ; --- --- -------- ------- ----- + ; IOC BUP -reserved- Buffer Buffer + ; Length Pointer + ; [15:0] [31:0] + + push es + mov ax, [BDL_BUFFER] ; get segment # for BDL + mov es, ax + + mov cx, 32 / 2 ; make 32 entries in BDL + xor di, di +_0: + movzx eax, word [WAV_BUFFER1] + shl eax, 4 ; convert seg:off ->0:offset + stosd ; store pointer to wavbuffer1 + + ;mov eax, BUFFERSIZE / 2 ; size of buffer (32K) in (16bit) words + ; 13/11/2023 (ich_wav3.asm) - 18/11/2023 (ich_wav4.asm) + mov eax, [buffersize] + + ;or eax, IOC + BUP + ; 06/11/2023 (TUNELOOP version, without interrupt) + or eax, BUP + stosd + + movzx eax, word [WAV_BUFFER2] + shl eax, 4 ; convert seg:off ->0:offset + stosd ; store pointer to wavbuffer2 + + ;mov eax, BUFFERSIZE / 2 ; size of half buffer (32K) + ; 13/11/2023 (ich_wav3.asm) - 18/11/2023 (ich_wav4.asm) + mov eax, [buffersize] + + ;or eax, IOC + BUP + ; 06/11/2023 (TUNELOOP version, without interrupt) + or eax, BUP + stosd + + loop _0 + pop es + + ; load 64k into buffer 1 + mov ax, [WAV_BUFFER1] + ;call loadFromFile + ; 13/11/2023 + call word [loadfromwavfile] + + ; and 64k into buffer 2 + mov ax, [WAV_BUFFER2] + ;call loadFromFile + ; 13/11/2023 + call word [loadfromwavfile] + + ; write NABMBAR+10h with offset of buffer descriptor list + + movzx eax, word [BDL_BUFFER] + shl eax, 4 ; convert seg:off to 0:off + mov dx, [NABMBAR] + add dx, PO_BDBAR_REG ; set pointer to BDL + out dx, eax ; write to AC97 controller + + ; 19/05/2024 + call delay1_4ms + + mov al, 31 + call setLastValidIndex + + ; 19/05/2024 + ;call delay1_4ms + + ; 17/02/2017 + mov dx, [NABMBAR] + add dx, PO_CR_REG ; PCM out Control Register + ;mov al, IOCE + RPBM ; Enable 'Interrupt On Completion' + run + ; ; (LVBI interrupt will not be enabled) + ; 06/11/2023 (TUNELOOP version, without interrupt) + mov al, RPBM + out dx, al ; Start bus master operation. + + ; 19/05/2024 + ; 06/11/2023 + call delay1_4ms ; 30/05/2024 + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + +; while DMA engine is running, examine current index and wait until it hits 1 +; as soon as it's 1, we need to refresh the data in wavbuffer1 with another +; 64k. Likewise when it's playing buffer 2, refresh buffer 1 and repeat. + +; 18/11/2023 +; 08/11/2023 +; 07/11/2023 + +tuneLoop: + ; 30/05/2024 + ; 18/11/2023 (ich_wav4.asm) + ; 08/11/2023 + ; 06/11/2023 + mov al, '1' + call tL0 +tL1: + call updateLVI ; /set LVI != CIV/ + jz short _exitt_ ; 08/11/2023 + call check4keyboardstop + jc short _exitt_ + call getCurrentIndex + test al, BIT0 + jz short tL1 ; loop if buffer 2 is not playing + + ; load buffer 1 + mov ax, [WAV_BUFFER1] + ;call loadFromFile + ; 18/11/2023 + call word [loadfromwavfile] + jc short _exitt_ ; end of file + + mov al, '2' + call tL0 +tL2: + call updateLVI + jz short _exitt_ ; 08/11/2023 + call check4keyboardstop + jc short _exitt_ + call getCurrentIndex + test al, BIT0 + jnz short tL2 ; loop if buffer 1 is not playing + + ; load buffer 2 + mov ax, [WAV_BUFFER2] + ;call loadFromFile + ; 18/11/2023 + call word [loadfromwavfile] + jnc short tuneLoop +_exitt_: + mov dx, [NABMBAR] + add dx, PO_CR_REG ; PCM out Control Register + mov al, 0 + out dx, al ; stop player + + ; 30/05/2024 + mov al, '0' + + ;add al, '0' + ;call tL0 + ; + ;retn + ; 06/11/2023 + ;jmp short tL0 + ;retn + + ; 06/11/2023 +tL0: + ; 08/11/2023 + ; 05/11/2023 + ; 17/02/2017 - Buffer switch test (temporary) + ; 06/11/2023 + ; al = buffer indicator ('1', '2' or '0' -stop- ) + push ds + ;push bx + mov bx, 0B800h ; video display page segment + mov ds, bx + sub bx, bx ; 0 + mov ah, 4Eh + mov [bx], ax ; show current play buffer (1, 2) + ;pop bx + pop ds + retn + + ; ------------------ + + ; 30/05/2024 +DetectAC97: +DetectICH: + ; 22/11/2023 + ; 19/11/2023 + ; 01/11/2023 - TRDOS 386 Kernel v2.0.7 + ;; 10/06/2017 + ;; 05/06/2017 + ;; 29/05/2017 + ;; 28/05/2017 + + ; 19/11/2023 + mov si, valid_ids ; address of Valid ICH (AC97) Device IDs + mov cx, valid_id_count +pfd_1: + lodsd + call pciFindDevice + jnc short d_ac97_1 + loop pfd_1 + + ;stc + retn + +d_ac97_1: + ; eax = BUS/DEV/FN + ; 00000000BBBBBBBBDDDDDFFF00000000 + ; edx = DEV/VENDOR + ; DDDDDDDDDDDDDDDDVVVVVVVVVVVVVVVV + + ; playwav4.asm - 19/05/2024 + + mov [bus_dev_fn], eax + mov [dev_vendor], edx + + ; get ICH base address regs for mixer and bus master + + mov al, NAMBAR_REG + call pciRegRead16 ; read PCI registers 10-11 + ;and dx, IO_ADDR_MASK ; mask off BIT0 + ; 19/05/2024 + and dl, 0FEh + + mov [NAMBAR], dx ; save audio mixer base addr + + mov al, NABMBAR_REG + call pciRegRead16 + ;and dx, IO_ADDR_MASK + ; 19/05/2024 + and dl, 0C0h + + mov [NABMBAR], dx ; save bus master base addr + + mov al, AC97_INT_LINE ; Interrupt line register (3Ch) + call pciRegRead8 ; 17/02/2017 + + mov [ac97_int_ln_reg], dl + + ;clc + + retn + +; FILE.ASM +;open or create file +; +;input: ds:dx-->filename (asciiz) +; al=file Mode (create or open) +;output: none cs:[filehandle] filled +; +openFile: ; (playwav4.asm) + push ax + push cx + mov ah, 3Bh ; start with a mode + add ah, al ; add in create or open mode + xor cx, cx + int 21h + jc short _of1 + ;mov [cs:filehandle], ax + mov [filehandle], ax +_of1: + pop cx + pop ax + retn + +; close the currently open file +; input: none, uses cs:[filehandle] +closeFile: ; (playwav4.asm) + push ax + push bx + cmp word [filehandle], -1 + jz short _cf1 + mov bx, [filehandle] + mov ax,3e00h + int 21h ;close file +_cf1: + pop bx + pop ax + retn + +getSampleRate: ; (playwav4.asm) + ; 08/12/2016 +; reads the sample rate from the .wav file. +; entry: none - assumes file is already open + ; 19/11/2016 - Erdogan Tan +; exit: ax = sample rate (11025, 22050, 44100, 48000) +; cx = number of channels (mono=1, stereo=2) +; dx = bits per sample (8, 16) + + push bx + + mov ah, 42h + mov al, 0 ; from start of file + mov bx, [filehandle] + xor cx, cx + mov dx, 08h ; "WAVE" + int 21h + + mov dx, smpRBuff + mov cx, 28 ; 28 bytes + mov ah, 3fh + int 21h + + cmp word [smpRBuff], 'WA' + jne short gsr_stc + + cmp word [smpRBuff+2], 'VE' + jne short gsr_stc + + cmp word [smpRBuff+12], 1 ; Offset 20, must be 1 (= PCM) + jne short gsr_stc + + + mov cx, [smpRBuff+14] ; return num of channels in CX + mov ax, [smpRBuff+16] ; return sample rate in AX + mov dx, [smpRBuff+26] ; return bits per sample value in DX +gsr_retn: + pop bx + retn + +gsr_stc: + stc + jmp short gsr_retn + +; ---- 30/05/2024 (playwav4.asm, 19/05/2024) + +; MEMALLOC.ASM +;-- SETFREE: Release memory not used ---------------- +;-- Input : ES = address of PSP +;-- Output : none +;-- Register : AX, BX, CL and FLAGS are changed +;-- Info : Since the stack-segment is always the last segment in an +; EXE-file, ES:0000 points to the beginning and SS:SP +; to the end of the program in memory. Through this the +; length of the program can be calculated +; call this routine once at the beginning of the program to free up memory +; assigned to it by DOS. + +setFree: + mov bx, 65536/16 ; 4K paragraphs ; 17/02/2017 (Erdogan Tan) + + mov ah, 4Ah ; pass new length to DOS + int 21h + + retn ; back to caller + ; new size (allocated memory) = 64KB + +memAlloc: +; input: AX = # of paragraphs required +; output: AX = segment of block to use + + push bx + mov bx, ax + mov ah, 48h + int 21h + pop bx + retn + +; ---- + +; ///// + + ; 30/05/2024 (ich_wav4.asm, 19/05/2024) +loadFromFile: + ; 07/11/2023 + + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff_0 ; no + stc + retn + +lff_0: + ; 08/11/2023 + mov bp, ax ; save buffer segment + + mov cl, [fbs_shift] + and cl, cl + jz short lff_1 ; stereo, 16 bit + + mov di, BUFFERSIZE - 1 ; 65535 + + ; fbs_shift = + ; 2 for mono and 8 bit sample (multiplier = 4) + ; 1 for mono or 8 bit sample (multiplier = 2) + shr di, cl + inc di ; 16384 for 8 bit and mono + ; 32768 for 8 bit or mono + + mov ax, cs + mov dx, temp_buffer ; temporary buffer for wav data + + ; 17/02/2017 (stereo/mono, 8bit/16bit corrections) + ; load file into memory + mov cx, di + mov bx, [filehandle] + mov ds, ax + mov ah, 3Fh + int 21h + + mov bx, cs + mov ds, bx + + jc short lff_4 ; error ! + + ; 08/11/2023 + xor dx, dx ; 0 + + and ax, ax + jz short lff_3 + + mov bl, [fbs_shift] + + push es + mov di, dx ; 0 ; [fbs_off] + ;mov bp, [fbs_seg] ; buffer segment + mov es, bp + mov si, temp_buffer ; temporary buffer address + mov cx, ax ; byte count + cmp byte [bps], 8 ; bits per sample (8 or 16) + jne short lff_7 ; 16 bit samples + ; 8 bit samples + dec bl ; shift count, 1 = stereo, 2 = mono + jz short lff_6 ; 8 bit, stereo +lff_5: + ; mono & 8 bit + lodsb + sub al, 80h ; 08/11/2023 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; left channel + stosw ; right channel + loop lff_5 + jmp short lff_9 +lff_6: + ; stereo & 8 bit + lodsb + sub al, 80h ; 08/11/2023 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw + loop lff_6 + jmp short lff_9 +lff_7: + shr cx, 1 ; word count +lff_8: + lodsw + stosw ; left channel + stosw ; right channel + loop lff_8 +lff_9: + pop es + or di, di + jz short endLFF ; 64KB ok + + mov ax, di ; [fbs_off] + dec ax + mov cx, BUFFERSIZE - 1 ; 65535 + jmp short lff_3 + +lff_1: + ;mov bp, ax ; save buffer segment + xor dx, dx + ; load file into memory + mov cx, (BUFFERSIZE / 2) ; 32k chunk + mov bx, [filehandle] + mov ds, ax + mov ah, 3Fh + int 21h + + mov di, cs + mov ds, di + + ; 07/11/2023 + jc short lff_4 ; error ! + + cmp ax, cx + jne short lff_3 +lff_2: + ; 08/11/2023 + add dx, ax + ;mov cx, (BUFFERSIZE / 2) ; 32k chunk + ;mov bx, [filehandle] + mov ds, bp + mov ah, 3Fh + int 21h + + ;mov di, cs + mov ds, di + + jc short lff_4 ; error ! + + cmp ax, cx + je short endLFF +lff_3: + call padfill ; blank pad the remainder + ;clc ; don't exit with CY yet. + or byte [flags], ENDOFFILE ; end of file flag +endLFF: + retn +lff_4: + ; 08/11/2023 + mov al, '!' ; error + call tL0 + + xor ax, ax + jmp short lff_3 + +; entry ds:ax points to last byte in file +; cx=target size +; note: must do byte size fill +; destroys bx, cx +; +padfill: + ; 07/11/2023 + ; 06/11/2023 + ; 17/02/2017 + push es + ;push di + ;mov di, [fbs_seg] + ;mov es, di + mov es, bp + sub cx, ax + ; 08/11/2023 + ;mov di, ax ; (wrong) + mov di, dx ; buffer offset + add di, ax + ; 07/11/2023 + ;add di, [fbs_off] + xor al, al + rep stosb + ;mov [fbs_off], di + ;pop di + pop es + retn +; ///// + +write_audio_dev_info: + ; 30/05/2024 + sys_msg msgAudioCardInfo, 0Fh + retn + +write_wav_file_info: + ; 30/05/2024 + ; 01/05/2017 + sys_msg msgWavFileName, 0Fh + sys_msg wav_file_name, 0Fh + +write_sample_rate: + ; 30/05/2024 + ; 01/05/2017 + mov ax, [sample_rate] + ; ax = sample rate (hertz) + xor dx, dx + mov cx, 10 + div cx + add [msgHertz+4], dl + sub dx, dx + div cx + add [msgHertz+3], dl + sub dx, dx + div cx + add [msgHertz+2], dl + sub dx, dx + div cx + add [msgHertz+1], dl + add [msgHertz], al + + ; 30/05/2024 + sys_msg msgSampleRate, 0Fh + + ; 19/11/2016 + mov dx, msg16Bits + cmp byte [bps], 16 + je short wsr_1 + mov dx, msg8Bits +wsr_1: + ; 30/05/2024 + sys_msg dx, 0Fh + + mov dx, msgMono + cmp byte [stmo], 1 + je short wsr_2 + mov dx, msgStereo +wsr_2: + ; 30/05/2024 + sys_msg dx, 0Fh + ; 30/05/2024 + sys_msg nextline, 07h + retn + +write_ac97_pci_dev_info: + ; 30/05/2024 + ; 06/06/2017 + ; 03/06/2017 + ; BUS/DEV/FN + ; 00000000BBBBBBBBDDDDDFFF00000000 + ; DEV/VENDOR + ; DDDDDDDDDDDDDDDDVVVVVVVVVVVVVVVV + + mov eax, [dev_vendor] + xor bh, bh + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgVendorId+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgVendorId+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgVendorId+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgVendorId], al + shr eax, 16 + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgDevId+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgDevId+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgDevId+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgDevId], al + + mov eax, [bus_dev_fn] + shr eax, 8 + mov bl, al + mov dl, bl + and bl, 7 ; bit 0,1,2 + mov al, [bx+hex_chars] + mov [msgFncNo+1], al + mov bl, dl + shr bl, 3 + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgDevNo+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgDevNo], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgBusNo+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgBusNo], al + + ;mov ax, [ac97_NamBar] + mov ax, [NAMBAR] + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgNamBar+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgNamBar+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgNamBar+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgNamBar], al + + ;mov ax, [ac97_NabmBar] + mov ax, [NABMBAR] + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgNabmBar+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgNabmBar+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgNabmBar+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgNabmBar], al + + xor eax, eax + mov al, [ac97_int_ln_reg] + mov cl, 10 + div cl + add [msgIRQ], ax + and al, al + jnz short _w_ac97imsg_ + mov al, byte [msgIRQ+1] + mov ah, ' ' + mov [msgIRQ], ax +_w_ac97imsg_: + ; 30/05/2024 + sys_msg msgAC97Info, 07h + + retn + + ; 30/05/2024 +write_VRA_info: + sys_msg msgVRAheader, 07h + cmp byte [VRA], 0 + jna short _w_VRAi_no +_w_VRAi_yes: + sys_msg msgVRAyes, 07h + retn +_w_VRAi_no: + sys_msg msgVRAno, 07h + retn + +; 30/05/2024 (playwav6.asm) +; 18/11/2023 (ich_wav3.asm & ich_wav4.asm) +; 15/11/2023 (ich_wav3.asm) +; 14/11/2023 +; 13/11/2023 - Erdogan Tan - (VRA, sample rate conversion) +; -------------------------------------------------------- + +;;Note: At the end of every buffer load, +;; during buffer switch/swap, there will be discontinuity +;; between the last converted sample and the 1st sample +;; of the next buffer. +;; (like as a dot noises vaguely between normal sound samples) +;; -To avoid this defect, the 1st sample of +;; the next buffer may be read from the wav file but +;; the file pointer would need to be set to 1 sample back +;; again via seek system call. Time comsumption problem! - +;; +;; Erdogan Tan - 15/11/2023 +;; +;; ((If entire wav data would be loaded at once.. conversion +;; defect/noise would disappear.. but for DOS, to keep +;; 64KB buffer limit is important also it is important +;; for running under 1MB barrier without HIMEM.SYS or DPMI. +;; I have tested this program by using 2-30MB wav files.)) +;; +;; Test Computer: ASUS desktop/mainboard, M2N4-SLI, 2010. +;; AMD Athlon 64 X2 2200 MHZ CPU. +;; NFORCE4 (CK804) AC97 audio hardware. +;; Realtek ALC850 codec. +;; Retro DOS v4.2 (MSDOS 6.22) operating system. + +load_8khz_mono_8_bit: + ; 15/11/2023 + ; 14/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff8m_0 ; no + stc + retn + +lff8m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + ;jc short lff8m_5 ; error ! + ; 14/11/2023 + jnc short lff8m_6 + jmp lff8m_5 + +lff8m_6: + mov si, dx ; temp_buffer ; temporary buffer address + and ax, ax + ;jz short lff8m_3 + ; 15/11/2023 + jz short lff8_eof + + mov cx, ax ; byte count +lff8m_1: + lodsb + mov [previous_val], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (left channel) + stosw ; original sample (right channel) + ;xor ax, ax + ; 14/11/2023 + mov al, 80h + dec cx + jz short lff8m_2 + mov al, [si] +lff8m_2: + ;mov [next_val], ax + mov bh, al ; [next_val] + mov ah, [previous_val] + add al, ah ; [previous_val] + rcr al, 1 + mov dl, al ; this is interpolated middle (3th) sample + add al, ah ; [previous_val] + rcr al, 1 + mov bl, al ; this is temporary interpolation value + add al, ah ; [previous_val] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (L) + stosw ; this is 1st interpolated sample (R) + mov al, bl + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (L) + stosw ; this is 2nd interpolated sample (R) + mov al, dl + sub al, 80h + shl ax, 8 + stosw ; this is middle (3th) interpolated sample (L) + stosw ; this is middle (3th) interpolated sample (R) + ;mov al, [next_val] + mov al, bh + add al, dl + rcr al, 1 + mov bl, al ; this is temporary interpolation value + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 4th interpolated sample (L) + stosw ; this is 4th interpolated sample (R) + ;mov al, [next_val] + mov al, bh + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 5th interpolated sample (L) + stosw ; this is 5th interpolated sample (R) + ; 8 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff8m_1 + + ; -------------- + +lff8s_3: +lff8m_3: +lff8s2_3: +lff8m2_3: +lff16s_3: +lff16m_3: +lff16s2_3: +lff16m2_3: +lff24_3: +lff32_3: +lff44_3: +lff22_3: +lff11_3: + mov cx, [buffersize] ; 16 bit (48 kHZ, stereo) sample size + shl cx, 1 ; byte count + sub cx, di + jna short lff8m_4 + ;inc cx + shr cx, 1 + xor ax, ax ; fill (remain part of) buffer with zeros + rep stosw +lff8m_4: + push cs + pop es + retn + +lff8_eof: +lff16_eof: +lff24_eof: +lff32_eof: +lff44_eof: +lff22_eof: +lff11_eof: + ; 15/11/2023 + mov byte [flags], ENDOFFILE + jmp short lff8m_3 + +lff8s_5: +lff8m_5: +lff8s2_5: +lff8m2_5: +lff16s_5: +lff16m_5: +lff16s2_5: +lff16m2_5: +lff24_5: +lff32_5: +lff44_5: +lff22_5: +lff11_5: + mov al, '!' ; error + call tL0 + + ;jmp short lff8m_3 + ; 15/11/2023 + jmp lff8_eof + + ; -------------- + +load_8khz_stereo_8_bit: + ; 15/11/2023 + ; 14/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff8s_0 ; no + stc + retn + +lff8s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff8s_5 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;;and ax, ax + ;jz short lff8s_3 + ; 15/11/2023 + jz short lff8_eof + + mov cx, ax ; word count +lff8s_1: + lodsb + mov [previous_val_l], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + lodsb + mov [previous_val_r], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + + ;xor ax, ax + ; 14/11/2023 + mov ax, 8080h + dec cx + jz short lff8s_2 + ; convert 8 bit sample to 16 bit sample + mov ax, [si] +lff8s_2: + mov [next_val_l], al + mov [next_val_r], ah + mov ah, [previous_val_l] + add al, ah + rcr al, 1 + mov dl, al ; this is interpolated middle (3th) sample (L) + add al, ah + rcr al, 1 + mov bl, al ; this is temporary interpolation value (L) + add al, ah + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (L) + mov al, [next_val_r] + mov ah, [previous_val_r] + add al, ah + rcr al, 1 + mov dh, al ; this is interpolated middle (3th) sample (R) + add al, ah + rcr al, 1 + mov bh, al ; this is temporary interpolation value (R) + add al, ah + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (R) + mov al, bl + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (L) + mov al, bh + add al, dh + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (R) + mov al, dl + sub al, 80h + shl ax, 8 + stosw ; this is middle (3th) interpolated sample (L) + mov al, dh + sub al, 80h + shl ax, 8 + stosw ; this is middle (3th) interpolated sample (R) + mov al, [next_val_l] + add al, dl + rcr al, 1 + mov bl, al ; this is temporary interpolation value (L) + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 4th interpolated sample (L) + mov al, [next_val_r] + add al, dh + rcr al, 1 + mov bh, al ; this is temporary interpolation value (R) + add al, dh + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 4th interpolated sample (R) + mov al, [next_val_l] + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 5th interpolated sample (L) + mov al, [next_val_r] + add al, bh + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 5th interpolated sample (R) + ; 8 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + jcxz lff8s_6 + jmp lff8s_1 +lff8s_6: + jmp lff8s_3 + +load_8khz_mono_16_bit: + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff8m2_0 ; no + stc + retn + +lff8m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff8m2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff8m2_8 + ;jmp lff8m2_3 + ; 15/11/2023 + jmp lff8_eof + +lff8m2_8: + mov cx, ax ; word count +lff8m2_1: + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + add ah, 80h ; convert sound level to 0-65535 format + mov [previous_val], ax + xor ax, ax + dec cx + jz short lff8m2_2 + mov ax, [si] +lff8m2_2: + add ah, 80h ; convert sound level to 0-65535 format + mov bp, ax ; [next_val] + add ax, [previous_val] + rcr ax, 1 + mov dx, ax ; this is interpolated middle (3th) sample + add ax, [previous_val] + rcr ax, 1 ; this is temporary interpolation value + mov bx, ax + add ax, [previous_val] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (L) + stosw ; this is 1st interpolated sample (R) + mov ax, bx + add ax, dx + rcr ax, 1 + sub ah, 80h + stosw ; this is 2nd interpolated sample (L) + stosw ; this is 2nd interpolated sample (R) + mov ax, dx + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is middle (3th) interpolated sample (L) + stosw ; this is middle (3th) interpolated sample (R) + mov ax, bp + add ax, dx + rcr ax, 1 + mov bx, ax ; this is temporary interpolation value + add ax, dx + rcr ax, 1 + sub ah, 80h + stosw ; this is 4th interpolated sample (L) + stosw ; this is 4th interpolated sample (R) + mov ax, bp + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 5th interpolated sample (L) + stosw ; this is 5th interpolated sample (R) + ; 8 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff8m2_1 + jmp lff8m2_3 + +lff8m2_7: +lff8s2_7: + jmp lff8m2_5 ; error + +load_8khz_stereo_16_bit: + ; 16/11/2023 + ; 15/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff8s2_0 ; no + stc + retn + +lff8s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff8s2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; 16/11/2023 + ;and ax, ax + jnz short lff8s2_8 + ;jmp lff8s2_3 + ; 15/11/2023 + jmp lff8_eof + +lff8s2_8: + mov cx, ax ; dword count +lff8s2_1: + lodsw + stosw ; original sample (L) + ; 15/11/2023 + add ah, 80h ; convert sound level to 0-65535 format + mov [previous_val_l], ax + lodsw + stosw ; original sample (R) + add ah, 80h ; convert sound level to 0-65535 format + mov [previous_val_r], ax + xor dx, dx + xor ax, ax + ; 16/11/2023 + dec cx + jz short lff8s2_2 + mov ax, [si] + mov dx, [si+2] +lff8s2_2: + add ah, 80h ; convert sound level to 0-65535 format + mov [next_val_l], ax + add dh, 80h ; convert sound level to 0-65535 format + mov [next_val_r], dx + add ax, [previous_val_l] + rcr ax, 1 + mov dx, ax ; this is interpolated middle (3th) sample (L) + add ax, [previous_val_l] + rcr ax, 1 + mov bx, ax ; this is temporary interpolation value (L) + add ax, [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (L) + mov ax, [next_val_r] + add ax, [previous_val_r] + rcr ax, 1 + mov bp, ax ; this is interpolated middle (3th) sample (R) + add ax, [previous_val_r] + rcr ax, 1 + push ax ; * ; this is temporary interpolation value (R) + add ax, [previous_val_r] + rcr ax, 1 + sub ah, 80h + stosw ; this is 1st interpolated sample (R) + mov ax, bx + add ax, dx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 2nd interpolated sample (L) + pop ax ; * + add ax, bp + rcr ax, 1 + sub ah, 80h + stosw ; this is 2nd interpolated sample (R) + mov ax, dx + sub ah, 80h + stosw ; this is middle (3th) interpolated sample (L) + mov ax, bp + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is middle (3th) interpolated sample (R) + mov ax, [next_val_l] + add ax, dx + rcr ax, 1 + mov bx, ax ; this is temporary interpolation value (L) + add ax, dx + rcr ax, 1 + sub ah, 80h + stosw ; this is 4th interpolated sample (L) + mov ax, [next_val_r] + add ax, bp + rcr ax, 1 + push ax ; ** ; this is temporary interpolation value (R) + add ax, bp + rcr ax, 1 + sub ah, 80h + stosw ; this is 4th interpolated sample (R) + mov ax, [next_val_l] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 5th interpolated sample (L) + pop ax ; ** + add ax, [next_val_r] + rcr ax, 1 + sub ah, 80h + stosw ; this is 5th interpolated sample (R) + ; 8 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + jcxz lff8_s2_9 + jmp lff8s2_1 +lff8_s2_9: + jmp lff8s2_3 + +; ..................... + +load_16khz_mono_8_bit: + ; 14/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff16m_0 ; no + stc + retn + +lff16m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff16m_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff16m_8 + ;jmp lff16m_3 + ; 15/11/2023 + jmp lff16_eof + +lff16m_8: + mov cx, ax ; byte count +lff16m_1: + lodsb + ;mov [previous_val], al + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (left channel) + stosw ; original sample (right channel) + ;xor ax, ax + ; 14/11/22023 + mov al, 80h + dec cx + jz short lff16m_2 + mov al, [si] +lff16m_2: + ;mov [next_val], al + mov bh, al + ;add al, [previous_val] + add al, bl + rcr al, 1 + mov dl, al ; this is interpolated middle (temp) sample + ;add al, [previous_val] + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (L) + stosw ; this is 1st interpolated sample (R) + ;mov al, [next_val] + mov al, bh + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (L) + stosw ; this is 2nd interpolated sample (R) + + ; 16 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff16m_1 + jmp lff16m_3 + +lff16m_7: +lff16s_7: + jmp lff16m_5 ; error + +load_16khz_stereo_8_bit: + ; 14/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff16s_0 ; no + stc + retn + +lff16s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff16s_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff16s_8 + ;jmp lff16s_3 + ; 15/11/2023 + jmp lff16_eof + +lff16s_8: + mov cx, ax ; word count +lff16s_1: + lodsb + mov [previous_val_l], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + lodsb + mov [previous_val_r], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + + ;xor ax, ax + ; 14/11/2023 + mov ax, 8080h + dec cx + jz short lff16s_2 + ; convert 8 bit sample to 16 bit sample + mov ax, [si] +lff16s_2: + ;mov [next_val_l], al + ;mov [next_val_r], ah + mov bx, ax + add al, [previous_val_l] + rcr al, 1 + mov dl, al ; this is temporary interpolation value (L) + add al, [previous_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (L) + mov al, bh ; [next_val_r] + add al, [previous_val_r] + rcr al, 1 + mov dh, al ; this is temporary interpolation value (R) + add al, [previous_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (R) + mov al, dl + add al, bl ; [next_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (L) + mov al, dh + add al, bh ; [next_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (R) + + ; 16 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff16s_1 + jmp lff16s_3 + +load_16khz_mono_16_bit: + ; 15/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff16m2_0 ; no + stc + retn + +lff16m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff16m2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff16m2_8 + ;jmp lff16m2_3 + ; 15/11/2023 + jmp lff16_eof + +lff16m2_8: + mov cx, ax ; word count +lff16m2_1: + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val], ax + mov bx, ax + xor ax, ax + dec cx + jz short lff16m2_2 + mov ax, [si] +lff16m2_2: + add ah, 80h ; convert sound level 0 to 65535 format + mov bp, ax ; [next_val] + ;add ax, [previous_val] + add ax, bx + rcr ax, 1 + mov dx, ax ; this is temporary interpolation value + ;add ax, [previous_val] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (L) + stosw ; this is 1st interpolated sample (R) + mov ax, bp + add ax, dx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 2nd interpolated sample (L) + stosw ; this is 2nd interpolated sample (R) + ; 16 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff16m2_1 + jmp lff16m2_3 + +lff16m2_7: +lff16s2_7: + jmp lff16m2_5 ; error + +load_16khz_stereo_16_bit: + ; 16/11/2023 + ; 15/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff16s2_0 ; no + stc + retn + +lff16s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff16s2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + ;shr ax, 1 + shr ax, 2 ; 16/11/2023 + ;and ax, ax + jnz short lff16s2_8 + ;jmp lff16s2_3 + ; 15/11/2023 + jmp lff16_eof + +lff16s2_8: + mov cx, ax ; dword count +lff16s2_1: + lodsw + stosw ; original sample (L) + add ah, 80h ; convert sound level 0 to 65535 format + mov [previous_val_l], ax + lodsw + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + mov [previous_val_r], ax + xor dx, dx + xor ax, ax + ; 16/11/2023 + dec cx + jz short lff16s2_2 + mov ax, [si] + mov dx, [si+2] +lff16s2_2: + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [next_val_l], ax + mov bp, ax + add dh, 80h ; convert sound level 0 to 65535 format + mov [next_val_r], dx + add ax, [previous_val_l] + rcr ax, 1 + mov dx, ax ; this is temporary interpolation value (L) + add ax, [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (L) + mov ax, [next_val_r] + add ax, [previous_val_r] + rcr ax, 1 + mov bx, ax ; this is temporary interpolation value (R) + add ax, [previous_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (R) + ;mov ax, [next_val_l] + mov ax, bp + add ax, dx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 2nd interpolated sample (L) + mov ax, [next_val_r] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 2nd interpolated sample (R) + + ; 16 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff16s2_1 + jmp lff16s2_3 + +; ..................... + +load_24khz_mono_8_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff24m_0 ; no + stc + retn + +lff24m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff24m_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff24m_8 + jmp lff24_eof + +lff24m_8: + mov cx, ax ; byte count +lff24m_1: + lodsb + ;mov [previous_val], al + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (left channel) + stosw ; original sample (right channel) + ;xor ax, ax + mov al, 80h + dec cx + jz short lff24m_2 + mov al, [si] +lff24m_2: + ;;mov [next_val], al + ;mov bh, al + ;add al, [previous_val] + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (L) + stosw ; this is interpolated sample (R) + + ; 24 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff24m_1 + jmp lff24_3 + +lff24m_7: +lff24s_7: + jmp lff24_5 ; error + +load_24khz_stereo_8_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff24s_0 ; no + stc + retn + +lff24s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff24s_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff24s_8 + jmp lff24_eof + +lff24s_8: + mov cx, ax ; word count +lff24s_1: + lodsb + mov [previous_val_l], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + lodsb + mov [previous_val_r], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + + ;xor ax, ax + mov ax, 8080h + dec cx + jz short lff24s_2 + ; convert 8 bit sample to 16 bit sample + mov ax, [si] +lff24s_2: + ;;mov [next_val_l], al + ;;mov [next_val_r], ah + ;mov bx, ax + mov bh, ah + add al, [previous_val_l] + rcr al, 1 + ;mov dl, al + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (L) + mov al, bh ; [next_val_r] + add al, [previous_val_r] + rcr al, 1 + ;mov dh, al + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (R) + + ; 24 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff24s_1 + jmp lff24_3 + +load_24khz_mono_16_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff24m2_0 ; no + stc + retn + +lff24m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff24m2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff24m2_8 + jmp lff24_eof + +lff24m2_8: + mov cx, ax ; word count +lff24m2_1: + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val], ax + ;mov bx, ax + ;xor ax, ax + xor bx, bx + dec cx + jz short lff24m2_2 + ;mov ax, [si + mov bx, [si] +lff24m2_2: + ;add ah, 80h ; convert sound level 0 to 65535 format + ;mov bp, ax ; [next_val] + ;add ax, [previous_val] + ; ax = [previous_val] + ; bx = [next_val] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (L) + stosw ; this is interpolated sample (R) + ; 24 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff24m2_1 + jmp lff24_3 + +lff24m2_7: +lff24s2_7: + jmp lff24_5 ; error + +load_24khz_stereo_16_bit: + ; 16/11/2023 + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff24s2_0 ; no + stc + retn + +lff24s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff24s2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + ;shr ax, 1 + shr ax, 2 ; 16/11/2023 + ;and ax, ax + jnz short lff24s2_8 + jmp lff24_eof + +lff24s2_8: + mov cx, ax ; dword count +lff24s2_1: + lodsw + stosw ; original sample (L) + add ah, 80h ; convert sound level 0 to 65535 format + mov [previous_val_l], ax + lodsw + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val_r], ax + mov bx, ax + xor dx, dx + xor ax, ax + ; 16/11/2023 + dec cx + jz short lff24s2_2 + mov ax, [si] + mov dx, [si+2] +lff24s2_2: + add ah, 80h ; convert sound level 0 to 65535 format + ;;mov [next_val_l], ax + ;mov bp, ax + add dh, 80h ; convert sound level 0 to 65535 format + ;mov [next_val_r], dx + add ax, [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (L) + ;mov ax, [next_val_r] + mov ax, dx + ;add ax, [previous_val_r] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (R) + + ; 24 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff24s2_1 + jmp lff24_3 + +; ..................... + +load_32khz_mono_8_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff32m_0 ; no + stc + retn + +lff32m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff32m_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff32m_8 + jmp lff32_eof + +lff32m_8: + mov cx, ax ; byte count +lff32m_1: + lodsb + ;mov [previous_val], al + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (left channel) + stosw ; original sample (right channel) + ;xor ax, ax + mov al, 80h + dec cx + jz short lff32m_2 + mov al, [si] +lff32m_2: + ;;mov [next_val], al + ;mov bh, al + ;add al, [previous_val] + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (L) + stosw ; this is interpolated sample (R) + + ; different than 8-16-24 kHZ ! + ; 'original-interpolated-original' trio samples + jcxz lff32m_3 + + lodsb + sub al, 80h + shl ax, 8 + stosw ; original sample (left channel) + stosw ; original sample (right channel) + + ; 32 kHZ mono to 48 kHZ stereo conversion of the sample is OK + dec cx + jnz short lff32m_1 +lff32m_3: + jmp lff32_3 + +lff32m_7: +lff32s_7: + jmp lff32_5 ; error + +load_32khz_stereo_8_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff32s_0 ; no + stc + retn + +lff32s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff32s_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff32s_8 + jmp lff32_eof + +lff32s_8: + mov cx, ax ; word count +lff32s_1: + lodsb + mov [previous_val_l], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + lodsb + mov [previous_val_r], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + + ;xor ax, ax + mov ax, 8080h + dec cx + jz short lff32s_2 + ; convert 8 bit sample to 16 bit sample + mov ax, [si] +lff32s_2: + ;;mov [next_val_l], al + ;;mov [next_val_r], ah + ;mov bx, ax + mov bh, ah + add al, [previous_val_l] + rcr al, 1 + ;mov dl, al + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (L) + mov al, bh ; [next_val_r] + add al, [previous_val_r] + rcr al, 1 + ;mov dh, al + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (R) + + ; different than 8-16-24 kHZ ! + ; 'original-interpolated-original' trio samples + jcxz lff32s_3 + + lodsb + sub al, 80h + shl ax, 8 + stosw ; original sample (left channel) + + lodsb + sub al, 80h + shl ax, 8 + stosw ; original sample (right channel) + + ; 32 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + dec cx + jnz short lff32s_1 +lff32s_3: + jmp lff32_3 + +load_32khz_mono_16_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff32m2_0 ; no + stc + retn + +lff32m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff32m2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff32m2_8 + jmp lff32_eof + +lff32m2_8: + mov cx, ax ; word count +lff32m2_1: + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val], ax + ;mov bx, ax + ;xor ax, ax + xor bx, bx + dec cx + jz short lff32m2_2 + ;mov ax, [si + mov bx, [si] +lff32m2_2: + ;add ah, 80h ; convert sound level 0 to 65535 format + ;mov bp, ax ; [next_val] + ;add ax, [previous_val] + ; ax = [previous_val] + ; bx = [next_val] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (L) + stosw ; this is interpolated sample (R) + + ; different than 8-16-24 kHZ ! + ; 'original-interpolated-original' trio samples + jcxz lff32m2_3 + + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + + ; 32 kHZ mono to 48 kHZ stereo conversion of the sample is OK + dec cx + jnz short lff32m2_1 +lff32m2_3: + jmp lff32_3 + +lff32m2_7: +lff32s2_7: + jmp lff32_5 ; error + +load_32khz_stereo_16_bit: + ;16/11/2023 + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff32s2_0 ; no + stc + retn + +lff32s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff32s2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; 16/11/2023 (word left ch + word right ch) + ;and ax, ax + jnz short lff32s2_8 + jmp lff32_eof + +lff32s2_8: + mov cx, ax ; dword count +lff32s2_1: + lodsw + stosw ; original sample (L) + add ah, 80h ; convert sound level 0 to 65535 format + mov [previous_val_l], ax + lodsw + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val_r], ax + mov bx, ax + xor dx, dx + xor ax, ax + ; 16/11/2023 + dec cx + jz short lff32s2_2 + mov ax, [si] + mov dx, [si+2] +lff32s2_2: + add ah, 80h ; convert sound level 0 to 65535 format + ;;mov [next_val_l], ax + ;mov bp, ax + add dh, 80h ; convert sound level 0 to 65535 format + ;mov [next_val_r], dx + add ax, [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (L) + ;mov ax, [next_val_r] + mov ax, dx + ;add ax, [previous_val_r] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (R) + + ; different than 8-16-24 kHZ ! + ; 'original-interpolated-original' trio samples + jcxz lff32s2_3 + + lodsw + stosw ; original sample (L) + lodsw + stosw ; original sample (R) + + ; 32 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + dec cx + jnz short lff32s2_1 +lff32s2_3: + jmp lff32_3 + +; ..................... + +load_22khz_mono_8_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff22m_0 ; no + stc + retn + +lff22m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff22m_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff22m_8 + jmp lff22_eof + +lff22m_8: + mov cx, ax ; byte count +lff22m_9: + mov bp, 5 ; interpolation (one step) loop count + mov byte [faz], 3 ; 3 steps/phases +lff22m_1: + ; 3:2:2:2:2:2::3:2:2:2:2::3:2:2:2:2:2 ; 37/17 + lodsb + mov dl, 80h + dec cx + jz short lff22m_2_1 + mov dl, [si] +lff22m_2_1: + ; al = [previous_val] + ; dl = [next_val] + call interpolating_3_8bit_mono ; 1 of 17 + jcxz lff22m_3 +lff22m_2_2: + lodsb + mov dl, 80h + dec cx + jz short lff22m_2_3 + mov dl, [si] +lff22m_2_3: + call interpolating_2_8bit_mono ; 2 of 17 .. 6 of 17 + jcxz lff22m_3 + dec bp + jnz short lff22m_2_2 + + mov al, [faz] + dec al + jz short lff22m_9 + dec byte [faz] + mov bp, 4 + dec al + jnz short lff22m_1 ; 3:2:2:2:2 ; 7-11 of 17 + inc bp ; 5 + jmp short lff22m_1 ; 3:2:2:2:2:2 ; 12-17 of 17 + +lff22m_3: +lff22s_3: + jmp lff22_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff22m_7: +lff22s_7: + jmp lff22_5 ; error + +load_22khz_stereo_8_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff22s_0 ; no + stc + retn + +lff22s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff22s_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff22s_8 + jmp lff22_eof + +lff22s_8: + mov cx, ax ; word count +lff22s_9: + mov bp, 5 ; interpolation (one step) loop count + mov byte [faz], 3 ; 3 steps/phase +lff22s_1: + ; 3:2:2:2:2:2::3:2:2:2:2::3:2:2:2:2:2 ; 37/17 + lodsw + mov dx, 8080h + dec cx + jz short lff22s_2_1 + mov dx, [si] +lff22s_2_1: + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dl = [next_val_r] + call interpolating_3_8bit_stereo ; 1 of 17 + jcxz lff22s_3 +lff22s_2_2: + lodsw + mov dx, 8080h + dec cx + jz short lff22s_2_3 + mov dx, [si] +lff22s_2_3: + call interpolating_2_8bit_stereo ; 2 of 17 .. 6 of 17 + jcxz lff22s_3 + dec bp + jnz short lff22s_2_2 + + mov al, [faz] + dec al + jz short lff22s_9 + dec byte [faz] + mov bp, 4 + dec al + jnz short lff22s_1 ; 3:2:2:2:2 ; 7-11 of 17 + inc bp ; 5 + jmp short lff22s_1 ; 3:2:2:2:2:2 ; 12-17 of 17 + +load_22khz_mono_16_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff22m2_0 ; no + stc + retn + +lff22m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff22m2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff22m2_8 + jmp lff22_eof + +lff22m2_8: + mov cx, ax ; word count +lff22m2_9: + mov bp, 5 ; interpolation (one step) loop count + mov byte [faz], 3 ; 3 steps/phases +lff22m2_1: + ; 3:2:2:2:2:2::3:2:2:2:2::3:2:2:2:2:2 ; 37/17 + lodsw + xor dx, dx + dec cx + jz short lff22m2_2_1 + mov dx, [si] +lff22m2_2_1: + ; ax = [previous_val] + ; dx = [next_val] + call interpolating_3_16bit_mono ; 1 of 17 + jcxz lff22m2_3 +lff22m2_2_2: + lodsw + xor dx, dx + dec cx + jz short lff22m2_2_3 + mov dx, [si] +lff22m2_2_3: + call interpolating_2_16bit_mono ; 2 of 17 .. 6 of 17 + jcxz lff22m2_3 + dec bp + jnz short lff22m2_2_2 + + mov al, [faz] + dec al + jz short lff22m2_9 + dec byte [faz] + mov bp, 4 + dec al + jnz short lff22m2_1 ; 3:2:2:2:2 ; 7-11 of 17 + inc bp ; 5 + jmp short lff22m2_1 ; 3:2:2:2:2:2 ; 12-17 of 17 + +lff22m2_3: +lff22s2_3: + jmp lff22_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff22m2_7: +lff22s2_7: + jmp lff22_5 ; error + +load_22khz_stereo_16_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff22s2_0 ; no + stc + retn + +lff22s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff22s2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; dword (left chan word + right chan word) + ;and ax, ax + jnz short lff22s2_8 + jmp lff22_eof + +lff22s2_8: + mov cx, ax ; dword count +lff22s2_9: + mov bp, 5 ; interpolation (one step) loop count + mov byte [faz], 3 ; 3 steps/phase +lff22s2_1: + ; 3:2:2:2:2:2::3:2:2:2:2::3:2:2:2:2:2 ; 37/17 + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + dec cx + jnz short lff22s2_2_1 + xor dx, dx ; 0 + mov [next_val_l], dx +lff22s2_2_1: + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + call interpolating_3_16bit_stereo ; 1 of 17 + jcxz lff22s2_3 +lff22s2_2_2: + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + dec cx + jnz short lff22s2_2_3 + xor dx, dx ; 0 + mov [next_val_l], dx +lff22s2_2_3: + call interpolating_2_16bit_stereo ; 2 of 17 .. 6 of 17 + jcxz lff22s2_3 + dec bp + jnz short lff22s2_2_2 + + mov al, [faz] + dec al + jz short lff22s2_9 + dec byte [faz] + mov bp, 4 + dec al + jnz short lff22s2_1 ; 3:2:2:2:2 ; 7-11 of 17 + inc bp ; 5 + jmp short lff22s2_1 ; 3:2:2:2:2:2 ; 12-17 of 17 + +; ..................... + +load_11khz_mono_8_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff11m_0 ; no + stc + retn + +lff11m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff11m_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff11m_8 + jmp lff11_eof + +lff11m_8: + mov cx, ax ; byte count +lff11m_9: + mov bp, 6 ; interpolation (one step) loop count +lff11m_1: + ; 5:4:4::5:4:4::5:4:4::5:4:4::5:4:4::5:4 ; 74/17 + lodsb + mov dl, 80h + dec cx + jz short lff11m_2_1 + mov dl, [si] +lff11m_2_1: + ; al = [previous_val] + ; dl = [next_val] + call interpolating_5_8bit_mono + jcxz lff11m_3 +lff11m_2_2: + lodsb + mov dl, 80h + dec cx + jz short lff11m_2_3 + mov dl, [si] +lff11m_2_3: + call interpolating_4_8bit_mono + jcxz lff11m_3 + + dec bp + jz short lff11m_9 + + lodsb + mov dl, 80h + dec cx + jz short lff11m_2_4 + mov dl, [si] +lff11m_2_4: + call interpolating_4_8bit_mono + jcxz lff11m_3 + jmp short lff11m_1 + +lff11m_3: +lff11s_3: + jmp lff11_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff11m_7: +lff11s_7: + jmp lff11_5 ; error + +load_11khz_stereo_8_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff11s_0 ; no + stc + retn + +lff11s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff11s_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff11s_8 + jmp lff11_eof + +lff11s_8: + mov cx, ax ; word count +lff11s_9: + mov bp, 6 ; interpolation (one step) loop count +lff11s_1: + ; 5:4:4::5:4:4::5:4:4::5:4:4::5:4:4::5:4 ; 74/17 + lodsw + mov dx, 8080h + dec cx + jz short lff11s_2_1 + mov dx, [si] +lff11s_2_1: + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dl = [next_val_r] + call interpolating_5_8bit_stereo + jcxz lff11s_3 +lff11s_2_2: + lodsw + mov dx, 8080h + dec cx + jz short lff11s_2_3 + mov dx, [si] +lff11s_2_3: + call interpolating_4_8bit_stereo + jcxz lff11s_3 + + dec bp + jz short lff11s_9 + + lodsw + mov dx, 8080h + dec cx + jz short lff11s_2_4 + mov dx, [si] +lff11s_2_4: + call interpolating_4_8bit_stereo + jcxz lff11s_3 + jmp short lff11s_1 + +load_11khz_mono_16_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff11m2_0 ; no + stc + retn + +lff11m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff11m2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff11m2_8 + jmp lff11_eof + +lff11m2_8: + mov cx, ax ; word count +lff11m2_9: + mov bp, 6 ; interpolation (one step) loop count +lff11m2_1: + ; 5:4:4::5:4:4::5:4:4::5:4:4::5:4:4::5:4 ; 74/17 + lodsw + xor dx, dx + dec cx + jz short lff11m2_2_1 + mov dx, [si] +lff11m2_2_1: + ; ax = [previous_val] + ; dx = [next_val] + call interpolating_5_16bit_mono + jcxz lff11m2_3 +lff11m2_2_2: + lodsw + xor dx, dx + dec cx + jz short lff11m2_2_3 + mov dx, [si] +lff11m2_2_3: + call interpolating_4_16bit_mono + jcxz lff11m2_3 + + dec bp + jz short lff11m2_9 + + lodsw + xor dx, dx + dec cx + jz short lff11m2_2_4 + mov dx, [si] +lff11m2_2_4: + call interpolating_4_16bit_mono + jcxz lff11m2_3 + jmp short lff11m2_1 + +lff11m2_7: +lff11s2_7: + jmp lff11_5 ; error + +load_11khz_stereo_16_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff11s2_0 ; no + stc + retn + +lff11s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff11s2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; dword (left chan word + right chan word) + ;and ax, ax + jnz short lff11s2_8 + jmp lff11_eof + +lff11m2_3: +lff11s2_3: + jmp lff11_3 ; padfill + ; (put zeros in the remain words of the buffer) + +lff11s2_8: + mov cx, ax ; dword count +lff11s2_9: + mov bp, 6 ; interpolation (one step) loop count +lff11s2_1: + ; 5:4:4::5:4:4::5:4:4::5:4:4::5:4:4::5:4 ; 74/17 + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + mov [next_val_r], dx + dec cx + jnz short lff11s2_2_1 + xor dx, dx ; 0 + mov [next_val_l], dx + mov [next_val_r], dx +lff11s2_2_1: + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + call interpolating_5_16bit_stereo + jcxz lff11s2_3 +lff11s2_2_2: + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + mov [next_val_r], dx + dec cx + jnz short lff11s2_2_3 + xor dx, dx ; 0 + mov [next_val_l], dx + mov [next_val_r], dx +lff11s2_2_3: + call interpolating_4_16bit_stereo + jcxz lff11s2_3 + + dec bp + jz short lff11s2_9 + + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + mov [next_val_r], dx + dec cx + jnz short lff11s2_2_4 + xor dx, dx ; 0 + mov [next_val_l], dx + mov [next_val_r], dx +lff11s2_2_4: + call interpolating_4_16bit_stereo + jcxz lff11s2_3 + jmp short lff11s2_1 + +; ..................... + +load_44khz_mono_8_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff44m_0 ; no + stc + retn + +lff44m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff44m_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff44m_8 + jmp lff44_eof + +lff44m_8: + mov cx, ax ; byte count +lff44m_9: + mov bp, 10 ; interpolation (one step) loop count + mov byte [faz], 2 ; 2 steps/phases +lff44m_1: + ; 2:1:1:1:1:1:1:1:1:1:1:: ; 25/23 + ; 2:1:1:1:1:1:1:1:1:1:1:1 + lodsb + mov dl, 80h + dec cx + jz short lff44m_2_1 + mov dl, [si] +lff44m_2_1: + ; al = [previous_val] + ; dl = [next_val] + call interpolating_2_8bit_mono + jcxz lff44m_3 +lff44m_2_2: + lodsb + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; (L) + stosw ; (R) + + dec cx + jz short lff44m_3 + dec bp + jnz short lff44m_2_2 + + dec byte [faz] + jz short lff44m_9 + mov bp, 11 + jmp short lff44m_1 + +lff44m_3: +lff44s_3: + jmp lff44_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff44m_7: +lff44s_7: + jmp lff44_5 ; error + +load_44khz_stereo_8_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff44s_0 ; no + stc + retn + +lff44s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff44s_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff44s_8 + jmp lff44_eof + +lff44s_8: + mov cx, ax ; word count +lff44s_9: + mov bp, 10 ; interpolation (one step) loop count + mov byte [faz], 2 ; 2 steps/phase +lff44s_1: + ; 2:1:1:1:1:1:1:1:1:1:1:: ; 25/23 + ; 2:1:1:1:1:1:1:1:1:1:1:1 + lodsw + mov dx, 8080h + dec cx + jz short lff44s_2_1 + mov dx, [si] +lff44s_2_1: + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dl = [next_val_r] + call interpolating_2_8bit_stereo + jcxz lff44s_3 +lff44s_2_2: + lodsb + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; (L) + lodsb + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; (R) + + dec cx + jz short lff44s_3 + dec bp + jnz short lff44s_2_2 + + dec byte [faz] + jz short lff44s_9 + mov bp, 11 + jmp short lff44s_1 + +load_44khz_mono_16_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff44m2_0 ; no + stc + retn + +lff44m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff44m2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff44m2_8 + jmp lff44_eof + +lff44m2_8: + mov cx, ax ; word count +lff44m2_9: + mov bp, 10 ; interpolation (one step) loop count + mov byte [faz], 2 ; 2 steps/phases +lff44m2_1: + ; 2:1:1:1:1:1:1:1:1:1:1:: ; 25/23 + ; 2:1:1:1:1:1:1:1:1:1:1:1 + lodsw + xor dx, dx + dec cx + jz short lff44m2_2_1 + mov dx, [si] +lff44m2_2_1: + ; ax = [previous_val] + ; dx = [next_val] + call interpolating_2_16bit_mono + jcxz lff44m2_3 +lff44m2_2_2: + lodsw + stosw ; (L)eft Channel + stosw ; (R)ight Channel + + dec cx + jz short lff44m2_3 + dec bp + jnz short lff44m2_2_2 + + dec byte [faz] + jz short lff44m2_9 + mov bp, 11 + jmp short lff44m2_1 + +lff44m2_3: +lff44s2_3: + jmp lff44_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff44m2_7: +lff44s2_7: + jmp lff44_5 ; error + +load_44khz_stereo_16_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff44s2_0 ; no + stc + retn + +lff44s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff44s2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; dword (left chan word + right chan word) + ;and ax, ax + jnz short lff44s2_8 + jmp lff44_eof + +lff44s2_8: + mov cx, ax ; dword count +lff44s2_9: + mov bp, 10 ; interpolation (one step) loop count + mov byte [faz], 2 ; 2 steps/phase +lff44s2_1: + ; 2:1:1:1:1:1:1:1:1:1:1:: ; 25/23 + ; 2:1:1:1:1:1:1:1:1:1:1:1 + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + dec cx + jnz short lff44s2_2_1 + xor dx, dx ; 0 + mov [next_val_l], dx +lff44s2_2_1: + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + call interpolating_2_16bit_stereo + jcxz lff44s2_3 +lff44s2_2_2: + ;lodsw + ;stosw ; (L) + ;lodsw + ;stosw ; (R) + movsw ; (L)eft Channel + movsw ; (R)ight Channel + + dec cx + jz short lff44s2_3 + dec bp + jnz short lff44s2_2_2 + + dec byte [faz] + jz short lff44s2_9 + mov bp, 11 + jmp short lff44s2_1 + +; ..................... + +interpolating_3_8bit_mono: + ; 16/11/2023 + ; al = [previous_val] + ; dl = [next_val] + ; original-interpolated-interpolated + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + stosw ; original sample (R) + mov al, bl + add al, dl + rcr al, 1 + mov bh, al ; interpolated middle (temporary) + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov al, bh + add al, dl ; [next_val] + rcr al, 1 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + retn + +interpolating_3_8bit_stereo: + ; 16/11/2023 + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dh = [next_val_r] + ; original-interpolated-interpolated + mov bx, ax + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + mov al, bh + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + push ax ; * ; al = interpolated middle (L) (temporary) + add al, bl ; [previous_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + push ax ; ** ; al = interpolated middle (R) (temporary) + add al, bh ; [previous_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (R) + pop bx ; ** + pop ax ; * + add al, dl ; [next_val_l] + rcr al, 1 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + mov al, bl + add al, dh ; [next_val_r] + rcr al, 1 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (R) + retn + +interpolating_2_8bit_mono: + ; 16/11/2023 + ; al = [previous_val] + ; dl = [next_val] + ; original-interpolated + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + stosw ; original sample (R) + mov al, bl + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample (L) + stosw ; interpolated sample (R) + retn + +interpolating_2_8bit_stereo: + ; 16/11/2023 + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dh = [next_val_r] + ; original-interpolated + mov bx, ax + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + mov al, bh + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + mov al, bl ; [previous_val_l] + add al, dl ; [next_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample (R) + retn + +interpolating_3_16bit_mono: + ; 16/11/2023 + ; ax = [previous_val] + ; dx = [next_val] + ; original-interpolated-interpolated + + stosw ; original sample (L) + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + push ax ; * ; [previous_val] + add dh, 80h + add ax, dx + rcr ax, 1 + pop bx ; * + xchg bx, ax ; bx = interpolated middle (temporary) + add ax, bx ; [previous_val] + interpolated middle + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov ax, bx + add ax, dx ;interpolated middle + [next_val] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + retn + +interpolating_3_16bit_stereo: + ; 16/11/2023 + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + ; original-interpolated-interpolated + + xchg ax, bx + stosw ; original sample (L) + xchg ax, bx + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + push ax ; * ; [previous_val_r] + add bh, 80h + add byte [next_val_l+1], 80h + mov ax, [next_val_l] + add ax, bx ; [previous_val_l] + rcr ax, 1 + xchg ax, bx ; ax = [previous_val_l] + add ax, bx ; bx = interpolated middle (L) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + pop ax ; * + add dh, 80h ; convert sound level 0 to 65535 format + push dx ; * ; [next_val_r] + xchg ax, dx + add ax, dx ; [next_val_r] + [previous_val_r] + rcr ax, 1 ; / 2 + push ax ; ** ; interpolated middle (R) + add ax, dx ; + [previous_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (R) + mov ax, [next_val_l] + add ax, bx ; + interpolated middle (L) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + pop ax ; ** + pop dx ; * + add ax, dx ; interpolated middle + [next_val_r] + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + retn + + +interpolating_2_16bit_mono: + ; 16/11/2023 + ; ax = [previous_val] + ; dx = [next_val] + ; original-interpolated + + stosw ; original sample (L) + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + add dh, 80h + add ax, dx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample (L) + stosw ; interpolated sample (R) + retn + +interpolating_2_16bit_stereo: + ; 16/11/2023 + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + ; original-interpolated + + xchg ax, bx + stosw ; original sample (L) + xchg ax, bx + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + add dh, 80h + add ax, dx ; [previous_val_r] + [next_val_r] + rcr ax, 1 ; / 2 + push ax ; * ; interpolated sample (R) + mov ax, [next_val_l] + add ah, 80h + add bh, 80h + add ax, bx ; [next_val_l] + [previous_val_l] + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample (L) + pop ax ; * + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample (R) + retn + +interpolating_5_8bit_mono: + ; 17/11/2023 + ; al = [previous_val] + ; dl = [next_val] + ; original-interpltd-interpltd-interpltd-interpltd + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + stosw ; original sample (R) + mov al, bl + add al, dl + rcr al, 1 + mov bh, al ; interpolated middle (temporary) + add al, bl ; [previous_val] + rcr al, 1 + mov dh, al ; interpolated 1st quarter (temporary) + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov al, bh + add al, dh + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + mov al, bh + add al, dl ; [next_val] + rcr al, 1 + mov dh, al ; interpolated 3rd quarter (temporary) + add al, bh + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (L) + stosw ; interpolated sample 3 (R) + mov al, dh + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 4 (L) + stosw ; interpolated sample 4 (R) + retn + +interpolating_5_8bit_stereo: + ; 17/11/2023 + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dh = [next_val_r] + ; original-interpltd-interpltd-interpltd-interpltd + mov bx, ax + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + mov al, bh + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + push dx ; * + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + push ax ; ** ; al = interpolated middle (L) (temporary) + add al, bl ; [previous_val_l] + rcr al, 1 + xchg al, bl + add al, bl ; bl = interpolated 1st quarter (L) (temp) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + push ax ; *** ; al = interpolated middle (R) (temporary) + add al, bh ; [previous_val_r] + rcr al, 1 + xchg al, bh + add al, bh ; bh = interpolated 1st quarter (R) (temp) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (R) + pop dx ; *** + pop ax ; ** ; al = interpolated middle (L) (temporary) + xchg al, bl ; al = interpolated 1st quarter (L) (temp) + add al, bl ; bl = interpolated middle (L) (temporary) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + mov al, dl ; interpolated middle (R) (temporary) + xchg al, bh ; al = interpolated 1st quarter (R) (temp) + add al, bh ; bh = interpolated middle (R) (temporary) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (R) + pop dx ; * + mov al, bl ; interpolated middle (L) (temporary) + add al, dl ; [next_val_l] + rcr al, 1 + xchg al, bl ; al = interpolated middle (R) (temporary) + add al, bl ; bl = interpolated 3rd quarter (L) (temp) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (L) + mov al, bh + add al, dh ; interpolated middle (R) + [next_val_r] + rcr al, 1 + xchg al, bh ; al = interpolated middle (R) + add al, bh ; bh = interpolated 3rd quarter (R) (temp) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (R) + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 4 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 4 (R) + retn + +interpolating_4_8bit_mono: + ; 17/11/2023 + ; al = [previous_val] + ; dl = [next_val] + ; original-interpolated-interpolated-interpolated + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + stosw ; original sample (R) + mov al, bl + add al, dl + rcr al, 1 + xchg al, bl ; al = [previous_val] + add al, bl ; bl = interpolated middle (sample 2) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov al, bl ; interpolated middle (sample 2) + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + mov al, bl + add al, dl ; [next_val] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (L) + stosw ; interpolated sample 3 (R) + retn + +interpolating_4_8bit_stereo: + ; 17/11/2023 + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dh = [next_val_r] + ; original-interpolated-interpolated-interpolated + mov bx, ax + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + mov al, bh + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + xchg al, bl ; al = [previous_val_l] + add al, bl ; bl = interpolated middle (L) (sample 2) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + xchg al, bh ; al = [previous_val_h] + add al, bh ; bh = interpolated middle (R) (sample 2) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (R) + mov al, bl ; interpolated middle (L) (sample 2) + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + mov al, bh ; interpolated middle (L) (sample 2) + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (R) + retn + +interpolating_5_16bit_mono: + ; 18/11/2023 + ; ax = [previous_val] + ; dx = [next_val] + ; original-interpltd-interpltd-interpltd-interpltd + stosw ; original sample (L) + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + mov bx, ax ; [previous_val] + add dh, 80h + add ax, dx + rcr ax, 1 + push ax ; * ; interpolated middle (temporary) + add ax, bx ; interpolated middle + [previous_val] + rcr ax, 1 + push ax ; ** ; interpolated 1st quarter (temporary) + add ax, bx ; 1st quarter + [previous_val] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + pop ax ; ** + pop bx ; * + add ax, bx ; 1st quarter + middle + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + mov ax, bx + add ax, dx ; interpolated middle + [next_val] + rcr ax, 1 + push ax ; * ; interpolated 3rd quarter (temporary) + add ax, bx ; + interpolated middle + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (L) + stosw ; interpolated sample 3 (R) + pop ax ; * + add ax, dx ; 3rd quarter + [next_val] + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 4 (L) + stosw ; interpolated sample 4 (R) + retn + +interpolating_5_16bit_stereo: + ; 18/11/2023 + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; [next_val_r] + ; original-interpltd-interpltd-interpltd-interpltd + push cx ; ! + xchg ax, bx + stosw ; original sample (L) + xchg ax, bx + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + push ax ; * ; [previous_val_r] + add bh, 80h + add byte [next_val_l+1], 80h + mov ax, [next_val_l] + add ax, bx ; [previous_val_l] + rcr ax, 1 + mov cx, ax ; interpolated middle (L) + add ax, bx + rcr ax, 1 + mov dx, ax ; interpolated 1st quarter (L) + add ax, bx ; [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + mov ax, cx + add ax, dx ; middle (L) + 1st quarter (L) + rcr ax, 1 ; / 2 + mov bx, ax ; interpolated sample 2 (L) + pop dx ; * ; [previous_val_r] + mov ax, dx + add byte [next_val_r+1], 80h + add ax, [next_val_r] + rcr ax, 1 + push ax ; * ; interpolated middle (R) + add ax, dx + rcr ax, 1 + push ax ; ** ; interpolated 1st quarter (R) + add ax, dx ; [previous_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (R) + mov ax, bx + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + pop ax ; ** + pop dx ; * + add ax, dx ; 1st quarter (R) + middle (R) + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (R) + mov ax, cx + add ax, [next_val_l] + rcr ax, 1 + push ax ; * ; interpolated 3rd quarter (L) + add ax, cx ; interpolated middle (L) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (L) + mov ax, dx + add ax, [next_val_r] + rcr ax, 1 + push ax ; ** ; interpolated 3rd quarter (R) + add ax, dx ; interpolated middle (R) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (R) + pop bx ; ** + pop ax ; * + add ax, [next_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 4 (L) + mov ax, bx + add ax, [next_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 4 (R) + pop cx ; ! + retn + +interpolating_4_16bit_mono: + ; 18/11/2023 + ; ax = [previous_val] + ; dx = [next_val] + ; original-interpolated + + stosw ; original sample (L) + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + mov bx, ax ; [previous_val] + add dh, 80h + add ax, dx ; [previous_val] + [next_val] + rcr ax, 1 + xchg ax, bx + add ax, bx ; [previous_val] + interpolated middle + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov ax, bx ; interpolated middle + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + mov ax, bx + add ax, dx ; interpolated middle + [next_val] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (L) + stosw ; interpolated sample 3 (R) + retn + +interpolating_4_16bit_stereo: + ; 18/11/2023 + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; [next_val_r] + ; original-interpolated-interpolated-interpolated + xchg ax, bx + stosw ; original sample (L) + xchg ax, bx + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + mov dx, ax ; [previous_val_r] + add bh, 80h + add byte [next_val_l+1], 80h + mov ax, [next_val_l] + add ax, bx ; [previous_val_l] + rcr ax, 1 + xchg ax, bx + add ax, bx ; bx = interpolated middle (L) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + add byte [next_val_r+1], 80h + mov ax, dx ; [previous_val_r] + add ax, [next_val_r] + rcr ax, 1 + xchg ax, dx + add ax, dx ; dx = interpolated middle (R) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (R) + mov ax, bx + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + mov ax, dx + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (R) + mov ax, bx + add ax, [next_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (L) + mov ax, dx + add ax, [next_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (R) + retn + +; 13/11/2023 +previous_val: +previous_val_l: dw 0 +previous_val_r: dw 0 +next_val: +next_val_l: dw 0 +next_val_r: dw 0 + +; 16/11/2023 +faz: db 0 + +; -------------------------------------------------------- +; 27/05/2024 - (TRDOS 386 Kernel) audio.s +; -------------------------------------------------------- + +NOT_PCI32_PCI16 EQU 03FFFFFFFh ; NOT BIT31+BIT30 ; 19/03/2017 +NOT_BIT31 EQU 7FFFFFFFh + +pciFindDevice: + ; 19/11/2023 + ; 03/04/2017 ('pci.asm', 20/03/2017) + ; + ; scan through PCI space looking for a device+vendor ID + ; + ; Entry: EAX=Device+Vendor ID + ; + ; Exit: EAX=PCI address if device found + ; EDX=Device+Vendor ID + ; CY clear if found, set if not found. EAX invalid if CY set. + ; + ; Destroys: ebx, edi ; 19/11/2023 + + ; 19/11/2023 + mov ebx, eax + mov edi, 80000000h +nextPCIdevice: + mov eax, edi ; read PCI registers + call pciRegRead32 + ; 19/11/2023 + cmp edx, ebx + je short PCIScanExit ; found + ; 19/11/2023 + cmp edi, 80FFF800h + jnb short pfd_nf ; not found + add edi, 100h + jmp short nextPCIdevice +pfd_nf: + stc + retn +PCIScanExit: + ;pushf + mov eax, NOT_BIT31 ; 19/03/2017 + and eax, edi ; return only bus/dev/fn # + retn + +pciRegRead: + ; 30/05/2024 + ; 03/04/2017 ('pci.asm', 20/03/2017) + ; + ; 8/16/32bit PCI reader + ; + ; Entry: EAX=PCI Bus/Device/fn/register number + ; BIT30 set if 32 bit access requested + ; BIT29 set if 16 bit access requested + ; otherwise defaults to 8 bit read + ; + ; Exit: DL,DX,EDX register data depending on requested read size + ; + ; Note1: this routine is meant to be called via pciRegRead8, + ; pciRegread16 or pciRegRead32, listed below. + ; + ; Note2: don't attempt to read 32 bits of data from a non dword + ; aligned reg number. Likewise, don't do 16 bit reads from + ; non word aligned reg # + + push ebx + push cx + mov ebx, eax ; save eax, dh + mov cl, dh + + and eax, NOT_PCI32_PCI16 ; clear out data size request + or eax, BIT31 ; make a PCI access request + and al, NOT 3 ; 13/11/2024 ; force index to be dword + + mov dx, PCI_INDEX_PORT + out dx, eax ; write PCI selector + + mov dx, PCI_DATA_PORT + mov al, bl + and al, 3 ; figure out which port to + add dl, al ; read to + + test ebx, PCI32+PCI16 + jnz short _pregr0 + + in al, dx ; return 8 bits of data + + mov dl, al + mov dh, cl ; restore dh for 8 bit read + jmp short _pregr2 +_pregr0: + test ebx, PCI32 + jnz short _pregr1 + + in ax, dx + + mov dx, ax ; return 16 bits of data + jmp short _pregr2 +_pregr1: + in eax, dx ; return 32 bits of data + + mov edx, eax +_pregr2: + mov eax, ebx ; restore eax + and eax, NOT_PCI32_PCI16 ; clear out data size request + pop cx + pop ebx + retn + +pciRegRead8: + and eax, NOT_PCI32_PCI16 ; set up 8 bit read size + jmp short pciRegRead ; call generic PCI access + +pciRegRead16: + and eax, NOT_PCI32_PCI16 ; set up 16 bit read size + or eax, PCI16 ; call generic PCI access + jmp short pciRegRead + +pciRegRead32: + and eax, NOT_PCI32_PCI16 ; set up 32 bit read size + or eax, PCI32 ; call generic PCI access + jmp pciRegRead + +pciRegWrite: + ; 30/05/2024 + ; 03/04/2017 ('pci.asm', 29/11/2016) + ; + ; 8/16/32bit PCI writer + ; + ; Entry: EAX=PCI Bus/Device/fn/register number + ; BIT31 set if 32 bit access requested + ; BIT30 set if 16 bit access requested + ; otherwise defaults to 8bit read + ; DL/DX/EDX data to write depending on size + ; + ; Note1: this routine is meant to be called via pciRegWrite8, + ; pciRegWrite16 or pciRegWrite32 as detailed below. + ; + ; Note2: don't attempt to write 32bits of data from a non dword + ; aligned reg number. Likewise, don't do 16 bit writes from + ; non word aligned reg # + + push ebx + push ecx + mov ebx, eax ; save eax, edx + mov ecx, edx + and eax, NOT_PCI32_PCI16 ; clear out data size request + or eax, BIT31 ; make a PCI access request + and al, NOT 3 ; 13/11/2024 ; force index to be dword + + mov dx, PCI_INDEX_PORT + out dx, eax ; write PCI selector + + mov dx, PCI_DATA_PORT + mov al, bl + and al, 3 ; figure out which port to + add dl, al ; write to + + test ebx, PCI32+PCI16 + jnz short _pregw0 + + mov al, cl ; put data into al + out dx, al + + jmp short _pregw2 +_pregw0: + test ebx, PCI32 + jnz short _pregw1 + + mov ax, cx ; put data into ax + out dx, ax + + jmp short _pregw2 +_pregw1: + mov eax, ecx ; put data into eax + out dx, eax +_pregw2: + mov eax, ebx ; restore eax + and eax, NOT_PCI32_PCI16 ; clear out data size request + mov edx, ecx ; restore dx + pop ecx + pop ebx + retn + +pciRegWrite8: + and eax, NOT_PCI32_PCI16 ; set up 8 bit write size + jmp short pciRegWrite ; call generic PCI access + +pciRegWrite16: + and eax, NOT_PCI32_PCI16 ; set up 16 bit write size + or eax, PCI16 ; call generic PCI access + jmp short pciRegWrite + +pciRegWrite32: + and eax, NOT_PCI32_PCI16 ; set up 32 bit write size + or eax, PCI32 ; call generic PCI access + jmp pciRegWrite + +; -------------------------------------------------------- +; 19/05/2024 - (playwav4.asm) ac97_vra.asm +; -------------------------------------------------------- + + ; 13/11/2023 + +;VRA: db 1 + +codecConfig: + ; 30/05/2024 + ; 19/05/2024 + ; 19/11/2023 + ; 15/11/2023 + ; 04/11/2023 + ; 17/02/2017 + ; 07/11/2016 (Erdogan Tan) + + ;AC97_EA_VRA equ 1 + AC97_EA_VRA equ BIT0 + + ; 04/11/2023 +init_ac97_controller: + mov eax, [bus_dev_fn] + mov al, PCI_CMD_REG + call pciRegRead16 ; read PCI command register + or dl, IO_ENA+BM_ENA ; enable IO and bus master + call pciRegWrite16 + + ;call delay_100ms + + ; 19/05/2024 + ; ('PLAYMOD3.ASM', Erdogan Tan, 18/05/2024) + +init_ac97_codec: + ; 18/11/2023 + mov bp, 40 + ; 29/05/2024 + ;mov bp, 1000 +_initc_1: + ; 30/05/2024 + mov dx, GLOB_STS_REG ; 30h + add dx, [NABMBAR] + in eax, dx + + ; 19/05/2024 + call delay1_4ms + + cmp eax, 0FFFFFFFFh ; -1 + jne short _initc_3 +_initc_2: + dec bp + jz short _ac97_codec_ready + + call delay_100ms + jmp short _initc_1 +_initc_3: + test eax, CTRL_ST_CREADY + jnz short _ac97_codec_ready + + ; 30/05/2024 + cmp byte [reset], 1 + jnb short _initc_2 + + call reset_ac97_codec + ; 30/05/2024 + mov byte [reset], 1 + ; 19/05/2024 + jmp short _initc_2 + +_ac97_codec_ready: + mov dx, [NAMBAR] + ;add dx, 0 ; ac_reg_0 ; reset register + out dx, ax + + call delay_100ms + + ; 19/11/2023 + or bp, bp + jnz short _ac97_codec_init_ok + + xor ax, ax ; 0 + mov dx, [NAMBAR] + add dx, CODEC_REG_POWERDOWN + out dx, ax + + ; 30/05/2024 + call delay1_4ms + + ; 19/11/2023 + ; wait for 1 second + ; 19/05/2024 + mov cx, 1000 ; 1000*4*0.25ms = 1s + ;;mov cx, 10 + ; 30/05/2024 + ;mov cx, 40 +_ac97_codec_rloop: + ;call delay_100ms + + ; 30/05/2024 + mov dx, [NAMBAR] + add dx, CODEC_REG_POWERDOWN + in ax, dx + + call delay1_4ms + + and ax, 0Fh + cmp al, 0Fh + je short _ac97_codec_init_ok + loop _ac97_codec_rloop + +init_ac97_codec_err1: + ;stc ; cf = 1 ; 19/05/2024 +init_ac97_codec_err2: + retn + +_ac97_codec_init_ok: + call reset_ac97_controller + + ; 30/05/2024 + ; 19/05/2024 + ;call delay_100ms + + ; 30/05/2024 + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + +setup_ac97_codec: + ; 12/11/2023 + cmp word [sample_rate], 48000 + je short skip_rate + + ; 30/05/2024 + ; 19/05/2024 + ;call delay1_4ms + + ; 30/05/2024 + ;cmp byte [VRA], 0 + ;jna short skip_rate + + ; 11/11/2023 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + in ax, dx + + ; 30/05/2024 + ; 19/05/2024 + call delay1_4ms + + ; 13/11/2024 + ;and al, NOT BIT1 ; Clear DRA + ;;; + ; 30/05/2024 + and al, NOT (BIT1+BIT0) ; Clear DRA+VRA + out dx, ax + + call check_vra + + cmp byte [VRA], 0 + jna short skip_rate + + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + in ax, dx + ;and al, ~BIT1 ; Clear DRA + ;;; + + or al, AC97_EA_VRA ; 1 ; 04/11/2023 + ; 30/05/2024 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + + out dx, ax ; Enable variable rate audio + + mov cx, 10 +check_vra_loop: + call delay_100ms + ; 30/05/2024 + ;call delay1_4ms + + ; 30/05/2024 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + ; 11/11/2023 + in ax, dx + + test al, AC97_EA_VRA ; 1 + jnz short set_rate + + ; 11/11/2023 + loop check_vra_loop + +;vra_not_supported: ; 19/05/2024 + mov byte [VRA], 0 + jmp short skip_rate + +set_rate: + mov ax, [sample_rate] ; 17/02/2017 (Erdogan Tan) + + mov dx, [NAMBAR] + add dx, CODEC_PCM_FRONT_DACRATE_REG ; 2Ch + out dx, ax ; PCM Front/Center Output Sample Rate + + ;call delay_100ms + ; 30/05/2024 + call delay1_4ms + + ; 12/11/2023 +skip_rate: + mov ax, 0202h + mov dx, [NAMBAR] + add dx, CODEC_MASTER_VOL_REG ;02h + out dx, ax + + ; 11/11/2023 + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + + mov ax, 0202h + mov dx, [NAMBAR] + add dx, CODEC_PCM_OUT_REG ;18h + out dx, ax + + ; 11/11/2023 + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + + ; 30/05/2024 + ; 19/05/2024 + ;clc + + retn + +reset_ac97_controller: + ; 19/05/2024 + ; 11/11/2023 + ; 10/06/2017 + ; 29/05/2017 + ; 28/05/2017 + ; reset AC97 audio controller registers + xor ax, ax + mov dx, PI_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov dx, PO_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov dx, MC_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov al, RR + mov dx, PI_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov dx, PO_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov dx, MC_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + retn + +reset_ac97_codec: + ; 11/11/2023 + ; 28/05/2017 - Erdogan Tan (Ref: KolibriOS, intelac97.asm) + mov dx, GLOB_CNT_REG ; 2Ch + add dx, [NABMBAR] + in eax, dx + + ;test eax, 2 + ; 06/08/2022 + test al, 2 + jz short _r_ac97codec_cold + + call warm_ac97codec_reset + jnc short _r_ac97codec_ok +_r_ac97codec_cold: + call cold_ac97codec_reset + jnc short _r_ac97codec_ok + + ; 16/04/2017 + ;xor eax, eax ; timeout error + ;stc + retn + +_r_ac97codec_ok: + xor eax, eax + ;mov al, VIA_ACLINK_C00_READY ; 1 + inc al + retn + +warm_ac97codec_reset: + ; 11/11/2023 + ; 06/08/2022 - TRDOS 386 v2.0.5 + ; 28/05/2017 - Erdogan Tan (Ref: KolibriOS, intelac97.asm) + mov eax, 6 + mov dx, GLOB_CNT_REG ; 2Ch + add dx, [NABMBAR] + out dx, eax + + mov cx, 10 ; total 1s +_warm_ac97c_rst_wait: + call delay_100ms + + mov dx, GLOB_STS_REG ; 30h + add dx, [NABMBAR] + in eax, dx + + test eax, CTRL_ST_CREADY + jnz short _warm_ac97c_rst_ok + + dec cx + jnz short _warm_ac97c_rst_wait + +_warm_ac97c_rst_fail: + stc +_warm_ac97c_rst_ok: + retn + +cold_ac97codec_reset: + ; 11/11/2023 + ; 06/08/2022 - TRDOS 386 v2.0.5 + ; 28/05/2017 - Erdogan Tan (Ref: KolibriOS, intelac97.asm) + mov eax, 2 + mov dx, GLOB_CNT_REG ; 2Ch + add dx, [NABMBAR] + out dx, eax + + call delay_100ms ; wait 100 ms + call delay_100ms ; wait 100 ms + call delay_100ms ; wait 100 ms + call delay_100ms ; wait 100 ms + + mov cx, 16 ; total 20*100 ms = 2s + +_cold_ac97c_rst_wait: + mov dx, GLOB_STS_REG ; 30h + add dx, [NABMBAR] + in eax, dx + + test eax, CTRL_ST_CREADY + jnz short _cold_ac97c_rst_ok + + call delay_100ms + + dec cx + jnz short _cold_ac97c_rst_wait + +_cold_ac97c_rst_fail: + stc +_cold_ac97c_rst_ok: + retn + +; 13/11/2024 +; 30/05/2024 +if 1 +check_vra: + ; 30/05/2024 + mov byte [VRA], 1 + + ; 29/05/2024 - audio.s (TRDOS 386 Kernel) - 27/05/2024 + ; 24/05/2024 + ; 23/05/2024 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_REG ; 28h + in ax, dx + + ; 30/05/2024 + ; 23/05/2024 + call delay1_4ms + + ; 30/05/2024 + test al, BIT0 + ;test al, 1 ; BIT0 ; Variable Rate Audio bit + jnz short check_vra_ok + +vra_not_supported: + ; 13/11/2023 + mov byte [VRA], 0 +check_vra_ok: + retn +end if + +; -------------------------------------------------------- + +PORTB EQU 061h +REFRESH_STATUS EQU 010h ; Refresh signal status + +delay_100ms: + ; 11/11/2023 + ; 29/05/2017 + ; 24/03/2017 ('codec.asm') + ; wait 100 ms + push cx + mov cx, 400 ; 400*0.25ms +_delay_x_ms: + call delay1_4ms + loop _delay_x_ms + pop cx + retn + +delay1_4ms: + push ax + push cx + mov cx, 16 ; close enough. + in al,PORTB + and al,REFRESH_STATUS + mov ah,al ; Start toggle state + or cx, cx + jz short _d4ms1 + inc cx ; Throwaway first toggle +_d4ms1: + in al,PORTB ; Read system control port + and al,REFRESH_STATUS ; Refresh toggles 15.085 microseconds + cmp ah,al + je short _d4ms1 ; Wait for state change + + mov ah,al ; Update with new state + dec cx + jnz short _d4ms1 + + ; 30/05/2024 + clc + + pop cx + pop ax + retn + +; -------------------------------------------------------- +; 19/05/2024 - (playwav4.asm) ich_wav4.asm +; -------------------------------------------------------- + +check4keyboardstop: + ; 19/05/2024 + ; 08/11/2023 + ; 04/11/2023 + mov ah, 1 + int 16h + ;clc + jz short _cksr + + xor ah, ah + int 16h + + ;;; + ; 19/05/2024 (change PCM out volume) + cmp al, '+' + jne short p_1 + + mov al, [volume] + cmp al, 0 + jna short p_3 + dec al + jmp short p_2 +p_1: + cmp al, '-' + jne short p_4 + + mov al, [volume] + cmp al, 31 + jnb short p_3 + inc al +p_2: + mov [volume], al + mov ah, al + mov dx, [NAMBAR] + ;add dx, CODEC_MASTER_VOL_REG + add dx, CODEC_PCM_OUT_REG + out dx, ax + + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms +_cksr: ; 19/05/2024 + clc +p_3: + retn +p_4: + ;;; +;_cskr: + stc + retn + +; returns AL = current index value +getCurrentIndex: + ; 08/11/2023 + ;push dx + mov dx, [NABMBAR] + add dx, PO_CIV_REG + in al, dx + ;pop dx +uLVI2: ; 06/11/2023 + retn + +updateLVI: + ; 06/11/2023 + mov dx, [NABMBAR] + add dx, PO_CIV_REG + ; (Current Index Value and Last Valid Index value) + in ax, dx + + cmp al, ah ; is current index = last index ? + jne short uLVI2 + + ; 08/11/2023 + call getCurrentIndex + + test byte [flags], ENDOFFILE + ;jnz short uLVI1 + jz short uLVI0 ; 08/11/2023 + + ; 08/11/2023 + push ax + mov dx, [NABMBAR] + add dx, PO_SR_REG ; PCM out status register + in ax, dx + + test al, 3 ; bit 1 = Current Equals Last Valid (CELV) + ; (has been processed) + ; bit 0 = 1 -> DMA Controller Halted (DCH) + pop ax + jz short uLVI1 +uLVI3: + xor ax, ax + ; zf = 1 + retn +uLVI0: + ; not at the end of the file yet. + dec al + and al, 1Fh +uLVI1: + ;call setLastValidIndex +;uLVI2: + ;retn + +;input AL = index # to stop on +setLastValidIndex: + ; 08/11/2023 + ;push dx + mov dx, [NABMBAR] + add dx, PO_LVI_REG + out dx, al + ;pop dx + retn + +; 29/05/2024 +; 19/05/2024 +volume: db 02h + +; -------------------------------------------------------- + +; DATA + +FileHandle: + dd -1 + +; 30/05/2024 +reset: db 0 + +Credits: + db 'Tiny WAV Player for Retro DOS by Erdogan Tan. ' + db 'November 2024.',10,13,0 + db '13/11/2024', 10,13,0 + +msgAudioCardInfo: + db 'for Intel AC97 (ICH) Audio Controller.', 10,13,0 + +msg_usage: + db 'usage: playwav7 filename.wav',10,13,0 ; 30/05/2024 + +noDevMsg: + db 'Error: Unable to find AC97 audio device!' + db 10,13,0 + +noFileErrMsg: + db 'Error: file not found.',10,13,0 + +msg_error: ; 30/05/2024 + +; 29/05/2024 +; 11/11/2023 +msg_init_err: + db CR, LF + db "AC97 Controller/Codec initialization error !" + db CR, LF, "$" + +; 25/11/2023 +msg_no_vra: + db 10,13 + db "No VRA support ! Only 48 kHZ sample rate supported !" + db 10,13,0 + +; 13/11/2024 +; ('<<' to 'shl' conversion for FASM) +; +; 29/05/2024 (TRDOS 386) +; 17/02/2017 +; Valid ICH device IDs + +valid_ids: +;dd (ICH_DID << 16) + INTEL_VID ; 8086h:2415h +dd (ICH_DID shl 16) + INTEL_VID ; 8086h:2415h +dd (ICH0_DID shl 16) + INTEL_VID ; 8086h:2425h +dd (ICH2_DID shl 16) + INTEL_VID ; 8086h:2445h +dd (ICH3_DID shl 16) + INTEL_VID ; 8086h:2485h +dd (ICH4_DID shl 16) + INTEL_VID ; 8086h:24C5h +dd (ICH5_DID shl 16) + INTEL_VID ; 8086h:24D5h +dd (ICH6_DID shl 16) + INTEL_VID ; 8086h:266Eh +dd (ESB6300_DID shl 16) + INTEL_VID ; 8086h:25A6h +dd (ESB631X_DID shl 16) + INTEL_VID ; 8086h:2698h +dd (ICH7_DID shl 16) + INTEL_VID ; 8086h:27DEh +; 03/11/2023 - Erdogan Tan +dd (MX82440_DID shl 16) + INTEL_VID ; 8086h:7195h +dd (SI7012_DID shl 16) + SIS_VID ; 1039h:7012h +dd (NFORCE_DID shl 16) + NVIDIA_VID ; 10DEh:01B1h +dd (NFORCE2_DID shl 16) + NVIDIA_VID ; 10DEh:006Ah +dd (AMD8111_DID shl 16) + AMD_VID ; 1022h:746Dh +dd (AMD768_DID shl 16) + AMD_VID ; 1022h:7445h +dd (CK804_DID shl 16) + NVIDIA_VID ; 10DEh:0059h +dd (MCP04_DID shl 16) + NVIDIA_VID ; 10DEh:003Ah +dd (CK8_DID shl 16) + NVIDIA_VID ; 1022h:008Ah +dd (NFORCE3_DID shl 16) + NVIDIA_VID ; 10DEh:00DAh +dd (CK8S_DID shl 16) + NVIDIA_VID ; 10DEh:00EAh + +;valid_id_count equ ($ - valid_ids)>>2 ; 05/11/2023 +; 13/11/2024 +valid_id_count = ($ - valid_ids) shr 2 ; 05/11/2023 + +msgWavFileName: db 0Dh, 0Ah, "WAV File Name: ",0 +msgSampleRate: db 0Dh, 0Ah, "Sample Rate: " +msgHertz: db "00000 Hz, ", 0 +msg8Bits: db "8 bits, ", 0 +;msgMono: db "Mono", 0Dh, 0Ah, 0 +msgMono: db "Mono", 0 +msg16Bits: db "16 bits, ", 0 +;msgStereo: db "Stereo" +msgStereo: db "Stereo",0 +nextline: db 0Dh, 0Ah, 0 + +; 03/06/2017 +hex_chars db "0123456789ABCDEF", 0 +msgAC97Info db 0Dh, 0Ah + db "AC97 Audio Controller & Codec Info", 0Dh, 0Ah + db "Vendor ID: " +msgVendorId db "0000h Device ID: " +msgDevId db "0000h", 0Dh, 0Ah + db "Bus: " +msgBusNo db "00h Device: " +msgDevNo db "00h Function: " +msgFncNo db "00h" + db 0Dh, 0Ah + db "NAMBAR: " +msgNamBar db "0000h " + db "NABMBAR: " +msgNabmBar db "0000h IRQ: " +msgIRQ dw 3030h + db 0Dh, 0Ah, 0 +; 25/11/2023 +msgVRAheader: db "VRA support: " + db 0 +msgVRAyes: db "YES", 0Dh, 0Ah, 0 +msgVRAno: db "NO ", 0Dh, 0Ah + db "(Interpolated sample rate playing method)" + db 0Dh, 0Ah, 0 + +; 30/05/2024 +print_msg: + mov bx, 07h +p_msg: + push es + push bp + push cx + push dx + + push ds + pop es + mov bp,si + mov ah, 03h ; Return cursor position (in DX) + ; bh = video page number + int 10h + xor cx, cx +p_msg_0: + lodsb + or al, al + jz short p_msg_1 + inc cx + jmp short p_msg_0 +p_msg_1: + or cx, cx + jz short p_msg_x + ; cx = number of chars + ; dx = screen (cursor) position + ; bl = color/attribute + ; bh = video page number + ; es:bp = string buffer + ;mov al, 1 ; attribute in BL, update cursor pos + ;mov ah, 13h ; write character string + mov ax, 1301h + int 10h +p_msg_x: + pop dx + pop cx + pop bp + pop es + retn + +EOF: + +; BSS + +; 17/02/2017 +bss_start: + +align 2 + +; 13/11/2024 +; ('resb','resw','resd' to 'rb','rw','rd' conversions for FASM) + +; 30/05/2024 +VRA: rb 1 ; Variable Rate Audio Support Status + rb 1 +; 28/11/2016 + +smpRBuff: rw 14 ; 19/11/2016 - Erdogan Tan + +filehandle: rw 1 + +flags: rb 1 +; 06/11/2023 +ac97_int_ln_reg: rb 1 + +; 30/05/2024 +wav_file_name: + rb 80 ; wave file, path name (<= 80 bytes) + + rw 1 + +; 17/02/2017 +; NAMBAR: Native Audio Mixer Base Address Register +; (ICH, Audio D31:F5, PCI Config Space) Address offset: 10h-13h +; NABMBAR: Native Audio Bus Mastering Base Address register +; (ICH, Audio D31:F5, PCI Config Space) Address offset: 14h-17h +NAMBAR: rw 1 ; BAR for mixer +NABMBAR: rw 1 ; BAR for bus master regs + +; 256 byte buffer for descriptor list +BDL_BUFFER: rw 1 ; segment of our 256byte BDL buffer +WAV_BUFFER1: rw 1 ; segment of our WAV storage +; 64k buffers for wav file storage +WAV_BUFFER2: rw 1 ; segment of 2nd wav buffer + +; 12/11/2016 - Erdogan Tan + +bus_dev_fn: rd 1 +dev_vendor: rd 1 + +; 06/11/2023 +sample_rate: rw 1 + +; 19/11/2016 +stmo: rw 1 +bps: rw 1 + +; 08/11/2023 +; 07/11/2023 +fbs_shift: rb 1 + rb 1 ; 08/11/2023 + +;alignb 2 + +; 32 kilo bytes for temporay buffer +; (for stereo-mono, 8bit/16bit corrections) +;temp_buffer: rb 32768 +; 18/11/2023 +temp_buffer: rb 56304 ; (44.1 kHZ stereo 14076 samples) + +;alignb 16 +bss_end: \ No newline at end of file diff --git a/trdos386/programs/16bit/playwav7.com b/trdos386/programs/16bit/playwav7.com new file mode 100644 index 0000000000000000000000000000000000000000..f5aa634c24f824b3d569d7de3543f678d7a29196 GIT binary patch literal 7954 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 literal 0 HcmV?d00001 diff --git a/trdos386/programs/16bit/playwav7_com_fasm_2024.zip b/trdos386/programs/16bit/playwav7_com_fasm_2024.zip new file mode 100644 index 0000000000000000000000000000000000000000..6a5bd1e05b961d5565698c7b00f2b50e31a3b5ab GIT binary patch literal 27483 zcmV)9K*hgMO9KQI000090E!xGSDvqJ!F&_|00l(=00;m80AXV}H!f*zW3*XqbK^7+ z{@k1Cf6ymrq0QOOYY!O4v0ctX-bm8p;7i7hmD<#?gYC40U(fDZvSPalFaw#+&1tp! zXeB+nTFKuqU4IXMhGw)c-+jZhZl%>eZt4B^ngK1n&#s)*PoBJ(Exq`L%|_-gKbxOg z=3;z}it8lKaxczXVZ3HvK-1@I`v27?NttVXWTti3XRqE1+eO}ir#I|NiD6C0UtY7z zcZhTQAN~-}nobr=bFyr?6YIan2ShpXj3pbE<@?Qs<$;&8jPorEywqoT!cxBF+ee-< z=*Yt@&su1^oIf~>IX^ux{qo(tIa)Z>(6G;$n8T4{m)*9zAc4{tx=T%TQ$sHr1~rVL z(V<4WXbh;)5jI*t&91N#&7QCm&AzY{&4IKP?K@#C+qx#KWm^~KvTaCvDQHUoDdJSDs<0hO>VR=g?{%Pxh)(`?7rp%<|=aMD}nJk2iOO&&%Jf5a(jj*gl`=cw6- z_JS$x0npbRs`lOGyV1Ss*TLSJAGO;+>4jy^1mR)U>h}%wurOmD#7V}}7w)syB=uYH z1J}{{O&IYaxGvw#9n+ppM!ygcSi^*2u#c{7I}>OsDTKx1m&MWwv+lNTOEEao{Z$1?y;XU^mTv@eW{i*H!6<1yoZgjpWOPc$N|IY2HQ($P_8 zopLYd0P!jmiYz;`T*iOjLsur7n|-{_!z5;&@2B84yPDmbl-eJ|oB^f2W4de^?GJhn z1dscS#d}I@_`A|>jc&KJ(YqgXH1qjOxaLBUwA#8-(mo78M~*JEP^n+)^gn2zlJX~* zDo>?~91dsXPFJRF&sSq}@uS*T#PHjXMBWpg4jE7mBC~CPOpu0< z^xg?1?JXpli{3lNDBQiDXblvNefupN$bP-iuUGnwM!!+%Z#VkemHtknzf7 z1#D>Sd+DJ7`;rC}QC3(?=a@mln6fxlg5HsTQd6u3t~>YEK>_xD8~(vlr5k2qCa6ez z1=L+QOC)feLAZEDIBOyq&;w-Oa8qi(SFM%z{gq5xCzja z00AV^U690FVAPx#PbX6eR>$booY*FD@;1tHI&maI9c55M$S6QDh?nvVoh{yUinh&4<&b}w@z5O5c)wjm0>BI7z^+4_4 zm?itXIe#eSrgM9>a7Ka&bTe4Q7oS%o>rC4F6mdE1XBBNPCy0c^u{ z4djPeee^nrQ8MC*$2|2Sw%ez>Br74>_6n}b%lYYv7$qOtHeUDhG>I^k8L-u1R+jGN zE=_-iNVS&p(}2A)Mv_;a`pIi7aV3cJc?o2(-Ra3dGs>;zf8;#&xetu-!=#BIU1=bA zZzCvQ6z%Tkutre-S#zkeC7425*J#HwZ@Y^)OTE0p-o?XwVxNX7H$2;?X|j)jdid`t zw9&oOz*1=Ka_2$sEr`(^YUiqT9l|)CR~R=@D5X_lnkX_QAb}ew$Ru?}w|lpJ4-Z*& zBTQmEmhmM?9gLrxi9MaWwtkWxeYqu~40wSJ#`h?j>2(m}GzdQhVib;#D@S<7G;kF* z?kQkhJ-{hI4rF0D0S5IZO)gGyEOTDH6j(=v37}PL6Il|`$T#dY2w_Gph@g+|%%GL$ zu#B%fgex;+qa=CGK={lNOOCkpo_WT?9GHYf74wt$%bdj=$qtvVC_0o^Fi(_eFfu*W z718j0Q3-(qJmy$I8OO!k4!0@JKd9=O08#&>LDj^UbHP7H6t8Hdvh`35z`l8OtlB5jMT3NE@asHgi~&PHL( z>j3}Dl#sXv4*tJgR_Nh_o|ULclZ*waHLJ%ch~x zG}K7ncw4{I)Hh`M#9Wke+BUeh(;m_ljs3$PW!D4U^s*q?M{p6W5#a0>loS^j9{o*b z%b904gUrd4&jW{v2m0-8cy|6GH<8&uU%1vJTxzSO-i`nE%_I4J$Eqh$Pf0L0PC!TS1L zH^AWOYr3JN(7^DypUy3(lxq4=FQtYOYdtfdFd68&t}r@1yAbz#10_Y)o}JX~zlhGn z#~SU&fz~Vn zD7K4N5U_;!1Blha{ne>cx!bEEkmT_IX_}>=6sFv76)p^=54B6_Sr^p%8@}a8SBA;*CLy$y z);OadeBtQR&2D!0$?ir7g*s9QDGCo{c07}7r3+Lq`b5eK22TMRd4PEV#vP^Bh-Tu? zjl*8J{5U$T^j>u@TrzmmMPoKg*Pf`98Av&Z+ZI&H6IJL!I;68VAYb%N3g*it^LU%bTvgYD+ChLUc-YP)&Cimg5*L^NG9 zLej68t`0FCHbZp#Wy{qOo+bUd<#hR5I)+MvD3*fD6mz(gYDaX?Ze3^IWsx&DSLA7cXkP73d$eTtFDY~pWYSMUN>D$B<>SpEme44N z&KMaZ&<=4l&DAx#mV5k{4LeTk04%?;s*4Vj$?G|e$cey!0Z+p*=+))N7Jo}@AI+pz zC+73#M(Up!&qK`OykIto%;dtFiA<9^AvX&dLHY?)!a{PEqYBE_*=|fdw_tgYZPe0d z5*kdY+Q>%zb2#v{=&oZB&&LDjZW7rClLZe`nm%$hn~HRibG8OmQ5M{UxthZ2!J5;7 zE8&UlM(jQ=r@RJ0 z$5)enm9REEgt1c-N5w5-c?mH;90Amk@5F zivoc?oko2(<0P!2?^8hIVKY#dmDPL-hlt_bvU2IG#bQLnAo+(S@NnoBsgp21n@4$b`eLt7Ki>ReaM zGqj0zcEt9YA(HE=W$GB?VKYYex@?ph1Zo5g0)M)n`3lYL@rU`5k$Aji26?e5 zf{2PDUg0A$aVAfqE?$i;UbVAW609nZU$lEofMg{)mUB8`8NPj{@KcqCfI-_Hi!dOK z%3~siqgQ`L3_UZj{^}PMX1)Kfq~imGTK*H4qlNk)jz^$YO6AAhN++v#Tj+GV@w*@n z#D6U~XoIE*A3p8cYO3}=83Hx|x3BsP${lrZM|EJ0)0gAFqdv23c7MvYn*X!A7RpdK zf5Na8lh>D%mtThOYO_@JiI&$AXrc5coo)xJ)MF|+#Q;qmfOdkPj zt9b%iT>)9e=!!lY)9iqisx3gKqA1ky&_G-R8w{Z<{`Sk{;-W1UU2Svpfn|Ay0}(zA zW@9tR+3fd&9sAC+^7E#`q9x~>pgriv7dCE;<}U3A&E?WievPsXCzt1qvL$vSlCz=P z?+xn}UQj%V1j$BNOv@?5}M-*}J=IRx$@Q*+}0&+v>ET!9aDe}KK>O9X>zGl+g zk(yslu9EI)kscC~UNI1br%o2NG}mEheocbn6MNsT4emh`T(=6Bw83?o;F1!Y4bUIP zUTZbDq#U4q70L$bG&;jdgUEmI^cF?eR>%%QQcP_JBpK~I?D^+EFZs!zlZen{=RHMm zMgwdlUmKk5P)$L;MzEmhp_avt<=ix?;1IQ-853>&{+a`9kl$0%hA3Fd+i(`a>F?3( zee)2TZ!IxOWIk0ZDS@?#)cYft$ZA+)u$vdH zDOFP3IhLmcVFhZ+XbwVTWduq&6hwz_2Jc?KYDhWdsuDbQQ^PL*$qDdlV1n%Eq`QNo6~_3_|jh^OA7kAu{Q072Jcvr@S)47dSU7*_b)l36R4Xrj^m zNhENkP&CV6g9fa!lHX}4q24Ig)G5Xv4KzhJ*ue0F6g>8b)6jkJQ5w;5h1v^T%-LoQ%*o52ag+YVC_ z@KcBX@ZKZB&k%`#?VGUG28vNz?Wne$=zyOWOh}&kQb6Q2=bF8?N6zGq?KM>$r1+Yd z>1h_7?@)?soF&iqh+shGp(j=ab;5Hjf?>-r3NmaoUN_G}t{`@LLhx2@dPvjEbA+ z5nq*pY@2dyru(xY{5=T(qqJD>F!^atd!22e`_1Qh@P00{u2m2Fvn zUnMbz{1_CO6YkCi#&-VFzwl9p>d$0I;^NkT(ME>K0 zf4|rEvpH+rBq_V%d77}J%j+iAZ@=OP;eBzo|NXc7-|V#yFVERqZ2xfUgFV(bJ^ZZ6 z+E7mQ$5(8TCby|SXOl;EoCe9QAG5FaF8~0-aJxIMyW@4do-Fv0o%vbL&XXX#38#J@ zCh^c}#eNd)WCI?sn>3j#RQiNU8;C%};A!pPe%xZ+&Q51njmwIk#(tLZ`6S}$kX`Iw zpEIxR?l$GPR^18Kx$V6!lsnY(1}Sf|p+F<&^_gI?y)W2qCe{?yUwwUXe0F*H1-s{I z2GnE?>=4Gc>>6+&;2P#YWA3o=h-bw7H%t9cyGS(8xR#*+T3#H$-R?>Eo=l; zbDm}XEr0V3#;9fzVT}hhIbY>~VU(oMX_chTWY%Jn8Pwc|0Z-Thy0MM~=tEuScm}_w zeiS(iMB~jjem4~6sUT78N9^8DLmy-yV}2a4B%eVg|78gj$=Yweaq#uY$??_o=?}*a z6taGgy~kWY-5J629lHsEdXweN4Rp%FUpe$RzBsx(IXOKO9b5-m-bDT_!zFwdClAOh zjw9VrZ$xUDakq~TNqP&=J2Rqb7*C^Rz}c2R{a~*RzqS~Vd2grV0rA{DY%{+8YX9o1 zufG^V^AcfUMW-;wjKPH1VakILp1%SrwxLq8MwJ7#4q(g*5GFrJMf}cqev)$T;G6;u zg~=2JXBoo;0@O^vz&XLO5v8Ap5%*JeaDB}h%Q%d~JoF==SHJ>4_nXX5xi1;(uUgDs zv61HH6bc%XEE^-$wi!NUxu53E9Z$9h!j>t9vXn2JEKjlriOUhs`7~#ZciC}_tZqv6 zw!aL*1ZwZYDObWG+Ttq0u0O|9Cz~Z{&OU{?1G_H#Ij<7iG*d(w10|C5v4*JQfZvbf zBp<_+gGa%+X|jxhcq<2qhy&u7PpAci+FKUK;snq=&u)QbCo{vLpXUquK3;`+&6p*u zhGHdX270@F(5WEsAe6)q64s-`^YP`^U$Fxr-bXx}rr{!onzJy=+pKYLbOvh4AOWnP zZ{#4V85&Kv~Q9?VQIsE2Aw}Ue=>6Xl zejGyuvsCK<^@&!eKW5=i1r;hZjWb!vMkol_>ix+IFzDcX=KdXry>c3cKM;X%gtqLL zg>SxbJ@sRSPLu@M1inFs`O{RkJxug(I*cf1tp-I>l8ROu0JKXbWy6dnq+Y`KCXuTpS@0MUDM_}h;44_l zup`M@M~O8O;_{2*3&&aC&Wjh(K0WXLOf1WqXx%-UOpbK*M|sq$e3>6CnbLWFxP`v?{pPkBPtj|=+%;4X!7s#b#G4aoIK zb`a~W0vBx*06I^A-=I_n2+(l^2S8#SxekM<1$7ADx50aCB$1Hx&(;s)$zcd{8b^-e z(J0X11EVzUb%OTPcrgw2QmH7}YWETKpU(L7ZhW8mbv>vBar`ieZ^B#T>N1`$0dXpA zq5Z^CGAxA*pdB>kDM)-pL~MM&x!SkU?6_i3cdyt?Ek$Zu2l6H7717@|{~O_ShGX>b zXwsB6f2Fo7YXzGn+h779Z!S)HBDp=C-HnxO(+ZOZpK)(6zMK6zbfnk{br>anfJZ}U zfHMSOSaJd-s0t95Vp}xDrG)o)cf0)pFkv*vCS7l@KVTzE+CX(UUjQ-}$pf=FjB_es zO~xB?)jm5d{1jAS4!@|Dj_w1Pz1!}1yYStIUC(QGc02IhLj>5}XFoJ8OQEpl1s$op zH|TUa_Qq8tnZVBTka|`x&x4_89dnEHu1h@(kEH$>P)oHWHNdf}w8%=3UKR^YFn0T6 zT73qb(oZfELstNL^#EZ#YjDJhx{elF!zb|?ydqi}n$>t{acytc?VzXGv>s%Kkrh;g%w<+sfw~lpG{BqVAfL;~gGpsWmEwqMD z;x%|hv@|r+*szZHv%5#E^E|i2y1ib3b!E;0E}A7a=XyQ2Q?uy$8*+{SRyjw-FXx;A z=v4te!#UH@LTmUWUV~ReOGC37lhReJb9X!aU1S}o`S-kTv$AP5$c{v2vG>tO0DrUG zpWZduhabVo@ACs&^SZsxUZ0@39wTr@61-hY61?sjNpSn+HQeviNWx&_CETxH!u^*E zf(_8C0(?dgOh*f?;gfg`UKK5S3HK{Yc(>PgZH;TM+BK{ilsGl0W0beCvK`biYVc?I zG^nM=pq@+BZU&>_Qz#8y47?iPru3^IZ~NRURkwzy*fU1y^Zaede!Rv zY1Qi0>oD&*)oMCgXbqplYw)UQ+4fAY!m)w-foH3~jXBmWTcBO9%rQ7XjbqLO9&E(2 zZoLWGeVGYb0q9i$KEpE8(L!tZBwmBpM9XGbw`zjAoew;3jTXf6Q9aZ2^RO0A`^1rD z$OiZk!GKhUCBtXAm}NAr^4Y!&%1lR{;*8T{8Nr+o28^VoaAaeKkvse%pIV61R`ZWq zw(GzebsEu+RG{FD>`)F1vm(0arH^xkplGR4WU9P+RGq8}awN`{6q+#WU|2d&!_P&s za3~HEgy0KJ1D5i9nUX&-MS0rE)}VgQ|p2frwQ351eP@(?6rnlJqb2~0s83ao#9_!$f5 z5IDc*6hZ;W%Lru&aC~GF&VnT7Y{pZfIgtUp+mgC!9Z;lrxmW;FJZMok0DfZ^>gdBi z5BmCX%%iNucs^}22A!(m5_F;Wyje{}1VZ_wW0i!5=Bh%cRVWj5pI{Z>62Rg!Eg;@O z-=I0*U$tjIr?#iY|9LrIpm#T?l!To$ytx6o`2kN2G~fw+du}zHYJ0HxDv!dLw?KAg zCMr$qxvkbmo1G^a&XtO9lO%xIg9rjYU>sr@MY*&q8%6(H|6ahGMoGqt0Lf2^{$}ci z%YMjM)n!jTPYUE^)+W=NLVOxEf|25c{P@#kE(Pta8rqoX zkgc+GAw{SQz}KiPwPwmtR5_}?jQ~-sg52|EP*j5n25aHGEbXK0tY(d`zQ4j?dUw!o znFN%qDg23zVzP{_(^{;crA3F@bRXFZHv^cSlpGn0PC00%`lzp(AVkAso`zF)lB9DG z(Q0dI_B=e+)C} zDE2!PZH5Nbt~?XwPPJxAhBVt@-WvTxS{a+b5NXI!N8lJ$4T!N~3^zi|v@p!CD?|X1 zM>lyfux%QG<;0k3_>{hsE^(UnFafo-{c#7sGoBl07?}+=39Dhtw6N=e^ok7`>_Fua z;*~(V$3|ikOKy~H*XVkmH<3CGw-1Iylct+J9nWCfPewxY*tS(D&`MIOA*p;H#ZrWD z`UY4zrK_b=xl9%pbdrE12qGMeuo(lre>DTWO&K`zqaqjo>r9K1gu>M0j-^?sh%^h~ zLT5nCQ9;Own!a1BcGfLgvPcWYdG)wKP3og<5)nVH;^9G!jX=H7Ie!rW+9UPZ;9~#a z{9ym;eYZ0ssxu*!))EiQrWL`a^~^dksu~CS^XmhsLJOqcxcpI~ZK#4LIbHq5<@n$T zs>fHypH_#$>6xWd)axL03JM~<7GZO=q8w2~KTi{Jcof{Igv$dChJico&9f2-DN&~D zs&;@L=J|f(M`3Up2Ygiraa0Cb%@edoSWh!Y((90jDzjLx5& zaRL=I|E#Kz2oh%S6Y6Q6encZ*)46A|%wU_xnPFm0O8M073av{RRGC>h7?Gj07GTf2CMasKZF?vOnEGT z%9LrX!&(Zk)~^;wHbAxAVsn2HgHtjbcd2DFzRcY?7r}-w^`s>i#WK4_Yg0q%$MS@m#00%9A zs`6j2`z@w*O8S(H(S^JSP&xYB-0p0NY8Y4*;7`SWe8zt%&*RF1wcYK|*0ig%gxX>4 z^4G~*rJa)L6Kw`MZ#rWr0j!bpIk@Qj^s!lk49uK;B>9VqIGp-uA2mRokXW-M#p$ta zq|G)%5O~OS#LIWf{YJ@sUmT`Hk5I zJFayz<}2l}VW0Cf<`KJx6t6a2A%KoBUSD5@K)%|)wd=?H9+=!zjeva^Sa&n@|Mb7|xVy|!Tg3T56 zJSu&@DSZHevfH0+7c3(A1XtOKs2X5a{xyhjLPFX6ITn4hW?Yfqoi=)CP zpwsJk|LEvye7=AEIfL$q$sHb+XrHJWjnI|Sayuuu8f&gP2wXACctz-B{=K@WLQ^*6 zATkxFd9c|$pP$MTh#z*=A%0NBTr;PHxKaPOe#WO4UyaXBFOESWnNtEf?B0N(nev&F5Etw~DlQE1J z%Y4X!Y#6Mzw?9^wG+4vOTN}SN5e}2w_y}w9$|Y0_KnM~+V>8$&2~>=6AvVp1c02_~ zjCep}s?`1=9*pcIrne4%rJklMOWAi1X2b-Ff;;!$TW=?17(X;}@}{w(<&# z4Ck0Igl#${HxwhLg$xtX^C)K0SBkOUQ0yrHUq@mMPweoD+MuFG!cDORu+~&;v1P_H zMM@KzA{d)eaI%s?cCx67NN>9Zb8|}5UKbK$tZ3VHIqc%K5v-E?fY6om8&3_1CbcB8 z?^T!yR!=*)IB?Yq<(8FiUQmpq6c>ZW8#BU^piC(QR5@GC2vW5fWph%Wi0R^PyOT(rPeEx~}XlF1JL%j{hf#bK=ggxu~X7j}r+N|}F4R1hz z;ai0AZEbNgTQ`usAQXJOHudfPRw1_r?}VULQs3i!5Bq#`{GvWCcEa=QrSLs^ARF^# zMxG#-H9o>)Npl@QV~5!gdp|iNnd5)q$LITJ zXP1X^Lxj-Z_3>9HSI5UgcEux(`?$E{N+(>rmt2iPihif4p%LdHJHBQg**5eS*I$S> zm&;r<5~_v@^$C*=fvj-ohJS}=WbU1u?SFcW=@7)ZTNqmnb(1hL)O8q7Y2y%S$lEF? zNLuT`e-s)p!ZZV26$5Zqd9%UscgNeflv{xQ5bb2)A=ZgO6F`&vaD>|R^$;dif+3qq zZwEf=S1g3Fq+^?XHA|D_EqdKT!ma`(q8Mr!0^Z-8P=3;M8Tq*&2HAW95&+H7j7pFo zeqO}61Pl=c4;=>wi$qH}3$ySx7Oue%lYsCFI{EA5MRhwhkM05OxP6fK-sf~l2LLZ- zS;0tS4Qq2~qR+uTr0#?IlNbDA{-CCvCpfGzLA3Qo8f^khh9)vii$N6@Q-2C;HPmh9 zKu)a5L|!_AQI~^<+M+;_g9h&aee5};{Fh~zl3|9<5ZzG85XDBKM4+W>WTEUtGN6X$L=*z;tJY~%MpES=DL|y9 z%S~N$r`2ATzOEU%D7HplaE(u>fU=Qj3Z4b>4U5I0`orOtjY`Wyg5Wr%g?4E@$7i)e z8}o_QpHK|s$EwRiW}_Or8)eSzD+A3CV6X1_@rVsdB>|rTg;17>JYw(`-g{PyS6@yp zleo_$ICVe}N@kaoj97Z_iU#Hd2IM#OBYKkqv-xXfG7n5Zy0~!jq&Op)hwy;%&Tn#M zV_L;&cstYO%E3oS7VJ1I`M?qA_X&M5qkn1wHfHD^t0E_G+Z)m-2O?_OIe24PVt5_L=F!;?DFv96{}R}~e| z6*TiIyS@oO`9z!zCqLR?_LIdXvmdRU{*&{qOqUk~QB1dMM==+EfPOwK%U19(mq2O+mKS8gX{Sl|em3B?W%N^5K#uXt-02 zkH59W)cgyv+QR##>XwUkETJFOUzziiFdzx{(75=ftB-O&rOeLoS1O5e>jR$UX#!`w2{D7*sFK)K3%DA=Ge(WsjV(q{Ne~)Iv9@4U$Vp;MC$kL;EiHG| z3Uv)gQXY+mG>LDUB~w7D6PYAP3r6-)(p@u4)yU{P+bN}9$zxvXHBs2;4mc$h4YVhx z^)LyJIi&y=buY{r*1!ME&i&rU4u^gk;EA46$*sde~}3KPpW!;*tHFu!bO&<7jVt%cIw5nuY=Ew&|ol?Jc@ z4WG0rF`Wp{4boUDn@g3x#h3pLEwc;$L9w`eOwelHwkHySeKTDs4##LOs^>?ZSwNWp z3WW-yK+E*3Hjd?7?3hqZEVnOHK5DbyyI9HI)i+m7+ui!MO^0fGs+N9r>)%oizZ!sN zYt4JkX`H|GzV^`t9{HX9+>WF2d#;_<p0(1IG5Fko{Z zhcK^%pl&L?2O8z7SMgN`5BTN+br%EyWIV?wR}M$9R_f~C`eDrOLm!&(I|f3V^EriJ zA(|b|Q3U20T<6Ew4~Cd05ud-swy`huFG`RRMBSj#I0ZHXi&Cy5PZGZgCzb<}eonFN zcH5FT>Mf|XLqr$7kmdej!Tl6k0|79kg;C`e&hL)%1@%LRu@$WwhA>9bSFt!Q6=f6Z|0FV0Veq?}TCm7=g*aNGXh zFf20!>TP#B08z0pYd4#kR9`_yx>B_S9>Pkw{`wmIV0U@4*gde)jQz92!EQ&trPqe0|7RNvRFcOU=hyh$Z+l)--Mxx$rDRdc zLEYQ1Xg?^(k7H}D(jCZuG~_*)uMK+3+M$Wkk<+gl;&xU#!0~5;wdgj^*hl2jeo4f^ zydP*yeBoJ#I=yGbCdaOEnpgSsb6jlPm;Phf)sU^P$d*Z`=!QYfa$I&)Vpg{*N`)3< zj>@(W8g-mvY?J_5Z$?+<%p&FYVFIT`NcbXKtQfGfV|30-gN)E2ftXns`;m^m+M%`P zlPwF;Hj2?32Y!V|G#P_4y})`^m3n=e)$hWW#I1 zpR@T0Pe_Yqt{Ilh1ABU!*=NlcHNR@wW_x7e8$_F-S2vs&2b*I@%{Ra#3)%F6-$s&-8Ke$?R+P+d53PPD7AGCDkR#s4vp9Ac=i$YdsS#MokLYghC$&tA_w zcRlmmv&ucI+;#D}YLOCQ*BF|mAUR2Z5sO_d7Q0$3Od&jK0WgnqtJG>?T6;b9)YWA@ zUFMlSE<9}#^>^e=+~=$*Y@(>Wc0H6{p!**%^Rp+-{Otd4<`=B|tZ3!`X;a;PYbf2> zeZqFn{;ch8=cy5(XKeTJKVrR~HJ`*G{ReQM4RNE>zzWBI>O3IcOS>^r2CO+c*l(>R zbHcE~E;iJetvfi3OGk%SI4Kar)&h0@j79e}$n~6m>0!X=cAI`{X_r1vyV;9rceQ?^ z`ds)j(p~)-(*5fXM)ik>7tZbv@~O9e6xEhLMnsEPpT0#_JB#p+3i zxW}%ashyBZ;HM<6J$CGwGjqm`sTSi|U8?_-QGHx`U0oD)y0{`X zEAgjN$`Q;N!$U@oqb?=2#YwPvw5h#A_^y(?&PwHN2j zGQxXd;3C%sT;v46g{-F^Kr!+P#mHn7BP|ruOL(+`fKe2K6>7Cx3ZCp0KnaL}m0z&k z@7%7wCCNfb`m^$f{cO;Lna?l3r~ZN}*=F>>3JNMye$1{v8D@h%#$M6B+v5wsJU+r0Z$j~etQMXp4sWD^!0?s^tNBkb4rcMnwC6e` zx{vp=%16Mt;YOCUFsP3ALRU^jVKVov3{)P!R1f$5mGitBy>w7#eh1>?KR=AevcbB6 zXsLQ){;1<#(*B(uUt~Ana;G(JsSW-wU4PEEoG%=17sTb)TYt_j-(Eq|F2Fu_xE$Db zL3%U;NYDTFL3+NcFunR}8&1mQQYN$CdD3zf6Z9Z+bkmb`>#ZwGmv4B}bngsq2|w8% zNXtj>1~zg$UVg~G9Qkn~#+xgY_Mrk>o;~rY(`_wnWBQE-tnDEV1%gV)ZsZO^oZXZ5N(K7swPlDCwPs zW*^#9GTvK@*Iz!vix2Xpcit<@cV}NSGD__F^ZOdlSpqOX$9bfu&d@r-#5;z4nuIOb za2V~vR$Q7^9GNDLqiwVcB5*kMJ!qBJmV3fIp5HE;*(ZEqgqLSgH!jOOO9Dzf+vD|l z<>}Od*W)~yfxlQj3P#fARxWqi(K5y}QaV?7I~-2~8NQnd7t)SgmTj~J!xR~APV0gwR5=5B&&)FfBmHV0JTvS)$u|1wvA3N@~16G&Db!peD#mQnNB%lA4KmNi_2olZP4& z08o=cJW}%?6ORc*BQ+kPks3ubx|zlfRO8h2-w0nSrpKr$?@FmzWXwaM&B9$fe3bkV zr7R!HJnYso6q^hywv{nv)Xd13q0NAnOQFQ5Sv@5dpu|!+FlzESFlrPB<|V;=ELaD; zt!H|CO6ROPkYX7MxFmZ8sXpaP1zitiKM821M!M9!edf6ZsP8bhLe1K^6>4VXR?uib zg{N>Q)I3P;q|<@~mexK0!RU*!%|N~dX3%mV|i(x6x~x-f=Y!7GDY*AIN1Ybnf+ zln2KXBV+PIW74oOC4u8{1jGDbIihXX#wbv;C`N(B@$2C<#(4CdtjZ$LGf)*5O78Hy% z3tCyMSQEXWgU7W6;Hnvb9R>BR>(`q2+s^>$NlH-lz- z%mtpPG2ZAkZPe8#)sOF=zg-UbsqOj`#9K5llY$*A|L9qIK^YDMCWy7h>dTZ6t+Ct$ z7MpS#1eqaq;Y>>sw5X7}AQ{%*D+{R$nlYq~HUr8$C8REB^&#~FA$39dA$38k52;Td zQlH$S$BH_JW_TKhOVIHlNZY;ZOaE!wj_2zP?%j1v^I7@(5&nN8Vy*p6m~(- z8rcOwiR^-))w2txnOc_Z_(GcT`1Jst9)j0H0k?-VzlX*;KCl;6w+y;Okc^m*wb3Pl zrvLHA>M85~VIfp6D*mUM?a!*H;}o(rX$*>>)iWqX7!*Ot42q!DGbrm|P^Nd(oW|C@ zbi<_}^u(SO!L_o?Yua7|H~+K!H(3T@{)g7a|Ij@A51ITA>4uM@{EsU2uGMy}y{WpZ zT~bf`6V{#Q`~5RMv8?*C{({2y=hM3gK13Lol&|hTy_X-PYT|N;mXZL zy}Jq_9)mm%H$phY%Z16ot@aU)+v;#%j(3LpqTW@g4aL`wd$B*CQ;Zi~FJ^sS5%mt5 zh?^2xqtxEg3*qerD~ie`85xq%U&(q6Qf+-gvIK{F*OX!dj;J3$;LDMx?i@0|8*XAc zXfvw8Hyv%&l{PK<&$~^HasB-DEMk8Z$Eb3A6<@AtQ}5Kb)v)2+rIJ5tt3^EO)Tx^K z>wFr@pFjAupl55Q9j%E0sT?%mut=X>8rY$MozZ|ZUknb=GBkI1GsW7NADWZ-L7M?J z9%p{I)O2cGwUD93e_>Vx$ro;h`jw6Hx(bv*MZQ-Ns!!IP@3xXhd0ZXJJ_>4oUb>q8 z2NWH2j3z9#w+(>s^gm((AYR-E$e7ClNdo;iU;@FM?nVQcuIoM^)`l~2_TxFL`U{S_<9o7 zq4jnIj;1h>rqM{6GN3eNU};JP)1;wkng&jjhNo#9pk9b}|3m&2EIAFs&~yGGN1z9g zqq0zr{K4Ki0G(kET%a(+=hLcq zb8ykgFC}ZK{U0s0=i7>C#LcvLWM}n`(|Qg`rES`!+SH77Nd<$8R}3z>WN-^=2DhMS zFr%H#z5|T1@9#E=H~>-h9bjkdJ3tZk9iYd)0|Ze6U<&&VFks)`+94yn*aPPAgx8;w z@mG7BB$!OC1E|zGKsIXq$OJZ{4hiT2QSLNH_fFMaM@Nk5!!Rhs-5_m_j;QO1R~-{o zWYA+7z^=)McB@R%M5@(q@w%U|9wOWF$ zms!}FPIv?8gg3ypg!eIIls&|F*a$Rqr+K~Zlunzttn1Y1&`b>VJVjAeRD!dur-Wy6 zx3Sz3-d2Eyak3gWFBO)!b}JzUh{OqRrm|=u9*~J|_C;xn7Y!InFt` z*iY5J)AWy`o34|QcTz1qM^B9CiSzW7$tMjb-?p2;q=D4DzejHi;(a05q|NFP z2NX8EnZ4{uE0%8f01V0SK<-X3@^iX>rGD2%+CUmBi>R{Rh}l?gH%8%-fR054tasK; zGln0UeerlZ!*9$WU85}kdQBO?d0lu1xt#7E9=?k4G zlg2mks1zkCGtP3c-#xb~Mc~$!!fUt%;5aK2sgjlaa0ORfz?;>4EYKdrM&u?to4b5sDIH*K9N2q;x?269*Z4eYm#?2kn| zhN|&P*Wk3jcKnniQchezjZU-oB-mIgUUQNV@CfI%#)(PDR$nBvaZCVWsxCRn;!k-T zh#O@I8lt-`*ZjA;|MJTO7y|X@2)=@0KifJ|1Pv6^RnEv+bzxYHsZAK^8*%@7eA@~# z?=^o3+tU@*M(j>+B&)RCi9954WN=RYI-t15g;nT?6hN*;2Zu8re!l6TiI)H zqsr^&^M1@RS(=y*(y2mwOOYxZ_sr<(6ADUmSVef~ftU3>pk9U;U^jUql;8=neO}%} zu#v!QG`h61ok;0+375Ouc>YRADzbw?BaEz}c zMGwIaVCXnXOF$;ot*y7rOsjY!Y;Bg+LZ#^wtEi}@)^|u*f*++|+ z1K~j)C2T#wu?hd&v5?TSROo1Rhqg{(W26u9IoK=FQ!fUyO8vOcpsza8RZCJW84i-J z^ZQ-%-kzZ{=FrjkICM-$2=^7qz{)3iC#a?WX20=>u(al=G!O%_qCb#6tO$k%D$a}x zIA8hd&Yp?pbIX6BuwNsN#u*<_X+5fD0(B+yBZ$ftE&+AXB`C7itCvV0^h#R%gcvB& z-Qq|4-5pvEXG(B>69UV}!xpH<4kY|4u)k+vX}Zi zKDPlo)7RsX#uL=k@FVb>VODe&gqk&~U9@WsG#d}(wCG>;8^@H)zH7=`RP)>Vw{1RD z_Ex%8J;>GLl2n5cLKc|3YM2_z)aa{4Zn>TC2f}8c$VJ*?kn*;fM!3BFAja;qRHI@s9KDg+Dzc(+< zRSmXAg0%j!ir;PYzrB;+~;;>NkIrKb|w<4Us24-pL9GV7|o> zcE4-F@{imQJ~?b>sPl%kj%^;?&sF9YAyH1MGu#O!vTxNS-w+uY<82?qkTI!r zzGtsdX&&OArqe!(aBH;AeS|f!Zun~D`hPG1I@CRWt0MR{5Ap(nkd9uwrxdI|sN~8% zEe~nalcw9CEHEVvROHWG>B*)IitLo*@RHaB?Z#>VWET0O2FD+}ZxQv2*I7>CL6_DU z*E-0pD&i_O+)FKiVa!~^>v`D1phGs}ddM`jm1(ye->LqeDY255FT~06oI5{r-vVH( zmpZFstzJ`E&K9i+$A8P&$5O(_WVXl`P|E}q%X zUfE+F6;o`G9|HEG(y`ScGuYv|d)IM)rBu4jhPWBEt{@ZCrLc}kQboI)ui2mrUpMeA z*oD_I)9&RihEBj#%=R&pga@i11A*8`pk!!@to>VGYKm?f9{j-%w?M<)q?=JNc|MKw zCt6)U)e$+Q1f()0Ut~sYUa`Yt^6I3x-qH(5YFe&$wq8&6F?pCq_Y{iY z0pQ@LR6C&{4xqHGAiG=#K-1c4+9MTn=4L5^0~jr!K=wnGNKo7`=IKPlUQrCC5DRgwmYQ zd)42BgFY-F!Zeu!)leWwDNNXxJ9y=47 zNo@KmZ6@-7H2G%=2b@e3hhBhw!L`~3ltWu5pg@GFkWPDA94~y#k98=dbD1s_ZSxMx zO!)Gr^$~b}L8uxP*pQta_@7^yPyj3f(aCC`-pnG9RtQz7f+2)!tn*~)x{F4pD}{f) zhymCW_yO_64^7HY+v~0`m6kV6;XI4okBgF#c-P|NQ3TD0Lnh&I)U139$cwODCRV9Q z3YDK$2rw&@esfM&-l*Yk3_M2X$vHaLY<(=chX6%3G=)_dqRu=wKcG-SnZ%jNg2~Er z7?*u$+{e8cx>&Gb-Hx#8VSiF|T8V8cXAO+HAIyl%N-UyHgEKFlFdZOC)AZGG5;U)8 zAZkBO{t8f@ceSf*!<%vMs16tt@`EmJAIvs=MurIVlrth9mizb9DUHVpnUK`sb;5$V z)RS+*?cgTXtPw+vAe;jy4+nw2O!1Qt*Mro#&BkadF>$8n>UEQSQwy;|#H7jXJ@yizDtf9F`aM4=%)nCG~SB5?Qp-5_&wCjrfK?Vr3V9ae4MJqC-W+Vt3 z^VLmbJY9sqk`_|0x+`(;kUk(m?p+{1W8f&BCV|-EfMSPwV}dwsYxbDRrdR6P)KZJ= zG0-)kdzBQF;z!%lFIUn_x0l3T&WHx@QXKbWDT5qDVd6KE_(8RcOrWHv09Ges?or8kg8|cYfc^^ zoMY}D-5BL%Zfcm`AhK%Xvm5YkXj5Qm-M0xBlGk#ZLF~Fgn48PDNEQP$afu&1<$}XY zHI18Rs7{P_$ioU!*n%u7airTE8%X3@Eid!I2?HXc6!r~Xv%0W))Rvv;ENOncPWC~a z=)(upJTMU<1Zm7DMp(qsF%6OKgq{WeM26{|NF70ZwbUqgu<4 zI%#LLA$?hG-PsC26c?gAhR#KgvpEv4exfRl@#>H!zKT9pf`X<6V|Sn` z-`jbi3Qw!)K=Z_eiT?Hp3&h&W6jvB)cwN^n^(Z`M#$+7y7nrMI=l#9*zSRJZb znVa*i#>wx(Zl)raPUz*l|8$^)=^IaZ|2J zyA`j~wMSsqv=s2?MH8WZME_YK6d)g3g_15BqlyGkAtH<`zUwKvt3Aj?`oL10hbJMx zl_dXduiC@zOy4=3|I(5>$%5O_yu+C}qwp5|0RdDl)qnj`m%VLrVeL-tB^@j z1txS@V}~b&LCHuyCxw)PCIG+O6=`FYiH$GeBU&#{uO(;i35k5XK4w+*(H@Cj>nh6C z>Q zH-#{dF^;a_Z8=r8bwQdiwtI1Ws}k>bjlD$_vO2UAbo)WL#mRsBh!Cn1%3!teVnb|$ zice?Eo@Sy!FU(_iG>j>r9BH)9va4w>#0-jWCtNNajS34q3cQ=E6DSa$x`JbxEJ_!z zWwgJ}1vmoH54#JWLQ__mM&gWYLld2&t6sp4hLyR}`qf+alT#QC%(@L(+nUKsWI}1C zWRGfLuaC%svD~%koj+{RUE`_nzB264cp9?a^`Xw&-%4U79Wm+3QD8W3N{z)J6ENUY z?T92JKdnyB!MK2x>boN>pSN{*Y6v^)FAMidokZdq;y=YFgkfLo}!;9_~33mz*B}7dM=~52aMJcAb;g#EOBJ&kaN0Us?OMb; zpR0n1vZGOmtEx!E_>Y<-)t9|zs8M>O7^QNIJ9>*lZ`R1IQfl2FL^JlGA*?g#Mse{= z#lSqlh){mGm>NI-UT&iKBo}_wI_+h{*V5M!&n;j#*LqRuB-@z5TwzU6!_5=|LGeWO zH4?ghA|*AbO`s_uiR`Dr2NSV*^#ri3L^DQ8qQ(HbG~1O|AYfo5pA@nIuHmz@s+_jj zfTmugaG$Pzu`rxy#Evf^u8cBDY+93yL|gdo3iLgS!9H169}|YC$#>pva0ABK|AHC* zi+*8CP^V38k}DLPO-`XDH9MY26Eqdl3bh2N&4vu(lA1I7hh$Xjrl)uu1D^)@XYYl_Dtk<*TvOk>EE$a^%vsEc$4M zkC6AGt(vbUJ5v-6{#CCwLazbh`uaslG-)n!sVgP;?gGp!Fzt6|&iLZc{)P!1Wr`+7 zEuu-3Ur&3PAXp)f!qt-HJ7M86{gJlAjXz*dg&Row*BU3-$h=~f7PX>O?5zNlEpbHP zrUvw2*Bm!e?8_3MesS-G4xWcPL{M@a4dNyKycCgyMjzC?3GHK}YO`>toKST7r-hV} zKwFM*#Reti35p4Ag3^{zi8X@tPgxDbDJSK(ON%^QB_m1QGJ;Qg#wcDNdKTqPRY+x7 zOiHfiu-U4Aq5?(>NmYr()rX?Iq&7|Yc1N0pjYiyKZmLzyy4cFP_c_r`@ctVdIoJ}) znI<4)3f9A;l_9nxEysUHZFsM4tGw z1G#`t%(OZLq!+&@yRiB&vm%^e%d*SBo0J4)IqM( z9C*(GJHa=t6#+Pp5J`?;e+!T-4iiax>9(K}+fFiQ8qK;j5x!?4^zsNJS!3xleN-%t zDZ}ufx_SD=g2}9%QDZ_#Ei8ED1}f zWnfS4@LbTxE`Nh05+yc4Z|}x>3a=6rQ@)d(9Ma>ID3L^%%rX<53#mvhzxkE=A9C;5!Ti+F>YkWXb*9p}W(U*A4l7qlIpG zn-FSa!NSC*_%He&NREx5yG3NRx}v1D*!P?t*2v9O>3MU7Om4W<&N; z5}g8??N|DUqgu=_5HfT@ijt+Cn|tEYOUzKzAn)><%W(tW z1V&5dOd`v3uMQeWUV9_t+clbwFA^@K*@s0-M=j+`mb0=T?mUL)U)I zlUE${3C`z%mR8shQq!yc^qkWgRgJ@fR*yfoEp!ZV`9@!;IZK z#$hR~m`J`_x=x};AVoI#nyFDISXVveFAw2u<%2g@@2=K4ia@<^wZfIFxMT;2$TkUyN8v78Zj?2eRLq z;UZG>#KHz@?NuahKd_03^m_3AVyFK8?!m8Kx0}ftg;G9k3p{^?Jk$oSe7cl43`lnn z*GOV-^HXmso`M(h`S!jTG+qjaxS9XH$M8t|2(DjwljaR5CC81W)S6!WbvSZcx7Ix) zlvHxieeHI)m8z2j(Jgu(Cc7MyLo9Yl_6nxBjziVy@IaiSANT(q5C2JR0mG&-wMaDR z1Djc@-Nrvm+S>kD52abIt}7rHz#H3gX+!KrbyA(3`z9jl@iA!AJOxk~sxPhU5y2|B zt7h=!2KDe0VXzT?hJW`r3yDO=mZMRQ=T~(#+<{em6m2j+;fBgvjjO?Z#>ZN}Bv*pq zr$QNMw|XotML}5o1L1kk zbigmZPg73TT?ZMeiBk_P(bm@=Y$o z6hoV*<(moD5rccNYNAT^8LaJJOM1;=Y!{$muU2!YB%%Q?FGF{A6 zyb3mcAGzFYb_9^93W2V&X2w+5EKQN7&(na_zk?td;mZ&VDhgIl37*49*s#Qxf++65 z6&LyA*+9&z2;$%du;O&X6?0f~SPpv@NTwI5ii9xj*Z?hXT1YL&au{B4Ruk#jY3!xW>E@r4}3Qm9FO4Whkg+YBf*v`@Bky3ixO2gdU?3Aojyh~rUA{` z5n}-ZkF*-JPVvg;DssionM3C&%N0ybkbb8n39F!EqeagfZsp_VaQ*N(nhj zdB32_vnu3X`n;8dOxHHAfE#J{-ijgp@0u#^!k(7ZK%;oJnUVOzB_~TdRY6tf@(({Io0|HcZZi=geUU}SxTSp^T z@Js?jsvD7)FFX&T`Up|DYAw-hDl)=TTxNgg`Hh|ai=oa`E<6L=prK2CKsJb%mFbBP ze^hP|`lkM$%~L$);8?P1>+E@2^>c4M<~tz}5nmjnpL>eUFps&X2Q--mk|JLfkq+7M z1l-4t{Ehmc&5p(dXr4Tq}xh~r#+jvW^b`xRmjX3H&dK0)u*{s-4OkR?A-JC~B@CBzEI&;@Wdh=?ew z&ppepj|z^(#UxFrF95)h{C?}|B2I`zJQAP{U~;)GTNvH&Dq^XF1c~B=Qi42PAAdlK zIiOy=Rdkp!CE<_3=m>tJ3Dxw$fVLAzc+nsWNQ`2(OsB?@F9mM`hu%KJAqVy|sw6Vr za@#G7s5@;(sqLvZZjF~;0NWJfDzrJm+j@} z82nix9v#%L%RSNZp6)d#RuP66?XF_Ua)_};G~g&a&5TPN{P*SWALj0?N!K`H0uF8} z%Axu8*!ANjARSbeGReiEBl`yfCQ;CO}~=48#czu-2cPyJ8Kd% zh#f9kCxS3tqs-~OkpBk7(CV$#1i+W75IK?hx`aoF&(}Z31ABLknq@%R&4F~v9lj3j zAT*tBV>k)R#>=M!ekD}~hg-ij^S4)XvY!0YorVb%RVpq!_$#D^AO1STnLbclKC3lL zQ0V!vIzS>E7|952T&-z&E7Kwmf9{t>^iJ$Z=qqPkH@ZD*hJI~eK;>0XBng7S%tNq2 zivcG6tWd}l3zA((05_w5D$@l=8r&6HAGyUMulsM3K!NT605O7x)NhF`qJXNK$KyAB z=0H&xLNnm)_>Jpao-4xXX-^oeGbhopFdNwez4<2xkU$`bGPzlxkFc+9CJ3&V$f=v}+y0 z;FZx-(0rTxh+wKi2Qm7KW|?Kzicvse5>Vuj0IG;{yB z2);9=6c(b=iP9GNqk}6C&nX)6Je9&XD60prZf|55xUz9r&SZGJ+;qM4c->4+Pq%9G zUJO(~=Y}#a5(fRVQHd`+mCl&}L zuh`;xXHdSkru?1Kdy;%Km$%iK8JhhJ{Casd7gB9J_2pDa9A z7@ay@yRFSjHrP1+=WI_jUL?O?65PX%+^YYt#H)lnB>7{mVz1}r!f2E210iT z4g)wqjZ~-NnM4+FFZwTO0a%C<8m(%5tm32TPsmtBG4V`Y^yYY7!?r-Om>_$w@rJT0 zjCp^OnA+q9(izIe)4fXBx49Q;A!N~zbRnoY1{-0GCsUEIoeW`y{i&HLXxkm!!ga(M zYx~hg@L|X}WI|=22jVm3u@iCEq4IT(La>y2NiQw2?`_)QJZSJl9`~4wnW`OL(8*ZP zZzHi(-14CMe_z3#?|ttH(Ddtu?L4{^tzTKvA9J-_^na$lVpW{EiFO^QSONp70?kS! zn=~6(@RdhP`VR*^zvZ*kn$R5&5Y-(m%~2ueqbrlPcd$&eZQob(4$aNcFFGpb7S@}u z81#pDa3Nj2E2=30SK-Ne>Oaoz5ni+kdFthbZi}o~t1T38-ovL4-&gv@zxbgmH^F<7 z@3B=!H}}=lczPn~pr{Z=@kgS7W3DKTB=A>mhcg2i7N!42BQ((nzm8oO zWeQ4UkhcC(F-H)rDoW3gz%`jGa;`RoEWt9VX{5CW@DrC}v#R1}coh?8!A2fwU58s_ zLZ5Os|0pBc`R!iu> z+Uo!{M%fiI9WW!9;Rxcexu{nYu?+^RIwwbN^-*vcysvMdobI!(4)?%6Z@;NRXx7j2 z*-kKIAovN)Xm#sx(bK!l<@*w;#YWi@xP&>!IIp*6HIEFF+~1tY;w4zoHj+cFe{cWk zJWn@KRfMc6)2#9(LzxVtaAEAD!c!lxPxbb}^Yq+2wZ~sk!B6js`^dGFv(MhdA8fOZ zKe^BW-MR1K?Pd#2{Y^Eu0srb7L>lV9Cm?uOklw*({PjokZ_2Wrp?@u9X-HnWU(go1 zh-;bI;xnO9yGY_EMbK9o)(v{dQ5pK1aFC;@w&m_wCZ<8)$nXY&R?Z%}oQI(+eN>Cj zfxQL5*|U18!aVieeBSWPN8%=`Ye~Fo95L;rXe_40DmMfRm(DNNdQbEV6@V%|BlDseiTKH1GP0zx^pd8vYZt%G4Pz&cJ zBuf!1qn4pr4z@|mI~C{n@qDdq5KqyzojF!c!`k{B$wdp7UstuVe9rf9NVm4?DU{al zJQj>A-9XGmTeuBvIxh5lG+uvoew}w5Yd!A*D>gF5XCUN_D>?rJOK| zn(!f=*9z~3$5NTWf|yGVE{T~(54ve2_^@GY>d&eA?%G`_kD2o{KK8bmYCJQz7df-guXSRY=%et_M4qS$ zdZz7tu-!Qn<5Lath=vK~E-(OD(8rXr{#(g#uv%f1D+MY&37kE(%z;sp?7Q2>joe0v z1#>Cx9487ki=25gh95(8I4N}e=&#vMOy^mYVTfn1b7Iho1> z>wl=HQ(8Agxw2+D3z)i^R(HCYIwhj*Kz1t0Z(d$K)4ZC39K{wTH4we{z6E&+Q0aNd zi*qwKMbWMgUU}7|xR0v69;ReW)i5re#ojW1pEcb13J6$Vo$v;DNamtm)la@8@QXLA z=3Y1@pA@;gp=7S+B2j-=+Xvsh5WGTy-h3I3_Pto&n>SvASH5gQI(>)mF@&pLsa9QM z1gUtM<}gl=+-{yk_{2ip`&H}ELYL^TuI{vuO!P5M?r}z11%8ZVuCIU6diDRE{C%VP zn-WBYa;5C`=u@CIAE0yB%DyvGJ|QQropT}TiqwufF7^c&EtGWebiDhSaJC0*63nM$ zM<9>sopAi}r70PponhhIpq{D;TjvQj`JKxM`?8%u5cqDFZ zYvEMrW0h6Q4uI1L z=zB`E151mUE|S#GyvUU?uBka_m(%_S4<0$Uu&darGsiZD`WQ-$-m**Lx7sY6OX#6T%~^Wvk-8*`fqXN z6!`s+bY$2nl}XBQeixv@6v!imutsuPBEbVYqvWFk!2@ld*2_KF{%~?bTw+Qew)OJM zkstJoNV=yfAjH{5- zQ9q4451N_#^)B{RU4i|9v+jNuQC-D)9q#V0Gh2IOT-1=Y28bOS z`lgN|7&gmt7K~^fxUOA@XjbG3<`8x1ATVnNb~e8i4H>bpNO-s0X2{ubf8kU8s`4b- zKjgoFaxYqzY<>8yfwsAXw}g2scI~umkcqWL#ae$ar+ZX|F^h~g+>KTb#=jxZ4KdMy z%OqGUC__oY94%+u9WAfDj`ofuy>j};-P{^vD%tv2xpuff>c;7++HU#!CHjh;DSUk_ zDtvYCqI`)Rqxe8LDgTAQTVm)F2j@pPIN-?UvlxppR$FVQmnKR*jKDs`U`&@IB5eOG zctfHKb;D#aNgrj-n(TFtnLK6^O(kK02n0J&i9)ICIbI)qwbGP}jN&p(%1Lcu{iXH{+_aGT zewWcf3mvoYNX@@}n;FeZH_-zg8mj##bX?Jrp1POqp#^0E%g6Wy%<3e?EkI~4)I?T0sVJj{Og;+^1tr>8{L1Yi~s-t literal 0 HcmV?d00001 diff --git a/trdos386/programs/16bit/playwav8.asm b/trdos386/programs/16bit/playwav8.asm new file mode 100644 index 0000000..dce94be --- /dev/null +++ b/trdos386/programs/16bit/playwav8.asm @@ -0,0 +1,6503 @@ +; **************************************************************************** +; playwav8.asm (for Retro DOS) +; ---------------------------------------------------------------------------- +; PLAYWAV8.COM ! AC'97 (ICH) .WAV PLAYER program by Erdogan TAN +; +; 14/11/2024 +; +; [ Last Modification: 18/12/2024 ] +; +; Modified from PLAYWAV7.COM .wav player program by Erdogan Tan, 13/11/2024 +; +; Assembler: FASM 1.73 +; fasm playwav8.asm PLAYWAV8.COM +; ---------------------------------------------------------------------------- +; In the visualization part of the code, the source code of Matan Alfasi's +; (Ami-Asaf) player.exe program was partially used. +; ---------------------------------------------------------------------------- +; Previous versions of this Wav Player were based in part on .wav file player +; (for DOS) source code written by Jeff Leyla in 2002. + +; playwav7.asm (13/11/2024) + +; TUNELOOP version (playing without AC97 interrupt) - 06/11/2023 - Erdogan Tan +; sample rate conversion version - 18/11/2023 - Erdogan Tan + +; CODE + + ; 13/11/2024 +macro sys_msg op1,op2 +{ ; 30/05/2024 + mov si, op1 ; message + mov bl, op2 ; text color + xor bh, bh ; video page 0 + mov ah, 0Eh + call p_msg +} + +; player internal variables and other equates. +;BUFFERSIZE equ 64 * 1024 ; 64k file buffer size. +; 17/11/2024 +BUFFERSIZE equ 65520 +ENDOFFILE equ 1 ; flag for knowing end of file + +use16 + +org 100h + + include 'ac97.inc' ; 17/02/2017 + +_STARTUP: + ; 30/05/2024 + ; Prints the Credits Text. + sys_msg Credits, 0Bh + + ; 30/05/2024 + call setFree ; deallocate unused DOS mem + + ; 17/02/2017 + ; Clear BSS (uninitialized data) area + xor ax, ax ; 0 + mov cx, (bss_end - bss_start)/2 + mov di, bss_start + rep stosw + + ; Detect (& Enable) AC'97 Audio Device + call DetectAC97 + ;jnc short GetFileName + ; 30/05/2024 + jnc short allocate_memory + + ; 30/05/2024 +_dev_not_ready: + ; couldn't find the audio device! + sys_msg noDevMsg, 0Fh + jmp Exit + + ; 30/05/2024 +allocate_memory: + +; allocate 256 bytes of data for DCM_OUT Buffer Descriptor List. (BDL) + + mov ax, BDL_SIZE / 16 + call memAlloc + mov [BDL_BUFFER], ax ; segment + +; allocate 2 buffers, 64k each for now. + + mov ax, BUFFERSIZE / 16 ; 64k for .WAV file + call memAlloc + mov [WAV_BUFFER1], ax ; segment + + mov ax, BUFFERSIZE / 16 + call memAlloc + mov [WAV_BUFFER2], ax + + ; 30/05/2024 +GetFileName: + mov di, wav_file_name + mov si, 80h + mov bl, [si] + xor bh, bh + inc bx + mov byte [si+bx], 0 ; make AsciiZ filename. + inc si +ScanName: + lodsb + test al, al + jz pmsg_usage + cmp al, 20h + je short ScanName ; scan start of name. + stosb + mov ah, 0FFh + ;;; + ; 14/11/2024 + ; (max. path length = 64 bytes for MSDOS ?) (*) + xor cx, cx ; 0 + ;;; +a_0: + inc ah +a_1: + ;;; + ; 14/11/2024 + inc cx + ;;; + lodsb + stosb + cmp al, '.' + je short a_0 + and al, al + ;jnz short a_1 + ;;; + ; 14/11/2024 + jz short a_3 + and ah, ah + jz short a_2 + cmp al, '\' + jne short a_2 + mov ah, 0 +a_2: + cmp cl, 75 ; 64+8+'.'+3 -> offset 75 is the last chr + jb short a_1 +a_3: + ;;; + or ah, ah ; if period NOT found, + jnz short _1 ; then add a .WAV extension. +SetExt: + dec di + mov dword [di], '.WAV' ; ! 64+12 is DOS limit + ; but writing +4 must not + ; destroy the following data + mov byte [di+4], 0 ; so, 80 bytes path + 0 is possible here +_1: + call write_audio_dev_info + +; open the file + ; open existing file + ; 14/11/2024 + ;mov al, OPEN ; open existing file + mov dx, wav_file_name + call openFile ; no error? ok. + jnc short getwavparms ; 14/11/2024 + +; file not found! + sys_msg noFileErrMsg, 0Ch +_exit_: + jmp Exit + +getwavparms: + ; 14/11/2024 + call getWAVParameters + jc short _exit_ ; nothing to do + + ; 17/11/2024 + mov bl, 4 + sub bl, byte [WAVE_BlockAlign] + ; = 0 for 16 bit stereo + ; = 2 for 8 bit stereo or 16 bit mono + ; = 3 for 8 bit mono + + shr bl, 1 ; 0 --> 0, 2 --> 1, 3 --> 1 + ; 15/11/2024 + adc bl, 0 ; 3 --> 1 --> 2 + mov byte [fbs_shift], bl ; = 2 mono and 8 bit + ; = 0 stereo and 16 bit + ; = 1 mono or 8 bit + ; 30/05/2024 + call codecConfig ; unmute codec, set rates. + jc init_err + + ; 15/11/2024 + ;; Set video mode to 03h (not necessary) + mov ax, 03h + int 10h + + ; 15/11/2024 + ;; Get the cursor type + mov ah, 03h + int 10h + mov [cursortype], cx ; save + + ; 15/11/2024 + ;; Set the cursor to invisible + mov ah, 01h + mov cx, 2607h + int 10h + + ;;; 14/11/2024 +Player_SplashScreen: + ; 15/11/2024 + ;xor dx, dx + ;call setCursorPosition + + ;; Print the splash screen in white + mov ax, 1300h + mov bx, 000Fh + mov cx, 1999 + mov dx, 0 + + mov bp, SplashScreen + int 10h + ;;; + + ;;; + ; 22/11/2024 + ; set wave volume led addresses + mov bx, 13*80*2 + mov bp, 80 + mov di, wleds_addr +wleds_sa_1: + mov cx, 7 +wleds_sa_2: + mov ax, 80*2 + mul cx + add ax, bx + stosw + loop wleds_sa_2 + mov ax, bx + stosw + inc bx + inc bx + dec bp + jnz short wleds_sa_1 + ;;; + + ;;; wait for 3 seconds + mov cx, 002Dh + mov dx, 0C6C0h + mov ah, 86h + int 15h + ;;; + + ;;; +Player_Template: + xor dx, dx + call setCursorPosition + + ;; Print the splash screen in white + mov ax, 1300h + mov bx, 000Fh + mov cx, 1999 + ; 09/12/2024 + ; dx = 0 + ;mov dx, 0 + + mov bp, Template + int 10h + ;;; + + ; 14/11/2024 + call SetTotalTime + call UpdateFileInfo + + ; 25/11/2023 + ; ------------------------------------------ + + ; 18/11/2023 (ich_wav4.asm) + ; 13/11/2023 (ich_wav3.asm) + + cmp byte [VRA], 1 + jb short chk_sample_rate + +playwav_48_khz: + mov word [loadfromwavfile], loadFromFile + ;mov word [loadsize], 0 ; 65536 + ;;; + ; 17/11/2024 + ;mov word [buffersize], 32768 + mov ax, BUFFERSIZE/2 ; 32760 + mov [buffersize], ax ; 16 bit samples + shl ax, 1 ; bytes + mov cl, [fbs_shift] + shr ax, cl + mov [loadsize], ax ; 16380 or 32760 or 65520 + ;;; + jmp PlayNow ; 30/05/2024 + +chk_sample_rate: + ; set conversion parameters + ; (for 8, 11.025, 16, 22.050, 24, 32 kHZ) + mov ax, [WAVE_SampleRate] + cmp ax, 48000 + je short playwav_48_khz +chk_22khz: + cmp ax, 22050 + jne short chk_11khz + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_22khz_1 + mov bx, load_22khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_22khz_2 + mov bx, load_22khz_mono_16_bit + jmp short chk_22khz_2 +chk_22khz_1: + mov bx, load_22khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_22khz_2 + mov bx, load_22khz_mono_8_bit +chk_22khz_2: + mov ax, 7514 ; (442*17) + mov dx, 37 + mov cx, 17 + jmp set_sizes +chk_11khz: + cmp ax, 11025 + jne short chk_44khz + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_11khz_1 + mov bx, load_11khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_11khz_2 + mov bx, load_11khz_mono_16_bit + jmp short chk_11khz_2 +chk_11khz_1: + mov bx, load_11khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_11khz_2 + mov bx, load_11khz_mono_8_bit +chk_11khz_2: + mov ax, 3757 ; (221*17) + mov dx, 74 + mov cx, 17 + jmp set_sizes +chk_44khz: + cmp ax, 44100 + jne short chk_16khz + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_44khz_1 + mov bx, load_44khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_44khz_2 + mov bx, load_44khz_mono_16_bit + jmp short chk_44khz_2 +chk_44khz_1: + mov bx, load_44khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_44khz_2 + mov bx, load_44khz_mono_8_bit +chk_44khz_2: + ;mov ax, 15065 ; (655*23) + ; 18/11/2023 ((file size + bss + stack) <= 64KB) + ;mov ax, 14076 ; (612*23) + ; 17/11/2024 + mov ax, 12650 ; (550*23) + mov dx, 25 + mov cx, 23 + jmp set_sizes +chk_16khz: + cmp ax, 16000 + jne short chk_8khz + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_16khz_1 + mov bx, load_16khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_16khz_2 + mov bx, load_16khz_mono_16_bit + jmp short chk_16khz_2 +chk_16khz_1: + mov bx, load_16khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_16khz_2 + mov bx, load_16khz_mono_8_bit +chk_16khz_2: + ;mov ax, 5461 + ; 17/11/2024 + mov ax, 5460 + mov dx, 3 + mov cx, 1 + jmp set_sizes +chk_8khz: + cmp ax, 8000 + jne short chk_24khz + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_8khz_1 + mov bx, load_8khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_8khz_2 + mov bx, load_8khz_mono_16_bit + jmp short chk_8khz_2 +chk_8khz_1: + mov bx, load_8khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_8khz_2 + mov bx, load_8khz_mono_8_bit +chk_8khz_2: + mov ax, 2730 + mov dx, 6 + mov cx, 1 + jmp short set_sizes +chk_24khz: + cmp ax, 24000 + jne short chk_32khz + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_24khz_1 + mov bx, load_24khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_24khz_2 + mov bx, load_24khz_mono_16_bit + jmp short chk_24khz_2 +chk_24khz_1: + mov bx, load_24khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_24khz_2 + mov bx, load_24khz_mono_8_bit +chk_24khz_2: + ;mov ax, 8192 + ; 17/11/2024 + mov ax, 8190 + mov dx, 2 + mov cx, 1 + jmp short set_sizes +chk_32khz: + cmp ax, 32000 + jne short vra_needed + cmp byte [WAVE_BitsPerSample], 8 + jna short chk_32khz_1 + mov bx, load_32khz_stereo_16_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_32khz_2 + mov bx, load_32khz_mono_16_bit + jmp short chk_32khz_2 +chk_32khz_1: + mov bx, load_32khz_stereo_8_bit + cmp byte [WAVE_NumChannels], 1 + jne short chk_32khz_2 + mov bx, load_32khz_mono_8_bit +chk_32khz_2: + ;mov ax, 10922 + ; 17/11/2024 + mov ax, 10920 + mov dx, 3 + mov cx, 2 + ;jmp short set_sizes +set_sizes: + ;;; + ; 17/11/2024 + push cx + mov cl, 2 + sub cl, [fbs_shift] + ; = 2 for 16 bit stereo + ; = 1 for 16 bit mono or 8 bit stereo + ; = 0 for 8 bit mono + shl ax, cl + pop cx + mov [loadsize], ax ; (one) read count in bytes + ;;; + mul dx + cmp cx, 1 + je short s_2 +s_1: + div cx +s_2: + ;;; + ; ax = byte count of (to be) converted samples + + ; 17/11/2024 + ;;; + mov cl, [fbs_shift] + + shl ax, cl + ; *1 for 16 bit stereo + ; *2 for 16 bit mono or 8 bit stereo + ; *4 for for 8 bit mono + ;;; + + ; ax = 16 bit stereo byte count (target buffer size) + + shr ax, 1 ; buffer size is 16 bit sample count + mov [buffersize], ax + mov [loadfromwavfile], bx + jmp short PlayNow + +vra_needed: + ; 13/11/2023 + pop ax ; discard return address to the caller + ; 30/05/2024 +vra_err: + sys_msg msg_no_vra, 0Fh + jmp Exit + + ; 15/11/2024 + ; 30/05/2024 + ; 13/11/2023 (ich_wav4.asm) +;loadfromwavfile: +; dw loadFromFile +;loadsize: ; read from wav file +; dw 0 +;buffersize: ; write to DMA buffer +; dd 32768 ; 16 bit samples (not bytes) + +PlayNow: + ;;; + ; 14/11/2024 + mov al, 3 ; 0 = max, 31 = min + ; 15/11/2024 + ;call SetMasterVolume + call SetPCMOutVolume + call UpdateVolume + ;;; + + ;;; + ; + ; 14/11/2024 + call UpdateProgressBar + ;;; + + ; 30/05/2024 + ; playwav4.asm +_2: + call check4keyboardstop ; flush keyboard buffer + jc short _2 ; 07/11/2023 + +; play the .wav file. Most of the good stuff is in here. + + call PlayWav + +; close the .wav file and exit. + +Exit: + ; 15/11/2024 + ;; Restore Cursor Type + mov cx, [cursortype] + cmp cx, 0 + jz short Exit@ + mov ah, 01h + int 10h +Exit@: + call closeFile + + mov ax, 4C00h ; bye ! + int 21h +here: + jmp short here ; do not come here ! + + ; 30/05/2024 +pmsg_usage: + sys_msg msg_usage, 0Fh ; 14/11/2024 + jmp short Exit + + ; 30/05/2024 +init_err: + sys_msg msg_init_err, 0Fh + jmp short Exit + + ; -------------------------------------------- + + ; 29/05/2024 (TYRDOS 386, playwav7.s) + ; ((Modified from playwav4.asm, ich_wav4.asm)) + ; ------------------ +;playwav_vra: +PlayWav: + ; create Buffer Descriptor List + + ; Generic Form of Buffer Descriptor + ; --------------------------------- + ; 63 62 61-48 47-32 31-0 + ; --- --- -------- ------- ----- + ; IOC BUP -reserved- Buffer Buffer + ; Length Pointer + ; [15:0] [31:0] + + push es + mov ax, [BDL_BUFFER] ; get segment # for BDL + mov es, ax + + mov cx, 32 / 2 ; make 32 entries in BDL + xor di, di +_0: + movzx eax, word [WAV_BUFFER1] + shl eax, 4 ; convert seg:off ->0:offset + stosd ; store pointer to wavbuffer1 + + ;mov eax, BUFFERSIZE / 2 ; size of buffer (32K) in (16bit) words + ; 13/11/2023 (ich_wav3.asm) - 18/11/2023 (ich_wav4.asm) + mov eax, [buffersize] + + ;or eax, IOC + BUP + ; 06/11/2023 (TUNELOOP version, without interrupt) + or eax, BUP + stosd + + movzx eax, word [WAV_BUFFER2] + shl eax, 4 ; convert seg:off ->0:offset + stosd ; store pointer to wavbuffer2 + + ;mov eax, BUFFERSIZE / 2 ; size of half buffer (32K) + ; 13/11/2023 (ich_wav3.asm) - 18/11/2023 (ich_wav4.asm) + mov eax, [buffersize] + + ;or eax, IOC + BUP + ; 06/11/2023 (TUNELOOP version, without interrupt) + or eax, BUP + stosd + + loop _0 + pop es + + ; 14/11/2024 + ;mov word [count], cx ; 0 + ;mov dword [LoadedDataBytes], 0 + + ; 19/11/2024 +RePlayWav: + + ; load 64k into buffer 1 + mov ax, [WAV_BUFFER1] + ;call loadFromFile + ; 13/11/2023 + call word [loadfromwavfile] + ; 14/11/2024 + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + ; 18/12/2024 + mov word [count], 0 + + ; and 64k into buffer 2 + mov ax, [WAV_BUFFER2] + ;call loadFromFile + ; 13/11/2023 + call word [loadfromwavfile] + ; 14/11/2024 + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + ; write NABMBAR+10h with offset of buffer descriptor list + + movzx eax, word [BDL_BUFFER] + shl eax, 4 ; convert seg:off to 0:off + mov dx, [NABMBAR] + add dx, PO_BDBAR_REG ; set pointer to BDL + out dx, eax ; write to AC97 controller + + ; 19/05/2024 + call delay1_4ms + + mov al, 31 + call setLastValidIndex + + ; 19/05/2024 + ;call delay1_4ms + + ; 17/02/2017 + mov dx, [NABMBAR] + add dx, PO_CR_REG ; PCM out Control Register + ;mov al, IOCE + RPBM ; Enable 'Interrupt On Completion' + run + ; ; (LVBI interrupt will not be enabled) + ; 06/11/2023 (TUNELOOP version, without interrupt) + mov al, RPBM + out dx, al ; Start bus master operation. + + ; 19/05/2024 + ; 06/11/2023 + call delay1_4ms ; 30/05/2024 + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + +; while DMA engine is running, examine current index and wait until it hits 1 +; as soon as it's 1, we need to refresh the data in wavbuffer1 with another +; 64k. Likewise when it's playing buffer 2, refresh buffer 1 and repeat. + +; 18/11/2023 +; 08/11/2023 +; 07/11/2023 + + ; 19/11/2024 + mov byte [wleds], 1 + + ;;; + ; 09/12/2024 + mov ax, 10548 ; (48000*10/182)*4 + cmp byte [VRA], 0 + jna short _3 ; 48kHZ (interpolation) + ; + mov ax, [WAVE_SampleRate] + mov cx, 10 + mul cx + mov cl, 182 + div cx + ; ax = samples per 1/18.2 second + ;mov cl, byte [WAVE_BlockAlign] + ; 09/12/2024 + ;mov cl, 4 ; 16 bit, stereo + ;mul cx + shl ax, 2 ; * 4 +_3: + mov [wleds_dif], ax ; buffer read differential (distance) + ; for wave volume leds update + ; (byte stream per 1/18.2 second) + ;;; + +tuneLoop: + ; 30/05/2024 + ; 18/11/2023 (ich_wav4.asm) + ; 08/11/2023 + ; 06/11/2023 + +tLWait: + ; 18/11/2024 + cmp byte [stopped], 0 + ;jna short tL@ + ; 21/11/2024 + ja short tLWait@ + mov al, [tLP] + cmp al, '1' + ja short tL2@ + je short tL1@ + mov al, '1' + mov [tLP], al + jmp short tL1@ +tLWait@: ; 21/11/2024 + call checkUpdateEvents + jc _exitt_ + cmp byte [tLO], '0' + je short tLWait + call tLZ + mov byte [tLO], '0' + jmp short tLWait + +;tLO: db 0 + +tL1@: + ;mov al, '1' + ; 19/11/2024 + mov [tLO], al + call tL0 +tL1: + call updateLVI ; /set LVI != CIV/ + jz short _exitt_ ; 08/11/2023 + ;;; + ;call check4keyboardstop + ; 14/11/2024 + call checkUpdateEvents + jc short _exitt_ + ; 18/11/2024 + cmp byte [stopped], 0 + ja short tLWait@ ; 21/11/2024 + ;;; + call getCurrentIndex + test al, BIT0 + jz short tL1 ; loop if buffer 2 is not playing + + ; load buffer 1 + mov ax, [WAV_BUFFER1] + ;call loadFromFile + ; 18/11/2023 + call word [loadfromwavfile] + jc short _exitt_ ; end of file + + ; 14/11/2024 + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + mov al, '2' + ; 21/11/2024 + mov [tLP], al +tL2@: + ; 19/11/2024 + mov [tLO], al + call tL0 +tL2: + call updateLVI + jz short _exitt_ ; 08/11/2023 + ;;; + ;call check4keyboardstop + ; 14/11/2024 + call checkUpdateEvents + jc short _exitt_ + ; 18/11/2024 + cmp byte [stopped], 0 + ja short tLWait@ ; 21/11/2024 + ;;; + call getCurrentIndex + test al, BIT0 + jnz short tL2 ; loop if buffer 1 is not playing + + ; load buffer 2 + mov ax, [WAV_BUFFER2] + ;call loadFromFile + ; 18/11/2023 + call word [loadfromwavfile] + ;jnc short tuneLoop + jc short _exitt_ + + ; 14/11/2024 + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + ; 21/11/2024 + mov byte [tLP], '1' + jmp tuneLoop +_exitt_: + mov dx, [NABMBAR] + add dx, PO_CR_REG ; PCM out Control Register + mov al, 0 + out dx, al ; stop player + + ;;; + ; 14/11/2024 + call UpdateProgressBar + ;;; + + ; 18/11/2024 +tLZ: + ; 30/05/2024 + mov al, '0' + + ;add al, '0' + ;call tL0 + ; + ;retn + ; 06/11/2023 + ;jmp short tL0 + ;retn + + ; 06/11/2023 +tL0: + ; 08/11/2023 + ; 05/11/2023 + ; 17/02/2017 - Buffer switch test (temporary) + ; 06/11/2023 + ; al = buffer indicator ('1', '2' or '0' -stop- ) + + push ds + ;push bx + mov bx, 0B800h ; video display page segment + mov ds, bx + sub bx, bx ; 0 + mov ah, 4Eh + mov [bx], ax ; show current play buffer (1, 2) + ;pop bx + pop ds + + retn + +; ------------------------------------------- + + ; 14/11/2024 +;SetMasterVolume: + ; 15/11/2024 +SetPCMOutVolume: + ;cmp al, 31 + ;ja short setvolume_ok + mov [volume], al ; max = 0, min = 31 +SetPCMOutVolume@: ; 19/11/2024 + mov ah, al + mov dx, [NAMBAR] + ; 15/11/2024 (QEMU) + ;add dx, CODEC_MASTER_VOL_REG + add dx, CODEC_PCM_OUT_REG + out dx, ax +;setvolume_ok: + retn + +; ------------------------------------------- + + ; 30/05/2024 +DetectAC97: +DetectICH: + ; 22/11/2023 + ; 19/11/2023 + ; 01/11/2023 - TRDOS 386 Kernel v2.0.7 + ;; 10/06/2017 + ;; 05/06/2017 + ;; 29/05/2017 + ;; 28/05/2017 + + ; 19/11/2023 + mov si, valid_ids ; address of Valid ICH (AC97) Device IDs + mov cx, valid_id_count +pfd_1: + lodsd + call pciFindDevice + jnc short d_ac97_1 + loop pfd_1 + + ;stc + retn + +d_ac97_1: + ; eax = BUS/DEV/FN + ; 00000000BBBBBBBBDDDDDFFF00000000 + ; edx = DEV/VENDOR + ; DDDDDDDDDDDDDDDDVVVVVVVVVVVVVVVV + + ; playwav4.asm - 19/05/2024 + + mov [bus_dev_fn], eax + mov [dev_vendor], edx + + ; get ICH base address regs for mixer and bus master + + mov al, NAMBAR_REG + call pciRegRead16 ; read PCI registers 10-11 + ;and dx, IO_ADDR_MASK ; mask off BIT0 + ; 19/05/2024 + and dl, 0FEh + + mov [NAMBAR], dx ; save audio mixer base addr + + mov al, NABMBAR_REG + call pciRegRead16 + ;and dx, IO_ADDR_MASK + ; 19/05/2024 + and dl, 0C0h + + mov [NABMBAR], dx ; save bus master base addr + + mov al, AC97_INT_LINE ; Interrupt line register (3Ch) + call pciRegRead8 ; 17/02/2017 + + mov [ac97_int_ln_reg], dl + + ;clc + + retn + +; ---------------------------------- + + ; 14/11/2024 + ; INPUT: ds:dx = file name address + ; OUTPUT: [filehandle] = ; -1 = not open +openFile: + mov ax, 3D00h ; open File for read + int 21h + jnc short _of1 + mov ax, -1 + ; cf = 1 -> not found or access error +_of1: + mov [filehandle], ax + retn + +; ---------------------------------- + +; close the currently open file + + ; 14/11/2024 + ; INPUT: [filehandle] ; -1 = not open + ; OUTPUT: none +closeFile: + cmp word [filehandle], -1 + jz short _cf1 + mov bx, [filehandle] + mov ax, 3E00h + int 21h ; close file +_cf1: + retn + +; ---------------------------------- + + ; 14/11/2024 - Erdogan Tan +getWAVParameters: +; reads WAV file header(s) (44 bytes) from the .wav file. +; entry: none - assumes file is already open +; exit: ax = sample rate (11025, 22050, 44100, 48000) +; cx = number of channels (mono=1, stereo=2) +; dx = bits per sample (8, 16) +; bx = number of bytes per sample (1 to 4) + + mov dx, WAVFILEHEADERbuff + mov bx, [filehandle] + mov cx, 44 ; 44 bytes + mov ah, 3Fh + int 21h + jc short gwavp_retn + + cmp ax, 44 + jb short gwavp_retn + + cmp dword [RIFF_Format], 'WAVE' + jne short gwavp_stc_retn + + cmp word [WAVE_AudioFormat], 1 ; Offset 20, must be 1 (= PCM) + ;jne short gwavp_stc_retn + je short gwavp_retn ; 15/11/2024 + + ; 15/11/2024 + ;mov cx, [WAVE_NumChannels] ; return num of channels in CX + ;mov ax, [WAVE_SampleRate] ; return sample rate in AX + ;mov dx, [WAVE_BitsPerSample] + ; return bits per sample value in DX + ;mov bx, [WAVE_BlockAlign] ; return bytes per sample in BX +;gwavp_retn: + ;retn + +gwavp_stc_retn: + stc +gwavp_retn: + retn + +; ---- 30/05/2024 (playwav4.asm, 19/05/2024) + +; MEMALLOC.ASM +;-- SETFREE: Release memory not used ---------------- +;-- Input : ES = address of PSP +;-- Output : none +;-- Register : AX, BX, CL and FLAGS are changed +;-- Info : Since the stack-segment is always the last segment in an +; EXE-file, ES:0000 points to the beginning and SS:SP +; to the end of the program in memory. Through this the +; length of the program can be calculated +; call this routine once at the beginning of the program to free up memory +; assigned to it by DOS. + +setFree: + mov bx, 65536/16 ; 4K paragraphs ; 17/02/2017 (Erdogan Tan) + + mov ah, 4Ah ; pass new length to DOS + int 21h + + retn ; back to caller + ; new size (allocated memory) = 64KB + +memAlloc: +; input: AX = # of paragraphs required +; output: AX = segment of block to use + + push bx + mov bx, ax + mov ah, 48h + int 21h + pop bx + retn + +; ---- + +; ///// + + ; 30/05/2024 (ich_wav4.asm, 19/05/2024) +loadFromFile: + ; 07/11/2023 + + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff_0 ; no + stc + retn + +lff_0: + ; 08/11/2023 + mov bp, ax ; save buffer segment + + ; 17/11/2024 + mov bx, [filehandle] + + ; 17/11/2024 + mov cx, [loadsize] + xor di, di ; 0 + + ;mov cl, [fbs_shift] + ;and cl, cl + ;jz short lff_1 ; stereo, 16 bit + ; 17/11/2024 + cmp byte [fbs_shift], 0 + jna short lff_1 ; stereo, 16 bit + + ;mov di, BUFFERSIZE - 1 ; 65535 + + ;; fbs_shift = + ;; 2 for mono and 8 bit sample (multiplier = 4) + ;; 1 for mono or 8 bit sample (multiplier = 2) + ;shr di, cl + ;inc di ; 16384 for 8 bit and mono + ; ; 32768 for 8 bit or mono + + ; 17/11/2024 + ;mov cx, [loadsize] ; 16380 or 32760 + + ;mov ax, cs + mov dx, temp_buffer ; temporary buffer for wav data + + ; 17/02/2017 (stereo/mono, 8bit/16bit corrections) + ; load file into memory + ;mov cx, di ; 17/11/2024 + ;mov bx, [filehandle] ; 17/11/2024 + ;mov ds, ax + mov ah, 3Fh + int 21h + + ;mov bx, cs + ;mov ds, bx + ; 17/11/2024 + ;push cs + ;pop ds + + jc lff_4 ; error ! + + ; 14/11/2024 + mov [count], ax + + ; 17/11/2024 + ; 08/11/2023 + ;xor dx, dx ; 0 + + and ax, ax + jz short lff_3 + + mov bl, [fbs_shift] + + push es + ;mov di, dx ; 0 ; [fbs_off] + ; 17/11/2024 + ; di = 0 + ;mov bp, [fbs_seg] ; buffer segment + mov es, bp + mov si, temp_buffer ; temporary buffer address + mov cx, ax ; byte count + cmp byte [WAVE_BitsPerSample], 8 ; bits per sample (8 or 16) + jne short lff_7 ; 16 bit samples + ; 8 bit samples + dec bl ; shift count, 1 = stereo, 2 = mono + jz short lff_6 ; 8 bit, stereo +lff_5: + ; mono & 8 bit + lodsb + sub al, 80h ; 08/11/2023 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; left channel + stosw ; right channel + loop lff_5 + jmp short lff_9 +lff_6: + ; stereo & 8 bit + lodsb + sub al, 80h ; 08/11/2023 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw + loop lff_6 + jmp short lff_9 +lff_7: + shr cx, 1 ; word count +lff_8: + lodsw + stosw ; left channel + stosw ; right channel + loop lff_8 +lff_9: + pop es + + ;or di, di + ;jz short endLFF ; 64KB ok + ;mov ax, di ; [fbs_off] + ;dec ax + ; 17/11/2024 + mov ax, di + ;cmp ax, BUFFERSIZE ; 65520 + ;jnb short endLFF + + ;mov cx, BUFFERSIZE - 1 ; 65535 + ; 17/11/2024 + mov cx, BUFFERSIZE + ; 17/11/2024 + ; ax = di + cmp ax, cx + ;jnb short endLFF + ;jmp short lff_3 + jb short lff_3 + retn + +lff_1: + ;mov bp, ax ; save buffer segment + xor dx, dx + ; load file into memory + ;mov cx, (BUFFERSIZE / 2) ; 32k chunk + + ; 17/11/2024 + ;mov cx, [buffersize] ; BUFFERSIZE / 2 + ; 17/11/2024 (*) + ; cx = [loadsize] = 2*[buffersize] + + ;mov bx, [filehandle] ; 17/11/2024 + mov ds, ax ; mov ds, bp + mov ah, 3Fh + int 21h + + ;mov di, cs + ;mov ds, di + ; 17/11/2024 + push cs + pop ds + + ; 07/11/2023 + jc short lff_4 ; error ! + + ; 14/11/2024 + mov [count], ax + ; 17/11/2024 + ; di = 0 + +; 17/11/2024 (*) +if 0 + cmp ax, cx + jne short lff_3 +lff_2: + ; 08/11/2023 + add dx, ax + ;;mov cx, (BUFFERSIZE / 2) ; 32k chunk + ;mov cx, [buffersize] ; BUFFERSIZE / 2 + ;mov bx, [filehandle] + mov ds, bp + mov ah, 3Fh + int 21h + + ;;mov di, cs + ;mov ds, di + ; 17/11/2024 + push cs + pop ds + + jc short lff_4 ; error ! + + ; 17/11/2024 + ; 14/11/2024 + add [count], ax +end if + + cmp ax, cx + je short endLFF + ; 17/11/2024 + ; di = 0 + mov di, ax +lff_3: + call padfill ; blank pad the remainder + ;clc ; don't exit with CY yet. + or byte [flags], ENDOFFILE ; end of file flag +endLFF: + retn +lff_4: + ; 08/11/2023 + mov al, '!' ; error + call tL0 + + xor ax, ax + jmp short lff_3 + +; entry ds:ax points to last byte in file +; cx = target size +; note: must do byte size fill +; destroys bx, cx +; +padfill: + ; 14/12/2024 + ; 17/11/2024 + ; di = offset (to be filled with ZEROs) + ; bp = buffer segment + ; ax = di = number of bytes loaded + ; cx = buffer size (> loaded bytes) + ; 07/11/2023 + ; 06/11/2023 + ; 17/02/2017 + push es + ;push di + ;mov di, [fbs_seg] + ;mov es, di + mov es, bp + sub cx, ax + ; 08/11/2023 + ;mov di, ax ; (wrong) + ; 17/11/2024 + ;mov di, dx ; buffer offset + ;add di, ax + ; 07/11/2023 + ;add di, [fbs_off] + ; 25/11/2024 + xor ax, ax + ; 14/12/2024 + rep stosb + ;mov [fbs_off], di + ;pop di + pop es + retn +; ///// + +write_audio_dev_info: + ; 30/05/2024 + sys_msg msgAudioCardInfo, 0Fh + retn + +write_ac97_pci_dev_info: + ; 19/11/2024 + ; 30/05/2024 + ; 06/06/2017 + ; 03/06/2017 + ; BUS/DEV/FN + ; 00000000BBBBBBBBDDDDDFFF00000000 + ; DEV/VENDOR + ; DDDDDDDDDDDDDDDDVVVVVVVVVVVVVVVV + + mov eax, [dev_vendor] + xor bh, bh + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgVendorId+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgVendorId+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgVendorId+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgVendorId], al + shr eax, 16 + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgDevId+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgDevId+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgDevId+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgDevId], al + + mov eax, [bus_dev_fn] + shr eax, 8 + mov bl, al + mov dl, bl + and bl, 7 ; bit 0,1,2 + mov al, [bx+hex_chars] + mov [msgFncNo+1], al + mov bl, dl + shr bl, 3 + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgDevNo+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgDevNo], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgBusNo+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgBusNo], al + + ;mov ax, [ac97_NamBar] + mov ax, [NAMBAR] + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgNamBar+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgNamBar+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgNamBar+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgNamBar], al + + ;mov ax, [ac97_NabmBar] + mov ax, [NABMBAR] + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgNabmBar+3], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgNabmBar+2], al + mov bl, ah + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgNabmBar+1], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgNabmBar], al + + xor eax, eax + mov al, [ac97_int_ln_reg] + mov cl, 10 + div cl + ; 23/11/2024 + ;add [msgIRQ], ax + add ax, 3030h + mov [msgIRQ], ax + ;and al, al + cmp al, 30h + jnz short _w_ac97imsg_ + mov al, byte [msgIRQ+1] + mov ah, ' ' + mov [msgIRQ], ax +_w_ac97imsg_: + ; 19/11/2024 + call clear_window + mov dh, 13 + mov dl, 0 + call setCursorPosition + ;;; + ; 30/05/2024 + sys_msg msgAC97Info, 07h + + ; 19/11/2024 + ;retn + + ; 30/05/2024 +write_VRA_info: + sys_msg msgVRAheader, 07h + cmp byte [VRA], 0 + jna short _w_VRAi_no +_w_VRAi_yes: + sys_msg msgVRAyes, 07h + retn +_w_VRAi_no: + sys_msg msgVRAno, 07h + retn + +; 30/05/2024 (playwav6.asm) +; 18/11/2023 (ich_wav3.asm & ich_wav4.asm) +; 15/11/2023 (ich_wav3.asm) +; 14/11/2023 +; 13/11/2023 - Erdogan Tan - (VRA, sample rate conversion) +; -------------------------------------------------------- + +;;Note: At the end of every buffer load, +;; during buffer switch/swap, there will be discontinuity +;; between the last converted sample and the 1st sample +;; of the next buffer. +;; (like as a dot noises vaguely between normal sound samples) +;; -To avoid this defect, the 1st sample of +;; the next buffer may be read from the wav file but +;; the file pointer would need to be set to 1 sample back +;; again via seek system call. Time comsumption problem! - +;; +;; Erdogan Tan - 15/11/2023 +;; +;; ((If entire wav data would be loaded at once.. conversion +;; defect/noise would disappear.. but for DOS, to keep +;; 64KB buffer limit is important also it is important +;; for running under 1MB barrier without HIMEM.SYS or DPMI. +;; I have tested this program by using 2-30MB wav files.)) +;; +;; Test Computer: ASUS desktop/mainboard, M2N4-SLI, 2010. +;; AMD Athlon 64 X2 2200 MHZ CPU. +;; NFORCE4 (CK804) AC97 audio hardware. +;; Realtek ALC850 codec. +;; Retro DOS v4.2 (MSDOS 6.22) operating system. + +load_8khz_mono_8_bit: + ; 15/11/2023 + ; 14/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff8m_0 ; no + stc + retn + +lff8m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + ;jc short lff8m_5 ; error ! + ; 14/11/2023 + jnc short lff8m_6 + jmp lff8m_5 + +lff8m_6: + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + and ax, ax + ;jz short lff8m_3 + ; 15/11/2023 + jz short lff8_eof + + mov cx, ax ; byte count +lff8m_1: + lodsb + mov [previous_val], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (left channel) + stosw ; original sample (right channel) + ;xor ax, ax + ; 14/11/2023 + mov al, 80h + dec cx + jz short lff8m_2 + mov al, [si] +lff8m_2: + ;mov [next_val], ax + mov bh, al ; [next_val] + mov ah, [previous_val] + add al, ah ; [previous_val] + rcr al, 1 + mov dl, al ; this is interpolated middle (3th) sample + add al, ah ; [previous_val] + rcr al, 1 + mov bl, al ; this is temporary interpolation value + add al, ah ; [previous_val] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (L) + stosw ; this is 1st interpolated sample (R) + mov al, bl + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (L) + stosw ; this is 2nd interpolated sample (R) + mov al, dl + sub al, 80h + shl ax, 8 + stosw ; this is middle (3th) interpolated sample (L) + stosw ; this is middle (3th) interpolated sample (R) + ;mov al, [next_val] + mov al, bh + add al, dl + rcr al, 1 + mov bl, al ; this is temporary interpolation value + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 4th interpolated sample (L) + stosw ; this is 4th interpolated sample (R) + ;mov al, [next_val] + mov al, bh + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 5th interpolated sample (L) + stosw ; this is 5th interpolated sample (R) + ; 8 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff8m_1 + + ; -------------- + +lff8s_3: +lff8m_3: +lff8s2_3: +lff8m2_3: +lff16s_3: +lff16m_3: +lff16s2_3: +lff16m2_3: +lff24_3: +lff32_3: +lff44_3: +lff22_3: +lff11_3: + mov cx, [buffersize] ; 16 bit (48 kHZ, stereo) sample size + shl cx, 1 ; byte count + sub cx, di + jna short lff8m_4 + ;inc cx + shr cx, 1 + xor ax, ax ; fill (remain part of) buffer with zeros + rep stosw +lff8m_4: + push cs + pop es + retn + +lff8_eof: +lff16_eof: +lff24_eof: +lff32_eof: +lff44_eof: +lff22_eof: +lff11_eof: + ; 15/11/2023 + mov byte [flags], ENDOFFILE + jmp short lff8m_3 + +lff8s_5: +lff8m_5: +lff8s2_5: +lff8m2_5: +lff16s_5: +lff16m_5: +lff16s2_5: +lff16m2_5: +lff24_5: +lff32_5: +lff44_5: +lff22_5: +lff11_5: + mov al, '!' ; error + call tL0 + + ;jmp short lff8m_3 + ; 15/11/2023 + jmp lff8_eof + + ; -------------- + +load_8khz_stereo_8_bit: + ; 15/11/2023 + ; 14/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff8s_0 ; no + stc + retn + +lff8s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff8s_5 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;;and ax, ax + ;jz short lff8s_3 + ; 15/11/2023 + jz short lff8_eof + + mov cx, ax ; word count +lff8s_1: + lodsb + mov [previous_val_l], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + lodsb + mov [previous_val_r], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + + ;xor ax, ax + ; 14/11/2023 + mov ax, 8080h + dec cx + jz short lff8s_2 + ; convert 8 bit sample to 16 bit sample + mov ax, [si] +lff8s_2: + mov [next_val_l], al + mov [next_val_r], ah + mov ah, [previous_val_l] + add al, ah + rcr al, 1 + mov dl, al ; this is interpolated middle (3th) sample (L) + add al, ah + rcr al, 1 + mov bl, al ; this is temporary interpolation value (L) + add al, ah + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (L) + mov al, [next_val_r] + mov ah, [previous_val_r] + add al, ah + rcr al, 1 + mov dh, al ; this is interpolated middle (3th) sample (R) + add al, ah + rcr al, 1 + mov bh, al ; this is temporary interpolation value (R) + add al, ah + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (R) + mov al, bl + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (L) + mov al, bh + add al, dh + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (R) + mov al, dl + sub al, 80h + shl ax, 8 + stosw ; this is middle (3th) interpolated sample (L) + mov al, dh + sub al, 80h + shl ax, 8 + stosw ; this is middle (3th) interpolated sample (R) + mov al, [next_val_l] + add al, dl + rcr al, 1 + mov bl, al ; this is temporary interpolation value (L) + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 4th interpolated sample (L) + mov al, [next_val_r] + add al, dh + rcr al, 1 + mov bh, al ; this is temporary interpolation value (R) + add al, dh + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 4th interpolated sample (R) + mov al, [next_val_l] + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 5th interpolated sample (L) + mov al, [next_val_r] + add al, bh + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 5th interpolated sample (R) + ; 8 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + jcxz lff8s_6 + jmp lff8s_1 +lff8s_6: + jmp lff8s_3 + +load_8khz_mono_16_bit: + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff8m2_0 ; no + stc + retn + +lff8m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff8m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff8m2_8 + ;jmp lff8m2_3 + ; 15/11/2023 + jmp lff8_eof + +lff8m2_8: + mov cx, ax ; word count +lff8m2_1: + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + add ah, 80h ; convert sound level to 0-65535 format + mov [previous_val], ax + xor ax, ax + dec cx + jz short lff8m2_2 + mov ax, [si] +lff8m2_2: + add ah, 80h ; convert sound level to 0-65535 format + mov bp, ax ; [next_val] + add ax, [previous_val] + rcr ax, 1 + mov dx, ax ; this is interpolated middle (3th) sample + add ax, [previous_val] + rcr ax, 1 ; this is temporary interpolation value + mov bx, ax + add ax, [previous_val] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (L) + stosw ; this is 1st interpolated sample (R) + mov ax, bx + add ax, dx + rcr ax, 1 + sub ah, 80h + stosw ; this is 2nd interpolated sample (L) + stosw ; this is 2nd interpolated sample (R) + mov ax, dx + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is middle (3th) interpolated sample (L) + stosw ; this is middle (3th) interpolated sample (R) + mov ax, bp + add ax, dx + rcr ax, 1 + mov bx, ax ; this is temporary interpolation value + add ax, dx + rcr ax, 1 + sub ah, 80h + stosw ; this is 4th interpolated sample (L) + stosw ; this is 4th interpolated sample (R) + mov ax, bp + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 5th interpolated sample (L) + stosw ; this is 5th interpolated sample (R) + ; 8 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff8m2_1 + jmp lff8m2_3 + +lff8m2_7: +lff8s2_7: + jmp lff8m2_5 ; error + +load_8khz_stereo_16_bit: + ; 16/11/2023 + ; 15/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff8s2_0 ; no + stc + retn + +lff8s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff8s2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; 16/11/2023 + ;and ax, ax + jnz short lff8s2_8 + ;jmp lff8s2_3 + ; 15/11/2023 + jmp lff8_eof + +lff8s2_8: + mov cx, ax ; dword count +lff8s2_1: + lodsw + stosw ; original sample (L) + ; 15/11/2023 + add ah, 80h ; convert sound level to 0-65535 format + mov [previous_val_l], ax + lodsw + stosw ; original sample (R) + add ah, 80h ; convert sound level to 0-65535 format + mov [previous_val_r], ax + xor dx, dx + xor ax, ax + ; 16/11/2023 + dec cx + jz short lff8s2_2 + mov ax, [si] + mov dx, [si+2] +lff8s2_2: + add ah, 80h ; convert sound level to 0-65535 format + mov [next_val_l], ax + add dh, 80h ; convert sound level to 0-65535 format + mov [next_val_r], dx + add ax, [previous_val_l] + rcr ax, 1 + mov dx, ax ; this is interpolated middle (3th) sample (L) + add ax, [previous_val_l] + rcr ax, 1 + mov bx, ax ; this is temporary interpolation value (L) + add ax, [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (L) + mov ax, [next_val_r] + add ax, [previous_val_r] + rcr ax, 1 + mov bp, ax ; this is interpolated middle (3th) sample (R) + add ax, [previous_val_r] + rcr ax, 1 + push ax ; * ; this is temporary interpolation value (R) + add ax, [previous_val_r] + rcr ax, 1 + sub ah, 80h + stosw ; this is 1st interpolated sample (R) + mov ax, bx + add ax, dx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 2nd interpolated sample (L) + pop ax ; * + add ax, bp + rcr ax, 1 + sub ah, 80h + stosw ; this is 2nd interpolated sample (R) + mov ax, dx + sub ah, 80h + stosw ; this is middle (3th) interpolated sample (L) + mov ax, bp + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is middle (3th) interpolated sample (R) + mov ax, [next_val_l] + add ax, dx + rcr ax, 1 + mov bx, ax ; this is temporary interpolation value (L) + add ax, dx + rcr ax, 1 + sub ah, 80h + stosw ; this is 4th interpolated sample (L) + mov ax, [next_val_r] + add ax, bp + rcr ax, 1 + push ax ; ** ; this is temporary interpolation value (R) + add ax, bp + rcr ax, 1 + sub ah, 80h + stosw ; this is 4th interpolated sample (R) + mov ax, [next_val_l] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 5th interpolated sample (L) + pop ax ; ** + add ax, [next_val_r] + rcr ax, 1 + sub ah, 80h + stosw ; this is 5th interpolated sample (R) + ; 8 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + jcxz lff8_s2_9 + jmp lff8s2_1 +lff8_s2_9: + jmp lff8s2_3 + +; ..................... + +load_16khz_mono_8_bit: + ; 14/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff16m_0 ; no + stc + retn + +lff16m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff16m_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff16m_8 + ;jmp lff16m_3 + ; 15/11/2023 + jmp lff16_eof + +lff16m_8: + mov cx, ax ; byte count +lff16m_1: + lodsb + ;mov [previous_val], al + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (left channel) + stosw ; original sample (right channel) + ;xor ax, ax + ; 14/11/22023 + mov al, 80h + dec cx + jz short lff16m_2 + mov al, [si] +lff16m_2: + ;mov [next_val], al + mov bh, al + ;add al, [previous_val] + add al, bl + rcr al, 1 + mov dl, al ; this is interpolated middle (temp) sample + ;add al, [previous_val] + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (L) + stosw ; this is 1st interpolated sample (R) + ;mov al, [next_val] + mov al, bh + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (L) + stosw ; this is 2nd interpolated sample (R) + + ; 16 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff16m_1 + jmp lff16m_3 + +lff16m_7: +lff16s_7: + jmp lff16m_5 ; error + +load_16khz_stereo_8_bit: + ; 14/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff16s_0 ; no + stc + retn + +lff16s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff16s_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff16s_8 + ;jmp lff16s_3 + ; 15/11/2023 + jmp lff16_eof + +lff16s_8: + mov cx, ax ; word count +lff16s_1: + lodsb + mov [previous_val_l], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + lodsb + mov [previous_val_r], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + + ;xor ax, ax + ; 14/11/2023 + mov ax, 8080h + dec cx + jz short lff16s_2 + ; convert 8 bit sample to 16 bit sample + mov ax, [si] +lff16s_2: + ;mov [next_val_l], al + ;mov [next_val_r], ah + mov bx, ax + add al, [previous_val_l] + rcr al, 1 + mov dl, al ; this is temporary interpolation value (L) + add al, [previous_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (L) + mov al, bh ; [next_val_r] + add al, [previous_val_r] + rcr al, 1 + mov dh, al ; this is temporary interpolation value (R) + add al, [previous_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 1st interpolated sample (R) + mov al, dl + add al, bl ; [next_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (L) + mov al, dh + add al, bh ; [next_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is 2nd interpolated sample (R) + + ; 16 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff16s_1 + jmp lff16s_3 + +load_16khz_mono_16_bit: + ; 15/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff16m2_0 ; no + stc + retn + +lff16m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff16m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff16m2_8 + ;jmp lff16m2_3 + ; 15/11/2023 + jmp lff16_eof + +lff16m2_8: + mov cx, ax ; word count +lff16m2_1: + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val], ax + mov bx, ax + xor ax, ax + dec cx + jz short lff16m2_2 + mov ax, [si] +lff16m2_2: + add ah, 80h ; convert sound level 0 to 65535 format + mov bp, ax ; [next_val] + ;add ax, [previous_val] + add ax, bx + rcr ax, 1 + mov dx, ax ; this is temporary interpolation value + ;add ax, [previous_val] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (L) + stosw ; this is 1st interpolated sample (R) + mov ax, bp + add ax, dx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 2nd interpolated sample (L) + stosw ; this is 2nd interpolated sample (R) + ; 16 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff16m2_1 + jmp lff16m2_3 + +lff16m2_7: +lff16s2_7: + jmp lff16m2_5 ; error + +load_16khz_stereo_16_bit: + ; 16/11/2023 + ; 15/11/2023 + ; 13/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff16s2_0 ; no + stc + retn + +lff16s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff16s2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + ;shr ax, 1 + shr ax, 2 ; 16/11/2023 + ;and ax, ax + jnz short lff16s2_8 + ;jmp lff16s2_3 + ; 15/11/2023 + jmp lff16_eof + +lff16s2_8: + mov cx, ax ; dword count +lff16s2_1: + lodsw + stosw ; original sample (L) + add ah, 80h ; convert sound level 0 to 65535 format + mov [previous_val_l], ax + lodsw + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + mov [previous_val_r], ax + xor dx, dx + xor ax, ax + ; 16/11/2023 + dec cx + jz short lff16s2_2 + mov ax, [si] + mov dx, [si+2] +lff16s2_2: + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [next_val_l], ax + mov bp, ax + add dh, 80h ; convert sound level 0 to 65535 format + mov [next_val_r], dx + add ax, [previous_val_l] + rcr ax, 1 + mov dx, ax ; this is temporary interpolation value (L) + add ax, [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (L) + mov ax, [next_val_r] + add ax, [previous_val_r] + rcr ax, 1 + mov bx, ax ; this is temporary interpolation value (R) + add ax, [previous_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 1st interpolated sample (R) + ;mov ax, [next_val_l] + mov ax, bp + add ax, dx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 2nd interpolated sample (L) + mov ax, [next_val_r] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is 2nd interpolated sample (R) + + ; 16 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff16s2_1 + jmp lff16s2_3 + +; ..................... + +load_24khz_mono_8_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff24m_0 ; no + stc + retn + +lff24m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff24m_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff24m_8 + jmp lff24_eof + +lff24m_8: + mov cx, ax ; byte count +lff24m_1: + lodsb + ;mov [previous_val], al + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (left channel) + stosw ; original sample (right channel) + ;xor ax, ax + mov al, 80h + dec cx + jz short lff24m_2 + mov al, [si] +lff24m_2: + ;;mov [next_val], al + ;mov bh, al + ;add al, [previous_val] + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (L) + stosw ; this is interpolated sample (R) + + ; 24 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff24m_1 + jmp lff24_3 + +lff24m_7: +lff24s_7: + jmp lff24_5 ; error + +load_24khz_stereo_8_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff24s_0 ; no + stc + retn + +lff24s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff24s_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff24s_8 + jmp lff24_eof + +lff24s_8: + mov cx, ax ; word count +lff24s_1: + lodsb + mov [previous_val_l], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + lodsb + mov [previous_val_r], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + + ;xor ax, ax + mov ax, 8080h + dec cx + jz short lff24s_2 + ; convert 8 bit sample to 16 bit sample + mov ax, [si] +lff24s_2: + ;;mov [next_val_l], al + ;;mov [next_val_r], ah + ;mov bx, ax + mov bh, ah + add al, [previous_val_l] + rcr al, 1 + ;mov dl, al + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (L) + mov al, bh ; [next_val_r] + add al, [previous_val_r] + rcr al, 1 + ;mov dh, al + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (R) + + ; 24 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff24s_1 + jmp lff24_3 + +load_24khz_mono_16_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff24m2_0 ; no + stc + retn + +lff24m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff24m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff24m2_8 + jmp lff24_eof + +lff24m2_8: + mov cx, ax ; word count +lff24m2_1: + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val], ax + ;mov bx, ax + ;xor ax, ax + xor bx, bx + dec cx + jz short lff24m2_2 + ;mov ax, [si + mov bx, [si] +lff24m2_2: + ;add ah, 80h ; convert sound level 0 to 65535 format + ;mov bp, ax ; [next_val] + ;add ax, [previous_val] + ; ax = [previous_val] + ; bx = [next_val] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (L) + stosw ; this is interpolated sample (R) + ; 24 kHZ mono to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff24m2_1 + jmp lff24_3 + +lff24m2_7: +lff24s2_7: + jmp lff24_5 ; error + +load_24khz_stereo_16_bit: + ; 16/11/2023 + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff24s2_0 ; no + stc + retn + +lff24s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff24s2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + ;shr ax, 1 + shr ax, 2 ; 16/11/2023 + ;and ax, ax + jnz short lff24s2_8 + jmp lff24_eof + +lff24s2_8: + mov cx, ax ; dword count +lff24s2_1: + lodsw + stosw ; original sample (L) + add ah, 80h ; convert sound level 0 to 65535 format + mov [previous_val_l], ax + lodsw + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val_r], ax + mov bx, ax + xor dx, dx + xor ax, ax + ; 16/11/2023 + dec cx + jz short lff24s2_2 + mov ax, [si] + mov dx, [si+2] +lff24s2_2: + add ah, 80h ; convert sound level 0 to 65535 format + ;;mov [next_val_l], ax + ;mov bp, ax + add dh, 80h ; convert sound level 0 to 65535 format + ;mov [next_val_r], dx + add ax, [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (L) + ;mov ax, [next_val_r] + mov ax, dx + ;add ax, [previous_val_r] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (R) + + ; 24 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + or cx, cx + jnz short lff24s2_1 + jmp lff24_3 + +; ..................... + +load_32khz_mono_8_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff32m_0 ; no + stc + retn + +lff32m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff32m_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff32m_8 + jmp lff32_eof + +lff32m_8: + mov cx, ax ; byte count +lff32m_1: + lodsb + ;mov [previous_val], al + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (left channel) + stosw ; original sample (right channel) + ;xor ax, ax + mov al, 80h + dec cx + jz short lff32m_2 + mov al, [si] +lff32m_2: + ;;mov [next_val], al + ;mov bh, al + ;add al, [previous_val] + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (L) + stosw ; this is interpolated sample (R) + + ; different than 8-16-24 kHZ ! + ; 'original-interpolated-original' trio samples + jcxz lff32m_3 + + lodsb + sub al, 80h + shl ax, 8 + stosw ; original sample (left channel) + stosw ; original sample (right channel) + + ; 32 kHZ mono to 48 kHZ stereo conversion of the sample is OK + dec cx + jnz short lff32m_1 +lff32m_3: + jmp lff32_3 + +lff32m_7: +lff32s_7: + jmp lff32_5 ; error + +load_32khz_stereo_8_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff32s_0 ; no + stc + retn + +lff32s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff32s_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff32s_8 + jmp lff32_eof + +lff32s_8: + mov cx, ax ; word count +lff32s_1: + lodsb + mov [previous_val_l], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + lodsb + mov [previous_val_r], al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + + ;xor ax, ax + mov ax, 8080h + dec cx + jz short lff32s_2 + ; convert 8 bit sample to 16 bit sample + mov ax, [si] +lff32s_2: + ;;mov [next_val_l], al + ;;mov [next_val_r], ah + ;mov bx, ax + mov bh, ah + add al, [previous_val_l] + rcr al, 1 + ;mov dl, al + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (L) + mov al, bh ; [next_val_r] + add al, [previous_val_r] + rcr al, 1 + ;mov dh, al + sub al, 80h + shl ax, 8 + stosw ; this is interpolated sample (R) + + ; different than 8-16-24 kHZ ! + ; 'original-interpolated-original' trio samples + jcxz lff32s_3 + + lodsb + sub al, 80h + shl ax, 8 + stosw ; original sample (left channel) + + lodsb + sub al, 80h + shl ax, 8 + stosw ; original sample (right channel) + + ; 32 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + dec cx + jnz short lff32s_1 +lff32s_3: + jmp lff32_3 + +load_32khz_mono_16_bit: + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff32m2_0 ; no + stc + retn + +lff32m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff32m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff32m2_8 + jmp lff32_eof + +lff32m2_8: + mov cx, ax ; word count +lff32m2_1: + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val], ax + ;mov bx, ax + ;xor ax, ax + xor bx, bx + dec cx + jz short lff32m2_2 + ;mov ax, [si + mov bx, [si] +lff32m2_2: + ;add ah, 80h ; convert sound level 0 to 65535 format + ;mov bp, ax ; [next_val] + ;add ax, [previous_val] + ; ax = [previous_val] + ; bx = [next_val] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (L) + stosw ; this is interpolated sample (R) + + ; different than 8-16-24 kHZ ! + ; 'original-interpolated-original' trio samples + jcxz lff32m2_3 + + lodsw + stosw ; original sample (left channel) + stosw ; original sample (right channel) + + ; 32 kHZ mono to 48 kHZ stereo conversion of the sample is OK + dec cx + jnz short lff32m2_1 +lff32m2_3: + jmp lff32_3 + +lff32m2_7: +lff32s2_7: + jmp lff32_5 ; error + +load_32khz_stereo_16_bit: + ;16/11/2023 + ; 15/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff32s2_0 ; no + stc + retn + +lff32s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff32s2_7 ; error ! + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; 16/11/2023 (word left ch + word right ch) + ;and ax, ax + jnz short lff32s2_8 + jmp lff32_eof + +lff32s2_8: + mov cx, ax ; dword count +lff32s2_1: + lodsw + stosw ; original sample (L) + add ah, 80h ; convert sound level 0 to 65535 format + mov [previous_val_l], ax + lodsw + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + ;mov [previous_val_r], ax + mov bx, ax + xor dx, dx + xor ax, ax + ; 16/11/2023 + dec cx + jz short lff32s2_2 + mov ax, [si] + mov dx, [si+2] +lff32s2_2: + add ah, 80h ; convert sound level 0 to 65535 format + ;;mov [next_val_l], ax + ;mov bp, ax + add dh, 80h ; convert sound level 0 to 65535 format + ;mov [next_val_r], dx + add ax, [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (L) + ;mov ax, [next_val_r] + mov ax, dx + ;add ax, [previous_val_r] + add ax, bx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; this is interpolated sample (R) + + ; different than 8-16-24 kHZ ! + ; 'original-interpolated-original' trio samples + jcxz lff32s2_3 + + lodsw + stosw ; original sample (L) + lodsw + stosw ; original sample (R) + + ; 32 kHZ stereo to 48 kHZ stereo conversion of the sample is OK + dec cx + jnz short lff32s2_1 +lff32s2_3: + jmp lff32_3 + +; ..................... + +load_22khz_mono_8_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff22m_0 ; no + stc + retn + +lff22m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff22m_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff22m_8 + jmp lff22_eof + +lff22m_8: + mov cx, ax ; byte count +lff22m_9: + mov bp, 5 ; interpolation (one step) loop count + mov byte [faz], 3 ; 3 steps/phases +lff22m_1: + ; 3:2:2:2:2:2::3:2:2:2:2::3:2:2:2:2:2 ; 37/17 + lodsb + mov dl, 80h + dec cx + jz short lff22m_2_1 + mov dl, [si] +lff22m_2_1: + ; al = [previous_val] + ; dl = [next_val] + call interpolating_3_8bit_mono ; 1 of 17 + jcxz lff22m_3 +lff22m_2_2: + lodsb + mov dl, 80h + dec cx + jz short lff22m_2_3 + mov dl, [si] +lff22m_2_3: + call interpolating_2_8bit_mono ; 2 of 17 .. 6 of 17 + jcxz lff22m_3 + dec bp + jnz short lff22m_2_2 + + mov al, [faz] + dec al + jz short lff22m_9 + dec byte [faz] + mov bp, 4 + dec al + jnz short lff22m_1 ; 3:2:2:2:2 ; 7-11 of 17 + inc bp ; 5 + jmp short lff22m_1 ; 3:2:2:2:2:2 ; 12-17 of 17 + +lff22m_3: +lff22s_3: + jmp lff22_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff22m_7: +lff22s_7: + jmp lff22_5 ; error + +load_22khz_stereo_8_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff22s_0 ; no + stc + retn + +lff22s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff22s_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff22s_8 + jmp lff22_eof + +lff22s_8: + mov cx, ax ; word count +lff22s_9: + mov bp, 5 ; interpolation (one step) loop count + mov byte [faz], 3 ; 3 steps/phase +lff22s_1: + ; 3:2:2:2:2:2::3:2:2:2:2::3:2:2:2:2:2 ; 37/17 + lodsw + mov dx, 8080h + dec cx + jz short lff22s_2_1 + mov dx, [si] +lff22s_2_1: + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dl = [next_val_r] + call interpolating_3_8bit_stereo ; 1 of 17 + jcxz lff22s_3 +lff22s_2_2: + lodsw + mov dx, 8080h + dec cx + jz short lff22s_2_3 + mov dx, [si] +lff22s_2_3: + call interpolating_2_8bit_stereo ; 2 of 17 .. 6 of 17 + jcxz lff22s_3 + dec bp + jnz short lff22s_2_2 + + mov al, [faz] + dec al + jz short lff22s_9 + dec byte [faz] + mov bp, 4 + dec al + jnz short lff22s_1 ; 3:2:2:2:2 ; 7-11 of 17 + inc bp ; 5 + jmp short lff22s_1 ; 3:2:2:2:2:2 ; 12-17 of 17 + +load_22khz_mono_16_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff22m2_0 ; no + stc + retn + +lff22m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff22m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff22m2_8 + jmp lff22_eof + +lff22m2_8: + mov cx, ax ; word count +lff22m2_9: + mov bp, 5 ; interpolation (one step) loop count + mov byte [faz], 3 ; 3 steps/phases +lff22m2_1: + ; 3:2:2:2:2:2::3:2:2:2:2::3:2:2:2:2:2 ; 37/17 + lodsw + xor dx, dx + dec cx + jz short lff22m2_2_1 + mov dx, [si] +lff22m2_2_1: + ; ax = [previous_val] + ; dx = [next_val] + call interpolating_3_16bit_mono ; 1 of 17 + jcxz lff22m2_3 +lff22m2_2_2: + lodsw + xor dx, dx + dec cx + jz short lff22m2_2_3 + mov dx, [si] +lff22m2_2_3: + call interpolating_2_16bit_mono ; 2 of 17 .. 6 of 17 + jcxz lff22m2_3 + dec bp + jnz short lff22m2_2_2 + + mov al, [faz] + dec al + jz short lff22m2_9 + dec byte [faz] + mov bp, 4 + dec al + jnz short lff22m2_1 ; 3:2:2:2:2 ; 7-11 of 17 + inc bp ; 5 + jmp short lff22m2_1 ; 3:2:2:2:2:2 ; 12-17 of 17 + +lff22m2_3: +lff22s2_3: + jmp lff22_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff22m2_7: +lff22s2_7: + jmp lff22_5 ; error + +load_22khz_stereo_16_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff22s2_0 ; no + stc + retn + +lff22s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff22s2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; dword (left chan word + right chan word) + ;and ax, ax + jnz short lff22s2_8 + jmp lff22_eof + +lff22s2_8: + mov cx, ax ; dword count +lff22s2_9: + mov bp, 5 ; interpolation (one step) loop count + mov byte [faz], 3 ; 3 steps/phase +lff22s2_1: + ; 3:2:2:2:2:2::3:2:2:2:2::3:2:2:2:2:2 ; 37/17 + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + dec cx + jnz short lff22s2_2_1 + xor dx, dx ; 0 + mov [next_val_l], dx +lff22s2_2_1: + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + call interpolating_3_16bit_stereo ; 1 of 17 + jcxz lff22s2_3 +lff22s2_2_2: + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + dec cx + jnz short lff22s2_2_3 + xor dx, dx ; 0 + mov [next_val_l], dx +lff22s2_2_3: + call interpolating_2_16bit_stereo ; 2 of 17 .. 6 of 17 + jcxz lff22s2_3 + dec bp + jnz short lff22s2_2_2 + + mov al, [faz] + dec al + jz short lff22s2_9 + dec byte [faz] + mov bp, 4 + dec al + jnz short lff22s2_1 ; 3:2:2:2:2 ; 7-11 of 17 + inc bp ; 5 + jmp short lff22s2_1 ; 3:2:2:2:2:2 ; 12-17 of 17 + +; ..................... + +load_11khz_mono_8_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff11m_0 ; no + stc + retn + +lff11m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff11m_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff11m_8 + jmp lff11_eof + +lff11m_8: + mov cx, ax ; byte count +lff11m_9: + mov bp, 6 ; interpolation (one step) loop count +lff11m_1: + ; 5:4:4::5:4:4::5:4:4::5:4:4::5:4:4::5:4 ; 74/17 + lodsb + mov dl, 80h + dec cx + jz short lff11m_2_1 + mov dl, [si] +lff11m_2_1: + ; al = [previous_val] + ; dl = [next_val] + call interpolating_5_8bit_mono + jcxz lff11m_3 +lff11m_2_2: + lodsb + mov dl, 80h + dec cx + jz short lff11m_2_3 + mov dl, [si] +lff11m_2_3: + call interpolating_4_8bit_mono + jcxz lff11m_3 + + dec bp + jz short lff11m_9 + + lodsb + mov dl, 80h + dec cx + jz short lff11m_2_4 + mov dl, [si] +lff11m_2_4: + call interpolating_4_8bit_mono + jcxz lff11m_3 + jmp short lff11m_1 + +lff11m_3: +lff11s_3: + jmp lff11_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff11m_7: +lff11s_7: + jmp lff11_5 ; error + +load_11khz_stereo_8_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff11s_0 ; no + stc + retn + +lff11s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff11s_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff11s_8 + jmp lff11_eof + +lff11s_8: + mov cx, ax ; word count +lff11s_9: + mov bp, 6 ; interpolation (one step) loop count +lff11s_1: + ; 5:4:4::5:4:4::5:4:4::5:4:4::5:4:4::5:4 ; 74/17 + lodsw + mov dx, 8080h + dec cx + jz short lff11s_2_1 + mov dx, [si] +lff11s_2_1: + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dl = [next_val_r] + call interpolating_5_8bit_stereo + jcxz lff11s_3 +lff11s_2_2: + lodsw + mov dx, 8080h + dec cx + jz short lff11s_2_3 + mov dx, [si] +lff11s_2_3: + call interpolating_4_8bit_stereo + jcxz lff11s_3 + + dec bp + jz short lff11s_9 + + lodsw + mov dx, 8080h + dec cx + jz short lff11s_2_4 + mov dx, [si] +lff11s_2_4: + call interpolating_4_8bit_stereo + jcxz lff11s_3 + jmp short lff11s_1 + +load_11khz_mono_16_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff11m2_0 ; no + stc + retn + +lff11m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff11m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff11m2_8 + jmp lff11_eof + +lff11m2_8: + mov cx, ax ; word count +lff11m2_9: + mov bp, 6 ; interpolation (one step) loop count +lff11m2_1: + ; 5:4:4::5:4:4::5:4:4::5:4:4::5:4:4::5:4 ; 74/17 + lodsw + xor dx, dx + dec cx + jz short lff11m2_2_1 + mov dx, [si] +lff11m2_2_1: + ; ax = [previous_val] + ; dx = [next_val] + call interpolating_5_16bit_mono + jcxz lff11m2_3 +lff11m2_2_2: + lodsw + xor dx, dx + dec cx + jz short lff11m2_2_3 + mov dx, [si] +lff11m2_2_3: + call interpolating_4_16bit_mono + jcxz lff11m2_3 + + dec bp + jz short lff11m2_9 + + lodsw + xor dx, dx + dec cx + jz short lff11m2_2_4 + mov dx, [si] +lff11m2_2_4: + call interpolating_4_16bit_mono + jcxz lff11m2_3 + jmp short lff11m2_1 + +lff11m2_7: +lff11s2_7: + jmp lff11_5 ; error + +load_11khz_stereo_16_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff11s2_0 ; no + stc + retn + +lff11s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff11s2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; dword (left chan word + right chan word) + ;and ax, ax + jnz short lff11s2_8 + jmp lff11_eof + +lff11m2_3: +lff11s2_3: + jmp lff11_3 ; padfill + ; (put zeros in the remain words of the buffer) + +lff11s2_8: + mov cx, ax ; dword count +lff11s2_9: + mov bp, 6 ; interpolation (one step) loop count +lff11s2_1: + ; 5:4:4::5:4:4::5:4:4::5:4:4::5:4:4::5:4 ; 74/17 + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + mov [next_val_r], dx + dec cx + jnz short lff11s2_2_1 + xor dx, dx ; 0 + mov [next_val_l], dx + mov [next_val_r], dx +lff11s2_2_1: + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + call interpolating_5_16bit_stereo + jcxz lff11s2_3 +lff11s2_2_2: + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + mov [next_val_r], dx + dec cx + jnz short lff11s2_2_3 + xor dx, dx ; 0 + mov [next_val_l], dx + mov [next_val_r], dx +lff11s2_2_3: + call interpolating_4_16bit_stereo + jcxz lff11s2_3 + + dec bp + jz short lff11s2_9 + + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + mov [next_val_r], dx + dec cx + jnz short lff11s2_2_4 + xor dx, dx ; 0 + mov [next_val_l], dx + mov [next_val_r], dx +lff11s2_2_4: + call interpolating_4_16bit_stereo + jcxz lff11s2_3 + jmp short lff11s2_1 + +; ..................... + +load_44khz_mono_8_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff44m_0 ; no + stc + retn + +lff44m_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff44m_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + and ax, ax + jnz short lff44m_8 + jmp lff44_eof + +lff44m_8: + mov cx, ax ; byte count +lff44m_9: + mov bp, 10 ; interpolation (one step) loop count + mov byte [faz], 2 ; 2 steps/phases +lff44m_1: + ; 2:1:1:1:1:1:1:1:1:1:1:: ; 25/23 + ; 2:1:1:1:1:1:1:1:1:1:1:1 + lodsb + mov dl, 80h + dec cx + jz short lff44m_2_1 + mov dl, [si] +lff44m_2_1: + ; al = [previous_val] + ; dl = [next_val] + call interpolating_2_8bit_mono + jcxz lff44m_3 +lff44m_2_2: + lodsb + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; (L) + stosw ; (R) + + dec cx + jz short lff44m_3 + dec bp + jnz short lff44m_2_2 + + dec byte [faz] + jz short lff44m_9 + mov bp, 11 + jmp short lff44m_1 + +lff44m_3: +lff44s_3: + jmp lff44_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff44m_7: +lff44s_7: + jmp lff44_5 ; error + +load_44khz_stereo_8_bit: + ; 16/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff44s_0 ; no + stc + retn + +lff44s_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff44s_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff44s_8 + jmp lff44_eof + +lff44s_8: + mov cx, ax ; word count +lff44s_9: + mov bp, 10 ; interpolation (one step) loop count + mov byte [faz], 2 ; 2 steps/phase +lff44s_1: + ; 2:1:1:1:1:1:1:1:1:1:1:: ; 25/23 + ; 2:1:1:1:1:1:1:1:1:1:1:1 + lodsw + mov dx, 8080h + dec cx + jz short lff44s_2_1 + mov dx, [si] +lff44s_2_1: + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dl = [next_val_r] + call interpolating_2_8bit_stereo + jcxz lff44s_3 +lff44s_2_2: + lodsb + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; (L) + lodsb + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; (R) + + dec cx + jz short lff44s_3 + dec bp + jnz short lff44s_2_2 + + dec byte [faz] + jz short lff44s_9 + mov bp, 11 + jmp short lff44s_1 + +load_44khz_mono_16_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff44m2_0 ; no + stc + retn + +lff44m2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff44m2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 1 + ;and ax, ax + jnz short lff44m2_8 + jmp lff44_eof + +lff44m2_8: + mov cx, ax ; word count +lff44m2_9: + mov bp, 10 ; interpolation (one step) loop count + mov byte [faz], 2 ; 2 steps/phases +lff44m2_1: + ; 2:1:1:1:1:1:1:1:1:1:1:: ; 25/23 + ; 2:1:1:1:1:1:1:1:1:1:1:1 + lodsw + xor dx, dx + dec cx + jz short lff44m2_2_1 + mov dx, [si] +lff44m2_2_1: + ; ax = [previous_val] + ; dx = [next_val] + call interpolating_2_16bit_mono + jcxz lff44m2_3 +lff44m2_2_2: + lodsw + stosw ; (L)eft Channel + stosw ; (R)ight Channel + + dec cx + jz short lff44m2_3 + dec bp + jnz short lff44m2_2_2 + + dec byte [faz] + jz short lff44m2_9 + mov bp, 11 + jmp short lff44m2_1 + +lff44m2_3: +lff44s2_3: + jmp lff44_3 ; padfill + ; (put zeros in the remain words of the buffer) +lff44m2_7: +lff44s2_7: + jmp lff44_5 ; error + +load_44khz_stereo_16_bit: + ; 18/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff44s2_0 ; no + stc + retn + +lff44s2_0: + mov es, ax ; buffer segment + xor di, di + mov dx, temp_buffer ; temporary buffer for wav data + ; ds = cs + + ; load file into memory + mov cx, [loadsize] + mov bx, [filehandle] + mov ah, 3Fh + int 21h + jc short lff44s2_7 ; error ! + + ; 14/11/2024 + mov [count], ax + + mov si, dx ; temp_buffer ; temporary buffer address + + shr ax, 2 ; dword (left chan word + right chan word) + ;and ax, ax + jnz short lff44s2_8 + jmp lff44_eof + +lff44s2_8: + mov cx, ax ; dword count +lff44s2_9: + mov bp, 10 ; interpolation (one step) loop count + mov byte [faz], 2 ; 2 steps/phase +lff44s2_1: + ; 2:1:1:1:1:1:1:1:1:1:1:: ; 25/23 + ; 2:1:1:1:1:1:1:1:1:1:1:1 + lodsw + mov bx, ax + lodsw + mov dx, [si] + mov [next_val_l], dx + mov dx, [si+2] + dec cx + jnz short lff44s2_2_1 + xor dx, dx ; 0 + mov [next_val_l], dx +lff44s2_2_1: + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + call interpolating_2_16bit_stereo + jcxz lff44s2_3 +lff44s2_2_2: + ;lodsw + ;stosw ; (L) + ;lodsw + ;stosw ; (R) + movsw ; (L)eft Channel + movsw ; (R)ight Channel + + dec cx + jz short lff44s2_3 + dec bp + jnz short lff44s2_2_2 + + dec byte [faz] + jz short lff44s2_9 + mov bp, 11 + jmp short lff44s2_1 + +; ..................... + +interpolating_3_8bit_mono: + ; 16/11/2023 + ; al = [previous_val] + ; dl = [next_val] + ; original-interpolated-interpolated + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + stosw ; original sample (R) + mov al, bl + add al, dl + rcr al, 1 + mov bh, al ; interpolated middle (temporary) + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov al, bh + add al, dl ; [next_val] + rcr al, 1 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + retn + +interpolating_3_8bit_stereo: + ; 16/11/2023 + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dh = [next_val_r] + ; original-interpolated-interpolated + mov bx, ax + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + mov al, bh + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + push ax ; * ; al = interpolated middle (L) (temporary) + add al, bl ; [previous_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + push ax ; ** ; al = interpolated middle (R) (temporary) + add al, bh ; [previous_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (R) + pop bx ; ** + pop ax ; * + add al, dl ; [next_val_l] + rcr al, 1 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + mov al, bl + add al, dh ; [next_val_r] + rcr al, 1 + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (R) + retn + +interpolating_2_8bit_mono: + ; 16/11/2023 + ; al = [previous_val] + ; dl = [next_val] + ; original-interpolated + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + stosw ; original sample (R) + mov al, bl + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample (L) + stosw ; interpolated sample (R) + retn + +interpolating_2_8bit_stereo: + ; 16/11/2023 + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dh = [next_val_r] + ; original-interpolated + mov bx, ax + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + mov al, bh + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + mov al, bl ; [previous_val_l] + add al, dl ; [next_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample (R) + retn + +interpolating_3_16bit_mono: + ; 16/11/2023 + ; ax = [previous_val] + ; dx = [next_val] + ; original-interpolated-interpolated + + stosw ; original sample (L) + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + push ax ; * ; [previous_val] + add dh, 80h + add ax, dx + rcr ax, 1 + pop bx ; * + xchg bx, ax ; bx = interpolated middle (temporary) + add ax, bx ; [previous_val] + interpolated middle + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov ax, bx + add ax, dx ;interpolated middle + [next_val] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + retn + +interpolating_3_16bit_stereo: + ; 16/11/2023 + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + ; original-interpolated-interpolated + + xchg ax, bx + stosw ; original sample (L) + xchg ax, bx + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + push ax ; * ; [previous_val_r] + add bh, 80h + add byte [next_val_l+1], 80h + mov ax, [next_val_l] + add ax, bx ; [previous_val_l] + rcr ax, 1 + xchg ax, bx ; ax = [previous_val_l] + add ax, bx ; bx = interpolated middle (L) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + pop ax ; * + add dh, 80h ; convert sound level 0 to 65535 format + push dx ; * ; [next_val_r] + xchg ax, dx + add ax, dx ; [next_val_r] + [previous_val_r] + rcr ax, 1 ; / 2 + push ax ; ** ; interpolated middle (R) + add ax, dx ; + [previous_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (R) + mov ax, [next_val_l] + add ax, bx ; + interpolated middle (L) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + pop ax ; ** + pop dx ; * + add ax, dx ; interpolated middle + [next_val_r] + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + retn + + +interpolating_2_16bit_mono: + ; 16/11/2023 + ; ax = [previous_val] + ; dx = [next_val] + ; original-interpolated + + stosw ; original sample (L) + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + add dh, 80h + add ax, dx + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample (L) + stosw ; interpolated sample (R) + retn + +interpolating_2_16bit_stereo: + ; 16/11/2023 + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; dx = [next_val_r] + ; original-interpolated + + xchg ax, bx + stosw ; original sample (L) + xchg ax, bx + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + add dh, 80h + add ax, dx ; [previous_val_r] + [next_val_r] + rcr ax, 1 ; / 2 + push ax ; * ; interpolated sample (R) + mov ax, [next_val_l] + add ah, 80h + add bh, 80h + add ax, bx ; [next_val_l] + [previous_val_l] + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample (L) + pop ax ; * + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample (R) + retn + +interpolating_5_8bit_mono: + ; 17/11/2023 + ; al = [previous_val] + ; dl = [next_val] + ; original-interpltd-interpltd-interpltd-interpltd + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + stosw ; original sample (R) + mov al, bl + add al, dl + rcr al, 1 + mov bh, al ; interpolated middle (temporary) + add al, bl ; [previous_val] + rcr al, 1 + mov dh, al ; interpolated 1st quarter (temporary) + add al, bl + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov al, bh + add al, dh + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + mov al, bh + add al, dl ; [next_val] + rcr al, 1 + mov dh, al ; interpolated 3rd quarter (temporary) + add al, bh + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (L) + stosw ; interpolated sample 3 (R) + mov al, dh + add al, dl + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 4 (L) + stosw ; interpolated sample 4 (R) + retn + +interpolating_5_8bit_stereo: + ; 17/11/2023 + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dh = [next_val_r] + ; original-interpltd-interpltd-interpltd-interpltd + mov bx, ax + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + mov al, bh + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + push dx ; * + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + push ax ; ** ; al = interpolated middle (L) (temporary) + add al, bl ; [previous_val_l] + rcr al, 1 + xchg al, bl + add al, bl ; bl = interpolated 1st quarter (L) (temp) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + push ax ; *** ; al = interpolated middle (R) (temporary) + add al, bh ; [previous_val_r] + rcr al, 1 + xchg al, bh + add al, bh ; bh = interpolated 1st quarter (R) (temp) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (R) + pop dx ; *** + pop ax ; ** ; al = interpolated middle (L) (temporary) + xchg al, bl ; al = interpolated 1st quarter (L) (temp) + add al, bl ; bl = interpolated middle (L) (temporary) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + mov al, dl ; interpolated middle (R) (temporary) + xchg al, bh ; al = interpolated 1st quarter (R) (temp) + add al, bh ; bh = interpolated middle (R) (temporary) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (R) + pop dx ; * + mov al, bl ; interpolated middle (L) (temporary) + add al, dl ; [next_val_l] + rcr al, 1 + xchg al, bl ; al = interpolated middle (R) (temporary) + add al, bl ; bl = interpolated 3rd quarter (L) (temp) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (L) + mov al, bh + add al, dh ; interpolated middle (R) + [next_val_r] + rcr al, 1 + xchg al, bh ; al = interpolated middle (R) + add al, bh ; bh = interpolated 3rd quarter (R) (temp) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (R) + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 4 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 4 (R) + retn + +interpolating_4_8bit_mono: + ; 17/11/2023 + ; al = [previous_val] + ; dl = [next_val] + ; original-interpolated-interpolated-interpolated + mov bl, al + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + stosw ; original sample (R) + mov al, bl + add al, dl + rcr al, 1 + xchg al, bl ; al = [previous_val] + add al, bl ; bl = interpolated middle (sample 2) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov al, bl ; interpolated middle (sample 2) + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + mov al, bl + add al, dl ; [next_val] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (L) + stosw ; interpolated sample 3 (R) + retn + +interpolating_4_8bit_stereo: + ; 17/11/2023 + ; al = [previous_val_l] + ; ah = [previous_val_r] + ; dl = [next_val_l] + ; dh = [next_val_r] + ; original-interpolated-interpolated-interpolated + mov bx, ax + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (L) + mov al, bh + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; original sample (R) + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + xchg al, bl ; al = [previous_val_l] + add al, bl ; bl = interpolated middle (L) (sample 2) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + xchg al, bh ; al = [previous_val_h] + add al, bh ; bh = interpolated middle (R) (sample 2) + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 1 (R) + mov al, bl ; interpolated middle (L) (sample 2) + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + mov al, bh ; interpolated middle (L) (sample 2) + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 2 (L) + mov al, bl + add al, dl ; [next_val_l] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (L) + mov al, bh + add al, dh ; [next_val_r] + rcr al, 1 + sub al, 80h + shl ax, 8 ; convert 8 bit sample to 16 bit sample + stosw ; interpolated sample 3 (R) + retn + +interpolating_5_16bit_mono: + ; 18/11/2023 + ; ax = [previous_val] + ; dx = [next_val] + ; original-interpltd-interpltd-interpltd-interpltd + stosw ; original sample (L) + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + mov bx, ax ; [previous_val] + add dh, 80h + add ax, dx + rcr ax, 1 + push ax ; * ; interpolated middle (temporary) + add ax, bx ; interpolated middle + [previous_val] + rcr ax, 1 + push ax ; ** ; interpolated 1st quarter (temporary) + add ax, bx ; 1st quarter + [previous_val] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + pop ax ; ** + pop bx ; * + add ax, bx ; 1st quarter + middle + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + mov ax, bx + add ax, dx ; interpolated middle + [next_val] + rcr ax, 1 + push ax ; * ; interpolated 3rd quarter (temporary) + add ax, bx ; + interpolated middle + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (L) + stosw ; interpolated sample 3 (R) + pop ax ; * + add ax, dx ; 3rd quarter + [next_val] + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 4 (L) + stosw ; interpolated sample 4 (R) + retn + +interpolating_5_16bit_stereo: + ; 18/11/2023 + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; [next_val_r] + ; original-interpltd-interpltd-interpltd-interpltd + push cx ; ! + xchg ax, bx + stosw ; original sample (L) + xchg ax, bx + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + push ax ; * ; [previous_val_r] + add bh, 80h + add byte [next_val_l+1], 80h + mov ax, [next_val_l] + add ax, bx ; [previous_val_l] + rcr ax, 1 + mov cx, ax ; interpolated middle (L) + add ax, bx + rcr ax, 1 + mov dx, ax ; interpolated 1st quarter (L) + add ax, bx ; [previous_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + mov ax, cx + add ax, dx ; middle (L) + 1st quarter (L) + rcr ax, 1 ; / 2 + mov bx, ax ; interpolated sample 2 (L) + pop dx ; * ; [previous_val_r] + mov ax, dx + add byte [next_val_r+1], 80h + add ax, [next_val_r] + rcr ax, 1 + push ax ; * ; interpolated middle (R) + add ax, dx + rcr ax, 1 + push ax ; ** ; interpolated 1st quarter (R) + add ax, dx ; [previous_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (R) + mov ax, bx + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + pop ax ; ** + pop dx ; * + add ax, dx ; 1st quarter (R) + middle (R) + rcr ax, 1 ; / 2 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (R) + mov ax, cx + add ax, [next_val_l] + rcr ax, 1 + push ax ; * ; interpolated 3rd quarter (L) + add ax, cx ; interpolated middle (L) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (L) + mov ax, dx + add ax, [next_val_r] + rcr ax, 1 + push ax ; ** ; interpolated 3rd quarter (R) + add ax, dx ; interpolated middle (R) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (R) + pop bx ; ** + pop ax ; * + add ax, [next_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 4 (L) + mov ax, bx + add ax, [next_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 4 (R) + pop cx ; ! + retn + +interpolating_4_16bit_mono: + ; 18/11/2023 + ; ax = [previous_val] + ; dx = [next_val] + ; original-interpolated + + stosw ; original sample (L) + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + mov bx, ax ; [previous_val] + add dh, 80h + add ax, dx ; [previous_val] + [next_val] + rcr ax, 1 + xchg ax, bx + add ax, bx ; [previous_val] + interpolated middle + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + stosw ; interpolated sample 1 (R) + mov ax, bx ; interpolated middle + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + stosw ; interpolated sample 2 (R) + mov ax, bx + add ax, dx ; interpolated middle + [next_val] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (L) + stosw ; interpolated sample 3 (R) + retn + +interpolating_4_16bit_stereo: + ; 18/11/2023 + ; bx = [previous_val_l] + ; ax = [previous_val_r] + ; [next_val_l] + ; [next_val_r] + ; original-interpolated-interpolated-interpolated + xchg ax, bx + stosw ; original sample (L) + xchg ax, bx + stosw ; original sample (R) + add ah, 80h ; convert sound level 0 to 65535 format + mov dx, ax ; [previous_val_r] + add bh, 80h + add byte [next_val_l+1], 80h + mov ax, [next_val_l] + add ax, bx ; [previous_val_l] + rcr ax, 1 + xchg ax, bx + add ax, bx ; bx = interpolated middle (L) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (L) + add byte [next_val_r+1], 80h + mov ax, dx ; [previous_val_r] + add ax, [next_val_r] + rcr ax, 1 + xchg ax, dx + add ax, dx ; dx = interpolated middle (R) + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 1 (R) + mov ax, bx + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (L) + mov ax, dx + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 2 (R) + mov ax, bx + add ax, [next_val_l] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (L) + mov ax, dx + add ax, [next_val_r] + rcr ax, 1 + sub ah, 80h ; -32768 to +32767 format again + stosw ; interpolated sample 3 (R) + retn + +; 13/11/2023 +previous_val: +previous_val_l: dw 0 +previous_val_r: dw 0 +next_val: +next_val_l: dw 0 +next_val_r: dw 0 + +; 16/11/2023 +faz: db 0 + +; -------------------------------------------------------- +; 27/05/2024 - (TRDOS 386 Kernel) audio.s +; -------------------------------------------------------- + +NOT_PCI32_PCI16 EQU 03FFFFFFFh ; NOT BIT31+BIT30 ; 19/03/2017 +NOT_BIT31 EQU 7FFFFFFFh + +pciFindDevice: + ; 19/11/2023 + ; 03/04/2017 ('pci.asm', 20/03/2017) + ; + ; scan through PCI space looking for a device+vendor ID + ; + ; Entry: EAX=Device+Vendor ID + ; + ; Exit: EAX=PCI address if device found + ; EDX=Device+Vendor ID + ; CY clear if found, set if not found. EAX invalid if CY set. + ; + ; Destroys: ebx, edi ; 19/11/2023 + + ; 19/11/2023 + mov ebx, eax + mov edi, 80000000h +nextPCIdevice: + mov eax, edi ; read PCI registers + call pciRegRead32 + ; 19/11/2023 + cmp edx, ebx + je short PCIScanExit ; found + ; 19/11/2023 + cmp edi, 80FFF800h + jnb short pfd_nf ; not found + add edi, 100h + jmp short nextPCIdevice +pfd_nf: + stc + retn +PCIScanExit: + ;pushf + mov eax, NOT_BIT31 ; 19/03/2017 + and eax, edi ; return only bus/dev/fn # + retn + +pciRegRead: + ; 30/05/2024 + ; 03/04/2017 ('pci.asm', 20/03/2017) + ; + ; 8/16/32bit PCI reader + ; + ; Entry: EAX=PCI Bus/Device/fn/register number + ; BIT30 set if 32 bit access requested + ; BIT29 set if 16 bit access requested + ; otherwise defaults to 8 bit read + ; + ; Exit: DL,DX,EDX register data depending on requested read size + ; + ; Note1: this routine is meant to be called via pciRegRead8, + ; pciRegread16 or pciRegRead32, listed below. + ; + ; Note2: don't attempt to read 32 bits of data from a non dword + ; aligned reg number. Likewise, don't do 16 bit reads from + ; non word aligned reg # + + push ebx + push cx + mov ebx, eax ; save eax, dh + mov cl, dh + + and eax, NOT_PCI32_PCI16 ; clear out data size request + or eax, BIT31 ; make a PCI access request + and al, NOT 3 ; 13/11/2024 ; force index to be dword + + mov dx, PCI_INDEX_PORT + out dx, eax ; write PCI selector + + mov dx, PCI_DATA_PORT + mov al, bl + and al, 3 ; figure out which port to + add dl, al ; read to + + test ebx, PCI32+PCI16 + jnz short _pregr0 + + in al, dx ; return 8 bits of data + + mov dl, al + mov dh, cl ; restore dh for 8 bit read + jmp short _pregr2 +_pregr0: + test ebx, PCI32 + jnz short _pregr1 + + in ax, dx + + mov dx, ax ; return 16 bits of data + jmp short _pregr2 +_pregr1: + in eax, dx ; return 32 bits of data + + mov edx, eax +_pregr2: + mov eax, ebx ; restore eax + and eax, NOT_PCI32_PCI16 ; clear out data size request + pop cx + pop ebx + retn + +pciRegRead8: + and eax, NOT_PCI32_PCI16 ; set up 8 bit read size + jmp short pciRegRead ; call generic PCI access + +pciRegRead16: + and eax, NOT_PCI32_PCI16 ; set up 16 bit read size + or eax, PCI16 ; call generic PCI access + jmp short pciRegRead + +pciRegRead32: + and eax, NOT_PCI32_PCI16 ; set up 32 bit read size + or eax, PCI32 ; call generic PCI access + jmp pciRegRead + +pciRegWrite: + ; 30/05/2024 + ; 03/04/2017 ('pci.asm', 29/11/2016) + ; + ; 8/16/32bit PCI writer + ; + ; Entry: EAX=PCI Bus/Device/fn/register number + ; BIT31 set if 32 bit access requested + ; BIT30 set if 16 bit access requested + ; otherwise defaults to 8bit read + ; DL/DX/EDX data to write depending on size + ; + ; Note1: this routine is meant to be called via pciRegWrite8, + ; pciRegWrite16 or pciRegWrite32 as detailed below. + ; + ; Note2: don't attempt to write 32bits of data from a non dword + ; aligned reg number. Likewise, don't do 16 bit writes from + ; non word aligned reg # + + push ebx + push ecx + mov ebx, eax ; save eax, edx + mov ecx, edx + and eax, NOT_PCI32_PCI16 ; clear out data size request + or eax, BIT31 ; make a PCI access request + and al, NOT 3 ; 13/11/2024 ; force index to be dword + + mov dx, PCI_INDEX_PORT + out dx, eax ; write PCI selector + + mov dx, PCI_DATA_PORT + mov al, bl + and al, 3 ; figure out which port to + add dl, al ; write to + + test ebx, PCI32+PCI16 + jnz short _pregw0 + + mov al, cl ; put data into al + out dx, al + + jmp short _pregw2 +_pregw0: + test ebx, PCI32 + jnz short _pregw1 + + mov ax, cx ; put data into ax + out dx, ax + + jmp short _pregw2 +_pregw1: + mov eax, ecx ; put data into eax + out dx, eax +_pregw2: + mov eax, ebx ; restore eax + and eax, NOT_PCI32_PCI16 ; clear out data size request + mov edx, ecx ; restore dx + pop ecx + pop ebx + retn + +pciRegWrite8: + and eax, NOT_PCI32_PCI16 ; set up 8 bit write size + jmp short pciRegWrite ; call generic PCI access + +pciRegWrite16: + and eax, NOT_PCI32_PCI16 ; set up 16 bit write size + or eax, PCI16 ; call generic PCI access + jmp short pciRegWrite + +pciRegWrite32: + and eax, NOT_PCI32_PCI16 ; set up 32 bit write size + or eax, PCI32 ; call generic PCI access + jmp pciRegWrite + +; -------------------------------------------------------- +; 19/05/2024 - (playwav4.asm) ac97_vra.asm +; -------------------------------------------------------- + + ; 13/11/2023 + +;VRA: db 1 + +codecConfig: + ; 30/05/2024 + ; 19/05/2024 + ; 19/11/2023 + ; 15/11/2023 + ; 04/11/2023 + ; 17/02/2017 + ; 07/11/2016 (Erdogan Tan) + + ;AC97_EA_VRA equ 1 + AC97_EA_VRA equ BIT0 + + ; 04/11/2023 +init_ac97_controller: + mov eax, [bus_dev_fn] + mov al, PCI_CMD_REG + call pciRegRead16 ; read PCI command register + or dl, IO_ENA+BM_ENA ; enable IO and bus master + call pciRegWrite16 + + ;call delay_100ms + + ; 19/05/2024 + ; ('PLAYMOD3.ASM', Erdogan Tan, 18/05/2024) + +init_ac97_codec: + ; 18/11/2023 + mov bp, 40 + ; 29/05/2024 + ;mov bp, 1000 +_initc_1: + ; 30/05/2024 + mov dx, GLOB_STS_REG ; 30h + add dx, [NABMBAR] + in eax, dx + + ; 19/05/2024 + call delay1_4ms + + cmp eax, 0FFFFFFFFh ; -1 + jne short _initc_3 +_initc_2: + dec bp + jz short _ac97_codec_ready + + call delay_100ms + jmp short _initc_1 +_initc_3: + test eax, CTRL_ST_CREADY + jnz short _ac97_codec_ready + + ; 30/05/2024 + cmp byte [reset], 1 + jnb short _initc_2 + + call reset_ac97_codec + ; 30/05/2024 + mov byte [reset], 1 + ; 19/05/2024 + jmp short _initc_2 + +_ac97_codec_ready: + mov dx, [NAMBAR] + ;add dx, 0 ; ac_reg_0 ; reset register + out dx, ax + + call delay_100ms + + ; 19/11/2023 + or bp, bp + jnz short _ac97_codec_init_ok + + xor ax, ax ; 0 + mov dx, [NAMBAR] + add dx, CODEC_REG_POWERDOWN + out dx, ax + + ; 30/05/2024 + call delay1_4ms + + ; 19/11/2023 + ; wait for 1 second + ; 19/05/2024 + mov cx, 1000 ; 1000*4*0.25ms = 1s + ;;mov cx, 10 + ; 30/05/2024 + ;mov cx, 40 +_ac97_codec_rloop: + ;call delay_100ms + + ; 30/05/2024 + mov dx, [NAMBAR] + add dx, CODEC_REG_POWERDOWN + in ax, dx + + call delay1_4ms + + and ax, 0Fh + cmp al, 0Fh + je short _ac97_codec_init_ok + loop _ac97_codec_rloop + +init_ac97_codec_err1: + ;stc ; cf = 1 ; 19/05/2024 +init_ac97_codec_err2: + retn + +_ac97_codec_init_ok: + call reset_ac97_controller + + ; 30/05/2024 + ; 19/05/2024 + ;call delay_100ms + + ; 30/05/2024 + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + +setup_ac97_codec: + ; 12/11/2023 + cmp word [WAVE_SampleRate], 48000 + je short skip_rate + + ; 30/05/2024 + ; 19/05/2024 + ;call delay1_4ms + + ; 30/05/2024 + ;cmp byte [VRA], 0 + ;jna short skip_rate + + ; 11/11/2023 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + in ax, dx + + ; 30/05/2024 + ; 19/05/2024 + call delay1_4ms + + ; 13/11/2024 + ;and al, NOT BIT1 ; Clear DRA + ;;; + ; 30/05/2024 + and al, NOT (BIT1+BIT0) ; Clear DRA+VRA + out dx, ax + + call check_vra + + cmp byte [VRA], 0 + jna short skip_rate + + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + in ax, dx + ;and al, ~BIT1 ; Clear DRA + ;;; + + or al, AC97_EA_VRA ; 1 ; 04/11/2023 + ; 30/05/2024 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + + out dx, ax ; Enable variable rate audio + + mov cx, 10 +check_vra_loop: + call delay_100ms + ; 30/05/2024 + ;call delay1_4ms + + ; 30/05/2024 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_CTRL_REG ; 2Ah + ; 11/11/2023 + in ax, dx + + test al, AC97_EA_VRA ; 1 + jnz short set_rate + + ; 11/11/2023 + loop check_vra_loop + +;vra_not_supported: ; 19/05/2024 + mov byte [VRA], 0 + jmp short skip_rate + +set_rate: + mov ax, [WAVE_SampleRate] ; 17/02/2017 (Erdogan Tan) + + mov dx, [NAMBAR] + add dx, CODEC_PCM_FRONT_DACRATE_REG ; 2Ch + out dx, ax ; PCM Front/Center Output Sample Rate + + ;call delay_100ms + ; 30/05/2024 + call delay1_4ms + + ; 12/11/2023 +skip_rate: + mov ax, 0202h + mov dx, [NAMBAR] + add dx, CODEC_MASTER_VOL_REG ;02h + out dx, ax + + ; 11/11/2023 + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + + mov ax, 0202h + mov dx, [NAMBAR] + add dx, CODEC_PCM_OUT_REG ;18h + out dx, ax + + ; 11/11/2023 + call delay1_4ms + call delay1_4ms + call delay1_4ms + call delay1_4ms + + ; 30/05/2024 + ; 19/05/2024 + ;clc + + retn + +reset_ac97_controller: + ; 19/05/2024 + ; 11/11/2023 + ; 10/06/2017 + ; 29/05/2017 + ; 28/05/2017 + ; reset AC97 audio controller registers + xor ax, ax + mov dx, PI_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov dx, PO_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov dx, MC_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov al, RR + mov dx, PI_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov dx, PO_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + mov dx, MC_CR_REG + add dx, [NABMBAR] + out dx, al + + ; 19/05/2024 + call delay1_4ms + + retn + +reset_ac97_codec: + ; 11/11/2023 + ; 28/05/2017 - Erdogan Tan (Ref: KolibriOS, intelac97.asm) + mov dx, GLOB_CNT_REG ; 2Ch + add dx, [NABMBAR] + in eax, dx + + ;test eax, 2 + ; 06/08/2022 + test al, 2 + jz short _r_ac97codec_cold + + call warm_ac97codec_reset + jnc short _r_ac97codec_ok +_r_ac97codec_cold: + call cold_ac97codec_reset + jnc short _r_ac97codec_ok + + ; 16/04/2017 + ;xor eax, eax ; timeout error + ;stc + retn + +_r_ac97codec_ok: + xor eax, eax + ;mov al, VIA_ACLINK_C00_READY ; 1 + inc al + retn + +warm_ac97codec_reset: + ; 11/11/2023 + ; 06/08/2022 - TRDOS 386 v2.0.5 + ; 28/05/2017 - Erdogan Tan (Ref: KolibriOS, intelac97.asm) + mov eax, 6 + mov dx, GLOB_CNT_REG ; 2Ch + add dx, [NABMBAR] + out dx, eax + + mov cx, 10 ; total 1s +_warm_ac97c_rst_wait: + call delay_100ms + + mov dx, GLOB_STS_REG ; 30h + add dx, [NABMBAR] + in eax, dx + + test eax, CTRL_ST_CREADY + jnz short _warm_ac97c_rst_ok + + dec cx + jnz short _warm_ac97c_rst_wait + +_warm_ac97c_rst_fail: + stc +_warm_ac97c_rst_ok: + retn + +cold_ac97codec_reset: + ; 11/11/2023 + ; 06/08/2022 - TRDOS 386 v2.0.5 + ; 28/05/2017 - Erdogan Tan (Ref: KolibriOS, intelac97.asm) + mov eax, 2 + mov dx, GLOB_CNT_REG ; 2Ch + add dx, [NABMBAR] + out dx, eax + + call delay_100ms ; wait 100 ms + call delay_100ms ; wait 100 ms + call delay_100ms ; wait 100 ms + call delay_100ms ; wait 100 ms + + mov cx, 16 ; total 20*100 ms = 2s + +_cold_ac97c_rst_wait: + mov dx, GLOB_STS_REG ; 30h + add dx, [NABMBAR] + in eax, dx + + test eax, CTRL_ST_CREADY + jnz short _cold_ac97c_rst_ok + + call delay_100ms + + dec cx + jnz short _cold_ac97c_rst_wait + +_cold_ac97c_rst_fail: + stc +_cold_ac97c_rst_ok: + retn + +; 13/11/2024 +; 30/05/2024 +if 1 +check_vra: + ; 30/05/2024 + mov byte [VRA], 1 + + ; 29/05/2024 - audio.s (TRDOS 386 Kernel) - 27/05/2024 + ; 24/05/2024 + ; 23/05/2024 + mov dx, [NAMBAR] + add dx, CODEC_EXT_AUDIO_REG ; 28h + in ax, dx + + ; 30/05/2024 + ; 23/05/2024 + call delay1_4ms + + ; 30/05/2024 + test al, BIT0 + ;test al, 1 ; BIT0 ; Variable Rate Audio bit + jnz short check_vra_ok + +vra_not_supported: + ; 13/11/2023 + mov byte [VRA], 0 +check_vra_ok: + retn +end if + +; -------------------------------------------------------- + +; 18/11/2024 +; Ref: TRDOS 386 v2.0.9, audio.s, Erdogan Tan, 06/06/2024 + +ac97_stop: + ; 18/11/2024 + mov byte [stopped], 2 + +ac97_po_cmd@: + xor al, al ; 0 +ac97_po_cmd: + mov dx, [NABMBAR] + add dx, PO_CR_REG ; PCM out control register + out dx, al + retn + +ac97_pause: + mov byte [stopped], 1 ; paused + ;mov al, 0 + ;jmp short ac97_po_cmd + jmp short ac97_po_cmd@ + +ac97_play: ; continue to play (after pause) + mov byte [stopped], 0 + mov al, RPBM + jmp short ac97_po_cmd + +; -------------------------------------------------------- + +PORTB EQU 061h +REFRESH_STATUS EQU 010h ; Refresh signal status + +delay_100ms: + ; 11/11/2023 + ; 29/05/2017 + ; 24/03/2017 ('codec.asm') + ; wait 100 ms + push cx + mov cx, 400 ; 400*0.25ms +_delay_x_ms: + call delay1_4ms + loop _delay_x_ms + pop cx + retn + +delay1_4ms: + push ax + push cx + mov cx, 16 ; close enough. + in al,PORTB + and al,REFRESH_STATUS + mov ah,al ; Start toggle state + or cx, cx + jz short _d4ms1 + inc cx ; Throwaway first toggle +_d4ms1: + in al,PORTB ; Read system control port + and al,REFRESH_STATUS ; Refresh toggles 15.085 microseconds + cmp ah,al + je short _d4ms1 ; Wait for state change + + mov ah,al ; Update with new state + dec cx + jnz short _d4ms1 + + ; 30/05/2024 + clc + + pop cx + pop ax + retn + +; -------------------------------------------------------- +; 14/11/2024 - Erdogan Tan +; -------------------------------------------------------- + +checkUpdateEvents: + call check4keyboardstop + jc short c4ue_ok + + ; 18/11/2024 + push ax ; * + or ax, ax + jz c4ue_cpt + + ; 18/11/2024 + cmp al, 20h ; SPACE (spacebar) ; pause/play + jne short ch4ue_chk_s + cmp byte [stopped], 0 + ja short ch4ue_chk_ps + ; pause + call ac97_pause + ; 21/11/2024 + mov al, [tLO] + mov byte [tLP], al + jmp c4ue_cpt +ch4ue_chk_ps: + cmp byte [stopped], 1 + ja short ch4ue_replay + ; continue to play (after a pause) + call ac97_play + jmp short c4ue_cpt +ch4ue_replay: + ; 19/11/2024 + pop ax ; * + pop ax ; return address + call codecConfig + mov al, [volume] + call SetPCMOutVolume@ + mov byte [stopped], 0 + call move_to_beginning + jmp PlayWav + +ch4ue_chk_s: + cmp al, 'S' ; stop + jne short ch4ue_chk_fb + cmp byte [stopped], 0 + ja short c4ue_cpt ; Already stopped/paused + call ac97_stop + ; 19/11/2024 + mov byte [tLO], 0 + ; 21/11/2024 + mov byte [tLP], '0' + jmp short c4ue_cpt + +ch4ue_chk_fb: + ; 17/11/2024 + cmp al, 'F' + jne short c4ue_chk_b + call Player_ProcessKey_Forwards + jmp short c4ue_cpt + + ; 18/11/2024 +c4ue_ok: + retn + +c4ue_chk_b: + cmp al, 'B' + ;jne short c4ue_cpt + ; 19/11/2024 + jne short c4ue_chk_h + call Player_ProcessKey_Backwards + jmp short c4ue_cpt +c4ue_chk_h: + ; 19/11/2024 + cmp al, 'H' + jne short c4ue_chk_cr + mov byte [wleds], 0 + call write_ac97_pci_dev_info + mov dh, 24 + mov dl, 79 + call setCursorPosition +c4ue_chk_cr: + ; 19/11/2024 + cmp al, 0Dh ; ENTER/CR key + jne short c4ue_cpt + ;inc byte [wleds] + ;jnz short c4ue_cpt + ;inc byte [wleds] + ;;; + ; 23/11/2024 + xor bx, bx + mov bl, [wleds] + inc bl + and bl, 0Fh + jnz short c4ue_sc + inc bx +c4ue_sc: + mov [wleds], bl + shr bl, 1 + mov al, [bx+colors] + jnc short c4ue_sc_@ + or al, 10h ; blue (dark) background +c4ue_sc_@: + mov [ccolor], al + ;;; +c4ue_cpt: + push ds + mov bx, 40h + mov ds, bx + mov bx, 6Ch ; counter (INT 08h, 18.2 ticks per sec) + ;cli + mov ax, [bx] + mov dx, [bx+2] + ;sti + pop ds + ; 18/11/2024 + pop cx ; * + cmp dx, [timerticks+2] + jne short c4ue_utt + cmp ax, [timerticks] + ;je short c4ue_ok + ; 18/11/2024 + je short c4ue_skip_utt +c4ue_utt: + mov [timerticks], ax + mov [timerticks+2], dx + jmp short c4ue_cpt_@ +c4ue_skip_utt: + ; 18/11/2024 + and cx, cx + jz short c4ue_ok +c4ue_cpt_@: + ; 18/11/2024 + cmp byte [stopped], 0 + ja short c4ue_ok + + call CalcProgressTime + + cmp ax, [ProgressTime] + ;je short c4ue_ok + ; same second, no need to update + ; 23/11/2024 + je short c4ue_uvb + + ;call UpdateProgressTime + ;call UpdateProgressBar@ + call UpdateProgressBar + + ; 23/11/2024 +c4ue_uvb: + cmp byte [wleds], 0 + jna short c4ue_vb_ok + + call UpdateWaveLeds + +c4ue_vb_ok: + retn + + ;clc +;c4ue_ok: +; retn + +; -------------------------------------------------------- +; 19/05/2024 - (playwav4.asm) ich_wav4.asm +; -------------------------------------------------------- + +check4keyboardstop: + ; 19/05/2024 + ; 08/11/2023 + ; 04/11/2023 + mov ah, 1 + int 16h + ;clc + jz short _cksr + + xor ah, ah + int 16h + + ;;; + ; 19/05/2024 (change PCM out volume) + cmp al, '+' + jne short p_1 + + mov al, [volume] + cmp al, 0 + jna short p_3 + dec al + jmp short p_2 +p_1: + cmp al, '-' + jne short p_4 + + mov al, [volume] + cmp al, 31 + jnb short p_3 + inc al +p_2: + mov [volume], al + ; 14/11/2024 + call SetPCMOutVolume + ; 15/11/2024 (QEMU) + ;call SetMasterVolume + ;call UpdateVolume + ;;clc + ;retn + jmp UpdateVolume + ;mov ah, al + ;mov dx, [NAMBAR] + ;;add dx, CODEC_MASTER_VOL_REG + ;add dx, CODEC_PCM_OUT_REG + ;out dx, ax + ; + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms + ;call delay1_4ms +_cksr: ; 19/05/2024 + ; 18/11/2024 + xor ax, ax + ;clc +p_3: + retn +p_4: + ; 17/11/2024 + cmp ah, 01h ; ESC + je short p_q + cmp al, 03h ; CTRL+C + je short p_q + + ; 18/11/2024 + cmp al, 20h + je short p_r + + ; 19/11/2024 + cmp al, 0Dh ; CR/ENTER + je short p_r + + and al, 0DFh + cmp al, 'B' + je short p_r + cmp al, 'F' + je short p_r + cmp al, 'Q' + je short p_q + + clc + retn + + ;;; +;_cskr: +p_q: + stc +p_r: + retn + +; returns AL = current index value +getCurrentIndex: + ; 08/11/2023 + ;push dx + mov dx, [NABMBAR] + add dx, PO_CIV_REG + in al, dx + ;pop dx +uLVI2: ; 06/11/2023 + retn + +updateLVI: + ; 06/11/2023 + mov dx, [NABMBAR] + add dx, PO_CIV_REG + ; (Current Index Value and Last Valid Index value) + in ax, dx + + cmp al, ah ; is current index = last index ? + jne short uLVI2 + + ; 08/11/2023 + call getCurrentIndex + + test byte [flags], ENDOFFILE + ;jnz short uLVI1 + jz short uLVI0 ; 08/11/2023 + + ; 08/11/2023 + push ax + mov dx, [NABMBAR] + add dx, PO_SR_REG ; PCM out status register + in ax, dx + + test al, 3 ; bit 1 = Current Equals Last Valid (CELV) + ; (has been processed) + ; bit 0 = 1 -> DMA Controller Halted (DCH) + pop ax + jz short uLVI1 +uLVI3: + xor ax, ax + ; zf = 1 + retn +uLVI0: + ; not at the end of the file yet. + dec al + and al, 1Fh +uLVI1: + ;call setLastValidIndex +;uLVI2: + ;retn + +;input AL = index # to stop on +setLastValidIndex: + ; 08/11/2023 + ;push dx + mov dx, [NABMBAR] + add dx, PO_LVI_REG + out dx, al + ;pop dx + retn + +; 29/05/2024 +; 19/05/2024 +volume: db 02h + +; -------------------------------------------------------- + + ; 14/11/2024 +setCursorPosition: + ; dh = Row + ; dl = Column + mov ax, 0500h + int 10h + mov ah, 02h + mov bh, 00h + ;mov dh, setCursorPosition_Row + ;mov dl, setCursorPosition_Column + int 10h + retn + +; -------------------------------------------------------- +; 14/11/2024 +; (Ref: player.asm, out_cs.asm, Matan Alfasi, 2017) + +;; NAME: SetTotalTime +;; DESCRIPTION: Calculates the total time in seconds in file +;; INPUT: DATA_SubchunkSize, WAVE_SampleRate, WAVE_BlockAlign +;; OUTPUT: CurrentTotalTime=Total time in seconds in file, +;; Output on the screen of the total time in seconds + +SetTotalTime: + ;; Calculate total seconds in file + mov ax, [DATA_SubchunkSize] + mov dx, [DATA_SubchunkSize + 2] + mov bx, [WAVE_SampleRate] + div bx + xor dx, dx + + mov bx, [WAVE_BlockAlign] + + div bx + + mov [TotalTime], ax + + mov bl, 60 + div bl + + ;; al = minutes, ah = seconds + push ax ; ** + push ax ; * + + mov dh, 24 + mov dl, 42 + call setCursorPosition + + pop ax ; * + xor ah, ah + mov bp, 2 + call PrintNumber + + mov dh, 24 + mov dl, 45 + call setCursorPosition + + pop ax ; ** + mov al, ah + xor ah, ah + ;mov bp, 2 + ;jmp short PrintNumber + +; -------------------------------------------------------- + +PrintNumber: + ; bp = digits + ; ax = binary number + mov bx, 10 + xor cx, cx +printNumber_CutNumber: + inc cx + xor dx, dx + div bx + push dx + cmp cx, bp + je short printNumber_printloop + jmp printNumber_CutNumber + +printNumber_printloop: + pop ax + mov dl, '0' + add dl, al + mov ah, 02h + int 21h + loop printNumber_printloop + + retn + +; -------------------------------------------------------- + + ; 14/11/2024 - Erdogan Tan +SetProgressTime: + ;; Calculate playing/progress seconds in file + call CalcProgressTime + +UpdateProgressTime: + ; ax = (new) progress time + + mov [ProgressTime], ax + + mov bl, 60 + div bl + + ;; al = minutes, ah = seconds + push ax ; ** + push ax ; * + + mov dh, 24 + mov dl, 33 + call setCursorPosition + + pop ax ; * + xor ah, ah + mov bp, 2 + call PrintNumber + + mov dh, 24 + mov dl, 36 + call setCursorPosition + + pop ax ; ** + mov al, ah + xor ah, ah + ;mov bp, 2 + jmp short PrintNumber + +; -------------------------------------------------------- + + ; 17/11/2024 + ; 14/11/2024 +CalcProgressTime: + mov ax, [LoadedDataBytes] + mov dx, [LoadedDataBytes+2] + mov bx, ax + or bx, dx + jz short cpt_ok + + mov bx, [WAVE_SampleRate] + div bx + xor dx, dx + mov bx, [WAVE_BlockAlign] + div bx +cpt_ok: + ; ax = (new) progress time + retn + +; -------------------------------------------------------- +; 14/11/2024 +; (Ref: player.asm, out_cs.asm, Matan Alfasi, 2017) + +;; DESCRIPTION: Update file information on template +;; PARAMS: WAVE parameters and other variables +;; REGS: AX(RW) +;; VARS: CurrentFileName, WAVE_SampleRate, +;; RETURNS: On-screen file info is updated. + +UpdateFileInfo: + ;; Print File Name + mov dh, 9 + mov dl, 23 + call setCursorPosition + + mov si, wav_file_name + + ;;; + ; 14/11/2024 + ; skip directory separators + ; (note: asciiz string, max. 79 bytes except zero tail) + mov bx, si +chk4_nxt_sep: + lodsb + cmp al, '\' + je short chg_fpos + and al, al + jz short chg_fpos_ok + jmp short chk4_nxt_sep +chg_fpos: + mov bx, si + jmp short chk4_nxt_sep +chg_fpos_ok: + mov si, bx ; file name (without its path/directory) + ;;; + + call PrintString + + ;; Print Frequency + mov dh, 10 + mov dl, 23 + call setCursorPosition + mov ax, [WAVE_SampleRate] + mov bp, 5 + call PrintNumber + + ;; Print BitRate + mov dh, 9 + mov dl, 57 + call setCursorPosition + mov ax, [WAVE_BitsPerSample] + mov bp, 2 + call PrintNumber + + ;; Print Channel Number + mov dh, 10 + mov dl, 57 + call setCursorPosition + mov ax, [WAVE_NumChannels] + mov bp, 1 + call PrintNumber + + ;call UpdateVolume + ;retn + +; -------------------------------------------------------- + + ; 14/11/2024 +UpdateVolume: + ;; Print Volume + mov dh, 24 + mov dl, 75 + call setCursorPosition + + mov al, [volume] + + mov bl, 100 + mul bl + + mov bl, 31 + div bl + + neg ax + add ax, 100 + + xor ah, ah + mov bp, 3 + ;call PrintNumber + ;retn + jmp PrintNumber + +; -------------------------------------------------------- + + ; 14/11/2024 +PrintString: + ; si = string address + mov bx, 0Fh ; white + mov ah, 0Eh ; write as tty +printstr_loop: + lodsb + or al, al + jz short printstr_ok + int 10h + jmp short printstr_loop +printstr_ok: + retn + +; -------------------------------------------------------- + + ; 14/11/2024 + ; (Ref: player.asm , Matan Alfasi, 2017) + ; (Modification: Erdogan Tan, 14/11/2024) + + PROGRESSBAR_ROW equ 23 + +UpdateProgressBar: + call SetProgressTime ; 14/11/2024 + + mov ax, [ProgressTime] +UpdateProgressBar@: + mov dx, 80 + mul dx + mov bx, [TotalTime] + div bx + + ;; Push for the 'Clean' part + push ax ; ** + push ax ; * + + ;; Set cursor position + mov dh, PROGRESSBAR_ROW + mov dl, 0 + call setCursorPosition + + pop ax ; * + or ax, ax + jz short UpdateProgressBar_Clean + +UpdateProgressBar_DrawProgress: + mov cx, ax + mov ah, 09h + mov al, 223 + mov bx, 0Fh + int 10h + +UpdateProgressBar_DrawCursor: + ;mov ax, cx + mov dh, PROGRESSBAR_ROW + ;mov dl, al + dec cx + mov dl, cl + call setCursorPosition + + mov ah, 09h + mov al, 223 + mov bx, 0Ch + mov cx, 1 + int 10h + +UpdateProgressBar_Clean: + pop ax ; ** + mov cx, ax + mov dh, PROGRESSBAR_ROW + mov dl, al + call setCursorPosition + + neg cx + add cx, 80 ; cf = 1 ; + + ;; CX = No. of times to print a clean character + ;mov cx, 80 + ;sub cx, ax + ;; 09h = Write character multiple times + mov ah, 09h + ;; 32 = Space ASCII code + ;mov al, 32 + ;mov bx, 0 + ; 15/11/2024 + mov al, 223 + mov bx, 8 + int 10h + ; 14/11/2024 + clc ; + + + retn + +; -------------------------------------------------------- +; 17/11/2024 + +Player_ProcessKey_Backwards: + ;; In order to go backwards 5 seconds: + ;; Update file pointer to the beginning, skip headers + mov cl, 'B' + jmp short Player_ProcessKey_B_or_F + +Player_ProcessKey_Forwards: + ;; In order to fast-forward 5 seconds, set the file pointer + ;; to CUR_SEEK + 5 * Freq + + mov cl, 'F' + ;jmp short Player_ProcessKey_B_or_F + +Player_ProcessKey_B_or_F: + ; 17/11/2024 + ; 04/11/2024 + ; (Ref: player.asm, Matan Alfasi, 2017) + + ; 04/11/2024 + mov ax, 5 + mov bx, [WAVE_BlockAlign] + mul bx + mov bx, [WAVE_SampleRate] + mul bx + ; dx:ax = transfer byte count for 5 seconds + + ; 17/11/2024 + cmp cl, 'B' + mov bx, [LoadedDataBytes] + mov cx, [LoadedDataBytes+2] + jne short move_forward ; cl = 'F' +move_backward: + sub bx, ax + sbb cx, dx + jnc short move_file_pointer +move_to_beginning: + xor cx, cx ; 0 + xor bx, bx ; 0 + jmp short move_file_pointer +move_forward: + add bx, ax + adc cx, dx + jc short move_to_end + cmp cx, [DATA_SubchunkSize+2] + ja short move_to_end + jb short move_file_pointer + cmp bx, [DATA_SubchunkSize] + jna short move_file_pointer +move_to_end: + mov bx, [DATA_SubchunkSize] + mov cx, [DATA_SubchunkSize+2] +move_file_pointer: + mov dx, bx + mov [LoadedDataBytes], dx + mov [LoadedDataBytes+2], cx + add dx, 44 ; + header + adc cx, 0 + + ; seek + mov bx, [filehandle] + mov ax, 4200h + int 21h + + retn + +; -------------------------------------------------------- + + ; 23/11/2024 + ; 19/11/2024 +clear_window: + xor ax, ax + jmp short clear_window_@ + +reset_wave_leds: + ; 23/11/2024 + ;mov al, 254 + ;mov ah, 8 ; gray (dark) + mov ax, 08FEh +clear_window_@: + push es + mov di, 0B800h + mov es, di + mov di, 2080 ; 13*80*2 + mov cx, 8*80 ; 8 rows + rep stosw + pop es + retn + +; -------------------------------------------------------- + + ; 09/12/2024 + ; 19/11/2024 +UpdateWaveLeds: + ; 23/11/2024 + call reset_wave_leds + ; 09/12/2024 + ;jmp short turn_on_leds + +; -------------------------------------------------------- + + ; 09/12/2024 +turn_on_leds: + ; 19/11/2024 +;turn_on_leds_stereo_16bit: + push es + push ds + + cmp byte [tLO],'2' + jne short tol_buffer_1 + +tol_buffer_2: + ; 21/11/2024 + mov si, [WAV_BUFFER2] + jmp short tol_@ + +tol_buffer_1: + cmp byte [tLO],'1' + ;jne short tol_retn + ; 23/11/2024 + jne short tol_clc_retn + + mov si, [WAV_BUFFER1] +tol_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + mov cx, [buffersize] ; word + shl cx, 1 ; byte + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol_o_@ + cmp si, cx + jna short tol_s_buf +tol_o_@: + mov si, cx + jmp short tol_s_buf + +tol_clc_retn: + ; 23/11/2024 + clc +tol_retn: + pop ds + pop es + retn + +tol_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol_s_buf: + mov [pbuf_o], si + +tol_buf_@: + ; 21/11/2024 + mov ds, [pbuf_s] + mov di, 0B800h + mov es, di + ;mov di, (20*80*2)-2 + + ; 23/11/2024 + mov cx, 80 + + ; 22/11/2024 + mov bx, wleds_addr + +tol_fill_c: + ; 22/11/2024 + ;inc di + ;inc di + ;push di + lodsw ; left + ;shr ax, 8 + mov dx, ax + lodsw ; right + ;shr ax, 8 + ;;; + ; 23/11/2024 + add ax, dx + ; 09/12/2024 + ;shr ax, 8 + ;;shr ax, 9 + ;add al, 80h + ;shr ax, 5 + add ah, 80h + shr ax, 13 + ;;; + ;;shr ax, 6 + + push bx + shl ax, 1 + add bx, ax + mov di, [cs:bx] + ; 23/11/2024 + mov ah, [cs:ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol_fill_c + + jmp short tol_retn + +; -------------------------------------------------------- + +; 30/05/2024 +print_msg: + mov bx, 07h +p_msg: + push es + push bp + push cx + push dx + + push ds + pop es + mov bp, si + mov ah, 03h ; Return cursor position (in DX) + ; bh = video page number + int 10h + xor cx, cx +p_msg_0: + lodsb + or al, al + jz short p_msg_1 + inc cx + jmp short p_msg_0 +p_msg_1: + or cx, cx + jz short p_msg_x + ; cx = number of chars + ; dx = screen (cursor) position + ; bl = color/attribute + ; bh = video page number + ; es:bp = string buffer + ;mov al, 1 ; attribute in BL, update cursor pos + ;mov ah, 13h ; write character string + mov ax, 1301h + int 10h +p_msg_x: + pop dx + pop cx + pop bp + pop es + retn + +; -------------------------------------------------------- +; -------------------------------------------------------- + +; DATA + +; 30/05/2024 +;reset: db 0 + +Credits: + db 'Tiny WAV Player for Retro DOS by Erdogan Tan. ' + db 'December 2024.',10,13,0 + db '18/12/2024', 10,13 +; 15/11/2024 +reset: + db 0 + +msgAudioCardInfo: + db 'for Intel AC97 (ICH) Audio Controller.', 10,13,0 + +msg_usage: + db 'usage: playwav8 filename.wav',10,13,0 ; 14/11/2024 + +noDevMsg: + db 'Error: Unable to find AC97 audio device!' + db 10,13,0 + +noFileErrMsg: + db 'Error: file not found.',10,13,0 + +msg_error: ; 30/05/2024 + +; 29/05/2024 +; 11/11/2023 +msg_init_err: + db CR, LF + db "AC97 Controller/Codec initialization error !" + db CR, LF, 0 ; 07/12/2024 + +; 25/11/2023 +msg_no_vra: + db 10,13 + db "No VRA support ! Only 48 kHZ sample rate supported !" + db 10,13,0 + +; 13/11/2024 +; ('<<' to 'shl' conversion for FASM) +; +; 29/05/2024 (TRDOS 386) +; 17/02/2017 +; Valid ICH device IDs + +valid_ids: +;dd (ICH_DID << 16) + INTEL_VID ; 8086h:2415h +dd (ICH_DID shl 16) + INTEL_VID ; 8086h:2415h +dd (ICH0_DID shl 16) + INTEL_VID ; 8086h:2425h +dd (ICH2_DID shl 16) + INTEL_VID ; 8086h:2445h +dd (ICH3_DID shl 16) + INTEL_VID ; 8086h:2485h +dd (ICH4_DID shl 16) + INTEL_VID ; 8086h:24C5h +dd (ICH5_DID shl 16) + INTEL_VID ; 8086h:24D5h +dd (ICH6_DID shl 16) + INTEL_VID ; 8086h:266Eh +dd (ESB6300_DID shl 16) + INTEL_VID ; 8086h:25A6h +dd (ESB631X_DID shl 16) + INTEL_VID ; 8086h:2698h +dd (ICH7_DID shl 16) + INTEL_VID ; 8086h:27DEh +; 03/11/2023 - Erdogan Tan +dd (MX82440_DID shl 16) + INTEL_VID ; 8086h:7195h +dd (SI7012_DID shl 16) + SIS_VID ; 1039h:7012h +dd (NFORCE_DID shl 16) + NVIDIA_VID ; 10DEh:01B1h +dd (NFORCE2_DID shl 16) + NVIDIA_VID ; 10DEh:006Ah +dd (AMD8111_DID shl 16) + AMD_VID ; 1022h:746Dh +dd (AMD768_DID shl 16) + AMD_VID ; 1022h:7445h +dd (CK804_DID shl 16) + NVIDIA_VID ; 10DEh:0059h +dd (MCP04_DID shl 16) + NVIDIA_VID ; 10DEh:003Ah +dd (CK8_DID shl 16) + NVIDIA_VID ; 1022h:008Ah +dd (NFORCE3_DID shl 16) + NVIDIA_VID ; 10DEh:00DAh +dd (CK8S_DID shl 16) + NVIDIA_VID ; 10DEh:00EAh + +;valid_id_count equ ($ - valid_ids)>>2 ; 05/11/2023 +; 13/11/2024 +valid_id_count = ($ - valid_ids) shr 2 ; 05/11/2023 + +; 19/11/2024 +; 03/06/2017 +hex_chars db "0123456789ABCDEF", 0 +msgAC97Info db 0Dh, 0Ah + db " AC97 Audio Controller & Codec Info", 0Dh, 0Ah + db " Vendor ID: " +msgVendorId db "0000h Device ID: " +msgDevId db "0000h", 0Dh, 0Ah + db " Bus: " +msgBusNo db "00h Device: " +msgDevNo db "00h Function: " +msgFncNo db "00h" + db 0Dh, 0Ah + db " NAMBAR: " +msgNamBar db "0000h " + db "NABMBAR: " +msgNabmBar db "0000h IRQ: " +msgIRQ dw 3030h + db 0Dh, 0Ah, 0 +; 25/11/2023 +msgVRAheader db " VRA support: " + db 0 +msgVRAyes db "YES", 0Dh, 0Ah, 0 +msgVRAno db "NO ", 0Dh, 0Ah + db " (Interpolated sample rate playing method)" + db 0Dh, 0Ah, 0 + +; -------------------------------------------------------- +; 14/11/2024 (Ref: player.asm, Matan Alfasi, 2017) + +; 23/11/2024 (overwrite splashscreen, a method to solve 64KB limit problem) +; wave volume leds address array +wleds_addr: ; 80*16 bytes + +SplashScreen: + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " _______ ______ _______. ", 221, 219, 222 + db 221, 219, 222, " | \ / __ \ / | ", 221, 219, 222 + db 221, 219, 222, " | .--. | | | | | (----` ", 221, 219, 222 + db 221, 219, 222, " | | | | | | | \ \ ", 221, 219, 222 + db 221, 219, 222, " | '--' | `--' | .----) | ", 221, 219, 222 + db 221, 219, 222, " |_______/ \______/ |_______/ ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " .______ __ ___ ____ ____ _______ .______ ", 221, 219, 222 + db 221, 219, 222, " | _ \ | | / \ \ \ / / | ____|| _ \ ", 221, 219, 222 + db 221, 219, 222, " | |_) | | | / ^ \ \ \/ / | |__ | |_) | ", 221, 219, 222 + db 221, 219, 222, " | ___/ | | / /_\ \ \_ _/ | __| | / ", 221, 219, 222 + db 221, 219, 222, " | | | `----./ _____ \ | | | |____ | |\ \----. ", 221, 219, 222 + db 221, 219, 222, " | _| |_______/__/ \__\ |__| |_______|| _| `._____| ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " WELCOME TO ", 221, 219, 222 + db 221, 219, 222, " DOS PLAYER ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db " " +Template: + db 201, 78 dup(205), 187 + db 186, 33 dup(219), " DOS Player ", 33 dup(219), 186 + db 204, 78 dup(205), 185 + db 186, 33 dup(32), " User Guide ", 33 dup(32), 186 + db 186, 6 dup(32), " Play/Pause ", 4 dup(32), " Hardware Info", 9 dup(32), 186 + db 186, 6 dup(32), " Stop ", 4 dup(32), " Wave Lighting", 9 dup(32), 186 + db 186, 6 dup(32), " Forwards ", 4 dup(32), "<+>/<-> Inc/Dec Volume", 8 dup(32), 186 + db 186, 6 dup(32), " Backwards ", 4 dup(32), " Quit Program ", 9 dup(32), 186 + db 204, 78 dup(205), 185 + db 186, 6 dup(32), "File Name : ", 4 dup(32), "Bit-Rate : 0 Bits ", 9 dup(32), 186 + db 186, 6 dup(32), "Frequency : 0 Hz ", 4 dup(32), "#-Channels: 0 ", 9 dup(32), 186 + db 200, 78 dup(205), 188 + db 80 dup(32) +improper_samplerate_txt: ; 03/11/2024 +read_error_txt: + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(205) + db 80 dup(32) + db 33 dup(32), "00:00 ", 174, 175, " 00:00", 24 dup(32), "VOL 000%" + +; 23/11/2024 +colors: db 0Fh, 0Bh, 0Ah, 0Ch, 0Eh, 09h, 0Dh, 0Fh + ; white, cyan, green, red, yellow, blue, magenta +ccolor: db 0Bh ; cyan + +EOF: + +; BSS + +align 2 + +; 22/11/2024 +; wave volume leds address array +;wleds_addr: rw 80*8 ; rb 2*80*8 + +; 14/11/2024 +; 17/02/2017 +bss_start: + +; 13/11/2024 +; ('resb','resw','resd' to 'rb','rw','rd' conversions for FASM) + +; 18/11/2024 +stopped: rb 1 +tLO: rb 1 +; 21/11/2024 +tLP: rb 1 +; 19/11/2024 +wleds: rb 1 +wleds_dif: rw 1 +pbuf_s: rw 1 +pbuf_o: rw 1 + +; 30/05/2024 +VRA: rb 1 ; Variable Rate Audio Support Status + rb 1 + +;;;;;;;;;;;;;; +; 14/11/2024 +; (Ref: player.asm, Matan Alfasi, 2017) +WAVFILEHEADERbuff: +RIFF_ChunkID: rd 1 ; Must be equal to "RIFF" - big-endian + ; 0x52494646 +RIFF_ChunkSize: + rd 1 ; Represents total file size, not + ; including the first 2 fields + ; (Total_File_Size - 8), little-endian +RIFF_Format: + rd 1 ; Must be equal to "WAVE" - big-endian + ; 0x57415645 + +;; WAVE header parameters ("Sub-chunk") +WAVE_SubchunkID: + rd 1 ; Must be equal to "fmt " - big-endian + ; 0x666d7420 +WAVE_SubchunkSize: + rd 1 ; Represents total chunk size +WAVE_AudioFormat: + rw 1 ; PCM (Raw) - is 1, other - is a form + ; of compression, not supported. +WAVE_NumChannels: + rw 1 ; Number of channels, Mono-1, Stereo-2 +WAVE_SampleRate: + rd 1 ; Frequency rate, in Hz (8000, 44100 ...) +WAVE_ByteRate: rd 1 ; SampleRate * NumChannels * BytesPerSample +WAVE_BlockAlign: + rw 1 ; NumChannels * BytesPerSample + ; Number of bytes for one sample. +WAVE_BitsPerSample: + rw 1 ; 8 = 8 bits, 16 = 16 bits, etc. + +;; DATA header parameters +DATA_SubchunkID: + rd 1 ; Must be equal to "data" - big-endian + ; 0x64617461 +DATA_SubchunkSize: + rd 1 ; NumSamples * NumChannels * BytesPerSample + ; Number of bytes in the data. +;;;;;;;;;;;;;; + +; 15/11/2024 +cursortype: rw 1 + +filehandle: rw 1 + +flags: rb 1 +; 06/11/2023 +ac97_int_ln_reg: rb 1 + +; 30/05/2024 +wav_file_name: + rb 80 ; wave file, path name (<= 80 bytes) + + rw 1 + +; 12/11/2016 - Erdogan Tan + +bus_dev_fn: rd 1 +dev_vendor: rd 1 + +; 17/02/2017 +; NAMBAR: Native Audio Mixer Base Address Register +; (ICH, Audio D31:F5, PCI Config Space) Address offset: 10h-13h +; NABMBAR: Native Audio Bus Mastering Base Address register +; (ICH, Audio D31:F5, PCI Config Space) Address offset: 14h-17h +NAMBAR: rw 1 ; BAR for mixer +NABMBAR: rw 1 ; BAR for bus master regs + +; 256 byte buffer for descriptor list +BDL_BUFFER: rw 1 ; segment of our 256byte BDL buffer +WAV_BUFFER1: rw 1 ; segment of our WAV storage +; 64k buffers for wav file storage +WAV_BUFFER2: rw 1 ; segment of 2nd wav buffer + +; 09/12/2024 +; 23/11/2024 +;turn_on_leds: rd 1 ; turn_on_leds procedure pointer (m8,m16,s8,s16) + +; 15/11/2024 +; 06/11/2023 +;sample_rate: rw 1 ; HZ (carrier frequency) +; 15/11/2024 +; 19/11/2016 +;stmo: rw 1 ; channels +;btps: rw 1 ; bits per ONE sample +; 14/11/2024 +;byps: rw 1 ; bytes per sample (channels * sample length) + ; sample length = 2 for 16 bit samples + ; = 1 for 8 bit samples + ; channels = 2 for stereo + ; = 1 for mono +; 08/11/2023 +; 07/11/2023 +fbs_shift: rb 1 + rb 1 ; 08/11/2023 + +; 15/11/2024 +loadfromwavfile: + rw 1 ; 'loadfromfile' or load+conversion proc address +loadsize: rw 1 ; (.wav file) read count (bytes) per one time +buffersize: rd 1 ; 16 bit samples (not bytes) + +; 14/11/2024 +TotalTime: rw 1 ; Total (WAV File) Playing Time in seconds +ProgressTime: rw 1 +count: rw 1 ; byte count of one (wav file) read +LoadedDataBytes: + rd 1 ; total read/load count + +timerticks: rd 1 ; (to eliminate excessive lookup of events in tuneloop) + ; (in order to get the emulator/qemu to run correctly) +; 14/11/2024 +bss_end: + +;alignb 2 + +; 32 kilo bytes for temporay buffer +; (for stereo-mono, 8bit/16bit corrections) +; 14/11/2024 +;temp_buffer: rb 32768 +; 17/11/2024 +temp_buffer: rb 50600 ; (44.1 kHZ stereo 12650 samples) +; 18/11/2023 +;temp_buffer: rb 56304 ; (44.1 kHZ stereo 14076 samples) + +;alignb 16 +;bss_end: \ No newline at end of file diff --git a/trdos386/programs/16bit/playwav8_com_2024.zip b/trdos386/programs/16bit/playwav8_com_2024.zip new file mode 100644 index 0000000000000000000000000000000000000000..b36c8588cf272048e0e05615b4544e564c0c558c GIT binary patch literal 35031 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 JYm$H5{sO+Xq3Hks literal 0 HcmV?d00001 diff --git a/trdos386/programs/16bit/playwav9.asm b/trdos386/programs/16bit/playwav9.asm new file mode 100644 index 0000000..5e577c0 --- /dev/null +++ b/trdos386/programs/16bit/playwav9.asm @@ -0,0 +1,2626 @@ +; **************************************************************************** +; playwav9.asm (for Retro DOS) +; ---------------------------------------------------------------------------- +; PLAYWAV9.COM ! Sound Blaster 16 (DOS) .WAV PLAYER program by Erdogan TAN +; +; 24/11/2024 +; +; [ Last Modification: 18/12/2024 ] +; +; Modified from PLAYWAV8.COM .wav player program by Erdogan Tan, 23/11/2024 +; +; Assembler: FASM 1.73 +; fasm playwav9.asm PLAYWAV9.COM +; ---------------------------------------------------------------------------- +; In the visualization part of the code, the source code of Matan Alfasi's +; (Ami-Asaf) player.exe program was partially used. +; ---------------------------------------------------------------------------- +; Previous versions of this Wav Player were based in part on .wav file player +; (for DOS) source code written by Jeff Leyla in 2002. + +; playwav8.asm (23/11/2024) + +; INTERRUPT (SRB) + TUNELOOP version ; 24/11/2024 +; (running in DOSBOX, VIRTUALBOX, QEMU is ok) +; Signal Response Byte = message/signal to user about an event/interrupt +; as requested (TuneLoop procedure continuously checks this SRB) +; (TRDOS 386 v2 feature is used here as very simple interrupt handler output) + +; CODE + + ; 13/11/2024 +macro sys_msg op1,op2 +{ ; 30/05/2024 + mov si, op1 ; message + mov bl, op2 ; text color + xor bh, bh ; video page 0 + mov ah, 0Eh + call p_msg +} + + ; 24/11/2024 +macro SbOut op1 +{ +local .wait +.wait: + in al, dx + or al, al + js short .wait + mov al, op1 ; command + out dx, al +} + +; player internal variables and other equates. +; 17/11/2024 +;BUFFERSIZE equ 65520 +; 24/11/2024 +;dma_buffer_size equ 32768 +;LOADSIZE equ 16384 +ENDOFFILE equ 1 ; flag for knowing end of file +; 27/11/2024 +dma_buffer_size equ 44100 +LOADSIZE equ 22050 + +use16 + +org 100h + +_STARTUP: + ; 30/05/2024 + ; Prints the Credits Text. + sys_msg Credits, 0Bh + + ; 30/05/2024 + call setFree ; deallocate unused DOS mem + + ; 17/02/2017 + ; Clear BSS (uninitialized data) area + xor ax, ax ; 0 + mov cx, (bss_end - bss_start)/2 + mov di, bss_start + rep stosw + + ; 24/11/2024 + ; Detect (& Reset) Sound Blaster 16 Audio Device + call DetectSB16 + jnc short GetFileName + + ; 30/05/2024 +_dev_not_ready: + ; couldn't find the audio device! + sys_msg noDevMsg, 0Fh + jmp Exit + + ; 30/05/2024 +GetFileName: + mov di, wav_file_name + mov si, 80h + mov bl, [si] + xor bh, bh + inc bx + mov byte [si+bx], 0 ; make AsciiZ filename. + inc si +ScanName: + lodsb + test al, al + jz pmsg_usage + cmp al, 20h + je short ScanName ; scan start of name. + stosb + mov ah, 0FFh + ;;; + ; 14/11/2024 + ; (max. path length = 64 bytes for MSDOS ?) (*) + xor cx, cx ; 0 + ;;; +a_0: + inc ah +a_1: + ;;; + ; 14/11/2024 + inc cx + ;;; + lodsb + stosb + cmp al, '.' + je short a_0 + and al, al + ;jnz short a_1 + ;;; + ; 14/11/2024 + jz short a_3 + and ah, ah + jz short a_2 + cmp al, '\' + jne short a_2 + mov ah, 0 +a_2: + cmp cl, 75 ; 64+8+'.'+3 -> offset 75 is the last chr + jb short a_1 +a_3: + ;;; + or ah, ah ; if period NOT found, + jnz short _1 ; then add a .WAV extension. +SetExt: + dec di + mov dword [di], '.WAV' ; ! 64+12 is DOS limit + ; but writing +4 must not + ; destroy the following data + mov byte [di+4], 0 ; so, 80 bytes path + 0 is possible here +_1: + call write_audio_dev_info + +; open the file + ; open existing file + ; 14/11/2024 + ;mov al, OPEN ; open existing file + mov dx, wav_file_name + call openFile ; no error? ok. + jnc short getwavparms ; 14/11/2024 + +; file not found! + sys_msg noFileErrMsg, 0Ch +_exit_: + jmp Exit + +getwavparms: + ; 14/11/2024 + call getWAVParameters + jc short _exit_ ; nothing to do + + ; 15/11/2024 + ;; Set video mode to 03h (not necessary) + mov ax, 03h + int 10h + + ; 15/11/2024 + ;; Get the cursor type + mov ah, 03h + int 10h + mov [cursortype], cx ; save + + ; 15/11/2024 + ;; Set the cursor to invisible + mov ah, 01h + mov cx, 2607h + int 10h + + ;;; 14/11/2024 +Player_SplashScreen: + ; 15/11/2024 + ;xor dx, dx + ;call setCursorPosition + + ;; Print the splash screen in white + mov ax, 1300h + mov bx, 000Fh + mov cx, 1999 + mov dx, 0 + + mov bp, SplashScreen + int 10h + ;;; + + ;;; + ; 22/11/2024 + ; set wave volume led addresses + mov bx, 13*80*2 + mov bp, 80 + mov di, wleds_addr +wleds_sa_1: + mov cx, 7 +wleds_sa_2: + mov ax, 80*2 + mul cx + add ax, bx + stosw + loop wleds_sa_2 + mov ax, bx + stosw + inc bx + inc bx + dec bp + jnz short wleds_sa_1 + ;;; + + ;;; + ; 23/11/2024 + cmp byte [WAVE_NumChannels], 1 + ja short stolp_s +stolp_m: + cmp byte [WAVE_BitsPerSample], 8 + ja short stolp_m16 +stolp_m8: + mov word [turn_on_leds], turn_on_leds_mono_8bit + jmp short stolp_ok +stolp_m16: + mov word [turn_on_leds], turn_on_leds_mono_16bit + jmp short stolp_ok +stolp_s: + cmp byte [WAVE_BitsPerSample], 8 + ja short stolp_s16 +stolp_s8: + mov word [turn_on_leds], turn_on_leds_stereo_8bit + jmp short stolp_ok +stolp_s16: + mov word [turn_on_leds], turn_on_leds_stereo_16bit + jmp short stolp_ok +stolp_ok: + ;;; + + ;;; wait for 3 seconds + ;mov cx, 002Dh + ;mov dx, 0C6C0h + ;mov ah, 86h + ;int 15h + ;;; + ; 26/11/2024 + ;mov cx, 3*18 + ; 27/11/2024 + mov cx, 2*18 +getticks: + ; 26/11/2024 + call GetTimerTicks + + cmp ax, [timerticks] + jne short chkws + cmp dx, [timerticks+2] + je short getticks +chkws: + mov [timerticks], ax + mov [timerticks+2], dx + loop getticks + ;;; + + ;;; +Player_Template: + xor dx, dx + call setCursorPosition + + ;; Print the splash screen in white + mov ax, 1300h + mov bx, 000Fh + mov cx, 1999 + mov dx, 0 + + mov bp, Template + int 10h + ;;; + + ; 14/11/2024 + call SetTotalTime + call UpdateFileInfo + +PlayNow: + ; 24/11/2024 + mov al, 5 ; 15 = max, 0 = min + ; 27/11/2024 + mov [volume], al + ; 15/11/2024 + call SetMasterVolume + call UpdateVolume + ;;; + + ;;; + ; + ; 14/11/2024 + call UpdateProgressBar + ;;; + + ; 30/05/2024 + ; playwav4.asm +_2: + call check4keyboardstop ; flush keyboard buffer + jc short _2 ; 07/11/2023 + +; play the .wav file. Most of the good stuff is in here. + + call PlayWav + +Exit@@: + ; 27/11/2024 + ; 24/11/2024 + ; restore old interrupt vector + mov al, [IRQnum] + xor ah, ah ; reset + call set_hardware_int_vector + +; close the .wav file and exit. + +Exit: + ; 15/11/2024 + ;; Restore Cursor Type + mov cx, [cursortype] + cmp cx, 0 + jz short Exit@ + mov ah, 01h + int 10h +Exit@: + call closeFile + + mov ax, 4C00h ; bye ! + int 21h +here: + jmp short here ; do not come here ! + + ; 30/05/2024 +pmsg_usage: + sys_msg msg_usage, 0Fh ; 14/11/2024 + jmp short Exit + + ; 30/05/2024 +init_err: + sys_msg msg_init_err, 0Fh + jmp short Exit + + ; -------------------------------------------- + + ; 24/11/2024 +PlayWav: + mov ax, wav_buffer1 + call loadFromFile + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + mov ax, wav_buffer2 + call loadFromFile + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + ; 25/11/2024 + call SB16Init_play ; initialize SB16 card + ; set sample rate, start to play + jc init_err + + ; 19/11/2024 + mov byte [wleds], 1 + + mov ax, [WAVE_SampleRate] + mov cx, 10 + mul cx + mov cl, 182 + div cx + ; ax = samples per 1/18.2 second + mov cl, byte [WAVE_BlockAlign] + mul cx + mov [wleds_dif], ax ; buffer read differential (distance) + ; for wave volume leds update + ; (byte stream per 1/18.2 second) + ; 27/11/2024 + ; set audio interrupt vector (to user's handler) + mov al, [IRQnum] + mov ah, 1 ; set + mov dx, IRQ_service + call set_hardware_int_vector + + ; 26/11/2024 + call check4keyboardstop + jc _exitt_ + + ; 27/11/2024 + mov byte [IRQnum], 0 + + ; 27/11/2024 + ; 24/11/2024 +TuneLoop: + ; 30/05/2024 + ; 18/11/2023 (ich_wav4.asm) + ; 08/11/2023 + ; 06/11/2023 +tLWait: + ; 18/11/2024 + cmp byte [stopped], 0 + ; 24/11/2024 + jna short tL1 +tLWait@: ; 21/11/2024 + call checkUpdateEvents + jc _exitt_ + cmp byte [tLO], '0' + je short tLWait + call tLZ + mov byte [tLO], '0' + jmp short tLWait +tL1: + ; 27/11/2024 + ; Check SB 16 interrupt status + cmp byte [IRQnum], 0 + ja short tL3 +tL2: + call checkUpdateEvents + jc _exitt_ + jmp short tLWait +tL3: + xor byte [half_buffer], 1 + + mov byte [IRQnum], 0 + + ; load buffer 1 + ;mov ax, wav_buffer1 + mov ax, dma_buffer ; wav_buffer1 + cmp byte [half_buffer], 0 + jna short tL4 + + ; load buffer 2 + ;mov ax, wav_buffer2 + add ax, LOADSIZE ; dma_buffer_size/2 +tL4: + call loadFromFile + jc short _exitt_ ; end of file + + ; 26/11/2024 + mov al, [half_buffer] + add al, '1' + ; 19/11/2024 + mov [tLO], al + call tL0 + ; 24/11/2024 + ; 14/11/2024 + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + ; 27/11/2024 + jmp short tL2 + +_exitt_: + ; 24/11/2024 + call sb16_stop + + ;;; + ; 14/11/2024 + call UpdateProgressBar + ;;; + + ; 18/11/2024 +tLZ: + ; 30/05/2024 + mov al, '0' + + ; 06/11/2023 +tL0: + ; 08/11/2023 + ; 05/11/2023 + ; 17/02/2017 - Buffer switch test (temporary) + ; 06/11/2023 + ; al = buffer indicator ('1', '2' or '0' -stop- ) + + push ds + ;push bx + mov bx, 0B800h ; video display page segment + mov ds, bx + sub bx, bx ; 0 + mov ah, 4Eh + mov [bx], ax ; show current play buffer (1, 2) + ;pop bx + pop ds + + retn + +; ------------------------------------------- + +; 27/11/2024 +; ; 24/11/2024 +;IRQ_ack: +; ; 26/11/2024 +; push dx +; push ax +; mov dx, [audio_io_base] +; ;add dx, 0Eh +; add dl, 0Eh ; 8bit DMA-mode int ack +; ; 25/11/2024 +; cmp byte [WAVE_BitsPerSample], 8 +; jna short irq_ack_@ +; inc dl ; 0Fh ; 16bit DMA-mode int ack +;irq_ack_@: +; in al, dx ; SB acknowledge. +; ; 27/11/2024 +; ;mov al, 20h +; ;out 20h, al ; Hardware acknowledge. +;irq_ack_ok: +; ; 26/11/2024 +; pop ax +; pop dx +; retn + +; ------------------------------------------- + + ; 24/11/2024 +SetMasterVolume: + ; al = sound volume (15 = max, 0 = min) + push ax + ; Tell the SB 16 card which register to write + mov dx, [audio_io_base] + ;add dx, 4 ; Mixer chip address port + add dl, 4 + mov al, 22h + out dx, al + pop ax + ;and al, 0Fh + ; Set the volume for both L and R + mov bl, 11h + mul bl + ; Set new volume + mov dx, [audio_io_base] + ;add dx, 5 + add dl, 5 + out dx, al + retn + +; ------------------------------------------- + + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9 audio.s (06/06/2024) + ; DetectSB procedure (06/08/2022, v2.0.5) +DetectSB16: + ; 06/08/2022 - TRDOS 386 v2.0.5 + ; 24/04/2017 +ScanPort: + mov bx, 0210h ; start scanning ports + ; 210h, 220h, .. 260h +ResetDSP: + ; 26/11/2024 + mov dx, bx ; try to reset the DSP. + add dl, 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 + add dl, 08h + mov cx, 100 +WaitID: + in al, dx + or al, al + js short GetID + loop WaitID + jmp short NextPort +GetID: + ;sub dx, 04h + sub dl, 04h + in al, dx + cmp al, 0AAh + je short Found + ;add dx, 04h + add dl, 04h + loop WaitID +NextPort: + ;add bx, 10h ; if not response, + add bl, 10h + ;cmp bx, 260h ; try the next port. + cmp bl, 60h + jbe short ResetDSP + stc + retn +Found: + mov [audio_io_base], bx ; SB Port Address Found! +ScanIRQ: +SetIrqs: + sub al, al ; 0 + mov [IRQnum], al ; reset + ; 27/11/2024 + ;mov [audio_intr], al + + ; 25/11/2024 + ; save IRQ status + in al, 21h ; save the IMR. + mov [IRQstatus], al + + ; ah > 0 -> set IRQ vector + ; al = IRQ number + mov ax, 105h ; IRQ 5 + ; 26/11/2024 + mov dx, IRQ5_service + call set_hardware_int_vector + mov ax, 107h ; IRQ 7 + ; 26/11/2024 + mov dx, IRQ7_service + call set_hardware_int_vector + + mov dx, [audio_io_base] ; tells to the SB to + ;add dx, 0Ch ; generate a IRQ! + add dl, 0Ch +WaitSb: + in al, dx + or al, al + js short WaitSb + mov al, 0F2h + out dx, al + ; 24/11/2024 + xor cx, cx ; wait until IRQ level +WaitIRQ: + mov al, [IRQnum] + cmp al, 0 ; is changed or timeout. + ja short IrqOk + dec cx + jnz short WaitIRQ + jmp short RestoreIrqs +IrqOk: + ;;; + ; 27/11/2024 + mov [audio_intr], al + mov dx, [audio_io_base] + ;add dx, 0Eh + add dl, 0Eh ; 8bit DMA-mode int ack + in al, dx ; SB acknowledge. + inc dx ; 0Fh ; 16bit DMA-mode int ack + in al, dx ; SB 16 acknowledge. + ;;; + mov al, 20h + out 20h, al ; Hardware acknowledge. +RestoreIrqs: + ; ah = 0 -> reset IRQ vector + ; al = IRQ number + mov ax, 5 ; IRQ 5 + call set_hardware_int_vector + mov ax, 7 ; IRQ 7 + call set_hardware_int_vector + + cmp byte [IRQnum], 1 ; IRQ level was changed? + + retn + +; ---------------------------------- + + ; 24/11/2024 +set_hardware_int_vector: + or ah, ah + jnz short shintv_1 ; set user's audio interrupt handler + +rhintv_1: + ; reset the interrupt vector to the old interrupt handler + push ds + cmp al, 5 + jne short rhintv_2 + + ; 25/11/2024 + ; restore IRQ 5 status + mov ah, [IRQstatus] + in al, 21h + and ah, 00100000b ; 20h + or al, ah + out 21h, al + + mov dx, [old_irq5v_o] + mov ds, [old_irq5v_s] +shintv_3: + mov al, 0Dh + mov ah, 25h + int 21h + pop ds + retn + +rhintv_2: + ; 25/11/2024 + ; restore IRQ 7 status + mov ah, [IRQstatus] + in al, 21h + and ah, 10000000b ; 80h + or al, ah + out 21h, al + + mov dx, [old_irq7v_o] + mov ds, [old_irq7v_s] +shintv_4: + mov al, 0Fh + mov ah, 25h + int 21h + pop ds + retn + +shintv_1: + push es + + cmp al, 5 + jne short shintv_2 + + ; INT 0Dh = IRQ 5 (default) interrupt number + + ; 25/11/2024 + ; enable IRQ 5 + ; 26/11/2024 + in al, 21h + and al, 11011111b + out 21h, al + + mov al, 0Fh + mov ah, 35h ; Get Interrupt Vector + int 21h + mov [old_irq5v_s], es + mov [old_irq5v_o], bx + pop es + push ds + ; 27/11/2024 + ;mov dx, IRQ5_service + jmp short shintv_3 + +shintv_2: + ; al = 7 + ; INT 0Fh = IRQ 7 (default) interrupt number + + ; 25/11/2024 + ; enable IRQ 7 + ; 26/11/2024 + in al, 21h + and al, 01111111b + out 21h, al + + mov al, 0Fh + mov ah, 35h ; Get Interrupt Vector + int 21h + mov [old_irq7v_s], es + mov [old_irq7v_o], bx + pop es + push ds + ; 27/11/2024 + ;mov dx, IRQ7_service + jmp short shintv_4 + +IRQ5_service: + mov byte [cs:IRQnum], 5 + iret + +IRQ7_service: + mov byte [cs:IRQnum], 7 + iret + + ; 27/11/2024 +IRQ_service: + push ds + push dx + push ax + ; + push cs + pop ds + mov byte [IRQnum], 5 + mov dx, [audio_io_base] + ;add dx, 0Eh + add dl, 0Eh ; 8bit DMA-mode int ack + cmp byte [WAVE_BitsPerSample], 8 + jna short irq_ack_@ + inc dl ; 0Fh ; 16bit DMA-mode int ack +irq_ack_@: + in al, dx ; SB acknowledge. + ; + mov al, 20h + out 20h, al ; Hardware acknowledge + ; + pop ax + pop dx + pop ds + iret + +; ---------------------------------- + + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9 audio.s (06/06/2024) + ; sb16_stop procedure (06/08/2022, v2.0.5) +sb16_stop: + mov dx, [audio_io_base] + ;add dx, 0Ch + add dl, 0Ch + + mov bl, 0D9h ; exit auto-initialize 16 bit transfer + ; stop autoinitialized DMA transfer mode + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb16_stop_1 + ;mov bl, 0DAh ; exit auto-initialize 8 bit transfer + inc bl +sb16_stop_1: + SbOut bl ; exit auto-initialize transfer command + + xor al, al ; stops all DMA processes on selected channel + + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb16_stop_2 + out 0Ch, al ; clear selected channel register + jmp short sb16_stop_3 + +sb16_stop_2: + out 0D8h, al ; clear selected channel register + +sb16_stop_3: + ; 24/11/2024 + mov byte [stopped], 2 ; stop ! +SbDone: + ;mov dx, [audio_io_base] + ;add dx, 0Ch + SbOut 0D0h + SbOut 0D3h +sb16_stop_4: + retn + +; ---------------------------------- + + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9 audio.s (06/06/2024) + ; sb16_pause procedure (06/08/2022, v2.0.5) +sb16_pause: + mov dx, [audio_io_base] + ;add dx, 0Ch ; Command & Data Port + add dl, 0Ch + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb_pause_1 + ; 8 bit samples + mov bl, 0D0h ; 8 bit DMA mode + jmp short sb_pause_2 +sb_pause_1: + ; 16 bit samples + mov bl, 0D5h ; 16 bit DMA mode +sb_pause_2: + SbOut bl ; bCommand +sb_pause_3: + retn + +; ---------------------------------- + + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9 audio.s (06/06/2024) + ; sb16_continue procedure (06/08/2022, v2.0.5) +sb16_play: +sb16_continue: + mov dx, [audio_io_base] + ;add dx, 0Ch ; Command & Data Port + add dl, 0Ch + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb_cont_1 + ; 8 bit samples + mov bl, 0D4h ; 8 bit DMA mode + jmp short sb_cont_2 +sb_cont_1: + ; 16 bit samples + mov bl, 0D6h ; 16 bit DMA mode +sb_cont_2: + SbOut bl ; bCommand +sb_cont_3: + retn + +; ---------------------------------- + + ; 14/11/2024 + ; INPUT: ds:dx = file name address + ; OUTPUT: [filehandle] = ; -1 = not open +openFile: + mov ax, 3D00h ; open File for read + int 21h + jnc short _of1 + mov ax, -1 + ; cf = 1 -> not found or access error +_of1: + mov [filehandle], ax + retn + +; ---------------------------------- + +; close the currently open file + + ; 14/11/2024 + ; INPUT: [filehandle] ; -1 = not open + ; OUTPUT: none +closeFile: + cmp word [filehandle], -1 + jz short _cf1 + mov bx, [filehandle] + mov ax, 3E00h + int 21h ; close file +_cf1: + retn + +; ---------------------------------- + + ; 14/11/2024 - Erdogan Tan +getWAVParameters: +; reads WAV file header(s) (44 bytes) from the .wav file. +; entry: none - assumes file is already open +; exit: ax = sample rate (11025, 22050, 44100, 48000) +; cx = number of channels (mono=1, stereo=2) +; dx = bits per sample (8, 16) +; bx = number of bytes per sample (1 to 4) + + mov dx, WAVFILEHEADERbuff + mov bx, [filehandle] + mov cx, 44 ; 44 bytes + mov ah, 3Fh + int 21h + jc short gwavp_retn + + cmp ax, 44 + jb short gwavp_retn + + cmp dword [RIFF_Format], 'WAVE' + jne short gwavp_stc_retn + + cmp word [WAVE_AudioFormat], 1 ; Offset 20, must be 1 (= PCM) + ;jne short gwavp_stc_retn + je short gwavp_retn ; 15/11/2024 + + ; 15/11/2024 + ;mov cx, [WAVE_NumChannels] ; return num of channels in CX + ;mov ax, [WAVE_SampleRate] ; return sample rate in AX + ;mov dx, [WAVE_BitsPerSample] + ; return bits per sample value in DX + ;mov bx, [WAVE_BlockAlign] ; return bytes per sample in BX +;gwavp_retn: + ;retn + + ; 27/11/2024 + ; frequency limit (for SB16) = 44100 kHz + ;cmp word [WAVE_SampleRate], 44101 ; 48000 + ;cmc + ;retn + +gwavp_stc_retn: + stc +gwavp_retn: + retn + +; ---- 30/05/2024 (playwav4.asm, 19/05/2024) + +; MEMALLOC.ASM +;-- SETFREE: Release memory not used ---------------- +;-- Input : ES = address of PSP +;-- Output : none +;-- Register : AX, BX, CL and FLAGS are changed +;-- Info : Since the stack-segment is always the last segment in an +; EXE-file, ES:0000 points to the beginning and SS:SP +; to the end of the program in memory. Through this the +; length of the program can be calculated +; call this routine once at the beginning of the program to free up memory +; assigned to it by DOS. + +setFree: + mov bx, 65536/16 ; 4K paragraphs ; 17/02/2017 (Erdogan Tan) + + mov ah, 4Ah ; pass new length to DOS + int 21h + + retn ; back to caller + ; new size (allocated memory) = 64KB + + ; 27/11/2024 +;memAlloc: +;; input: AX = # of paragraphs required +;; output: AX = segment of block to use +; +; push bx +; mov bx, ax +; mov ah, 48h +; int 21h +; pop bx +; retn + +; ---- + +; ///// + + ; 24/11/2024 (SB16 version of playwav8.asm -> playwav9.asm) + ; 30/05/2024 (ich_wav4.asm, 19/05/2024) +loadFromFile: + ; 18/12/2024 + mov word [count], 0 + + ; 07/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff_0 ; no + stc + retn + +lff_0: + ; 24/11/2024 + ; 08/11/2023 + mov di, ax ; save buffer address + ; 17/11/2024 + mov bx, [filehandle] + + ; 24/11/2024 + mov cx, LOADSIZE + mov dx, ax ; buffer address + + ; 24/11/2024 + ; load/read file + ; bx = file handle + ; ds = cs + ; ds:dx = buffer + ; cx = read count + mov ah, 3Fh + int 21h + jc short lff_4 ; error ! + + ; 14/11/2024 + mov [count], ax + + cmp ax, cx + je short endLFF + ; 24/11/2024 + ; di = buffer address + add di, ax +lff_3: + call padfill ; blank pad the remainder + ;clc ; don't exit with CY yet. + or byte [flags], ENDOFFILE ; end of file flag +endLFF: + retn +lff_4: + ; 08/11/2023 + mov al, '!' ; error + call tL0 + + xor ax, ax + jmp short lff_3 + +; entry ds:ax points to last byte in file +; cx = target size +; note: must do byte size fill +; destroys bx, cx +; +padfill: + ; 24/11/2024 + ; di = offset (to be filled with ZEROs) + ; es = ds = cs + ; ax = di = number of bytes loaded + ; cx = buffer size (> loaded bytes) + sub cx, ax + xor ax, ax + cmp byte [WAVE_BitsPerSample], 8 + ja short padfill@ + mov al, 80h +padfill@: + rep stosb + retn +; ///// + +write_audio_dev_info: + ; 30/05/2024 + sys_msg msgAudioCardInfo, 0Fh + retn + +write_sb16_dev_info: + ; 24/11/2024 + mov ax, [audio_io_base] + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgBasePort+2], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgBasePort+1], al + mov bl, ah + mov dl, bl + ;and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgBasePort], al + + xor ax, ax + ;mov al, [IRQnum] + ; 27/11/2024 + mov al, [audio_intr] + ;mov cl, 10 + ;div cl + ;add ah, 30h + ;mov [msgIRQ], ah + ; 25/11/2024 + add al, 30h + mov [msgIRQ], al + + call clear_window + mov dh, 13 + mov dl, 0 + call setCursorPosition + + sys_msg msgSB16Info, 07h + + retn + +; -------------------------------------------------------- +; 24/11/2024 - Sound Blaster 16 initialization +; -------------------------------------------------------- + + ; 25/11/2024 + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9, audio.s (06/06/2024) + ; SbInit_play procedure (06/08/2024, v2.0.5) +SB16Init_play: + mov ax, ds + mov dx, ax + shr dx, 12 + shl ax, 4 + add ax, dma_buffer + adc dx, 0 + mov bx, ax ; linear address + ; dx = page number + + mov cx, dma_buffer_size + + cmp byte [WAVE_BitsPerSample], 16 + jne short sbInit_0 ; set 8 bit DMA buffer + + ; 26/11/2024 + mov ax, dx ; page number + + ; convert byte count to word count + ; 26/11/2024 + ;dec cx + shr cx, 1 + dec cx ; word count - 1 + + ; convert byte offset to word offset + shr ax, 1 + rcr bx, 1 + ; 26/11/2024 + ;shr bx, 1 + + ; 16 bit DMA buffer setting (DMA channel 5) + mov al, 05h ; set mask bit for channel 5 (4+1) + out 0D4h, al + + xor al, al ; stops all DMA processes on selected channel + out 0D8h, al ; clear selected channel register + + mov al, bl ; byte 0 of DMA buffer offset in words (physical) + out 0C4h, al ; DMA channel 5 port number + + mov al, bh ; byte 1 of DMA buffer offset in words (physical) + out 0C4h, al + + ; 26/11/2024 + and dl, 0FEh ; clear bit 0 (not necessary, it will be ignored) + + mov al, dl ; byte 2 of DMA buffer address (physical) + out 8Bh, al ; page register port addr for channel 5 + + mov al, cl ; low byte of DMA count - 1 + out 0C6h, al ; count register port addr for channel 5 + + mov al, ch ; high byte of DMA count - 1 + out 0C6h, al + + ; channel 5, read, autoinitialized, single mode + mov al, 59h + out 0D6h, al ; DMA mode register port address + + mov al, 01h ; clear mask bit for channel 5 + out 0D4h, al ; DMA mask register port address + + jmp short ResetDsp + +sbInit_0: + dec cx ; byte count - 1 + + ; 8 bit DMA buffer setting (DMA channel 1) + mov al, 05h ; set mask bit for channel 1 (4+1) + out 0Ah, al ; DMA mask register + + xor al, al ; stops all DMA processes on selected channel + out 0Ch, al ; clear selected channel register + + mov al, bl ; byte 0 of DMA buffer address (physical) + out 02h, al ; DMA channel 1 port number + + mov al, bh ; byte 1 of DMA buffer address (physical) + out 02h, al + + mov al, dl ; byte 2 of DMA buffer address (physical) + out 83h, al ; page register port addr for channel 1 + + mov al, cl ; low byte of DMA count - 1 + out 03h, al ; count register port addr for channel 1 + + mov al, ch ; high byte of DMA count - 1 + out 03h, al + + ; channel 1, read, autoinitialized, single mode + mov al, 59h + out 0Bh, al ; DMA mode register port address + + mov al, 01h ; clear mask bit for channel 1 + out 0Ah, al ; DMA mask register port address + +ResetDsp: + mov dx, [audio_io_base] + ;add dx, 06h + add dl, 06h + mov al, 1 + out dx, al + + in al, dx + in al, dx + in al, dx + in al, dx + + xor ax, ax + out dx, al + + mov cx, 100 +WaitId: + mov dx, [audio_io_base] + add dl, 0Eh + in al, dx + or al, al + ;js short sb_GetId + ; 26/11/2024 + jns short sb_next + ;loop WaitId + ;jmp sb_Exit + +sb_GetId: + mov dx, [audio_io_base] + ;add dx, 0Ah + add dl, 0Ah + in al, dx + cmp al, 0AAh + je short SbOk +sb_next: + loop WaitId + stc + retn +SbOk: + mov dx, [audio_io_base] + ;add dx, 0Ch + add dl, 0Ch + SbOut 0D1h ; Turn on speaker + SbOut 41h ; 8 bit or 16 bit transfer + mov bx, [WAVE_SampleRate] ; sampling rate (Hz) + SbOut bh ; sampling rate high byte + SbOut bl ; sampling rate low byte + + ; 25/11/2024 + +StartDMA: + ; autoinitialized mode + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb_play_1 + ; 8 bit samples + mov bx, 0C6h ; 8 bit output (0C6h) + cmp byte [WAVE_NumChannels], 2 ; 1 = mono, 2 = stereo + jb short sb_play_2 + mov bh, 20h ; 8 bit stereo (20h) + jmp short sb_play_2 +sb_play_1: + ; 16 bit samples + mov bx, 10B6h ; 16 bit output (0B6h) + cmp byte [WAVE_NumChannels], 2 ; 1 = mono, 2 = stereo + jb short sb_play_2 + add bh, 20h ; 16 bit stereo (30h) +sb_play_2: + ; PCM output (8/16 bit mono autoinitialized transfer) + SbOut bl ; bCommand + SbOut bh ; bMode + ; 25/11/2024 + mov bx, dma_buffer_size/2 + ; half buffer size + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit DMA + jne short sb_play_3 + shr bx, 1 ; byte count to word count (samples) +sb_play_3: + dec bx ; wBlkSize is one less than the actual size + SbOut bl + SbOut bh + + ; 24/11/2024 + ;mov byte [stopped], 0 ; playing ! +sb_Exit: + retn + +; -------------------------------------------------------- +; 14/11/2024 - Erdogan Tan +; -------------------------------------------------------- + + ; 24/11/2024 (SB16 version) +checkUpdateEvents: + call check4keyboardstop + jc short c4ue_ok + + ; 18/11/2024 + push ax ; * + or ax, ax + jz c4ue_cpt + + ; 18/11/2024 + cmp al, 20h ; SPACE (spacebar) ; pause/play + jne short ch4ue_chk_s + cmp byte [stopped], 0 + ja short ch4ue_chk_ps + ; pause + call sb16_pause ; 24/11/2024 + ; 27/11/2024 + mov byte [stopped], 1 + jmp c4ue_cpt +ch4ue_chk_ps: + cmp byte [stopped], 1 + ja short ch4ue_replay + ; continue to play (after a pause) + call sb16_play ; 24/11/2024 + ; 27/11/2024 + mov byte [stopped], 0 + jmp short c4ue_cpt +ch4ue_replay: + ; 19/11/2024 + pop ax ; * + pop ax ; return address + ; 24/11/2024 + ; initialize (again) + ; and start playing (after stop) + call SB16Init_play + mov al, [volume] + call SetMasterVolume ; 24/11/2024 + mov byte [stopped], 0 + ; 24/11/2024 + mov byte [half_buffer], 1 + call move_to_beginning + jmp PlayWav + +ch4ue_chk_s: + cmp al, 'S' ; stop + jne short ch4ue_chk_fb + cmp byte [stopped], 0 + ja short c4ue_cpt ; Already stopped/paused + call sb16_stop ; 24/11/2024 + ; 19/11/2024 + mov byte [tLO], 0 + jmp short c4ue_cpt + +ch4ue_chk_fb: + ; 17/11/2024 + cmp al, 'F' + jne short c4ue_chk_b + call Player_ProcessKey_Forwards + jmp short c4ue_cpt + + ; 18/11/2024 +c4ue_ok: + retn + +c4ue_chk_b: + cmp al, 'B' + ; 19/11/2024 + jne short c4ue_chk_h + call Player_ProcessKey_Backwards + jmp short c4ue_cpt +c4ue_chk_h: + ; 19/11/2024 + cmp al, 'H' + jne short c4ue_chk_cr + mov byte [wleds], 0 + call write_sb16_dev_info + mov dh, 24 + mov dl, 79 + call setCursorPosition +c4ue_chk_cr: + ; 19/11/2024 + cmp al, 0Dh ; ENTER/CR key + jne short c4ue_cpt + ; 23/11/2024 + xor bx, bx + mov bl, [wleds] + inc bl + and bl, 0Fh + jnz short c4ue_sc + inc bx +c4ue_sc: + mov [wleds], bl + shr bl, 1 + mov al, [bx+colors] + jnc short c4ue_sc_@ + or al, 10h ; blue (dark) background +c4ue_sc_@: + mov [ccolor], al + ;;; +c4ue_cpt: + ;push ds + ;mov bx, 40h + ;mov ds, bx + ;mov bx, 6Ch ; counter (INT 08h, 18.2 ticks per sec) + ;;cli + ;mov ax, [bx] + ;mov dx, [bx+2] + ;;sti + ;pop ds + ; 26/11/2024 + call GetTimerTicks + + ; 18/11/2024 + pop cx ; * + cmp dx, [timerticks+2] + jne short c4ue_utt + cmp ax, [timerticks] + ; 18/11/2024 + je short c4ue_skip_utt +c4ue_utt: + mov [timerticks], ax + mov [timerticks+2], dx + jmp short c4ue_cpt_@ +c4ue_skip_utt: + ; 18/11/2024 + and cx, cx + jz short c4ue_ok +c4ue_cpt_@: + ; 18/11/2024 + cmp byte [stopped], 0 + ja short c4ue_ok + + call CalcProgressTime + + cmp ax, [ProgressTime] + ; 23/11/2024 + je short c4ue_uvb + ; same second, no need to update + + call UpdateProgressBar + + ; 23/11/2024 +c4ue_uvb: + cmp byte [wleds], 0 + jna short c4ue_vb_ok + + call UpdateWaveLeds + +c4ue_vb_ok: + retn + + ; 26/11/2024 +GetTimerTicks: + push ds + mov bx, 40h + mov ds, bx + mov bx, 6Ch ; counter (INT 08h, 18.2 ticks per sec) + ;cli + mov ax, [bx] + mov dx, [bx+2] + ;sti + pop ds + retn + +; -------------------------------------------------------- +; 19/05/2024 - (playwav4.asm) ich_wav4.asm +; -------------------------------------------------------- + + ; 24/11/2024 (SB16 version) +check4keyboardstop: + ; 19/05/2024 + ; 08/11/2023 + ; 04/11/2023 + mov ah, 1 + int 16h + ;clc + jz short _cksr + + xor ah, ah + int 16h + + ;;; + ; 19/05/2024 (change PCM out volume) + cmp al, '+' + jne short p_1 + + mov al, [volume] + ; 24/11/2024 + cmp al, 15 + jnb short p_3 + inc al + jmp short p_2 +p_1: + cmp al, '-' + jne short p_4 + + mov al, [volume] + ; 24/11/2024 + cmp al, 0 + jna short p_3 + dec al +p_2: + mov [volume], al + ; 24/11/2024 + call SetMasterVolume + ;call UpdateVolume + ;;clc + ;retn + jmp UpdateVolume +_cksr: + ; 18/11/2024 + xor ax, ax + ;clc +p_3: + retn +p_4: + ; 17/11/2024 + cmp ah, 01h ; ESC + je short p_q + cmp al, 03h ; CTRL+C + je short p_q + + ; 18/11/2024 + cmp al, 20h + je short p_r + + ; 19/11/2024 + cmp al, 0Dh ; CR/ENTER + je short p_r + + and al, 0DFh + cmp al, 'B' + je short p_r + cmp al, 'F' + je short p_r + cmp al, 'Q' + je short p_q + + clc + retn + + ;;; +;_cskr: +p_q: + stc +p_r: + retn + +; -------------------------------------------------------- + + ; 14/11/2024 +setCursorPosition: + ; dh = Row + ; dl = Column + mov ax, 0500h + int 10h + mov ah, 02h + mov bh, 00h + ;mov dh, setCursorPosition_Row + ;mov dl, setCursorPosition_Column + int 10h + retn + +; -------------------------------------------------------- +; 14/11/2024 +; (Ref: player.asm, out_cs.asm, Matan Alfasi, 2017) + +;; NAME: SetTotalTime +;; DESCRIPTION: Calculates the total time in seconds in file +;; INPUT: DATA_SubchunkSize, WAVE_SampleRate, WAVE_BlockAlign +;; OUTPUT: CurrentTotalTime=Total time in seconds in file, +;; Output on the screen of the total time in seconds + +SetTotalTime: + ;; Calculate total seconds in file + mov ax, [DATA_SubchunkSize] + mov dx, [DATA_SubchunkSize + 2] + mov bx, [WAVE_SampleRate] + div bx + xor dx, dx + + mov bx, [WAVE_BlockAlign] + + div bx + + mov [TotalTime], ax + + mov bl, 60 + div bl + + ;; al = minutes, ah = seconds + push ax ; ** + push ax ; * + + mov dh, 24 + mov dl, 42 + call setCursorPosition + + pop ax ; * + xor ah, ah + mov bp, 2 + call PrintNumber + + mov dh, 24 + mov dl, 45 + call setCursorPosition + + pop ax ; ** + mov al, ah + xor ah, ah + ;mov bp, 2 + ;jmp short PrintNumber + +; -------------------------------------------------------- + +PrintNumber: + ; bp = digits + ; ax = binary number + mov bx, 10 + xor cx, cx +printNumber_CutNumber: + inc cx + xor dx, dx + div bx + push dx + cmp cx, bp + je short printNumber_printloop + jmp printNumber_CutNumber + +printNumber_printloop: + pop ax + mov dl, '0' + add dl, al + mov ah, 02h + int 21h + loop printNumber_printloop + + retn + +; -------------------------------------------------------- + + ; 14/11/2024 - Erdogan Tan +SetProgressTime: + ;; Calculate playing/progress seconds in file + call CalcProgressTime + +UpdateProgressTime: + ; ax = (new) progress time + + mov [ProgressTime], ax + + mov bl, 60 + div bl + + ;; al = minutes, ah = seconds + push ax ; ** + push ax ; * + + mov dh, 24 + mov dl, 33 + call setCursorPosition + + pop ax ; * + xor ah, ah + mov bp, 2 + call PrintNumber + + mov dh, 24 + mov dl, 36 + call setCursorPosition + + pop ax ; ** + mov al, ah + xor ah, ah + ;mov bp, 2 + jmp short PrintNumber + +; -------------------------------------------------------- + + ; 17/11/2024 + ; 14/11/2024 +CalcProgressTime: + mov ax, [LoadedDataBytes] + mov dx, [LoadedDataBytes+2] + mov bx, ax + or bx, dx + jz short cpt_ok + + mov bx, [WAVE_SampleRate] + div bx + xor dx, dx + mov bx, [WAVE_BlockAlign] + div bx +cpt_ok: + ; ax = (new) progress time + retn + +; -------------------------------------------------------- +; 14/11/2024 +; (Ref: player.asm, out_cs.asm, Matan Alfasi, 2017) + +;; DESCRIPTION: Update file information on template +;; PARAMS: WAVE parameters and other variables +;; REGS: AX(RW) +;; VARS: CurrentFileName, WAVE_SampleRate, +;; RETURNS: On-screen file info is updated. + +UpdateFileInfo: + ;; Print File Name + mov dh, 9 + mov dl, 23 + call setCursorPosition + + mov si, wav_file_name + + ;;; + ; 14/11/2024 + ; skip directory separators + ; (note: asciiz string, max. 79 bytes except zero tail) + mov bx, si +chk4_nxt_sep: + lodsb + cmp al, '\' + je short chg_fpos + and al, al + jz short chg_fpos_ok + jmp short chk4_nxt_sep +chg_fpos: + mov bx, si + jmp short chk4_nxt_sep +chg_fpos_ok: + mov si, bx ; file name (without its path/directory) + ;;; + + call PrintString + + ;; Print Frequency + mov dh, 10 + mov dl, 23 + call setCursorPosition + mov ax, [WAVE_SampleRate] + mov bp, 5 + call PrintNumber + + ;; Print BitRate + mov dh, 9 + mov dl, 57 + call setCursorPosition + mov ax, [WAVE_BitsPerSample] + mov bp, 2 + call PrintNumber + + ;; Print Channel Number + mov dh, 10 + mov dl, 57 + call setCursorPosition + mov ax, [WAVE_NumChannels] + mov bp, 1 + call PrintNumber + + ;call UpdateVolume + ;retn + +; -------------------------------------------------------- + + ; 24/11/2024 + ; 14/11/2024 +UpdateVolume: + ;; Print Volume + mov dh, 24 + mov dl, 75 + call setCursorPosition + + mov al, [volume] + + mov bl, 100 + mul bl + + mov bl, 15 ; 24/11/2024 + div bl + + xor ah, ah + mov bp, 3 + ;call PrintNumber + ;retn + jmp PrintNumber + +; 24/11/2024 +; 29/05/2024 +; 19/05/2024 +volume: db 12 + +; -------------------------------------------------------- + + ; 14/11/2024 +PrintString: + ; si = string address + mov bx, 0Fh ; white + mov ah, 0Eh ; write as tty +printstr_loop: + lodsb + or al, al + jz short printstr_ok + int 10h + jmp short printstr_loop +printstr_ok: + retn + +; -------------------------------------------------------- + + ; 14/11/2024 + ; (Ref: player.asm , Matan Alfasi, 2017) + ; (Modification: Erdogan Tan, 14/11/2024) + + PROGRESSBAR_ROW equ 23 + +UpdateProgressBar: + call SetProgressTime ; 14/11/2024 + + mov ax, [ProgressTime] +UpdateProgressBar@: + mov dx, 80 + mul dx + mov bx, [TotalTime] + div bx + + ;; Push for the 'Clean' part + push ax ; ** + push ax ; * + + ;; Set cursor position + mov dh, PROGRESSBAR_ROW + mov dl, 0 + call setCursorPosition + + pop ax ; * + or ax, ax + jz short UpdateProgressBar_Clean + +UpdateProgressBar_DrawProgress: + mov cx, ax + mov ah, 09h + mov al, 223 + mov bx, 0Fh + int 10h + +UpdateProgressBar_DrawCursor: + ;mov ax, cx + mov dh, PROGRESSBAR_ROW + ;mov dl, al + dec cx + mov dl, cl + call setCursorPosition + + mov ah, 09h + mov al, 223 + mov bx, 0Ch + mov cx, 1 + int 10h + +UpdateProgressBar_Clean: + pop ax ; ** + mov cx, ax + mov dh, PROGRESSBAR_ROW + mov dl, al + call setCursorPosition + + neg cx + add cx, 80 ; cf = 1 ; + + ;; CX = No. of times to print a clean character + ;mov cx, 80 + ;sub cx, ax + ;; 09h = Write character multiple times + mov ah, 09h + ;; 32 = Space ASCII code + ;mov al, 32 + ;mov bx, 0 + ; 15/11/2024 + mov al, 223 + mov bx, 8 + int 10h + ; 14/11/2024 + clc ; + + + retn + +; -------------------------------------------------------- +; 17/11/2024 + +Player_ProcessKey_Backwards: + ;; In order to go backwards 5 seconds: + ;; Update file pointer to the beginning, skip headers + mov cl, 'B' + jmp short Player_ProcessKey_B_or_F + +Player_ProcessKey_Forwards: + ;; In order to fast-forward 5 seconds, set the file pointer + ;; to CUR_SEEK + 5 * Freq + + mov cl, 'F' + ;jmp short Player_ProcessKey_B_or_F + +Player_ProcessKey_B_or_F: + ; 17/11/2024 + ; 04/11/2024 + ; (Ref: player.asm, Matan Alfasi, 2017) + + ; 04/11/2024 + mov ax, 5 + mov bx, [WAVE_BlockAlign] + mul bx + mov bx, [WAVE_SampleRate] + mul bx + ; dx:ax = transfer byte count for 5 seconds + + ; 17/11/2024 + cmp cl, 'B' + mov bx, [LoadedDataBytes] + mov cx, [LoadedDataBytes+2] + jne short move_forward ; cl = 'F' +move_backward: + sub bx, ax + sbb cx, dx + jnc short move_file_pointer +move_to_beginning: + xor cx, cx ; 0 + xor bx, bx ; 0 + jmp short move_file_pointer +move_forward: + add bx, ax + adc cx, dx + jc short move_to_end + cmp cx, [DATA_SubchunkSize+2] + ja short move_to_end + jb short move_file_pointer + cmp bx, [DATA_SubchunkSize] + jna short move_file_pointer +move_to_end: + mov bx, [DATA_SubchunkSize] + mov cx, [DATA_SubchunkSize+2] +move_file_pointer: + mov dx, bx + mov [LoadedDataBytes], dx + mov [LoadedDataBytes+2], cx + add dx, 44 ; + header + adc cx, 0 + + ; seek + mov bx, [filehandle] + mov ax, 4200h + int 21h + + retn + +; -------------------------------------------------------- + + ; 19/11/2024 +UpdateWaveLeds: + ; 23/11/2024 + call reset_wave_leds + ;call word [turn_on_leds] + ;retn + jmp word [turn_on_leds] + +; -------------------------------------------------------- + + ; 23/11/2024 + ; 19/11/2024 +clear_window: + xor ax, ax + jmp short clear_window_@ + +reset_wave_leds: + ; 23/11/2024 + ;mov al, 254 + ;mov ah, 8 ; gray (dark) + mov ax, 08FEh +clear_window_@: + push es + mov di, 0B800h + mov es, di + mov di, 2080 ; 13*80*2 + mov cx, 8*80 ; 8 rows + rep stosw + pop es + retn + +; -------------------------------------------------------- + + ; 24/11/2024 + ; 19/11/2024 +turn_on_leds_stereo_16bit: + ; 25/11/2024 + push es + + cmp byte [tLO],'2' + jne short tol_buffer_1 + +tol_buffer_2: + ; 21/11/2024 + mov si, wav_buffer2 ; 24/11/2024 + jmp short tol_@ + +tol_buffer_1: + cmp byte [tLO],'1' + ;jne short tol_retn + ; 23/11/2024 + jne short tol_clc_retn + + mov si, wav_buffer1 ; 24/11/2024 +tol_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + ; 24/11/2024 + mov cx, LOADSIZE + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol_o_@ + cmp si, cx + jna short tol_s_buf +tol_o_@: + mov si, cx + jmp short tol_s_buf + +tol_clc_retn: + ; 23/11/2024 + clc +tol_retn: + ; 25/11/2024 + pop es + retn + +tol_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol_s_buf: + mov [pbuf_o], si + +tol_buf_@: + ; 25/11/2024 + mov di, 0B800h + mov es, di + ;mov di, (20*80*2)-2 + + ; 23/11/2024 + mov cx, 80 + + ; 22/11/2024 + mov bx, wleds_addr + + ; 27/11/2024 + add si, [pbuf_s] +tol_fill_c: + ; 22/11/2024 + ;inc di + ;inc di + ;push di + lodsw ; left + ;shr ax, 8 + mov dx, ax + lodsw ; right + ;shr ax, 8 + ;;; + ; 23/11/2024 + add ax, dx + shr ax, 8 + ;shr ax, 9 + add al, 80h + shr ax, 5 + ;;; + ;shr ax, 6 + + push bx + shl ax, 1 + add bx, ax + ; 25/11/2024 + mov di, [bx] + ; 23/11/2024 + mov ah, [ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol_fill_c + + jmp short tol_retn + + + ; 24/11/2024 + ; 23/11/2024 +turn_on_leds_mono_16bit: + ; 25/11/2024 + push es + + cmp byte [tLO],'2' + jne short tol2_buffer_1 + +tol2_buffer_2: + mov si, wav_buffer2 ; 24/11/2024 + jmp short tol2_@ + +tol2_buffer_1: + cmp byte [tLO],'1' + jne short tol_clc_retn + + mov si, wav_buffer1 ; 24/11/2024 +tol2_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol2_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + ; 24/11/2024 + mov cx, LOADSIZE + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol2_o_@ + cmp si, cx + jna short tol2_s_buf +tol2_o_@: + mov si, cx + jmp short tol2_s_buf + +;tol2_clc_retn: +; clc +;tol2_retn: +; ; 25/11/2024 +; pop es +; retn + +tol2_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol2_s_buf: + mov [pbuf_o], si + +tol2_buf_@: + ; 25/11/2024 + mov di, 0B800h + mov es, di + + mov cx, 80 + + mov bx, wleds_addr + + ; 27/11/2024 + add si, [pbuf_s] +tol2_fill_c: + lodsw + shr ax, 8 + add al, 80h + shr ax, 5 + push bx + shl ax, 1 + add bx, ax + ; 25/11/2024 + mov di, [bx] + mov ah, [ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol2_fill_c + + jmp tol_retn + + ; 24/11/2024 +turn_on_leds_stereo_8bit: + ; 25/11/2024 + push es + + cmp byte [tLO],'2' + jne short tol3_buffer_1 + +tol3_buffer_2: + mov si, wav_buffer2 ; 24/11/2024 + jmp short tol3_@ + +tol3_buffer_1: + cmp byte [tLO],'1' + jne short tol3_clc_retn + + mov si, wav_buffer1 ; 24/11/2024 +tol3_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol3_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + ; 24/11/2024 + mov cx, LOADSIZE + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol3_o_@ + cmp si, cx + jna short tol3_s_buf +tol3_o_@: + mov si, cx + jmp short tol3_s_buf + +tol3_clc_retn: + clc +tol3_retn: + ; 25/11/2024 + pop es + retn + +tol3_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol3_s_buf: + mov [pbuf_o], si + +tol3_buf_@: + ; 25/11/2024 + mov di, 0B800h + mov es, di + + mov cx, 80 + + mov bx, wleds_addr + + ; 27/11/2024 + add si, [pbuf_s] +tol3_fill_c: + lodsw ; left (al), right (ah) + add al, ah + add al, 80h + xor ah, ah + ;shr ax, 6 + shr ax, 5 + push bx + shl ax, 1 + add bx, ax + ; 25/11/2024 + mov di, [bx] + mov ah, [ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol3_fill_c + + jmp short tol3_retn + + ; 24/11/2024 + ; 23/11/2024 +turn_on_leds_mono_8bit: + ; 25/11/2024 + push es + + cmp byte [tLO],'2' + jne short tol4_buffer_1 + +tol4_buffer_2: + mov si, wav_buffer2 ; 24/11/2024 + jmp short tol4_@ + +tol4_buffer_1: + cmp byte [tLO],'1' + jne short tol3_clc_retn + + mov si, wav_buffer1 ; 24/11/2024 +tol4_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol4_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + ; 24/11/2024 + mov cx, LOADSIZE + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol4_o_@ + cmp si, cx + jna short tol4_s_buf +tol4_o_@: + mov si, cx + jmp short tol4_s_buf + +;tol4_clc_retn: +; clc +;tol4_retn: +; ; 25/11/2024 +; pop es +; retn + +tol4_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol4_s_buf: + mov [pbuf_o], si + +tol4_buf_@: + ; 25/11/2024 + mov di, 0B800h + mov es, di + + mov cx, 80 + + mov bx, wleds_addr + + ; 27/11/2024 + add si, [pbuf_s] +tol4_fill_c: + lodsb + ; 27/11/2024 + add ax, ax + add al, 80h + xor ah, ah + shr ax, 5 + push bx + shl ax, 1 + add bx, ax + ; 25/11/2024 + mov di, [bx] + mov ah, [ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol4_fill_c + + jmp tol3_retn + +; -------------------------------------------------------- + +; 30/05/2024 +print_msg: + mov bx, 07h +p_msg: + push es + push bp + push cx + push dx + + push ds + pop es + mov bp, si + mov ah, 03h ; Return cursor position (in DX) + ; bh = video page number + int 10h + xor cx, cx +p_msg_0: + lodsb + or al, al + jz short p_msg_1 + inc cx + jmp short p_msg_0 +p_msg_1: + or cx, cx + jz short p_msg_x + ; cx = number of chars + ; dx = screen (cursor) position + ; bl = color/attribute + ; bh = video page number + ; es:bp = string buffer + ;mov al, 1 ; attribute in BL, update cursor pos + ;mov ah, 13h ; write character string + mov ax, 1301h + int 10h +p_msg_x: + pop dx + pop cx + pop bp + pop es + retn + +; -------------------------------------------------------- +; -------------------------------------------------------- + +; DATA + +Credits: + db 'Tiny WAV Player for Retro DOS by Erdogan Tan. ' + db 'December 2024.',10,13,0 + db '18/12/2024', 10,13,0 + +msgAudioCardInfo: + db 'for Sound Blaster 16 audio device.', 10,13,0 + +msg_usage: + db 'usage: playwav9 filename.wav',10,13,0 ; 24/11/2024 + + ; 24/11/2024 +noDevMsg: + db 'Error: Unable to find Sound Blaster 16 audio device!' + db 10,13,0 + +noFileErrMsg: + db 'Error: file not found.',10,13,0 + +msg_error: ; 30/05/2024 + +; 24/11/2024 +msg_init_err: + db 0Dh, 0Ah + db "Sound Blaster 16 hardware initialization error !" + db 0Dh, 0Ah, 0 ; 07/12/2024 + +; 19/11/2024 +; 03/06/2017 +hex_chars: db "0123456789ABCDEF", 0 + +; 24/11/2024 +msgSB16Info: db 0Dh, 0Ah + db " Audio Hardware: Sound Blaster 16", 0Dh, 0Ah + db " Base Port: " +msgBasePort: db "000h", 0Dh, 0Ah + db " IRQ: " +msgIRQ: db 30h + db 0Dh, 0Ah, 0 + +; -------------------------------------------------------- +; 14/11/2024 (Ref: player.asm, Matan Alfasi, 2017) + +SplashScreen: + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " _______ ______ _______. ", 221, 219, 222 + db 221, 219, 222, " | \ / __ \ / | ", 221, 219, 222 + db 221, 219, 222, " | .--. | | | | | (----` ", 221, 219, 222 + db 221, 219, 222, " | | | | | | | \ \ ", 221, 219, 222 + db 221, 219, 222, " | '--' | `--' | .----) | ", 221, 219, 222 + db 221, 219, 222, " |_______/ \______/ |_______/ ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " .______ __ ___ ____ ____ _______ .______ ", 221, 219, 222 + db 221, 219, 222, " | _ \ | | / \ \ \ / / | ____|| _ \ ", 221, 219, 222 + db 221, 219, 222, " | |_) | | | / ^ \ \ \/ / | |__ | |_) | ", 221, 219, 222 + db 221, 219, 222, " | ___/ | | / /_\ \ \_ _/ | __| | / ", 221, 219, 222 + db 221, 219, 222, " | | | `----./ _____ \ | | | |____ | |\ \----. ", 221, 219, 222 + db 221, 219, 222, " | _| |_______/__/ \__\ |__| |_______|| _| `._____| ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " WELCOME TO ", 221, 219, 222 + db 221, 219, 222, " DOS PLAYER ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db " " +Template: + db 201, 78 dup(205), 187 + db 186, 33 dup(219), " DOS Player ", 33 dup(219), 186 + db 204, 78 dup(205), 185 + db 186, 33 dup(32), " User Guide ", 33 dup(32), 186 + db 186, 6 dup(32), " Play/Pause ", 4 dup(32), " Hardware Info", 9 dup(32), 186 + db 186, 6 dup(32), " Stop ", 4 dup(32), " Wave Lighting", 9 dup(32), 186 + db 186, 6 dup(32), " Forwards ", 4 dup(32), "<+>/<-> Inc/Dec Volume", 8 dup(32), 186 + db 186, 6 dup(32), " Backwards ", 4 dup(32), " Quit Program ", 9 dup(32), 186 + db 204, 78 dup(205), 185 + db 186, 6 dup(32), "File Name : ", 4 dup(32), "Bit-Rate : 0 Bits ", 9 dup(32), 186 + db 186, 6 dup(32), "Frequency : 0 Hz ", 4 dup(32), "#-Channels: 0 ", 9 dup(32), 186 + db 200, 78 dup(205), 188 + db 80 dup(32) +improper_samplerate_txt: ; 03/11/2024 +read_error_txt: + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(205) + db 80 dup(32) + db 33 dup(32), "00:00 ", 174, 175, " 00:00", 24 dup(32), "VOL 000%" + +; 23/11/2024 +colors: db 0Fh, 0Bh, 0Ah, 0Ch, 0Eh, 09h, 0Dh, 0Fh + ; white, cyan, green, red, yellow, blue, magenta +ccolor: db 0Bh ; cyan + +; 24/11/2024 +half_buffer: db 1 ; dma half buffer 1 or 2 (0 or 1) + ; (initial value = 1 -> after xor in TuneLoop -> 0) +EOF: + +; BSS + +align 2 + +; 24/11/2024 +; 22/11/2024 +; wave volume leds address array +wleds_addr: rw 80*8 ; rb 2*80*8 + +; 24/11/2024 (SB16 version of playwav8.com -> playwav9.com) +; 14/11/2024 +; 17/02/2017 +bss_start: + +; 13/11/2024 +; ('resb','resw','resd' to 'rb','rw','rd' conversions for FASM) + +; 24/11/2024 +old_irq5v_o: rw 1 +old_irq5v_s: rw 1 +old_irq7v_o: rw 1 +old_irq7v_s: rw 1 +; +IRQnum: rb 1 +; 27/11/2024 +audio_intr: rb 1 +; 25/11/2024 +IRQstatus: rb 1 + +; 18/11/2024 +stopped: rb 1 +tLO: rb 1 +; 19/11/2024 +wleds: rb 1 +wleds_dif: rw 1 +pbuf_s: rw 1 +pbuf_o: rw 1 + +; 25/11/2024 +align 4 + +;;;;;;;;;;;;;; +; 14/11/2024 +; (Ref: player.asm, Matan Alfasi, 2017) +WAVFILEHEADERbuff: +RIFF_ChunkID: rd 1 ; Must be equal to "RIFF" - big-endian + ; 0x52494646 +RIFF_ChunkSize: + rd 1 ; Represents total file size, not + ; including the first 2 fields + ; (Total_File_Size - 8), little-endian +RIFF_Format: + rd 1 ; Must be equal to "WAVE" - big-endian + ; 0x57415645 + +;; WAVE header parameters ("Sub-chunk") +WAVE_SubchunkID: + rd 1 ; Must be equal to "fmt " - big-endian + ; 0x666d7420 +WAVE_SubchunkSize: + rd 1 ; Represents total chunk size +WAVE_AudioFormat: + rw 1 ; PCM (Raw) - is 1, other - is a form + ; of compression, not supported. +WAVE_NumChannels: + rw 1 ; Number of channels, Mono-1, Stereo-2 +WAVE_SampleRate: + rd 1 ; Frequency rate, in Hz (8000, 44100 ...) +WAVE_ByteRate: rd 1 ; SampleRate * NumChannels * BytesPerSample +WAVE_BlockAlign: + rw 1 ; NumChannels * BytesPerSample + ; Number of bytes for one sample. +WAVE_BitsPerSample: + rw 1 ; 8 = 8 bits, 16 = 16 bits, etc. + +;; DATA header parameters +DATA_SubchunkID: + rd 1 ; Must be equal to "data" - big-endian + ; 0x64617461 +DATA_SubchunkSize: + rd 1 ; NumSamples * NumChannels * BytesPerSample + ; Number of bytes in the data. +;;;;;;;;;;;;;; + +; 15/11/2024 +cursortype: rw 1 + +filehandle: rw 1 + +flags: rb 1 ; (END_OF_FILE flag) + rb 1 + +audio_io_base: rw 1 ; Sound Blaster 16 base port address (220h) + +; 30/05/2024 +wav_file_name: + rb 80 ; wave file, path name (<= 80 bytes) + + rw 1 +; 24/11/2024 +align 4 + +; 23/11/2024 +turn_on_leds: rw 1 ; turn_on_leds procedure pointer (m8,m16,s8,s16) + +; 14/11/2024 +TotalTime: rw 1 ; Total (WAV File) Playing Time in seconds +ProgressTime: rw 1 +count: rw 1 ; byte count of one (wav file) read +LoadedDataBytes: + rd 1 ; total read/load count + +timerticks: rd 1 ; (to eliminate excessive lookup of events in TuneLoop) + ; (in order to get the emulator/qemu to run correctly) +align 16 + +; 24/11/2024 +dma_buffer: ; 32768 bytes +wav_buffer1: rb dma_buffer_size/2 ; 16384 +wav_buffer2: rb dma_buffer_size/2 ; 16384 + +bss_end: diff --git a/trdos386/programs/16bit/playwav9_com_sb16_2024.zip b/trdos386/programs/16bit/playwav9_com_sb16_2024.zip new file mode 100644 index 0000000000000000000000000000000000000000..d17fb079a6a4407de81c9f249002a6df76a6c70e GIT binary patch literal 32316 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 literal 0 HcmV?d00001 diff --git a/trdos386/programs/16bit/playwavx.asm b/trdos386/programs/16bit/playwavx.asm new file mode 100644 index 0000000..7f6b49a --- /dev/null +++ b/trdos386/programs/16bit/playwavx.asm @@ -0,0 +1,2628 @@ +; **************************************************************************** +; playwav9.asm (for Retro DOS) +; ---------------------------------------------------------------------------- +; PLAYWAV9.COM ! Sound Blaster 16 (DOS) .WAV PLAYER program by Erdogan TAN +; +; 24/11/2024 +; +; [ Last Modification: 18/12/2024 ] +; +; Modified from PLAYWAV8.COM .wav player program by Erdogan Tan, 23/11/2024 +; +; Assembler: FASM 1.73 +; fasm playwav9.asm PLAYWAV9.COM +; ---------------------------------------------------------------------------- +; In the visualization part of the code, the source code of Matan Alfasi's +; (Ami-Asaf) player.exe program was partially used. +; ---------------------------------------------------------------------------- +; Previous versions of this Wav Player were based in part on .wav file player +; (for DOS) source code written by Jeff Leyla in 2002. + +; playwav8.asm (23/11/2024) + +; TUNELOOP version ; 27/11/2024 +; (running in DOSBOX, VIRTUALBOX is ok, QEMU fails) +; ((checking SB16 interrupt status via mixer register 82h)) + +; CODE + + ; 13/11/2024 +macro sys_msg op1,op2 +{ ; 30/05/2024 + mov si, op1 ; message + mov bl, op2 ; text color + xor bh, bh ; video page 0 + mov ah, 0Eh + call p_msg +} + + ; 24/11/2024 +macro SbOut op1 +{ +local .wait +.wait: + in al, dx + or al, al + js short .wait + mov al, op1 ; command + out dx, al +} + +; player internal variables and other equates. +; 17/11/2024 +;BUFFERSIZE equ 65520 +; 24/11/2024 +;dma_buffer_size equ 32768 +;LOADSIZE equ 16384 +ENDOFFILE equ 1 ; flag for knowing end of file +; 27/11/2024 +dma_buffer_size equ 44100 +LOADSIZE equ 22050 + +use16 + +org 100h + +_STARTUP: + ; 30/05/2024 + ; Prints the Credits Text. + sys_msg Credits, 0Bh + + ; 30/05/2024 + call setFree ; deallocate unused DOS mem + + ; 17/02/2017 + ; Clear BSS (uninitialized data) area + xor ax, ax ; 0 + mov cx, (bss_end - bss_start)/2 + mov di, bss_start + rep stosw + + ; 24/11/2024 + ; Detect (& Reset) Sound Blaster 16 Audio Device + call DetectSB16 + jnc short GetFileName + + ; 30/05/2024 +_dev_not_ready: + ; couldn't find the audio device! + sys_msg noDevMsg, 0Fh + jmp Exit + + ; 30/05/2024 +GetFileName: + mov di, wav_file_name + mov si, 80h + mov bl, [si] + xor bh, bh + inc bx + mov byte [si+bx], 0 ; make AsciiZ filename. + inc si +ScanName: + lodsb + test al, al + jz pmsg_usage + cmp al, 20h + je short ScanName ; scan start of name. + stosb + mov ah, 0FFh + ;;; + ; 14/11/2024 + ; (max. path length = 64 bytes for MSDOS ?) (*) + xor cx, cx ; 0 + ;;; +a_0: + inc ah +a_1: + ;;; + ; 14/11/2024 + inc cx + ;;; + lodsb + stosb + cmp al, '.' + je short a_0 + and al, al + ;jnz short a_1 + ;;; + ; 14/11/2024 + jz short a_3 + and ah, ah + jz short a_2 + cmp al, '\' + jne short a_2 + mov ah, 0 +a_2: + cmp cl, 75 ; 64+8+'.'+3 -> offset 75 is the last chr + jb short a_1 +a_3: + ;;; + or ah, ah ; if period NOT found, + jnz short _1 ; then add a .WAV extension. +SetExt: + dec di + mov dword [di], '.WAV' ; ! 64+12 is DOS limit + ; but writing +4 must not + ; destroy the following data + mov byte [di+4], 0 ; so, 80 bytes path + 0 is possible here +_1: + call write_audio_dev_info + +; open the file + ; open existing file + ; 14/11/2024 + ;mov al, OPEN ; open existing file + mov dx, wav_file_name + call openFile ; no error? ok. + jnc short getwavparms ; 14/11/2024 + +; file not found! + sys_msg noFileErrMsg, 0Ch +_exit_: + jmp Exit + +getwavparms: + ; 14/11/2024 + call getWAVParameters + jc short _exit_ ; nothing to do + + ; 15/11/2024 + ;; Set video mode to 03h (not necessary) + mov ax, 03h + int 10h + + ; 15/11/2024 + ;; Get the cursor type + mov ah, 03h + int 10h + mov [cursortype], cx ; save + + ; 15/11/2024 + ;; Set the cursor to invisible + mov ah, 01h + mov cx, 2607h + int 10h + + ;;; 14/11/2024 +Player_SplashScreen: + ; 15/11/2024 + ;xor dx, dx + ;call setCursorPosition + + ;; Print the splash screen in white + mov ax, 1300h + mov bx, 000Fh + mov cx, 1999 + mov dx, 0 + + mov bp, SplashScreen + int 10h + ;;; + + ;;; + ; 22/11/2024 + ; set wave volume led addresses + mov bx, 13*80*2 + mov bp, 80 + mov di, wleds_addr +wleds_sa_1: + mov cx, 7 +wleds_sa_2: + mov ax, 80*2 + mul cx + add ax, bx + stosw + loop wleds_sa_2 + mov ax, bx + stosw + inc bx + inc bx + dec bp + jnz short wleds_sa_1 + ;;; + + ;;; + ; 23/11/2024 + cmp byte [WAVE_NumChannels], 1 + ja short stolp_s +stolp_m: + cmp byte [WAVE_BitsPerSample], 8 + ja short stolp_m16 +stolp_m8: + mov word [turn_on_leds], turn_on_leds_mono_8bit + jmp short stolp_ok +stolp_m16: + mov word [turn_on_leds], turn_on_leds_mono_16bit + jmp short stolp_ok +stolp_s: + cmp byte [WAVE_BitsPerSample], 8 + ja short stolp_s16 +stolp_s8: + mov word [turn_on_leds], turn_on_leds_stereo_8bit + jmp short stolp_ok +stolp_s16: + mov word [turn_on_leds], turn_on_leds_stereo_16bit + jmp short stolp_ok +stolp_ok: + ;;; + + ;;; wait for 3 seconds + ;mov cx, 002Dh + ;mov dx, 0C6C0h + ;mov ah, 86h + ;int 15h + ;;; + ; 26/11/2024 + mov cx, 3*18 +getticks: + ; 26/11/2024 + call GetTimerTicks + + cmp ax, [timerticks] + jne short chkws + cmp dx, [timerticks+2] + je short getticks +chkws: + mov [timerticks], ax + mov [timerticks+2], dx + loop getticks + ;;; + + ;;; +Player_Template: + xor dx, dx + call setCursorPosition + + ;; Print the splash screen in white + mov ax, 1300h + mov bx, 000Fh + mov cx, 1999 + mov dx, 0 + + mov bp, Template + int 10h + ;;; + + ; 14/11/2024 + call SetTotalTime + call UpdateFileInfo + +PlayNow: + ; 24/11/2024 + mov al, 5 ; 15 = max, 0 = min + ; 27/11/2024 + mov [volume], al + ; 15/11/2024 + call SetMasterVolume + call UpdateVolume + ;;; + + ;;; + ; + ; 14/11/2024 + call UpdateProgressBar + ;;; + + ; 30/05/2024 + ; playwav4.asm +_2: + call check4keyboardstop ; flush keyboard buffer + jc short _2 ; 07/11/2023 + +; play the .wav file. Most of the good stuff is in here. + + call PlayWav + +Exit@@: + ; 27/11/2024 + ; 24/11/2024 + ; restore old interrupt vector + ;mov al, [IRQnum] + ;xor ah, ah ; reset + ;call set_hardware_int_vector + +; close the .wav file and exit. + +Exit: + ; 15/11/2024 + ;; Restore Cursor Type + mov cx, [cursortype] + cmp cx, 0 + jz short Exit@ + mov ah, 01h + int 10h +Exit@: + call closeFile + + mov ax, 4C00h ; bye ! + int 21h +here: + jmp short here ; do not come here ! + + ; 30/05/2024 +pmsg_usage: + sys_msg msg_usage, 0Fh ; 14/11/2024 + jmp short Exit + + ; 30/05/2024 +init_err: + sys_msg msg_init_err, 0Fh + jmp short Exit + + ; -------------------------------------------- + + ; 24/11/2024 +PlayWav: + mov ax, wav_buffer1 + call loadFromFile + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + mov ax, wav_buffer2 + call loadFromFile + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + ; 25/11/2024 + call SB16Init_play ; initialize SB16 card + ; set sample rate, start to play + jc init_err + + ; 19/11/2024 + mov byte [wleds], 1 + + mov ax, [WAVE_SampleRate] + mov cx, 10 + mul cx + mov cl, 182 + div cx + ; ax = samples per 1/18.2 second + mov cl, byte [WAVE_BlockAlign] + mul cx + mov [wleds_dif], ax ; buffer read differential (distance) + ; for wave volume leds update + ; (byte stream per 1/18.2 second) + ; 27/11/2024 + ; set audio interrupt vector (to user's handler) + ;mov al, [IRQnum] + ;mov ah, 1 ; set + ;mov dx, IRQ_service + ;call set_hardware_int_vector + + ; 26/11/2024 + call check4keyboardstop + jc _exitt_ + + ;mov byte [IRQnum], 0 + + ; 27/11/2024 + ; 24/11/2024 +TuneLoop: + ; 30/05/2024 + ; 18/11/2023 (ich_wav4.asm) + ; 08/11/2023 + ; 06/11/2023 +tLWait: + ; 18/11/2024 + cmp byte [stopped], 0 + ; 24/11/2024 + jna short tL1 +tLWait@: ; 21/11/2024 + call checkUpdateEvents + jc _exitt_ + cmp byte [tLO], '0' + je short tLWait + call tLZ + mov byte [tLO], '0' + jmp short tLWait +tL1: + ; 27/11/2024 + ; Check SB 16 interrupt status + mov al, 82h + mov dx, [audio_io_base] + add dl, 4 ; 2x4h + out dx, al + inc dx ; 2x5h + in al, dx + + test al, 00000011b + jnz short tL3 +tL2: + call checkUpdateEvents + jc _exitt_ + jmp short tLWait +tL3: + ; 27/11/2024 + ;mov dx, [audio_io_base] + ;;add dx, 0Eh + ;add dl, 0Eh ; 8bit DMA-mode int ack + add dl, 0Eh-05h + in al, dx ; SB acknowledge. + inc dx ; 0Fh ; 16bit DMA-mode int ack + in al, dx ; SB 16 acknowledge. + + xor byte [half_buffer], 1 + + ; load buffer 1 + ;mov ax, wav_buffer1 + mov ax, dma_buffer ; wav_buffer1 + cmp byte [half_buffer], 0 + jna short tL4 + + ; load buffer 2 + ;mov ax, wav_buffer2 + add ax, LOADSIZE ; dma_buffer_size/2 +tL4: + call loadFromFile + jc short _exitt_ ; end of file + + ; 26/11/2024 + mov al, [half_buffer] + add al, '1' + ; 19/11/2024 + mov [tLO], al + call tL0 + ; 24/11/2024 + ; 14/11/2024 + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + ; 27/11/2024 + jmp short tL2 + +_exitt_: + ; 24/11/2024 + call sb16_stop + + ;;; + ; 14/11/2024 + call UpdateProgressBar + ;;; + + ; 18/11/2024 +tLZ: + ; 30/05/2024 + mov al, '0' + + ; 06/11/2023 +tL0: + ; 08/11/2023 + ; 05/11/2023 + ; 17/02/2017 - Buffer switch test (temporary) + ; 06/11/2023 + ; al = buffer indicator ('1', '2' or '0' -stop- ) + + push ds + ;push bx + mov bx, 0B800h ; video display page segment + mov ds, bx + sub bx, bx ; 0 + mov ah, 4Eh + mov [bx], ax ; show current play buffer (1, 2) + ;pop bx + pop ds + + retn + +; ------------------------------------------- + +; 27/11/2024 +; ; 24/11/2024 +;IRQ_ack: +; ; 26/11/2024 +; push dx +; push ax +; mov dx, [audio_io_base] +; ;add dx, 0Eh +; add dl, 0Eh ; 8bit DMA-mode int ack +; ; 25/11/2024 +; cmp byte [WAVE_BitsPerSample], 8 +; jna short irq_ack_@ +; inc dl ; 0Fh ; 16bit DMA-mode int ack +;irq_ack_@: +; in al, dx ; SB acknowledge. +; ; 27/11/2024 +; ;mov al, 20h +; ;out 20h, al ; Hardware acknowledge. +;irq_ack_ok: +; ; 26/11/2024 +; pop ax +; pop dx +; retn + +; ------------------------------------------- + + ; 24/11/2024 +SetMasterVolume: + ; al = sound volume (15 = max, 0 = min) + push ax + ; Tell the SB 16 card which register to write + mov dx, [audio_io_base] + ;add dx, 4 ; Mixer chip address port + add dl, 4 + mov al, 22h + out dx, al + pop ax + ;and al, 0Fh + ; Set the volume for both L and R + mov bl, 11h + mul bl + ; Set new volume + mov dx, [audio_io_base] + ;add dx, 5 + add dl, 5 + out dx, al + retn + +; ------------------------------------------- + + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9 audio.s (06/06/2024) + ; DetectSB procedure (06/08/2022, v2.0.5) +DetectSB16: + ; 06/08/2022 - TRDOS 386 v2.0.5 + ; 24/04/2017 +ScanPort: + mov bx, 0210h ; start scanning ports + ; 210h, 220h, .. 260h +ResetDSP: + ; 26/11/2024 + mov dx, bx ; try to reset the DSP. + add dl, 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 + add dl, 08h + mov cx, 100 +WaitID: + in al, dx + or al, al + js short GetID + loop WaitID + jmp short NextPort +GetID: + ;sub dx, 04h + sub dl, 04h + in al, dx + cmp al, 0AAh + je short Found + ;add dx, 04h + add dl, 04h + loop WaitID +NextPort: + ;add bx, 10h ; if not response, + add bl, 10h + ;cmp bx, 260h ; try the next port. + cmp bl, 60h + jbe short ResetDSP + stc + retn +Found: + mov [audio_io_base], bx ; SB Port Address Found! +ScanIRQ: +SetIrqs: + sub al, al ; 0 + mov [IRQnum], al ; reset + + ; 25/11/2024 + ; save IRQ status + in al, 21h ; save the IMR. + mov [IRQstatus], al + + ; ah > 0 -> set IRQ vector + ; al = IRQ number + mov ax, 105h ; IRQ 5 + ; 26/11/2024 + mov dx, IRQ5_service + call set_hardware_int_vector + mov ax, 107h ; IRQ 7 + ; 26/11/2024 + mov dx, IRQ7_service + call set_hardware_int_vector + + mov dx, [audio_io_base] ; tells to the SB to + ;add dx, 0Ch ; generate a IRQ! + add dl, 0Ch +WaitSb: + in al, dx + or al, al + js short WaitSb + mov al, 0F2h + out dx, al + ; 24/11/2024 + xor cx, cx ; wait until IRQ level +WaitIRQ: + mov al, [IRQnum] + cmp al, 0 ; is changed or timeout. + ja short IrqOk + dec cx + jnz short WaitIRQ + jmp short RestoreIrqs +IrqOk: + ;;; + ; 27/11/2024 + mov dx, [audio_io_base] + ;add dx, 0Eh + add dl, 0Eh ; 8bit DMA-mode int ack + in al, dx ; SB acknowledge. + inc dx ; 0Fh ; 16bit DMA-mode int ack + in al, dx ; SB 16 acknowledge. + ;;; + mov al, 20h + out 20h, al ; Hardware acknowledge. +RestoreIrqs: + ; ah = 0 -> reset IRQ vector + ; al = IRQ number + mov ax, 5 ; IRQ 5 + call set_hardware_int_vector + mov ax, 7 ; IRQ 7 + call set_hardware_int_vector + + cmp byte [IRQnum], 1 ; IRQ level was changed? + + retn + +; ---------------------------------- + + ; 24/11/2024 +set_hardware_int_vector: + or ah, ah + jnz short shintv_1 ; set user's audio interrupt handler + +rhintv_1: + ; reset the interrupt vector to the old interrupt handler + push ds + cmp al, 5 + jne short rhintv_2 + + ; 25/11/2024 + ; restore IRQ 5 status + mov ah, [IRQstatus] + in al, 21h + and ah, 00100000b ; 20h + or al, ah + out 21h, al + + mov dx, [old_irq5v_o] + mov ds, [old_irq5v_s] +shintv_3: + mov al, 0Dh + mov ah, 25h + int 21h + pop ds + retn + +rhintv_2: + ; 25/11/2024 + ; restore IRQ 7 status + mov ah, [IRQstatus] + in al, 21h + and ah, 10000000b ; 80h + or al, ah + out 21h, al + + mov dx, [old_irq7v_o] + mov ds, [old_irq7v_s] +shintv_4: + mov al, 0Fh + mov ah, 25h + int 21h + pop ds + retn + +shintv_1: + push es + + cmp al, 5 + jne short shintv_2 + + ; INT 0Dh = IRQ 5 (default) interrupt number + + ; 25/11/2024 + ; enable IRQ 5 + ; 26/11/2024 + in al, 21h + and al, 11011111b + out 21h, al + + mov al, 0Fh + mov ah, 35h ; Get Interrupt Vector + int 21h + mov [old_irq5v_s], es + mov [old_irq5v_o], bx + pop es + push ds + ; 27/11/2024 + ;mov dx, IRQ5_service + jmp short shintv_3 + +shintv_2: + ; al = 7 + ; INT 0Fh = IRQ 7 (default) interrupt number + + ; 25/11/2024 + ; enable IRQ 7 + ; 26/11/2024 + in al, 21h + and al, 01111111b + out 21h, al + + mov al, 0Fh + mov ah, 35h ; Get Interrupt Vector + int 21h + mov [old_irq7v_s], es + mov [old_irq7v_o], bx + pop es + push ds + ; 27/11/2024 + ;mov dx, IRQ7_service + jmp short shintv_4 + +IRQ5_service: + mov byte [cs:IRQnum], 5 + iret + +IRQ7_service: + mov byte [cs:IRQnum], 7 + iret + +; ; 27/11/2024 +;IRQ_service: +; push ds +; push dx +; push ax +; ; +; push cs +; pop ds +; mov byte [IRQnum], 5 +; mov dx, [audio_io_base] +; ;add dx, 0Eh +; add dl, 0Eh ; 8bit DMA-mode int ack +; cmp byte [WAVE_BitsPerSample], 8 +; jna short irq_ack_@ +; inc dl ; 0Fh ; 16bit DMA-mode int ack +;irq_ack_@: +; in al, dx ; SB acknowledge. +; ; +; mov al, 20h +; out 20h, al ; Hardware acknowledge +; ; +; pop ax +; pop dx +; pop ds +; iret + +; ---------------------------------- + + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9 audio.s (06/06/2024) + ; sb16_stop procedure (06/08/2022, v2.0.5) +sb16_stop: + mov dx, [audio_io_base] + ;add dx, 0Ch + add dl, 0Ch + + mov bl, 0D9h ; exit auto-initialize 16 bit transfer + ; stop autoinitialized DMA transfer mode + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb16_stop_1 + ;mov bl, 0DAh ; exit auto-initialize 8 bit transfer + inc bl +sb16_stop_1: + SbOut bl ; exit auto-initialize transfer command + + xor al, al ; stops all DMA processes on selected channel + + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb16_stop_2 + out 0Ch, al ; clear selected channel register + jmp short sb16_stop_3 + +sb16_stop_2: + out 0D8h, al ; clear selected channel register + +sb16_stop_3: + ; 24/11/2024 + mov byte [stopped], 2 ; stop ! +SbDone: + ;mov dx, [audio_io_base] + ;add dx, 0Ch + SbOut 0D0h + SbOut 0D3h +sb16_stop_4: + retn + +; ---------------------------------- + + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9 audio.s (06/06/2024) + ; sb16_pause procedure (06/08/2022, v2.0.5) +sb16_pause: + mov dx, [audio_io_base] + ;add dx, 0Ch ; Command & Data Port + add dl, 0Ch + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb_pause_1 + ; 8 bit samples + mov bl, 0D0h ; 8 bit DMA mode + jmp short sb_pause_2 +sb_pause_1: + ; 16 bit samples + mov bl, 0D5h ; 16 bit DMA mode +sb_pause_2: + SbOut bl ; bCommand +sb_pause_3: + retn + +; ---------------------------------- + + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9 audio.s (06/06/2024) + ; sb16_continue procedure (06/08/2022, v2.0.5) +sb16_play: +sb16_continue: + mov dx, [audio_io_base] + ;add dx, 0Ch ; Command & Data Port + add dl, 0Ch + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb_cont_1 + ; 8 bit samples + mov bl, 0D4h ; 8 bit DMA mode + jmp short sb_cont_2 +sb_cont_1: + ; 16 bit samples + mov bl, 0D6h ; 16 bit DMA mode +sb_cont_2: + SbOut bl ; bCommand +sb_cont_3: + retn + +; ---------------------------------- + + ; 14/11/2024 + ; INPUT: ds:dx = file name address + ; OUTPUT: [filehandle] = ; -1 = not open +openFile: + mov ax, 3D00h ; open File for read + int 21h + jnc short _of1 + mov ax, -1 + ; cf = 1 -> not found or access error +_of1: + mov [filehandle], ax + retn + +; ---------------------------------- + +; close the currently open file + + ; 14/11/2024 + ; INPUT: [filehandle] ; -1 = not open + ; OUTPUT: none +closeFile: + cmp word [filehandle], -1 + jz short _cf1 + mov bx, [filehandle] + mov ax, 3E00h + int 21h ; close file +_cf1: + retn + +; ---------------------------------- + + ; 14/11/2024 - Erdogan Tan +getWAVParameters: +; reads WAV file header(s) (44 bytes) from the .wav file. +; entry: none - assumes file is already open +; exit: ax = sample rate (11025, 22050, 44100, 48000) +; cx = number of channels (mono=1, stereo=2) +; dx = bits per sample (8, 16) +; bx = number of bytes per sample (1 to 4) + + mov dx, WAVFILEHEADERbuff + mov bx, [filehandle] + mov cx, 44 ; 44 bytes + mov ah, 3Fh + int 21h + jc short gwavp_retn + + cmp ax, 44 + jb short gwavp_retn + + cmp dword [RIFF_Format], 'WAVE' + jne short gwavp_stc_retn + + cmp word [WAVE_AudioFormat], 1 ; Offset 20, must be 1 (= PCM) + ;jne short gwavp_stc_retn + je short gwavp_retn ; 15/11/2024 + + ; 15/11/2024 + ;mov cx, [WAVE_NumChannels] ; return num of channels in CX + ;mov ax, [WAVE_SampleRate] ; return sample rate in AX + ;mov dx, [WAVE_BitsPerSample] + ; return bits per sample value in DX + ;mov bx, [WAVE_BlockAlign] ; return bytes per sample in BX +;gwavp_retn: + ;retn + + ; 27/11/2024 + ; frequency limit (for SB16) = 44100 kHz + ;cmp word [WAVE_SampleRate], 44101 ; 48000 + ;cmc + ;retn + +gwavp_stc_retn: + stc +gwavp_retn: + retn + +; ---- 30/05/2024 (playwav4.asm, 19/05/2024) + +; MEMALLOC.ASM +;-- SETFREE: Release memory not used ---------------- +;-- Input : ES = address of PSP +;-- Output : none +;-- Register : AX, BX, CL and FLAGS are changed +;-- Info : Since the stack-segment is always the last segment in an +; EXE-file, ES:0000 points to the beginning and SS:SP +; to the end of the program in memory. Through this the +; length of the program can be calculated +; call this routine once at the beginning of the program to free up memory +; assigned to it by DOS. + +setFree: + mov bx, 65536/16 ; 4K paragraphs ; 17/02/2017 (Erdogan Tan) + + mov ah, 4Ah ; pass new length to DOS + int 21h + + retn ; back to caller + ; new size (allocated memory) = 64KB + + ; 27/11/2024 +;memAlloc: +;; input: AX = # of paragraphs required +;; output: AX = segment of block to use +; +; push bx +; mov bx, ax +; mov ah, 48h +; int 21h +; pop bx +; retn + +; ---- + +; ///// + + ; 24/11/2024 (SB16 version of playwav8.asm -> playwav9.asm) + ; 30/05/2024 (ich_wav4.asm, 19/05/2024) +loadFromFile: + ; 18/12/2024 + mov word [count], 0 + + ; 07/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff_0 ; no + stc + retn + +lff_0: + ; 24/11/2024 + ; 08/11/2023 + mov di, ax ; save buffer address + ; 17/11/2024 + mov bx, [filehandle] + + ; 24/11/2024 + mov cx, LOADSIZE + mov dx, ax ; buffer address + + ; 24/11/2024 + ; load/read file + ; bx = file handle + ; ds = cs + ; ds:dx = buffer + ; cx = read count + mov ah, 3Fh + int 21h + jc short lff_4 ; error ! + + ; 14/11/2024 + mov [count], ax + + cmp ax, cx + je short endLFF + ; 24/11/2024 + ; di = buffer address + add di, ax +lff_3: + call padfill ; blank pad the remainder + ;clc ; don't exit with CY yet. + or byte [flags], ENDOFFILE ; end of file flag +endLFF: + retn +lff_4: + ; 08/11/2023 + mov al, '!' ; error + call tL0 + + xor ax, ax + jmp short lff_3 + +; entry ds:ax points to last byte in file +; cx = target size +; note: must do byte size fill +; destroys bx, cx +; +padfill: + ; 24/11/2024 + ; di = offset (to be filled with ZEROs) + ; es = ds = cs + ; ax = di = number of bytes loaded + ; cx = buffer size (> loaded bytes) + sub cx, ax + xor ax, ax + cmp byte [WAVE_BitsPerSample], 8 + ja short padfill@ + mov al, 80h +padfill@: + rep stosb + retn +; ///// + +write_audio_dev_info: + ; 30/05/2024 + sys_msg msgAudioCardInfo, 0Fh + retn + +write_sb16_dev_info: + ; 24/11/2024 + mov ax, [audio_io_base] + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgBasePort+2], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgBasePort+1], al + mov bl, ah + mov dl, bl + ;and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgBasePort], al + + xor ax, ax + mov al, [IRQnum] + ;mov cl, 10 + ;div cl + ;add ah, 30h + ;mov [msgIRQ], ah + ; 25/11/2024 + add al, 30h + mov [msgIRQ], al + + call clear_window + mov dh, 13 + mov dl, 0 + call setCursorPosition + + sys_msg msgSB16Info, 07h + + retn + +; -------------------------------------------------------- +; 24/11/2024 - Sound Blaster 16 initialization +; -------------------------------------------------------- + + ; 25/11/2024 + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9, audio.s (06/06/2024) + ; SbInit_play procedure (06/08/2024, v2.0.5) +SB16Init_play: + mov ax, ds + mov dx, ax + shr dx, 12 + shl ax, 4 + add ax, dma_buffer + adc dx, 0 + mov bx, ax ; linear address + ; dx = page number + + mov cx, dma_buffer_size + + cmp byte [WAVE_BitsPerSample], 16 + jne short sbInit_0 ; set 8 bit DMA buffer + + ; 26/11/2024 + mov ax, dx ; page number + + ; convert byte count to word count + ; 26/11/2024 + ;dec cx + shr cx, 1 + dec cx ; word count - 1 + + ; convert byte offset to word offset + shr ax, 1 + rcr bx, 1 + ; 26/11/2024 + ;shr bx, 1 + + ; 16 bit DMA buffer setting (DMA channel 5) + mov al, 05h ; set mask bit for channel 5 (4+1) + out 0D4h, al + + xor al, al ; stops all DMA processes on selected channel + out 0D8h, al ; clear selected channel register + + mov al, bl ; byte 0 of DMA buffer offset in words (physical) + out 0C4h, al ; DMA channel 5 port number + + mov al, bh ; byte 1 of DMA buffer offset in words (physical) + out 0C4h, al + + ; 26/11/2024 + and dl, 0FEh ; clear bit 0 (not necessary, it will be ignored) + + mov al, dl ; byte 2 of DMA buffer address (physical) + out 8Bh, al ; page register port addr for channel 5 + + mov al, cl ; low byte of DMA count - 1 + out 0C6h, al ; count register port addr for channel 5 + + mov al, ch ; high byte of DMA count - 1 + out 0C6h, al + + ; channel 5, read, autoinitialized, single mode + mov al, 59h + out 0D6h, al ; DMA mode register port address + + mov al, 01h ; clear mask bit for channel 5 + out 0D4h, al ; DMA mask register port address + + jmp short ResetDsp + +sbInit_0: + dec cx ; byte count - 1 + + ; 8 bit DMA buffer setting (DMA channel 1) + mov al, 05h ; set mask bit for channel 1 (4+1) + out 0Ah, al ; DMA mask register + + xor al, al ; stops all DMA processes on selected channel + out 0Ch, al ; clear selected channel register + + mov al, bl ; byte 0 of DMA buffer address (physical) + out 02h, al ; DMA channel 1 port number + + mov al, bh ; byte 1 of DMA buffer address (physical) + out 02h, al + + mov al, dl ; byte 2 of DMA buffer address (physical) + out 83h, al ; page register port addr for channel 1 + + mov al, cl ; low byte of DMA count - 1 + out 03h, al ; count register port addr for channel 1 + + mov al, ch ; high byte of DMA count - 1 + out 03h, al + + ; channel 1, read, autoinitialized, single mode + mov al, 59h + out 0Bh, al ; DMA mode register port address + + mov al, 01h ; clear mask bit for channel 1 + out 0Ah, al ; DMA mask register port address + +ResetDsp: + mov dx, [audio_io_base] + ;add dx, 06h + add dl, 06h + mov al, 1 + out dx, al + + in al, dx + in al, dx + in al, dx + in al, dx + + xor ax, ax + out dx, al + + mov cx, 100 +WaitId: + mov dx, [audio_io_base] + add dl, 0Eh + in al, dx + or al, al + ;js short sb_GetId + ; 26/11/2024 + jns short sb_next + ;loop WaitId + ;jmp sb_Exit + +sb_GetId: + mov dx, [audio_io_base] + ;add dx, 0Ah + add dl, 0Ah + in al, dx + cmp al, 0AAh + je short SbOk +sb_next: + loop WaitId + stc + retn +SbOk: + mov dx, [audio_io_base] + ;add dx, 0Ch + add dl, 0Ch + SbOut 0D1h ; Turn on speaker + SbOut 41h ; 8 bit or 16 bit transfer + mov bx, [WAVE_SampleRate] ; sampling rate (Hz) + SbOut bh ; sampling rate high byte + SbOut bl ; sampling rate low byte + + ; 25/11/2024 + +StartDMA: + ; autoinitialized mode + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb_play_1 + ; 8 bit samples + mov bx, 0C6h ; 8 bit output (0C6h) + cmp byte [WAVE_NumChannels], 2 ; 1 = mono, 2 = stereo + jb short sb_play_2 + mov bh, 20h ; 8 bit stereo (20h) + jmp short sb_play_2 +sb_play_1: + ; 16 bit samples + mov bx, 10B6h ; 16 bit output (0B6h) + cmp byte [WAVE_NumChannels], 2 ; 1 = mono, 2 = stereo + jb short sb_play_2 + add bh, 20h ; 16 bit stereo (30h) +sb_play_2: + ; PCM output (8/16 bit mono autoinitialized transfer) + SbOut bl ; bCommand + SbOut bh ; bMode + ; 25/11/2024 + mov bx, dma_buffer_size/2 + ; half buffer size + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit DMA + jne short sb_play_3 + shr bx, 1 ; byte count to word count (samples) +sb_play_3: + dec bx ; wBlkSize is one less than the actual size + SbOut bl + SbOut bh + + ; 24/11/2024 + ;mov byte [stopped], 0 ; playing ! +sb_Exit: + retn + +; -------------------------------------------------------- +; 14/11/2024 - Erdogan Tan +; -------------------------------------------------------- + + ; 24/11/2024 (SB16 version) +checkUpdateEvents: + call check4keyboardstop + jc short c4ue_ok + + ; 18/11/2024 + push ax ; * + or ax, ax + jz c4ue_cpt + + ; 18/11/2024 + cmp al, 20h ; SPACE (spacebar) ; pause/play + jne short ch4ue_chk_s + cmp byte [stopped], 0 + ja short ch4ue_chk_ps + ; pause + call sb16_pause ; 24/11/2024 + ; 27/11/2024 + mov byte [stopped], 1 + jmp c4ue_cpt +ch4ue_chk_ps: + cmp byte [stopped], 1 + ja short ch4ue_replay + ; continue to play (after a pause) + call sb16_play ; 24/11/2024 + ; 27/11/2024 + mov byte [stopped], 0 + jmp short c4ue_cpt +ch4ue_replay: + ; 19/11/2024 + pop ax ; * + pop ax ; return address + ; 24/11/2024 + ; initialize (again) + ; and start playing (after stop) + call SB16Init_play + mov al, [volume] + call SetMasterVolume ; 24/11/2024 + mov byte [stopped], 0 + ; 24/11/2024 + mov byte [half_buffer], 1 + call move_to_beginning + jmp PlayWav + +ch4ue_chk_s: + cmp al, 'S' ; stop + jne short ch4ue_chk_fb + cmp byte [stopped], 0 + ja short c4ue_cpt ; Already stopped/paused + call sb16_stop ; 24/11/2024 + ; 19/11/2024 + mov byte [tLO], 0 + jmp short c4ue_cpt + +ch4ue_chk_fb: + ; 17/11/2024 + cmp al, 'F' + jne short c4ue_chk_b + call Player_ProcessKey_Forwards + jmp short c4ue_cpt + + ; 18/11/2024 +c4ue_ok: + retn + +c4ue_chk_b: + cmp al, 'B' + ; 19/11/2024 + jne short c4ue_chk_h + call Player_ProcessKey_Backwards + jmp short c4ue_cpt +c4ue_chk_h: + ; 19/11/2024 + cmp al, 'H' + jne short c4ue_chk_cr + mov byte [wleds], 0 + call write_sb16_dev_info + mov dh, 24 + mov dl, 79 + call setCursorPosition +c4ue_chk_cr: + ; 19/11/2024 + cmp al, 0Dh ; ENTER/CR key + jne short c4ue_cpt + ; 23/11/2024 + xor bx, bx + mov bl, [wleds] + inc bl + and bl, 0Fh + jnz short c4ue_sc + inc bx +c4ue_sc: + mov [wleds], bl + shr bl, 1 + mov al, [bx+colors] + jnc short c4ue_sc_@ + or al, 10h ; blue (dark) background +c4ue_sc_@: + mov [ccolor], al + ;;; +c4ue_cpt: + ;push ds + ;mov bx, 40h + ;mov ds, bx + ;mov bx, 6Ch ; counter (INT 08h, 18.2 ticks per sec) + ;;cli + ;mov ax, [bx] + ;mov dx, [bx+2] + ;;sti + ;pop ds + ; 26/11/2024 + call GetTimerTicks + + ; 18/11/2024 + pop cx ; * + cmp dx, [timerticks+2] + jne short c4ue_utt + cmp ax, [timerticks] + ; 18/11/2024 + je short c4ue_skip_utt +c4ue_utt: + mov [timerticks], ax + mov [timerticks+2], dx + jmp short c4ue_cpt_@ +c4ue_skip_utt: + ; 18/11/2024 + and cx, cx + jz short c4ue_ok +c4ue_cpt_@: + ; 18/11/2024 + cmp byte [stopped], 0 + ja short c4ue_ok + + call CalcProgressTime + + cmp ax, [ProgressTime] + ; 23/11/2024 + je short c4ue_uvb + ; same second, no need to update + + call UpdateProgressBar + + ; 23/11/2024 +c4ue_uvb: + cmp byte [wleds], 0 + jna short c4ue_vb_ok + + call UpdateWaveLeds + +c4ue_vb_ok: + retn + + ; 26/11/2024 +GetTimerTicks: + push ds + mov bx, 40h + mov ds, bx + mov bx, 6Ch ; counter (INT 08h, 18.2 ticks per sec) + ;cli + mov ax, [bx] + mov dx, [bx+2] + ;sti + pop ds + retn + +; -------------------------------------------------------- +; 19/05/2024 - (playwav4.asm) ich_wav4.asm +; -------------------------------------------------------- + + ; 24/11/2024 (SB16 version) +check4keyboardstop: + ; 19/05/2024 + ; 08/11/2023 + ; 04/11/2023 + mov ah, 1 + int 16h + ;clc + jz short _cksr + + xor ah, ah + int 16h + + ;;; + ; 19/05/2024 (change PCM out volume) + cmp al, '+' + jne short p_1 + + mov al, [volume] + ; 24/11/2024 + cmp al, 15 + jnb short p_3 + inc al + jmp short p_2 +p_1: + cmp al, '-' + jne short p_4 + + mov al, [volume] + ; 24/11/2024 + cmp al, 0 + jna short p_3 + dec al +p_2: + mov [volume], al + ; 24/11/2024 + call SetMasterVolume + ;call UpdateVolume + ;;clc + ;retn + jmp UpdateVolume +_cksr: + ; 18/11/2024 + xor ax, ax + ;clc +p_3: + retn +p_4: + ; 17/11/2024 + cmp ah, 01h ; ESC + je short p_q + cmp al, 03h ; CTRL+C + je short p_q + + ; 18/11/2024 + cmp al, 20h + je short p_r + + ; 19/11/2024 + cmp al, 0Dh ; CR/ENTER + je short p_r + + and al, 0DFh + cmp al, 'B' + je short p_r + cmp al, 'F' + je short p_r + cmp al, 'Q' + je short p_q + + clc + retn + + ;;; +;_cskr: +p_q: + stc +p_r: + retn + +; -------------------------------------------------------- + + ; 14/11/2024 +setCursorPosition: + ; dh = Row + ; dl = Column + mov ax, 0500h + int 10h + mov ah, 02h + mov bh, 00h + ;mov dh, setCursorPosition_Row + ;mov dl, setCursorPosition_Column + int 10h + retn + +; -------------------------------------------------------- +; 14/11/2024 +; (Ref: player.asm, out_cs.asm, Matan Alfasi, 2017) + +;; NAME: SetTotalTime +;; DESCRIPTION: Calculates the total time in seconds in file +;; INPUT: DATA_SubchunkSize, WAVE_SampleRate, WAVE_BlockAlign +;; OUTPUT: CurrentTotalTime=Total time in seconds in file, +;; Output on the screen of the total time in seconds + +SetTotalTime: + ;; Calculate total seconds in file + mov ax, [DATA_SubchunkSize] + mov dx, [DATA_SubchunkSize + 2] + mov bx, [WAVE_SampleRate] + div bx + xor dx, dx + + mov bx, [WAVE_BlockAlign] + + div bx + + mov [TotalTime], ax + + mov bl, 60 + div bl + + ;; al = minutes, ah = seconds + push ax ; ** + push ax ; * + + mov dh, 24 + mov dl, 42 + call setCursorPosition + + pop ax ; * + xor ah, ah + mov bp, 2 + call PrintNumber + + mov dh, 24 + mov dl, 45 + call setCursorPosition + + pop ax ; ** + mov al, ah + xor ah, ah + ;mov bp, 2 + ;jmp short PrintNumber + +; -------------------------------------------------------- + +PrintNumber: + ; bp = digits + ; ax = binary number + mov bx, 10 + xor cx, cx +printNumber_CutNumber: + inc cx + xor dx, dx + div bx + push dx + cmp cx, bp + je short printNumber_printloop + jmp printNumber_CutNumber + +printNumber_printloop: + pop ax + mov dl, '0' + add dl, al + mov ah, 02h + int 21h + loop printNumber_printloop + + retn + +; -------------------------------------------------------- + + ; 14/11/2024 - Erdogan Tan +SetProgressTime: + ;; Calculate playing/progress seconds in file + call CalcProgressTime + +UpdateProgressTime: + ; ax = (new) progress time + + mov [ProgressTime], ax + + mov bl, 60 + div bl + + ;; al = minutes, ah = seconds + push ax ; ** + push ax ; * + + mov dh, 24 + mov dl, 33 + call setCursorPosition + + pop ax ; * + xor ah, ah + mov bp, 2 + call PrintNumber + + mov dh, 24 + mov dl, 36 + call setCursorPosition + + pop ax ; ** + mov al, ah + xor ah, ah + ;mov bp, 2 + jmp short PrintNumber + +; -------------------------------------------------------- + + ; 17/11/2024 + ; 14/11/2024 +CalcProgressTime: + mov ax, [LoadedDataBytes] + mov dx, [LoadedDataBytes+2] + mov bx, ax + or bx, dx + jz short cpt_ok + + mov bx, [WAVE_SampleRate] + div bx + xor dx, dx + mov bx, [WAVE_BlockAlign] + div bx +cpt_ok: + ; ax = (new) progress time + retn + +; -------------------------------------------------------- +; 14/11/2024 +; (Ref: player.asm, out_cs.asm, Matan Alfasi, 2017) + +;; DESCRIPTION: Update file information on template +;; PARAMS: WAVE parameters and other variables +;; REGS: AX(RW) +;; VARS: CurrentFileName, WAVE_SampleRate, +;; RETURNS: On-screen file info is updated. + +UpdateFileInfo: + ;; Print File Name + mov dh, 9 + mov dl, 23 + call setCursorPosition + + mov si, wav_file_name + + ;;; + ; 14/11/2024 + ; skip directory separators + ; (note: asciiz string, max. 79 bytes except zero tail) + mov bx, si +chk4_nxt_sep: + lodsb + cmp al, '\' + je short chg_fpos + and al, al + jz short chg_fpos_ok + jmp short chk4_nxt_sep +chg_fpos: + mov bx, si + jmp short chk4_nxt_sep +chg_fpos_ok: + mov si, bx ; file name (without its path/directory) + ;;; + + call PrintString + + ;; Print Frequency + mov dh, 10 + mov dl, 23 + call setCursorPosition + mov ax, [WAVE_SampleRate] + mov bp, 5 + call PrintNumber + + ;; Print BitRate + mov dh, 9 + mov dl, 57 + call setCursorPosition + mov ax, [WAVE_BitsPerSample] + mov bp, 2 + call PrintNumber + + ;; Print Channel Number + mov dh, 10 + mov dl, 57 + call setCursorPosition + mov ax, [WAVE_NumChannels] + mov bp, 1 + call PrintNumber + + ;call UpdateVolume + ;retn + +; -------------------------------------------------------- + + ; 24/11/2024 + ; 14/11/2024 +UpdateVolume: + ;; Print Volume + mov dh, 24 + mov dl, 75 + call setCursorPosition + + mov al, [volume] + + mov bl, 100 + mul bl + + mov bl, 15 ; 24/11/2024 + div bl + + xor ah, ah + mov bp, 3 + ;call PrintNumber + ;retn + jmp PrintNumber + +; 24/11/2024 +; 29/05/2024 +; 19/05/2024 +volume: db 12 + +; -------------------------------------------------------- + + ; 14/11/2024 +PrintString: + ; si = string address + mov bx, 0Fh ; white + mov ah, 0Eh ; write as tty +printstr_loop: + lodsb + or al, al + jz short printstr_ok + int 10h + jmp short printstr_loop +printstr_ok: + retn + +; -------------------------------------------------------- + + ; 14/11/2024 + ; (Ref: player.asm , Matan Alfasi, 2017) + ; (Modification: Erdogan Tan, 14/11/2024) + + PROGRESSBAR_ROW equ 23 + +UpdateProgressBar: + call SetProgressTime ; 14/11/2024 + + mov ax, [ProgressTime] +UpdateProgressBar@: + mov dx, 80 + mul dx + mov bx, [TotalTime] + div bx + + ;; Push for the 'Clean' part + push ax ; ** + push ax ; * + + ;; Set cursor position + mov dh, PROGRESSBAR_ROW + mov dl, 0 + call setCursorPosition + + pop ax ; * + or ax, ax + jz short UpdateProgressBar_Clean + +UpdateProgressBar_DrawProgress: + mov cx, ax + mov ah, 09h + mov al, 223 + mov bx, 0Fh + int 10h + +UpdateProgressBar_DrawCursor: + ;mov ax, cx + mov dh, PROGRESSBAR_ROW + ;mov dl, al + dec cx + mov dl, cl + call setCursorPosition + + mov ah, 09h + mov al, 223 + mov bx, 0Ch + mov cx, 1 + int 10h + +UpdateProgressBar_Clean: + pop ax ; ** + mov cx, ax + mov dh, PROGRESSBAR_ROW + mov dl, al + call setCursorPosition + + neg cx + add cx, 80 ; cf = 1 ; + + ;; CX = No. of times to print a clean character + ;mov cx, 80 + ;sub cx, ax + ;; 09h = Write character multiple times + mov ah, 09h + ;; 32 = Space ASCII code + ;mov al, 32 + ;mov bx, 0 + ; 15/11/2024 + mov al, 223 + mov bx, 8 + int 10h + ; 14/11/2024 + clc ; + + + retn + +; -------------------------------------------------------- +; 17/11/2024 + +Player_ProcessKey_Backwards: + ;; In order to go backwards 5 seconds: + ;; Update file pointer to the beginning, skip headers + mov cl, 'B' + jmp short Player_ProcessKey_B_or_F + +Player_ProcessKey_Forwards: + ;; In order to fast-forward 5 seconds, set the file pointer + ;; to CUR_SEEK + 5 * Freq + + mov cl, 'F' + ;jmp short Player_ProcessKey_B_or_F + +Player_ProcessKey_B_or_F: + ; 17/11/2024 + ; 04/11/2024 + ; (Ref: player.asm, Matan Alfasi, 2017) + + ; 04/11/2024 + mov ax, 5 + mov bx, [WAVE_BlockAlign] + mul bx + mov bx, [WAVE_SampleRate] + mul bx + ; dx:ax = transfer byte count for 5 seconds + + ; 17/11/2024 + cmp cl, 'B' + mov bx, [LoadedDataBytes] + mov cx, [LoadedDataBytes+2] + jne short move_forward ; cl = 'F' +move_backward: + sub bx, ax + sbb cx, dx + jnc short move_file_pointer +move_to_beginning: + xor cx, cx ; 0 + xor bx, bx ; 0 + jmp short move_file_pointer +move_forward: + add bx, ax + adc cx, dx + jc short move_to_end + cmp cx, [DATA_SubchunkSize+2] + ja short move_to_end + jb short move_file_pointer + cmp bx, [DATA_SubchunkSize] + jna short move_file_pointer +move_to_end: + mov bx, [DATA_SubchunkSize] + mov cx, [DATA_SubchunkSize+2] +move_file_pointer: + mov dx, bx + mov [LoadedDataBytes], dx + mov [LoadedDataBytes+2], cx + add dx, 44 ; + header + adc cx, 0 + + ; seek + mov bx, [filehandle] + mov ax, 4200h + int 21h + + retn + +; -------------------------------------------------------- + + ; 19/11/2024 +UpdateWaveLeds: + ; 23/11/2024 + call reset_wave_leds + ;call word [turn_on_leds] + ;retn + jmp word [turn_on_leds] + +; -------------------------------------------------------- + + ; 23/11/2024 + ; 19/11/2024 +clear_window: + xor ax, ax + jmp short clear_window_@ + +reset_wave_leds: + ; 23/11/2024 + ;mov al, 254 + ;mov ah, 8 ; gray (dark) + mov ax, 08FEh +clear_window_@: + push es + mov di, 0B800h + mov es, di + mov di, 2080 ; 13*80*2 + mov cx, 8*80 ; 8 rows + rep stosw + pop es + retn + +; -------------------------------------------------------- + + ; 24/11/2024 + ; 19/11/2024 +turn_on_leds_stereo_16bit: + ; 25/11/2024 + push es + + cmp byte [tLO],'2' + jne short tol_buffer_1 + +tol_buffer_2: + ; 21/11/2024 + mov si, wav_buffer2 ; 24/11/2024 + jmp short tol_@ + +tol_buffer_1: + cmp byte [tLO],'1' + ;jne short tol_retn + ; 23/11/2024 + jne short tol_clc_retn + + mov si, wav_buffer1 ; 24/11/2024 +tol_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + ; 24/11/2024 + mov cx, LOADSIZE + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol_o_@ + cmp si, cx + jna short tol_s_buf +tol_o_@: + mov si, cx + jmp short tol_s_buf + +tol_clc_retn: + ; 23/11/2024 + clc +tol_retn: + ; 25/11/2024 + pop es + retn + +tol_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol_s_buf: + mov [pbuf_o], si + +tol_buf_@: + ; 25/11/2024 + mov di, 0B800h + mov es, di + ;mov di, (20*80*2)-2 + + ; 23/11/2024 + mov cx, 80 + + ; 22/11/2024 + mov bx, wleds_addr + + ; 27/11/2024 + add si, [pbuf_s] +tol_fill_c: + ; 22/11/2024 + ;inc di + ;inc di + ;push di + lodsw ; left + ;shr ax, 8 + mov dx, ax + lodsw ; right + ;shr ax, 8 + ;;; + ; 23/11/2024 + add ax, dx + shr ax, 8 + ;shr ax, 9 + add al, 80h + shr ax, 5 + ;;; + ;shr ax, 6 + + push bx + shl ax, 1 + add bx, ax + ; 25/11/2024 + mov di, [bx] + ; 23/11/2024 + mov ah, [ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol_fill_c + + jmp short tol_retn + + + ; 24/11/2024 + ; 23/11/2024 +turn_on_leds_mono_16bit: + ; 25/11/2024 + push es + + cmp byte [tLO],'2' + jne short tol2_buffer_1 + +tol2_buffer_2: + mov si, wav_buffer2 ; 24/11/2024 + jmp short tol2_@ + +tol2_buffer_1: + cmp byte [tLO],'1' + jne short tol_clc_retn + + mov si, wav_buffer1 ; 24/11/2024 +tol2_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol2_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + ; 24/11/2024 + mov cx, LOADSIZE + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol2_o_@ + cmp si, cx + jna short tol2_s_buf +tol2_o_@: + mov si, cx + jmp short tol2_s_buf + +;tol2_clc_retn: +; clc +;tol2_retn: +; ; 25/11/2024 +; pop es +; retn + +tol2_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol2_s_buf: + mov [pbuf_o], si + +tol2_buf_@: + ; 25/11/2024 + mov di, 0B800h + mov es, di + + mov cx, 80 + + mov bx, wleds_addr + + ; 27/11/2024 + add si, [pbuf_s] +tol2_fill_c: + lodsw + shr ax, 8 + add al, 80h + shr ax, 5 + push bx + shl ax, 1 + add bx, ax + ; 25/11/2024 + mov di, [bx] + mov ah, [ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol2_fill_c + + jmp tol_retn + + ; 24/11/2024 +turn_on_leds_stereo_8bit: + ; 25/11/2024 + push es + + cmp byte [tLO],'2' + jne short tol3_buffer_1 + +tol3_buffer_2: + mov si, wav_buffer2 ; 24/11/2024 + jmp short tol3_@ + +tol3_buffer_1: + cmp byte [tLO],'1' + jne short tol3_clc_retn + + mov si, wav_buffer1 ; 24/11/2024 +tol3_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol3_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + ; 24/11/2024 + mov cx, LOADSIZE + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol3_o_@ + cmp si, cx + jna short tol3_s_buf +tol3_o_@: + mov si, cx + jmp short tol3_s_buf + +tol3_clc_retn: + clc +tol3_retn: + ; 25/11/2024 + pop es + retn + +tol3_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol3_s_buf: + mov [pbuf_o], si + +tol3_buf_@: + ; 25/11/2024 + mov di, 0B800h + mov es, di + + mov cx, 80 + + mov bx, wleds_addr + + ; 27/11/2024 + add si, [pbuf_s] +tol3_fill_c: + lodsw ; left (al), right (ah) + add al, ah + add al, 80h + xor ah, ah + ;shr ax, 6 + shr ax, 5 + push bx + shl ax, 1 + add bx, ax + ; 25/11/2024 + mov di, [bx] + mov ah, [ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol3_fill_c + + jmp short tol3_retn + + ; 24/11/2024 + ; 23/11/2024 +turn_on_leds_mono_8bit: + ; 25/11/2024 + push es + + cmp byte [tLO],'2' + jne short tol4_buffer_1 + +tol4_buffer_2: + mov si, wav_buffer2 ; 24/11/2024 + jmp short tol4_@ + +tol4_buffer_1: + cmp byte [tLO],'1' + jne short tol3_clc_retn + + mov si, wav_buffer1 ; 24/11/2024 +tol4_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol4_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + ; 24/11/2024 + mov cx, LOADSIZE + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol4_o_@ + cmp si, cx + jna short tol4_s_buf +tol4_o_@: + mov si, cx + jmp short tol4_s_buf + +;tol4_clc_retn: +; clc +;tol4_retn: +; ; 25/11/2024 +; pop es +; retn + +tol4_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol4_s_buf: + mov [pbuf_o], si + +tol4_buf_@: + ; 25/11/2024 + mov di, 0B800h + mov es, di + + mov cx, 80 + + mov bx, wleds_addr + + ; 27/11/2024 + add si, [pbuf_s] +tol4_fill_c: + lodsb + ; 27/11/2024 + add ax, ax + add al, 80h + xor ah, ah + shr ax, 5 + push bx + shl ax, 1 + add bx, ax + ; 25/11/2024 + mov di, [bx] + mov ah, [ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol4_fill_c + + jmp tol3_retn + +; -------------------------------------------------------- + +; 30/05/2024 +print_msg: + mov bx, 07h +p_msg: + push es + push bp + push cx + push dx + + push ds + pop es + mov bp, si + mov ah, 03h ; Return cursor position (in DX) + ; bh = video page number + int 10h + xor cx, cx +p_msg_0: + lodsb + or al, al + jz short p_msg_1 + inc cx + jmp short p_msg_0 +p_msg_1: + or cx, cx + jz short p_msg_x + ; cx = number of chars + ; dx = screen (cursor) position + ; bl = color/attribute + ; bh = video page number + ; es:bp = string buffer + ;mov al, 1 ; attribute in BL, update cursor pos + ;mov ah, 13h ; write character string + mov ax, 1301h + int 10h +p_msg_x: + pop dx + pop cx + pop bp + pop es + retn + +; -------------------------------------------------------- +; -------------------------------------------------------- + +; DATA + +Credits: + db 'Tiny WAV Player for Retro DOS by Erdogan Tan. ' + db 'December 2024.',10,13,0 + db '18/12/2024', 10,13,0 + +msgAudioCardInfo: + db 'for Sound Blaster 16 audio device.', 10,13,0 + +msg_usage: + db 'usage: playwav9 filename.wav',10,13,0 ; 24/11/2024 + + ; 24/11/2024 +noDevMsg: + db 'Error: Unable to find Sound Blaster 16 audio device!' + db 10,13,0 + +noFileErrMsg: + db 'Error: file not found.',10,13,0 + +msg_error: ; 30/05/2024 + +; 24/11/2024 +msg_init_err: + db 0Dh, 0Ah + db "Sound Blaster 16 hardware initialization error !" + db 0Dh, 0Ah, 0 ; 07/12/2024 + +; 19/11/2024 +; 03/06/2017 +hex_chars: db "0123456789ABCDEF", 0 + +; 24/11/2024 +msgSB16Info: db 0Dh, 0Ah + db " Audio Hardware: Sound Blaster 16", 0Dh, 0Ah + db " Base Port: " +msgBasePort: db "000h", 0Dh, 0Ah + db " IRQ: " +msgIRQ: db 30h + db 0Dh, 0Ah, 0 + +; -------------------------------------------------------- +; 14/11/2024 (Ref: player.asm, Matan Alfasi, 2017) + +SplashScreen: + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " _______ ______ _______. ", 221, 219, 222 + db 221, 219, 222, " | \ / __ \ / | ", 221, 219, 222 + db 221, 219, 222, " | .--. | | | | | (----` ", 221, 219, 222 + db 221, 219, 222, " | | | | | | | \ \ ", 221, 219, 222 + db 221, 219, 222, " | '--' | `--' | .----) | ", 221, 219, 222 + db 221, 219, 222, " |_______/ \______/ |_______/ ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " .______ __ ___ ____ ____ _______ .______ ", 221, 219, 222 + db 221, 219, 222, " | _ \ | | / \ \ \ / / | ____|| _ \ ", 221, 219, 222 + db 221, 219, 222, " | |_) | | | / ^ \ \ \/ / | |__ | |_) | ", 221, 219, 222 + db 221, 219, 222, " | ___/ | | / /_\ \ \_ _/ | __| | / ", 221, 219, 222 + db 221, 219, 222, " | | | `----./ _____ \ | | | |____ | |\ \----. ", 221, 219, 222 + db 221, 219, 222, " | _| |_______/__/ \__\ |__| |_______|| _| `._____| ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " WELCOME TO ", 221, 219, 222 + db 221, 219, 222, " DOS PLAYER ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db " " +Template: + db 201, 78 dup(205), 187 + db 186, 33 dup(219), " DOS Player ", 33 dup(219), 186 + db 204, 78 dup(205), 185 + db 186, 33 dup(32), " User Guide ", 33 dup(32), 186 + db 186, 6 dup(32), " Play/Pause ", 4 dup(32), " Hardware Info", 9 dup(32), 186 + db 186, 6 dup(32), " Stop ", 4 dup(32), " Wave Lighting", 9 dup(32), 186 + db 186, 6 dup(32), " Forwards ", 4 dup(32), "<+>/<-> Inc/Dec Volume", 8 dup(32), 186 + db 186, 6 dup(32), " Backwards ", 4 dup(32), " Quit Program ", 9 dup(32), 186 + db 204, 78 dup(205), 185 + db 186, 6 dup(32), "File Name : ", 4 dup(32), "Bit-Rate : 0 Bits ", 9 dup(32), 186 + db 186, 6 dup(32), "Frequency : 0 Hz ", 4 dup(32), "#-Channels: 0 ", 9 dup(32), 186 + db 200, 78 dup(205), 188 + db 80 dup(32) +improper_samplerate_txt: ; 03/11/2024 +read_error_txt: + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(32) + db 80 dup(205) + db 80 dup(32) + db 33 dup(32), "00:00 ", 174, 175, " 00:00", 24 dup(32), "VOL 000%" + +; 23/11/2024 +colors: db 0Fh, 0Bh, 0Ah, 0Ch, 0Eh, 09h, 0Dh, 0Fh + ; white, cyan, green, red, yellow, blue, magenta +ccolor: db 0Bh ; cyan + +; 24/11/2024 +half_buffer: db 1 ; dma half buffer 1 or 2 (0 or 1) + ; (initial value = 1 -> after xor in TuneLoop -> 0) +EOF: + +; BSS + +align 2 + +; 24/11/2024 +; 22/11/2024 +; wave volume leds address array +wleds_addr: rw 80*8 ; rb 2*80*8 + +; 24/11/2024 (SB16 version of playwav8.com -> playwav9.com) +; 14/11/2024 +; 17/02/2017 +bss_start: + +; 13/11/2024 +; ('resb','resw','resd' to 'rb','rw','rd' conversions for FASM) + +; 24/11/2024 +old_irq5v_o: rw 1 +old_irq5v_s: rw 1 +old_irq7v_o: rw 1 +old_irq7v_s: rw 1 +; +IRQnum: rb 1 +; 25/11/2024 +IRQstatus: rb 1 + rb 1 +; 18/11/2024 +stopped: rb 1 +tLO: rb 1 +; 19/11/2024 +wleds: rb 1 +wleds_dif: rw 1 +pbuf_s: rw 1 +pbuf_o: rw 1 + +; 25/11/2024 +align 4 + +;;;;;;;;;;;;;; +; 14/11/2024 +; (Ref: player.asm, Matan Alfasi, 2017) +WAVFILEHEADERbuff: +RIFF_ChunkID: rd 1 ; Must be equal to "RIFF" - big-endian + ; 0x52494646 +RIFF_ChunkSize: + rd 1 ; Represents total file size, not + ; including the first 2 fields + ; (Total_File_Size - 8), little-endian +RIFF_Format: + rd 1 ; Must be equal to "WAVE" - big-endian + ; 0x57415645 + +;; WAVE header parameters ("Sub-chunk") +WAVE_SubchunkID: + rd 1 ; Must be equal to "fmt " - big-endian + ; 0x666d7420 +WAVE_SubchunkSize: + rd 1 ; Represents total chunk size +WAVE_AudioFormat: + rw 1 ; PCM (Raw) - is 1, other - is a form + ; of compression, not supported. +WAVE_NumChannels: + rw 1 ; Number of channels, Mono-1, Stereo-2 +WAVE_SampleRate: + rd 1 ; Frequency rate, in Hz (8000, 44100 ...) +WAVE_ByteRate: rd 1 ; SampleRate * NumChannels * BytesPerSample +WAVE_BlockAlign: + rw 1 ; NumChannels * BytesPerSample + ; Number of bytes for one sample. +WAVE_BitsPerSample: + rw 1 ; 8 = 8 bits, 16 = 16 bits, etc. + +;; DATA header parameters +DATA_SubchunkID: + rd 1 ; Must be equal to "data" - big-endian + ; 0x64617461 +DATA_SubchunkSize: + rd 1 ; NumSamples * NumChannels * BytesPerSample + ; Number of bytes in the data. +;;;;;;;;;;;;;; + +; 15/11/2024 +cursortype: rw 1 + +filehandle: rw 1 + +flags: rb 1 ; (END_OF_FILE flag) + rb 1 + +audio_io_base: rw 1 ; Sound Blaster 16 base port address (220h) + +; 30/05/2024 +wav_file_name: + rb 80 ; wave file, path name (<= 80 bytes) + + rw 1 +; 24/11/2024 +align 4 + +; 23/11/2024 +turn_on_leds: rw 1 ; turn_on_leds procedure pointer (m8,m16,s8,s16) + +; 14/11/2024 +TotalTime: rw 1 ; Total (WAV File) Playing Time in seconds +ProgressTime: rw 1 +count: rw 1 ; byte count of one (wav file) read +LoadedDataBytes: + rd 1 ; total read/load count + +timerticks: rd 1 ; (to eliminate excessive lookup of events in TuneLoop) + ; (in order to get the emulator/qemu to run correctly) +align 16 + +; 24/11/2024 +dma_buffer: ; 32768 bytes +wav_buffer1: rb dma_buffer_size/2 ; 16384 +wav_buffer2: rb dma_buffer_size/2 ; 16384 + +bss_end: diff --git a/trdos386/programs/16bit/sb16play.asm b/trdos386/programs/16bit/sb16play.asm new file mode 100644 index 0000000..d44eeae --- /dev/null +++ b/trdos386/programs/16bit/sb16play.asm @@ -0,0 +1,2880 @@ +; **************************************************************************** +; sb16play.asm (for Retro DOS) +; ---------------------------------------------------------------------------- +; SB16PLAY.COM ! Sound Blaster 16 (DOS) .WAV PLAYER program by Erdogan TAN +; +; 29/11/2024 +; +; [ Last Modification: 18/12/2024 ] +; +; Modified from PLAYWAV9.COM .wav player program by Erdogan Tan, 27/11/2024 +; +; Assembler: FASM 1.73 +; fasm sb16play.asm SB16PLAY.COM +; ---------------------------------------------------------------------------- +; In the visualization part of the code, the source code of Matan Alfasi's +; (Ami-Asaf) player.exe program was partially used. +; ---------------------------------------------------------------------------- +; Previous versions of this Wav Player were based in part on .wav file player +; (for DOS) source code written by Jeff Leyla in 2002. + +; playwav9.asm (27/11/2024) -- ref: ac97play.asm, 29/11/2024 -- + +; INTERRUPT (SRB) + TUNELOOP version ; 24/11/2024 +; (running in DOSBOX, VIRTUALBOX, QEMU is ok) +; Signal Response Byte = message/signal to user about an event/interrupt +; as requested (TuneLoop procedure continuously checks this SRB) +; (TRDOS 386 v2 feature is used here as very simple interrupt handler output) + +; CODE + + ; 13/11/2024 +macro sys_msg op1,op2 +{ ; 30/05/2024 + mov si, op1 ; message + mov bl, op2 ; text color + xor bh, bh ; video page 0 + mov ah, 0Eh + call p_msg +} + + ; 24/11/2024 +macro SbOut op1 +{ +local .wait +.wait: + in al, dx + or al, al + js short .wait + mov al, op1 ; command + out dx, al +} + +; player internal variables and other equates. +; 17/11/2024 +;BUFFERSIZE equ 65520 +; 24/11/2024 +;dma_buffer_size equ 32768 +;LOADSIZE equ 16384 +ENDOFFILE equ 1 ; flag for knowing end of file +; 27/11/2024 +dma_buffer_size equ 44100 +LOADSIZE equ 22050 + +use16 + +org 100h + +_STARTUP: + ; 30/05/2024 + ; Prints the Credits Text. + sys_msg Credits, 0Bh + + ; 30/05/2024 + call setFree ; deallocate unused DOS mem + + ; 17/02/2017 + ; Clear BSS (uninitialized data) area + xor ax, ax ; 0 + mov cx, (bss_end - bss_start)/2 + mov di, bss_start + rep stosw + + ; 24/11/2024 + ; Detect (& Reset) Sound Blaster 16 Audio Device + call DetectSB16 + ;jnc short GetFileName + ; 29/11/2024 + jnc short Player_InitalizePSP + + ; 30/05/2024 +_dev_not_ready: + ; couldn't find the audio device! + sys_msg noDevMsg, 0Fh + jmp Exit + + ;;; + ; 28/11/2024 (ac97play.asm) +Player_InitalizePSP: + mov si, 81h + mov [PSP_CurrentOffset], si + cmp byte [si], 0Dh ; "CR": No command line parameters + ja short Player_ParseParameters + jmp pmsg_usage + +Player_ParseParameters: + ; 18/12/2024 + ; 29/11/2024 + ;mov dx, wav_file_name + cmp byte [IsInSplash], 0 + jna short check_p_command + + call write_audio_dev_info + + mov dx, SplashFileName + jmp short _1 + +check_p_command: + cmp byte [command], 'P' + je short Player_ParsePreviousParameter + + mov si, [PSP_CurrentOffset] + cmp byte [si], 0Dh + ja short Player_ParseNextParameter +jmp_Player_Quit: + jmp Player_Quit + +Player_ParsePreviousParameter: + ; 29/11/2024 + ;mov byte [command], 0 + + mov si, [PSP_CurrentOffset] + + cmp si, 81h + je short Player_ParseNextParameter + + ;; Search for previous space character + dec si + mov cx, 2 +PSPParsePrev_Search: + dec si + mov al, [si] + cmp al, 20h + jne short PSPParsePrev_Search + + cmp si, 81h + jna PSPParsePrev_Copy + loop PSPParsePrev_Search + +PSPParsePrev_Copy: + mov [PSP_CurrentOffset], si + +Player_ParseNextParameter: + ; 29/11/2024 + call GetFileName + jcxz jmp_Player_Quit + + ; 28/11/2024 + mov dx, wav_file_name + ;;; +_1: + +; open the file + ; open existing file + ; 14/11/2024 + ;mov al, OPEN ; open existing file + ; 28/11/2024 + ;mov dx, wav_file_name + call openFile ; no error? ok. + jnc getwavparms ; 14/11/2024 + + ; 28/11/2024 + cmp byte [IsInSplash], 0 + ja Player_SplashScreen + + ; 29/11/2024 + cmp byte [filecount], 0 + ja short check_p_command + + call ClearScreen + sys_msg Credits, 0Bh + call write_audio_dev_info + +wav_file_open_error: +; file not found! + sys_msg noFileErrMsg, 0Ch +_exit_: + jmp Exit + + ; 29/11/2024 + ; 30/05/2024 +GetFileName: + mov di, wav_file_name + mov si, [PSP_CurrentOffset] + xor cx, cx ; 0 +ScanName: + lodsb + ;test al, al + ;jz short a_4 + ; 29/11/2024 + cmp al, 0Dh + jna short a_4 + cmp al, 20h + je short ScanName ; scan start of name. + stosb + mov ah, 0FFh + ;;; + ; 14/11/2024 + ; (max. path length = 64 bytes for MSDOS ?) (*) + ;xor cx, cx ; 0 + ;;; +a_0: + inc ah +a_1: + ;;; + ; 14/11/2024 + inc cx + ;;; + lodsb + stosb + cmp al, '.' + je short a_0 + ; 29/11/2024 + cmp al, 20h + ;and al, al + ;jnz short a_1 + ;;; + ; 14/11/2024 + jna short a_3 + and ah, ah + jz short a_2 + cmp al, '\' + jne short a_2 + mov ah, 0 +a_2: + cmp cl, 75 ; 64+8+'.'+3 -> offset 75 is the last chr + jb short a_1 + ; 29/11/2024 + sub cx, cx + jmp short a_4 +a_3: + ; 29/11/2024 + dec di + ;;; + or ah, ah ; if period NOT found, + jnz short a_4 ; then add a .WAV extension. +SetExt: + ; 29/11/2024 + ;dec di + mov dword [di], '.WAV' ; ! 64+12 is DOS limit + ; but writing +4 must not + ; destroy the following data + ;mov byte [di+4], 0 ; so, 80 bytes path + 0 is possible here + ; 29/11/2024 + add cx, 4 + add di, 4 +a_4: + mov byte [di], 0 + dec si + mov [PSP_CurrentOffset], si + retn + +getwavparms: + ; 14/11/2024 + call getWAVParameters + jc short _exit_ ; nothing to do + + ; 29/11/2024 + cmp byte [IsInSplash], 0 + jna short Player_Template + + ; 29/11/2024 +Player_SplashScreen: + ; 15/11/2024 + ;; Set video mode to 03h (not necessary) + mov ax, 03h + int 10h + + ; 15/11/2024 + ;; Get the cursor type + mov ah, 03h + int 10h + mov [cursortype], cx ; save + + ; 15/11/2024 + ;; Set the cursor to invisible + mov ah, 01h + mov cx, 2607h + int 10h + + ; 15/11/2024 + ;xor dx, dx + ;call setCursorPosition + + ;; Print the splash screen in white + mov ax, 1300h + mov bx, 000Fh + mov cx, 1999 + mov dx, 0 + + mov bp, SplashScreen + int 10h + ;;; + + ;;; + ; 22/11/2024 + ; set wave volume led addresses + mov bx, 13*80*2 + mov bp, 80 + mov di, wleds_addr +wleds_sa_1: + mov cx, 7 +wleds_sa_2: + mov ax, 80*2 + mul cx + add ax, bx + stosw + loop wleds_sa_2 + mov ax, bx + stosw + inc bx + inc bx + dec bp + jnz short wleds_sa_1 + ;;; + + ; 29/11/2024 + cmp word [filehandle], -1 + jne short PlayNow + + ;;; wait for 3 seconds + ;mov cx, 002Dh + ;mov dx, 0C6C0h + ;mov ah, 86h + ;int 15h + ;;; + ; 26/11/2024 + ;mov cx, 3*18 + ; 27/11/2024 + mov cx, 2*18 +getticks: + ; 26/11/2024 + call GetTimerTicks + + cmp ax, [timerticks] + jne short chkws + cmp dx, [timerticks+2] + je short getticks +chkws: + mov [timerticks], ax + mov [timerticks+2], dx + loop getticks + ;;; + + ; 28/11/2024 (ac97play.asm) + mov byte [IsInSplash], 0 + ; 29/11/2024 + jmp Player_ParseNextParameter + + ; 29/11/2024 +Player_Template: + ;;; + ; 23/11/2024 + cmp byte [WAVE_NumChannels], 1 + ja short stolp_s +stolp_m: + cmp byte [WAVE_BitsPerSample], 8 + ja short stolp_m16 +stolp_m8: + mov word [turn_on_leds], turn_on_leds_mono_8bit + jmp short stolp_ok +stolp_m16: + mov word [turn_on_leds], turn_on_leds_mono_16bit + jmp short stolp_ok +stolp_s: + cmp byte [WAVE_BitsPerSample], 8 + ja short stolp_s16 +stolp_s8: + mov word [turn_on_leds], turn_on_leds_stereo_8bit + jmp short stolp_ok +stolp_s16: + mov word [turn_on_leds], turn_on_leds_stereo_16bit + jmp short stolp_ok +stolp_ok: + ; 29/11/2024 + inc byte [filecount] + mov byte [command], 0 + ;;; + + xor dx, dx + call setCursorPosition + + ;; Print the splash screen in white + mov ax, 1300h + mov bx, 000Fh + mov cx, 1999 + mov dx, 0 + + mov bp, Template + int 10h + ;;; + + ; 14/11/2024 + call SetTotalTime + call UpdateFileInfo + +PlayNow: + ; 29/11/2024 + cmp byte [IsInSplash], 0 + ;ja short PlayNow@ + ; 02/12/2024 + jna short PlayNow@ + +;PlayNow@: + ; 24/11/2024 + mov al, 5 ; 15 = max, 0 = min + ; 27/11/2024 + mov [volume], al + ; 15/11/2024 + call SetMasterVolume + + ; 29/11/2024 + ;cmp byte [IsInSplash], 0 + ;ja short _3 + ; + ;call UpdateVolume + ; + ; 02/12/2024 + jmp short _3 + +PlayNow@: + ; reset file loading and EOF parameters + ;mov word [count], 0 + mov word [LoadedDataBytes], 0 + mov word [LoadedDataBytes+2], 0 + mov byte [flags], 0 + mov byte [stopped], 0 + ;jmp short PlayNow@@ + +PlayNow@@: + ;;; + ; + ; 14/11/2024 + call UpdateProgressBar + ;;; + + ; 30/05/2024 + ; playwav4.asm +_2: + call check4keyboardstop ; flush keyboard buffer + jc short _2 ; 07/11/2023 + +; play the .wav file. Most of the good stuff is in here. + +_3: + call PlayWav + + ; 29/11/2024 + ; 28/11/2024 (ac97play.asm) + call closeFile + ;mov dx, wav_file_name + cmp byte [IsInSplash], 0 + ;jna short Exit@@ + jna short _4 ; 29/11/2024 + mov byte [IsInSplash], 0 + ; 29/11/2024 + jmp Player_ParseNextParameter + + ; 29/11/2024 +_4: + cmp byte [command], 'Q' + je short Exit@@ + jmp check_p_command + +Exit@@: + ; 27/11/2024 + ; 24/11/2024 + ; restore old interrupt vector + mov al, [IRQnum] + xor ah, ah ; reset + call set_hardware_int_vector + +; close the .wav file and exit. + +Exit: + ; 15/11/2024 + ;; Restore Cursor Type + mov cx, [cursortype] + cmp cx, 0 + jz short Exit@ + mov ah, 01h + int 10h +Exit@: + ; 29/11/2024 + ;call closeFile +terminate: + mov ax, 4C00h ; bye ! + int 21h +here: + jmp short here ; do not come here ! + + ; 30/05/2024 +pmsg_usage: + sys_msg msg_usage, 0Fh ; 14/11/2024 + jmp short Exit + + ; 30/05/2024 +init_err: + sys_msg msg_init_err, 0Fh + jmp short Exit + + ; 29/11/2024 +Player_Quit: + call ClearScreen + jmp short terminate +ClearScreen: + mov ax, 03h + int 10h + retn + + ; -------------------------------------------- + + ; 24/11/2024 +PlayWav: + mov ax, wav_buffer1 + call loadFromFile + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + mov ax, wav_buffer2 + call loadFromFile + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + ; 25/11/2024 + call SB16Init_play ; initialize SB16 card + ; set sample rate, start to play + jc init_err + + ; 19/11/2024 + mov byte [wleds], 1 + + mov ax, [WAVE_SampleRate] + mov cx, 10 + mul cx + mov cl, 182 + div cx + ; ax = samples per 1/18.2 second + mov cl, byte [WAVE_BlockAlign] + mul cx + mov [wleds_dif], ax ; buffer read differential (distance) + ; for wave volume leds update + ; (byte stream per 1/18.2 second) + ; 27/11/2024 + ; set audio interrupt vector (to user's handler) + mov al, [IRQnum] + mov ah, 1 ; set + mov dx, IRQ_service + call set_hardware_int_vector + + ; 26/11/2024 + call check4keyboardstop + jc _exitt_ + + ; 27/11/2024 + mov byte [IRQnum], 0 + + ; 29/11/2024 + cmp byte [IsInSplash], 0 + jna short TuneLoop + +sL1: + cmp byte [IRQnum], 0 + ja short sL2 + + ; delay + nop + in al, 0EBh + out 0EBh, al + nop + jmp short sL1 + +sL2: + xor byte [half_buffer], 1 + mov byte [IRQnum], 0 + + mov ax, dma_buffer ; wav_buffer1 + cmp byte [half_buffer], 0 + jna short sL3 + + ; load buffer 2 + ;mov ax, wav_buffer2 + add ax, LOADSIZE ; dma_buffer_size/2 +sL3: + call loadFromFile + jnc short sL1 + +sL4: + ; end of file + ;call sb16_stop + ;retn + jmp sb16_stop + + ; 29/11/2024 + ; 27/11/2024 + ; 24/11/2024 +TuneLoop: + ; 30/05/2024 + ; 18/11/2023 (ich_wav4.asm) + ; 08/11/2023 + ; 06/11/2023 +tLWait: + ; 18/11/2024 + cmp byte [stopped], 0 + ; 24/11/2024 + jna short tL1 +tLWait@: ; 21/11/2024 + call checkUpdateEvents + jc _exitt_ + ;;; + ; 29/11/2024 + cmp byte [command], 'N' + je _exitt_ + cmp byte [command], 'P' + je _exitt_ + ;;; + cmp byte [tLO], '0' + je short tLWait + call tLZ + mov byte [tLO], '0' + jmp short tLWait +tL1: + ; 27/11/2024 + ; Check SB 16 interrupt status + cmp byte [IRQnum], 0 + ja short tL3 +tL2: + call checkUpdateEvents + jc _exitt_ + jmp short tLWait +tL3: + xor byte [half_buffer], 1 + + mov byte [IRQnum], 0 + + ; load buffer 1 + ;mov ax, wav_buffer1 + mov ax, dma_buffer ; wav_buffer1 + cmp byte [half_buffer], 0 + jna short tL4 + + ; load buffer 2 + ;mov ax, wav_buffer2 + add ax, LOADSIZE ; dma_buffer_size/2 +tL4: + call loadFromFile + jc short _exitt_ ; end of file + + ; 26/11/2024 + mov al, [half_buffer] + add al, '1' + ; 19/11/2024 + mov [tLO], al + call tL0 + ; 24/11/2024 + ; 14/11/2024 + mov ax, [count] + add [LoadedDataBytes], ax + adc word [LoadedDataBytes+2], 0 + + ; 27/11/2024 + jmp short tL2 + +_exitt_: + ; 24/11/2024 + call sb16_stop + + ;;; + ; 14/11/2024 + call UpdateProgressBar + ;;; + + ; 18/11/2024 +tLZ: + ; 30/05/2024 + mov al, '0' + + ; 06/11/2023 +tL0: + ; 08/11/2023 + ; 05/11/2023 + ; 17/02/2017 - Buffer switch test (temporary) + ; 06/11/2023 + ; al = buffer indicator ('1', '2' or '0' -stop- ) + + push ds + ;push bx + mov bx, 0B800h ; video display page segment + mov ds, bx + sub bx, bx ; 0 + mov ah, 4Eh + mov [bx], ax ; show current play buffer (1, 2) + ;pop bx + pop ds + + retn + +; ------------------------------------------- + +; 27/11/2024 +; ; 24/11/2024 +;IRQ_ack: +; ; 26/11/2024 +; push dx +; push ax +; mov dx, [audio_io_base] +; ;add dx, 0Eh +; add dl, 0Eh ; 8bit DMA-mode int ack +; ; 25/11/2024 +; cmp byte [WAVE_BitsPerSample], 8 +; jna short irq_ack_@ +; inc dl ; 0Fh ; 16bit DMA-mode int ack +;irq_ack_@: +; in al, dx ; SB acknowledge. +; ; 27/11/2024 +; ;mov al, 20h +; ;out 20h, al ; Hardware acknowledge. +;irq_ack_ok: +; ; 26/11/2024 +; pop ax +; pop dx +; retn + +; ------------------------------------------- + + ; 24/11/2024 +SetMasterVolume: + ; al = sound volume (15 = max, 0 = min) + push ax + ; Tell the SB 16 card which register to write + mov dx, [audio_io_base] + ;add dx, 4 ; Mixer chip address port + add dl, 4 + mov al, 22h + out dx, al + pop ax + ;and al, 0Fh + ; Set the volume for both L and R + mov bl, 11h + mul bl + ; Set new volume + mov dx, [audio_io_base] + ;add dx, 5 + add dl, 5 + out dx, al + retn + +; ------------------------------------------- + + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9 audio.s (06/06/2024) + ; DetectSB procedure (06/08/2022, v2.0.5) +DetectSB16: + ; 06/08/2022 - TRDOS 386 v2.0.5 + ; 24/04/2017 +ScanPort: + mov bx, 0210h ; start scanning ports + ; 210h, 220h, .. 260h +ResetDSP: + ; 26/11/2024 + mov dx, bx ; try to reset the DSP. + add dl, 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 + add dl, 08h + mov cx, 100 +WaitID: + in al, dx + or al, al + js short GetID + loop WaitID + jmp short NextPort +GetID: + ;sub dx, 04h + sub dl, 04h + in al, dx + cmp al, 0AAh + je short Found + ;add dx, 04h + add dl, 04h + loop WaitID +NextPort: + ;add bx, 10h ; if not response, + add bl, 10h + ;cmp bx, 260h ; try the next port. + cmp bl, 60h + jbe short ResetDSP + stc + retn +Found: + mov [audio_io_base], bx ; SB Port Address Found! +ScanIRQ: +SetIrqs: + sub al, al ; 0 + mov [IRQnum], al ; reset + ; 27/11/2024 + ;mov [audio_intr], al + + ; 25/11/2024 + ; save IRQ status + in al, 21h ; save the IMR. + mov [IRQstatus], al + + ; ah > 0 -> set IRQ vector + ; al = IRQ number + mov ax, 105h ; IRQ 5 + ; 26/11/2024 + mov dx, IRQ5_service + call set_hardware_int_vector + mov ax, 107h ; IRQ 7 + ; 26/11/2024 + mov dx, IRQ7_service + call set_hardware_int_vector + + mov dx, [audio_io_base] ; tells to the SB to + ;add dx, 0Ch ; generate a IRQ! + add dl, 0Ch +WaitSb: + in al, dx + or al, al + js short WaitSb + mov al, 0F2h + out dx, al + ; 24/11/2024 + xor cx, cx ; wait until IRQ level +WaitIRQ: + mov al, [IRQnum] + cmp al, 0 ; is changed or timeout. + ja short IrqOk + dec cx + jnz short WaitIRQ + jmp short RestoreIrqs +IrqOk: + ;;; + ; 27/11/2024 + mov [audio_intr], al + mov dx, [audio_io_base] + ;add dx, 0Eh + add dl, 0Eh ; 8bit DMA-mode int ack + in al, dx ; SB acknowledge. + inc dx ; 0Fh ; 16bit DMA-mode int ack + in al, dx ; SB 16 acknowledge. + ;;; + mov al, 20h + out 20h, al ; Hardware acknowledge. +RestoreIrqs: + ; ah = 0 -> reset IRQ vector + ; al = IRQ number + mov ax, 5 ; IRQ 5 + call set_hardware_int_vector + mov ax, 7 ; IRQ 7 + call set_hardware_int_vector + + cmp byte [IRQnum], 1 ; IRQ level was changed? + + retn + +; ---------------------------------- + + ; 24/11/2024 +set_hardware_int_vector: + or ah, ah + jnz short shintv_1 ; set user's audio interrupt handler + +rhintv_1: + ; reset the interrupt vector to the old interrupt handler + push ds + cmp al, 5 + jne short rhintv_2 + + ; 25/11/2024 + ; restore IRQ 5 status + mov ah, [IRQstatus] + in al, 21h + and ah, 00100000b ; 20h + or al, ah + out 21h, al + + mov dx, [old_irq5v_o] + mov ds, [old_irq5v_s] +shintv_3: + mov al, 0Dh + mov ah, 25h + int 21h + pop ds + retn + +rhintv_2: + ; 25/11/2024 + ; restore IRQ 7 status + mov ah, [IRQstatus] + in al, 21h + and ah, 10000000b ; 80h + or al, ah + out 21h, al + + mov dx, [old_irq7v_o] + mov ds, [old_irq7v_s] +shintv_4: + mov al, 0Fh + mov ah, 25h + int 21h + pop ds + retn + +shintv_1: + push es + + cmp al, 5 + jne short shintv_2 + + ; INT 0Dh = IRQ 5 (default) interrupt number + + ; 25/11/2024 + ; enable IRQ 5 + ; 26/11/2024 + in al, 21h + and al, 11011111b + out 21h, al + + mov al, 0Fh + mov ah, 35h ; Get Interrupt Vector + int 21h + mov [old_irq5v_s], es + mov [old_irq5v_o], bx + pop es + push ds + ; 27/11/2024 + ;mov dx, IRQ5_service + jmp short shintv_3 + +shintv_2: + ; al = 7 + ; INT 0Fh = IRQ 7 (default) interrupt number + + ; 25/11/2024 + ; enable IRQ 7 + ; 26/11/2024 + in al, 21h + and al, 01111111b + out 21h, al + + mov al, 0Fh + mov ah, 35h ; Get Interrupt Vector + int 21h + mov [old_irq7v_s], es + mov [old_irq7v_o], bx + pop es + push ds + ; 27/11/2024 + ;mov dx, IRQ7_service + jmp short shintv_4 + +IRQ5_service: + mov byte [cs:IRQnum], 5 + iret + +IRQ7_service: + mov byte [cs:IRQnum], 7 + iret + + ; 27/11/2024 +IRQ_service: + push ds + push dx + push ax + ; + push cs + pop ds + mov byte [IRQnum], 5 + mov dx, [audio_io_base] + ;add dx, 0Eh + add dl, 0Eh ; 8bit DMA-mode int ack + cmp byte [WAVE_BitsPerSample], 8 + jna short irq_ack_@ + inc dl ; 0Fh ; 16bit DMA-mode int ack +irq_ack_@: + in al, dx ; SB acknowledge. + ; + mov al, 20h + out 20h, al ; Hardware acknowledge + ; + pop ax + pop dx + pop ds + iret + +; ---------------------------------- + + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9 audio.s (06/06/2024) + ; sb16_stop procedure (06/08/2022, v2.0.5) +sb16_stop: + mov dx, [audio_io_base] + ;add dx, 0Ch + add dl, 0Ch + + mov bl, 0D9h ; exit auto-initialize 16 bit transfer + ; stop autoinitialized DMA transfer mode + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb16_stop_1 + ;mov bl, 0DAh ; exit auto-initialize 8 bit transfer + inc bl +sb16_stop_1: + SbOut bl ; exit auto-initialize transfer command + + xor al, al ; stops all DMA processes on selected channel + + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb16_stop_2 + out 0Ch, al ; clear selected channel register + jmp short sb16_stop_3 + +sb16_stop_2: + out 0D8h, al ; clear selected channel register + +sb16_stop_3: + ; 24/11/2024 + mov byte [stopped], 2 ; stop ! +SbDone: + ;mov dx, [audio_io_base] + ;add dx, 0Ch + SbOut 0D0h + SbOut 0D3h +sb16_stop_4: + retn + +; ---------------------------------- + + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9 audio.s (06/06/2024) + ; sb16_pause procedure (06/08/2022, v2.0.5) +sb16_pause: + mov dx, [audio_io_base] + ;add dx, 0Ch ; Command & Data Port + add dl, 0Ch + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb_pause_1 + ; 8 bit samples + mov bl, 0D0h ; 8 bit DMA mode + jmp short sb_pause_2 +sb_pause_1: + ; 16 bit samples + mov bl, 0D5h ; 16 bit DMA mode +sb_pause_2: + SbOut bl ; bCommand +sb_pause_3: + retn + +; ---------------------------------- + + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9 audio.s (06/06/2024) + ; sb16_continue procedure (06/08/2022, v2.0.5) +sb16_play: +sb16_continue: + mov dx, [audio_io_base] + ;add dx, 0Ch ; Command & Data Port + add dl, 0Ch + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb_cont_1 + ; 8 bit samples + mov bl, 0D4h ; 8 bit DMA mode + jmp short sb_cont_2 +sb_cont_1: + ; 16 bit samples + mov bl, 0D6h ; 16 bit DMA mode +sb_cont_2: + SbOut bl ; bCommand +sb_cont_3: + retn + +; ---------------------------------- + + ; 14/11/2024 + ; INPUT: ds:dx = file name address + ; OUTPUT: [filehandle] = ; -1 = not open +openFile: + mov ax, 3D00h ; open File for read + int 21h + jnc short _of1 + mov ax, -1 + ; cf = 1 -> not found or access error +_of1: + mov [filehandle], ax + retn + +; ---------------------------------- + +; close the currently open file + + ; 14/11/2024 + ; INPUT: [filehandle] ; -1 = not open + ; OUTPUT: none +closeFile: + cmp word [filehandle], -1 + jz short _cf1 + mov bx, [filehandle] + mov ax, 3E00h + int 21h ; close file +_cf1: + retn + +; ---------------------------------- + + ; 14/11/2024 - Erdogan Tan +getWAVParameters: +; reads WAV file header(s) (44 bytes) from the .wav file. +; entry: none - assumes file is already open +; exit: ax = sample rate (11025, 22050, 44100, 48000) +; cx = number of channels (mono=1, stereo=2) +; dx = bits per sample (8, 16) +; bx = number of bytes per sample (1 to 4) + + mov dx, WAVFILEHEADERbuff + mov bx, [filehandle] + mov cx, 44 ; 44 bytes + mov ah, 3Fh + int 21h + jc short gwavp_retn + + cmp ax, 44 + jb short gwavp_retn + + cmp dword [RIFF_Format], 'WAVE' + jne short gwavp_stc_retn + + cmp word [WAVE_AudioFormat], 1 ; Offset 20, must be 1 (= PCM) + ;jne short gwavp_stc_retn + je short gwavp_retn ; 15/11/2024 + + ; 15/11/2024 + ;mov cx, [WAVE_NumChannels] ; return num of channels in CX + ;mov ax, [WAVE_SampleRate] ; return sample rate in AX + ;mov dx, [WAVE_BitsPerSample] + ; return bits per sample value in DX + ;mov bx, [WAVE_BlockAlign] ; return bytes per sample in BX +;gwavp_retn: + ;retn + + ; 27/11/2024 + ; frequency limit (for SB16) = 44100 kHz + ;cmp word [WAVE_SampleRate], 44101 ; 48000 + ;cmc + ;retn + +gwavp_stc_retn: + stc +gwavp_retn: + retn + +; ---- 30/05/2024 (playwav4.asm, 19/05/2024) + +; MEMALLOC.ASM +;-- SETFREE: Release memory not used ---------------- +;-- Input : ES = address of PSP +;-- Output : none +;-- Register : AX, BX, CL and FLAGS are changed +;-- Info : Since the stack-segment is always the last segment in an +; EXE-file, ES:0000 points to the beginning and SS:SP +; to the end of the program in memory. Through this the +; length of the program can be calculated +; call this routine once at the beginning of the program to free up memory +; assigned to it by DOS. + +setFree: + mov bx, 65536/16 ; 4K paragraphs ; 17/02/2017 (Erdogan Tan) + + mov ah, 4Ah ; pass new length to DOS + int 21h + + retn ; back to caller + ; new size (allocated memory) = 64KB + + ; 27/11/2024 +;memAlloc: +;; input: AX = # of paragraphs required +;; output: AX = segment of block to use +; +; push bx +; mov bx, ax +; mov ah, 48h +; int 21h +; pop bx +; retn + +; ---- + +; ///// + + ; 24/11/2024 (SB16 version of playwav8.asm -> playwav9.asm) + ; 30/05/2024 (ich_wav4.asm, 19/05/2024) +loadFromFile: + ; 18/12/2024 + mov word [count], 0 + + ; 07/11/2023 + test byte [flags], ENDOFFILE ; have we already read the + ; last of the file? + jz short lff_0 ; no + stc + retn + +lff_0: + ; 24/11/2024 + ; 08/11/2023 + mov di, ax ; save buffer address + ; 17/11/2024 + mov bx, [filehandle] + + ; 24/11/2024 + mov cx, LOADSIZE + mov dx, ax ; buffer address + + ; 24/11/2024 + ; load/read file + ; bx = file handle + ; ds = cs + ; ds:dx = buffer + ; cx = read count + mov ah, 3Fh + int 21h + jc short lff_4 ; error ! + + ; 14/11/2024 + mov [count], ax + + cmp ax, cx + je short endLFF + ; 24/11/2024 + ; di = buffer address + add di, ax +lff_3: + call padfill ; blank pad the remainder + ;clc ; don't exit with CY yet. + or byte [flags], ENDOFFILE ; end of file flag +endLFF: + retn +lff_4: + ; 08/11/2023 + mov al, '!' ; error + call tL0 + + xor ax, ax + jmp short lff_3 + +; entry ds:ax points to last byte in file +; cx = target size +; note: must do byte size fill +; destroys bx, cx +; +padfill: + ; 24/11/2024 + ; di = offset (to be filled with ZEROs) + ; es = ds = cs + ; ax = di = number of bytes loaded + ; cx = buffer size (> loaded bytes) + sub cx, ax + xor ax, ax + cmp byte [WAVE_BitsPerSample], 8 + ja short padfill@ + mov al, 80h +padfill@: + rep stosb + retn +; ///// + +write_audio_dev_info: + ; 30/05/2024 + sys_msg msgAudioCardInfo, 0Fh + retn + +write_sb16_dev_info: + ; 24/11/2024 + mov ax, [audio_io_base] + mov bl, al + mov dl, bl + and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgBasePort+2], al + mov bl, dl + shr bl, 4 + mov al, [bx+hex_chars] + mov [msgBasePort+1], al + mov bl, ah + mov dl, bl + ;and bl, 0Fh + mov al, [bx+hex_chars] + mov [msgBasePort], al + + xor ax, ax + ;mov al, [IRQnum] + ; 27/11/2024 + mov al, [audio_intr] + ;mov cl, 10 + ;div cl + ;add ah, 30h + ;mov [msgIRQ], ah + ; 25/11/2024 + add al, 30h + mov [msgIRQ], al + + call clear_window + mov dh, 13 + mov dl, 0 + call setCursorPosition + + sys_msg msgSB16Info, 07h + + retn + +; -------------------------------------------------------- +; 24/11/2024 - Sound Blaster 16 initialization +; -------------------------------------------------------- + + ; 25/11/2024 + ; 24/11/2024 + ; Ref: TRDOS 386 Kernel v2.0.9, audio.s (06/06/2024) + ; SbInit_play procedure (06/08/2022, v2.0.5) +SB16Init_play: + mov ax, ds + mov dx, ax + shr dx, 12 + shl ax, 4 + add ax, dma_buffer + adc dx, 0 + mov bx, ax ; linear address + ; dx = page number + + mov cx, dma_buffer_size + + cmp byte [WAVE_BitsPerSample], 16 + jne short sbInit_0 ; set 8 bit DMA buffer + + ; 26/11/2024 + mov ax, dx ; page number + + ; convert byte count to word count + ; 26/11/2024 + ;dec cx + shr cx, 1 + dec cx ; word count - 1 + + ; convert byte offset to word offset + shr ax, 1 + rcr bx, 1 + ; 26/11/2024 + ;shr bx, 1 + + ; 16 bit DMA buffer setting (DMA channel 5) + mov al, 05h ; set mask bit for channel 5 (4+1) + out 0D4h, al + + xor al, al ; stops all DMA processes on selected channel + out 0D8h, al ; clear selected channel register + + mov al, bl ; byte 0 of DMA buffer offset in words (physical) + out 0C4h, al ; DMA channel 5 port number + + mov al, bh ; byte 1 of DMA buffer offset in words (physical) + out 0C4h, al + + ; 26/11/2024 + and dl, 0FEh ; clear bit 0 (not necessary, it will be ignored) + + mov al, dl ; byte 2 of DMA buffer address (physical) + out 8Bh, al ; page register port addr for channel 5 + + mov al, cl ; low byte of DMA count - 1 + out 0C6h, al ; count register port addr for channel 5 + + mov al, ch ; high byte of DMA count - 1 + out 0C6h, al + + ; channel 5, read, autoinitialized, single mode + mov al, 59h + out 0D6h, al ; DMA mode register port address + + mov al, 01h ; clear mask bit for channel 5 + out 0D4h, al ; DMA mask register port address + + jmp short ResetDsp + +sbInit_0: + dec cx ; byte count - 1 + + ; 8 bit DMA buffer setting (DMA channel 1) + mov al, 05h ; set mask bit for channel 1 (4+1) + out 0Ah, al ; DMA mask register + + xor al, al ; stops all DMA processes on selected channel + out 0Ch, al ; clear selected channel register + + mov al, bl ; byte 0 of DMA buffer address (physical) + out 02h, al ; DMA channel 1 port number + + mov al, bh ; byte 1 of DMA buffer address (physical) + out 02h, al + + mov al, dl ; byte 2 of DMA buffer address (physical) + out 83h, al ; page register port addr for channel 1 + + mov al, cl ; low byte of DMA count - 1 + out 03h, al ; count register port addr for channel 1 + + mov al, ch ; high byte of DMA count - 1 + out 03h, al + + ; channel 1, read, autoinitialized, single mode + mov al, 59h + out 0Bh, al ; DMA mode register port address + + mov al, 01h ; clear mask bit for channel 1 + out 0Ah, al ; DMA mask register port address + +ResetDsp: + mov dx, [audio_io_base] + ;add dx, 06h + add dl, 06h + mov al, 1 + out dx, al + + in al, dx + in al, dx + in al, dx + in al, dx + + xor ax, ax + out dx, al + + mov cx, 100 +WaitId: + mov dx, [audio_io_base] + add dl, 0Eh + in al, dx + or al, al + ;js short sb_GetId + ; 26/11/2024 + jns short sb_next + ;loop WaitId + ;jmp sb_Exit + +sb_GetId: + mov dx, [audio_io_base] + ;add dx, 0Ah + add dl, 0Ah + in al, dx + cmp al, 0AAh + je short SbOk +sb_next: + loop WaitId + stc + retn +SbOk: + mov dx, [audio_io_base] + ;add dx, 0Ch + add dl, 0Ch + SbOut 0D1h ; Turn on speaker + SbOut 41h ; 8 bit or 16 bit transfer + mov bx, [WAVE_SampleRate] ; sampling rate (Hz) + SbOut bh ; sampling rate high byte + SbOut bl ; sampling rate low byte + + ; 25/11/2024 + +StartDMA: + ; autoinitialized mode + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit samples + je short sb_play_1 + ; 8 bit samples + mov bx, 0C6h ; 8 bit output (0C6h) + cmp byte [WAVE_NumChannels], 2 ; 1 = mono, 2 = stereo + jb short sb_play_2 + mov bh, 20h ; 8 bit stereo (20h) + jmp short sb_play_2 +sb_play_1: + ; 16 bit samples + mov bx, 10B6h ; 16 bit output (0B6h) + cmp byte [WAVE_NumChannels], 2 ; 1 = mono, 2 = stereo + jb short sb_play_2 + add bh, 20h ; 16 bit stereo (30h) +sb_play_2: + ; PCM output (8/16 bit mono autoinitialized transfer) + SbOut bl ; bCommand + SbOut bh ; bMode + ; 25/11/2024 + mov bx, dma_buffer_size/2 + ; half buffer size + cmp byte [WAVE_BitsPerSample], 16 ; 16 bit DMA + jne short sb_play_3 + shr bx, 1 ; byte count to word count (samples) +sb_play_3: + dec bx ; wBlkSize is one less than the actual size + SbOut bl + SbOut bh + + ; 24/11/2024 + ;mov byte [stopped], 0 ; playing ! +sb_Exit: + retn + +; -------------------------------------------------------- +; 14/11/2024 - Erdogan Tan +; -------------------------------------------------------- + + ; 29/11/2024 + ; 24/11/2024 (SB16 version) +checkUpdateEvents: + call check4keyboardstop + jc short c4ue_ok + + ; 18/11/2024 + push ax ; * + or ax, ax + jz c4ue_cpt + + ; 18/11/2024 + cmp al, 20h ; SPACE (spacebar) ; pause/play + jne short ch4ue_chk_s + cmp byte [stopped], 0 + ja short ch4ue_chk_ps + ; pause + call sb16_pause ; 24/11/2024 + ; 27/11/2024 + mov byte [stopped], 1 + jmp c4ue_cpt +ch4ue_chk_ps: + cmp byte [stopped], 1 + ja short ch4ue_replay + ; continue to play (after a pause) + call sb16_play ; 24/11/2024 + ; 27/11/2024 + mov byte [stopped], 0 + jmp c4ue_cpt +ch4ue_replay: + ; 19/11/2024 + pop ax ; * + pop ax ; return address + ; 24/11/2024 + ; initialize (again) + ; and start playing (after stop) + call SB16Init_play + mov al, [volume] + call SetMasterVolume ; 24/11/2024 + mov byte [stopped], 0 + ; 24/11/2024 + mov byte [half_buffer], 1 + call move_to_beginning + jmp PlayWav + +ch4ue_chk_s: + cmp al, 'S' ; stop + jne short ch4ue_chk_fb + cmp byte [stopped], 0 + ja short c4ue_cpt ; Already stopped/paused + call sb16_stop ; 24/11/2024 + ; 19/11/2024 + mov byte [tLO], 0 + jmp short c4ue_cpt + +ch4ue_chk_fb: + ; 17/11/2024 + cmp al, 'F' + jne short c4ue_chk_b + call Player_ProcessKey_Forwards + jmp short c4ue_cpt + + ; 18/11/2024 +c4ue_ok: + retn + +c4ue_chk_b: + cmp al, 'B' + ;;jne short c4ue_cpt + ; 19/11/2024 + ;jne short c4ue_chk_h + ; 29/11/2024 + jne short c4ue_chk_n + call Player_ProcessKey_Backwards + jmp short c4ue_cpt + + ;;; + ; 29/11/2024 +c4ue_chk_n: + cmp al, 'N' + je short c4ue_nps +c4ue_chk_p: + cmp al, 'P' + jne short c4ue_chk_h +c4ue_nps: + mov byte [stopped], 3 + jmp short c4ue_cpt + ;;; + +c4ue_chk_h: + ; 19/11/2024 + cmp al, 'H' + jne short c4ue_chk_cr + mov byte [wleds], 0 + call write_sb16_dev_info + mov dh, 24 + mov dl, 79 + call setCursorPosition +c4ue_chk_cr: + ; 19/11/2024 + cmp al, 0Dh ; ENTER/CR key + jne short c4ue_cpt + ; 23/11/2024 + xor bx, bx + mov bl, [wleds] + inc bl + and bl, 0Fh + jnz short c4ue_sc + inc bx +c4ue_sc: + mov [wleds], bl + shr bl, 1 + mov al, [bx+colors] + jnc short c4ue_sc_@ + or al, 10h ; blue (dark) background +c4ue_sc_@: + mov [ccolor], al + ;;; +c4ue_cpt: + ;push ds + ;mov bx, 40h + ;mov ds, bx + ;mov bx, 6Ch ; counter (INT 08h, 18.2 ticks per sec) + ;;cli + ;mov ax, [bx] + ;mov dx, [bx+2] + ;;sti + ;pop ds + ; 26/11/2024 + call GetTimerTicks + + ; 18/11/2024 + pop cx ; * + cmp dx, [timerticks+2] + jne short c4ue_utt + cmp ax, [timerticks] + ; 18/11/2024 + je short c4ue_skip_utt +c4ue_utt: + mov [timerticks], ax + mov [timerticks+2], dx + jmp short c4ue_cpt_@ +c4ue_skip_utt: + ; 18/11/2024 + and cx, cx + jz short c4ue_ok +c4ue_cpt_@: + ; 18/11/2024 + cmp byte [stopped], 0 + ja short c4ue_ok + + call CalcProgressTime + + cmp ax, [ProgressTime] + ; 23/11/2024 + je short c4ue_uvb + ; same second, no need to update + + call UpdateProgressBar + + ; 23/11/2024 +c4ue_uvb: + cmp byte [wleds], 0 + jna short c4ue_vb_ok + + call UpdateWaveLeds + +c4ue_vb_ok: + retn + + ; 26/11/2024 +GetTimerTicks: + push ds + mov bx, 40h + mov ds, bx + mov bx, 6Ch ; counter (INT 08h, 18.2 ticks per sec) + ;cli + mov ax, [bx] + mov dx, [bx+2] + ;sti + pop ds + retn + +; -------------------------------------------------------- +; 19/05/2024 - (playwav4.asm) ich_wav4.asm +; -------------------------------------------------------- + + ; 29/11/2024 + ; 24/11/2024 (SB16 version) +check4keyboardstop: + ; 19/05/2024 + ; 08/11/2023 + ; 04/11/2023 + mov ah, 1 + int 16h + ;clc + jz short _cksr + + xor ah, ah + int 16h + + ; 29/11/2024 + mov [command], al + + ;;; + ; 19/05/2024 (change PCM out volume) + cmp al, '+' + jne short p_1 + + mov al, [volume] + ; 24/11/2024 + cmp al, 15 + jnb short p_3 + inc al + jmp short p_2 +p_1: + cmp al, '-' + jne short p_4 + + mov al, [volume] + ; 24/11/2024 + cmp al, 0 + jna short p_3 + dec al +p_2: + mov [volume], al + ; 24/11/2024 + call SetMasterVolume + ;call UpdateVolume + ;;clc + ;retn + jmp UpdateVolume +_cksr: + ; 18/11/2024 + xor ax, ax + ;clc +p_3: + retn +p_4: + ; 17/11/2024 + cmp ah, 01h ; ESC + je short p_q + cmp al, 03h ; CTRL+C + je short p_q + + ; 18/11/2024 + cmp al, 20h + je short p_r + + ; 19/11/2024 + cmp al, 0Dh ; CR/ENTER + je short p_r + + and al, 0DFh + + ; 29/11/2024 + mov [command], al + + ;cmp al, 'B' + ;je short p_r + ;cmp al, 'F' + ;je short p_r + + ; 29/11/2024 + ;cmp al, 'N' + ;je short p_r + ;cmp al, 'P' + ;je short p_r + + cmp al, 'Q' + ;je short p_q + je short p_quit ; 29/11/2024 + + clc + retn + + ;;; +;_cskr: +p_q: + ; 29/11/2024 + mov byte [command], 'Q' +p_quit: + stc +p_r: + retn + +; -------------------------------------------------------- + + ; 14/11/2024 +setCursorPosition: + ; dh = Row + ; dl = Column + mov ax, 0500h + int 10h + mov ah, 02h + mov bh, 00h + ;mov dh, setCursorPosition_Row + ;mov dl, setCursorPosition_Column + int 10h + retn + +; -------------------------------------------------------- +; 14/11/2024 +; (Ref: player.asm, out_cs.asm, Matan Alfasi, 2017) + +;; NAME: SetTotalTime +;; DESCRIPTION: Calculates the total time in seconds in file +;; INPUT: DATA_SubchunkSize, WAVE_SampleRate, WAVE_BlockAlign +;; OUTPUT: CurrentTotalTime=Total time in seconds in file, +;; Output on the screen of the total time in seconds + +SetTotalTime: + ;; Calculate total seconds in file + mov ax, [DATA_SubchunkSize] + mov dx, [DATA_SubchunkSize + 2] + mov bx, [WAVE_SampleRate] + div bx + xor dx, dx + + mov bx, [WAVE_BlockAlign] + + div bx + + mov [TotalTime], ax + + mov bl, 60 + div bl + + ;; al = minutes, ah = seconds + push ax ; ** + push ax ; * + + mov dh, 24 + mov dl, 42 + call setCursorPosition + + pop ax ; * + xor ah, ah + mov bp, 2 + call PrintNumber + + mov dh, 24 + mov dl, 45 + call setCursorPosition + + pop ax ; ** + mov al, ah + xor ah, ah + ;mov bp, 2 + ;jmp short PrintNumber + +; -------------------------------------------------------- + +PrintNumber: + ; bp = digits + ; ax = binary number + mov bx, 10 + xor cx, cx +printNumber_CutNumber: + inc cx + xor dx, dx + div bx + push dx + cmp cx, bp + je short printNumber_printloop + jmp printNumber_CutNumber + +printNumber_printloop: + pop ax + mov dl, '0' + add dl, al + mov ah, 02h + int 21h + loop printNumber_printloop + + retn + +; -------------------------------------------------------- + + ; 14/11/2024 - Erdogan Tan +SetProgressTime: + ;; Calculate playing/progress seconds in file + call CalcProgressTime + +UpdateProgressTime: + ; ax = (new) progress time + + mov [ProgressTime], ax + + mov bl, 60 + div bl + + ;; al = minutes, ah = seconds + push ax ; ** + push ax ; * + + mov dh, 24 + mov dl, 33 + call setCursorPosition + + pop ax ; * + xor ah, ah + mov bp, 2 + call PrintNumber + + mov dh, 24 + mov dl, 36 + call setCursorPosition + + pop ax ; ** + mov al, ah + xor ah, ah + ;mov bp, 2 + jmp short PrintNumber + +; -------------------------------------------------------- + + ; 17/11/2024 + ; 14/11/2024 +CalcProgressTime: + mov ax, [LoadedDataBytes] + mov dx, [LoadedDataBytes+2] + mov bx, ax + or bx, dx + jz short cpt_ok + + mov bx, [WAVE_SampleRate] + div bx + xor dx, dx + mov bx, [WAVE_BlockAlign] + div bx +cpt_ok: + ; ax = (new) progress time + retn + +; -------------------------------------------------------- +; 14/11/2024 +; (Ref: player.asm, out_cs.asm, Matan Alfasi, 2017) + +;; DESCRIPTION: Update file information on template +;; PARAMS: WAVE parameters and other variables +;; REGS: AX(RW) +;; VARS: CurrentFileName, WAVE_SampleRate, +;; RETURNS: On-screen file info is updated. + +UpdateFileInfo: + ;; Print File Name + mov dh, 9 + mov dl, 23 + call setCursorPosition + + mov si, wav_file_name + + ;;; + ; 14/11/2024 + ; skip directory separators + ; (note: asciiz string, max. 79 bytes except zero tail) + mov bx, si +chk4_nxt_sep: + lodsb + cmp al, '\' + je short chg_fpos + and al, al + jz short chg_fpos_ok + jmp short chk4_nxt_sep +chg_fpos: + mov bx, si + jmp short chk4_nxt_sep +chg_fpos_ok: + mov si, bx ; file name (without its path/directory) + ;;; + + call PrintString + + ;; Print Frequency + mov dh, 10 + mov dl, 23 + call setCursorPosition + mov ax, [WAVE_SampleRate] + mov bp, 5 + call PrintNumber + + ;; Print BitRate + mov dh, 9 + mov dl, 57 + call setCursorPosition + mov ax, [WAVE_BitsPerSample] + mov bp, 2 + call PrintNumber + + ;; Print Channel Number + mov dh, 10 + mov dl, 57 + call setCursorPosition + mov ax, [WAVE_NumChannels] + mov bp, 1 + call PrintNumber + + ;call UpdateVolume + ;retn + +; -------------------------------------------------------- + + ; 24/11/2024 + ; 14/11/2024 +UpdateVolume: + ;; Print Volume + mov dh, 24 + mov dl, 75 + call setCursorPosition + + mov al, [volume] + + mov bl, 100 + mul bl + + mov bl, 15 ; 24/11/2024 + div bl + + xor ah, ah + mov bp, 3 + ;call PrintNumber + ;retn + jmp PrintNumber + +; 24/11/2024 +; 29/05/2024 +; 19/05/2024 +volume: db 12 + +; -------------------------------------------------------- + + ; 14/11/2024 +PrintString: + ; si = string address + mov bx, 0Fh ; white + mov ah, 0Eh ; write as tty +printstr_loop: + lodsb + or al, al + jz short printstr_ok + int 10h + jmp short printstr_loop +printstr_ok: + retn + +; -------------------------------------------------------- + + ; 14/11/2024 + ; (Ref: player.asm , Matan Alfasi, 2017) + ; (Modification: Erdogan Tan, 14/11/2024) + + PROGRESSBAR_ROW equ 23 + +UpdateProgressBar: + call SetProgressTime ; 14/11/2024 + + mov ax, [ProgressTime] +UpdateProgressBar@: + mov dx, 80 + mul dx + mov bx, [TotalTime] + div bx + + ;; Push for the 'Clean' part + push ax ; ** + push ax ; * + + ;; Set cursor position + mov dh, PROGRESSBAR_ROW + mov dl, 0 + call setCursorPosition + + pop ax ; * + or ax, ax + jz short UpdateProgressBar_Clean + +UpdateProgressBar_DrawProgress: + mov cx, ax + mov ah, 09h + mov al, 223 + mov bx, 0Fh + int 10h + +UpdateProgressBar_DrawCursor: + ;mov ax, cx + mov dh, PROGRESSBAR_ROW + ;mov dl, al + dec cx + mov dl, cl + call setCursorPosition + + mov ah, 09h + mov al, 223 + mov bx, 0Ch + mov cx, 1 + int 10h + +UpdateProgressBar_Clean: + pop ax ; ** + mov cx, ax + mov dh, PROGRESSBAR_ROW + mov dl, al + call setCursorPosition + + neg cx + add cx, 80 ; cf = 1 ; + + ;; CX = No. of times to print a clean character + ;mov cx, 80 + ;sub cx, ax + ;; 09h = Write character multiple times + mov ah, 09h + ;; 32 = Space ASCII code + ;mov al, 32 + ;mov bx, 0 + ; 15/11/2024 + mov al, 223 + mov bx, 8 + int 10h + ; 14/11/2024 + clc ; + + + retn + +; -------------------------------------------------------- +; 17/11/2024 + +Player_ProcessKey_Backwards: + ;; In order to go backwards 5 seconds: + ;; Update file pointer to the beginning, skip headers + mov cl, 'B' + jmp short Player_ProcessKey_B_or_F + +Player_ProcessKey_Forwards: + ;; In order to fast-forward 5 seconds, set the file pointer + ;; to CUR_SEEK + 5 * Freq + + mov cl, 'F' + ;jmp short Player_ProcessKey_B_or_F + +Player_ProcessKey_B_or_F: + ; 17/11/2024 + ; 04/11/2024 + ; (Ref: player.asm, Matan Alfasi, 2017) + + ; 04/11/2024 + mov ax, 5 + mov bx, [WAVE_BlockAlign] + mul bx + mov bx, [WAVE_SampleRate] + mul bx + ; dx:ax = transfer byte count for 5 seconds + + ; 17/11/2024 + cmp cl, 'B' + mov bx, [LoadedDataBytes] + mov cx, [LoadedDataBytes+2] + jne short move_forward ; cl = 'F' +move_backward: + sub bx, ax + sbb cx, dx + jnc short move_file_pointer +move_to_beginning: + xor cx, cx ; 0 + xor bx, bx ; 0 + jmp short move_file_pointer +move_forward: + add bx, ax + adc cx, dx + jc short move_to_end + cmp cx, [DATA_SubchunkSize+2] + ja short move_to_end + jb short move_file_pointer + cmp bx, [DATA_SubchunkSize] + jna short move_file_pointer +move_to_end: + mov bx, [DATA_SubchunkSize] + mov cx, [DATA_SubchunkSize+2] +move_file_pointer: + mov dx, bx + mov [LoadedDataBytes], dx + mov [LoadedDataBytes+2], cx + add dx, 44 ; + header + adc cx, 0 + + ; seek + mov bx, [filehandle] + mov ax, 4200h + int 21h + + retn + +; -------------------------------------------------------- + + ; 19/11/2024 +UpdateWaveLeds: + ; 23/11/2024 + call reset_wave_leds + ;call word [turn_on_leds] + ;retn + jmp word [turn_on_leds] + +; -------------------------------------------------------- + + ; 23/11/2024 + ; 19/11/2024 +clear_window: + xor ax, ax + jmp short clear_window_@ + +reset_wave_leds: + ; 23/11/2024 + ;mov al, 254 + ;mov ah, 8 ; gray (dark) + mov ax, 08FEh +clear_window_@: + push es + mov di, 0B800h + mov es, di + mov di, 2080 ; 13*80*2 + mov cx, 8*80 ; 8 rows + rep stosw + pop es + retn + +; -------------------------------------------------------- + + ; 24/11/2024 + ; 19/11/2024 +turn_on_leds_stereo_16bit: + ; 25/11/2024 + push es + + cmp byte [tLO],'2' + jne short tol_buffer_1 + +tol_buffer_2: + ; 21/11/2024 + mov si, wav_buffer2 ; 24/11/2024 + jmp short tol_@ + +tol_buffer_1: + cmp byte [tLO],'1' + ;jne short tol_retn + ; 23/11/2024 + jne short tol_clc_retn + + mov si, wav_buffer1 ; 24/11/2024 +tol_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + ; 24/11/2024 + mov cx, LOADSIZE + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol_o_@ + cmp si, cx + jna short tol_s_buf +tol_o_@: + mov si, cx + jmp short tol_s_buf + +tol_clc_retn: + ; 23/11/2024 + clc +tol_retn: + ; 25/11/2024 + pop es + retn + +tol_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol_s_buf: + mov [pbuf_o], si + +tol_buf_@: + ; 25/11/2024 + mov di, 0B800h + mov es, di + ;mov di, (20*80*2)-2 + + ; 23/11/2024 + mov cx, 80 + + ; 22/11/2024 + mov bx, wleds_addr + + ; 27/11/2024 + add si, [pbuf_s] +tol_fill_c: + ; 22/11/2024 + ;inc di + ;inc di + ;push di + lodsw ; left + ;shr ax, 8 + mov dx, ax + lodsw ; right + ;shr ax, 8 + ;;; + ; 23/11/2024 + add ax, dx + shr ax, 8 + ;shr ax, 9 + add al, 80h + shr ax, 5 + ;;; + ;shr ax, 6 + + push bx + shl ax, 1 + add bx, ax + ; 25/11/2024 + mov di, [bx] + ; 23/11/2024 + mov ah, [ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol_fill_c + + jmp short tol_retn + + + ; 24/11/2024 + ; 23/11/2024 +turn_on_leds_mono_16bit: + ; 25/11/2024 + push es + + cmp byte [tLO],'2' + jne short tol2_buffer_1 + +tol2_buffer_2: + mov si, wav_buffer2 ; 24/11/2024 + jmp short tol2_@ + +tol2_buffer_1: + cmp byte [tLO],'1' + jne short tol_clc_retn + + mov si, wav_buffer1 ; 24/11/2024 +tol2_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol2_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + ; 24/11/2024 + mov cx, LOADSIZE + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol2_o_@ + cmp si, cx + jna short tol2_s_buf +tol2_o_@: + mov si, cx + jmp short tol2_s_buf + +;tol2_clc_retn: +; clc +;tol2_retn: +; ; 25/11/2024 +; pop es +; retn + +tol2_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol2_s_buf: + mov [pbuf_o], si + +tol2_buf_@: + ; 25/11/2024 + mov di, 0B800h + mov es, di + + mov cx, 80 + + mov bx, wleds_addr + + ; 27/11/2024 + add si, [pbuf_s] +tol2_fill_c: + lodsw + shr ax, 8 + add al, 80h + shr ax, 5 + push bx + shl ax, 1 + add bx, ax + ; 25/11/2024 + mov di, [bx] + mov ah, [ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol2_fill_c + + jmp tol_retn + + ; 24/11/2024 +turn_on_leds_stereo_8bit: + ; 25/11/2024 + push es + + cmp byte [tLO],'2' + jne short tol3_buffer_1 + +tol3_buffer_2: + mov si, wav_buffer2 ; 24/11/2024 + jmp short tol3_@ + +tol3_buffer_1: + cmp byte [tLO],'1' + jne short tol3_clc_retn + + mov si, wav_buffer1 ; 24/11/2024 +tol3_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol3_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + ; 24/11/2024 + mov cx, LOADSIZE + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol3_o_@ + cmp si, cx + jna short tol3_s_buf +tol3_o_@: + mov si, cx + jmp short tol3_s_buf + +tol3_clc_retn: + clc +tol3_retn: + ; 25/11/2024 + pop es + retn + +tol3_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol3_s_buf: + mov [pbuf_o], si + +tol3_buf_@: + ; 25/11/2024 + mov di, 0B800h + mov es, di + + mov cx, 80 + + mov bx, wleds_addr + + ; 27/11/2024 + add si, [pbuf_s] +tol3_fill_c: + lodsw ; left (al), right (ah) + add al, ah + add al, 80h + xor ah, ah + ;shr ax, 6 + shr ax, 5 + push bx + shl ax, 1 + add bx, ax + ; 25/11/2024 + mov di, [bx] + mov ah, [ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol3_fill_c + + jmp short tol3_retn + + ; 24/11/2024 + ; 23/11/2024 +turn_on_leds_mono_8bit: + ; 25/11/2024 + push es + + cmp byte [tLO],'2' + jne short tol4_buffer_1 + +tol4_buffer_2: + mov si, wav_buffer2 ; 24/11/2024 + jmp short tol4_@ + +tol4_buffer_1: + cmp byte [tLO],'1' + jne short tol3_clc_retn + + mov si, wav_buffer1 ; 24/11/2024 +tol4_@: + ; calculate differential + cmp [pbuf_s], si + jne short tol4_ns_buf + mov bx, [wleds_dif] + mov si, [pbuf_o] + ; 24/11/2024 + mov cx, LOADSIZE + sub cx, bx ; sub cx, [wleds_dif] + add si, bx + jc short tol4_o_@ + cmp si, cx + jna short tol4_s_buf +tol4_o_@: + mov si, cx + jmp short tol4_s_buf + +;tol4_clc_retn: +; clc +;tol4_retn: +; ; 25/11/2024 +; pop es +; retn + +tol4_ns_buf: + mov [pbuf_s], si + xor si, si ; 0 +tol4_s_buf: + mov [pbuf_o], si + +tol4_buf_@: + ; 25/11/2024 + mov di, 0B800h + mov es, di + + mov cx, 80 + + mov bx, wleds_addr + + ; 27/11/2024 + add si, [pbuf_s] +tol4_fill_c: + lodsb + ; 27/11/2024 + add ax, ax + add al, 80h + xor ah, ah + shr ax, 5 + push bx + shl ax, 1 + add bx, ax + ; 25/11/2024 + mov di, [bx] + mov ah, [ccolor] + mov al, 254 + mov [es:di], ax + pop bx + add bx, 16 + loop tol4_fill_c + + jmp tol3_retn + +; -------------------------------------------------------- + +; 30/05/2024 +print_msg: + mov bx, 07h +p_msg: + push es + push bp + push cx + push dx + + push ds + pop es + mov bp, si + mov ah, 03h ; Return cursor position (in DX) + ; bh = video page number + int 10h + xor cx, cx +p_msg_0: + lodsb + or al, al + jz short p_msg_1 + inc cx + jmp short p_msg_0 +p_msg_1: + or cx, cx + jz short p_msg_x + ; cx = number of chars + ; dx = screen (cursor) position + ; bl = color/attribute + ; bh = video page number + ; es:bp = string buffer + ;mov al, 1 ; attribute in BL, update cursor pos + ;mov ah, 13h ; write character string + mov ax, 1301h + int 10h +p_msg_x: + pop dx + pop cx + pop bp + pop es + retn + +; -------------------------------------------------------- +; -------------------------------------------------------- + +; DATA + +Credits: + db 'Tiny WAV Player for Retro DOS by Erdogan Tan. ' + db 'December 2024.',10,13,0 + db '18/12/2024', 10,13,0 + +msgAudioCardInfo: + db 'for Sound Blaster 16 audio device.', 10,13,0 + +msg_usage: + db 'usage: SB16PLAY <...>',10,13,0 ; 29/11/2024 + + ; 24/11/2024 +noDevMsg: + db 'Error: Unable to find Sound Blaster 16 audio device!' + db 10,13,0 + +noFileErrMsg: + db 'Error: file not found.',10,13,0 + +msg_error: ; 30/05/2024 + +; 24/11/2024 +msg_init_err: + db 0Dh, 0Ah + db "Sound Blaster 16 hardware initialization error !" + db 0Dh, 0Ah, 0 + +; 19/11/2024 +; 03/06/2017 +hex_chars: db "0123456789ABCDEF", 0 + +; 24/11/2024 +msgSB16Info: db 0Dh, 0Ah + db " Audio Hardware: Sound Blaster 16", 0Dh, 0Ah + db " Base Port: " +msgBasePort: db "000h", 0Dh, 0Ah + db " IRQ: " +msgIRQ: db 30h + db 0Dh, 0Ah, 0 + +; -------------------------------------------------------- +; 14/11/2024 (Ref: player.asm, Matan Alfasi, 2017) + +SplashScreen: + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " _______ ______ _______. ", 221, 219, 222 + db 221, 219, 222, " | \ / __ \ / | ", 221, 219, 222 + db 221, 219, 222, " | .--. | | | | | (----` ", 221, 219, 222 + db 221, 219, 222, " | | | | | | | \ \ ", 221, 219, 222 + db 221, 219, 222, " | '--' | `--' | .----) | ", 221, 219, 222 + db 221, 219, 222, " |_______/ \______/ |_______/ ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " .______ __ ___ ____ ____ _______ .______ ", 221, 219, 222 + db 221, 219, 222, " | _ \ | | / \ \ \ / / | ____|| _ \ ", 221, 219, 222 + db 221, 219, 222, " | |_) | | | / ^ \ \ \/ / | |__ | |_) | ", 221, 219, 222 + db 221, 219, 222, " | ___/ | | / /_\ \ \_ _/ | __| | / ", 221, 219, 222 + db 221, 219, 222, " | | | `----./ _____ \ | | | |____ | |\ \----. ", 221, 219, 222 + db 221, 219, 222, " | _| |_______/__/ \__\ |__| |_______|| _| `._____| ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " WELCOME TO ", 221, 219, 222 + db 221, 219, 222, " DOS PLAYER ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db 221, 219, 222, " ", 221, 219, 222 + db " " +Template: + db 201, 78 dup(205), 187 + db 186, 33 dup(219), " DOS Player ", 33 dup(219), 186 + db 204, 78 dup(205), 185 + db 186, 33 dup(32), " User Guide ", 33 dup(32), 186 + ; 29/11/2024 + db 186, 6 dup(32), " Play/Pause ", 4 dup(32), "/