Thread: Play multipul sounds at once.

  1. #1
    Registered User Queatrix's Avatar
    Join Date
    Apr 2005
    Posts
    1,342

    Question Play multipul sounds at once.

    I have looked it up and I can't seem to get what I am looking for.

    I want to play multipul (like 3 or 4) wav files at once, without using a big driver like DirectSound or DirectMusic.

    Thanks, Queatrix.

  2. #2
    Registered User Queatrix's Avatar
    Join Date
    Apr 2005
    Posts
    1,342

  3. #3
    Software engineer
    Join Date
    Aug 2005
    Location
    Oregon
    Posts
    283
    I had one in the past that helped for several formats, here is MIDI and MP3. I haven't tested it for a while but I'm sure it'll be a good start. It's easy anyway
    You will need winmm.lib and mmsystem.h included in your project.

    Code:
    	////////////////////////////////////////////////////////////////////
    	// MIDI Class
    	//
    	class MIDI 
    	{
    	private: 
    		std::string szFileName;		// The filename and alias.
    		std::string szCommand;		// The command to send.
    	public:
    		// Initializes the MIDI.
    		void Init(std::string szFileName) {
    			this->szFileName = szFileName;			
    		}
    
    		// Play MIDI 
    		void Play() { 
    			szCommand = "play " + szFileName;
    			mciSendString(szCommand.c_str(), NULL, 0, NULL);
    		}
    
    		// Stop MIDI 
    		void Stop() {
    			szCommand = "stop " + szFileName; 
    			mciSendString(szCommand.c_str(), 0, 0, 0);			  
    		}
    	};
    
    	/////////////////////////////////////////////////////////////////////////
    	// MP3 Class
    	//
    	class MP3
    	{
    	private:
    		std::string szFileName;		// The filename and alias.
    		std::string szCommand;		// The command to send.
    
    		~MP3() { 
    			szCommand = "close " + szFileName;		
    			mciSendString(szCommand.c_str(), NULL, 0, 0);
    		}
    		
    		// Initializes the MP3 class.
    		void Init(std::string szFileName) {
    			this->szFileName = szFileName; 
    
    			szCommand = "open \"" + szFileName + 
    				"\" type mpegvideo alias " + szFileName;	
    			mciSendString(szCommand.c_str(), NULL, 0, 0);
    		}
    
    		// Play MP3
    		void Play()	{
    			szCommand = "play " + szFileName + " from 0";
    			mciSendString(szCommand.c_str(), NULL, 0, 0);
    		} 
    
    		// Pause MP3
    		void Pause() {
    			szCommand = "pause " + szFileName;
    			mciSendString(szCommand.c_str(), NULL, 0, 0);
    		}
    
    		// Unpause MP3
    		void Unpause() {
    			szCommand = "resume " + szFileName;
    			mciSendString(szCommand.c_str(), NULL, 0, 0);
    		}
    
    		// Stop MP3
    		void Stop() {
    			szCommand = "stop " + szFileName;
    			mciSendString(szCommand.c_str(), NULL, 0, 0);
    		}
    	};

  4. #4
    Registered User Queatrix's Avatar
    Join Date
    Apr 2005
    Posts
    1,342
    Hmm, that doesn't make sense, you shouldn't be able to play 2 MIDIs at the same time.

  5. #5
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    What's the difference between using a big driver or any driver? PM necessitates the use of drivers.

  6. #6
    Registered User Queatrix's Avatar
    Join Date
    Apr 2005
    Posts
    1,342
    First off, you have to have them.
    Second, they tend to take up more resources.

  7. #7
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    And firing off threads isn't going to take resources?

    Playing multiple waves is actually quite simple if you can get to the data. Otherwise you are at the mercy of threads, processes, and pseudo multiple wav file techniques.

    The correct way to do it is grab a sample from every sound that is marked as playing. Then perform some type of mixing algorithm on the samples (I normally use additive mixing) and output the final sample to the primary buffer.

    With the buffer most APIs will give you two pointers. A write pointer and a read pointer. This is because sound buffers are circular and always operate as read into section that just played, play from section that just loaded.

    Play...............|Load....................|Play. ...................|Load

    You can do this in as little as 256 bytes and get excellent sound quality.

    Unless the Windows media interfaces/functions allow you access to the buffer, you cannot implement this type of code. I'm sure there are functions to get to the nitty gritty of the system.

    Here is the simple algo:

    Code:
    UINT CSoftwareAudio::Mix()
    {
      UINT uSampleValue;
    
      do
      {
      
        for (UINT i=0;i<m_iNumSounds;i++)
        {
          uSampleValue+=m_pBufferMgr->GetNextSample(i);
        }
    
        uSampleValue/=m_iNumSounds;
        return uSampleValue;
    }
    Code:
    UINT CSoundBuffer::GetNextSample(UINT uPos)
    {
      UINT uSample=m_pBuffer[m_uBufferPos];
      m_uBufferPos++;
      return uSample;
    }
    This does not take into account that all sounds are of variable length. You would have to check this and update your sound manager to remove that sound from the list when it reached the end. The end of sound condition would be returned by the class saying there are no more samples in the buffer. If the sound buffer was to be looped you would check the boolean and if set simply reset m_uBufferPos to 0 and the process starts over.

    It is difficult to avoid getting small clicks and pops as sounds reach the end of their buffer midway in the play buffer. This means a sound dies out in the middle of a 128 byte buffer and yet other sounds may not. This causes a noticeable 'click' and or 'pop' and even DirectSound suffers from this at times.

    How do you know when the DSP has reached the end of the play buffer which means you need to load? Well in the old days you programmed the DSP for HALF the length and you programmed the DMA for the WHOLE length. You would point the DMA to a section of memory to be used as the buffer. The DMA simply scans that entire segment of memory over and over and over and over. Now when the DSP reached the programmed sample count it would fire off a hardware interrupt on 55,56, or 57 (if I remember correctly). You would write an interrupt handler to intercept the interrupt, load into the buffer at right spot, re-program the DSP for another HALF length, and return.

    The cycle then repeats until the sound is played. Multiple sounds are achieved by simply adding samples onto one another. Sound is a unique beastie in that when you hear 2 sounds you are really hearing 2 waveforms at once and possibly interfering with one another. So when you add 2 sounds together and divide by 2, you will hear both sounds. One problem with additive mixing or average mixing is that the volume tends to decrease slightly the more sounds you get. DSP and digital sound algos are a very complex subject and go far beyond the scope of this post.
    I encourage you to research on your own.

    I've given you more than enough information to create a small audio mixer and sound system that can play multiple sounds. Look on the net for some sound code and even inside of Allegro. You will find much of what I've been talking about embedded deep in the assembly code for Allegro's sound support.
    Last edited by VirtualAce; 09-19-2006 at 11:32 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. how to play play and stop wav files
    By cnu_sree in forum Linux Programming
    Replies: 4
    Last Post: 08-14-2006, 11:11 PM
  2. Updated sound engine code
    By VirtualAce in forum Game Programming
    Replies: 8
    Last Post: 11-18-2004, 12:38 PM
  3. pls post here tricks that you know of in C/C++, thanks
    By mickey in forum C++ Programming
    Replies: 55
    Last Post: 06-12-2003, 04:28 PM
  4. Gui Class With Tic Tac Toe
    By xxYukoxx in forum C++ Programming
    Replies: 1
    Last Post: 06-01-2003, 04:28 PM
  5. Cribbage Game
    By PJYelton in forum Game Programming
    Replies: 14
    Last Post: 04-07-2003, 10:00 AM