home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 September / Simtel20_Sept92.cdr / msdos / music / dousound.arc / DOUSOUND.ASM next >
Assembly Source File  |  1989-09-22  |  8KB  |  272 lines

  1. Title  DouSound - Two channel sound routine
  2.  
  3. ; Written by Ori Berger
  4. ; Phone number 972-(0)3-540-1519
  5. ;
  6. Comment @
  7.  
  8. This program simulates 2 channel sound using the regular PC speaker. This
  9. program was written so that is will work on any speed, not depending on
  10. the CPU. This is doneby re-vectoring and re-speeding interrupt 8 (IRQ0).
  11.  
  12. The tune here was taken from 'The great Gianna sisters', and was composed
  13. by Chris Huelsback (somewhere in england). The data is given in half tones,
  14. so
  15.  
  16. C = 1
  17. C#= 2
  18. D = 3
  19.  
  20. etc.
  21.  
  22. Try replacing SetC1 with SetC2 because the channels sound differently,
  23. and which channel is better as the main channel (40h,40h,43h) is depending
  24. on the tune.
  25.  
  26. Should be assembled under MASM 5.0 or TASM 1.0, and either LINK and EXE2BIN
  27. or TLINK /T.
  28.  
  29. @
  30.  
  31. SetC1    Macro  Rate
  32.          Mov    Al,0b6h                          ; Set channel two speed!
  33.          Out    43h,Al                           ; Set mode
  34.          Mov    Ax,Rate
  35.          Out    42h,Al
  36.          Mov    Al,Ah
  37.          Out    42h,Al
  38.          Endm
  39.  
  40. SetC2    Macro  Rate
  41.          Mov    Al,036h
  42.          Out    43h,Al
  43.          Mov    Ax,Rate
  44. ; This is a test - now we should try alternating frequencies!
  45.          Shl    Ax,1
  46.          Shl    Ax,1
  47.          Shl    Ax,1
  48.          Shr    Rate,1
  49.          Shr    Rate,1
  50.          Shr    Rate,1
  51.          Shr    Rate,1
  52.          Add    Ax,Rate
  53.          Shr    Ax,1
  54.          Shr    Ax,1
  55.          Shr    Ax,1
  56. ; The following line should be removed if there's no need for timing.
  57.          Mov    Cs:C2Rate,Ax
  58. ;
  59.          Out    40h,Al
  60.          Mov    Al,Ah
  61.          Out    40h,Al
  62.          Endm
  63.  
  64. Speed    Equ 4                ; speed in 1/18.2 of second per note.
  65.  
  66. Code     Segment
  67.          Assume CS:Code,Ds:Code,Es:Code,Ss:Code
  68.          Org    100h
  69. Start:   Jmp    Program
  70.  
  71. ; This area holds timing parameters - count, rate, etc.
  72. ; C2 rate is the current rate for channel 2 - must be used to determine time.
  73. ; Tick18 is used both as a counter and as an indicator of the time to add to
  74. ; the bios ticker value.
  75. ; C2 roll is an accumulated value - an roll over means 1/18.2 of a second.
  76.  
  77. C2Rate   Dw     ?
  78. C2Roll   Dw     ?
  79. Ticks18  Dw     ?
  80.  
  81. OldInt8  Dw     ?,?
  82.  
  83. Int8     Proc   Far
  84.          Push   Ax
  85.          In     Al,61h
  86.          Xor    Al,2
  87.          Out    61h,Al
  88.  
  89. ; These commands should be removed if timing is not dealt through clock 0
  90.  
  91.          Mov    Ax,Cs:C2Rate
  92.          Add    Cs:C2Roll,Ax
  93.          Adc    Cs:Ticks18,0
  94.  
  95. ; This ends the commands to be removed
  96.  
  97.          Mov    Al,20h
  98.          Out    20h,Al
  99.          Pop    Ax
  100.          Iret
  101. Int8     Endp
  102.  
  103. ; FreqTabl is the Frequency table (compiled!) for lowest octave.
  104.  
  105. FreqTabl Dw     4560,4304,4062,3834,3619,3416,3224,3043,2873,2711,2559,2416
  106. ;                C    C#   D    D#   E    F    F#   G    G#   A    A#   B
  107.  
  108. Sound    Proc   Near         ; Sound CX on channel 1, DX on channel 2
  109.          Push   Ax
  110.          SetC1  Dx
  111.          SetC2  Cx
  112.          Pop    Ax
  113.          Ret
  114. Sound    Endp
  115.  
  116. AlterOct Db     0
  117.  
  118. MakeTAB  Proc   Near         ; Builds a table of output values - from DS:SI and DS:DX into ES:DI, -1 is terminal!
  119.          Push   Ax
  120.          Push   Si
  121.          Push   Dx
  122.          Push   Bx
  123.          Push   Di
  124.          Push   Cx
  125.          Cld
  126.          Mov    Ch,12              ; Length of octave - speed constant!
  127. Loop001: Lodsb                     ; Get next note.
  128.          Inc    Al                 ; is it a terminal?
  129.          Jz     MkTABend           ; if so, EXIT!
  130.          Dec    Al                 ; Restore orig value.
  131.          Add    Al,Ch              ; I've discovered higher sounds better!
  132.          Cbw                       ; If not, we have to find the FREQUENCY!
  133.          Mov    Cl,Ah              ; AH is zero from the CBW.
  134. Loop002: Cmp    Al,Ch              ; Now do octave shifting!
  135.          Jb     NoAdj              ; if in range 0-11 no need to do octave adjusting.
  136.          Sub    Al,Ch              ; Put it in range
  137.          Inc    Cl                 ; And mark one shift.
  138.          Jmp    Loop002            ; Repeat till in range
  139. NoAdj:   Shl    Ax,1               ; It is a WORD table.
  140.          Mov    Bx,Ax              ; AX cannot address
  141.          Mov    Ax,FreqTabl[Bx]    ; Get the exact count for known octave
  142.          Or     Cl,Cl              ; Are we using octave 1? (NoAdjAg means No Adjust Again)
  143.          Jz     NoAdjAg            ; If so, no need to shift on 8086 (80286/Vx0 must not shift!)
  144.          Shr    Ax,Cl              ; Now the RIGHT count is in Ax
  145. NoAdjAg: Stosw                     ; Put it in the output buffer.
  146.          Xor    Ah,Ah              ; Zero AH again.
  147.          Xchg   Dx,Si              ; Now, to the second channel....
  148.          Jmp    Loop001            ; Redo this operation (channels alternate)
  149. MkTABend:
  150.          Xor    Ax,Ax              ; Zero AX
  151.          Stosw                     ; Put two terminals in output
  152.          Stosw
  153.          Pop    Cx
  154.          Pop    Di
  155.          Pop    Bx
  156.          Pop    Dx
  157.          Pop    Si
  158.          Pop    Ax
  159.          Ret
  160. MakeTAB  Endp
  161.  
  162. Before   Proc   Near               ; BEFORE action handler.
  163.          Push   Ax                 ; 1. Steal INT8.
  164.          Push   Bx
  165.          Push   Es
  166.          Push   Dx
  167.          Push   Ds
  168.          Mov    Ax,3508h           ; Dos code for GetIntVec (8)
  169.          Int    21h
  170.          Mov    OldInt8[0],Bx      ; Offset
  171.          Mov    OldInt8[2],Es      ; Segment
  172.          Mov    Dx,Offset Int8     ; Point DS:DX at int 8 routine
  173.          Mov    Ax,Cs
  174.          Mov    Ds,Ax
  175.          Mov    Ax,2508h
  176.          Int    21h
  177.          In     Al,61h             ; Now we need to gate channel 2 to the speaker
  178.          Or     Al,1               ; GATE value
  179.          Out    61h,Al             ; We must not disturb other bits.
  180.          Mov    Dx,3f2h
  181.          Mov    Al,0ch
  182.          Out    Dx,Al
  183.          Pop    Ds
  184.          Pop    Dx
  185.          Pop    Es
  186.          Pop    Bx
  187.          Pop    Ax
  188.          Ret
  189. Before   Endp
  190.  
  191. After    Proc   Near
  192.          Push   Ax
  193.          Push   Dx
  194.          Push   Ds
  195.          Mov    Ax,2508h
  196.          Lds    Dx,Dword Ptr OldInt8
  197.          Int    21h
  198.          Mov    Al,36h
  199.          Out    43h,Al
  200.          Sub    Al,Al
  201.          Out    40h,Al
  202.          Out    40h,Al
  203.          In     Al,61h
  204.          And    Al,Not 3
  205.          Out    61h,Al
  206.          Pop    Ds
  207.          Pop    Dx
  208.          Pop    Ax
  209.          Ret
  210. After    Endp
  211.  
  212. Play     Proc   Near               ; Actually plays the buffer. (DS:SI)
  213. Loop003: Lodsw
  214.          Or     Ax,Ax
  215.          Jz     Terminal
  216.          Mov    Cx,Ax
  217.          Lodsw
  218.          Or     Ax,Ax
  219.          Jz     Terminal
  220.          Mov    Dx,Ax
  221.          Call   Sound
  222.          Mov    Ticks18,0
  223. Loop004: Cmp    Ticks18,Speed
  224.          Jb     Loop004
  225.          Jmp    Loop003
  226. Terminal:
  227.          Ret
  228. Play     Endp
  229.  
  230. Program  Proc   Near
  231.          Call   Before
  232.          Mov    Si,Offset Channel1
  233.          Mov    Dx,Offset Channel2
  234.          Mov    Di,Offset WorkSpace
  235.          Call   MakeTAB
  236.          Mov    Si,Offset WorkSpace
  237.          Call   Play
  238.          Call   After
  239.          Mov    Ax,4c00h
  240.          Int    21h
  241. Program  Endp
  242.  
  243. Channel1 Db 22,17,24,17,25,17,24,17,22,17,27,17,25,17,24,17,22,17,24,17,25,17
  244.          Db 27,17,29,17,27,17,25,17,24,17
  245.          Db 22,17,24,17,25,17,24,17,22,17,27,17,25,17,24,17,21,17,22,17,24,17,25,17
  246.          Db 27,17,29,17,25,17,24,17
  247.  
  248.          Db 22,22,24,24,25,25,24,24,22,22,27,27,25,25,24,24,22,22,24,24,25,25
  249.          Db 27,27,29,29,27,27,25,25,24,24
  250.          Db 22,22,24,24,25,25,24,24,22,22,27,27,25,25,24,24,21,21,22,22,24,24,25,25
  251.          Db 27,27,29,29,25,25,24,24
  252.  
  253.          Db 24,19,26,19,27,19,26,19,24,19,29,19,27,19,26,19,24,19,26,19,27,19
  254.          Db 29,19,31,19,29,19,27,19,26,19
  255.          Db 24,19,26,19,27,19,26,19,24,19,29,19,27,19,26,19,23,19,24,19,26,19,27,19
  256.          Db 29,19,31,19,27,19,26,19,-1
  257.  
  258. Channel2 Db 16 dup (10),16 dup(8),16 dup(6),16 dup (5),
  259.  
  260.          Db 8 dup (10,17),8 dup (8,15),8 dup (6,13), 8 dup (5,12)
  261.  
  262.          Db 8 dup (12,19),8 dup (10,17),8 dup (8,15), 8 dup (7,14),-1
  263.  
  264.  
  265.  
  266.  
  267. WorkSpace Db 'WorkSpace'
  268. Code     Ends
  269.          End   Start
  270.  
  271.  
  272.