Solved

Sound Recording

Posted on 1998-07-15
3
342 Views
Last Modified: 2013-11-20
I am working with Visual C++ 4.2 and  WindowsNT 4.0 on a P233.
I want to implement an MFC application which record and play sounds. I would like to be able to :
- record a sound
- to play it and stop it
- to be able to reach any particular time in the audio file
The sound I want to record comes from a microphone plugged into the PC.
 Could anyone tell me what are the available functions and how to integrate it in my application?
Thanks.
0
Comment
Question by:Nicolas060297
3 Comments
 
LVL 2

Expert Comment

by:lucidity
ID: 1319217
Check out the DirectX SDK, it has lots of examples for using Direct Input (which is handy for this kind of thing).
0
 
LVL 23

Accepted Solution

by:
chensu earned 200 total points
ID: 1319218
There are several methods.
1. The easiest way is to use MCI commands or MCIWnd Window Class. Here is an example for recording copied from the Platform SDK documentation. There are some samples for MCI playing in Visual C++ samples.

Recording with a Waveform-Audio Device
The following example opens a waveform-audio device with a new file, records for the specified time, plays the recording, and prompts the user to save the recording if desired.

// Uses the MCI_OPEN, MCI_RECORD, and MCI_SAVE commands to record and
// save a waveform-audio file. Returns 0L if successful; otherwise,
// it returns an MCI error code.
DWORD recordWAVEFile(DWORD dwMilliSeconds)
{
    UINT wDeviceID;
    DWORD dwReturn;
    MCI_OPEN_PARMS mciOpenParms;
    MCI_RECORD_PARMS mciRecordParms;
    MCI_SAVE_PARMS mciSaveParms;
    MCI_PLAY_PARMS mciPlayParms;

    // Open a waveform-audio device with a new file for recording.
    mciOpenParms.lpstrDeviceType = "waveaudio";
    mciOpenParms.lpstrElementName = "";
    if (dwReturn = mciSendCommand(0, MCI_OPEN,
        MCI_OPEN_ELEMENT | MCI_OPEN_TYPE,
        (DWORD)(LPVOID) &mciOpenParms))
    {
        // Failed to open device; don't close it, just return error.
        return (dwReturn);
    }

    // The device opened successfully; get the device ID.
    wDeviceID = mciOpenParms.wDeviceID;

    // Begin recording and record for the specified number of
    // milliseconds. Wait for recording to complete before continuing.
    // Assume the default time format for the waveform-audio device
    // (milliseconds).
    mciRecordParms.dwTo = dwMilliSeconds;
    if (dwReturn = mciSendCommand(wDeviceID, MCI_RECORD,
        MCI_TO | MCI_WAIT, (DWORD)(LPVOID) &mciRecordParms))
    {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (dwReturn);
    }

    // Play the recording and query user to save the file.
    mciPlayParms.dwFrom = 0L;
    if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY,
        MCI_FROM | MCI_WAIT, (DWORD)(LPVOID) &mciPlayParms))
    {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (dwReturn);
    }
    if (MessageBox(hMainWnd, "Do you want to save this recording?",
        "", MB_YESNO) == IDNO)
    {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (0L);
    }

    // Save the recording to a file named TEMPFILE.WAV. Wait for
    // the operation to complete before continuing.
    mciSaveParms.lpfilename = "tempfile.wav";
    if (dwReturn = mciSendCommand(wDeviceID, MCI_SAVE,
        MCI_SAVE_FILE | MCI_WAIT, (DWORD)(LPVOID) &mciSaveParms))
    {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (dwReturn);
    }

    return (0L);
}


2. Use low-level audio functions waveIn* and waveOut* functions.
Sample: "Reverse: Play a Waveform in Reverse" for playing. Here is an example for recording copied from the Platform SDK documentation.

Example of Writing Waveform Data
The following example illustrates the steps required to allocate and set up a WAVEHDR structure and write a block of data to a waveform output device.

// Global variables.

HANDLE hData  = NULL;  // handle of waveform data memory
HPSTR  lpData = NULL;  // pointer to waveform data memory
 
