// Audio.cpp : Defines the initialization routines for the DLL. // #include "stdafx.h" #include "Audio.h" #include "Winbase.h" #include "mmsystem.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // //TODO: If this DLL is dynamically linked against the MFC DLLs, // any functions exported from this DLL which call into // MFC must have the AFX_MANAGE_STATE macro added at the // very beginning of the function. // // For example: // // extern "C" BOOL PASCAL EXPORT ExportedFunction() // { // AFX_MANAGE_STATE(AfxGetStaticModuleState()); // // normal function body here // } // // It is very important that this macro appear in each // function, prior to any calls into MFC. This means that // it must appear as the first statement within the // function, even before any object variable declarations // as their constructors may generate calls into the MFC // DLL. // // Please see MFC Technical Notes 33 and 58 for additional // details. // // CAudioApp BEGIN_MESSAGE_MAP(CAudioApp, CWinApp) END_MESSAGE_MAP() // CAudioApp construction CAudioApp::CAudioApp() { // TODO: add construction code here, // Place all significant initialization in InitInstance } // The one and only CAudioApp object CAudioApp theApp; // CAudioApp initialization BOOL CAudioApp::InitInstance() { CWinApp::InitInstance(); return TRUE; } AUDIO_API BOOL RecordInit(int channel,int SamplesPerSec,int BitsPerSample,int second){ //set WAVEFORMATEX waveTex.wFormatTag = WAVE_FORMAT_PCM; waveTex.nChannels= (WORD) channel; waveTex.nSamplesPerSec= (DWORD) SamplesPerSec; waveTex.wBitsPerSample = (WORD) BitsPerSample; waveTex.nBlockAlign= (1 * waveTex.wBitsPerSample) / 8; waveTex.nAvgBytesPerSec= waveTex.nBlockAlign * waveTex.nSamplesPerSec; waveTex.cbSize=sizeof(WAVEFORMATEX); //Create voice buffer int bufferSize = second * (waveTex.nAvgBytesPerSec); bufferSize += bufferSize % waveTex.nBlockAlign; data = new BYTE [bufferSize]; if(data == NULL) return false; //set WAVE Header waveHDR.dwBufferLength = bufferSize; waveHDR.lpData = new char[bufferSize]; waveHDR.lpData = (char *) data; waveHDR.dwUser = (DWORD) FALSE; DWORD HDRSize = sizeof(WAVEHDR); int result = waveInOpen(&wave,WAVE_MAPPER,&waveTex,0, NULL, CALLBACK_NULL); //int result = waveInOpen(&wave,WAVE_MAPPER,&waveTex,(DWORD) BufferFill, NULL, CALLBACK_FUNCTION); if(result !=MMSYSERR_NOERROR){ return false; } //Prepare a buffer to input device result = waveInPrepareHeader(wave,&waveHDR,(UINT)HDRSize); if(result !=MMSYSERR_NOERROR){ return false; } result = waveInAddBuffer(wave,&waveHDR,sizeof(WAVEHDR)); if(result != MMSYSERR_NOERROR){ return false; } return true; } AUDIO_API BOOL StartRecord(){ //Start record voice int result = waveInStart(wave); if(result != MMSYSERR_NOERROR){ return false; } return true; } AUDIO_API BOOL EndRecord(LPTSTR file){ //Reset position to 0 and stop input device int result = waveInReset(wave); if(result != MMSYSERR_NOERROR){ printf("waveInReset error\n"); return false; } //Clear Wave header result = waveInUnprepareHeader(wave,&waveHDR,sizeof(WAVEHDR)); if(result != MMSYSERR_NOERROR){ printf("waveInUnprepareHeader error\n"); return false; } //Close input device result = waveInClose(wave); if(result != MMSYSERR_NOERROR){ printf("waveInUnprepareHeader error\n"); return false; } RIFF_FILEHEADER FileHeader; RIFF_CHUNKHEADER WaveHeader; RIFF_CHUNKHEADER DataHeader; DWORD WriteLength; WaveHeader.dwCKID = RIFF_FORMAT; WaveHeader.dwSize = sizeof(WAVEFORMATEX) + waveTex.cbSize; DataHeader.dwCKID = RIFF_CHANNEL; DataHeader.dwSize = waveHDR.dwBytesRecorded; FileHeader.dwRiff = RIFF_FILE; FileHeader.dwWave = RIFF_WAVE; FileHeader.dwSize = sizeof(FileHeader.dwWave)+sizeof(WaveHeader) + WaveHeader.dwSize + sizeof(DataHeader) + DataHeader.dwSize; //Create .wav file writeData = CreateFile(file,GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); if(writeData == INVALID_HANDLE_VALUE){ wprintf(L"CreateFile %s error, error code %d\n",file,GetLastError()); return false; } //write File header if (! WriteFile(writeData, &FileHeader, sizeof(FileHeader), &WriteLength, NULL)) { CloseHandle(writeData); printf("WriteFile error\n"); return false; } //write Wave header if (! WriteFile(writeData, &WaveHeader, sizeof(WaveHeader), &WriteLength, NULL)) { CloseHandle(writeData); printf("Write Wave Header error\n"); return false; } //write Wave header data if (! WriteFile(writeData, &waveTex, WaveHeader.dwSize, &WriteLength, NULL)) { CloseHandle(writeData); printf("Write Wave header data error\n"); return false; } //Write Data Header if (! WriteFile(writeData, &DataHeader, sizeof(DataHeader), &WriteLength, NULL)) { CloseHandle(writeData); printf("Write Data Header error\n"); return false; } //Write record data if (! WriteFile(writeData, data, DataHeader.dwSize, &WriteLength, NULL)) { CloseHandle(writeData); printf("Write record data error\n"); return false; } CloseHandle(writeData); return true; } BOOL ReadChunk(HANDLE hFile,DWORD Type,PVOID * InBuffer, DWORD * chksize,PDWORD ChunkLength){ DWORD ReadByte; PVOID Buffer; RIFF_CHUNKHEADER Chunk; if ((!ChunkLength) || (*ChunkLength <= 0) || (!chksize) || (!InBuffer)) { printf("Invalid parameter to ReadChunk()\r\n"); return FALSE; } while(*ChunkLength > 0){ if (! ReadFile(hFile, &Chunk, sizeof(Chunk), &ReadByte, NULL) || ReadByte < sizeof(Chunk)) { printf("Error reading chunk header\n"); return FALSE; } *ChunkLength -= ReadByte; if (Chunk.dwCKID == Type) { // found the desired chunk break; } if (0xFFFFFFFF == SetFilePointer (hFile, Chunk.dwSize, NULL, FILE_CURRENT)) { printf("Error setting file pointer while scanning for chunk\n"); return FALSE; } *ChunkLength -= Chunk.dwSize; } Buffer = new BYTE[Chunk.dwSize]; if (Buffer == NULL) { printf("Unable to allocate chunk buffer\r\n"); return 0; } if (! ReadFile(hFile, Buffer, Chunk.dwSize, &ReadByte, NULL) || ReadByte < Chunk.dwSize) { delete [] Buffer; printf("Unable to read chunk data\r\n"); return FALSE; } *ChunkLength -= ReadByte; *InBuffer = Buffer; *chksize = Chunk.dwSize; return TRUE; } AUDIO_API DWORD PlayAudio(LPTSTR file){ HANDLE PlayEvent; HANDLE hFile; RIFF_FILEHEADER FileHeader; DWORD BufferSize; DWORD ReadLength; DWORD ChunkByte; DWORD FormatLength; DWORD BufferLength; PWAVEFORMATEX WaveTex = NULL; PBYTE ReadBuffer = NULL; DWORD AudioLength; ZeroMemory(&WaveTex,0,sizeof(WAVEFORMATEX)); //printf("in play audio\n"); PlayEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if(PlayEvent == NULL){ printf("create play event error\n"); return -1; } //printf("open audio\n"); hFile = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if( hFile == INVALID_HANDLE_VALUE ) { printf("open file error\n"); return -1; } //read header //printf("read audio header\n"); if (! ReadFile(hFile, &FileHeader, sizeof(FileHeader), &ReadLength, NULL) || ReadLength < sizeof(FileHeader)) { printf("open file error\n"); return -1; } //printf("check audio header\n"); if ( FileHeader.dwRiff != RIFF_FILE || FileHeader.dwWave != RIFF_WAVE) { printf("wave file header error\n"); return -1; } ChunkByte = FileHeader.dwSize; // load the wave format //printf("load audio format\n"); if (! ReadChunk(hFile, RIFF_FORMAT, (PVOID*) &WaveTex, &FormatLength, &ChunkByte)) { printf("Unable to read format chunk\r\n"); return -1; } //printf("check audio format size\n"); if (FormatLength < sizeof(PCMWAVEFORMAT)) { //printf("Format record too small\r\n"); return -1; } //printf("read chunk\n"); if (! ReadChunk(hFile, RIFF_CHANNEL, (PVOID*) &ReadBuffer, &BufferLength, &ChunkByte)) { //printf("Unable to read format chunk\r\n"); return -1; } BufferSize = BufferLength; AudioLength = (DWORD)(((UINT64)BufferSize) * 1000 / WaveTex->nAvgBytesPerSec); //printf("audio length: %d ms buffer size: %d\n",AudioLength,BufferSize); //HWAVEOUT AudioOut; //LPHWAVEOUT AudioOut; //WAVEHDR OutHdr={0}; //WAVEHDR OutHdr; DWORD result; ZeroMemory(&AudioOut,0,sizeof(HWAVEOUT)); ZeroMemory(&wavePlay,0,sizeof(WAVEHDR)); result = waveOutOpen(&AudioOut, WAVE_MAPPER, WaveTex, 0, NULL, CALLBACK_NULL); if(result !=0){ //printf("waveOutOpen error , error code: %d\n",result); return -1; } wavePlay.dwBufferLength = BufferSize; wavePlay.lpData = new char[BufferSize]; wavePlay.lpData = (char *) ReadBuffer; wavePlay.dwUser = (DWORD) FALSE; DWORD HDRSize = sizeof(WAVEHDR); //printf("waveOutPrepareHeader set\n"); //result = waveOutPrepareHeader(AudioOut,&wavePlay,(UINT)HDRSize); result = waveOutPrepareHeader(AudioOut,&wavePlay,sizeof(wavePlay)); if(result !=MMSYSERR_NOERROR){ printf("waveOutPrepareHeader error,error code: %d\n",result); waveOutClose(AudioOut); delete [] wavePlay.lpData; return -1; } //printf("waveOutWrite set\n"); result = waveOutWrite(AudioOut,&wavePlay,sizeof(wavePlay)); if(result !=MMSYSERR_NOERROR){ printf("waveOutWriteerror,error code: %d\n",result); waveOutUnprepareHeader(AudioOut,&wavePlay,sizeof(WAVEHDR)); waveOutClose(AudioOut); delete [] wavePlay.lpData; return -1; } /*result = WaitForSingleObject(PlayEvent,AudioLength+100); if(result != WAIT_OBJECT_0){ printf("play end\n"); }*/ //waveOutUnprepareHeader(AudioOut,&OutHdr,sizeof(OutHdr)); //printf("read length:%d\n",AudioLength); return AudioLength; } AUDIO_API BOOL EndPlay(){ int result = waveOutReset(AudioOut); if(result != MMSYSERR_NOERROR){ return false; } result = waveOutUnprepareHeader(AudioOut,&wavePlay,sizeof(wavePlay)); if(result != MMSYSERR_NOERROR){ return false; } result = waveOutClose(AudioOut); if(result != MMSYSERR_NOERROR){ return false; } return true; } //unfinished function AUDIO_PRIVATE_API void BufferFill(WPARAM Wparm , LPARAM Lparm){ DWORD message = (DWORD) Lparm; WAVEHDR * hdr = (PWAVEHDR) Wparm; if(hdr ==NULL) printf("hdr is null\n"); if(message == MM_WIM_DATA){ printf("buffer fill and hdr\n"); } return ; } AUDIO_PRIVATE_API void CallBuffer(HWAVEIN hWaveIn,UINT uMsg,DWORD dwInstance, DWORD dwParam1,DWORD dwParam2){ if(uMsg == MM_WIM_DATA){ printf("buffer fill\n"); } return ; } //