codice:
/*
*
* main.cpp (v0.2) (Author: THEARTOFWEB Software - theartofweb@hotmail.com)
*
* Capture and record audio from an input device by using the Win32 waveForm API
*
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#pragma comment (lib, "winmm.lib")
#include <mmsystem.h>
#include <process.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <stdlib.h>
using namespace std;
unsigned __stdcall startRecorder (void* lpParam);
unsigned __stdcall stopRecorder (void*);
bool createWAVEFile(const char*);
bool saveWAVEChunk(const char*, const DWORD);
bool closeWAVEFile(void);
DWORD dwBufferLength = 176400;
DWORD dwNumBuffers = 3;
DWORD uDevice = 0; // Built-in Microphone
const char* szFilePath = "C:\\Users\\giangaetano\\Desktop\\mmio\\waveCapture.WAVE";
bool volatile stopThreadFlag = false;
DWORD dwTotalBytesRecorded = 0;
std::ofstream hFile;
WAVEFORMATEX wf;
enum WAVECAPTURE_ERROR {
ERR_WAVEINOPEN = -1,
ERR_WAVEINSTART = -2,
ERR_WAVEINPREPAREHEADER = -3,
ERR_WAVEINADDBUFFER = -4,
ERR_NOERROR = 0,
ERR_ALREADYSTARTED = -5,
ERR_BUFFERALLOC = -6,
ERR_EVENTNULL = -10,
ERR_OPENFILE = -20,
ERR_SAVECHUNK = -21,
ERR_CLOSEFILE = -22
};
int main()
{
HANDLE hThread[2];
unsigned ThreadId[2];
// Start capturing Thread: thread[0]
hThread[0] = (HANDLE)_beginthreadex(NULL, 0, startRecorder, NULL, 0, &ThreadId[0]);
if (hThread[0] == 0)
{
cout << "thread[0] error" << endl;
return -1;
}
cout << "Started capturing...(press any key to stop)" << endl;
system("pause");
// Stop thread[0] by lanching thread[1]
hThread[1] = (HANDLE)_beginthreadex(NULL, 0, stopRecorder, NULL, 0, &ThreadId[1]);
if (hThread[1] == 0)
{
cout << "thread[1] error" << endl;
return -1;
}
WaitForMultipleObjects(2, hThread, true, INFINITE);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
cout << "Stopped capturing!" << endl;
cout << "Total Bytes Recorded: " << dwTotalBytesRecorded << endl;
system("pause");
return EXIT_SUCCESS;
}
unsigned __stdcall startRecorder (void* lpParam)
{
// Define WAVEFORMATEX
wf.wFormatTag = WAVE_FORMAT_PCM;
wf.wBitsPerSample = 16;
wf.nChannels = 2;
wf.nSamplesPerSec = 44100;
wf.nBlockAlign = (wf.nChannels * wf.wBitsPerSample) / 8;
wf.nAvgBytesPerSec = (wf.nSamplesPerSec * wf.nBlockAlign);
wf.cbSize = 0;
// Create event
HANDLE hevent = CreateEvent(NULL,FALSE,FALSE,NULL);
if(hevent == NULL)
return ERR_EVENTNULL;
// WaveInOpen
HWAVEIN hwi;
if(waveInOpen(&hwi,uDevice,(LPWAVEFORMATEX)&wf,(DWORD)hevent,0,CALLBACK_EVENT)
!= MMSYSERR_NOERROR)
return ERR_WAVEINOPEN;
// Define WAVEHDR Structure
std::vector<WAVEHDR> buff(dwNumBuffers);
std::vector<char> pool(dwNumBuffers * dwBufferLength);
for (int i = 0; i<(int)dwNumBuffers; i++)
{
ZeroMemory(&buff[i],sizeof(WAVEHDR));
buff[i].lpData = &pool[i * dwBufferLength];
buff[i].dwBufferLength = dwBufferLength;
buff[i].dwBytesRecorded = 0;
buff[i].dwUser = 0;
buff[i].dwFlags = 0;
buff[i].dwLoops = 0;
if(waveInPrepareHeader(hwi, &buff[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
return ERR_WAVEINPREPAREHEADER;
if(waveInAddBuffer(hwi, &buff[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
return ERR_WAVEINADDBUFFER;
}
// Start capturing...
if(waveInStart(hwi) != MMSYSERR_NOERROR)
return ERR_WAVEINSTART;
// Alloc "local" buffer
std::vector<char> pWAVBuffer(dwBufferLength);
// Create WAVE file
if(!createWAVEFile(szFilePath))
return ERR_OPENFILE;
// Loop: capturing...
int k = 0;
while(1)
{
if(stopThreadFlag)
break;
// CALLBACK EVENT
WaitForSingleObject(hevent, INFINITE);
if(buff[k].dwFlags & WHDR_DONE)
{
memcpy(&pWAVBuffer[0], buff[k].lpData, buff[k].dwBytesRecorded);
cout << buff[k].dwBytesRecorded << endl;
dwTotalBytesRecorded += buff[k].dwBytesRecorded;
if(!saveWAVEChunk(&pWAVBuffer[0], buff[k].dwBytesRecorded))
return ERR_SAVECHUNK;
if(waveInAddBuffer(hwi, &buff[k], sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
return ERR_WAVEINADDBUFFER;
}
if(k == dwNumBuffers-1)
k=0;
else
k++;
}
// Close WAVE file
if(!closeWAVEFile())
return ERR_CLOSEFILE;
// Unprepare header
MMRESULT h;
for (int u = 0; u<(int)dwNumBuffers; u++)
{
do {
h = waveInUnprepareHeader(hwi, &buff[u], sizeof(WAVEHDR));
} while (h != MMSYSERR_NOERROR);
}
waveInClose(hwi);
CloseHandle(hevent);
return ERR_NOERROR;
}
unsigned __stdcall stopRecorder (void*)
{
stopThreadFlag = true;
return 0;
}
bool createWAVEFile(const char*)
{
char nullbuff[44];
ZeroMemory(&nullbuff, sizeof(nullbuff));
hFile.open( szFilePath, std::ios::out|std::ios::binary );
if(hFile.bad())
return false;
hFile.write(nullbuff, 44);
return true;
}
bool saveWAVEChunk(const char* pWAVBuffer, const DWORD bufflen)
{
hFile.write(pWAVBuffer, bufflen);
if(hFile.bad())
return false;
return true;
}
bool closeWAVEFile(void)
{
// close file and re-open it to add the header at the beginning:
hFile.close();
MMCKINFO mmckinfo;
MMCKINFO mmckinfoSubchunk;
MMCKINFO mmckinfoData;
memset(&mmckinfo, 0, sizeof(mmckinfo));
memset(&mmckinfoSubchunk, 0, sizeof(mmckinfoSubchunk));
memset(&mmckinfoData, 0, sizeof(mmckinfoData));
// Open the WAVE file using mmio (no create!)
// creating a file using mmio
HMMIO hfile;
hfile = mmioOpen((LPSTR)szFilePath, NULL, MMIO_WRITE);
mmioSeek(hfile, 0, SEEK_SET);
//step 1 create riff chunk
mmckinfo.fccType = mmioFOURCC('W','A','V','E');
mmckinfo.cksize = (36 + dwTotalBytesRecorded);
mmioCreateChunk(hfile, &mmckinfo, MMIO_CREATERIFF);
//step 2 create fmt chunk
//creating fmt chunk also includes writing formatex to this chunk
mmckinfoSubchunk.ckid = mmioFOURCC('f','m','t',' ');
mmckinfoSubchunk.cksize = sizeof(WAVEFORMATEX);
mmioCreateChunk(hfile, &mmckinfoSubchunk, 0);
mmioWrite(hfile, (char*)&wf, sizeof(wf));
mmioAscend(hfile, &mmckinfoSubchunk, 0);
//step 3 creating data chunk
//creating this chunk includes writing actual voice data
mmckinfoData.ckid=mmioFOURCC('d','a','t','a');
mmckinfoData.cksize = dwTotalBytesRecorded;
mmioCreateChunk(hfile, &mmckinfoData, 0);
mmioClose( MMIO_READ, MMIO_FHOPEN );
return true;
}
grazie