void WriteWaveData(void)
{
    HWAVEOUT    hWaveOut;
    HGLOBAL     hWaveHdr;
    LPWAVEHDR   lpWaveHdr;
    HMMIO       hmmio;
    UINT        wResult;
    HANDLE      hFormat;
    WAVEFORMAT  *pFormat;
    DWORD       dwDataSize;

    // Open a waveform device for output using window callback.

    if (waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER,
                    (LPWAVEFORMAT)pFormat,
                    (LONG)hwndApp, 0L, CALLBACK_WINDOW))
    {
        MessageBox(hwndApp,
                   "Failed to open waveform output device.",
                   NULL, MB_OK | MB_ICONEXCLAMATION);
        LocalUnlock(hFormat);
        LocalFree(hFormat);
        mmioClose(hmmio, 0);
        return;
    }
 
    // Allocate and lock memory for the waveform data.
 
    hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, dwDataSize );
    if (!hData)
    {
        MessageBox(hwndApp, "Out of memory.",
                   NULL, MB_OK | MB_ICONEXCLAMATION);
        mmioClose(hmmio, 0);
        return;
    }
    if ((lpData = GlobalLock(hData)) == NULL)
    {
        MessageBox(hwndApp, "Failed to lock memory for data chunk.",
                   NULL, MB_OK | MB_ICONEXCLAMATION);
        GlobalFree(hData);
        mmioClose(hmmio, 0);
        return;
    }
 
    // Read the waveform data subchunk.
 
    if(mmioRead(hmmio, (HPSTR) lpData, dwDataSize) != (LRESULT)dwDataSize)
    {
        MessageBox(hwndApp, "Failed to read data chunk.",
                   NULL, MB_OK | MB_ICONEXCLAMATION);
        GlobalUnlock(hData);
        GlobalFree(hData);
        mmioClose(hmmio, 0);
        return;
    }
 
    // Allocate and lock memory for the header.

    hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
        (DWORD) sizeof(WAVEHDR));
    if (hWaveHdr == NULL)
    {
        GlobalUnlock(hData);
        GlobalFree(hData);
        MessageBox(hwndApp, "Not enough memory for header.",
            NULL, MB_OK | MB_ICONEXCLAMATION);
        return;
    }
 
    lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr);
    if (lpWaveHdr == NULL)
    {
        GlobalUnlock(hData);
        GlobalFree(hData);
        MessageBox(hwndApp,
            "Failed to lock memory for header.",
            NULL, MB_OK | MB_ICONEXCLAMATION);
        return;
    }
 
    // After allocation, set up and prepare header.
 
    lpWaveHdr->lpData = lpData;
    lpWaveHdr->dwBufferLength = dwDataSize;
    lpWaveHdr->dwFlags = 0L;
    lpWaveHdr->dwLoops = 0L;
    waveOutPrepareHeader(hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
 
    // Now the data block can be sent to the output device. The
    // waveOutWrite function returns immediately and waveform
    // data is sent to the output device in the background.
 
    wResult = waveOutWrite(hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
    if (wResult != 0)
    {
        waveOutUnprepareHeader(hWaveOut, lpWaveHdr,
                               sizeof(WAVEHDR));
        GlobalUnlock( hData);
        GlobalFree(hData);
        MessageBox(hwndApp, "Failed to write block to device",
                   NULL, MB_OK | MB_ICONEXCLAMATION);
        return;
    }
}

Processing the MM_WOM_DONE Message
The following example shows how to process the MM_WOM_DONE message. This example assumes the application does not play multiple data blocks, so it can close the output device after playing a single data block.

// WndProc--Main window procedure.
LRESULT FAR PASCAL WndProc(HWND hWnd, UINT msg, WPARAM wParam,
    LPARAM lParam)
{
switch (msg)
{
    case MM_WOM_DONE:
 
    // A waveform-audio data block has been played and
    // can now be freed.
    waveOutUnprepareHeader((HWAVEOUT) wParam,
        (LPWAVEHDR) lParam, sizeof(WAVEHDR) );
   
    // Free hData memory.
   
    waveOutClose((HWAVEOUT) wParam);
    break;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}


3. Use DirectX 5 or later which come with IDirectSound and IDirectSoundCapture interfaces. There are a lot of samples in the SDK.

By the way, DirectInput provides support for input devices including the mouse, keyboard, and joystick, as well as for force-feedback (input/output) devices, but not sound devices.
0
 

Author Comment

by:Nicolas060297
ID: 1319219
Thanks for your answer.
0

Featured Post

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
no14 challenge 14 69
sumHeights2  challenge 7 105
Thin secure Windows 10 5 98
JQuery serialize and unserialize 8 86
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: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
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.
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …

809 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