From 8c144ac04fa9a9460bcfe927669d6d78cb3120b3 Mon Sep 17 00:00:00 2001 From: maxotaku11niku Date: Thu, 24 Aug 2023 18:22:12 +0100 Subject: [PATCH] Added stereo support Added support for stereo sound in a way that allows the program to fall back on mono when necessary. This is not a breaking change. --- 98video.txt | 14 ++++- Makefile | 2 +- doscom.lds | 12 +++- src/98videoplayer.asm | 128 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 145 insertions(+), 11 deletions(-) diff --git a/98video.txt b/98video.txt index bc66cc0..49d8995 100644 --- a/98video.txt +++ b/98video.txt @@ -19,14 +19,18 @@ Header: Screen resolution spec (bit 4) 0x00 640x400 (pixel aspect 1:1) 0x10 640x200 (pixel aspect 1:2) - Unused (bit 5-7) + Audio channel spec (bit 5) + 0x00 Mono + 0x20 Stereo (if ADPCM, else also mono) + Unused (bit 6-7) high byte uint8 Unused 0x0A uint4[16][3] colour table (rg br gb ...) for all 16 initial colours Frame Data: Audio Data: 0x00 uint16 length of audio data (16-bit words, n) -0x02 uint16[n] Audio data +0x02 uint16[n] Audio data (mean level) +var uint16[n] Audio data (stereo difference, only if stereo specified, otherwise it is left out) ADPCM: The audio data is in 8-bit signed ADPCM format which expands to signed 16-bit PCM Buzzer audio: @@ -38,6 +42,12 @@ ADPCM codec: abs(data) <= 0x18: decrement bitshift by 1 after this sample. abs(data) >= 0x68: increment bitshift by 1 after this sample. (My decoder actually uses an acceleration table it creates at startup just to speed things up by using an acceptable amount of memory) +Stereo encoding: + The mean level signal (m) is always included as this is the mono signal. Stereo is encoded through a difference signal (d), which uses the same ADPCM encoding as the mean level signal. + To get the right (r) and left (l) signals, we apply the following transformations: + l = m + d + r = m - d + This ordering is arbitrary. Video Frame Header: 0x00 low byte UUUU IRGB planes to update (automatically determines how many plane sections and which planes they correspond to, U is reserved for 256 colour board compatibility) high byte 0000 000P update palette? diff --git a/Makefile b/Makefile index efa6eea..1e26506 100644 --- a/Makefile +++ b/Makefile @@ -29,4 +29,4 @@ $(PROCESS)/98videop.o : $(BUILD)/$(OFILES) ld -T doscom.lds -m i386pe -o $(PROCESS)/98videop.o $^ $(BUILD)/$(OFILES) : $(SOURCES)/$(ASMFILES) - as $< -o $@ -march=i386 -mtune=i386 --32 \ No newline at end of file + as $< -o $@ -march=i386 -mtune=i286 --32 \ No newline at end of file diff --git a/doscom.lds b/doscom.lds index f046765..33ebce9 100644 --- a/doscom.lds +++ b/doscom.lds @@ -1,9 +1,15 @@ /* Simple GNU ld linker script to build a DOS .COM executable */ +MEMORY +{ + segment (wxa) : ORIGIN = 0, LENGTH = 64K +} + SECTIONS { . = 0x100; - .text : { *(.text) } - .data : { *(.data) } - .bss : { *(.bss) } + .text ALIGN(0x10) : { *(.text) } >segment + .data ALIGN(0x10) : { *(.data) *(.rdata) } >segment + .bss (NOLOAD) : ALIGN(0x10) { *(.bss) } >segment + /DISCARD/ : { *(.rdata$zzz) *(.reloc) } >segment } \ No newline at end of file diff --git a/src/98videoplayer.asm b/src/98videoplayer.asm index 3769aee..266c617 100644 --- a/src/98videoplayer.asm +++ b/src/98videoplayer.asm @@ -23,7 +23,7 @@ ;#FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ;#OTHER DEALINGS IN THE SOFTWARE. -.arch i486 +.arch i286 .intel_syntax noprefix .code16 ;#This is intended to run in real mode @@ -221,6 +221,9 @@ video_read_end_magicnum: ;#Set various options int 0x18 ;#PC98 CRT BIOS: Set display options (640x200, display page 0, colour mode) pop ax video_read_fullres: + and bx, 0x0020 + shr bx, 5 + mov cs:is_stereo, bl and ax, 0x0007 mov cs:audiospec, ax xor ax, ax @@ -581,19 +584,25 @@ PROCEDURE_frameloop: ;#void frameloop(void) mov cx, ax push cx mov cs:filebuffercurpos, si + mov bl, cs:is_stereo + test bl, bl + jz notstereo + shl ax, 1 +notstereo: shl ax, 1 add ax, 4 call PROCEDURE_tryreadsection mov al, cs:using_86 mov si, cs:filebuffercurpos - cmp al, 0x01 - jne frameloop_buzaudio + test al, al + jz frameloop_buzaudio jmp frameloop_86audio ;#Decode ADPCM for buzzer PCM frameloop_buzaudio: pop bp + push bp mov di, cs:samplebufferptr push cs pop es @@ -643,14 +652,23 @@ frameloop_buzaudio_pushloop: mov cx, 0x0010 rep stosb ;#Add padding to reduce clipping(?) pop cx + pop ax + mov bl, cs:is_stereo + test bl, bl + jz no_skip_stereodata + shl ax, 1 + add si, ax ;#Needed to skip over unused stereo difference data (buzzer audio is forced mono) +no_skip_stereodata: jmp frameloop_videodata_process frameloop_86audio: ;#Decode ADPCM for 86 PCM + test bl, bl + jnz frameloop_86audio_stereo pop di mov dx, 0xA46C mov cx, cs:adpcmshiftval -frameloop_86audio_pushloop: +frameloop_86audio_mono_pushloop: lodsw push ax xor ah, ah @@ -690,7 +708,104 @@ frameloop_86audio_pushloop: out dx, al mov cl, cs:[bx+accelerationtable_adpcm] dec di - jnz frameloop_86audio_pushloop + jnz frameloop_86audio_mono_pushloop + jmp frameloop_videodata_process + +frameloop_86audio_stereo: + pop bp + mov dx, 0xA46C + mov cl, cs:adpcmshiftval + mov ch, cs:adpcmshiftval_diff + mov bx, bp + shl bx, 1 +frameloop_86audio_stereo_pushloop: + lodsw + push ax + xor ah, ah + mov di, cx + and di, 0x00FF + shl di, 8 + add di, ax + cbw + shl ax, cl + add ax, cs:lastsample + mov cs:lastsample, ax + mov cl, cs:[di+accelerationtable_adpcm] + mov al, [bx+si-2] + xor ah, ah + xchg cl, ch + mov di, cx + and di, 0x00FF + shl di, 8 + add di, ax + cbw + shl ax, cl + add ax, cs:lastsample_diff + mov cs:lastsample_diff, ax + mov cl, cs:[di+accelerationtable_adpcm] + mov di, ax + mov ax, cs:lastsample + push bx + mov bx, ax + add ax, di + xchg al, ah ;#output left sample + out dx, al + xchg al, ah + out dx, al + sub bx, di + mov ax, bx + xchg al, ah ;#output right sample + out dx, al + xchg al, ah + out dx, al + pop bx + xchg cl, ch + pop ax + xchg al, ah + xor ah, ah + mov di, cx + and di, 0x00FF + shl di, 8 + add di, ax + cbw + shl ax, cl + add ax, cs:lastsample + mov cs:lastsample, ax + mov cl, cs:[di+accelerationtable_adpcm] + mov al, [bx+si-1] + xor ah, ah + xchg cl, ch + mov di, cx + and di, 0x00FF + shl di, 8 + add di, ax + cbw + shl ax, cl + add ax, cs:lastsample_diff + mov cs:lastsample_diff, ax + mov cl, cs:[di+accelerationtable_adpcm] + mov di, ax + mov ax, cs:lastsample + push bx + mov bx, ax + add ax, di + xchg al, ah ;#output left sample + out dx, al + xchg al, ah + out dx, al + sub bx, di + mov ax, bx + xchg al, ah ;#output right sample + out dx, al + xchg al, ah + out dx, al + pop bx + xchg cl, ch + dec bp + jnz frameloop_86audio_stereo_pushloop + mov cs:adpcmshiftval_diff, ch + xor ch, ch + add si, bx frameloop_videodata_process: mov cs:adpcmshiftval, cx @@ -944,6 +1059,7 @@ frameloop_stopplaneread: old_timer_vector_offset: .word 0x0000 old_timer_vector_segment: .word 0x0000 using_86: .byte 0x00 + is_stereo: .byte 0x00 current_buzzer_shiftdown: .byte 0x00 old_interrupt_mask: .byte 0x00 current_sample_midpoint: .word 0x0000 @@ -959,7 +1075,9 @@ frameloop_stopplaneread: framesleft: .word 0x0000 audiospec: .word 0x0000 lastsample: .word 0x0000 + lastsample_diff: .word 0x0000 adpcmshiftval: .word 0x0000 + adpcmshiftval_diff: .word 0x0000 numframes_lo: .word 0x0000 numframes_hi: .word 0x0000 ;#32-bit to support very long videos filehandle: .word 0x0000