Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Playing .wav files on DOSBox's Sound Blaster device

I want to make a program in assembly/8086/masm/dosbox that turns the keyboard into various musical instruments so i need to be able to play some .wav files to produce the required sounds.I am aware of beep char and producing sound via sending frequencies to pc speaker (ports 41h,42h and 61h) but both ways are clearly not going to get me there.

I searched around and found that I need to use int 21h for opening files, knowledge of .wav format and knowledge of sound programming using Sound Blaster.

Unfortunately I couldn't find any helpful documentation on how to use the Sound Blaster in Dosbox (or in general) so kindly if you can help me with my problem of how to play .wav files on dosbox or if you have any workarounds I am all ears ( more accurate eyes).

like image 460
Bombo Avatar asked Jan 29 '26 03:01

Bombo


1 Answers

This present a demo program that plays a specific WAV file (to avoid introducing a RIFF parser to the already too-long-for-SO code. The program has been tested in DOSBox, but a lot of things can go wrong on different configurations.

Finally, I was forced to split the code into two answers.
This is part 2.

dsp.asm

.8086
.MODEL SMALL

 FORMAT_MONO     EQU 00h
 FORMAT_STEREO   EQU 20h
 FORMAT_SIGNED   EQU 10h
 FORMAT_UNSIGNED EQU 00h


_CODE SEGMENT PARA PUBLIC 'CODE' USE16
 ASSUME CS:_CODE


 ResetDSP:
  push ax
  push dx

  ;Set reset bit

  mov dx, REG_DSP_RESET
  mov al, 01h
  out dx, al

  ;Wait 3 us

  in al, 80h
  in al, 80h
  in al, 80h

  ;Clear reset bit

  xor al, al
  out dx, al

  ;Poll BS until bit 7 is set

  mov dx, REG_DSP_READ_BS

 _rd_poll_bs:
  in al, dx
  test al, 80h
 jz _rd_poll_bs

  ;Poll data until 0aah

  mov dx, REG_DSP_READ

 _rd_poll_data:
  in al, dx
  cmp al, 0aah
 jne _rd_poll_data

  pop dx
  pop ax
  ret



 ;AL = command/data
 WriteDSP:
  push dx
  push ax

  mov dx, REG_DSP_WRITE_BS

 _wd_poll:
  in al, dx
  test al, 80h
 jz _wd_poll

  pop ax

  mov dx, REG_DSP_WRITE_DATA
  out dx, al

  pop dx
  ret


 ;Return AL 
 ReadDSP:
  push dx

  mov dx, REG_DSP_READ_BS

 _rdd_poll:
  in al, dx
  test al, 80h
 jz _rdd_poll

  pop ax

  mov dx, REG_DSP_READ
  in al, dx

  pop dx
  ret


 ;AX = sampling
 SetSampling:
  push dx

  xchg al, ah

  push ax

  mov al, DSP_SET_SAMPLING_OUTPUT
  call WriteDSP

  pop ax

  call WriteDSP

  mov al, ah
  call WriteDSP

  pop dx
  ret


 ;Starts a playback

 ;AX = Sampling
 ;BL = Mode
 ;CX = Size
 StartPlayback:

  ;Set sampling

  call SetSampling

  ;Start playback command

  mov al, DSP_DMA_16_OUTPUT_AUTO
  call WriteDSP
  mov al, bl            
  call WriteDSP                            ;Format 
  mov al, cl
  call WriteDSP                            ;Size (Low)
  mov al, ch   
  call WriteDSP                            ;Size (High)

  ret

 ;Stops the playback

 StopPlayback:
   push ax

   mov al, DSP_STOP_DMA_16
   call WriteDSP

   pop ax
   ret

_CODE ENDS

buffer.asm

.8086
.MODEL SMALL


 ;Block size is 1/100 of a second at 44100 samplings per seconds

 BLOCK_SIZE      EQU 44100 / 100 * 2

 ;Buffer size allocated, it is twice the BLOCK_SIZE because there are two blocks.
 ;Size is doubled again so that we are sure to find an area that doesn't cross a
 ;64KiB boundary
 ;Total buffer size is about 3.5 KiB

 BUFFER_SIZE     EQU  BLOCK_SIZE * 2 * 2

_DATI SEGMENT PARA PUBLIC 'DATA' USE16

 ;This is the buffer

 buffer            db BUFFER_SIZE DUP(0)


 bufferOffset      dw OFFSET buffer
 bufferSegment     dw _DATI

_DATI ENDS


_CODE SEGMENT PARA PUBLIC 'CODE' USE16
 ASSUME CS:_CODE, DS:_DATI


 ;Allocate a buffer of size BLOCK_SIZE * 2 that doesn't cross
 ;a physical 64KiB
 ;This is achieved by allocating TWICE as much space and than
 ;Aligning the segment on 64KiB if necessary


 AllocateBuffer:
  push bx
  push cx
  push ax
  push dx

  ;Compute linear address of the buffer

  mov bx, _DATI
  shr bx, 0ch
  mov cx, _DATI
  shl cx, 4
  add cx, OFFSET buffer
  adc bx, 0                                 ;BX:CX = Linear address



  ;Does it starts at 64KiB?

  test cx, cx
 jz _ab_End                                ;Yes, we are fine

  mov dx, cx
  mov ax, bx

  ;Find next start of 64KiB

  xor dx, dx
  inc ax

  push ax
  push dx

  ;Check if next boundary is after our buffer

  sub dx, cx
  sub ax, bx

  cmp dx, BUFFER_SIZE / 2

  pop dx
  pop ax

 jae _ab_end



  mov bx, dx
  and bx, 0fh
  mov WORD PTR [bufferOffset], bx

  mov bx, ax
  shl bx, 0ch
  shr dx, 04h
  or bx, dx
  mov WORD PTR [bufferSegment], bx

 _ab_end:
  clc

  pop dx
  pop ax
  pop cx
  pop bx

  ret


 ;Free the buffer

 FreeBufferIfAllocated:

  ;Nothing to do

  ret




_CODE ENDS
like image 149
Margaret Bloom Avatar answered Jan 31 '26 20:01

Margaret Bloom



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!