Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Audio Capture

5.00/5 (4 votes)
13 Apr 2017CPOL1 min read 26.6K   2.2K  
Stereo mix audio capture with peak level display

Introduction

This 64-bit Visual Studio 2017 community project is intended to perform real time audio capture of anything playing on your PC.

While it could be used to record from the microphone, the best quality is achieved when using a multiplex audio card and recording from the "Stereo mix" device.

How to Use AudioCap

  1. Start AudioCap.
  2. Start playing a movie (with a sound track) or a local or internet audio file (streaming).
  3. Press the [Start capture] button, to see the oscilloscope PCM WIMDATA curve.
  4. Check "Capture to Wave" if you want to create the "capture.wav", or check "Monitoring only" if you want to see only the peak level.

Background

The original version was written long ago at the time of XP in PowerBASIC.

Using the Code

Here is the OpenWaveIn function that can be customized to use a specific device.

Search for:

C++
if ((DeviceToUse == MICROPHONE) && (StrStrI(wic.szPname, L"micro"))) { break; } // Microphone
if ((DeviceToUse == STEREO_MIX) && (StrStrI(wic.szPname, L"stereo"))) { break; } // Stereo mix
C++
DWORD OpenWaveIn(IN HWND hParent, IN long UseWaveFormat, IN long DeviceToUse) {
    WAVEINCAPS wic = { 0 };
    WORD zBitsPerSample = 0, zChannels = 0;
    LONG zSamplesPerSec = 0, I = 0;
    DWORD nRet = 0;

    switch (UseWaveFormat) {
    case WAVE_FORMAT_1M08: // Mono   11025 8-bit
         zChannels = 1; zSamplesPerSec = 11025; zBitsPerSample = 8;
         break;
    case WAVE_FORMAT_1S08: // Stereo 11025 8-bit
         zChannels = 2; zSamplesPerSec = 11025; zBitsPerSample = 8;
         break;
    case WAVE_FORMAT_1M16: // Mono   11025 16-bit
         zChannels = 1; zSamplesPerSec = 11025; zBitsPerSample = 16;
         break;
    case WAVE_FORMAT_1S16: // Stereo 11025 16-bit
         zChannels = 2; zSamplesPerSec = 11025; zBitsPerSample = 16;
         break;
    case WAVE_FORMAT_2M08: // Mono   22050 8-bit
         zChannels = 1; zSamplesPerSec = 22050; zBitsPerSample = 8;
         break;
    case WAVE_FORMAT_2S08: // Stereo 22050 8-bit
         zChannels = 2; zSamplesPerSec = 22050; zBitsPerSample = 8;
         break;
    case WAVE_FORMAT_2S16: // Stereo 22050 16-bit
         zChannels = 2; zSamplesPerSec = 22050; zBitsPerSample = 16;
         break;
    case WAVE_FORMAT_4M08: // Mono   44100 8-bit
         zChannels = 1; zSamplesPerSec = 44100; zBitsPerSample = 8;
         break;
    case WAVE_FORMAT_4S08: // Stereo 44100 8-bit
         zChannels = 2; zSamplesPerSec = 44100; zBitsPerSample = 8;
         break;
    case WAVE_FORMAT_4M16: // Mono   44100 16-bit
         zChannels = 1; zSamplesPerSec = 44100; zBitsPerSample = 16;
         break;
    case WAVE_FORMAT_4S16: // Stereo 44100 16-bit
         zChannels = 2; zSamplesPerSec = 44100; zBitsPerSample = 16;
         break;
    default:   //WAVE_FORMAT_2M16 Mono   22050 16-bit
         zChannels = 1; zSamplesPerSec = 22050; zBitsPerSample = 16;
    }
    LONG nDev = (LONG) waveInGetNumDevs();
    for (I = 0; I < nDev; I++) {
         nRet = waveInGetDevCaps(I, &wic, sizeof(wic));
         if (nRet == 0) {
             if (wic.dwFormats & UseWaveFormat) {
                 gCap.wfx.nChannels = zChannels;
                 gCap.wfx.nSamplesPerSec = zSamplesPerSec;
                 gCap.wfx.wFormatTag = WAVE_FORMAT_PCM;
                 gCap.wfx.wBitsPerSample = zBitsPerSample;
                 gCap.wfx.nBlockAlign = gCap.wfx.nChannels * gCap.wfx.wBitsPerSample / 8;
                 gCap.wfx.nAvgBytesPerSec = gCap.wfx.nSamplesPerSec * gCap.wfx.nBlockAlign;
                 gCap.wfx.cbSize = 0;
                 nRet = waveInOpen(&gCap.hWaveIn, I, &gCap.wfx, 
                 (DWORD_PTR) gCap.hAudioWnd, (DWORD_PTR)gCap.hAudioWnd, CALLBACK_WINDOW);
                 if (nRet == 0) {
                     if ((DeviceToUse == MICROPHONE) && 
                     (StrStrI(wic.szPname, L"micro"))) { break; } // Microphone
                     if ((DeviceToUse == STEREO_MIX) && 
                     (StrStrI(wic.szPname, L"stereo"))) { break; } // Stereo mix
                 }
            } else {
                 nRet = 22;   //"Le périphérique 
                 //ne reconnaît pas la commande." alias "No suitable device found"
            }
        }
    }
    return nRet;
}

And here is a link to show you how to setup Windows to enable the hidden "Stereo mix" mode. .

Points of Interest

The code is written in full procedural mode, using only the core flat API SDK, to be easily translated from one language to another. The AudioCap.h section has been designed to also be easily turned into a DLL.

You can find more free contributions on my private forum www.objreader.com, especially if you like graphic, multimedia, OpenGL and 3D wavefront model viewer.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)