home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / PCGPEV10.ZIP / SBDSP.TXT < prev    next >
Text File  |  1994-05-10  |  16KB  |  443 lines

  1.  
  2.                   ┌──────────────────────────────────┐
  3.                   │ Programming the SoundBlaster DSP │
  4.                   └──────────────────────────────────┘
  5.  
  6.                   Written for the PC-GPE by Mark Feldman
  7.               e-mail address : u914097@student.canberra.edu.au
  8.                                myndale@cairo.anu.edu.au
  9.  
  10.              ┌───────────────────────────────────────────┐
  11.              │      THIS FILE MAY NOT BE DISTRIBUTED     │
  12.              │ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. │
  13.              └───────────────────────────────────────────┘
  14.  
  15.  
  16. ┌────────────┬───────────────────────────────────────────────────────────────
  17. │ Disclaimer │
  18. └────────────┘
  19.  
  20. I assume no responsibility whatsoever for any effect that this file, the
  21. information contained therein or the use thereof has on you, your sanity,
  22. computer, spouse, children, pets or anything else related to you or your
  23. existance. No warranty is provided nor implied with this information.
  24.  
  25. ┌──────────────┬─────────────────────────────────────────────────────────────
  26. │ Introduction │
  27. └──────────────┘
  28.  
  29. The SoundBlaster is capable of both FM and digitised sounds. The FM wave
  30. is fully Adlib compatible, so check the ADLIB.TXT file for info
  31. on how to program it. This file will concentrate on recording and playback
  32. of digital samples through the SoundBlaster CT-DSP 1321 chip.
  33.  
  34. ┌────────────────────────────────┬───────────────────────────────────────────
  35. │ The SoundBlaster DSP I/O Ports │
  36. └────────────────────────────────┘
  37.  
  38. The DSP (Digital Sound Processor) chip is programmed through 4 ports which
  39. are determined by the SoundBlaster base address jumper setting:
  40.  
  41.                     RESET    2x6h
  42.  
  43.                 READ DATA    2xAh
  44.  
  45. WRITE COMMAND/DATA output
  46. WRITE BUFFER STATUS input    2xCh
  47.  
  48.  
  49.            DATA AVAILABLE    2xEh
  50.  
  51. where x = 1 for base address jumper setting 210h
  52.       x = 2 for base address jumper setting 220h
  53.       .
  54.       .
  55.       x = 6 for base address jumper setting 260h
  56.  
  57.  
  58. ┌───────────────────┬────────────────────────────────────────────────────────
  59. │ Resetting the DSP │
  60. └───────────────────┘
  61.  
  62. You have to reset the DSP before you program it. This is done with the
  63. following procedure :
  64.  
  65. 1) Write a 1 to the SoundBlaster RESET port (2x6h)
  66. 2) Wait for 3 micro-seconds
  67. 3) Write a 0 to the SoundBlaster RESET port (2x6h)
  68. 4) Read the byte from the DATA AVAILABLE (2xEh) port until bit 7 = 1
  69. 5) Poll for a ready byte (AAh) from the READ DATA port (2xAh). Before
  70.    reading the READ DATA port it is avdvisable.
  71.  
  72. The DSP usually takes somewhere around 100 micro-seconds to reset itself.
  73. If it fails to do within a reasonable time (say 200 micro-seconds) then
  74. an error has occurred, possibly an incorrect I/O address is being used.
  75.  
  76. ┌────────────────────┬───────────────────────────────────────────────────────
  77. │ Writing to the DSP │
  78. └────────────────────┘
  79.  
  80. A value can be written to the DSP with the following procedure :
  81.  
  82. 1) Read the DSP's WRITE BUFFER STATUS port (2xCh) until bit 7 = 0
  83. 2) Write the value to the WRITE COMMAND/DATA port (2xCh)
  84.  
  85. ┌─────────────────┬──────────────────────────────────────────────────────────
  86. │ Reading the DSP │
  87. └─────────────────┘
  88.  
  89. A value can be read from the DSP with the following procedure :
  90.  
  91. 1) Read the DSP's DATA AVAILABLE port (2xEh) until bit 7 = 1
  92. 2) Read the data from the READ DATA port (2xAh)
  93.  
  94. ┌────────────────────────────────────────────┬───────────────────────────────
  95. │ Turning the speaker on and controlling DMA │
  96. └────────────────────────────────────────────┘
  97.  
  98. Speaker and DMA control are handled by writing one of the following bytes
  99. to the DSP:
  100.  
  101.                      ┌─────────────────────────┐
  102.                      │ Value   Description     │
  103.                      ├─────────────────────────┤
  104.                      │ D0h    DMA Stop         │
  105.                      │ D1h    Turn speaker on  │
  106.                      │ D3h    Turn speaker off │
  107.                      │ D4h    DMA Continue     │
  108.                      └─────────────────────────┘
  109.  
  110. DMA is discussed below. The DMA commands shown here can be used to pause
  111. the sample during DMA playback playback.
  112.  
  113. ┌────────────────────┬───────────────────────────────────────────────────────
  114. │ Writing to the DAC │
  115. └────────────────────┘
  116.  
  117. The DAC (Digital to Analog Converter) is the part of the card which converts
  118. a sample number (ie 0 -> 255) to a sound level. To generate a square sound
  119. wave at maximum volume (for example) you could alternate writing 0's and
  120. 255's to the DAC.
  121.  
  122. Programming the DAC in direct mode involves the main program setting the
  123. DAC to a desired value. Only 8 bit DAC is available in direct mode. To set
  124. the DAC level you write the value 10h to the DSP followed by the sample
  125. number (0 -> 255). Note that no sound will be heard unless the speaker has
  126. been turned on. In direct mode the main program is responsible for the
  127. timing between samples, the DAC can output sound samples as fast as the
  128. calling program can change it. Typically the timer interrupt is reprogrammed
  129. and used to generate the timing required for a sample playback. Info on
  130. programming the PIT chip can be found in the PIT.TXT file.
  131.  
  132. The DAC can also be programmed to accept values sent to it via the DMA
  133. chip. Draeden has written an excellent article on programming the DMA chip
  134. (see DMA_VLA.TXT) so only a brief example of it's use will be given here.
  135. The important thing to remember is that the DMA chip cannot transfer data
  136. which crosses between page breaks. If the data does cross page breaks then
  137. it will have to be split up into several transfers, with one page per
  138. transfer.
  139.  
  140. Setting the playback frequency for the DMA transfer is done by writing
  141. the value 40h to the DSP followed by TIME_CONSTANT, where
  142. TIME_CONSTANT = 256 - 1000000 / frequency
  143.  
  144. There are several types of DMA transfers available. The following table
  145. lists them:
  146.  
  147.       ┌────────────────────────────────────────────────────────────┐
  148.       │DMA_TYPE_VALUE   Description             Frequency Range    │
  149.       ├────────────────────────────────────────────────────────────┤
  150.       │    14h          8 bit                   4KHz -> 23 KHz     │
  151.       │    74h          4 bit ADPCM             4KHz -> 12 KHz     │
  152.       │    75h          4 bit ADPCM with        4KHz -> 12 KHz     │
  153.       │                 reference byte                             │
  154.       │    76h          2.6 bit ADPCM           4KHz -> 13 KHz     │
  155.       │    77h          2.6 bit ADPCM with      4KHz -> 13 KHz     │
  156.       │                 reference byte                             │
  157.       │    16h          2 bit ADPCM             4KHz -> 11 KHz     │
  158.       │    17h          2 bit ADPCM with        4KHz -> 11 KHz     │
  159.       │                 reference byte                             │
  160.       └────────────────────────────────────────────────────────────┘
  161.  
  162. ADPCM stands for Adaptive Pulse Code Modulation, a sound compression
  163. technique where the difference between successive samples is stored rather
  164. than their actual values. In the modes with reference bytes, the first
  165. byte is the actual starting value. Having modes with and without reference
  166. bytes means you can output successive blocks without the need for a
  167. reference byte at the start of each one.
  168.  
  169. The procedure for doing a DMA transfer is as follows:
  170.  
  171. 1) Load the sound data into memory
  172. 2) Set up the DMA chip for the tranfer
  173. 3) Set the DSP TIME_CONSTANT to the sampling rate
  174. 4) Write DMA_TYPE_VALUE value to the DSP
  175. 5) Write DATA_LENGTH to the DSP (2 bytes, LSB first) where
  176.    DATA_LENGTH = number of bytes to send - 1
  177.  
  178. Note that the DMA chip must be programmed before the BSP.
  179.  
  180. ┌──────────────────────┬─────────────────────────────────────────────────────
  181. │ Reading from the ADC │
  182. └──────────────────────┘
  183.  
  184. Reading samples from the ADC (Analog to Digital Converter) can also be
  185. done in either direct or DMA mode.
  186.  
  187. To read a sample in direct mode write the value 20h to the DSP and then
  188. read the value from the DSP. Simple as that!
  189.  
  190. To set up the DSP for a DMA transfer, follow this procedure :
  191.  
  192. 1) Get a memory buffer ready to hold the sample
  193. 2) Set up the DMA chip for the transfer
  194. 3) Set the DSP TIME_CONSTANT to the sampling rate
  195. 4) Write the value 24h to the DSP
  196. 5) Write DATA_LENGTH to the DSP (2 bytes, LSB first) where
  197.    DATA_LENGTH = number of bytes to read - 1
  198.  
  199. Note that the DMA chip must be programmed before the BSP.
  200.  
  201. DMA reads only support 8 bit mode, compressed modes are done by software and
  202. stored in the voc file. I haven't tried to figure out how the compression is
  203. done. If someone does figure it out I'd like to know about it!
  204.  
  205. ┌──────────────────────────┬─────────────────────────────────────────────────
  206. │ Programming the DMA Chip │
  207. └──────────────────────────┘
  208.  
  209. As mentioned before, Draeden has written a very good article on the dma
  210. chip, but here is a brief run down on what you would need to do to program
  211. the DMA channel 1 for the DSP in real mode:
  212.  
  213. 1) Calculate the 20 bit address of the memory buffer you are using
  214.    where Base Address = Segment * 16 + Offset
  215.    eg 1234h:5678h = 179B8h
  216. 2) Send the value 05h to port 0Ah (mask off channel 1)
  217. 3) Send the value 00h to port 0Ch (clear the internal DMA flip/flop)
  218. 4) Send the value 49h to port 0Bh (for playback) or
  219.                   45h to port 0Bh (for recording)
  220. 5) Write the LSB (bits 0 -> 7) of the 20 bit memory address to port 02h
  221. 6) Write the MSB (bits 8 -> 15) of the 20 bit memory address to ort 02h
  222. 7) Write the Page (bits 16 -> 19) of the 20 bit memory address to port 83h
  223. 8) Send the LSB of DATA_LENGTH to port 03h
  224. 9) Send the MSB of DATA_LENGTH to port 03h
  225. 10) Send the value 01h to port 0Ah (enable channel 1)
  226.  
  227. ┌──────────────────────┬─────────────────────────────────────────────────────
  228. │ End of DMA Interrupt │
  229. └──────────────────────┘
  230.  
  231. When a DMA transfer is complete an interrupt is generated. The actual
  232. interrupt number depends on the SoundBlaster card's IRQ jumper setting:
  233.  
  234.                          ┌────────────────────────┐
  235.                          │ IRQ Jumper             │
  236.                          │  Setting     Interrupt │
  237.                          ├────────────────────────┤
  238.                          │    2            0Ah    │
  239.                          │    3            0Bh    │
  240.                          │    5            0Dh    │
  241.                          │    7            0Fh    │
  242.                          └────────────────────────┘
  243.  
  244. To service one of these interrupts you must perform these 3 tasks:
  245.  
  246. 1) Acknowledge the DSP interrupt by reading the DATA AVAILABLE port (2xEh)
  247.    once.
  248. 2) If there are more blocks to transfer then set them up
  249. 3) Output value 20h (EOI) to the interrupt controller port 20h
  250.  
  251. Of course, as with any hardware interrupt you must also leave the
  252. state of the system (registers etc..) the way it was when the interrupt
  253. was called.
  254.  
  255. ┌──────────────────────────┬────────────────────────────────────────────────
  256. │ A Simple DSP Pascal Unit │
  257. └──────────────────────────┘
  258.  
  259. {
  260.  
  261.   DSP.PAS - A demo SoundBlaster DSP unit for real mode
  262.  
  263.   By Mark Feldman
  264. }
  265.  
  266. Unit DSP;
  267.  
  268. Interface
  269.  
  270. { ResetDSP returns true if reset was successful
  271.   base should be 1 for base address 210h, 2 for 220h etc... }
  272. function ResetDSP(base : word) : boolean;
  273.  
  274. { Write DAC sets the speaker output level }
  275. procedure WriteDAC(level : byte);
  276.  
  277. { ReadDAC reads the microphone input level }
  278. function ReadDAC : byte;
  279.  
  280. { SpeakerOn connects the DAC to the speaker }
  281. function SpeakerOn: byte;
  282.  
  283. { SpeakerOff disconnects the DAC from the speaker,
  284.   but does not affect the DAC operation }
  285. function SpeakerOff: byte;
  286.  
  287. { Functions to pause DMA playback }
  288. procedure DMAStop;
  289. procedure DMAContinue;
  290.  
  291. { Playback plays a sample of a given size back at a given frequency using
  292.   DMA channel 1. The sample must not cross a page boundry }
  293. procedure Playback(sound : Pointer; size : word; frequency : word);
  294.  
  295. Implementation
  296.  
  297. Uses Crt;
  298.  
  299. var      DSP_RESET : word;
  300.      DSP_READ_DATA : word;
  301.     DSP_WRITE_DATA : word;
  302.   DSP_WRITE_STATUS : word;
  303.     DSP_DATA_AVAIL : word;
  304.  
  305. function ResetDSP(base : word) : boolean;
  306. begin
  307.  
  308.   base := base * $10;
  309.  
  310.   { Calculate the port addresses }
  311.   DSP_RESET := base + $206;
  312.   DSP_READ_DATA := base + $20A;
  313.   DSP_WRITE_DATA := base + $20C;
  314.   DSP_WRITE_STATUS := base + $20C;
  315.   DSP_DATA_AVAIL := base + $20E;
  316.  
  317.   { Reset the DSP, and give some nice long delays just to be safe }
  318.   Port[DSP_RESET] := 1;
  319.   Delay(10);
  320.   Port[DSP_RESET] := 0;
  321.   Delay(10);
  322.   if (Port[DSP_DATA_AVAIL] And $80 = $80) And
  323.      (Port[DSP_READ_DATA] = $AA) then
  324.     ResetDSP := true
  325.   else
  326.     ResetDSP := false;
  327. end;
  328.  
  329. procedure WriteDSP(value : byte);
  330. begin
  331.   while Port[DSP_WRITE_STATUS] And $80 <> 0 do;
  332.   Port[DSP_WRITE_DATA] := value;
  333. end;
  334.  
  335. function ReadDSP : byte;
  336. begin
  337.   while Port[DSP_DATA_AVAIL] and $80 = 0 do;
  338.   ReadDSP := Port[DSP_READ_DATA];
  339. end;
  340.  
  341. procedure WriteDAC(level : byte);
  342. begin
  343.   WriteDSP($10);
  344.   WriteDSP(level);
  345. end;
  346.  
  347. function ReadDAC : byte;
  348. begin
  349.   WriteDSP($20);
  350.   ReadDAC := ReadDSP;
  351. end;
  352.  
  353. function SpeakerOn: byte;
  354. begin
  355.   WriteDSP($D1);
  356. end;
  357.  
  358. function SpeakerOff: byte;
  359. begin
  360.   WriteDSP($D3);
  361. end;
  362.  
  363. procedure DMAContinue;
  364. begin
  365.   WriteDSP($D4);
  366. end;
  367.  
  368. procedure DMAStop;
  369. begin
  370.   WriteDSP($D0);
  371. end;
  372.  
  373. procedure Playback(sound : Pointer; size : word; frequency : word);
  374. var time_constant : word;
  375.      page, offset : word;
  376. begin
  377.  
  378.   SpeakerOn;
  379.  
  380.   size := size - 1;
  381.  
  382.   { Set up the DMA chip }
  383.   offset := Seg(sound^) Shl 4 + Ofs(sound^);
  384.   page := (Seg(sound^) + Ofs(sound^) shr 4) shr 12;
  385.   Port[$0A] := 5;
  386.   Port[$0C] := 0;
  387.   Port[$0B] := $49;
  388.   Port[$02] := Lo(offset);
  389.   Port[$02] := Hi(offset);
  390.   Port[$83] := page;
  391.   Port[$03] := Lo(size);
  392.   Port[$03] := Hi(size);
  393.   Port[$0A] := 1;
  394.  
  395.   { Set the playback frequency }
  396.   time_constant := 256 - 1000000 div frequency;
  397.   WriteDSP($40);
  398.   WriteDSP(time_constant);
  399.  
  400.   { Set the playback type (8-bit) }
  401.   WriteDSP($14);
  402.   WriteDSP(Lo(size));
  403.   WriteDSP(Hi(size));
  404. end;
  405.  
  406. end.
  407.  
  408.  
  409. ┌────────────┬───────────────────────────────────────────────────────────────
  410. │ References │
  411. └────────────┘
  412.  
  413. Title : The SoundBlaster Developpers Kit
  414. Publishers : Creative Labs Inc
  415.              Creative Technology PTE LTD
  416.  
  417. Title : Sound Blaster - The Official Book
  418. Authors : Richard Heimlich, David M. Golden, Ivan Luk, Peter M. Ridge
  419. Publishers : Osborne/McGraw Hill
  420. ISBN : 0-07-881907-5
  421.  
  422. Some of the information in this file was either obtained from or verified
  423. by the source code in a public domain library called SOUNDX by Peter
  424. Sprenger. I haven't tried using his library yet (I don't have a C compiler
  425. at the moment) but it looks very well done and contains numerous sound card
  426. detection routines. Says Peter : "It would be nice, that when you make
  427. something commercial with my routines, that you send me a copy of your
  428. project or send me some bucks, just enough for pizza and coke to support my
  429. night programming sessions. If you send me nothing, ok. But USE the stuff,
  430. if you can need it!". Heh...a REAL programmer!
  431.  
  432. ftpsite: ftp.uwp.edu
  433. directory: /pub/msdos/demos/programming/game-dev/source
  434. filename: soundx.zip
  435.  
  436. ┌─────────────────┬─────────────────────────────────────────────────────────
  437. │ Sound Familiar? │
  438. └─────────────────┘
  439.  
  440. What the...why is there a faint glimmer of sunlight outside? HOLY $#!^!! It's
  441. 5:30am! I'm goin' to bed!
  442.  
  443.