Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Audio recording and saving to a wave file.

Posted on 1997-04-21
9
Medium Priority
?
1,048 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Will your db performance match your db growth?

In Percona’s white paper “Performance at Scale: Keeping Your Database on Its Toes,” we take a high-level approach to what you need to think about when planning for database scalability.

 
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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
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.
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…

715 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