Author Topic: reproducing a file wav through the speaker  (Read 23966 times)

Offline avcaballero

  • Full Member
  • **
  • Posts: 133
  • Country: es
    • Abre los Ojos al Ensamblador
reproducing a file wav through the speaker
« on: April 09, 2010, 08:23:43 AM »
Hello. Actually, this example doesn't work and I'm looking for any help.

My purpose is reproducing a file wav through the speaker. The original information comes from Phil Inch in his Game Developers Magazine. As I think, the file wav only has bytes with amplitudes of the sound wave and, since the speaker takes 60 microseconds to attain its maximum distension, only we should use a maximum value of 72. The trick consists in to turn on and to turn off the speaker before its cone has reached its maximum possible extension in order to simulate different amplitudes to standard square wave. We have to reprogram PIT channel 0 to achieve it.

Phil's program doesn't work in my PC, simply it doesn't emit any sound. To begin with, Phil sends the code 90h to the PIT command register, i.e. produce an interruption ( 8h ) when finishing the count. It pretends halt the processor, with a HLT, until the interruption takes place (speaker cone is increasing meanwhile). After that, we repeat the same operation with another byte from the wav file. I need to put a 96h command to generate a square wave in order to emit a sound from the speaker. Besides, I don't like stopping system until generating an interruption, I prefer to use a variable to be changed in the Int 08h that I will intercept. In theory, the mechanism is the same.

I present a shortened version of my program in order to be simpler to revise and anderstand. I want to reproduce something like it should be. The duration of the notes could become regulated manually with the constant cOversamp. I believe that the main problem is in the "Sound" routine and how interpreting the byte that we will send to the speaker. In theory this byte should not surpass 72. I have tried several possibilities and no one emits a similar sound it should go out to.

Can anybody help me, please?

Code: [Select]
; ----------------------------------------------------------------------------
; -      TITLE   : Plays wav files through the speaker COM-NASM              -
; -----                                                                  -----
; -      AUTHOR  : Alfonso Víctor Caballero Hurtado                          -
; -                http://www.abreojosensamblador.net/                       -
; -----                                                                  -----
; -      VERSION : 1.0                                                       -
; -----                                                                  -----
; -      COMMENT : Based on Phil Inch, Game Developers Magazine              -
; ----------------------------------------------------------------------------

cOversamp      EQU   52000                  ; Oversampling (perhaps we should modify it)

[org 100h]
[section .text]
  CALL     SaveValSPK
  CALL     OpenFile
  CALL     ReadHead
  CALL     PlayWav
  CALL     WrtMsg
  ; Salimos al DOS
  MOV      AX, 4C00h                   
  INT      21h

  SaveValSPK:
    ; Purpose   : Save 61h port original value
    ; In        : None
    ; Out       : vbSpeaker
    ; Destroys  : AX
    IN       AL, 61h
    AND      AL, 11111100b
    MOV      BYTE [vbSpeaker], AL
  RET

  OpenFile:
    ; Purpose   : Open wav file
    ; In        : None
    ; Out       : HandleEntrada
    ; Destroys  : AX, DX
    MOV      AX, 3D00h                      ; Open for reading
    MOV      DX, SourceFile                 ; DS:DX ASCIIZ filepathname
    INT      21h
    MOV      WORD [Handle], AX              ; We don't check fails
  RET

  ReadFile:
    ; Purpose   : Extract bytes from file to DS:DX
    ; In        : CX: number of bytes to read, DX: offset
    ; Out       : Readed bytes in some buffer, AX number of bytes actually read
    ; Destroys  : AX, BX
    MOV      AH, 3Fh                        ; Función leer fichero
    MOV      BX, WORD [Handle]
    INT      21h                            ; We don't check fails
  RET

  ReadHead:
    ; Purpose   : Extract wav head from file to MWavCab
    ; In        : None
    ; Out       : MWavCab
    ; Destroys  : CX, DX
    MOV      CX, LTWavCab
    MOV      DX, MWavCab
    CALL     ReadFile
  RET

  SetCanal2:
    ; Purpose   : Program channel 2 from PIT
    ; In        : None
    ; Out       : None
    ; Destroys  : AX
;     MOV      AL, 90h                        ; 90h = 10010000b. 10-canal2,01-byte bajo (Phil)
;                                             ;       000-Mode0 Int at the end
    MOV      AL, 96h                        ; 96h = 10010110b. 10-canal2,01-byte bajo (Mine)
                                            ;       011-Square wave
    OUT      43h, AL                       
    MOV      AL, BYTE [vbSpeaker]
    OR       AL, 3                          ; Conectamos el canal 2 al altavoz
    OUT      61h, AL                        ; Lo hacemos
  RET

  SpkOn:
    ; Purpose   : Turns on the speaker
    ; In        : None
    ; Out       : None
    ; Destroys  : AX
    MOV      AL, BYTE [vbSpeaker]
    OR       AL, 3
    OUT      61h, AL
  RET

  SpkOff:
    ; Purpose   : Turns off the speaker
    ; In        : None
    ; Out       : None
    ; Destroys  : AX
    MOV      AL, BYTE [vbSpeaker]
    AND      AL, 11111101b
    OUT      61h, AL
  RET

