JD2022-TU1/main/extern/Camcam/LIBS/Input/MicroIn.cpp

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;
}