Capturing audio with C++ using an external microphone

I need to capture voice with C++ for my graduation project. I looked up for it, I found 2 major solutions. Portaudio library and waveIn function set. I found them, yet I don't have enough knowledge to use them, I guess.

I compiled portaudio and created necessary lib and dll files. However, although I completed steps of building guide in Portaudio website, when I tried to compile a sample C code of Portaudio. I have encountered with dll not found error. I could not find solution of it on Internet.

I tried to use waveIn, but even if I added(I guess) external libraries and put mmsystem.h, windows.h and my cpp file in same folder, I received huge amount of errors.

I saw an older thread, mentioned to this topic, yet It is in archive now, so I need to ask you about this topic. Would you please help me with this? Thank you.

PS: I am using Windows 7 and Visual Studio 2010 Ultimate as compiler. If additional information is needed, please tell me. Finally, I am sharing the code I found, yet don't understand.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <mmsystem.h>

 const int NUMPTS = 44100 * 10;   // 10 seconds
 int sampleRate = 44100;
 short int waveIn[NUMPTS];   // 'short int' is a 16-bit type; I request 16-bit samples below
                             // for 8-bit capture, you'd use 'unsigned char' or 'BYTE' 8-bit types

 HWAVEIN      hWaveIn;
 WAVEHDR      WaveInHdr;
 MMRESULT result;

 // Specify recording parameters
 WAVEFORMATEX pFormat;
 pFormat.wFormatTag=WAVE_FORMAT_PCM;     // simple, uncompressed format
 pFormat.nChannels=1;                    //  1=mono, 2=stereo
 pFormat.nSamplesPerSec=sampleRate;      // 44100
 pFormat.nAvgBytesPerSec=sampleRate*2;   // = nSamplesPerSec * n.Channels * wBitsPerSample/8
 pFormat.nBlockAlign=2;                  // = n.Channels * wBitsPerSample/8
 pFormat.wBitsPerSample=16;              //  16 for high quality, 8 for telephone-grade
 pFormat.cbSize=0;

 result = waveInOpen(&hWaveIn, WAVE_MAPPER,&pFormat,
            0L, 0L, WAVE_FORMAT_DIRECT);
 if (result)
 {
  char fault[256];
  waveInGetErrorText(result, fault, 256);
  Application->MessageBox(fault, "Failed to open waveform input device.",
              MB_OK | MB_ICONEXCLAMATION);
  return;
 }

 // Set up and prepare header for input
 WaveInHdr.lpData = (LPSTR)waveIn;
 WaveInHdr.dwBufferLength = NUMPTS*2;
 WaveInHdr.dwBytesRecorded=0;
 WaveInHdr.dwUser = 0L;
 WaveInHdr.dwFlags = 0L;
 WaveInHdr.dwLoops = 0L;
 waveInPrepareHeader(hWaveIn, &WaveInHdr, sizeof(WAVEHDR));

 // Insert a wave input buffer
 result = waveInAddBuffer(hWaveIn, &WaveInHdr, sizeof(WAVEHDR));
 if (result)
 {
  MessageBox(Application->Handle, "Failed to read block from device",
                   NULL, MB_OK | MB_ICONEXCLAMATION);
  return;
 }


 // Commence sampling input
 result = waveInStart(hWaveIn);
 if (result)
 {
  MessageBox(Application->Handle, "Failed to start recording",
                   NULL, MB_OK | MB_ICONEXCLAMATION);
  return;
 }


 // Wait until finished recording
 do {} while (waveInUnprepareHeader(hWaveIn, &WaveInHdr, sizeof(WAVEHDR))==WAVERR_STILLPLAYING);

 waveInClose(hWaveIn);
