windows-nt/Source/XPSP1/NT/base/mvdm/vdd/vsndblst/fm.c

274 lines
7.4 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/***************************************************************************
*
* fm.c
*
* Copyright (c) 1991-1996 Microsoft Corporation. All Rights Reserved.
*
* This code provides VDD support for SB 2.0 sound output, specifically:
* FM Chip OPL2 (a.k.a. Adlib)
*
***************************************************************************/
/*****************************************************************************
*
* #includes
*
*****************************************************************************/
#include <windows.h> // The VDD is a win32 DLL
#include <mmsystem.h> // Multi-media APIs
#include <vddsvc.h> // Definition of VDD calls
#include <vsb.h>
#include <fm.h>
/*****************************************************************************
*
* Globals
*
*****************************************************************************/
HANDLE HFM = NULL; // current open FM device
BOOL FMActive = FALSE; // indicates whether we have an FM device
BYTE AdlibRegister = 0x00; // register currently selected
int Position = 0; // position in PortData array
SYNTH_DATA PortData[BATCH_SIZE]; // batched data to be written to OPL2 device
BOOL Timer1Started = FALSE; // if a timer interrupts then it's stopped
BOOL Timer2Started = FALSE; // if a timer interrupts then it's stopped
BYTE Status = 0x06; // or 0x00, see sb programming book page xi
/****************************************************************************
*
* FM device routines
*
****************************************************************************/
VOID
ResetFM(
VOID
)
{
AdlibRegister = 0x00; // register currently selected
Position = 0;
Timer1Started = FALSE;
Timer2Started = FALSE;
Status = 0x06;
}
VOID
FMStatusRead(
BYTE *data
)
{
#if 0 // This should work but doesn't (ReadFile fails)
// Are we expecting a state change ?
if (Timer1Started || Timer2Started) {
// Read the status port from the driver - this is how the
// driver interprets read.
// Well, actually don't because the WSS driver doesn't work!
if (!ReadFile(HFM, &Status, 1, &bytesRead, NULL)) {
#if DBG
FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(char *) &lpMsgBuf, 0, NULL);
dprintf1(("FM read port failed: %d bytes of data read, error message: %s",
bytesRead, lpMsgBuf));
LocalFree( lpMsgBuf ); // Free the buffer.
#endif DBG
break;
}
else {
// Look for state change
if (Status & 0x40) {
Timer1Started = FALSE;
dprintf2(("Timer 1 finished"));
}
if (Status & 0x20) {
Timer2Started = FALSE;
dprintf2(("Timer 2 finished"));
}
}
}
#endif
*data = Status;
}
VOID
FMRegisterSelect(
BYTE data
)
{
AdlibRegister = data;
}
VOID
FMDataWrite(
BYTE data
)
{
if(AdlibRegister==AD_NEW) {
data &=0xFE; // don't enter opl3 mode
}
// put data in PortData array
if(Position <= BATCH_SIZE-2) {
PortData[Position].IoPort = ADLIB_REGISTER_SELECT_PORT;
PortData[Position].PortData = AdlibRegister;
PortData[Position + 1].IoPort = ADLIB_DATA_PORT;
PortData[Position + 1].PortData = data;
Position += 2;
} else {
dprintf1(("Attempting to write beyond end of PortData array"));
}
if (Position == BATCH_SIZE ||
AdlibRegister>=0xB0 && AdlibRegister<=0xBD ||
AdlibRegister == AD_MASK) {
// PortData full or note-on/off command or changing status
if (!FMPortWrite()) {
dprintf1(("Failed to write to device!"));
} else {
// Work out what status change may have occurred
if (AdlibRegister == AD_MASK) {
// Look for RST and starting timers
if (data & 0x80) {
Status = 0x00; // reset both timers
}
// We ignore starting of timers if their interrupt
// flag is set because the timer status will have to
// be set again to make the status for this timer change
if ((data & 1) && !(Status & 0x40)) {
dprintf2(("Timer 1 started"));
#if 0
Timer1Started = TRUE;
#else
Status |= 0xC0; // simulate immediate expiry of timer1
#endif
} else {
Timer1Started = FALSE;
}
if ((data & 2) && !(Status & 0x20)) {
dprintf2(("Timer 2 started"));
#if 0
Timer2Started = TRUE;
#else
Status |= 0xA0; // simulate immediate expiry of timer2
#endif
Timer2Started = TRUE;
} else {
Timer2Started = FALSE;
}
}
}
}
}
/*
* Opens opl2 device adlib.mid or adlib.mid0 as a file handle.
* Returns TRUE on success.
*/
BOOL
OpenFMDevice(
VOID
)
{
DWORD dwBytesReturned;
LPVOID lpMsgBuf;
// attempt to open device file adlib.mid or adlib.mid0
HFM = CreateFile(L"\\\\.\\adlib.mid", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (HFM == INVALID_HANDLE_VALUE) {
HFM = CreateFile(L"\\\\.\\adlib.mid0", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
}
if (HFM == INVALID_HANDLE_VALUE) {
#if DBG
FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char *) &lpMsgBuf, 0, NULL);
dprintf1(("Create FM out failed, error message: %s", lpMsgBuf));
LocalFree( lpMsgBuf ); // Free the buffer.
#endif // DBG
return FALSE;
}
FMActive = TRUE;
return TRUE;
}
/***************************************************************************/
/*
* Closes our FM device.
*/
VOID
CloseFMDevice(
VOID
)
{
dprintf2(("Closing FM device"));
if (HFM) {
CloseHandle(HFM);
HFM = NULL;
FMActive = FALSE;
}
}
/***************************************************************************/
/*
* Sends FM data to the card.
* Returns TRUE on success.
*/
BOOL
FMPortWrite(
VOID
)
{
DWORD bytesWritten = 0;
LPVOID lpMsgBuf;
if(FMActive) {
dprintf4(("Writing %d bytes of data to port",
Position * sizeof(PortData[0])));
if(!WriteFile(HFM, &PortData, Position * sizeof(PortData[0]),
&bytesWritten, NULL)) {
#if DBG
FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char *) &lpMsgBuf,
0, NULL);
dprintf1(("FM write failed: %d bytes of data written, error message: %s",
bytesWritten, lpMsgBuf));
LocalFree( lpMsgBuf ); // Free the buffer.
#endif //DBG
return FALSE;
}
}
Position = 0;
return TRUE;
}
/***************************************************************************/