Audio recording and saving to a wave file.

Hello,

I tried to implement audio recording in my application.  I am having some difficulties.  I tried looking into the sample "Recording and Playing Waveform Audio," but I have not been able to save the audio into a wave file correctly.  I tried adding the some of my code into this sample code without taking the sample code out.  When I run this application, I do hear the recording when I do record and then play back.  However, what I tried to save into a wave file is not correct.  Below is an excerpt of my code:

void CWaveInDevice::WaveInData(CWave* pWave, WAVEHDR* pHdr)
{
    // Send another block to the driver
    // Allocate a header
    WAVEHDR* phdrNew = (WAVEHDR*)malloc(sizeof(WAVEHDR));
    ASSERT(phdrNew);
    // fill out the wave header
    memset(phdrNew, 0, sizeof(WAVEHDR));
    phdrNew->lpData = (LPSTR)malloc(m_iBlockSize);
    ASSERT(phdrNew->lpData);
    phdrNew->dwBufferLength = m_iBlockSize;
    phdrNew->dwUser = (DWORD)(void*)pWave;  // so we can find the object

    // Prepare the header
    MMRESULT mmr = waveInPrepareHeader(m_hInDev,
                                       phdrNew,
                                       sizeof(WAVEHDR));
    if (mmr) MMERR(mmr);

    // Send it to the driver
    mmr = waveInAddBuffer(m_hInDev,
                          phdrNew,
                          sizeof(WAVEHDR));
    if (mmr) MMERR(mmr);

      //write this block of wave info into file where m_WaveFile is a CFile object
//this is one of the lines that I have added in this sample code.
      m_WaveFile.Write(pHdr->lpData, pHdr->dwBytesRecorded);

    // Now handle the block that was completed
    // Unprepare the header
    mmr = waveInUnprepareHeader(m_hInDev,
                                pHdr,
                                sizeof(WAVEHDR));
    if (mmr) {
        MMERR(mmr);
    }

    // See if it contains any data
    if (pHdr->dwBytesRecorded != 0)
      {
        // Create a wave block and attach it to the wave
        WAVEFORMATEX* pfmt = (WAVEFORMATEX*) pWave->GetFormat();
        ASSERT(pfmt->wFormatTag = WAVE_FORMAT_PCM);
        int iSampleSize = pfmt->wBitsPerSample / 8;
        int iSamples = pHdr->dwBytesRecorded / iSampleSize;

        CWaveBlock* pWB = new CWaveBlock(pHdr->lpData,
                                         pHdr->dwBufferLength,
                                         iSamples);
        pWave->GetBlockList()->AppendBlock(pWB);
        pWave->NewData(pWB);
    } else {
        // Delete the block
        free(pHdr->lpData);
    }

    // free the header
    free(pHdr);
}

I hope someone can give me some hints.

Thanks,
Jennifer
jliAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jliAuthor Commented:
Edited text of question
0
xbwenCommented:
 below is my function for write wave to a file, it works very well.

