405 lines
12 KiB
C++
405 lines
12 KiB
C++
#include <process.h>
|
|
#include "SCENE.h"
|
|
#include "MicroIn.h"
|
|
|
|
//#pragma optimize("",off)
|
|
|
|
#define WAVE_BUFFER_SECOND 5
|
|
#define WAVE_BUFFER_SIZE (WAVE_BUFFER_SECOND*192000) // 1 second of 48khz 32bit audio
|
|
#define WAVE_BASE_SIZE (SND_NB_CHANNELS*320*5) // channels * 1/60 second of 48khz 32bit audio
|
|
|
|
//* Callbacks ***************************************************************
|
|
void CALLBACK waveInProc( HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
|
|
{
|
|
MicroIn *data = (MicroIn *)dwInstance;
|
|
if ( uMsg != WIM_DATA || !data) return;
|
|
|
|
for ( u32 hdrIdx = 0; hdrIdx< NB_WHDR; hdrIdx++)
|
|
{
|
|
u32 uCurrentWHDR = (data->waveHDRIndex + hdrIdx) % NB_WHDR;
|
|
if ( data->waveHDR[uCurrentWHDR ].dwFlags & WHDR_DONE )
|
|
{
|
|
if (data->lTimeState)
|
|
{
|
|
int copySize = min(data->waveHDR[uCurrentWHDR ].dwBytesRecorded, WAVE_BUFFER_SIZE);
|
|
if (data->waveEnd + copySize > WAVE_BUFFER_SIZE)
|
|
{
|
|
int copySize1 = WAVE_BUFFER_SIZE - data->waveEnd;
|
|
memcpy(data->pWaveBuffer + data->waveEnd, data->waveHDR[uCurrentWHDR ].lpData, copySize1);
|
|
memcpy(data->pWaveBuffer, data->waveHDR[uCurrentWHDR ].lpData + copySize1, copySize - copySize1);
|
|
data->waveEnd = copySize - copySize1;
|
|
} else
|
|
{
|
|
memcpy(data->pWaveBuffer + data->waveEnd, data->waveHDR[uCurrentWHDR ].lpData, copySize);
|
|
data->waveEnd += copySize;
|
|
}
|
|
for (int i=0; i<NB_HEADS; i++)
|
|
{
|
|
if (!data->waveActiv[i]) continue;
|
|
data->waveSize[i] += copySize;
|
|
if (data->waveSize[i] > WAVE_BUFFER_SIZE)
|
|
{
|
|
data->waveBegin[i] = data->waveEnd + 1;
|
|
if (data->waveBegin[i] >= WAVE_BUFFER_SIZE)
|
|
data->waveBegin[i] = 0;
|
|
data->waveSize[i] = WAVE_BUFFER_SIZE;
|
|
}
|
|
}
|
|
}
|
|
// -> waveInAddBuffer IS NOT ALLOWED IN CALLBACK HAHAHA
|
|
waveInUnprepareHeader( hwi, &data->waveHDR[uCurrentWHDR ], sizeof(WAVEHDR));
|
|
data->waveHDR[uCurrentWHDR ].dwFlags = 0;
|
|
waveInPrepareHeader( hwi, &data->waveHDR[uCurrentWHDR ], sizeof(WAVEHDR));
|
|
waveInAddBuffer( hwi, &data->waveHDR[uCurrentWHDR ], sizeof(WAVEHDR));
|
|
}
|
|
}
|
|
}
|
|
|
|
u32 WINAPI waveInThread( LPVOID arg)
|
|
{
|
|
MSG msg;
|
|
MicroIn *data = (MicroIn *)arg;
|
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
if (msg.message == WIM_CLOSE)
|
|
break;
|
|
waveInProc( (HWAVEIN)msg.wParam,msg.message, (DWORD)arg, 0, 0 );
|
|
}
|
|
|
|
waveInReset(data->waveIn);
|
|
waveInClose(data->waveIn);
|
|
|
|
CC_free(data->pWaveBuffer);
|
|
for (int uCurrentWHDR=0; uCurrentWHDR<NB_WHDR; uCurrentWHDR++)
|
|
CC_free(data->waveHDR[uCurrentWHDR].lpData);
|
|
|
|
memset(data, 0, sizeof(MicroIn));
|
|
return 0;
|
|
}
|
|
|
|
|
|
int MicroInInit(MicroIn *data, int force)
|
|
{
|
|
MMRESULT result;
|
|
|
|
if (!data) return 0;
|
|
if (data->initOK && !force) return 1;
|
|
|
|
memset(data, 0, sizeof(MicroIn));
|
|
WAVEFORMATEX waveFormat;
|
|
memset(&waveFormat, 0, sizeof(waveFormat));
|
|
|
|
waveFormat.nSamplesPerSec = SND_SAMPLES;
|
|
waveFormat.wBitsPerSample = SND_BITS;
|
|
waveFormat.nChannels = SND_NB_CHANNELS;
|
|
|
|
waveFormat.cbSize = 0; /* size of _extra_ info */
|
|
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
|
|
waveFormat.nBlockAlign = (waveFormat.wBitsPerSample >> 3) * waveFormat.nChannels;
|
|
waveFormat.nAvgBytesPerSec = waveFormat.nBlockAlign * waveFormat.nSamplesPerSec;
|
|
|
|
memset(data->waveHDR, 0, sizeof(data->waveHDR));
|
|
data->pWaveBuffer = (char *)CC_malloc(WAVE_BUFFER_SIZE);
|
|
data->waveHDRSize = WAVE_BASE_SIZE;
|
|
for (int uCurrentWHDR=0; uCurrentWHDR<NB_WHDR; uCurrentWHDR++)
|
|
{
|
|
data->waveHDR[uCurrentWHDR].lpData = (char *)CC_malloc(data->waveHDRSize);
|
|
data->waveHDR[uCurrentWHDR].dwBufferLength = data->waveHDRSize;
|
|
}
|
|
|
|
//result = waveInOpen(&data->waveIn, WAVE_MAPPER, &waveFormat, (DWORD_PTR)waveInProc, (DWORD_PTR)data, CALLBACK_FUNCTION);
|
|
//for (int c=0; c<waveInGetNumDevs() && result != MMSYSERR_NOERROR; c++)
|
|
// result = waveInOpen(&data->waveIn, c, &waveFormat, (DWORD_PTR)waveInProc, (DWORD_PTR)data, CALLBACK_FUNCTION);
|
|
//
|
|
|
|
// Using thread because callback function is a joke
|
|
_beginthreadex( NULL , 10*1024 , waveInThread , data , 0 , &data->threadID );
|
|
result = waveInOpen(&data->waveIn, WAVE_MAPPER, &waveFormat, (DWORD_PTR)data->threadID, (DWORD_PTR)data, CALLBACK_THREAD);
|
|
for (int c=0; c<waveInGetNumDevs() && result != MMSYSERR_NOERROR; c++)
|
|
result = waveInOpen(&data->waveIn, c, &waveFormat, (DWORD_PTR)data->threadID, (DWORD_PTR)data, CALLBACK_THREAD);
|
|
|
|
if (result != MMSYSERR_NOERROR)
|
|
return 0;
|
|
|
|
for (int uCurrentWHDR=0; uCurrentWHDR<NB_WHDR; uCurrentWHDR++)
|
|
{
|
|
waveInPrepareHeader( data->waveIn, data->waveHDR + uCurrentWHDR,sizeof(WAVEHDR) );
|
|
waveInAddBuffer (data->waveIn, &data->waveHDR[uCurrentWHDR ], sizeof(WAVEHDR) );
|
|
}
|
|
result = waveInStart( data->waveIn );
|
|
if (result != MMSYSERR_NOERROR)
|
|
return 0;
|
|
|
|
data->lTimeState = 1; // playing by default
|
|
data->initOK = 1;
|
|
return 1;
|
|
}
|
|
|
|
void MicroInStop(MicroIn *data)
|
|
{
|
|
if (!data || data->initOK != 1) return;
|
|
|
|
PostThreadMessage(data->threadID, WIM_CLOSE, 0, 0);
|
|
}
|
|
|
|
int MicroInGetBufferedTime(MicroIn *data, int head)
|
|
{
|
|
if (!data || data->initOK != 1 ||
|
|
head >= NB_HEADS) return 0;
|
|
return 1000*data->waveSize[head]/(SND_NB_CHANNELS*SND_SAMPLES*(SND_BITS>>3));
|
|
}
|
|
|
|
|
|
int MicroInAddHead(MicroIn *data)
|
|
{
|
|
int head;
|
|
|
|
if (!MicroInInit(data)) return -1;
|
|
if (!data || data->initOK != 1) return -1;
|
|
for (head = 0; head < NB_HEADS && data->waveActiv[head]; head++);
|
|
if (head >= NB_HEADS) return -1;
|
|
|
|
data->waveActiv[head] = 1;
|
|
data->waveBegin[head] = data->waveEnd;
|
|
data->waveSize[head] = 0;
|
|
return head;
|
|
}
|
|
|
|
void MicroInDelHead(MicroIn *data, int head, int stopLast)
|
|
{
|
|
if (!data || data->initOK != 1 ||
|
|
head >= NB_HEADS) return;
|
|
data->waveActiv[head] = 0;
|
|
|
|
if (!stopLast) return;
|
|
for (int head=0; head<NB_HEADS; head++)
|
|
if (data->waveActiv[head])
|
|
return;
|
|
// no head
|
|
MicroInStop(data);
|
|
}
|
|
|
|
int MicroInFlush(MicroIn *data, int head, int timeInMilliseconds)
|
|
{
|
|
if (!data || data->initOK != 1 ||
|
|
head >= NB_HEADS) return 0;
|
|
if (timeInMilliseconds == 0)
|
|
{
|
|
data->waveBegin[head] = data->waveEnd;
|
|
data->waveSize[head] = 0;
|
|
return 1;
|
|
}
|
|
int bufferToRemove;
|
|
if (timeInMilliseconds > 0) // time to flush
|
|
{
|
|
bufferToRemove = timeInMilliseconds*(SND_NB_CHANNELS*SND_SAMPLES*(SND_BITS>>3))/1000;
|
|
} else
|
|
{
|
|
int bufferToKeep = -timeInMilliseconds*(SND_NB_CHANNELS*SND_SAMPLES*(SND_BITS>>3))/1000;
|
|
if (bufferToKeep > data->waveSize[head])
|
|
bufferToKeep = data->waveSize[head];
|
|
bufferToRemove = data->waveSize[head] - bufferToKeep;
|
|
}
|
|
|
|
bufferToRemove = (bufferToRemove/WAVE_BASE_SIZE + 1)*WAVE_BASE_SIZE;
|
|
|
|
if (bufferToRemove > data->waveSize[head])
|
|
bufferToRemove = data->waveSize[head];
|
|
|
|
data->waveBegin[head] += bufferToRemove;
|
|
if (data->waveBegin[head] >= WAVE_BUFFER_SIZE)
|
|
data->waveBegin[head] -= WAVE_BUFFER_SIZE;
|
|
data->waveSize[head] -= bufferToRemove;
|
|
return 1;
|
|
}
|
|
|
|
|
|
int MicroInPlay(MicroIn *data)
|
|
{
|
|
data->lTimeState = 1;
|
|
return data->lTimeState;
|
|
}
|
|
|
|
int MicroInPause(MicroIn *data)
|
|
{
|
|
data->lTimeState = 0;
|
|
return data->lTimeState;
|
|
}
|
|
|
|
int MicroInReadExactly(MicroIn *data, int head, char *buffer, int bufferSize)
|
|
{
|
|
if (!data || data->initOK != 1 ||
|
|
head >= NB_HEADS || !data->waveActiv[head] ||
|
|
data->waveSize[head] < bufferSize) return 0;
|
|
|
|
if (data->waveBegin[head] + bufferSize > WAVE_BUFFER_SIZE)
|
|
{
|
|
int copySize = WAVE_BUFFER_SIZE - data->waveBegin[head];
|
|
memcpy(buffer, data->pWaveBuffer + data->waveBegin[head], copySize);
|
|
memcpy(buffer + copySize, data->pWaveBuffer, bufferSize - copySize);
|
|
data->waveBegin[head] = bufferSize - copySize;
|
|
} else
|
|
{
|
|
memcpy(buffer, data->pWaveBuffer + data->waveBegin[head], bufferSize);
|
|
data->waveBegin[head] += bufferSize;
|
|
}
|
|
data->waveSize[head] -= bufferSize;
|
|
return bufferSize;
|
|
}
|
|
|
|
int MicroInReadMax(MicroIn *data, int head, char *buffer, int bufferSize)
|
|
{
|
|
if (!data || data->initOK != 1 ||
|
|
head >= NB_HEADS || !data->waveActiv[head]) return 0;
|
|
|
|
return MicroInReadExactly(data, head, buffer, min(bufferSize, data->waveSize[head]));
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CALLBACK waveOutProc( HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
|
|
{
|
|
MicroOut *data = (MicroOut *)dwInstance;
|
|
if ( uMsg != WOM_DONE || !data) return;
|
|
|
|
for ( u32 hdrIdx = 0; hdrIdx < NB_WHDR; hdrIdx++)
|
|
{
|
|
u32 uCurrentWHDR = (data->waveHDRIndex + hdrIdx) % NB_WHDR;
|
|
if ( data->waveHDR[uCurrentWHDR ].dwFlags & WHDR_DONE )
|
|
{
|
|
if (data->lTimeState)
|
|
{
|
|
int copySize = min(data->waveHDRSize, data->waveSize);
|
|
if (data->waveBegin + copySize > WAVE_BUFFER_SIZE)
|
|
{
|
|
int copySize1 = WAVE_BUFFER_SIZE - data->waveBegin;
|
|
memcpy(data->waveHDR[uCurrentWHDR ].lpData, data->pWaveBuffer + data->waveBegin, copySize1);
|
|
memcpy(data->waveHDR[uCurrentWHDR ].lpData + copySize1, data->pWaveBuffer, copySize - copySize1);
|
|
data->waveBegin = copySize - copySize1;
|
|
} else
|
|
{
|
|
memcpy(data->waveHDR[uCurrentWHDR ].lpData, data->pWaveBuffer + data->waveBegin, copySize);
|
|
data->waveBegin += copySize;
|
|
}
|
|
data->waveSize -= copySize;
|
|
if (copySize < data->waveHDRSize)
|
|
memset(data->waveHDR[uCurrentWHDR ].lpData + copySize, 0, data->waveHDRSize - copySize);
|
|
}
|
|
waveOutUnprepareHeader( hwo, &data->waveHDR[uCurrentWHDR ], sizeof(WAVEHDR));
|
|
data->waveHDR[uCurrentWHDR ].dwFlags = 0;
|
|
waveOutPrepareHeader( hwo, &data->waveHDR[uCurrentWHDR ], sizeof(WAVEHDR));
|
|
waveOutWrite( hwo, &data->waveHDR[uCurrentWHDR ], sizeof(WAVEHDR));
|
|
|
|
//data->waveHDRIndex = (uCurrentWHDR + 1) % NB_WHDR;
|
|
//return;
|
|
}
|
|
}
|
|
}
|
|
|
|
int MicroOutInit(MicroOut *data, int force)
|
|
{
|
|
if (!data) return 0;
|
|
if (data->initOK && !force) return 1;
|
|
|
|
memset(data, 0, sizeof(MicroOut));
|
|
WAVEFORMATEX waveFormat;
|
|
memset(&waveFormat, 0, sizeof(waveFormat));
|
|
|
|
waveFormat.nSamplesPerSec = SND_SAMPLES;
|
|
waveFormat.wBitsPerSample = SND_BITS;
|
|
waveFormat.nChannels = SND_NB_CHANNELS;
|
|
|
|
waveFormat.cbSize = 0; /* size of _extra_ info */
|
|
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
|
|
waveFormat.nBlockAlign = (waveFormat.wBitsPerSample >> 3) * waveFormat.nChannels;
|
|
waveFormat.nAvgBytesPerSec = waveFormat.nBlockAlign * waveFormat.nSamplesPerSec;
|
|
|
|
memset(data->waveHDR, 0, sizeof(data->waveHDR));
|
|
data->pWaveBuffer = (char *)CC_malloc(WAVE_BUFFER_SIZE);
|
|
data->waveHDRSize = WAVE_BASE_SIZE;
|
|
for (int uCurrentWHDR=0; uCurrentWHDR<NB_WHDR; uCurrentWHDR++)
|
|
{
|
|
data->waveHDR[uCurrentWHDR].lpData = (char *)CC_malloc(data->waveHDRSize);
|
|
data->waveHDR[uCurrentWHDR].dwBufferLength = data->waveHDRSize;
|
|
}
|
|
|
|
MMRESULT result = waveOutOpen(&data->waveOut, WAVE_MAPPER, &waveFormat, (DWORD_PTR)waveOutProc, (DWORD_PTR)data, CALLBACK_FUNCTION);
|
|
for (int uCurrentWHDR=0; uCurrentWHDR<NB_WHDR; uCurrentWHDR++)
|
|
{
|
|
waveOutPrepareHeader( data->waveOut, data->waveHDR + uCurrentWHDR,sizeof(WAVEHDR) );
|
|
waveOutWrite (data->waveOut, &data->waveHDR[uCurrentWHDR ], sizeof(WAVEHDR) );
|
|
}
|
|
data->lTimeState = 1; // playing by default
|
|
data->initOK = 1;
|
|
return 1;
|
|
}
|
|
|
|
int MicroOutFlush(MicroOut *data)
|
|
{
|
|
if (!data || data->initOK != 1) return 0;
|
|
data->waveBegin = data->waveEnd;
|
|
data->waveSize = 0;
|
|
return 1;
|
|
}
|
|
|
|
|
|
void MicroOutStop(MicroOut *data)
|
|
{
|
|
if (!data || data->initOK != 1) return;
|
|
|
|
waveOutPause(data->waveOut);
|
|
waveOutClose(data->waveOut);
|
|
|
|
CC_free(data->pWaveBuffer);
|
|
for (int uCurrentWHDR=0; uCurrentWHDR<NB_WHDR; uCurrentWHDR++)
|
|
CC_free(data->waveHDR[uCurrentWHDR].lpData);
|
|
|
|
memset(data, 0, sizeof(MicroOut));
|
|
}
|
|
|
|
|
|
int MicroOutGetBufferedTime(MicroOut *data)
|
|
{
|
|
if (!data || data->initOK != 1)
|
|
return 0;
|
|
return 1000*data->waveSize/(SND_NB_CHANNELS*SND_SAMPLES*(SND_BITS>>3));
|
|
}
|
|
|
|
int MicroOutPlay(MicroOut *data)
|
|
{
|
|
data->lTimeState = 1;
|
|
return data->lTimeState;
|
|
}
|
|
int MicroOutPause(MicroOut *data)
|
|
{
|
|
data->lTimeState = 0;
|
|
return data->lTimeState;
|
|
}
|
|
|
|
int MicroOutWrite(MicroOut *data, char *buffer, int bufferSize)
|
|
{
|
|
int copySize = min(bufferSize, WAVE_BUFFER_SIZE);
|
|
if (data->waveEnd + copySize > WAVE_BUFFER_SIZE)
|
|
{
|
|
int copySize1 = WAVE_BUFFER_SIZE - data->waveEnd;
|
|
memcpy(data->pWaveBuffer + data->waveEnd, buffer, copySize1);
|
|
memcpy(data->pWaveBuffer, buffer + copySize1, copySize - copySize1);
|
|
data->waveEnd = copySize - copySize1;
|
|
} else
|
|
{
|
|
memcpy(data->pWaveBuffer + data->waveEnd, buffer, copySize);
|
|
data->waveEnd += copySize;
|
|
}
|
|
data->waveSize += copySize;
|
|
if (data->waveSize > WAVE_BUFFER_SIZE)
|
|
{
|
|
data->waveBegin = data->waveEnd + 1;
|
|
if (data->waveBegin >= WAVE_BUFFER_SIZE)
|
|
data->waveBegin = 0;
|
|
data->waveSize = WAVE_BUFFER_SIZE;
|
|
}
|
|
return copySize;
|
|
}
|