Solved

wave file resampling

Posted on 2004-09-16
4
465 Views
Last Modified: 2012-06-27
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.
0
Comment
Question by:sinha_abhijeet
  • 2
4 Comments
 
LVL 6

Expert Comment

by:Svetlin_Panayotov
Comment Utility
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
 

Author Comment

by:sinha_abhijeet
Comment Utility
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
 
LVL 6

Accepted Solution

by:
Svetlin_Panayotov earned 125 total points
Comment Utility
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

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

The following diagram presents a diamond class hierarchy: As depicted, diamond inheritance denotes when two classes (e.g., CDerived1 and CDerived2), separately extending a common base class (e.g., CBase), are sub classed simultaneously by a fourt…
In Easy String Encryption Using CryptoAPI in C++ (http://www.experts-exchange.com/viewArticle.jsp?aid=1193) I described how to encrypt text and recommended that the encrypted text be stored as a series of hexadecimal digits -- because cyphertext may…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now