wave file resampling

Hi,
I am new to VC++.
How do I resample(upsample/downsample) any wave file to a predefined value. Basically how do I change the attributes denoted by the WAVEFORMATEX structure, of an already existing file. (for example I have to convert any wav file into 8 khz 16 bit, PCM). The file will be an already existing one and not one to be recorded.
Thanx in advance.
sinha_abhijeetAsked:
Who is Participating?
 
Svetlin_PanayotovConnect With a Mentor Commented:
Ok..here's a sample class that works well (for me) with ACM.

//////////// File AcmStream.h
#include <mmsystem.h>
#include <mmreg.h>
#include <msacm.h>

#pragma comment( lib, "msacm32.lib" )

class AcmStream  
{
public:
      AcmStream();
      virtual ~AcmStream();

public:
      bool Open(WAVEFORMATEX *pWfxInput, WAVEFORMATEX *pWfxOutput);
      void Close();
      bool Convert(const LPBYTE pbInputData, DWORD nInputSize, DWORD &dwInputBytesUsed, LPBYTE pbOutputData, DWORD &dwOutputBytesUsed);
      DWORD GetInputBufferSize();
      DWORD GetOutputBufferSize();
protected:
      void Init();

private:
      HACMSTREAM m_hAcmStream;
      ACMSTREAMHEADER m_AcmStreamHeader;
      DWORD m_dwSrcBufferSize;
      DWORD m_dwDstBufferSize;
      bool m_bStreamOpened;
};
////////////// End of AcmStream.h


///////////// File AcmStream.cpp
#include "AcmStream.h"
#include <mmsystem.h>
#include <mmreg.h>
#include <msacm.h>

AcmStream::AcmStream()
{
      m_hAcmStream = NULL;
      memset(&m_AcmStreamHeader, 0, sizeof(m_AcmStreamHeader));
      m_AcmStreamHeader.cbStruct = sizeof(m_AcmStreamHeader);
      Init();
}

AcmStream::~AcmStream()
{
      Init();
}

void AcmStream::Init()
{
      //Close the stream if opened
      if(m_hAcmStream)
      {
            if(m_AcmStreamHeader.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)
            {
                  //Cleanup the preparation performed by acmStreamPrepareHeader
            m_AcmStreamHeader.cbSrcLength = m_dwSrcBufferSize;
                  m_AcmStreamHeader.cbDstLength = m_dwDstBufferSize;
            acmStreamUnprepareHeader(m_hAcmStream, &m_AcmStreamHeader, 0L);
            }
            acmStreamClose(m_hAcmStream, 0);
            m_hAcmStream = NULL;
      }

      if(m_AcmStreamHeader.pbSrc)
      {
            delete []m_AcmStreamHeader.pbSrc;
      }
      
      if(m_AcmStreamHeader.pbDst)
      {
            delete []m_AcmStreamHeader.pbDst;
      }
      //Init to zero
      memset(&m_AcmStreamHeader, 0, sizeof(m_AcmStreamHeader));
      m_AcmStreamHeader.cbStruct = sizeof(m_AcmStreamHeader);

      m_dwSrcBufferSize = 0;
      m_dwDstBufferSize = 0;
      m_bStreamOpened = false;
}

