Sound Playback Using Direct Mode
Example 4


	    Mission : Get to hear something in the easiest way possible!
                       Download the Expansion Pack!



Intro


Playing sounds on the Sound Blaster 16 is extremely easy in Direct Mode. The only real pain in the keester is that we have to regulate the frequency that we send the data to the sound card. The only real way of doing this is to hook up with the Timer Interrupt. The tutorial on how to do that is located here

Getting the Interrupt Ready


We know from the Programming the Timer Interrupt Tutorial that we have a function that replaces the current interrupt function with a new one, and also one that changes its frequency. We will be adding onto our existing SB16 class with some new functions that will let us seemlessly add functionality by supporting this type of playback. Lets create the function that utilizes the ISRS class and gets everything ready.

  Located in Header File
  void SetupDirectPlay();
  void DirectPlay(unsigned char);
  void DirectPlay();
  void GetISRPtr(ISRS*);
  long place;
  ISRS * isrs;


void SB16::SetupDirectPlay()
{isrs->SetupTimerISR();
 isrs->SetTimerFrequency(11025);
}

void SB16::GetISRPtr(ISRS* isrs)
{ this->isrs=isrs;
}


Here we have two functions that actually set up the Timer Interrupt while the others serves as a means of gaining a pointer to a dynamically allocated instance of the ISRS class. We create this access function so that we won't have to require a pointer to be passed to the constructor. We don't want to do that since we may not even use the Timer Interrupt! I hope you realize that you must call GetISRPtr before calling SetupDirectPlay so that we actually have a REAL pointer to a dynamically allocated instance of the ISRS class. In the first function we tell the ISRS class to setup the Timer Interrupt with our new interrupt already defined int the ISRS class. Remember that in that class, it was defined as extern so we have to make a global declaration of the function. Look at the main .cpp file in the example file to see how to do it. Finally, we are setting the timer frequency to 11025 hz which is what I usually use. That function could easily be changed to have an arbitrary frequency passed to the SetTimerFrequency function. After this function is called, we know that the function that we declared globally will be calling a function, but what!?


Outputing the Byte


void SB16::DirectPlay(unsigned char byte)
{WriteDSP(0x10);
 WriteDSP(byte);
}
void SB16::DirectPlay()
{unsigned char byte=Sounds[0].Sound[place];
 WriteDSP(0x10);
 WriteDSP(byte);
 place++;
 if(place >=Sounds[0].Length)
 {place=0;
 }
}


All we have to do to output a byte of sample data is output a 0x10 to the DSP and then follow it up with the byte. In the example program, I have the Timer_ISR function calling DirectPlay(). This is just a simple function that I trew together to test if everything worked out ok or not. Remember from our last tutorial that we learned how to load samples from a .VOC file. Each sound was contained in a structure with information on its length, frequency etc. Sounds was an array of structures. Sound was the actual sound data. Knowing that, we are simply playing 1 byte of the Sound #0 and if we play the last sample, set our counter back to 0.

NOTE: I probably should tell you that the sample must be 8 bit mono unsigned. That should be kind obvious since we are just shoving a byte at the DSP and telling it to play!

There we go! The simplest way of output sound on a Sound Blaster Compatable card. The cool thing about this is that it is available on all versions 4.XX through 1.xx! If you have any questions, comments, or some tips on how i can improve this page, please send me some Feedback!