Solved

Audio recording and saving to a wave file.

Posted on 1997-04-21
9
1,030 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
Comment Utility
Edited text of question
0
 
LVL 1

Accepted Solution

by:
xbwen earned 50 total points
Comment Utility
 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
Comment Utility
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
 
LVL 1

Expert Comment

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

 
LVL 1

Expert Comment

by:xbwen
Comment Utility
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
Comment Utility
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
Comment Utility
 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
Comment Utility
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
Comment Utility
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 Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
Introduction: The undo support, implementing a stack. Continuing from the eigth article about sudoku.   We need a mechanism to keep track of the digits entered so as to implement an undo mechanism.  This should be a ‘Last In First Out’ collec…
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.
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…

763 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

11 Experts available now in Live!

Get 1:1 Help Now