#!/bin/sh # This is a shell archive (produced by shar 3.49) # To extract the files from this archive, save it to a file, remove # everything above the "!/bin/sh" line above, and type "sh file_name". # # made 02/03/1993 23:16 UTC by tjt@wink # Source directory /b2/midi/tmp/blast # # existing files will NOT be overwritten unless -c is specified # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 5943 -rw-rw-r-- dac # 21932 -rw-rw-rw- fmdoc # 7111 -rw-rw-r-- howto # 9553 -rw-rw-r-- midi # 7318 -rw-rw-r-- voicelib # # ============= dac ============== if test -f 'dac' -a X"$1" != X"-c"; then echo 'x - skipping dac (File already exists)' else echo 'x - extracting dac (Text)' sed 's/^X//' << 'SHAR_EOF' > 'dac' && Sender: MSDOS Sound Card Forum and Discussion List X XFrom: Matthew Newcomb Subject: Programing the SB DAC To: Multiple recipients of list IBMSND-L X X Dear SB Programing Hopefulls, X I though a few of you would enjoy this article on how to program the X digital sound aspect of the sound blaster. It appeared in Sound Blaster X Magazine #5 and was written by the wizard himself, Gary Madox. (The other of X all that nice guiltware)! X * I apologize to those who don't want to read this.... X bye, X Matthew Newcomb X iqm139@uriacc.uri.edu X X X ACCESSING THE SOUND BLASTER DAC CHANNEL X =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= X X Written by Gary Maddox. X X The Sound Blaster can add some terrific sounds to games through the use of its FM music synthesizer. But to me, the most fun feature of this sound card is the ability to digitize real-world sounds and play them back at will. Once a sound has been digitized into a data file, the data can be processed into a limitless number of new sounds. There are several ways to create your own sound files. Included with the Sound Blaster is Voxkit, a software program to record, play back and compress VOC files. There is also my own program called BLASTER Master, which features recording, playback, editing and several other ways to process sound files. For those of you who like to "roll their own", or for the curious, this article will reveal some of the techniques used to directly control the DAC channel through software. Since providing examples in assembly language, C, Turbo Pascal and QuickBASIC would make this article too lengthy, I will instead use a type of pseudo code. This should be very easy to both translate into your programming language of choice and to provide information to the non-programmers among you. So here we go... X X First off, lets find out if a Sound Blaster is present and what port address is being used. (NOTE: Some PC interface cards may not like being tickled by our program...you may wish to have the user configure the software for the proper port.) The Sound Blaster uses one of 6 port addresses, i.e., 210H, 220H, 230H, 240H, 250H, 260H. We will be concerned with 4 addresses, the base address (2x0H), the reset address (2x6H), the read address (2xAH) and the write address (2xCH). Let's look at some code: X ---- \* Initialize Variables *\ X BPORT = 210H \*DSP port BASE address *\ X XPORT = 216H \*DSP RESET port address *\ X WPORT = 21CH \*DSP WRITE port address *\ X RPORT = 21AH \*DSP READ port address *\ X APORT = 21EH \*DSP DATA AVAILABLE port address*\ X READY = 0AAH \* Initialize DSP and scan for port base address *\ X DO X OUTPORT XPORT, 1 \*send 1 to reset port 2x6H *\ X WAIT 3ms \*wait about 3 micro seconds *\ X OUTPORT XPORT, 0 \*send 0 to reset port 2x6H *\ X LOOPCTR = 0 X DO \*poll for READYBYTE *\ X INPORT RPORT, BYTE \*try to read a byte *\ X LOOPCTR = LOOPCTR + 1 X LOOP WHILE BYTE # READY OR LOOPCTR < 100 X IF BYTE # AAH \*compare byte to AAH *\ X BPORT = BPORT + 10H \*else check next port address*\ X XPORT = XPORT + 10H X WPORT = WPORT + 10H X RPORT = RPORT + 10H X Page 5 X APORT = APORT + 10H X END IF X LOOP WHILE BYTE # AAH OR BPORT < 270H \* Check BPORT for success *\ X IF BPORT = 270H X DISPLAY "Sound Blaster Not Found!" X STOP X ELSE X DISPLAY "Sound Blaster Installed at Port ", BPORT X END IF X ---- X X Now that we have located the base address and initialized the DSP, we are ready to read data directly from the Sound Blasters DAC. We will do so by writing a command to the DSP WRITE port to fetch a byte. The command to read is 20H. We will then read the DSP DATA AVAILABLE port to see if a byte is ready to be read from the READ port. If the data is ready, we can then proceed with the READ port operation. Once we have a byte of PCM data, we can call a routine to process it. Lets look at the pseudo code to do this: X ---- \* DSP READ loop *\ X EXIT = FALSE X DO X OUTPORT WPORT, 20H \*send the READ command byte *\ X DO X INPORT APORT, byte X LOOP WHILE BYTE # 127 \*poll until a byte is ready *\ X INPORT RPORT, BYTE \*read our PCM byte from the DSP*\ \* *\ \* insert your code to do amazing things here! *\ \* *\ X LOOP UNTIL EXIT X ---- X X Now that we can read sample data coming into the Sound Blaster, we can let our imaginations explore an endless array of applications. We could use the sound data to control a graphics program to change colors and pulse to the music. We could graph the data and make our own oscilloscope. With a bit more effort, we could write a PC answering machine or even a voice recognition system. We could even write a program that recognized the music of the New Kids on the Block and played back loud puking sounds! I hope that this article has been informative and that you will try this out for yourself. I tried to make it as easy as I could, but it is a very technical subject. This is very similar to the technique I used to write my Hi-Res sample program. I suggest that you use assembly language if you can. You will have to execute your code as fast as possible to achieve a very high sample rate. If you have any questions, please feel free to register BLASTER Master and then give me a call. X SHAR_EOF chmod 0664 dac || echo 'restore of dac failed' Wc_c="`wc -c < 'dac'`" test 5943 -eq "$Wc_c" || echo 'dac: original size 5943, current size' "$Wc_c" fi # ============= fmdoc ============== if test -f 'fmdoc' -a X"$1" != X"-c"; then echo 'x - skipping fmdoc (File already exists)' else echo 'x - extracting fmdoc (Text)' sed 's/^X//' << 'SHAR_EOF' > 'fmdoc' && XXref: cbfsb comp.os.msdos.programmer:11613 comp.music:6456 rec.games.programmer:5685 Path: cbfsb!att!linac!pacific.mps.ohio-state.edu!zaphod.mps.ohio-state.edu!usc!news.bbn.com!noc.near.net!uhasun!smylex!jlee XFrom: jlee@smylex.UUCP (Jeff Lee) Newsgroups: comp.os.msdos.programmer,comp.music,rec.games.programmer Subject: Programming the AdLib/Sound Blaster Message-ID: <250-JNEWS-1.2@smylex.UUCP> Date: 25 Feb 92 15:02:02 GMT Sender: jlee@smylex.UUCP Organization: Shipbrook Software (Newington, CT) Lines: 484 X Hello, all. I've updated my doc file on programming the AdLib/Sound Blaster cards, and since I'm still getting requests for the original, I decided that it would save time to post it here. Apologies to those who aren't interested. X ------------------------------------------------------------------------------- X X Programming the AdLib/Sound Blaster X FM Music Chips X Version 2.0 (24 Feb 1992) X X Copyright (c) 1991, 1992 by Jeffrey S. Lee X X jlee@smylex.uucp X X X X Warranty and Copyright Policy X X This document is provided on an "as-is" basis, and its author makes X no warranty or representation, express or implied, with respect to X its quality performance or fitness for a particular purpose. In no X event will the author of this document be liable for direct, indirect, X special, incidental, or consequential damages arising out of the use X or inability to use the information contained within. Use of this X document is at your own risk. X X This file may be used and copied freely so long as the applicable X copyright notices are retained, and no modifications are made to the X text of the document. No money shall be charged for its distribution X beyond reasonable shipping, handling and duplication costs, nor shall X proprietary changes be made to this document so that it cannot be X distributed freely. This document may not be included in published X material or commercial packages without the written consent of its X author. X X X X Overview X X Two of the most popular sound cards for the IBM-PC, the AdLib and the X Sound Blaster, suffer from a real dearth of clear documentation for X programmers. AdLib Inc. and Creative Labs, Inc. both sell developers' X kits for their sound cards, but these are expensive, and (in the case X of the Sound Blaster developers' kit) can be extremely cryptic. X X This document is intended to provide programmers with a FREE source X of information about the programming of these sound cards. X X The information contained in this document is a combination of X information found in the Sound Blaster Software Developer's Kit, and X that learned by painful experience. Some of the information may not X be valid for AdLib cards; if this is so, I apologize in advance. X X Please note that numbers will be given in hexadecimal, unless otherwise X indicated. If a number is written out longhand (sixteen instead of 16) X it is in decimal. X X | Changes from Version 1 of the file will be indicated by the use of change X | bars in the left-hand margin. X X X X Chapter One - Sound Card I/O X X The sound card is programmed by sending data to its internal registers X via its two I/O ports: X X 0388 (hex) - Address/Status port (R/W) X 0389 (hex) - Data port (W/O) X X | The Sound Blaster Pro is capable of stereo FM music, which is accessed X | in exactly the same manner. Ports 0220 and 0221 (hex) are the address/ X | data ports for the left speaker, and ports 0222 and 0223 (hex) are the X | ports for the right speaker. Ports 0388 and 0389 (hex) will cause both X | speakers to output sound. X X The sound card possesses an array of two hundred forty-four registers; X to write to a particular register, send the register number (01-F5) to X the address port, and the desired value to the data port. X X After writing to the register port, you must wait twelve cycles before X sending the data; after writing the data, eighty-four cycles must elapse X before any other sound card operation may be performed. X X | The AdLib manual gives the wait times in microseconds: three point three X | (3.3) microseconds for the address, and twenty-three (23) microseconds X | for the data. X | X | The most accurate method of producing the delay is to read the register X | port six times after writing to the register port, and read the register X | port thirty-five times after writing to the data port. X X The sound card registers are write-only. X X The address port also functions as a sound card status byte. To X retrieve the sound card's status, simply read port 388. The status X byte has the following structure: X X 7 6 5 4 3 2 1 0 X +------+------+------+------+------+------+------+------+ X | both | tmr | tmr | unused | X | tmrs | 1 | 2 | | X +------+------+------+------+------+------+------+------+ X X Bit 7 - set if either timer has expired. X 6 - set if timer 1 has expired. X 5 - set if timer 2 has expired. X X X X Chapter Two - The Registers X The following table shows the function of each register in the sound card. Registers will be explained in detail after the table. Registers not listed are unused. X X Address Function X ------- ---------------------------------------------------- X 01 Test LSI / Enable waveform control X 02 Timer 1 data X 03 Timer 2 data X 04 Timer control flags X 08 Speech synthesis mode / Keyboard split note select X 20..35 Amp Mod / Vibrato / EG type / Key Scaling / Multiple X 40..55 Key scaling level / Operator output level X 60..75 Attack Rate / Decay Rate X 80..95 Sustain Level / Release Rate X A0..A8 Frequency (low 8 bits) X B0..B8 Key On / Octave / Frequency (high 2 bits) X BD AM depth / Vibrato depth / Rhythm control X C0..C8 Feedback strength / Connection type X E0..F5 Wave Select X The groupings of twenty-two registers (20-35, 40-55, etc.) have an odd order due to the use of two operators for each FM voice. The following table shows the offsets within each group of registers for each operator. X X X Channel 1 2 3 4 5 6 7 8 9 X Operator 1 00 01 02 08 09 0A 10 11 12 X Operator 2 03 04 05 0B 0C 0D 13 14 15 X Thus, the addresses of the attack/decay bytes for channel 3 are 62 for the first operator, and 65 for the second. (The address of the second operator is always the address of the first operator plus three). X To further illustrate the relationship, the addresses needed to control channel 5 are: X X 29 - Operator 1 AM/VIB/EG/KSR/Multiplier X 2C - Operator 2 AM/VIB/EG/KSR/Multiplier X 49 - Operator 1 KSL/Output Level X 4C - Operator 2 KSL/Output Level X 69 - Operator 1 Attack/Decay X 6C - Operator 2 Attack/Decay X 89 - Operator 1 Sustain/Release X 8C - Operator 2 Sustain/Release X A4 - Frequency (low 8 bits) X B4 - Key On/Octave/Frequency (high 2 bits) X C4 - Feedback/Connection Type X E9 - Operator 1 Waveform X EC - Operator 2 Waveform X X X X Explanations of Registers X Byte 01 - This byte is normally used to test the LSI device. All bits X should normally be zero. Bit 5, if enabled, allows the FM X chips to control the waveform of each operator. X X 7 6 5 4 3 2 1 0 X +-----+-----+-----+-----+-----+-----+-----+-----+ X | unused | WS | unused | X +-----+-----+-----+-----+-----+-----+-----+-----+ X X Byte 02 - Timer 1 Data. If Timer 1 is enabled, the value in this X register will be incremented until it overflows. Upon X overflow, the sound card will signal a TIMER interrupt X (INT 08) and set bits 7 and 6 in its status byte. The X value for this timer is incremented every eighty (80) X microseconds. X X Byte 03 - Timer 2 Data. If Timer 2 is enabled, the value in this X register will be incremented until it overflows. Upon X overflow, the sound card will signal a TIMER interrupt X (INT 08) and set bits 7 and 5 in its status byte. The X value for this timer is incremented every three hundred X twenty (320) microseconds. X X Byte 04 - Timer Control Byte X X 7 6 5 4 3 2 1 0 X +-----+-----+-----+-----+-----+-----+-----+-----+ X | IRQ | T1 | T2 | unused | T2 | T1 | X | RST | MSK | MSK | | CTL | CTL | X +-----+-----+-----+-----+-----+-----+-----+-----+ X X bit 7 - Resets the flags for timers 1 & 2. If set, X all other bits are ignored. X bit 6 - Masks Timer 1. If set, bit 0 is ignored. X bit 5 - Masks Timer 2. If set, bit 1 is ignored. X bit 1 - When clear, Timer 2 does not operate. X When set, the value from byte 03 is loaded into X Timer 2, and incrementation begins. X bit 0 - When clear, Timer 1 does not operate. X When set, the value from byte 02 is loaded into X Timer 1, and incrementation begins. X X Byte 08 - CSM Mode / Keyboard Split. X X 7 6 5 4 3 2 1 0 X +-----+-----+-----+-----+-----+-----+-----+-----+ X | CSM | Key | unused | X | sel | Spl | | X +-----+-----+-----+-----+-----+-----+-----+-----+ X X bit 7 - When set, selects composite sine-wave speech synthesis X mode (all KEY-ON bits must be clear). When clear, X selects FM music mode. X X bit 6 - Selects the keyboard split point (in conjunction with X the F-Number data). The documentation in the Sound X Blaster manual is utterly incomprehensible on this; X I can't reproduce it without violating their copyright. X X Bytes 20-35 - Amplitude Modulation / Vibrato / Envelope Generator Type / X Keyboard Scaling Rate / Modulator Frequency Multiple X X 7 6 5 4 3 2 1 0 X +-----+-----+-----+-----+-----+-----+-----+-----+ X | Amp | Vib | EG | KSR | Modulator Frequency | X | Mod | | Typ | | Multiple | X +-----+-----+-----+-----+-----+-----+-----+-----+ X X bit 7 - Apply amplitude modulation when set; AM depth is X controlled by the AM-Depth flag in address BD. X bit 6 - Apply vibrato when set; vibrato depth is controlled X by the Vib-Depth flag in address BD. X bit 5 - When set, the sustain level of the voice is maintained X until released; when clear, the sound begins to decay X immediately after hitting the SUSTAIN phase. X bit 4 - Keyboard scaling rate. This is another incomprehensible X bit in the Sound Blaster manual. From experience, if X this bit is set, the sound's envelope is foreshortened as X it rises in pitch. X bits 3-0 - These bits indicate which harmonic the operator will X produce sound (or modulation) in relation to the voice's X specified frequency: X X 0 - one octave below X 1 - at the voice's specified frequency X 2 - one octave above X 3 - an octave and a fifth above X 4 - two octaves above X 5 - two octaves and a major third above X 6 - two octaves and a fifth above X 7 - two octaves and a minor seventh above X 8 - three octaves above X 9 - three octaves and a major second above X A - three octaves and a major third above X B - " " " " " " " X C - three octaves and a fifth above X D - " " " " " " X E - three octaves and a major seventh above X F - " " " " " " " X X Bytes 40-55 - Level Key Scaling / Total Level X X 7 6 5 4 3 2 1 0 X +-----+-----+-----+-----+-----+-----+-----+-----+ X | Scaling | Total Level | X | Level | 24 12 6 3 1.5 .75 | <-- dB X +-----+-----+-----+-----+-----+-----+-----+-----+ X X bits 7-6 - causes output levels to decrease as the frequency X rises: X X 00 - no change X 10 - 1.5 dB/8ve X 01 - 3 dB/8ve X 11 - 6 dB/8ve X X bits 5-0 - controls the total output level of the operator. X all bits CLEAR is loudest; all bits SET is the X softest. Don't ask me why. X X Bytes 60-75 - Attack Rate / Decay Rate X X 7 6 5 4 3 2 1 0 X +-----+-----+-----+-----+-----+-----+-----+-----+ X | Attack | Decay | X | Rate | Rate | X +-----+-----+-----+-----+-----+-----+-----+-----+ X X bits 7-4 - Attack rate. 0 is the slowest, F is the fastest. X bits 3-0 - Decay rate. 0 is the slowest, F is the fastest. X X Bytes 80-95 - Sustain Level / Release Rate X X 7 6 5 4 3 2 1 0 X +-----+-----+-----+-----+-----+-----+-----+-----+ X | Sustain Level | Release | X | 24 12 6 3 | Rate | X +-----+-----+-----+-----+-----+-----+-----+-----+ X X bits 7-4 - Sustain Level. 0 is the loudest, F is the softest. X bits 3-0 - Release Rate. 0 is the slowest, F is the fastest. X X Bytes A0-B8 - Octave / F-Number / Key-On X X 7 6 5 4 3 2 1 0 X +-----+-----+-----+-----+-----+-----+-----+-----+ X | F-Number (least significant byte) | (A0-A8) X | | X +-----+-----+-----+-----+-----+-----+-----+-----+ X X 7 6 5 4 3 2 1 0 X +-----+-----+-----+-----+-----+-----+-----+-----+ X | Unused | Key | Octave | F-Number | (B0-B8) X | | On | | most sig. | X +-----+-----+-----+-----+-----+-----+-----+-----+ X X bit 5 - Channel is voiced when set, silent when clear. X bits 4-2 - Octave (0-7). 0 is lowest, 7 is highest. X bits 1-0 - Most significant bits of F-number. X X In octave 4, the F-number values for the chromatic scale and their X corresponding frequencies would be: X X F Number Frequency Note X 16B 277.2 C# X 181 293.7 D X 198 311.1 D# X 1B0 329.6 E X 1CA 349.2 F X 1E5 370.0 F# X 202 392.0 G X 220 415.3 G# X 241 440.0 A X 263 466.2 A# X 287 493.9 B X 2AE 523.3 C X X Bytes C0-C8 - Feedback / Algorithm X X 7 6 5 4 3 2 1 0 X +-----+-----+-----+-----+-----+-----+-----+-----+ X | unused | Feedback | Alg | X | | | | X +-----+-----+-----+-----+-----+-----+-----+-----+ X X bits 3-1 - Feedback strength. If all three bits are set to X zero, no feedback is present. With values 1-7, X operator 1 will send a portion of its output back X into itself. 1 is the least amount of feedback, X 7 is the most. X bit 0 - If set to 0, operator 1 modulates operator 2. In this X case, operator 2 is the only one producing sound. X If set to 1, both operators produce sound directly. X Complex sounds are more easily created if the algorithm X is set to 0. X X Byte BD - Amplitude Modulation Depth / Vibrato Depth / Rhythm X X 7 6 5 4 3 2 1 0 X +-----+-----+-----+-----+-----+-----+-----+-----+ X | AM | Vib | Rhy | BD | SD | TOM | Top | HH | X | Dep | Dep | Ena | | | | Cym | | X +-----+-----+-----+-----+-----+-----+-----+-----+ X X bit 7 - Set: AM depth is 4.8dB X Clear: AM depth is 1 dB X bit 6 - Set: Vibrato depth is 14 cent X Clear: Vibrato depth is 7 cent X bit 5 - Set: Rhythm enabled (6 melodic voices) X Clear: Rhythm disabled (9 melodic voices) X bit 4 - Bass drum on/off X bit 3 - Snare drum on/off X bit 2 - Tom tom on/off X bit 1 - Cymbal on/off X bit 0 - Hi Hat on/off X X Note: KEY-ON registers for channels 06, 07, and 08 must be OFF X in order to use the rhythm section. Other parameters X such as attack/decay/sustain/release must also be set X appropriately. X X Bytes E0-F5 - Waveform Select X X 7 6 5 4 3 2 1 0 X +-----+-----+-----+-----+-----+-----+-----+-----+ X | unused | Waveform | X | | Select | X +-----+-----+-----+-----+-----+-----+-----+-----+ X X bits 1-0 - When bit 5 of address 01 is set, the output waveform X will be distorted according to the waveform indicated X by these two bits. I'll try to diagram them here, X but this medium is fairly restrictive. X X ___ ___ ___ ___ _ _ X / \ / \ / \ / \ / | / | X /_____\_______ /_____\_____ /_____\/_____\ /__|___/__|___ X \ / X \___/ X X 00 01 10 11 X X X X | Detecting a Sound Card X | X | According to the AdLib manual, the 'official' method of checking for a X | sound card is as follows: X | X | 1) Reset both timers by writing 60h to register 4. X | 2) Enable the interrupts by writing 80h to register 4. NOTE: this X | must be a separate step from number 1. X | 3) Read the status register (port 388h). Store the result. X | 4) Write FFh to register 2 (Timer 1). X | 5) Start timer 1 by writing 21h to register 4. X | 6) Delay for at least 80 microseconds. X | 7) Read the status register (port 388h). Store the result. X | 8) Reset both timers and interrupts (see steps 1 and 2). X | 9) Test the stored results of steps 3 and 7 by ANDing them X | with E0h. The result of step 3 should be 00h, and the X | result of step 7 should be C0h. If both are correct, an X | AdLib-compatible board is installed in the computer. X | X | X | Making a Sound X | X | Many people have asked me, upon reading this document, what the proper X | register values should be to make a simple sound. Well, here they are. X | X | First, clear out all of the registers by setting all of them to zero. X | This is the quick-and-dirty method of resetting the sound card, but it X | works. Note that if you wish to use different waveforms, you must then X | turn on bit 5 of register 1. (This reset need be done only once, at the X | start of the program, and optionally when the program exits, just to X | make sure that your program doesn't leave any notes on when it exits.) X | X | Now, set the following registers to the indicated value: X | X | REGISTER VALUE DESCRIPTION X | 20 01 Set the modulator's multiple to 1 X | 40 10 Set the modulator's level to about 40 dB X | 60 F0 Modulator attack: quick; decay: long X | 80 77 Modulator sustain: medium; release: medium X | A0 98 Set voice frequency's LSB (it'll be a D#) X | 23 01 Set the carrier's multiple to 1 X | 43 00 Set the carrier to maximum volume (about 47 dB) X | 63 F0 Carrier attack: quick; decay: long X | 83 77 Carrier sustain: medium; release: medium X | B0 31 Turn the voice on; set the octave and freq MSB X | X | To turn the voice off, set register B0h to 11h (or, in fact, any value X | which leaves bit 5 clear). It's generally preferable, of course, to X | induce a delay before doing so. X | X | X | Acknowledgements X | X | Thanks are due to the following people: X | X | Ezra M. Dreisbach (ed10+@andrew.cmu.edu), for providing the information X | about the recommended port write delay from the AdLib manual, and the X | 'official' method of detecting an AdLib-compatible sound card. X | X | Nathan Isaac Laredo (gt7080a@prism.gatech.edu), for providing the X | port numbers for stereo sound on the Sound Blaster Pro. X SHAR_EOF chmod 0666 fmdoc || echo 'restore of fmdoc failed' Wc_c="`wc -c < 'fmdoc'`" test 21932 -eq "$Wc_c" || echo 'fmdoc: original size 21932, current size' "$Wc_c" fi # ============= howto ============== if test -f 'howto' -a X"$1" != X"-c"; then echo 'x - skipping howto (File already exists)' else echo 'x - extracting howto (Text)' sed 's/^X//' << 'SHAR_EOF' > 'howto' && XFrom: "ROBERTSON.JOEL" Subject: SB MIDI programming To: Multiple recipients of list IBMSND-L X At the request of Fergal Suipeil I am posting the following information on programming the SB MIDI port. X I ftp'd it from somewhere, I think it was ftp.cs.ruu.nl (131.211.80.17) in pub/MIDI/DOC. This is a good FTP site for music/MIDI stuff. X sbf.zip in PD1: on wsmr-simtel20.army.mil, and it's mirror sites such as wuarchive.wustl.edu, has some soundblaster programming information as does sbdos10.zoo in pub/heathh/sb on cco.caltech.edu X ===============BEGIN QUOTED MESSAGE=============================== X XFrom: voz5@elis.elis (Pedro e Paulo) Newsgroups: alt.sb.programmer Subject: Info on how to acess SB midi Message-ID: Date: 8 Apr 92 08:30:42 GMT X X X I received many requests on info about the Sound Blaster midi port, so insted of "emailling" I dicided to post it here. X The ideas expressed here are my own, and they reflect my investigations on the subject of midi I/O on Sound Blaster versions 1.5 and 2.0. X All info was obtained by following some software in msdos debug and by performing tests in PASCAL, because I DON'T have any documentation on SB. X These are the major ports for dsp (&midi) commands: X const X PORT_BASE = $0220; { may vary if you installed SB on other port } X DSP_RESET = PORT_BASE + $0006; X DSP_COMMAND = PORT_BASE + $000c; X DSP_WRITESTATUS = PORT_BASE + $000c; X DSP_DATAAVAIL = PORT_BASE + $000e; X DSP_READDATA = PORT_BASE + $000a; X X { the following are necessary for talking to PC's PIC } X PIC = $20; X EOI = $20; X PIC_IMR = $21; X To send a command to the DSP you must do this: X X procedure send(val:byte); X X begin X { you might want to consider some time-out to prevent crash } X while( port[DSP_WRITESTATUS] and $80 ) <>0 do; X port[DSP_COMMAND] := val; X end; X Reading a byte from midi port (on Sound Blaster v1.5 mode) is something like this: X X function midi_in:byte; X X begin X send($30); X X while( port[ DSP_DATAAVAIL ] and $80 ) = 0 do; X midi_in := port[ DSP_READDATA ]; X end; X For writing a byte to the midi port (on Sound Blaster v1.5 mode) use something like this: X X procedure midi_out {(b:byte)} ; X X begin X send($38); X send(b); X end; X There is another way to receive data from the midi port, the way is using hardware interrupts. The procedure is as follows: X - Prepare some buffer (probably circular) for holding the receiving data X - Save the old interrupt vector (in my case int15<>irq7 on SB config.) X - Point this interrupt vector to your procedure (i.e., midi_rec_isr) X - Prepare the PC's PIC (Programmable Interrupt Controller) to receive X (And enable) IRQ7 X - Do that strange while (if you can figure it out, please tell me) X - Send command ($31) X X procedure midi_recv_start; X X begin X midi_buf_in:=0; X midi_buf_out:=0; X X getintvec($0f,oldint15); X setintvec($0f,addr(midi_recv_isr)); X X port[ PIC_IMR ]:=port[ PIC_IMR ] and $7f; X X while port[ DSP_DATAAVAIL ] and $80<>0 do aux:=port[ DSP_READDATA ]; X X send($31); X end; X X Now for the interrupt service routine: X X procedure midi_recv_isr; interrupt; X var b:byte; X begin X b:=0; X X repeat X while (port[DSP_DATAAVAIL] and $80=0) do; X X { Store info in buffer } X midi_buf[midi_buf_in] := port[ DSP_READDATA ]; X midi_buf_in := (midi_buf_in + 1) mod MIDI_BUF_LEN; X inc(b); X X until b>=4; X { In mode SBv1.5 only one cycle is necessary <> only 1 byte read X per interrupt } X X { next line>> acknowledges the interrupt to the DSP on SB } X b:=port[ DSP_DATAAVAIL ]; X X { Send End Of Interrupt Command to PC's PIC } X port[ PIC ]:= EOI; X end; X The necessary cleaning up after reading: X X procedure midi_recv_stop; X X begin X { reset the SB's DSP , see bellow } X reset_dsp; X X { Disable IRQ7 interrupts } X port[ PIC_IMR ]:=port[ PIC_IMR ] or $80; X X { Restore the old interrupt vector } X setintvec($0f,oldint15); X end; X X procedure reset_dsp; X var aux:byte; X begin X port[DSP_RESET]:=$01; X X asm { just wait for a while, probably on 486 this is not enaugh } X push ax X pop ax X end; X X port[DSP_RESET]:=$00; X X while port[DSP_DATAAVAIL] and $80<>0 do aux:=port[DSP_READDATA]; X end; X Now for the problem, the Sound Blaster v1.5 is Half-Duplex in midi communications so simultaneous "record" and "playback" on midi is not possible. X I think Creative Labs was crowded with complains about this so they decided to lunch Sound Blaster 2.0 (which I now have). The new features include: more sampling&recording speed with DSP and full duplex midi with Time Stamp and 64 byte FIFO. X I believe that Time Stamp is an internal mechanism to stamp incoming bytes with some time signature for "perfect" recording purposes. X So the following changes can improve the examples I posted before: X - At midi_recv_start, send command $37 instead of $31 to enter in X Sound Blaster 2.0 full duplex receive mode. X - The midi_recv_isr interrupt routine now reads 4 bytes for each X byte that becomes available at midi port (1 byte data + 3byte X time stamp). X - The only way to stop is to reset the DSP because any of the other X dsp funcs won't work (sorry, cant play vocs while recording or playing X midi tunes) X - One point is important now, for sending bytes to the midi port the X sequence: send($38) send(byte) at midi_out now changes to send(byte) X (that's why we can not use any other DSP commands without resetting) X I hope this will help you. Remember that this was obtained without any documentation so something may be wrong or work improperly. If PASCAL, or better Borland's Turbo Pascal 6.0 doesn't meet your ideal language, email me your doubts and I will try to help you further. (Sorry about the English) X X Pedro Carvalho X voz5@elis.inesc.pt X PS: Does anyone nows how we can use the drum secction on SB fm (adlib) ? X ------------------------------------------------------------------------ X ___ ___ \ / / \ / --- : INESC - Instituto de Engenharia e X \ / | | / |___ : Sistemas de Computadores, Lisboa X \ / | | / | : Portugal X \/ \___/ /___ ___| : voz5@elis.inesc.pt X ===================END OF QUOTED MESSAGE =========================== X X Joel Robertson X --------------------------------------------------------------------------- Joel Robertson | Internet: robertson@ewir-wr.robins.af.mil (131.45.15.18) Robins AFB, GA | CIS: 70675,160 or X | >INTERNET:robertson@ewir-wr.robins.af.mil --------------------------------------------------------------------------- X SHAR_EOF chmod 0664 howto || echo 'restore of howto failed' Wc_c="`wc -c < 'howto'`" test 7111 -eq "$Wc_c" || echo 'howto: original size 7111, current size' "$Wc_c" fi # ============= midi ============== if test -f 'midi' -a X"$1" != X"-c"; then echo 'x - skipping midi (File already exists)' else echo 'x - extracting midi (Text)' sed 's/^X//' << 'SHAR_EOF' > 'midi' && XFrom tjt Thu Aug 8 16:09:55 1991 Return-Path: Received: by blink.att.com (4.1/SMI-3.2) X id AA04332; Thu, 8 Aug 91 16:09:52 EDT Path: cbfsb!att!pacbell.com!mips!samsung!olivea!uunet!zephyr.ens.tek.com!tektronix!percy!m2xenix!quagga!undeed!ucthpx!uctcs!gram XFrom: gram@uctcs.cs.uct.ac.za (Graham Wheeler) Newsgroups: comp.music Subject: Make your own MIDI for Soundblaster Message-Id: Date: 8 Aug 91 07:41:33 GMT Sender: news@ucthpx.uct.ac.za (UCT News Admin.) Organization: University of Cape Town Lines: 238 Apparently-To: tjt Status: R X Hi all X The following is one of the replies I received about the SB: X ------------------------------------------------------------------------------- X ============================== X A cheap MIDI connector box X for the Sound Blaster card X v1.2 March 22nd, 1991 X X by X Adam Mirowski X mir@chorus.fr X ============================== X X X Sound Blaster has a "built-in MIDI interface", but "all you need X is a MIDI Connector Box (optionally available) in order to connect X your SB to MIDI instruments or keyboards", says the add on the X box. The list price for that gadget is as high as $79.95 and X anyway it is not available here in France. Also, the MIDI X interface is not compatible with the MPU-401 standard (and de X facto norm) and is only one-way-at-a-time. So the box is not worth X the money, except if you try to set up it by yourself. For $5 you X can get the basic functionalities and for $10 everything which X comes with the original one. X X I have heard on Usenet recently that Sound Blaster will soon come X out with a standard MIDI interface. Chances are that this circuit X will also work with that new version. X X X Parts X ===== X X Qty Name Type Tandy ref X --------------------------------------------------- X 1 Optocoupler 4N25 276-9294 X 3 Resistors 220 ohm 271-015 X 1 Resistor 1 Kohm X 1 AND gate 74LS08 276-9276 X 2 DIN plugs Female 5 pins 274-9110 X 1 Canon DB plug Male 15 pins Not sold X [1] Diode 1N914 X 1 Veroboard (*) 5cm by 5cm X 8 Wires Not shielded X 1 Box to put all that stuff inside X X X [] - didn't use it myself. X X (*) It is a piece of X epoxide with a raster of holes spaced at 2.54mm. On one side X there are preprinted copper tracks along each line of holes X (in one direction only). You cut off unused portions of the X tracks and join the other with straps, so as to get a X primitive form of a printed circuit board. You then insert the X electronic parts and solder them. X X X X Sound Blaster MIDI/Game connector REAL cabling X ============================================== X X X +------------------------------------------+ X ! Pin Signal ! X !------------------------------------------! X ! 1 +5V ! X ! 2 X button for joystick A ! X ! 3 X potentiometer for joystick A ! X ! 4 Ground ! X ! 5 Ground ! X ! 6 Y potentiometer for joystick A ! X ! 7 Y button for joystick A ! X ! 8 +5V ! X ! 9 +5V ! X ! 10 X button for joystick B ! X ! 11 X potentiometer for joystick B ! X ! 12 MIDI out ! X ! 13 Y potentiometer for joystick B ! X ! 14 Y button for joystick B ! X ! 15 MIDI in ! X +------------------------------------------+ X X The interesting pins are 12, 15, 4 (or 5) and 9 (or 8 or 1). X X BTW, if your joystick Y cable assumes that pin 12 is ground (as it X is on a normal game port), it will not work with the SB. X X X Interface cabling X ================= X X The cabling is roughly the same as in the MIDI 1.0 Specification, X except that I used a different optocoupler and "AND" gates instead X of inverters (simply because Tandy sold the former with docs :-). X X Numbers between parentheses are pin numbers. ICs have a standard X pin numbering scheme. Other parts have pin numbers written on X them. For resistors, it's simply to make difference between the X two ends. X X X 6 5 4 X +--!----!----!--+ X Usually ! ! IC seen from the top X a hole --> > ! X ! ! X +--!----!----!--+ X 1 2 3 X X "MIDI-in", "MIDI-out" design the female MIDI plugs. "Game/MIDI" X designs the 15 pin female connector on the SB. X X X FROM PIN TO PIN X X X MIDI input part X --------------- X MIDI-in (4) Resistor1 220ohm (1) X Resistor1 220ohm (2) Optocoupler (1) X Optocoupler (2) MIDI-in (5) X [Optocoupler (1) Diode -] X [Optocoupler (2) Diode +] X X Games/MIDI (9) Resistor4 1Kohm (1) X Resistor4 1Kohm (2) Optocoupler (5) X Games/MIDI (15) Optocoupler (5) X Optocoupler (4) Game/MIDI (4) X X X MIDI output part X ---------------- X Games/MIDI (12) AND gate (1) X AND gate (1) AND gate (2) X AND gate (3) Resistor2 220ohm (1) X Resistor2 220ohm (2) MIDI-out (5) X MIDI-out (4) Resistor3 220ohm (1) X Resistor3 220ohm (2) Game/MIDI (9) X Games/MIDI (9) AND gate (14) X Games/MIDI (4) AND gate (7) X X X Final remarks X ============= X X When using a "veroboard", don't forget to cut tracks under the IC X and the optocoupler, or they will be short-circuited. X X You will probably also want to setup two MIDI cords, to attach the X interface to an instrument. To stay under $5, you could use male X plugs instead of female ones for the interface and plug them X directly into the instrument. X X When preparing the cords, be careful about not swapping the wires. X The pin 4 from one plug must be wired to pin 4 from the other end, X and the pin 5 must be attached to pin 5. None of the other pins X must be wired, nor the overall cable shielded. There is no ground X in MIDI cords. X X If you want more outputs, you have to slightly extend the MIDI X output part. I would rather have only one AND gate input attached X to the SB MIDI-out pin and only one MIDI-out plug per AND gate X output. If Creative Labs offer 5 MIDI outs in the original X Connector Box, it is probably because they use simple inverters X (or buffers) and there are 6 per IC. As I previously said, I X bought AND gates only because they had data sheets attached, X whereas inverters/buffers had not... X X Direct your remarks to mir@chorus.fr, or to X X M. Adam Mirowski X Chorus systemes X 6, avenue Gustave Eiffel X F-78182 Saint-Quentin-en-Yvelines CEDEX X FRANCE X X My phone number is +33 (1) 30-64-82-00 X X I obviously won't take any responsibility for the damages you X could do to your Sound Blaster or to your MIDI equipment while X using this interface. X X SUPPLEMENT ---------- X I) You can use invertors in place of AND gates. The schematic diagram would be the following (for 2 outputs), instead of the old "MIDI output part" description. X X X !\ !\ SB ! \ 2 ! \ 4 +--------+ 5 MIDI 4 +--------+ SB MIDI ---! >o--+---! >o----! R=220 !----[ out ]---! R=220 !---- +5V out 1! / ! 3! / +--------+ plug 1 +--------+ (pin 9) X 12 !/ ! !/ X ! X ! X ! !\ X ! ! \ 6 +--------+ 5 MIDI 4 +--------+ SB X +---! >o----! R=220 !----[ out ]---! R=220 !----- +5V X ! 5! / +--------+ plug 2 +--------+ (pin 9) X ! !/ X ! X ! X +--- etc. X Pin 14 of the chip must be connected to +5V, and pin 7 to ground, just like with the previous one. Also don't forget to remove the strap between old pins 1 and 2! It is no more necessary and would court- circuit the first inverter. X The other inverters in the chip are cabled between pins 13 (input) and 12 (output), 11 and 10, 9 and 8 (all the inverters point to the right). X If you try to use CMOS inverters (4... series) instead of TTL ones (74.. and 74LS... series), please remark that CMOS inverters "point" to the left. X Tandy references are different for 74.., 74LS.. and 74HC.. circuits. X II) If you really want to save money, don't put any AND gate. Connect together the wires going to pins 1, 2 & 3. Don't short-circuit the power supply pins; leave them unconnected. X X III) For the optocoupler, you could also use a 4N26, a 4N27 or a 4N28. X X X -- Graham Wheeler | "That which is weak conquers the strong, Data Network Architectures Lab | that which is soft conquers the hard." Dept. of Computer Science | Lao Tzu - Tao Te Ching Ch. 78 University of Cape Town | There's no justus; there's just us SHAR_EOF chmod 0664 midi || echo 'restore of midi failed' Wc_c="`wc -c < 'midi'`" test 9553 -eq "$Wc_c" || echo 'midi: original size 9553, current size' "$Wc_c" fi # ============= voicelib ============== if test -f 'voicelib' -a X"$1" != X"-c"; then echo 'x - skipping voicelib (File already exists)' else echo 'x - extracting voicelib (Text)' sed 's/^X//' << 'SHAR_EOF' > 'voicelib' && X /*-----------------------------VOICE.H--------------------------*/ X /****************************************************************/ /* Header file for VOICE.OBJ - using the CT-VOICE.DRV driver */ /* Ilia Bisnovatyi, 1992 */ /* Note: I take no credit for the information contained in */ /* this file, as well as no responsibility for possible */ /* damage resulting from its use. */ /****************************************************************/ X extern char far *driver_mem; extern void far (*driver)(void); X X void LoadDriver(void); /****************************************************************/ /* Loads CT-VOICE.DRV into memory. Path to the driver is */ /* determined from the SOUND variable in DOS environment */ /****************************************************************/ X int GetVersion(void); /****************************************************************/ /* Get the version number of the CT-VOICE.DRV */ /* Returns the Version number */ /****************************************************************/ X void SetIOAddr(int base); /***************************************************************2*/ /* Override the IOaddress found inside the CT-VOICE.DRV file. */ /* base is the new IO address. */ /****************************************************************/ X X void SetIRQ(int irq); /****************************************************************/ /* Allows you to override the Interrupt number in the driver. */ /* IRQo is your new interrupt number (3, 5, 7 or 9). */ /****************************************************************/ X X int InitialiseDriver(void); /****************************************************************/ /* Call this in the beginning (after LoadDriver) */ /****************************************************************/ X X void UninstallDriver(void); /****************************************************************/ /* Call this in the end of your program. */ /****************************************************************/ X X void SpeakerOnOff(int onoff); /****************************************************************/ /* Set the speaker on/off. Off is mode 0, and On is anything */ /* else. This is the fourth thing you should do in your */ /* initialization. */ /****************************************************************/ X X void SetStatusWord(unsigned int *addr); /****************************************************************/ /* Sets the location of the status word. This is the third */ /* thing you should do, after loading the driver and */ /* initializing it. */ /* The StatusWord will contain $0FFFF if input/output is in */ /* output, and 0 when it's done. It will also hold the values */ /* of the markers in voice files if any are encounterred, */ /* allowing you to coordinate output with your programs. */ /****************************************************************/ X X X void OutputVoice(char *buffer); /****************************************************************/ /* Play it! */ /****************************************************************/ X X void InputVoice(int sample_rate, char *buffer, long length); /****************************************************************/ /* Input digitized sound. */ /* Length: the length of the input buffer. */ /****************************************************************/ X X void StopVoiceProcess(void); /****************************************************************/ /* Stop playing voice */ /****************************************************************/ X X int PauseOutputVoice(void); /****************************************************************/ /* Pause the voice output */ /****************************************************************/ X X int ContinueOutputVoice(void); /****************************************************************/ /* Continue playing the paused voice */ /****************************************************************/ X X char *LoadF(char *name); /****************************************************************/ /* Load a VOC file into memory. Returns a pointer to a buffer */ /* containing the data (stipped off header). Don't forget to */ /* free the buffer in the end! */ /****************************************************************/ X X X X X /*-----------------------------VOICE.C--------------------------*/ X /* X Example code that uses CT-VOICE.DRV to access the Soundblaster X DAC channel. */ X #include #include #include #include #include #include X char far *driver_mem = NULL; void far (*driver)(void) = NULL; X void LoadDriver(void) { X FILE *f; X long length; X char *sp; X char sn 129Ü; X X strcpy(sn,""); X sp = getenv("SOUND"); X if(sp) X { X strcpy(sn,sp); X if(sn strlen(sn)-1Ü != '\\') X strcat(sn,"\\"); X } X strcat(sn,"drv\\CT-VOICE.DRV"); X X f = fopen(sn,"rb"); X if(!f) X return; X length = filelength(fileno(f)); X X driver_mem = (char far *)malloc((int)length + 16); X if(FP_SEG(driver_mem) != 0) X driver = MK_FP(FP_SEG(driver_mem)+1,0); X else X driver = driver_mem; X X fread(driver,1,(int)length,f); X X fclose(f); } X int GetVersion(void) { X _BX = 0; X (*driver)(); X return _AX; } X void SetIOAddr(int base) { X _BX = 1; X _AX = base; X (*driver)(); } X void SetIRQ(int irq) { X _BX = 2; X _AX = irq; X (*driver)(); } X int InitialiseDriver(void) { X _BX = 3; X (*driver)(); X return _AX; } X void UninstallDriver(void) { X _BX = 9; X (*driver)(); } X void SpeakerOnOff(int onoff) { X _BX = 4; X _AX = onoff & 0x0001; X (*driver)(); } X void SetStatusWord(unsigned int *addr) { X _BX = 5; X _ES = FP_SEG(addr); X _DI = FP_OFF(addr); X (*driver)(); } X void OutputVoice(char *buffer) { X _BX = 6; X _ES = FP_SEG(buffer); X _DI = FP_OFF(buffer); X (*driver)(); } X void InputVoice(int sample_rate, char *buffer, long length) { X _BX = 7; X _AX = sample_rate; X _ES = FP_SEG(buffer); X _DI = FP_OFF(buffer); X _DX = (unsigned)(length >> 16); X _CX = (unsigned)(length & 0x0000ffff); X (*driver)(); } X void StopVoiceProcess(void) { X _BX = 8; X (*driver)(); } X int PauseOutputVoice(void) { X _BX = 10; X (*driver)(); X return _AX; } X int ContinueOutputVoice(void) { X _BX = 11; X (*driver)(); X return _AX; } X X char *LoadF(char *name) { X FILE *f; X char *buf; X long length; X X f = fopen(name,"rb"); X if(!f) X return NULL; X X length = filelength(fileno(f)) - 0x1a; /* Offset to the end of the VOC header /* X X buf = (char *) malloc((int)length); X fseek(f,0x1a,SEEK_SET); X fread(buf,1,length,f); X X fclose(f); X return buf; } SHAR_EOF chmod 0664 voicelib || echo 'restore of voicelib failed' Wc_c="`wc -c < 'voicelib'`" test 7318 -eq "$Wc_c" || echo 'voicelib: original size 7318, current size' "$Wc_c" fi exit 0