bool AcmStream::Open(WAVEFORMATEX *pWfxInput, WAVEFORMATEX *pWfxOutput)
{
      long nGeneralEx(0);
      
      if(m_bStreamOpened)
      {
            return false;
      }

      try
      {
            if( 0 != acmStreamOpen(&m_hAcmStream,
                                    NULL,
                                    pWfxInput,
                                    pWfxOutput,
                                    NULL,
                                    0L,
                                    0L,
                                    ACM_STREAMOPENF_NONREALTIME))
            {
                  throw nGeneralEx;
            }
            
            //Compute source bytes to read (round down to nearest block for
            //one second of data)
            DWORD nAvgBytesPerSec = pWfxInput->nAvgBytesPerSec;
            WORD nBlockAlign = pWfxInput->nBlockAlign;
            m_dwSrcBufferSize = nAvgBytesPerSec - (nAvgBytesPerSec % nBlockAlign);
            
            if(acmStreamSize(m_hAcmStream,
                                    m_dwSrcBufferSize,
                                    &m_dwDstBufferSize,
                                    ACM_STREAMSIZEF_SOURCE) !=0)
            {
                  throw nGeneralEx;
            }
            
            //Initialize the stream header
          m_AcmStreamHeader.fdwStatus = 0L;
            m_AcmStreamHeader.dwUser = 0L;
            m_AcmStreamHeader.pbSrc = new BYTE[m_dwSrcBufferSize];
            m_AcmStreamHeader.cbSrcLength = m_dwSrcBufferSize;
            m_AcmStreamHeader.cbSrcLengthUsed = 0L;
            m_AcmStreamHeader.dwSrcUser = m_dwSrcBufferSize;
            m_AcmStreamHeader.pbDst = new BYTE[m_dwDstBufferSize];
            m_AcmStreamHeader.cbDstLength = m_dwDstBufferSize;
            m_AcmStreamHeader.cbDstLengthUsed = 0L;
            m_AcmStreamHeader.dwDstUser = m_dwDstBufferSize;
            
            if(acmStreamPrepareHeader(m_hAcmStream, &m_AcmStreamHeader, 0L) != 0)
            {
                  throw nGeneralEx;
            }
            m_bStreamOpened = true;
      }
      catch(long)
      {
            Init();
            return false;
      }
      
      return true;
}

void AcmStream::Close()
{
      Init();
}

DWORD AcmStream::GetInputBufferSize()
{
      return m_dwSrcBufferSize;
}

DWORD AcmStream::GetOutputBufferSize()
{
      return m_dwDstBufferSize;
}


bool AcmStream::Convert(const LPBYTE pbInputData, DWORD nInputSize, DWORD &dwInputBytesUsed, LPBYTE pbOutputData, DWORD &dwOutputBytesUsed)
{
      if(!m_bStreamOpened)
      {
            return false;
      }

      //Copy the passed input data to the source buffer of the stream header
      memcpy(m_AcmStreamHeader.pbSrc, pbInputData, nInputSize);
    m_AcmStreamHeader.cbSrcLength = nInputSize;
      m_AcmStreamHeader.cbDstLengthUsed = 0L;
      
      if(acmStreamConvert(m_hAcmStream, &m_AcmStreamHeader,
                                       ACM_STREAMCONVERTF_BLOCKALIGN) != MMSYSERR_NOERROR)
      {
            return false;
      }
      
      //Wait until the convert is on
      while((ACMSTREAMHEADER_STATUSF_DONE & m_AcmStreamHeader.fdwStatus) == 0)
      {
      }


      dwInputBytesUsed = m_AcmStreamHeader.cbSrcLengthUsed;
      dwOutputBytesUsed = m_AcmStreamHeader.cbDstLengthUsed;

      memcpy(pbOutputData, m_AcmStreamHeader.pbDst, dwOutputBytesUsed);

      return true;
}
/////////// End of file AcmStream.cpp
0
 
Svetlin_PanayotovCommented:
There's good article on how to do something similar with DirectSound:
http://msdn.microsoft.com/archive/en-us/directx9_c/directx/htm/capturingwaveforms.asp
but they are capturing the sound there.Since you already have your WAV file you can read it into memory (mmioRead etc.), use it from there and write it to another file with different sample rate using CWaveFile.

0
 
sinha_abhijeetAuthor Commented:
Instead of using directsound I tried to use the ACM class of wav format converters.
But I tried it too and it does change the file format and also reduces the size as we are downsampling. It also playes well( as a downsamled wave would play) but when I give it to a amr converter software as that is my primary purpose, it does not work. i downloaded some software and did the wav format coversion and then the amr converter could properly convert the wav file into an amr. So, there's something wrong or missing in my code. I am doing it just like the msdn documentation says. Is there something that somebody knows abt this class of wav conversion that is missing? what is it that these professional softwaremakers know that we don't?
thanx in advance

The acmStreamOpen function opens a conversion stream.
The acmStreamSize function calculates the appropriate size of the source or destination buffer.
The acmStreamPrepareHeader function prepares source and destination buffers to be used in a conversion.
The acmStreamConvert function converts data in a source buffer into the destination format, writing the converted data into the destination buffer.
The acmStreamUnprepareHeader function cleans up the source and destination buffers prepared by acmStreamPrepareHeader. You must call this function before freeing the source and destination buffers.
The acmStreamClose function closes a conversion stream.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.