----------------------------------------------------------------------------- Digital Sound Interface Kit (DSIK) Version 2.00 -- User's Manual -- Copyright (c) 1993-95 by Carlos Hasan. All Rights Reserved. ----------------------------------------------------------------------------- Table of Contents: 1. Introduction 1.1 What's in this Manual? 1.2 Hardware Requirements 1.3 Installing the Software 1.4 Contacting the Author 2. Tutorial 2.1 Initializing DSIK 2.2 Playing Digital Samples 2.3 Playing a Music Module 2.4 Playing Sound Effects over Music 3. Programming Guide 3.1 Initializing DSIK 3.2 Openining Voice Channels 3.3 Mixing Voices 3.4 Playing Music 3.4.1 Loading a Module 3.4.2 Playing the Module 3.4.3 Stopping the Module 3.5 Sound Effects 3.5.1 Channels 3.5.2 Available Channels 3.5.3 Playing Sounds 3.5.4 Altering the Playing Sounds 3.6 Digital Sound Module Format 3.6.1 Converting Modules 3.7 Getting Information from DSIK 3.8 Interrupts 3.9 Using Timer Services Chapter 1. Introduction ----------------------------------------------------------------------------- The Digital Sound Interface Kit (DSIK) version 2.0 is a interface library written in 32-bit protected mode by which you can play music modules and sound effects on IBM PCs and is currently available for WATCOM C/C++ compiler 9.5 or later. 1.1 What's in this Manual? This manual has two parts: Tutorial and Programming Guide sections. The tutorial section of this manual will show you only the most basic functions of DSIK. You should read the Programming Guide section to learn more about the DSIK's capabilities. For more detailed information about every function, structure and equates defined in DSIK you should read the Reference Guide decument. 1.2 Hardware and Software Requirements In order to work with DSIK you need at least an 80386 processor and a soundcard device. The following soundcards are supported: - Sound Blaster 1.x - Sound Blaster 2.x - Sound Blaster Pro - Sound Blaster 16 - Pro Audio Spectrum - Pro Audio Spectrum+ - Pro Audio Spectrum 16 - Windows Sound System - Gravis UltraSound and all cards that are 100% register compatible with any of the above soundcards (ie. Logitech SoundMan 16, Sound Galaxy Pro, Audiotrix Pro, Gravis UltraSound Max, Aria soundcard, etc). 1.3 Installing the Software DSIK comes on a single high density diskette containing the object libraries, C source files, example programs and document files. Run the INSTALL.BAT batch file on the diskette and follow it is instructions. When it finishes installing the files, you need to modify your WATCOM C/C++ programming environment to recognize the DSIK sound system. Modify your WLSYSTEM.LNK linker initialization file to specify where are the sound system .LIB library files, and your INCLUDE environment variable to specify where are the sound system .H include files. For example, if you install the software in the C:\DSIK directory and the WATCOM C/C++ compiler is installed in the C:\WATCOMC directory, your AUTOEXEC.BAT startup batch file may look like: @echo off prompt $p$g path c:\dos;c:\watcomc\bin;c:\watcomc\binb set watcom=c:\watcomc set include=c:\watcomc\h;c:\dsik\include set dos4gpath=c:\watcomc\bin\dos4gw.exe and your WLSYSTEM.LNK linker initialization file: # linker initialization file system begin dos4g option osname='Rational Systems' libpath %WATCOM%\lib386 libpath %WATCOM%\lib386\dos libpath c:\dsik\lib op stub=wstub.exe format os2 le end You can also use command line options to specify the location of the include and library files. For example, to make the EXAMPLE.C file you can type at the DOS prompt: wcl386 example.c -i=c:\dsik\include -"libpath c:\dsik\lib" Check out the Makefile included in the EXAMPLES directory for more information about how to compile DSIK applications. 1.4 Contacting the Author If you encounter problems, find a bug in this package or want to suggest something, use the following Internet email addresses: Carlos Hasan chasan@cec.uchile.cl chasan@dcc.uchile.cl Chapter 2. Tutorial ----------------------------------------------------------------------------- This tutorial will show you how to use DSIK in your own applications by providing some simple example programs. These example programs will be built from scratch and new features will be added step by step through the tutorial. 2.1 Initializing DSIK Before using any of the DSIK's routines it has to be initialized. First you need your soundcard hardware parameters. To ease things there is an external program called SETUP which will ask to the user the soundcard parameters and will save them into your disk. After, you can load these hardware parameters from disk in your own programs. When you have all the soundcard parameters, call the routine dRegisterDrivers and then dInit to initialize the DSIK sound system. Now the program would be able to play sounds on different channels, and music modules of course. Here is an example code for initializing DSIK: #include #include #include "audio.h" int main(void) { SoundCard SC; dRegisterDrivers(); if (dLoadSetup(&SC,"SETUP.CFG")) { printf("Please run SETUP.EXE to configure.\n"); exit(EXIT_FAILURE); } if (dInit(&SC)) { printf("Error initializing the sound system.\n"); exit(EXIT_FAILURE); } atexit(dDone); : : } If everything went alright and dInit found the specified soundcard it returns zero. After dInit has initialized the system, you must call the deinitialization routine dDone before exiting from your program. 2.2 Playing Digital Samples DSIK is now initialized and waits for your instructions. But first you have to setup the amount of voices you are going to use and the master volume level (or amplification factor) for all these voices: dSetupVoices(4,96); Now you have four independant channels to play sounds. To play a digital sample (or instrument) you have to load the sample from disk, then pass it to dPlayVoice to start playing the sample. DSIK currently supports many sound sample file formats which can be loaded from disk using the import routine dImportSample. Also, you can use dLoadSample to load RIFF/WAVE sample files: #include #include #include #include "audio.h" int main(void) { SoundCard SC; Sample *Drum; dRegisterDrivers(); if (dLoadSetup(&SC,"SETUP.CFG") || dInit(&SC)) exit(EXIT_FAILURE); atexit(dDone); dSetupVoices(4,96); if (!(Drum = dLoadSample("DRUM.WAV"))) exit(EXIT_FAILURE); dPlayVoice(0,Drum); while (!kbhit()) dPoll(); dStopVoice(0); dFreeSample(Drum); } The previous code loads a digital instrument from disk and plays it on the first audio channel at the default frequency and volume. 2.3 Playing a Music Module Module is a music file format first used in the Amiga computer. There are many music formats around like: ProTracker, FastTracker, Scream Tracker, Composer 669, and MultiTracker file formats. The DSIK sound system supports the RIFF/DSMF file format. You can use the M2DSM.EXE utility to convert other files formats to RIFF/DSMF or you can use the dImportModule import routine to load other module file formats from your own program at runtime. Here is an simple example program to play an RIFF/DSMF module file: #include #include #include #include "audio.h" int main(void) { SoundCard SC; DSM *M; dRegisterDrivers(); if (dLoadSetup(&SC,"SETUP.CFG") || dInit(&SC)) exit(EXIT_FAILURE); atexit(dDone); if (!(M = dLoadModule("SONG.DSM"))) exit(EXIT_FAILURE); dSetupVoices(M->Header.NumTracks,M->Header.MasterVolume); dPlayMusic(M); while (!kbhit()) dPoll(); dStopMusic(); dFreeModule(M); } When running the program it should play the SONG.DSM module. If there are problems, check that the module exists in the current directory. 2.4 Playing Sound Effects over Music With DSIK it's possible to play sound effects over the music. All you have to do is to open more voices than your module needs. The extra voices can be used to play sound effects. Remember that DSIK always uses the first voices to play the music. For example, if you open 8 voices using dSetupVoices and then you start playing a 4-track module file, the voices 4-7 can be used to play your own sound effects over the music. Chapter 3. Programming Guide ----------------------------------------------------------------------------- In this section you will learn more about all the DSIK's capabilities. It describes not only what DSIK can do, but also how. For more details about every function and structures defined in DSIK you should read the Reference Guide document. 3.1 Initializing DSIK The first thing you should do to initialize DSIK is to get the soundcard hardware parameters: base port address, IRQ interrupt line, DMA channel, sampling rate, etc. The structure SoundCard holds this information: typedef struct { byte ID; /* soundcard identifier value */ byte Modes; /* output mode (ie. 16-bit stereo) */ word Port; /* base I/O port address */ byte IrqLine; /* IRQ interrupt line */ byte DmaChannel; /* output DMA channel */ word SampleRate; /* sampling rate (in hertz) */ char DriverName[16]; /* DLL driver file name */ } SoundCard; The identification number ID is unique for each soundcard. The currently supported soundcard identifier values are the following: #define ID_NONE 0 /* no sound */ #define ID_SB 1 /* Sound Blaster */ #define ID_SB201 2 /* Sound Blaster 2.01 */ #define ID_SBPRO 3 /* Sound Blaster Pro */ #define ID_SB16 4 /* Sound Blaster 16 */ #define ID_PAS 5 /* Pro Audio Spectrum */ #define ID_PASPLUS 6 /* Pro Audio Spectrum+ */ #define ID_PAS16 7 /* Pro Audio Spectrum 16 */ #define ID_WSS 8 /* Windows Sound System */ #define ID_GUS 9 /* Gravis UltraSound */ There are parameters which are unused for some soundcards (for example, the GUS soundcard does not requires the sample rate). Also, the virtual soundcard ID_NONE is useful for users without any sound device, because your program can use all the DSIK functions without problems, but no sound will be heard though. The Modes field specifies the output format used. For example, you can specify 8-bit mono, 8-bit stereo, 16-bit mono or 16-bit stereo output mode. Notice that some soundcards may not support all these formats; monophonic cards can not play in stereo, and 8-bit cards can not play at 16-bits of resolution. The following equates are defined: #define AF_8BITS 0x00 /* 8-bits per sample */ #define AF_16BITS 0x01 /* 16-bits per sample */ #define AF_MONO 0x00 /* mono output */ #define AF_STEREO 0x02 /* stereo output */ When the SoundCard structure is filled call dInit routine to initialize the sound system. If everything went alright this routine will return a zero value. Notice that the specified sound driver must be registered before calling dInit, because the sound system only knows registered sound drivers. Here is an example: #include #include #include "audio.h" int main(void) { SoundCard SC; SC.ID = ID_SB16; SC.Modes = AF_16BITS | AF_STEREO; SC.Port = 0x220; SC.IrqLine = 5; SC.DmaChannel = 5; SC.SampleRate = 44100; dRegisterDrivers(); if (dInit(&SC)) { printf("Error initializing the sound system.\n"); exit(EXIT_FAILURE); } atexit(dDone); : : } The above example will initialize the system using a Sound Blaster 16 playing at 16-bit stereo 44100 Hz configured at Port 0x220, IRQ 5 and DMA channel 5 (the driver filename field is not required here). I suggest to use dLoadSetup to fill the SoundCard structure, or you can use the dAutoDetect soundcard autodetection routine to fill out this structure. However, the current autodetection routine is not perfect, so I highly suggest to use dLoadSetup and SETUP.EXE to get your soundcard parameters. After initializing DSIK you should make sure that dDone is called upon exit. The easiest way to do it is to use the atexit machanism. 3.2 Opening Voice Channels Now DSIK is initialized, but you can't play any sound with it yet. First you will have to call dSetupVoices to specify the amount of voices that your program needs and the master volume level: dSetupVoices(8,96); The above line will open 8 voices and set the master volume level. The master volume (or amplification factor) is used only for 8-bit output modes. It is very useful to make the sound much more dynamic and clean on 8-bit soundcards. This value specifies the dynamic range of every digital voice. A suggested value for this parameter is: MasterVolume = min(255,768/NumVoices); When you change the amount of open voices in your programs, be sure to turn off all the currently active voices and the music module before you call dSetupVoices. You can use dStopVoice and dStopMusic for it. 3.3 Mixing Voices When everything is initialized it's time to start playing some sounds. Before any sound can be heard it has to be loaded from disk. Because DSIK supports many more channels than your soundcard supports (except for the GUS), DSIK has to combine many channels into a single channel, this process is called digital mixing or waveform synthesis. DSIK lets you do the mixing whenever you want to do it. It does not force you to use the timer interrupt, all that DSIK requires is to call the function dPoll frequently. Actually this is not required if you are using the GUS soundcard which uses his own interrupt service to poll the sound system. To play music and sound effects in background, you only need to call dPoll regularly at least 50 times per second. You can call it at any rate greater than 50 times per second, and even at irregular intervals if required by your application. If you hear small cracks and the music sounds like a broken record, it means that you need to call dPoll much more frequently. If you want a timer interrupt to handle all the mixing, you can easily hook the dPoll into the timer interrupt service: #include #include #include "audio.h" #include "timer.h" int main(void) { SoundCard SC; dRegisterDrivers(); if (dLoadSetup(&SC,"SETUP.CFG") || dInit(&SC)) exit(EXIT_FAILURE); atexit(dDone); dInitTimer(); atexit(dDoneTimer); dStartTimer(dPoll,TICKS(70)); : : } The previous code will use the timer interrupt to call dPoll 70 times per second. Notice that the BIOS clock will be updated while using the timer services. 3.4 Playing Music After DSIK has been setup to play sounds, you are allowed to play music modules. As DSIK uses his own music module format, it's necessary to use the utility M2DSM.EXE to convert standard MODs, STMs, 669s, S3Ms and MTMs to RIFF/DSMF file format or you can use the import routines to load other file formats directly from your programs at runtime. 3.4.1 Loading a Module Before any music can be played it has to be loaded from the disk into system memory (and soundcard memory for the GUS driver). The module loader is called as follows: Module = dLoadModule(Filename); If you want to load other module file formats: Module = dImportModule(Filename,Format); The Filename parameter is the full path name of the module file, and the Format parameter for the import routine specifies the module file format of the file: #define FORM_DSM 0x00 /* RIFF/DSMF module file */ #define FORM_MOD 0x01 /* Protracker modules */ #define FORM_S3M 0x02 /* Scream Tracker 3.0 modules */ #define FORM_MTM 0x03 /* Multitracker 1.0 modules */ #define FORM_669 0x04 /* Composer 669 modules */ #define FORM_STM 0x05 /* Scream Tracker 2.0 modules */ The loader returns a pointer to a DSM structure. If something went wrong, NULL is returned and the global variable dError is set to one of the following values to indicate the error occurred: #define ERR_OK 0 /* no error */ #define ERR_FORMAT 1 /* invalid/unsupported format */ #define ERR_NOFILE 2 /* file not found */ #define ERR_FILEIO 3 /* error reading file */ #define ERR_NOMEM 4 /* not enough system memory */ #define ERR_NODRAM 5 /* not enough soundcard memory */ The DSM structure contains all the information about the module, so it is totally possible to load multiple modules into memory. 3.4.2 Playing the Module When the module has been loaded into memory it can be played with a single function call: dPlayMusic(Module); The parameter is a pointer to a variable of type DSM. If you have set up DSIK correctly and mixing routines are called frequently, you should hear the music playing in background. If you don't hear any music and no error was detected, then something went wrong during initialization (probably the soundcard hardware parameters are wrong). 3.4.3 Stopping the Module If you want to stop the module which is currently being played, call the routine dStopMusic. If the module looping is enabled, the module will not stop playing until dStopMusic is called. If you want to enable the looping for a module, you can do the following: Module->Header.ReStart = 0; The above line will tell to the sound system to restart playing the song at the first order position in the sequence list. 3.5 Sound effects Playing modules in the background is a thing that can be achieved with DSIK, but also you can play sound effects simultaneous with music. 3.5.1 Channels First you need to know the amount of voices that your program will need to play the music and sound effects. For example, if you are going to play a 4-track module and also you want stereo sound effects, you need to open 6 channels (four for music and two for the sound effect channels). To open the desired amount of channels you does: dSetupVoices(NumChannels,MasterVolume); The first parameter is the number of channels you want, and the second parameter is the master volume level (or amplification factor). You can open upto 32 digital voices, every voice can be referenced by numbers starting from 0 upto 31. The first voices are enabled when you use dSetupVoices. For example, if you open 4 voices for playback the channels 0-3 will be enabled. You can call dSetupVoices multiple times. However, it can't be called while music or sound effects are being played. So be sure to stop all the channels before changing the amount of voices (you must use the routine dStopMusic to stop the music and dStopVoice to stop sound effect channels). 3.5.2 Available Channels You have opened six channels and DSIK is playing a four channel module, so the channels four and five are available for your own sound effects. DSIK always uses the first channels starting from zero, so you can be sure that playing a sample on channel four or five will not interfere with the music. 3.5.3 Playing Sounds When you want to play a sample, you must load it from disk. The function dLoadSample load RIFF/WAVE sound files from disk: Guitar = dLoadSample("GUITAR.WAV"); If you want to load samples in other file formats, you can use the import routine to load VOC, IFF/8SVX, or RAW sound files: Speech = dImportSample("SPEECH.VOC",FORM_VOC); The second parameter specifies the sound file format. The following file formats are currently supported: #define FORM_WAV 0x80 /* Windows WAVE PCM files */ #define FORM_VOC 0x81 /* Creative Labs Voice Files */ #define FORM_IFF 0x82 /* Amiga IFF/8SVX sample files */ #define FORM_RAW 0x83 /* 8-bit mono RAW sample files */ To learn more about how to load samples into memory, look at the example source files and at the module/sample loading routines. After the sample has been loaded in memory, you can play it calling the dPlayVoice function: dPlayVoice(Voice,Drum); where Voice is the channel number and Drum is a pointer to a Sample structure. This function will play the sample at the default frequency and volume specified in the Sample structure. The Volume and Rate fields of the Sample structure specifies the default volume and the playback frequency. The volume level goes from 0 to 64, and the frequency is given in hertz. 3.5.4 Altering the Playing Sounds Now that the sample is being played, it would be nice to change the frequency and the volume of the sample. DSIK has functions to make it possible. Changing the frequency and volume is as simple as calling: dSetVoiceFreq(Voice,Freq); dSetVoiceVolume(Voice,Volume); Also you can change the channel panning (or balance): dSetVoiceBalance(Voice,Balance); where Balance is a number between 0 (left panned) and 128 (right panned), also you can use stereo surround setting the balance to 228. There are some useful equates which you can use to set the balance or panning: #define PAN_LEFT 0x00 /* left balance */ #define PAN_MIDDLE 0x40 /* middle balance */ #define PAN_RIGHT 0x80 /* right balance */ #define PAN_SURROUND 0xA4 /* stereo surround */ You can also interpole these values to do smooth pannings. Notice that this routine only works in stereo cards, and the surround does not work for Gravis UltraSound cards. 3.6 Digital Sound Module Format (RIFF/DSMF) DSIK uses his own music module file format. It was designed to cope with a variety of different module formats like MOD, STM, 669, S3M, and MTM. It would have been very hard to write a system that supports all those module formats, so I have made a system that supports just one format, but with a utility and import routines to convert other module formats into this RIFF/DSMF module format. 3.6.1 Converting Modules As DSIK only supports the RIFF/DSMF format, you need to convert MODs, STMs, 669s, S3Ms and MTMs into DSMs before playing. You can do this manually using the M2DSM.EXE utility. For example, you can type at the DOS prompt: M2DSM NOWWHAT3.MOD The above line will convert the Protracker/Fastracker module file named NOWWHAT3.MOD to a RIFF/DSMF module file. Also, you can use the built-in import routines to load other module file formats at runtime from your own programs. For example, Module = dImportModule("NOWWHAT3.MOD",FORM_MOD); The above line will load the Protracker module file without need to previouly translate it to the RIFF/DSMF file format. However, I suggest to use RIFF/DSMF module files in your programs, because these files are loaded faster and the M2DSM.EXE utility will remove any problem that other module files may have. For example, I have seen lots of buggy S3M module files created by Scream Tracker 3.0 BETA version. 3.7 Getting Information from DSIK DSIK can give you information about what is going on. There is a routine called dGetMusicStruc which returns a pointer to the following structure which hold a lot of useful runtime information: typedef struct { dword MusicVolume; /* music volume */ dword SoundVolume; /* sound effects volume */ MTrk Tracks[MAXVOICES]; /* track structures */ byte NumTracks; /* number of active tracks */ byte NumVoices; /* number of active voices */ byte OrderPos; /* order position */ byte OrderLen; /* order length */ byte ReStart; /* restart position */ byte PattNum; /* pattern number */ byte PattRow; /* pattern row */ byte BreakFlag; /* break pattern mode */ byte Tempo; /* tempo (or speed) */ byte TempoCount; /* tempo counter */ byte BPM; /* beats per minute */ byte SyncMark; /* synchronization mark */ byte Status; /* music status */ byte DriverStatus; /* audio driver status */ void *PattPtr; /* internal pattern pointer */ DSM *SongPtr; /* module pointer */ } MHdr; For synchronization with music you can use the SyncMark field. You need to place special synchronization marks in your modules. You can use Scream Tracker 3.0 command Z to put these marks. The command parameter should be a byte value between 0 and 127. When DSIK encounters this command, it sets the internal variable SyncMark with the value of the command parameter. So the variable SyncMark always have the previous synchronization mark value. With the Tracks array you get everything you need to know about what is currently playing. The structure of each Track is defined as: typedef struct { byte Note; /* note index */ byte Sample; /* sample number */ byte Volume; /* volume level */ byte Balance; /* balance */ word Effect; /* Protracker command */ word Rate; /* middle-C finetune frequency */ byte VUMeter; /* volume unit meter */ byte Flags; /* audio message bitflags */ byte Reserved[38]; /* reserved */ } MTrk; The first field is the current note playing on the track. The following field is the current instrument number. For example, if you need to know the name of the current instrument being played in the track, you can use the following code: Name = Module->Samples[TrackPtr->Sample-1]->SampleName; The Volume field is self explaining, and the Effect field is the current standard Protracker command which is being interpreted. 3.8 Interrupts DSIK doesn't require interrupts. Normally you would poll DSIK in an interrupt occuring about 50-70 times per second, which will decrease the overhead caused by the interrupt service. 3.9 Using Timer Services The Timer Service (TS) library was designed for easy handling of the timer interrupt service. This library was included because DSIK doesn't give you any routine to easily play music and sounds in background. With this library you can hook your own routines to be called by the timer interrupt service at the specified rates. For example, you can hook the dPoll routine to be called 70 times per second. When the TS services are installed the previous BIOS service is called at 18.2 Hz, so the BIOS clock time and date are updated normally. First, to initialize the TS routines you must call dInitTimer and be sure to call dDoneTimer to deinitialize the routines upon exit. Now you can hook your own service routine doing: dStartTimer(MyTimer,TICKS(70)); The above line will setup the timer interrupt service to call MyTimer at 70 hertz (or times per second). The speed value is given in clock ticks, but you can use the macro TICKS to translate frequencies in hertz to clock ticks.