Modules/SB16 - Stub driver, nowhere near complete
authorJohn Hodge <[email protected]>
Sun, 25 Sep 2011 03:21:56 +0000 (11:21 +0800)
committerJohn Hodge <[email protected]>
Sun, 25 Sep 2011 03:22:16 +0000 (11:22 +0800)
Modules/Sound/SoundBlaster16/Makefile [new file with mode: 0644]
Modules/Sound/SoundBlaster16/main.c [new file with mode: 0644]
Modules/Sound/SoundBlaster16/sbdsp.txt [new file with mode: 0644]

diff --git a/Modules/Sound/SoundBlaster16/Makefile b/Modules/Sound/SoundBlaster16/Makefile
new file mode 100644 (file)
index 0000000..9384859
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = main.o
+NAME = SoundBlaster16
+
+-include ../Makefile.tpl
diff --git a/Modules/Sound/SoundBlaster16/main.c b/Modules/Sound/SoundBlaster16/main.c
new file mode 100644 (file)
index 0000000..5288399
--- /dev/null
@@ -0,0 +1,116 @@
+/*\r
+ * Acess2 SoundBlaster16 Driver\r
+ */\r
+#define DEBUG  0\r
+#include <acess.h>\r
+#include <errno.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include <fs_devfs.h>\r
+#include <drv_pci.h>\r
+#include <tpl_drv_sound.h>\r
+\r
+#define INT\r
+\r
+// === TYPES ===\r
+typedef struct sSB16\r
+{\r
+       Uint16  Base;\r
+}      tSB16;\r
+\r
+// === CONSTANTS ===\r
+enum {\r
+       SB16_PORT_RESET = 0x6,\r
+       SB16_PORT_READ  = 0xA,\r
+       SB16_PORT_WRITE = 0xC,\r
+       SB16_PORT_AVAIL = 0xE\r
+};\r
+#define SB16_BASE_PORT 0x200\r
+enum {\r
+       SB16_CMD_RAW8    = 0x10,        // 8-bit DAC value follows\r
+       SB16_CMD_DMAFREQ = 0x40,        // followed by TIME_CONSTANT = 256 - 1000000 / frequency\r
+       SB16_CMD_DMASTOP = 0xD0,\r
+       SB16_CMD_SPKRON  = 0xD1,\r
+       SB16_CMD_SPKROFF = 0xD3,\r
+       SB16_CMD_DMACONT = 0xD4,\r
+       \r
+       // DMA Types (uses channel 1)\r
+       // - Followed by 16-bit length (well, length - 1)\r
+       SB16_CMD_DMA_8BIT = 0x14,\r
+};\r
+\r
+\r
+// === PROTOTYPES ===\r
+// Driver\r
+ int   SB16_Install(char **Arguments);\r
+void   SB16_Uninstall();\r
+// Filesystem\r
+Uint64 SB16_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+ int   SB16_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, 0x0032, SoundBlaster16, SB16_Install, SB16_Uninstall, "PCI", NULL);\r
+tDevFS_Driver  gBGA_DriverStruct = {\r
+       NULL, "SoundBlaster16",\r
+       {\r
+       .Write = SB16_Write,\r
+       .IOCtl = SB16_IOCtl\r
+       }\r
+};\r
+\r
+// === CODE ===\r
+int SB16_Install(char **Arguments)\r
+{\r
+        int    jumper_port_setting = 1;        // 1-6 incl\r
+       \r
+       // Reset\r
+       outb(card->Base+SB16_PORT_RESET, 1);\r
+       // - Wait 3us\r
+       outb(card->Base+SB16_PORT_RESET, 0);\r
+       \r
+       SB16_ReadDSP(card);\r
+       \r
+       return MODULE_ERR_OK;\r
+}\r
+\r
+void SB16_Uninstall()\r
+{\r
+}\r
+\r
+/**\r
+ * \fn Uint64 SB16_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+ * \brief Write to the framebuffer\r
+ */\r
+Uint64 SB16_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+{      \r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \fn int SB16_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
+ * \brief Handle messages to the device\r
+ */\r
+int SB16_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
+{\r
+       return -1;\r
+}\r
+\r
+//\r
+int SB16_WriteDSP(tSB16 *Card, Uint8 Value)\r
+{\r
+       // Wait for the card to be ready\r
+       while( inb(Card->Base+SB16_PORT_WRITE) & 0x80 )\r
+               ;\r
+       \r
+       outb(Card->Base+SB16_PORT_WRITE, Value);\r
+       \r
+       return 0;\r
+}\r
+\r
+Uint8 SB16_ReadDSP(tSB16 *Card)\r
+{\r
+       // Wait for bit 7 of AVAIL\r
+       while( !(inb(card->Base+SB16_PORT_AVAIL) & 0x80) )\r
+               ;\r
+       return inb(card->Base+SB16_PORT_READ);\r
+}\r
diff --git a/Modules/Sound/SoundBlaster16/sbdsp.txt b/Modules/Sound/SoundBlaster16/sbdsp.txt
new file mode 100644 (file)
index 0000000..94364cd
--- /dev/null
@@ -0,0 +1,442 @@
+
+                  ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
+                  ³ Programming the SoundBlaster DSP ³
+                  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+                  Written for the PC-GPE by Mark Feldman
+              e-mail address : [email protected]
+                               [email protected]
+
+             ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
+             ³      THIS FILE MAY NOT BE DISTRIBUTED     ³
+             ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³
+             ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Disclaimer ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+I assume no responsibility whatsoever for any effect that this file, the
+information contained therein or the use thereof has on you, your sanity,
+computer, spouse, children, pets or anything else related to you or your
+existance. No warranty is provided nor implied with this information.
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Introduction ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+The SoundBlaster is capable of both FM and digitised sounds. The FM wave
+is fully Adlib compatible, so check the ADLIB.TXT file for info
+on how to program it. This file will concentrate on recording and playback
+of digital samples through the SoundBlaster CT-DSP 1321 chip.
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ The SoundBlaster DSP I/O Ports ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+The DSP (Digital Sound Processor) chip is programmed through 4 ports which
+are determined by the SoundBlaster base address jumper setting:
+
+                    RESET    2x6h
+
+                READ DATA    2xAh
+
+WRITE COMMAND/DATA output
+WRITE BUFFER STATUS input    2xCh
+
+
+           DATA AVAILABLE    2xEh
+
+where x = 1 for base address jumper setting 210h
+      x = 2 for base address jumper setting 220h
+      .
+      .
+      x = 6 for base address jumper setting 260h
+
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Resetting the DSP ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+You have to reset the DSP before you program it. This is done with the
+following procedure :
+
+1) Write a 1 to the SoundBlaster RESET port (2x6h)
+2) Wait for 3 micro-seconds
+3) Write a 0 to the SoundBlaster RESET port (2x6h)
+4) Read the byte from the DATA AVAILABLE (2xEh) port until bit 7 = 1
+5) Poll for a ready byte (AAh) from the READ DATA port (2xAh). Before
+   reading the READ DATA port it is avdvisable.
+
+The DSP usually takes somewhere around 100 micro-seconds to reset itself.
+If it fails to do within a reasonable time (say 200 micro-seconds) then
+an error has occurred, possibly an incorrect I/O address is being used.
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Writing to the DSP ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+A value can be written to the DSP with the following procedure :
+
+1) Read the DSP's WRITE BUFFER STATUS port (2xCh) until bit 7 = 0
+2) Write the value to the WRITE COMMAND/DATA port (2xCh)
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Reading the DSP ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+A value can be read from the DSP with the following procedure :
+
+1) Read the DSP's DATA AVAILABLE port (2xEh) until bit 7 = 1
+2) Read the data from the READ DATA port (2xAh)
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Turning the speaker on and controlling DMA ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+Speaker and DMA control are handled by writing one of the following bytes
+to the DSP:
+
+                     ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
+                     ³ Value   Description     ³
+                     ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
+                     ³ D0h    DMA Stop         ³
+                     ³ D1h    Turn speaker on  ³
+                     ³ D3h    Turn speaker off ³
+                     ³ D4h    DMA Continue     ³
+                     ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+DMA is discussed below. The DMA commands shown here can be used to pause
+the sample during DMA playback playback.
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Writing to the DAC ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+The DAC (Digital to Analog Converter) is the part of the card which converts
+a sample number (ie 0 -> 255) to a sound level. To generate a square sound
+wave at maximum volume (for example) you could alternate writing 0's and
+255's to the DAC.
+
+Programming the DAC in direct mode involves the main program setting the
+DAC to a desired value. Only 8 bit DAC is available in direct mode. To set
+the DAC level you write the value 10h to the DSP followed by the sample
+number (0 -> 255). Note that no sound will be heard unless the speaker has
+been turned on. In direct mode the main program is responsible for the
+timing between samples, the DAC can output sound samples as fast as the
+calling program can change it. Typically the timer interrupt is reprogrammed
+and used to generate the timing required for a sample playback. Info on
+programming the PIT chip can be found in the PIT.TXT file.
+
+The DAC can also be programmed to accept values sent to it via the DMA
+chip. Draeden has written an excellent article on programming the DMA chip
+(see DMA_VLA.TXT) so only a brief example of it's use will be given here.
+The important thing to remember is that the DMA chip cannot transfer data
+which crosses between page breaks. If the data does cross page breaks then
+it will have to be split up into several transfers, with one page per
+transfer.
+
+Setting the playback frequency for the DMA transfer is done by writing
+the value 40h to the DSP followed by TIME_CONSTANT, where
+TIME_CONSTANT = 256 - 1000000 / frequency
+
+There are several types of DMA transfers available. The following table
+lists them:
+
+      ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
+      ³DMA_TYPE_VALUE   Description             Frequency Range    ³
+      ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
+      ³    14h          8 bit                   4KHz -> 23 KHz     ³
+      ³    74h          4 bit ADPCM             4KHz -> 12 KHz     ³
+      ³    75h          4 bit ADPCM with        4KHz -> 12 KHz     ³
+      ³                 reference byte                             ³
+      ³    76h          2.6 bit ADPCM           4KHz -> 13 KHz     ³
+      ³    77h          2.6 bit ADPCM with      4KHz -> 13 KHz     ³
+      ³                 reference byte                             ³
+      ³    16h          2 bit ADPCM             4KHz -> 11 KHz     ³
+      ³    17h          2 bit ADPCM with        4KHz -> 11 KHz     ³
+      ³                 reference byte                             ³
+      ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+ADPCM stands for Adaptive Pulse Code Modulation, a sound compression
+technique where the difference between successive samples is stored rather
+than their actual values. In the modes with reference bytes, the first
+byte is the actual starting value. Having modes with and without reference
+bytes means you can output successive blocks without the need for a
+reference byte at the start of each one.
+
+The procedure for doing a DMA transfer is as follows:
+
+1) Load the sound data into memory
+2) Set up the DMA chip for the tranfer
+3) Set the DSP TIME_CONSTANT to the sampling rate
+4) Write DMA_TYPE_VALUE value to the DSP
+5) Write DATA_LENGTH to the DSP (2 bytes, LSB first) where
+   DATA_LENGTH = number of bytes to send - 1
+
+Note that the DMA chip must be programmed before the BSP.
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Reading from the ADC ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+Reading samples from the ADC (Analog to Digital Converter) can also be
+done in either direct or DMA mode.
+
+To read a sample in direct mode write the value 20h to the DSP and then
+read the value from the DSP. Simple as that!
+
+To set up the DSP for a DMA transfer, follow this procedure :
+
+1) Get a memory buffer ready to hold the sample
+2) Set up the DMA chip for the transfer
+3) Set the DSP TIME_CONSTANT to the sampling rate
+4) Write the value 24h to the DSP
+5) Write DATA_LENGTH to the DSP (2 bytes, LSB first) where
+   DATA_LENGTH = number of bytes to read - 1
+
+Note that the DMA chip must be programmed before the BSP.
+
+DMA reads only support 8 bit mode, compressed modes are done by software and
+stored in the voc file. I haven't tried to figure out how the compression is
+done. If someone does figure it out I'd like to know about it!
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Programming the DMA Chip ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+As mentioned before, Draeden has written a very good article on the dma
+chip, but here is a brief run down on what you would need to do to program
+the DMA channel 1 for the DSP in real mode:
+
+1) Calculate the 20 bit address of the memory buffer you are using
+   where Base Address = Segment * 16 + Offset
+   eg 1234h:5678h = 179B8h
+2) Send the value 05h to port 0Ah (mask off channel 1)
+3) Send the value 00h to port 0Ch (clear the internal DMA flip/flop)
+4) Send the value 49h to port 0Bh (for playback) or
+                  45h to port 0Bh (for recording)
+5) Write the LSB (bits 0 -> 7) of the 20 bit memory address to port 02h
+6) Write the MSB (bits 8 -> 15) of the 20 bit memory address to ort 02h
+7) Write the Page (bits 16 -> 19) of the 20 bit memory address to port 83h
+8) Send the LSB of DATA_LENGTH to port 03h
+9) Send the MSB of DATA_LENGTH to port 03h
+10) Send the value 01h to port 0Ah (enable channel 1)
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ End of DMA Interrupt ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+When a DMA transfer is complete an interrupt is generated. The actual
+interrupt number depends on the SoundBlaster card's IRQ jumper setting:
+
+                         ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
+                         ³ IRQ Jumper             ³
+                         ³  Setting     Interrupt ³
+                         ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
+                         ³    2            0Ah    ³
+                         ³    3            0Bh    ³
+                         ³    5            0Dh    ³
+                         ³    7            0Fh    ³
+                         ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+To service one of these interrupts you must perform these 3 tasks:
+
+1) Acknowledge the DSP interrupt by reading the DATA AVAILABLE port (2xEh)
+   once.
+2) If there are more blocks to transfer then set them up
+3) Output value 20h (EOI) to the interrupt controller port 20h
+
+Of course, as with any hardware interrupt you must also leave the
+state of the system (registers etc..) the way it was when the interrupt
+was called.
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ A Simple DSP Pascal Unit ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+{
+
+  DSP.PAS - A demo SoundBlaster DSP unit for real mode
+
+  By Mark Feldman
+}
+
+Unit DSP;
+
+Interface
+
+{ ResetDSP returns true if reset was successful
+  base should be 1 for base address 210h, 2 for 220h etc... }
+function ResetDSP(base : word) : boolean;
+
+{ Write DAC sets the speaker output level }
+procedure WriteDAC(level : byte);
+
+{ ReadDAC reads the microphone input level }
+function ReadDAC : byte;
+
+{ SpeakerOn connects the DAC to the speaker }
+function SpeakerOn: byte;
+
+{ SpeakerOff disconnects the DAC from the speaker,
+  but does not affect the DAC operation }
+function SpeakerOff: byte;
+
+{ Functions to pause DMA playback }
+procedure DMAStop;
+procedure DMAContinue;
+
+{ Playback plays a sample of a given size back at a given frequency using
+  DMA channel 1. The sample must not cross a page boundry }
+procedure Playback(sound : Pointer; size : word; frequency : word);
+
+Implementation
+
+Uses Crt;
+
+var      DSP_RESET : word;
+     DSP_READ_DATA : word;
+    DSP_WRITE_DATA : word;
+  DSP_WRITE_STATUS : word;
+    DSP_DATA_AVAIL : word;
+
+function ResetDSP(base : word) : boolean;
+begin
+
+  base := base * $10;
+
+  { Calculate the port addresses }
+  DSP_RESET := base + $206;
+  DSP_READ_DATA := base + $20A;
+  DSP_WRITE_DATA := base + $20C;
+  DSP_WRITE_STATUS := base + $20C;
+  DSP_DATA_AVAIL := base + $20E;
+
+  { Reset the DSP, and give some nice long delays just to be safe }
+  Port[DSP_RESET] := 1;
+  Delay(10);
+  Port[DSP_RESET] := 0;
+  Delay(10);
+  if (Port[DSP_DATA_AVAIL] And $80 = $80) And
+     (Port[DSP_READ_DATA] = $AA) then
+    ResetDSP := true
+  else
+    ResetDSP := false;
+end;
+
+procedure WriteDSP(value : byte);
+begin
+  while Port[DSP_WRITE_STATUS] And $80 <> 0 do;
+  Port[DSP_WRITE_DATA] := value;
+end;
+
+function ReadDSP : byte;
+begin
+  while Port[DSP_DATA_AVAIL] and $80 = 0 do;
+  ReadDSP := Port[DSP_READ_DATA];
+end;
+
+procedure WriteDAC(level : byte);
+begin
+  WriteDSP($10);
+  WriteDSP(level);
+end;
+
+function ReadDAC : byte;
+begin
+  WriteDSP($20);
+  ReadDAC := ReadDSP;
+end;
+
+function SpeakerOn: byte;
+begin
+  WriteDSP($D1);
+end;
+
+function SpeakerOff: byte;
+begin
+  WriteDSP($D3);
+end;
+
+procedure DMAContinue;
+begin
+  WriteDSP($D4);
+end;
+
+procedure DMAStop;
+begin
+  WriteDSP($D0);
+end;
+
+procedure Playback(sound : Pointer; size : word; frequency : word);
+var time_constant : word;
+     page, offset : word;
+begin
+
+  SpeakerOn;
+
+  size := size - 1;
+
+  { Set up the DMA chip }
+  offset := Seg(sound^) Shl 4 + Ofs(sound^);
+  page := (Seg(sound^) + Ofs(sound^) shr 4) shr 12;
+  Port[$0A] := 5;
+  Port[$0C] := 0;
+  Port[$0B] := $49;
+  Port[$02] := Lo(offset);
+  Port[$02] := Hi(offset);
+  Port[$83] := page;
+  Port[$03] := Lo(size);
+  Port[$03] := Hi(size);
+  Port[$0A] := 1;
+
+  { Set the playback frequency }
+  time_constant := 256 - 1000000 div frequency;
+  WriteDSP($40);
+  WriteDSP(time_constant);
+
+  { Set the playback type (8-bit) }
+  WriteDSP($14);
+  WriteDSP(Lo(size));
+  WriteDSP(Hi(size));
+end;
+
+end.
+
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ References ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+Title : The SoundBlaster Developpers Kit
+Publishers : Creative Labs Inc
+             Creative Technology PTE LTD
+
+Title : Sound Blaster - The Official Book
+Authors : Richard Heimlich, David M. Golden, Ivan Luk, Peter M. Ridge
+Publishers : Osborne/McGraw Hill
+ISBN : 0-07-881907-5
+
+Some of the information in this file was either obtained from or verified
+by the source code in a public domain library called SOUNDX by Peter
+Sprenger. I haven't tried using his library yet (I don't have a C compiler
+at the moment) but it looks very well done and contains numerous sound card
+detection routines. Says Peter : "It would be nice, that when you make
+something commercial with my routines, that you send me a copy of your
+project or send me some bucks, just enough for pizza and coke to support my
+night programming sessions. If you send me nothing, ok. But USE the stuff,
+if you can need it!". Heh...a REAL programmer!
+
+ftpsite: ftp.uwp.edu
+directory: /pub/msdos/demos/programming/game-dev/source
+filename: soundx.zip
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Sound Familiar? ³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+What the...why is there a faint glimmer of sunlight outside? HOLY $#!^!! It's
+5:30am! I'm goin' to bed!
+

UCC git Repository :: git.ucc.asn.au