XSD XGE SOUND DEVICE "Raw" sound services Whew! This was the hardest part of all, my target was (and is) to provide "basic sound services" to implement digital sound effects and decent playback of MIDI and/or MOD files. To do this i had to "think in advance" about what i want NOW from a decent sound system and what i MAY NEED in the future (Heck! A sinestetic interface needs full-power sound support just to look decent). I've included some "overkilling" features like "syncronized" playback and delayed play, i think i won't use 'em for at least a year (until i implement holographic/3Dbinaural sound or other nice things). In this release midi/mod music playback support IS NOT INCLUDED (it takes too much time to devenlop a "do it all" music driver) (not to mention all the different MOD file "extensions" and the problem i had with finding midi instruments sample/patches) I just wanted to give you an "unified model" to help you make "portable" SOUND DRIVERS you can recycle from a game to another and distribuite around, so more games will support to the max. your soundcard. Music support "above" or "side by side" the sound drivers is up to you (not very hard, if you just want a "basic" MOD player you can do it in just a week). Another thing not included is support for 16bit sound output. I've included comments & descriptions about how to make a 16bit driver but the current 386mixer module DOES NOT SUPPORT 16bit sound (currently i don't have a 16bit sound card available for testing) Eh! If you want to make a cool game with lots of graphics and sounds and want to make it run with 4Mbyte of ram .... 8bit is good enough and uses half the memory of equivalent 16bit samples. In the next MAJOR release (386P 3.00) there will be complete 16bit support into 386mixer, plus lots of other goodies. ------------------------------------------------------------------------------ Well, sound on a pc compatibles is the part i'm less skilled at all. I bought a sound card last summer, and started making experiments with it but i'm not an expert. Another problem is that sound hardware is the less standardized thing on PCs and sometimes needs a complex setup and trimming. By the way, given the current trends i plan to "standardize" on MOD files for music sources (and later MIDI, because is a lot harder to support and a lot less flexible) and on a "wavetable mixer sound system" for digital sound that's easy to implement on the current sound hardware. By the way, if you still haven't one, go get a sound card at least a cheap SoundBlaster Pro compatible (HARDWARE COMPATIBLE!!!!!! Not a thing with software emulation!!!!!). If you don't want to, .... well you are stuck with the beeper buzzs & clicks plus higher cpu overhead. ------------------------------------------------------------------------------ What's an XSD driver? An XSD driver is a software module that interfaces you program to any hardware device (or software module) capable to play sound. There are basically TWO "sound output" models supported by XSD drivers : XSDACD XGE Sound DAC Device A DAC device for sound output (with or without DMA support) with software simulated multiple voices XSWAVD XGE Sound WAVetable Device A multiple wavetable device with on-board ram An XSDACD hardware supports playback of ONE digital sound sample at a fixed sample rate, without "effects". It can be the any kind of DAC, from the 1bit "dac equivalent" pc-speaker output to an 8bit sound dac plugged into the printer port (Example: Disney SoundSource, SoundPlayer, Covox kits etc. etc.) to a 8/16bit dac included into a "real" sound card (Examples: SoundBlaster, Pro Audio Spectrum, etc. etc.) An XSWAVD is a sound card with internal ram and "multiple wavetable output hardware" it can play multiple sounds and manipulate 'em with OPTIONAL effects (Examples: Gravis UltraSound,SoundBlaster AWE32, Ensoniq boards, etc. etc.) HOW AN XSD DRIVER IS INSTALLED: You don't access thge driver directly, you use an higher level module called 386mixer that "smooths out" differences between different sound hardware and gives you the illusion to always have a multi-voice wavetable system. When 386mixer initializes it checks in order for: 1) the external default sound driver module XSD.XSD 2) if XSD.XSD is not present, 386mixer "activates" a built-in driver if sound output is on [ usually you should let the user choose between one of these drivers: a) "null" driver (no sound) b) pc-speaker driver c) 8bit SoundBlaster driver ] The XSD driver gets "connected" to the 386MIXER interface module. 386MIXER "unifies" support for multi channel digital sound thru dac and wavetables devices (see the 386mixer.inc file). An XSWAVD driver MUST include support for XDACW (this way it is possible to "overflow" the wavetable ram and store wavetables in excess into system ram). If XSWAVD is not present it can be emulated on the XSDACD by 386mixer (remember that at least the pc-speaker is present) but this will produce additional cpu work. Because of this "emulation overhead", 386mixer includes options for partially disabling "wavetable sound". Here follows the description of the XSD interface, but i suggest you to read rm_sound.xt first because some terms described there are not explained here. XSD DAC INTERFACE: Knee deep in the DAC :) If just a DAC is present (even the PC-SPEAKER can be seen as a 1bit DAC controlled with sort of pulse width modulation) this baby is capable to simulate a multi-voice sound system "mixing on the flight" the sound data. In practice, a "simple" multi-voice wavetable device is simulated by software routines (hoping your cpu is powerful enough) so you don't see the "raw" dac and you can think you have a decent sound hardware available. Instead of mixing sounds every time a new sample has to be played, the mixer mixes "a block" of samples and then sends the block to the actual sound hardware. This way we can simulate multiple voices (softchannels) on a single dac port (hardchannel) AND still take advantage of the DMA support most sound cards have. Even if the sound card has no DMA, the "block" mixing helps reduce the mixing overhead (you reduce the load/store of pointers needed to reference the sound samples to mix). DAC FEEDBACK RATE: When you "play" a sound it actually starts at the next "mix block" interval, so, to avoid "decoupling" problems between sound and video you can control the DAC FEEDBACK RATE (the frequency the "mix sound" routine is called and thus the "play sound --> hear sound" feedback frequency you get). When you set the DAC FEEDBACK RATE, the 386mixer system just calculates how big must be the "mixage block" it sends to the sound hardware to have the sound hardware "call for reload" the mixage system at the requested rate. DAC PLAYBACK RATE: The playback rate is the frequency you send your sound samples to the DAC. PRACTICAL LIMITS ON PLAYBACK AND FEEDBACK RATES: Usually, the higher the playback rate, the better sound quality you get but more memory is needed to store sound samples, and more time is spend by the cpu to mix samples. The feedback frequency has not to be too high (or you'll loose the speed advandaces of "block mixing" and you will add too much noise because of the possible "sound gaps" between a sound block and the next) nor too low (or you'll "decouple" sounds from animation). The mixing itself can be a cpu intensive thing if you play sounds at high playback rates or in 16bit stereo. Remember to include into you program a way to control the capabilities of the sound systems (i.e. so if 44Khz, 16bit stereo sound slows down the game or uses too much memory, the user can set the system to 8bit 8Khz mono sound). Remember to include an EXTERNAL setup program to take care of settings that may hang your main program. AUTOROTATION: When you play a sound, you can use a specific softchannel or tell the mixer to "autorotate" (choose a channel not playing OR the channel that is playing the same sound for the longest time). Using autorotation you can have impressive multi-voice sound with very few channels, but sometimes you want to exclude some channels from autorotation (i.e. if you want to use a channel to play the soundtrack you don't want a new sound to autorotate on it). To keep care of this there are options in the initialization routine. THE FEEDERS: This "DAC software mixer" looks very weak, isn't it? Well, you can EXTEND IT !!! Let's lee how.... Question: What happens when a sample on a softchannel is completed ? Answer: The softchannel FEEDER routine gets called. Every softchannels has a "feeder", when the currently playing sound is completed, the softchannels' feeder routine is called and it must "feed" the next sample to play to the mixage system. Usually when a sound ends playing on a channel, that channel is set to a "silence" soundtrack, but you can specify what sound to repeat on sound termination (this way you can add "background sounds" when no specific sounds have to be played). This "reloading" is performed by the default "feeder" routine, if you change the feeder you can do more complex things (like "composing" sound and envelopes on the flight). 386Mixer includes "extended feeders" and other support code to let you emulate on softchannels the capabilities of a "super" wavetable device: - volume control - volume ramps - panning control - panning ramps - playback rate control - playback rate ramps - delayed playback - synchronized playback If all this is not enough, you can hook to every softchannel a "custom" feeder to add other capabilities or to override the default capabilities. These "feeders" can be allocated indipendently channel-by-channel so you can minimize the sound processing overhead. MASTER VOLUME CONTROL: The XSDACD driver can provide "MASTER" SOUND VOLUME control, if it does the mixer will use the fastest mixage-routine it has and will leave the sound output volume control to the driver. If no master volume control is available (argh!) the mixer will use a slower routine that supports software volume control. If you don't want sound volume control (i.e. because your speakers have volume controls) you can disable it. XSD WAVETABLE INTERFACE: The XSWAVD device supports all the functions provided by XSDACD devices plus extra capabilities. These capabilities usually include AT LEAST: - hardware mixing of multiple "voices" - storing of sound samples into "on board" soundcard ram - hardware support for volume control and panning control. Practically speaking, if you have a wavetable based sound card you can "move to hardware" lots of functions that using an XSDACD you'd have to perform with software emulation and "feeders". I call "wavechannels" the "hardware enhanced" softchannels (even if when you play sounds on 386mixer you don't see the difference if you don't need to) As i said before, an XSWAVD includes support for XSDACD too the reason for this is that only samples stored into "on board" soundcard ram can take advantage of wavetable hardware support. If there is not enough ram into the soundcard it is still possible to load and play other samples loaded into system ram. When you want to play a sound, the mixer can detect where the actual sound data is and use the appropriate channel (softchannel or wavechannel). The "virtualized" mixer sound channels are called soundchannels they will be implemented on softchannels or on wavechannels depending on where the digital sound data is stored. Sounds can be on wavetable ram and on system ram (but a single sound must be either totally into system ram or into wavetable ram, not splitted between them). Because of this, you MUST have as many "not autorotating" softchannels as the "not autorotating" wavechannels. When you exclude from autorotation wavetable sound channel N you exclude "wavetable emulating" softchannel N AND wavechannel N (so you can play a Sound on channel N indipendently from where it resides). You can have more "autorotating" wavechannels than softchannel-emulated ones but the "not rotating" ones must be in the same number. The reverse applies to softchannels. This is hidden by the 386mixer module (when you say "play wavetable sound on channel N" it will be the mixer that will select the correct sound channel either a real one or an emulated one). If you want N "not autorotating" soundchannels the mixer will set up N "not autorotating" softchannels and N "not autorotating" wavechannels. 386mixer will choose the correct softchannel or wavechannel to use. Of course, you can always "limit" the system an tell it to "not emulate" if you can put everything into soundcard ram. REAL OVERKILL: There are three "capabilities" that look like they are overkill for a "basic" sound system: - playback rate ramps These are useful to simulate the "doppler effect" sound distortion caused by ACCELERATING/DECELERATING sound sources. ( If for example an airplane runs to you, then decelerates turns around you and then runs away, you will hear the "swhoosh" caused by the jet engine changing frequency in a rate ramp, a constant rate level (together with a panning ramp) and a final rate ramp). I don't even know if i will really want to implement such things but i may decide to do so, and because of this 386mixer has the "hooks" needed to implement it. - delayed playback This is useful to simulate echo effects (together with panning and volume control), and provide "hooks" for 3dbinaural sound. - synchronized playback This is useful to take care of sound system's limitations when playing on XSDACW and wanting a group of sounds starting together. You can do the same turning off and on irqs, but this way it is possible to minimize system overhead. THE GOOD THE BAD AND THE UGLY, how to speed up things. The golden rule is: The lower the playback rate, the faster you mix (less samples to process) but this also means the worse the sound. If you don't want to walk this way, you can try .... If you just make not-3d games, use a "simple" DAC model (it has the least cpu overhead) an use a stripped down music system with no support for volume, panning and variable playback rate ramps. Faster "DAC sound": To further speed-up sound generation it is possible to cut other corners. Because softchannels are mixed in 4 channels groups when "no effects" are used, if you use 4 or less softchannels the mixer can reduce the sound resolution (8 to 6 bits or 16 to 12 bits) to be sure no sample overflows can happen and get a faster mixing. If you choose not to use "software emulated" master sound volume control you can get another little speed gain. Faster WAVETABLE EMULATION: Volume ramping and pan ramping adds TWO steps to wavetable emulation playback ramping adds another. Removing panning and freq.ramping you can reduce sound manipulation overhead. These "ramping" effects are only needed if you want to include support full support for MOD/MIDI files playback or if you want "sound motion" effects. [ using both volume and pan ramps you can produces "sound distortion" caused by sound sources ACCELERATING/DECELERATING AT HIGH SPEED while using volume ramps and panning control you can produce effects equivalent to MOVING sound sources] Volume control and panning control can be eliminated if you don't need "sound source 2D positioning". Playback rate control can be eliminated if you don't need doppler effects at all and don't play MOD/MIDI files. ALL THESE OPTIMIZATIONS CAN BE DONE "CHANNEL BY CHANNEL" with different settings for every channel and ONE COMMON SETTING for all the autorotating sound channels. Faster sound playback on MULTIPLE WAVETABLE HARDWARE: By turning on some flags in the 386mixer configuration menu, you can tell the system to store everything into wavetable ram, so no system ram will be used to store sound samples and no emulation at all will happen. Now, let's see the sound system capabilities depending on the available hardware: HARDWARE: DAC: WAVETABLE: WAVETABLE EFFECTS: SPEED: MONO DAC yes emulated volume and looping medium STEREO DAC yes emulated volume,panning and looping slow MONO WAVETABLE yes yes volume and looping fast STEREO WAVETABLE yes yes volume,looping and panning fast & now, the mixer .... ------------------------------------------------------------------------------- THE COMPLETE 386MIXER INTERFACE _MixInit: Initializes sound system in: All the "user defined" entries into the _XSDTable must be set to tell the mixer what you exactly want out: The _XSDTable entries modified to the nearest values the current driver can support Setting impossible values (i.e -1) into parameters the mixer system responds setting itself to the "default" status. The "dac mixer feedback frequency" is the frequency the ac mixer system "feeds" a new mixed sound data block to the dac hardware. Given the current 4k block limit, the lowest "feed" frequencies can be: Frequency 8bit 16bit/8bit_stereo 16bit_stereo 8000 2Hz 4Hz 8Hz 11000 3Hz 6Hz 12Hz 22000 6Hz 12Hz 24Hz 44100 11Hz 22Hz 44Hz For maximum "animation/sound feedback" it is better to choose a 30..45Hz feedback frequency, or a feedback frequency twice the frame rate if the frame rate is under 20 FPS. DAC "soft channels" and Wavetable "wave channels" are numbered starting from 0, but if wavetable hardware is present it must reserve one or two wavechannels to simulate the DAC hardchannel. HOW _MixInit WORKS: First of all it tries to load&init XSD.XSD the "not supported" entries are set to the default emulation code. The config data and environment var is then read and a pointer to it is set into the device table. Then the check routine is called _XSD_CHECK (sound hardware check) It must return carry clear if successful. Then _XSD_INIT is called. Once this is completed, the config file is rewritten with the current settings (settings can be modified by the check or the init routine). At last _XSD_ON is called and the sound system is ready to go. N.B. The config files contains the "old" iobase/irq/dma settings plus the volume settings and other things. ; XSD DRIVER TABLE ; - All entries marked with [*] means the user/program ; can set 'em as it want, but the driver will correct 'em to the nearest ; supported value. ; ; - All entries marked with [@] means their meaning can be different ; if a wavetable driver is present (example: if a field contains ; a pointer to a system ram location when a "dac" device is used, ; when a "wavetable" is used it could be a pointer to soundcard ram). ; - All entries marked with [W] are "wavetable specific" fields ; the wavetable driver can use for storing internal values ; "the name of the entry" is just indicative, the XSWAVD driver ; can use it for anything it want!!!! ; - All entries marked with [C] means that a "custom routine" may change ; the meaning of the entry. ; ; - Field sizes: [D] = dword, [W] = word, [B] =byte. align byte _XSDTable dd 0 ; dummy field internally used by the XSD driver. ; the XSD driver code receives a pointer to _XSDTable ; and thru it can reference all the variables ; following it.... _XSD_DRVTYPE dd 0 ; XSD driver capabilities, flags set by the XSD driver ; these flags are set by the xsd driver to tell 386mixer ; what the hardware can do xsd_dacvol=1 ; set= device supports "master" volume control ; the following flags describes the XSWAVD capabilities ; (available only if xsd_wavedriver is set) xsd_volctrl=2 ; set= device supports VOLUME control xsd_panctrl=4 ; set= device supports PANNING control xsd_ratectrl=8 ; set= device supports xsd_volramp=16 ; set= device supports VOL. RAMPS xsd_panramp=32 ; set= device supports PAN. RAMPS xsd_rateramp=64 ; set= device supports playback rate ramps ; specific driver capabilities xsd_stereo=128 ; set= stereo sound output xsd_16bit=256 ; set= 16bit SAM sound output (16bit integer samples) ; else 8bit PCM sound output (8bit unsigned samples) ; CURRENTLY ONLY 8bit PCM is supported ; 16bit will be included in 386P 3.00 xsd_wavedriver=512; set= device is a multiple wavetable device ; (and XSWAVD device) ; else it is a DAC device _XSD_MIXTYPE dd 0 ; 386mixer capabilities ; list of flags for _XSD_SETTINGS and their names ; these flags lets you fine tune the mixer capabilities ; ; emulation control flags, these are global flags you can use ; at startup to globally turn or or inhibit some emulation capabilities ; (i.e. if you want volume ramping on a channel ; and volume ramping is globally disabled ; that channel won't be set for volume ramping) ; THESE ARE IGNORED IF THE CAPABILITY IS PERFORMED BY HARDWARE mix_dacvol=1 ; set= software master volume control mix_volcrtl=2 ; set= software volume control mix_pancrtl=4 ; set= software panning control mix_ratectrl=8 ; set= software playback rate control mix_volramps=16 ; set= software volume ramping on mix_panramps=32 ; set= software pan ramping on mix_rateramps=64 ; set= software playback rate ramping on ; sample conversion/mapping/allocation flags mix_cut=128 ; set= mixer performs "cutted" sample mixing ; (this speeds up things a lot when emulating ; multiple voice systems) mix_soundout=256 ; set= if soundcard has internal ram ; STORE EVERY SAMPLE into soundcard ; AND EXIT THIS PROGRAM IF THERE IS NOT ENOUGH ; SOUNDCARD RAM mix_soundin=512 ; set= STORE EVERY SAMPLE into system ram ; (useful to test drivers in "all emulated" mode ; or to disable faulty functions on a ; not-so-well coded driver) ; THIS FLAG OVERRIDES mix_soundout !!!!!! mix_interpolate=1024 ; set= the final "mixed" sound sample ; on emulated soundchannels gets smoothed ; and played AT TWICE the sampling frequency ; to eliminate noise _XSD_MIXMENU dd 0 ; pointer to mixer-control menu ; ("generic" configuration menu ; it includes cosmetic options that are not essential ; to set AND it includes _XSD_DRVMENU menu as a submenu) _XSD_DRVMENU dd 0 ; pointer to device-control menu ; (call this if you need user-driven ; basic mixer/driver configuration) ; (it includes the XSD driver menu as a submenu) ; sound hardware settings, save these on the config file ; and then reload 'em from it _XSD_Base dd 0 ; [*] i/o address of device _XSD_IRQ dd 0 ; [*] irq used by the sound system ; IF SET To ZERO, the 386mixer must use ; the _XSD _XSD_DMA dd 0 ; [*] dma channel 0..3 == 8bit ISA dma, 4..7 == 16bit ISA dma ; sound configuration by "ENVIRONMENT STRING" _XSDEnvValue dd 0 ; pointer to the ASCIIZ value of the environment var ; named like _XSDEnvVar ; (set by 386mixer) ; NULL == use _XSD_Base,_XSD_IRQ,_XSD_DMA settings ; The SoftChnnelizer: MAIN SOFTCHANNEL EMULATOR ; Call this from the irq driver to perform softchannel-emulation. ; The called routine will return INTO ESI the PHYSICAL address of the resulting ; block to send to the hardchannel, the equivalent CODE32 RELATIVE offset ; will be returned into EDI. ; You can trust the physical address is "dma reachable". _XSD_SOFTCHANNELIZER dd 0 ; Well, that's what it does! :) ; freeze/unfreeze data _XSD_SYNC dd 0 ; "atomic access" flag , this "freezes" the internal status ; of the mixer system, preventing IRQs to modify it. ; IRQs can set the _XSD_SYNCMIX entry to their ; "delayed update" routine to take care of this. _XSD_SYNCMIX dd 0 ; routine to call when _MixUnSyncSound is called. ; DMA block addresses (the first is the block currently playing on the dac) ; (the second is the block "under mixage" (will be sent when the ; currently playing block ends) ; their size can range between 4k to 8k ; A call to _XSD_SOFTCHANNELIZER will "swap" 'em as a side effect ; DAC DMA DATA _XSDBlock1 dd 0 ; code32 address of first data block buffer _XSDPhys1 dd 0 ; physical address " " " " " _XSDBlock2 dd 0 ; ditto for second data block buffer _XSDPhys2 dd 0 ; _XSDBaseDriver dd 0 ; base offset where the XSD driver is loaded ; START OF "copied" driver header ; Here follows the "relocated" XSD driver table ; (see xsdrv.txt for specific info about the XSD driver format) _XSDSignature dd 0 ; there must be four bytes as follows: ; db 'XSD',0 ; This means XSD revision ZERO driver ; has been found and loaded _XSDInit dd 0 ; pointer to the ; "hardware check" and system initialization code ; it will also initialize all data structures needed ; by the driver. ; IN: ebp=driver base offset (code32 relative) ; (use this to fix-up addresses) ; edi=XSD device table ; (code 32 relative offset ; of _XSDTable, from it you know ; where the other "XSD variables" are ; and where the sound channel descriptors are) ; OUT: ; If carry clear then OK ; else ; EAX=error code ; 0 = device not recognized ; 1 = not enough memory ; 2 = XSD device table contains ; wrong values _XSDSetup dd 0 ; pointer to the ; sound system setup routine ; Simply set properly the values into the ; XSD device table (playback frequency, feed frequency ; active channels, types of emulation ; etc.etc.) ; and then call this. ; IN: none : OUT: XSD table set to the NEAREST supported values. ; all channels "preset" to silence. _XSDON dd 0 ; pointer to routine that ; turns on sound system (setting up IRQ handlers ; locking DMA channels, starting up transferts ; AND turning ON sound output). ; THIS ROUTINE will at least "set up" an IRQ handler ; to handle "end of DMA" from soundcard ; and calls to the _SOFTCHANNELIZER ; "mixer emulation" routine. _XSDOFF dd 0 ; pointer to routine that ; turns off sound system (turns off sound output ; disables DMA, unlocks DMA channel, restore IRQ handlers) ; the following entries may be not supported, it will be up to ; _XSDInit to set correctly the flags into _XSD_DRVTYPE (into XSD device table) ; to tell 386mixer what is supported and what's not _XSDMVol dd 0 ; pointer to ; MASTER VOLUME CONTROL routine ; this affects the output volume of all active channels ; ; actual_channel_volume = (chan_volume/255)*master_volume ; ; IN: al=channel volume (0..255) ; 0 = sound off ; 255 = maximum output ; ; The master volume can have a coarser granularity ; than sound channel volume ; (i.e. on a sound blaster Pro, master volume can range ; between 0..15 if you just use "output volume" ; but if you split master volume with ; the lower four bits controlling ; "voice volume" (0..15) ; and the higher four bits controlling ; "output volume" (0..15) ; you can get the "complete" 0..255 range. ; these entries are specific of "wavetable" soundcards ; (flag xsd_wavedriver set) _XSDPlay dd 0 ; pointer to routine that ; plays a sound sample ; IN: esi= ptr to the sound channel descriptor ; describing what to play and HOW to play it _XSDVol dd 0 ; pointer to routine that ; sets volume level/ramp only ; IN: esi= ptr to the sound channel descriptor ; describing what to play and HOW to play it _XSDPan dd 0 ; pointer to routine that ; sets panning level/ramp only ; IN: esi= ptr to the sound channel descriptor ; describing what to play and HOW to play it _XSDRate dd 0 ; pointer to routine that ; sets playback rate ratio (relative to playback freq) ; level/ramp only ; IN: esi= ptr to the sound channel descriptor ; describing what to play and HOW to play it _XSDEnvVar dd 0 ; pointer to ASCIIZ string ; with the name of the MS-DOS ENVIROMENT VAR ; to check for config info ;(for a sound blaster it is "BLASTER",0 ) _XSDMenu dd 0 ; pointer to ; User driven "driver setup" menu for custom configuration ; ("executing" this menu results in interactive calls to ; _XSDSetup subroutines) _XSDCardType dd 0 ; pointer to ASCIIZ string ; max. 30 character long ; (use this in the "choose driver" list) _XSDProgrammer dd 0 ; pointer to ASCIIZ string ; with multiple lines of text,max. 40 char each ; (use the LF char (code 10h) to mark newlines) ; (extended info on driver) _XSDNotes dd 0 ; pointer to ASCIIZ string ; with multiple lines of text,max. 40 char each ; (use the LF char (code 10h) to mark newlines) ; of notes about the driver usage and supperted display ; cards. (detailed info) _XSDWClear dd 0 ; pointer to routine that ; "resets" wavetable ram to "all free" _XSDWMark dd 0 ; pointer to routine that ; "marks" currently used wavetable ram ; OUT: eax= mark handle _XSDWRelease dd 0 ; pointer to routine that ; releases wavetable ram from the higher "currently in use" ; location down to the "marked" position ; IN: eax= mark handle that will be the new ; "currently in use" limit _XSDWUpLoad dd 0 ; pointer to routine that ; "loads" into wavetable ram a sound sample ; and returns info about it in "soundcard specific" ; units. ; IN: eax= sample size in dwords ; edx= sample data ptr ; OUT: ; IF carry clear THEN ; eax= "internal" sample size count ; edx= "internal" sample data ptr ; ELSE ; carry set, not enough wavetable ram ; END-IF _XSDTimed dd 0 ; pointer to the "timer driven" sound support system ; for "sound systems" without irq support ; (i.e. the pc-speaker or the "dac on printer port") ; (similar to the irq handler used by ; "soundcards with irq support", but this is just ; a near routine) ; end of "copied" driver header _XSD_BASERATE dd 0 ; [*] basic sample rate ; ALL samples will be converted ; to this sample rate. _XSD_BRATETRANS dd 0 ; [@] rate "translation" value to use when emulating ; the DAC hardchannel on a wavechannel _XSD_MVOL dd 0 ; master volume (0..255) _XSD_MVOLTRANS dd 0 ; [@] volume "translation" value to use when using ; "hardware" volume control _XSD_FEEDRATE dd 0 ; basic feeder rate for sofchannels [*] _XSD_FEEDSIZE dd 0 ; size of feeder block in bytes [*] _XSD_FEEDBLCK dd 0 ; maximum size of feed blocks _XSD_CUSTOM dd 16 dup(?) ; 64bytes available for soundcard's "private info" ; soundcard ram info _XSD_WAVFOOT dd 0 ; start of soundcard ram [@] _XSD_WAVBASE dd 0 ; start of soundcard's free ram [@] _XSD_WAVTOP dd 0 ; top of soundcard ram [@] _XSD_WAVCHAN db 0 ; base channel for wavechannels if wavetable hardware [@] _XSD_WAVFLAGS db 0 ; "custom" wavetable flags [@] _XSD_VOICES db 0 ; "active" soundchannels (max 255) [*] _XSD_ROTCHAN db 0 ; base index for autorotating soundchannels ; 0 <= _XSD_ROTCHAN <= _XSD_VOICES _XSD_CHANNEL dd _XSD_VOICES*32 ; soundchannel descriptors ; every descriptor uses 128 bytes softchan_size=128 ; START OF SOUNDCHANNEL DESCRIPTOR wt_len=0 ; [D] LENGHT IN DWORDSof sound sample data TO PLAY [@] wt_ptr=4 ; [D] pointer to sound sample data TO PLAY [@] wt_sfeed=8 ; [D] sample data feeder ; this is called with esi=ptr to soundchannel descriptor ; and must SET INTO wt_len and wt_ptr ; the lenght and pointer to the next sample to play ; AND SET INTO wt_settings the required "sample info data" ; about what's playing next ; (bit8 =sample into soundcard ram ; bit9 =stereo sample ; bit10=delay) ; to let the mixage system determine what to do. wt_sdata=12 ; [D] "default sample" data 0 == silence, no output ; this is useful to play "background" sounds ; or to implement "sample looping" when playing ; instrument samples. ; The default feeder does not modify this entry ; once it has been set. wt_ndata=16 ; [D] "next sample" data 0 == use wt_sdata ; the default feeder sets this entry to zero ; once the referenced sample is "loaded to play" ; into wt_len and wt_ptr descriptors. ; SOUNDCHANNEL SETTINGS wt_settings=20 ; [D] ; the "settings" entry is used as an index/reference to ; show how this soundchannel is "set" and ; to select the "internal feeder" routines needed to mix sound. ; ; Only EFFECTS with FLAG SET are supported, the others ; are ignored. ; wt_settings flags ; user settable flags: sset_vctrl=1 ;volume settings sset_vramp=2 ; bit0 = volume control sset_pctrl=4 ; bit1 = volume control & ramps sset_pramp=8 ; and call custom feeder sset_rctrl=16 ; when ramp ends sset_rramp=32 ; sset_rotate=64 ;panning settings sset_active=128 ; bit2 = pan control sset_wavram=256 ; bit3 = pan control & ramps sset_stereo=512 ; and call custom feeder sset_delay=1024 ; when ramp ends ; ;rate settings ; bit4 = rate control ; bit5 = rate control & ramps ; and call custom feeder ; when ramp ends ;sound rotation/active channel ; bit6 = this is an autorotating ; channel. ; bit7 = this is an active channel ;386mixer "private" flags ;sample location [set by 386mixer, for internal usage] ; bit8 = sample into soundcard ram ; ;format settings [set by 386mixer, for internal usage] ; bit9 = stereo sample ; (no panning control) ;delayed launch [set by 386mixer, for internal usage] ; bit10= delayed launch is pending: ; wt_len is a "silence" ; count (wt_ptr points to ; 4k "silence" buffer). ; When count gets lower than ; "feed buffer" size ; start mixing the silence ; track, then load ; the wt_sdata sample ; and set wt_sdata to zero. ; voice mixage routines wt_mix_step1=24 ; data_feed/rate_convert/rate_ramp/mono_to_stereo wt_mix_step2=28 ; panning_control/panning_ramp wt_mix_step3=32 ; volume_control/volume_ramp ; custom feeders and data ; THESE ARE ALWAYS CALLED WHEN a "ramp" ends ; the default handlers are simple "do nothing& return" routines ; but if you stick here custom feeders you can do very complex thing wt_vfeed=36 ; [D] custom volume feeder ; called with esi=ptr to sounchannel descriptor ; must return into edx the "packed data" for the next ; volume ramp wt_vdata=40 ; [D] custom volume envelope data 0=nothing wt_pfeed=44 ; [D] custom panning feeder ; called with esi=sounchannel descriptor ; must return into edx the "packed data" for the next ; panning ramp wt_pdata=48 ; [D] custom panning envelope data 0=nothing wt_rfeed=52 ; [D] custom rate feeder ; called with esi=sounchannel descriptor ; must return into edx,cx the "packed data" for the next ; rate ramp wt_rdata=56 ; [D] custom rate envelope data 0=nothing ; "current values" and "ramp limit" data wt_vol=60 ; [W] [@] volume in fixed point 8:8 format wt_volend=62 ; [W] [@] ditto wt_pan=64 ; [W] [@] panning in fixed point 8:8 format wt_panend=66 ; [W] [@] ditto wt_rate=68 ; [W] [@] current data rate ratio (relative to wavetable base ; frequency ( _XSD_WAVRATE) ; in fixed point 6:10 format (Gus format) wt_rateend=70 ; [W] [@] ditto ; "increment" values using the same format of current settings wt_volinc=72 ; [W] 8:8 wt_paninc=74 ; [W] 8:8 wt_rateinc=76 ; [W] 6:10 wt_reserved1=78 ; [W] ; "width" of single ramp steps (in DWORDS of sample data) wt_volstep=80 ; [D] wt_panstep=84 ; [D] wt_ratestep=88 ; [D] wt_reserved2=92 ; [D] "reserved" for future extension, this should be zero wt_xswavd=96 ; [32 bytes] driver's private data ; (from offset 96 included to offset 128 excluded) ; THE DRIVER CAN USE THIS SPACE AS IT WANTS ; END OF SOUNDCHANNEL DESCRIPTOR _MixShutDown: Shuts down mixer system (automatically called by _Exit) Calls the _XSD_OFF routine. _MixVolume: Master volume control in: eax= volume: 0 = sound off 255 = maximum output Either a driver routine or a software emulated one ALL THE OTHER VOLUME SETTING ARE RELATIVE TO THIS actual_voice_volume = (voice_volume/255)*master_volume _MixFeeder: Set "mixer feeder" capabilities in: eax= channel (-1 = set on all channels) edx= new values for wt_settings (only bit0..bit7 are used) This routine will set the "mix steps" entries according to the driver settings and and the channel settings (i.e. if there is a mono driver, panning is ignored). N.B. You can read wt_settings DIRECTLY, but you can modify it only by way of _MixFeeder, because when you change the settings the mixer has to change some descriptor entries and other internal things _MixPlay: Play sound without sound effects (use the default settings) in: eax= channel (-1 = autorotate to next "free" channel) edx= sound handle ( 0 = silence) _MixFXPlay: Play sound with "sound effects". eax= channel (-1 = autorotate) edx= sound handle ecx= volstart(b),volstop(b), panstart(b),panstop(b) (dword packed) ebx= voltime (w)(msec), pantime(w) (msec) (dword packed) ; the maximum "ramp" time for volume and panning ; is around 65 sec and the minimum is 1msec n.b. panning works only with stereo sound on esi= ratestart (w), rateend (w) playback rate is given as a fixed point ratio 6:10 (6bit unsigned integer, 10bit mantissa) between "base rate" an "voice rate". di= ratetime (msec) ebp= sound start DELAY in dwords of silence sample data time: time for a COMPLETE ramp in milliseconds panning: 0=full left, 255=full right volume: 0=minimum, 255=maximum The DELAY parameter is a quite critical thing needed to implement "live" echo effects and 3D sound. It tells the mixer the exact number of DWORDS of silence data that must be "played" BEFORE the actual sample starts. So if is say 850 it means "perform equivalent action" of playing a "silence" sample 850*4 bytes long. Notice that changing the playback rate and the sample size (8bit mono, 8bit stereo, 16bit mono, 16bit stereo) the delay time changes, but it can be easily calculated into lookup tables at program startup. The actual "delay" time limits you can get ranges from 0.5 milliseconds to more than 65000 seconds. The great advantage of delayed playback is that with it you can "pack together" delayed sounds knowing that even on autorotating softchannels the echo/3d_sound will hold at least until something else "rotates over" some of the channels "playing together" to produce the effect. N.B. Packing is in big endian order so ecx= volstart(b) ,volstop(b),panstart(b),panstop(b) means cl= volstart ch= volstop high word,low byte = panstart high word,high byte = panstop _SoundVolume: Set wavechannel volume in: eax= channel ( -1 = set volume of all autorotating channels) edx= volstart (B),volend(B),voltime(W) N.B. volstart==volend or voltime== 0 produces "constat" volume setting with volume=volend (this function can be ignored by emulators if you want) _SoundPanning: Set wavechannel panning in: eax= channel ( -1 = set volume of all autorotating channels) edx= panstart (B),panend(B),pantime(W) N.B. panstart==panend or pantime== 0 produces "constat" volume setting with volume=volend (this function can be ignored by emulators if you want) _SoundRate: Set wavechannel playback rate & disable rate ramp in: eax= channel ( -1 = set volume of all autorotating channels) edx= ratestart(w),rateend(w) cx= ratetime N.B. ratestart==rateend or ratetime== 0 produces "constat" volume setting with volume=volend (this function can be ignored by emulators if you want) As you can see these "default" effects are useful to emulate the "basic hardware" on wavetable boards, they are NOT intended to provide a full power "sound handling" system. Effects such as echo, surround and others can be "bolted on" later, using the appropriate feeders depending where you think there is the maximum advantage. _SndLoad: Loads a sound file (currently it can only be an 8bit mono VOC file but in a the next release it will cover more file formats) in: esi= pointer to file name string eax= destination bit0: 0 = into ram. 1 = into wavetable ram if you can. bit1: 0 = use it as a DAC sample (convert it to the current DAC playback rate and sample size) 1 = use it as a wavetable sample (fill in the extra wavetable attributes) edi= pointer to start of sample header located into system ram (even sounds with their samples located into wavetable ram have their header located into system ram) out: if CARRY CLEAR then eax=sample handle (pointer to its header) check the sample header to see if the sound has been loaded into soundcard ram or not. edi=first free byte AFTER the sample header/data. if CARRY SET then error registers unchanged ;SOUND SAMPLE (SMP) HEADER : ; digital sound samples are handled ; by way of headers that let the mixer code "detect" ; the digital sound sample attributes. ; The current header is 16 bytes long, but its size may change in future ; releases of 386mixer, you CAN access the "already defined" entries ; of a sound header, but don't assume anything about possible "new" ; fields and flags. When the sound sample is into system ram ; you can also copy the sample data and/or process it ; In future releases i may add support for holographic/3dbinaural sound ; (as soon as i get my hands on a cpu powerful enough and on ; documents giving me a decent audiomechanical model of the auditive system) ; [ I know about the delayed sound reflection method and the ; phase difference to 3d position translation, what i still don't know ; are the exact parameters needed to process the delay+reflection ; (how many different delayed secondary waves? what's the law ; correlating direction and reflected wave scaling ?) ; ] smp_len=0 ; [D] lenght of sample in bytes smp_datptr=4 ; [D] pointer to sample data smp_type=8 ; [D] sample type flags (only bits 0..5 are currently defined) smp_hlen=12 ; [D] size of header in bytes (must be dword aligned) ; flags for sample type smp_stereo=1 ; set= this is a stereo sample, play it without applying ; panning or other effects except volume control ; (it contains precalculated sound effects) ; else mono sample, you can apply effects to it ; N.B. the wavetable device CANNOT PLAY stereo samples!!!! ; (it can "play in stereo", but the "base sample" ; is a mono one!!) smp_soundcard=2 ; set= sample can be directly played by sound hardware ; else this is a sample completely stored into system ram ; and needs to be played on softchannels smp_biport=4 ; set= soundcard ram is MAPPED INTO SYSTEM RAM ; so you can process samples like if they are ; on "plain" system ram AND play them ; on "hardware" directly ; else soundcard ram is not directly accessible ; wt_len and wt_ptr contains values that are ; meaningful only for XSD the driver smp_16bit=8 ; set = this is a 16bit sample ; else it is an 8bit sample smp_signed=16 ; set = sound samples use a signed format ; else they use an unsigned format smp_int=32 ; set = signed samples are like "ints" ; else signed samples use a "detached" sign bit ; (like in floating point numbers) _Map2CPURam: Maps to a buffer in system ram the sound/wave sample data referenced by esi. in: esi =sound header edi =pointer to buffer to use to store sound header AND sound sample data immediately after (but we don't know how wide is the header so use the sound header fields to look where the sound data is, or this could "break" with future releases of 386mixer) ebp = top of allocable ram in the heap pointed by edi (this way we can avoid to run out of memory) out: if CARRY CLEAR then esi=new sound header edi=ptr to first free byte after sound data else error, nothing has been changed _Map2WAVRam: Tries to "map into soundcard ram" the sound/wave sample referenced by esi. in: esi=sound header edi=pointer to buffer for new sound header ebp=top of allocable ram in the heap pointed by edi out: if CARRY CLEAR then esi=new handle. edi=ptr to first free byte after sound data else error, nothing has been changed _WRClear: resets all the sound card ram _WRAMMark: marks the allocate memory into wavetable ram out: eax=mark handle _WRAMRelease: releases the allocated memory into wavetable ram in: eax=mark handle _MixSyncSound: Call this when you have to "play together" multiple sounds so they will start AFTER the mixer has been "unsynched" _MixUnSyncSound: Mixer system back to "normal" mode, all synched channels will start playing from here. It is assumed you will "sync"-->"unsync" the mixer faster than the feed rate (or "feed noise" will happen)