; Here resides the problem, I believe. That is, how treating the byte that we receive
;   Sound:
;     ; Purpose   : Plays a note on the speaker using the PIT
;     ;             method1: we play it if positive, else turn off the speaker
;     ; In        : AL: byte from wav file
;     ; Out       : None
;     ; Destroys  : AX, CX
;     OR       AL, AL
;     JL       L_SD_Apagar
;       CALL     SpkOn
;       JMP      L_SD_Fin
;     L_SD_Apagar:
;       CALL     SpkOff
;     L_SD_Fin:
;     MOV      CX, cOversamp
;     LOOP     $
;   RET

;   Sound:
;     ; Purpose   : Plays a note on the speaker using the PIT
;     ;             method2: we play it if positive, else turn off the speaker (max 72)
;     ; In        : AL: byte from wav file
;     ; Out       : None
;     ; Destroys  : AX, CX
;     OR       AL, AL
;     JL       L_SD_Apagar
;       CMP      AL, 72
;       JB       L_SD_Next1
;         MOV      AL, 72
;       L_SD_Next1:
;       CALL     SpkOn
;       JMP      L_SD_Fin
;     L_SD_Apagar:
;       NEG      AL
;       CMP      AL, 72
;       JB       L_SD_Next2
;         MOV      AL, 72
;       L_SD_Next2:
;       CALL     SpkOff
;     L_SD_Fin:
;     MOV      CX, cOversamp
;     LOOP     $
;   RET

  Sound:
    ; Purpose   : Plays a note on the speaker using the PIT
    ;             method3: we play 72*AL/256 (max 72)
    ; In        : AL: byte from wav file
    ; Out       : None
    ; Destroys  : AX, CX
    MUL      BYTE [SeventyTwo]
    XCHG     AL, AH
    CALL     SpkOn
    MOV      CX, cOversamp
    LOOP     $
    CALL     SpkOff
  RET

  PlayWav:
    ; Purpose   : Plays wav file through the speaker
    ; In        : None
    ; Out       : MWavCab
    ; Destroys  : CX, DX
    ; Calculate counter
    MOV      DX, 12h
    MOV      AX, 34DCh
    DIV      WORD [MWavCab+SampRat]       ; Dividimos por la tasa de muestreo
    MOV      WORD [Contador], AX
    CALL     SetCanal2                    ; Programamos el canal 2
    L_PW_Bucle:
      MOV      CX, 1                      ; One byte
      MOV      DX, vbTmp
      CALL     ReadFile
      OR       AX, AX
      JZ       L_PW_Fin
      MOV      AL, BYTE [vbTmp]
      CALL     Sound
      MOV      AH, 1
      INT      16h
    JZ       L_PW_Bucle
    MOV      AH, 0
    INT      16h
    L_PW_Fin:
  RET
 
  WrtMsg:
    ; Purpose   : Write final message onto the screen
    ; In        : None
    ; Out       : None
    ; Destroys  : AX, DX
    ; Calculate counter
    MOV      DX, msg
    MOV      AH, 9
    INT      21h
  RET

[section .bss]
  STRUC  TWavCab
    ; Trozo Riff - 12 bytes
    Riff:    RESB 4                            ; 0 - 3 "RIFF"
    RLen:    RESD 1                            ; 4 - 7 total size
    Wave:    RESB 4                            ; 8 - 11 "WAVE"
    ; Trozo Formato - 24 bytes
    Fmt:     RESB 4                            ; 0 - 3 "fmt "
    FLen:    RESD 1                            ; 4 - 7 Format chunk size
    Uno:     RESW 1                            ; 8 - 9 Always 1
    Canal:   RESW 1                            ; 10 - 11 Number of channels
    SampRat: RESD 1                            ; 12 - 15 Sample rate
    BxSec:   RESD 1                            ; 16 - 19 Bytes per second
    BxSamp:  RESW 1                            ; 20 - 21 Bytes per sample
    BixSam:  RESW 1                            ; 22 - 23 Bits per sample
    ; Trozo de Datos - 8 bytes
    Datos:   RESB 4                            ; 0 - 3 "data"
    DLen:    RESD 1                            ; 4 - 7 Following data chunk size
  ENDSTRUC

  LTWavCab   EQU TWavCab_size

[section .data]
  SourceFile DB "zAryx2.wav", 0
  msg        DB "That's all folks!$"
  SeventyTwo DB 72
  MWavCab:
    ISTRUC TWavCab
    IEND

[section .bss]
  Handle    RESW 1
  Contador  RESW 1
  vbSpeaker RESB 1
  vbTmp     RESB 1
  vwCont    RESW 1

You won't believe it, but I couldn't find the way to upload the entire zip...

Offline avcaballero

  • Full Member
  • **
  • Posts: 133
  • Country: es
    • Abre los Ojos al Ensamblador
Re: reproducing a file wav through the speaker
« Reply #1 on: April 09, 2010, 08:28:50 AM »
By the way. Maybe someone wants to give a RadASM template for Nasm. Also it is needed to modify Nasm.ini in order to utilise GoLink instead Alink.

Thank you