UINT WINAPI ReadWaveFrommmio(HMMIO hmmio,
                             LPPCMWAVEFORMAT lppcmWaveFormat,
                             HPSTR FAR*lphpWaveData,                                          LPDWORD lpdwWaveDataSize)
{
    ASSERT(lppcmWaveFormat != NULL);
    ASSERT(lpdwWaveDataSize != NULL);
   
    MMCKINFO mmckinfoParent, mmckinfoSubchunk;
   
    if (lphpWaveData != NULL)
        *lphpWaveData = NULL;
   
    if (hmmio == NULL)
        // Invalid file handle.
        return 1;
   
    // Locate a 'RIFF' chunk with a 'WAVE' form type
    // to make sure it's a WAVE file.
    mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
    if (::mmioDescend(hmmio, &mmckinfoParent, NULL, MMIO_FINDRIFF) != 0)
        // This is not a WAVE file.
        return 2;
   
    // Now, find the format chunk (form type 'fmt '). It should be
    // a subchunk of the 'RIFF' parent chunk.
    mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
    if (::mmioDescend(hmmio, &mmckinfoSubchunk,
                      &mmckinfoParent, MMIO_FINDCHUNK) != 0)
        // WAVE file is corrupted.
        return 3;
   
    // Get the size of the format chunk.
    // if (mmckinfoSubchunk.cksize != sizeof(PCMWAVEFORMAT))
           // Format size is not the size of PCMWAVEFORMAT!
   
    // Read the format chunk.
    if (::mmioRead(hmmio, (HPSTR)lppcmWaveFormat, sizeof(PCMWAVEFORMAT))
        != (LONG)sizeof(PCMWAVEFORMAT))
        // Failed to read format chunk.
        return 4;
   
    // Make sure it's a PCM file.
    if (lppcmWaveFormat->wf.wFormatTag != WAVE_FORMAT_PCM)
        // The file is not a PCM file.
        return 5;
   
    // Ascend out of the format subchunk.
    ::mmioAscend(hmmio, &mmckinfoSubchunk, 0);
   
    // Find the data subchunk.
    mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
    if (::mmioDescend(hmmio, &mmckinfoSubchunk,
                      &mmckinfoParent, MMIO_FINDCHUNK) != 0)
        // WAVE file has no data chunk.
        return 6;
   
    // Get the size of the data subchunk.
    if ((*lpdwWaveDataSize = mmckinfoSubchunk.cksize) != 0L &&
        lphpWaveData != NULL)
    {
        // Allocate and lock memory for the waveform data.
        if ((*lphpWaveData = (HPSTR)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
                                                   *lpdwWaveDataSize)) == NULL)
            // Not enough memory
            return 7;
       
        // Read the waveform data subchunk.
        if (::mmioRead(hmmio, *lphpWaveData, (LONG)*lpdwWaveDataSize)
            != (LONG)*lpdwWaveDataSize)
        {
            // Failed to read data chunk.
            GlobalFreePtr(*lphpWaveData);
            *lphpWaveData = NULL;
           
            return 8;
        }
    }
   
    return 0;      // successful
}

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
jliAuthor Commented:
xbwen,

I am a little confused with your fucntion.  Is your function doing reading from a wave file and not write the recording audio information into a wave file.
0
Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

xbwenCommented:
sorry for mistake, I give you the right one.

