Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

Audio recording and saving to a wave file.

Posted on 1997-04-21
9
Medium Priority
?
1,052 Views
Last Modified: 2013-11-20
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
0
Comment
Question by:jli
  • 4
  • 4
9 Comments
 

Author Comment

by:jli
ID: 1301128
Edited text of question
0
 
LVL 1

Accepted Solution

by:
xbwen earned 100 total points
ID: 1301129
 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
 

Author Comment

by:jli
ID: 1301130
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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 1

Expert Comment

by:xbwen
ID: 1301131
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
 
LVL 1

Expert Comment

by:xbwen
ID: 1301132
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
 

Author Comment

by:jli
ID: 1301133
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
 
LVL 1

Expert Comment

by:xbwen
ID: 1301134
 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
 

Author Comment

by:jli
ID: 1301135
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
 

Expert Comment

by:Shahzad_mca
ID: 2302459
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

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
In this post we will learn different types of Android Layout and some basics of an Android App.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
When cloud platforms entered the scene, users and companies jumped on board to take advantage of the many benefits, like the ability to work and connect with company information from various locations. What many didn't foresee was the increased risk…

927 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