home *** CD-ROM | disk | FTP | other *** search
- How WaveMix works.
-
- 1. Mixing Sounds
-
- The low-level multimedia wave out put function (waveOutWrite) does not support multiple simultaneous
- channels of output. So in order to accomplish this we must fake out the output device. This is done by
- premixing the wave output and then sending this new wave to the wave output device. The core concept
- which wavemix uses to mix files at run time is very simple. What it does is take a small slice off of each
- input wave file (each input is referred to as an "channel"), mix them together into an extra buffer which is
- the same length of the slice and then submit this wave buffer to the multimedia function waveOutWrite.
-
- /|
- _______________ __ / |
- |-----------| | | | | |
- | Wave 1 |----| |-------waveOutWrite()---| | |
- |-----------| | | | | |
- | | | | |
- |-----------| | | |__| |
- | Wave 2 |----| WaveMixer | \ |
- |-----------| | | \|
- ... | |
- |-----------| | |
- | Wave n |----| |
- |-----------| |--------------|
-
- A digital wave is essentially an array of wave samples. At 11Khz 8bit Mono (which is used by the Wave
- Mixer) a wave array (or buffer) will contain 11025 byte elements per sec. of the wave duration. (i.e. a one
- second wave will contain 11025 data samples, a 1 minute data wave will contain 60*11025=661500
- samples). To mix the waves in real time the input waves are summed together into another destination
- buffer. The destination buffer is typically a small size so that we can achieve real time results. A typical
- length is 1/8 th of a second = 11025/8=1378 samples.
-
- Waves are added as vectors. eg. D[i] = w1[i]+w2[i]+w3[i]+...+wn[i]
-
- e.g. Assuming that we have 4 waves playing and the slice length = 1378 samples. we could call a mixing
- routine: mixit(lpDest,rgpCDdata,4,1378);
-
- void mixit(LPSAMPLE lpDest, LPSAMPLE rgWaveSrc[], int iNumWaves, WORD wLen)
- {
- int i,iSum;
- WORD ctr;
- ctr = 0;
- while (wLen)
- {
- iSum=128; /* 128 is the "normal" value (silence) for 8 bit 11KHz */
- for (i=0;i<iNumWaves;i++)
- iSum = iSum + *(rgWaveSrc[i]+ctr) -128;
- PEG((int)0,iSum,(int)255);
- *lpDest++=iSum;
- ctr++;
- wLen--;
- }
- }
-
- The above routine will visit the i th element in each source array, sum them into a destination variable
- (iSum) that can accommodate any possible overflow (i.e. 8 bit elements are summed into a 16 bit
- destination) and then the destination variable is converted back to the original magnitude (saturation is
- done after the additions to minimize distortion).
-
- The destination buffer can now be submitted to the wave output device (using waveOutWrite) and the user
- will hear all four sounds played simultaneously. When the wave output device completes playing the
- buffer it will return it to the client (WaveMix.DLL) with a request for more output data.
-
- Since the wave output device can only play data that has been submitted to it and it takes a finite amount of
- time to mix the wave data, as soon as we submit the destination wave to the output device we must mix
- another buffer with the next slice of data and submit it to the wave output device to avoid an interruption in
- the audio output. This buffer will get queued by the device and it will then play the data in it when it
- finishes playing the data in the first buffer.
-
- While the output device is playing this second buffer we can mix the third slice into the first buffer and
- then submit it back to the device. We continue this "ping-pong" procedure of mixing the data and
- submitting the buffer to the wave output device until we have submitted all the wave data, at that point
- since we no longer submit data to the device it will stop playing. Note: In practice we often use more than
- two buffers (i.e. 3 or 4 is common) We then replace the ping-pong action with a "juggling" system:
-
- Wave Inputs
- _______________ |----------|
- |_______________|----| |
- _______________ | |
- |_______________|----| WaveMiver|
- _______________ | |
- |_______________|----| |
- |----------|
- |
- |
- _____________________________________________________
- | Buffer 4: Curently being mixed by Wave Mixer Program|
- |_____________________________________________________|
- ^ |
- | |
- _______________________|_____________________________ ___v__________________________________________
- |Buffer 1: Returned to Wave Mixer after play completed| |Buffer 3: Currently queued by wave out device|
- |_____________________________________________________| |_____________________________________________|
- ^ |
- | |
- _________|______________________________v__________
- |Buffer 2: Currently being played by wave out device|
- |___________________________________________________|
- |
- | /|
- _|_ / |
- | | |
- | | |
- |___| |
- \ |
- \|
-
- The above text and diagrams describe the mixing process. There are, however, other situations which
- occur that greatly complicate the mixing process: Playing multiple files that are of uneven length, A
- request to start a new wave playing while others are already playing, A request to terminate a specific wave
- that is simultaneously playing with other wave files, A request to play multiple wave files and start them
- together. A request to pause the wave output, but not lose the current location.
-
- Playing multiple files of uneven length:
-
-
-
- The Wave Mixer has to take into account the possibility that the current slice will be shorter than the wave
- slice which it is attempting to fill. That is: one of the waves which it is mixing does not contain sufficient
- data to have a sample mixed into all the elements of the destination buffer. To handle the situation the
- wave mixer must first determine if a wave like this exists. If it does then it must determine how many
- samples it can mix from that wave. It will then mix from all the waves for that many samples. Then it will
- stop mixing that wave and mix the remaining waves for the second part of the destination buffer. Since it
- is possible that the same situation can occur again while mixing the remaining waves into the remaining
- part of the buffer it must repeat the above process again. This process will continue until the destination
- buffer gets completely filled up or their is no more wave data remaining to be mixed. At this point the
- destination buffer is submitted to the wave output device.
-
- A request to start a new wave playing while others are already playing: "remixing"
-
- A complex situation that the real time wave mixer must handle is a request to play a new wave file while
- there is currently other waves being played. The reason that this is difficult is that the wave mixer is
- actually mixing wave data a finite amount of time before the wave output that is currently being played by
- the wave driver. The wave mixer must determine the position at which the wave output device is actually
- playing wave data, "remix" the wave data to include the new wave, notify the output device that the data it
- is currently playing is no longer valid (waveOutReset( ) ) and submit new wave data to it that contains the
- new wave too. All of this must be done very quickly so that the user does not hear an interruption in the
- audio.
-
- A second algorithm is also employed to achieve the above effect on hardware configurations where doing a
- waveOutReset can cause an audible click or cause the hardware to slow down. In these situations the wave
- mixer queues the new wave but does not interrupt the wave output device. When it mixes the next slice of
- data it will include the new wave also. This method can have a small delay which is the amount of time
- from which the wave data is submitted to when it is played: The driver must finish playing the current
- buffer, play all the previously queued buffers, and then play the new buffer. If there are three buffers being
- juggled with the wave output device the delay can be the amount of time required to play two to three
- buffers before the new wave data can be heard. If the wave buffers are very short then it is difficult but not
- impossible to hear the delay.
-
- A request to terminate a specific wave that is simultaneously playing with other wave files:
-
- Occasionally while playing multiple files the WaveMix.DLL will be requested to stop playing a wave on a
- particular channel before that wave has completed playing, i.e. "flush" a channel. This is handled in a
- similar manner to starting a new wave while others are playing. The wave mixer first determines the wave
- output position. It then removes the desired wave from the specified channel and "remixes" the remaining
- waves from the obtained output position.
-