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

#define LENGTH 30
const int DATASIZE = 22050 * 2 * LENGTH; //SamplesPerSec * byte per sample * duration time
char soundBuffer[DATASIZE];

void get_audio(WAVEFORMATEX audio_format, WAVEHDR audio_header);
void save_file(WAVEFORMATEX audio_format, WAVEHDR audio_header);

int main()
{
	WAVEFORMATEX audio_format;  //structure of wave format      
	audio_format.wFormatTag = WAVE_FORMAT_PCM;
	audio_format.nChannels = 1;
	audio_format.nSamplesPerSec = 22050;
	audio_format.wBitsPerSample = 16;
	audio_format.cbSize = 0;
	audio_format.nBlockAlign = (audio_format.nChannels * audio_format.wBitsPerSample) / 8;
	audio_format.nAvgBytesPerSec = (audio_format.nSamplesPerSec*audio_format.nBlockAlign);

	WAVEHDR audio_header;
	audio_header.dwFlags = 0;
	audio_header.dwUser = 0;
	audio_header.dwLoops = 0;
	audio_header.dwBytesRecorded = 0;
	audio_header.lpData = (LPSTR)soundBuffer;
	audio_header.dwBufferLength = DATASIZE;

	get_audio(audio_format, audio_header);
	save_file(audio_format, audio_header);
	

	return 0;
}

void get_audio(WAVEFORMATEX audio_format, WAVEHDR audio_header)
{
	HWAVEIN audio_in;
	int log;
	log = waveInOpen(&audio_in, WAVE_MAPPER, &audio_format, NULL, NULL, NULL);
	//open input device

	if (log == MMSYSERR_NOERROR)
		printf("waveInOpen success\n");
	else
		printf("waveInOpen fail\n");

	//prepare buffer header
	log = waveInPrepareHeader(audio_in, &audio_header, sizeof(WAVEHDR));

	if (log == MMSYSERR_NOERROR)
		printf("waveInPrepareHeader success\n");
	else
		printf("waveInPrepareHeader fail\n");
	//send buffer to input device
	log = waveInAddBuffer(audio_in, &audio_header, sizeof(WAVEHDR));

	if (log == MMSYSERR_NOERROR)
		printf("waveInAddBuffer success\n");
	else
		printf("waveInAddBuffer fail\n");

	printf("Press Enter to start recording\n");
	getchar();
	if (!waveInStart(audio_in))	//start recording										
		printf("recording start ...\n");
	else
		printf("recording fail...\n");
	Sleep(LENGTH * 1000);

	if (!waveInStop(audio_in))	//stop recording										
		printf("recording stop\n");
	else
		printf("recording stop fail\n");

	//clean buffer header
	if (waveInUnprepareHeader(audio_in, &audio_header, sizeof(WAVEHDR)))
		printf("UnPrepare Header fail\n");
	else
		printf("UnPrepare Header success\n");



	if (waveInClose(audio_in) == MMSYSERR_NOERROR)
		printf("waveInClose success\n");
	else
		printf("waveInClose fail\n");
}

void save_file(WAVEFORMATEX audio_format, WAVEHDR audio_header)
{
	//saving as wave file
	MMCKINFO wav_file_header1;
	MMCKINFO wav_file_header2;
	HMMIO wav_file;
	MMRESULT result;
	long wav_log;

	//create wav file
	wav_file = mmioOpen("wavfile.wav", NULL, MMIO_CREATE | MMIO_WRITE | MMIO_EXCLUSIVE | MMIO_ALLOCBUF);
	if (wav_file == NULL)
		printf("mmioOpen fail\n");

	ZeroMemory(&wav_file_header1, sizeof(MMCKINFO));
	wav_file_header1.fccType = mmioFOURCC('W', 'A', 'V', 'E');

	result = mmioCreateChunk(wav_file, &wav_file_header1, MMIO_CREATERIFF);  //create RIFF chunk 
	if (result == MMSYSERR_NOERROR)
		printf("mmioCreateChunk: wav_file_header1 %s ok\n", result);
	else
		printf("mmioCreateChunk: wav_file_header1 fail\n");


	ZeroMemory(&wav_file_header2, sizeof(MMCKINFO));
	wav_file_header2.ckid = mmioFOURCC('f', 'm', 't', ' ');
	wav_file_header2.cksize = sizeof(WAVEFORMATEX) + audio_format.cbSize;

	//create fmt chunk
	result = mmioCreateChunk(wav_file, &wav_file_header2, 0);
	if (result == MMSYSERR_NOERROR)
		printf("mmioCreateChunk wav_file_header2  %s ok\n", result);
	else
		printf("mmioCreateChunk wav_file_header2 fail\n");

	//輸入fmt chunk的data
	wav_log = mmioWrite(wav_file, (char*)&audio_format, sizeof(WAVEFORMATEX) + audio_format.cbSize);
	if (wav_log == -1)
		printf("mmioWrite audio_format fail\n");
	else
		printf("mmioWrite write %d bytes\n", wav_log);

	//跳出fmt chunk
	result = mmioAscend(wav_file, &wav_file_header2, 0);
	if (result == MMSYSERR_NOERROR)
		printf("mmioAscend wav_file_header2 %s ok\n", result);
	else
		printf("mmioAscend wav_file_header2 %s fail\n", result);

	wav_file_header2.ckid = mmioFOURCC('d', 'a', 't', 'a');

	//create data Chunk
	result = mmioCreateChunk(wav_file, &wav_file_header2, 0);
	if (result == MMSYSERR_NOERROR)
		printf("mmioCreateChunk wav_file_header2 %s ok\n", result);
	else
		printf("mmioCreateChunk wav_file_header2 %s fail\n", result);
	printf("audio_header %d BytesRecorded\n", audio_header.dwBytesRecorded);

	//輸入audio data 
	wav_log = mmioWrite(wav_file, (char*)audio_header.lpData, DATASIZE);

	if (wav_log == -1)
		printf("mmioWrite audio data fail\n");
	else
		printf("mmioWrite success : write %d bytes\n", wav_log);
	//跳出data chunk 
	result = mmioAscend(wav_file, &wav_file_header2, 0);
	if (result == MMSYSERR_NOERROR)
		printf("mmioAscend wav_file_header2 %s ok\n", result);
	else
		printf("mmioAscend wav_file_header2 %s fail\n", result);

	//跳出RIFF chunk
	result = mmioAscend(wav_file, &wav_file_header1, 0);
	if (result == MMSYSERR_NOERROR)
		printf("mmioAscend wav_file_header1 %s ok\n", result);
	else
		printf("mmioAscend wav_file_header1 %s fail\n", result);

	result = mmioClose(wav_file, 0);	//close the wav file 
	if (result == MMIOERR_CANNOTWRITE){
		printf("mmioClose fail\n");
	}
}
