mididd.c
来自「Windows NT声卡驱动VXD」· C语言 代码 · 共 1,581 行 · 第 1/4 页
C
1,581 行
CloseHandle(pClient->AuxEvent1);
}
if (pClient->AuxEvent2) {
CloseHandle(pClient->AuxEvent2);
}
if (pClient->Event) {
CloseHandle(pClient->Event);
}
HeapFree(hHeap, 0, (LPSTR)pClient);
}
/****************************************************************************
* @doc INTERNAL
*
* @api DWORD | midiOutWrite | Synchronously process a midi output
* buffer.
*
* @parm LPMIDIHDR | pHdr | Pointer to a midi buffer
*
* @parm PMIDIALLOC | pClient | The data associated with the logical midi
* device.
*
* @rdesc A MMSYS... type return code for the application.
***************************************************************************/
STATIC DWORD midiOutWrite(PBYTE pData, ULONG Len, PMIDIALLOC pClient)
{
DWORD BytesReturned;
//
// Try passing the request to our driver
// We operate synchronously but allow for the driver to operate
// asynchronously by waiting on an event.
//
if (!DeviceIoControl(
pClient->hDev,
IOCTL_MIDI_PLAY,
(PVOID)pData, // Input buffer
Len, // Input buffer size
NULL, // Output buffer
0, // Output buffer size
&BytesReturned,
NULL)) {
return sndTranslateStatus();
}
return MMSYSERR_NOERROR;
}
/****************************************************************************
* @doc INTERNAL
*
* @api DWORD | midiInPutBuffer | Pass a buffer to receive midi input
*
* @parm LPMIDIHDR | pHdr | Pointer to a midi buffer
*
* @parm PMIDIALLOC | pClient | The data associated with the logical midi
* device.
*
* @rdesc A MMSYS... type return code for the application.
***************************************************************************/
STATIC MMRESULT midiInPutBuffer(PLOCALMIDIHDR pHdr, PMIDIALLOC pClient)
{
DWORD BytesReturned;
BOOL Result;
WinAssert(!pHdr->Done); // Flag should be clear ready for setting by Apc
//
// BUGBUG - nice to have a semaphore for some of this !
//
//
// Try passing the request to our driver
// We operate synchronously but allow for the driver to operate
// asynchronously by waiting on an event.
//
Result = ReadFileEx(
pClient->hDev,
(LPVOID)&pHdr->MidiData,
sizeof(pHdr->ExtraData) +
sizeof(MIDI_DD_INPUT_DATA),
&pHdr->Ovl,
midiInOvl);
//
// Put the buffer in our queue
//
if (Result || GetLastError() == ERROR_IO_PENDING) {
PLOCALMIDIHDR *ppHdr;
pHdr->lpNext = NULL;
ppHdr = &pClient->Mid->DeviceQueue;
while (*ppHdr) {
ppHdr = &(*ppHdr)->lpNext;
}
*ppHdr = pHdr;
return MMSYSERR_NOERROR;
}
return sndTranslateStatus();
}
/****************************************************************************
* @doc INTERNAL
*
* @api DWORD | midiInWrite | Pass a new buffer to the Auxiliary thread for
* a midi device.
*
* @parm LPMIDIHDR | pHdr | Pointer to a midit buffer
*
* @parm PMIDIALLOC | pClient | The data associated with the logical midi
* device.
*
* @rdesc A MMSYS... type return code for the application.
*
* @comm The buffer flags are set and the buffer is passed to the auxiliary
* device task for processing.
***************************************************************************/
STATIC DWORD midiInWrite(LPMIDIHDR pHdr, PMIDIALLOC pClient)
{
//
// Put the request at the end of our queue.
//
pHdr->dwFlags |= MHDR_INQUEUE;
pHdr->dwFlags &= ~MHDR_DONE;
pClient->AuxParam.pHdr = pHdr;
return midiThreadCall(MidiThreadAddBuffer, pClient);
}
/****************************************************************************
* @doc INTERNAL
*
* @api DWORD | midiSetState | Set a midi device to a given state
*
* @parm PMIDIALLOC | pClient | The data associated with the logical midi
* output device.
*
* @parm ULONG | State | The new state
*
* @rdesc A MMSYS... type return code for the application.
***************************************************************************/
STATIC DWORD midiSetState(PMIDIALLOC pClient, ULONG State)
{
MMRESULT mRc;
mRc = sndSetHandleData(pClient->hDev,
sizeof(State),
&State,
IOCTL_MIDI_SET_STATE,
pClient->Event);
midiFlush(pClient);
return mRc;
}
/****************************************************************************
* @doc INTERNAL
*
* @api DWORD | midiThreadCall | Set the function for the thread to perform
* and 'call' the thread using the event pair mechanism.
*
* @parm MIDITHREADFUNCTION | Function | The function to perform
*
* @parm PMIDIALLOC | Our logical device data
*
* @rdesc An MMSYS... type return value suitable for returning to the
* application
*
* @comm The AuxParam field in the device data is the 'input' to
* the function processing loop in MidiThread().
***************************************************************************/
STATIC DWORD midiThreadCall(MIDITHREADFUNCTION Function, PMIDIALLOC pClient)
{
//
// Set the function code
//
pClient->AuxFunction = Function;
//
// Kick off the thread
//
SetEvent(pClient->AuxEvent1);
//
// Wait for it to complete
//
WaitForSingleObject(pClient->AuxEvent2, INFINITE);
//
// Return the return code that our task set.
//
return pClient->AuxReturnCode;
}
/****************************************************************************
* @doc INTERNAL
*
* @api void | midiInApc | Apc routine. Called when a kernel sound driver
* completes processing of a midi buffer.
*
* @parm PVOID | ApcContext | The Apc parameter. In our case this is a
* pointer to our midi device data.
*
* @parm PIO_STATUS_BLOCK | pIosb | Pointer to the Io status block
* used for the request.
*
* @rdesc There is no return code.
***************************************************************************/
STATIC void midiInOvl(DWORD dwRet, DWORD dwBytesReturned, LPOVERLAPPED pOverlap)
{
PLOCALMIDIHDR pHdr;
pHdr = ((PLOCALMIDIHDR)pOverlap);
WinAssert(((PMIDIALLOC)pHdr->pClient)->DeviceType == MidiInDevice);
//
// Note that the buffer is complete. We don't do anything else here
// because funny things happen if we call the client's callback
// routine from within an Apc.
//
pHdr->BytesReturned = dwBytesReturned;
pHdr->Done = TRUE;
}
/****************************************************************************
* @doc INTERNAL
*
* @api void | midiFlush | Buffer completion routine. This completes
* the work of the Apc routine at below Apc priority. This gets
* round the nasty situations arising when the user's callback
* causes more apcs to run (I strongly suspect this is a kernel
* but).
*
* @parm PMIDIALLOC | pClient | The client's handle data
*
* @rdesc There is no return code.
***************************************************************************/
STATIC void midiFlush(PMIDIALLOC pClient)
{
//
// Process any completed buffers - the Apc routine
// set the 'Done' flag in any completed requests.
// Note that the call to the user's callback can
// cause more requests to become complete
//
if (pClient->DeviceType == MidiInDevice) { // Output is synchronous
while (pClient->Mid->DeviceQueue &&
pClient->Mid->DeviceQueue->Done) {
PLOCALMIDIHDR pHdr;
pHdr = pClient->Mid->DeviceQueue;
//
// Clear our flag ready for next time
//
pHdr->Done = FALSE;
//
// Take buffer off the device queue
//
pClient->Mid->DeviceQueue = pHdr->lpNext;
//
// Grab the latest time estimate - convert from 100ns units
// to milliseconds
//
pClient->Mid->dwCurTime =
(DWORD)(pHdr->MidiData.Time.QuadPart / 10000);
//
// Complete our buffer
//
if (!pClient->Mid->Bad) {
int i;
for (i = 0;
i + sizeof(LARGE_INTEGER) < pHdr->BytesReturned;
i++) {
midByteRec(pClient, pHdr->MidiData.Data[i]);
}
//
// Requeue our buffer if we're still recording
//
if (pClient->Mid->fMidiInStarted) {
if (midiInPutBuffer(pHdr, pClient) != MMSYSERR_NOERROR) {
pClient->Mid->Bad = TRUE;
}
}
}
} // End of processing completed buffers
}
}
/****************************************************************************
* @doc INTERNAL
*
* @api DWORD | midiThread | Midi device auxiliary thread.
*
* @parm LPVOID | lpParameter | The thread parameter. In our case this is a
* pointer to our midi device data.
*
* @rdesc Thread return code.
***************************************************************************/
STATIC DWORD midiThread(LPVOID lpParameter)
{
PMIDIALLOC pClient;
BOOL Close;
Close = FALSE;
pClient = (PMIDIALLOC)lpParameter;
//
// Set our thread to high priority so we don't fail to pass
// new buffers to the device when we get them back. Also
// we don't want any gaps if callbacks are meant to play
// notes just received.
//
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
//
// We start notifying our creator we have started and
// waiting for something to do.
//
SetEvent(pClient->AuxEvent2);
WaitForSingleObject(pClient->AuxEvent1, INFINITE);
//
// Now we're going
//
for(;;) {
//
// Initialize our return code
//
pClient->AuxReturnCode = MMSYSERR_NOERROR;
//
// Decode function number to perform
//
switch (pClient->AuxFunction) {
case MidiThreadAddBuffer:
//
// Add the buffer to our list to be processed
//
{
LPMIDIHDR *pHdrSearch;
pClient->AuxParam.pHdr->lpNext = NULL;
pHdrSearch = &pClient->lpMIQueue;
while (*pHdrSearch) {
pHdrSearch = &(*pHdrSearch)->lpNext;
}
*pHdrSearch = pClient->AuxParam.pHdr;
}
break;
case MidiThreadSetState:
switch (pClient->AuxParam.State) {
case MIDI_DD_RECORD:
//
// Start means we must add our buffers to the driver's list
//
if (!pClient->Mid->fMidiInStarted && !pClient->Mid->Bad) {
int i;
for (i = 0; i < NUMBER_OF_LOCAL_MIDI_BUFFERS; i++) {
pClient->AuxReturnCode =
midiInPutBuffer(&pClient->Mid->Bufs[i], pClient);
if (pClient->AuxReturnCode != MMSYSERR_NOERROR) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?