UINT WINAPI WriteWaveToFile(LPCSTR lpszWaveFilename,
                            LPCPCMWAVEFORMAT lppcmWaveFormat,
                            HPCSTR hpWaveData, DWORD                             dwWaveDataSize)
{
    ASSERT(lpszWaveFilename != NULL);
    ASSERT(::AfxIsValidString(lpszWaveFilename));
    ASSERT(lppcmWaveFormat != NULL);
    ASSERT(::IsValidPCMWaveFormat(lppcmWaveFormat));
   
    MMCKINFO mmckinfoParent, mmckinfoSubchunk;
    HMMIO hmmio;
   
    // Open the given file for writing using buffered I/O.
    if ((hmmio = ::mmioOpen((LPSTR)lpszWaveFilename, NULL,
                            MMIO_CREATE | MMIO_WRITE |                             MMIO_EXCLUSIVE))
        == NULL)
        // Failed to create wave
0
xbwenCommented:
sorry for my mistake, I give you the right one.
UINT WINAPI WriteWaveToFile(LPCSTR lpszWaveFilename,
                            LPCPCMWAVEFORMAT lppcmWaveFormat,
                            HPCSTR hpWaveData, DWORD dwWaveDataSize)
{
    ASSERT(lpszWaveFilename != NULL);
    ASSERT(::AfxIsValidString(lpszWaveFilename));
    ASSERT(lppcmWaveFormat != NULL);
    ASSERT(::IsValidPCMWaveFormat(lppcmWaveFormat));
   
    MMCKINFO mmckinfoParent, mmckinfoSubchunk;
    HMMIO hmmio;
   
    // Open the given file for writing using buffered I/O.
    if ((hmmio = ::mmioOpen((LPSTR)lpszWaveFilename, NULL,
                            MMIO_CREATE | MMIO_WRITE | MMIO_EXCLUSIVE))
        == NULL)
        // Failed to create wave file.
        return 1;
   
    // Create a 'RIFF' chunk with a 'WAVE' form type
    mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
    if (::mmioCreateChunk(hmmio, &mmckinfoParent, MMIO_CREATERIFF) != 0)
    {
        // Failed create 'RIFF' chunk.
        ::mmioClose(hmmio, 0);
        return 2;
    }
   
    // Create the format subchunk (form type 'fmt ').
    mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
    mmckinfoSubchunk.cksize = sizeof(PCMWAVEFORMAT);
    if (::mmioCreateChunk(hmmio, &mmckinfoSubchunk, 0) != 0)
    {
        // Failed create the format subchunk.
        ::mmioClose(hmmio, 0);
        return 3;
    }
   
    // Write the format subchunk.
    if (::mmioWrite(hmmio, (HPSTR)lppcmWaveFormat, sizeof(PCMWAVEFORMAT))
        != (LONG)sizeof(PCMWAVEFORMAT))
    {
        // Failed to write the format subchunk.
        ::mmioClose(hmmio, 0);
        return 4;
    }
   
    // Ascend out of the format subchunk.
    if (::mmioAscend(hmmio, &mmckinfoSubchunk, 0) != 0)
    {
        // Failed to write the format subchunk.
        ::mmioClose(hmmio, 0);
        return 4;
    }
   
    // Create the data subchunk that holds the waveform samples.
    mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
    mmckinfoSubchunk.cksize = dwWaveDataSize;
    if (::mmioCreateChunk(hmmio, &mmckinfoSubchunk, 0) != 0)
    {
        // Failed to create the data subchunk.
        ::mmioClose(hmmio, 0);
        return 5;
    }
   
    if (hpWaveData != NULL && dwWaveDataSize != 0)
        // Write the waveform data subchunk.
        if (::mmioWrite(hmmio, hpWaveData, (LONG)dwWaveDataSize)
            != (LONG)dwWaveDataSize)
        {
            // Failed to write the data subchunk.
            ::mmioClose(hmmio, 0);
            return 6;
        }
   
    // Ascend out of the data subchunk.
    if (::mmioAscend(hmmio, &mmckinfoSubchunk, 0) != 0)
    {
        // Failed to write the data subchunk.
        ::mmioClose(hmmio, 0);
        return 6;
    }
   
    // Ascend out of the 'RIFF' chunk.
    if (::mmioAscend(hmmio, &mmckinfoParent, 0) != 0)
    {
        // Failed create 'RIFF' chunk.
        ::mmioClose(hmmio, 0);
        return 2;
    }
   
    // We're done with the file, close it.
    ::mmioClose(hmmio, 0);
   
    return 0;    // successful
}

0
jliAuthor Commented:
I tried to open the input device for recording to write the recording into a wave file, but I cannot seem to open the input device.  When I call the function
mmr = waveInOpen(&m_hInDev,
                     iID,
                     pFormat,
                     (DWORD)(GetSafeHwnd()),
                     0,
                     CALLBACK_WINDOW);
mmr indicates bad device id.  How can I get a valid device id when I call the function waveInGetDeviceCaps?

    m_iNumDevs = waveInGetNumDevs();
    if (m_iNumDevs == 0) {
        AfxMessageBox("There are no suitable input devices");
        return;
    }
    // Allocate memory for the device list
    if (m_pDevCaps) delete m_pDevCaps;
    m_pDevCaps = new WAVEINCAPS[m_iNumDevs];
    for (int i=0; i<m_iNumDevs; i++)
      {
        waveInGetDevCaps(i,
                         &m_pDevCaps[i],
                         sizeof(WAVEINCAPS));
    }
I was wondering if there is a good book on these issues and on multimedia programming using mfc if possible.  Thanks.
0
xbwenCommented:
 I think MFC on-line help will give you some help, and the JUMP_START CD-ROM also have some samples but it is SDK.
  there should be some books ,but I can't remember its name, if possible, I will check for you.
0
jliAuthor Commented:
xbwen,

What is JumpStart CD-ROM?  Do I need to purchase it from Microsoft, or does it come with the developer platform?  Is it possible to record the audio with Microsoft ADPCM compression settings, so I don't have to do conversion after I finish recording the audio?  I tried using

acmFormatChoose( &acmopt );

to select the compression which returns me the WAVEFORMATEX structure with the following information:

wFormatTag = 2
nChannels = 1
nSamplesPerSec = 8000
nAvgBytesPerSec = 4096
nBlockAlign = 256
wBitsPerSample = 4
cbSize = 32

but when I tried to do
waveInOpen(&m_hInDev,
                     iID,
                     pFormat,
                     (DWORD)(GetSafeHwnd()),
                     0,
                     CALLBACK_WINDOW);
I get the MMRESULT to be no valid device to support this format.  I was wondering what I did wrong?  Thank you so much for all your assistance that you have given me.
0
Shahzad_mcaCommented:
hi xbwen,
  I've tried this code given by U to record & save it in a .wav file..

UINT WINAPI WriteWaveToFile(LPCSTR lpszWaveFilename,                     LPCPCMWAVEFORMAT lppcmWaveFormat,
HPCSTR hpWaveData, DWORD dwWaveDataSize)
{
    ASSERT(lpszWaveFilename != NULL);
    ASSERT(::AfxIsValidString(lpszWaveFilename));
    ASSERT(lppcmWaveFormat != NULL);
    ASSERT(::IsValidPCMWaveFormat(lppcmWaveFormat));
     
    MMCKINFO mmckinfoParent, mmckinfoSubchunk;
    HMMIO hmmio;
     
    // Open the given file for writing using buffered I/O.
    if ((hmmio = ::mmioOpen((LPSTR)lpszWaveFilename, NULL,
                            MMIO_CREATE | MMIO_WRITE | MMIO_EXCLUSIVE))
        == NULL)
        // Failed to create wave file.
        return 1;
     
    // Create a 'RIFF' chunk with a 'WAVE' form type
    mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
    if (::mmioCreateChunk(hmmio, &mmckinfoParent, MMIO_CREATERIFF) != 0)
    {
        // Failed create 'RIFF' chunk.
        ::mmioClose(hmmio, 0);
        return 2;
    }
     
    // Create the format subchunk (form type 'fmt ').
    mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
    mmckinfoSubchunk.cksize = sizeof(PCMWAVEFORMAT);
    if (::mmioCreateChunk(hmmio, &mmckinfoSubchunk, 0) != 0)
    {
        // Failed create the format subchunk.
        ::mmioClose(hmmio, 0);
        return 3;
    }
     
    // Write the format subchunk.
    if (::mmioWrite(hmmio, (HPSTR)lppcmWaveFormat, sizeof(PCMWAVEFORMAT))
        != (LONG)sizeof(PCMWAVEFORMAT))
    {
        // Failed to write the format subchunk.
        ::mmioClose(hmmio, 0);
        return 4;
    }
     
    // Ascend out of the format subchunk.
    if (::mmioAscend(hmmio, &mmckinfoSubchunk, 0) != 0)
    {
        // Failed to write the format subchunk.
        ::mmioClose(hmmio, 0);
        return 4;
    }
     
    // Create the data subchunk that holds the waveform samples.
    mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
    mmckinfoSubchunk.cksize = dwWaveDataSize;
    if (::mmioCreateChunk(hmmio, &mmckinfoSubchunk, 0) != 0)
    {
        // Failed to create the data subchunk.
        ::mmioClose(hmmio, 0);
        return 5;
    }
     
    if (hpWaveData != NULL && dwWaveDataSize != 0)
        // Write the waveform data subchunk.
        if (::mmioWrite(hmmio, hpWaveData, (LONG)dwWaveDataSize)
            != (LONG)dwWaveDataSize)
        {
            // Failed to write the data subchunk.
            ::mmioClose(hmmio, 0);
            return 6;
        }
     
    // Ascend out of the data subchunk.
    if (::mmioAscend(hmmio, &mmckinfoSubchunk, 0) != 0)
    {
        // Failed to write the data subchunk.
        ::mmioClose(hmmio, 0);
        return 6;
    }
     
    // Ascend out of the 'RIFF' chunk.
    if (::mmioAscend(hmmio, &mmckinfoParent, 0) != 0)
    {
        // Failed create 'RIFF' chunk.
        ::mmioClose(hmmio, 0);
        return 2;
    }
     
    // We're done with the file, close it.
    ::mmioClose(hmmio, 0);
     
    return 0;    // successful
}

  But the problem with me , is that , first I get the error for LPCPCMWAVEFORMAT & HPCSTR  as unknown identifier, but later inconvert it into PCMWAVEFROMAT & LPTSTR repst.,the code work & stores the data in file.But when I try tried to plat that file, i got the error "This is not a waveform file "

Please help me out & provide the proper info.

thanks...
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.