What dll file does it say you are missing? There has to be an instance of the dll file either in the systems search path or the working directory that you are running your binary from (this isn't always the same as the directory that the binary is in).

Your first step is to pick a library and go with it, you won't be doing your self any favors by jumping back and forth between them. Another option for you to consider is SFML: http://www.sfml-dev.org/index.php . Pick one of those three and we can go from there.
WaveInHdr.lpData = (LPSTR)waveIn;

This is wrong. lpData must point to a buffer that you create. This is where the audio data will be written to once it is recorded.

On top of this being a bad cast, even if it compiles you are giving a pointer to your waveIn structure (sort of), which is bad because this means recorded data will overwrite your waveIn handle.



I was very rusty on all this stuff so I had to do a quick example program to make sure I still understood how to do it. Here's the program I made... you can use it for reference if you like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

#pragma comment(lib,"winmm.lib")

#include <Windows.h>
#include <mmsystem.h>
#include <fstream>
#include <iostream>

int main()
{
    // Fill the WAVEFORMATEX struct to indicate the format of our recorded audio
    //   For this example we'll use "CD quality", ie:  44100 Hz, stereo, 16-bit
    WAVEFORMATEX wfx = {};
    wfx.wFormatTag = WAVE_FORMAT_PCM;       // PCM is standard
    wfx.nChannels = 2;                      // 2 channels = stereo sound
    wfx.nSamplesPerSec = 44100;             // Samplerate.  44100 Hz
    wfx.wBitsPerSample = 16;                // 16 bit samples
    // These others are computations:
    wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8;
    wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;


    // Open our 'waveIn' recording device
    HWAVEIN wi;
    waveInOpen( &wi,            // fill our 'wi' handle
                WAVE_MAPPER,    // use default device (easiest)
                &wfx,           // tell it our format
                NULL,NULL,      // we don't need a callback for this example
                CALLBACK_NULL | WAVE_FORMAT_DIRECT   // tell it we do not need a callback
              );

    // At this point, we have our device, now we need to give it buffers (with headers) that it can
    //  put the recorded audio somewhere
    char buffers[2][44100 * 2 * 2 / 2];    // 2 buffers, each half of a second long
    WAVEHDR headers[2] = {{},{}};           // initialize them to zeros
    for(int i = 0; i < 2; ++i)
    {
        headers[i].lpData =         buffers[i];             // give it a pointer to our buffer
        headers[i].dwBufferLength = 44100 * 2 * 2 / 2;      // tell it the size of that buffer in bytes
        // the other parts of the header we don't really care about for this example, and can be left at zero

        // Prepare each header
        waveInPrepareHeader( wi, &headers[i], sizeof(headers[i]) );

        // And add it to the queue
        //  Once we start recording, queued buffers will get filled with audio data
        waveInAddBuffer( wi, &headers[i], sizeof(headers[i]) );
    }

    // In this example, I'm just going to dump the audio data to a binary file
    std::ofstream outfile("my_recorded_audio.bin", std::ios_base::out | std::ios_base::binary );

    // Print some simple directions to the user
    std::cout << "Now recording audio.  Press Escape to stop and exit." << std::endl;

    // start recording!
    waveInStart( wi );

    // Now that we are recording, keep polling our buffers to see if they have been filled.
    //   If they have been, dump their contents to the file and re-add them to the queue so they
    //   can get filled again, and again, and again
    while( !(GetAsyncKeyState(VK_ESCAPE) & 0x8000) )  // keep looping until the user hits escape
    {
        for(auto& h : headers)      // check each header
        {
            if(h.dwFlags & WHDR_DONE)           // is this header done?
            {
                // if yes, dump it to our file
                outfile.write( h.lpData, h.dwBufferLength );

                // then re-add it to the queue
                h.dwFlags = 0;          // clear the 'done' flag
                h.dwBytesRecorded = 0;  // tell it no bytes have been recorded

                // re-add it  (I don't know why you need to prepare it again though...)
                waveInPrepareHeader( wi, &h, sizeof(h) );
                waveInAddBuffer( wi, &h, sizeof(h) );
            }
        }
    }

    // Once the user hits escape, stop recording, and clean up
    waveInStop( wi );
    for(auto& h : headers)
    {
        waveInUnprepareHeader( wi, &h, sizeof(h) );
    }
    waveInClose( wi );

    // All done!
}
Topic archived. No new replies allowed.