windows-nt/Source/XPSP1/NT/multimedia/directx/dmusic/dmsynth/midi.cpp
2020-09-26 16:20:57 +08:00

491 lines
11 KiB
C++

// Copyright (c) 1996-1999 Microsoft Corporation
// MIDI.cpp
//
#ifdef DMSYNTH_MINIPORT
#include "common.h"
#else
#include "simple.h"
#include <mmsystem.h>
#include "synth.h"
#include "math.h"
#include "debug.h"
#endif
CMIDIDataList CMIDIRecorder::m_sFreeList;
DWORD CMIDIRecorder::m_sUsageCount = 0;
CMIDIData::CMIDIData()
{
m_stTime = 0;
m_lData = 0;
}
CMIDIRecorder::CMIDIRecorder()
{
m_sUsageCount++;
m_lCurrentData = 0;
m_stCurrentTime = 0;
}
CMIDIRecorder::~CMIDIRecorder()
{
ClearMIDI(0x7FFFFFFF);
m_sUsageCount--;
// If there are no instances of CMIDIRecorder left, get rid of the free pool.
if (!m_sUsageCount)
{
CMIDIData *pMD;
while (pMD = m_sFreeList.RemoveHead())
{
delete pMD;
}
}
}
VREL CMIDIRecorder::m_vrMIDIToVREL[128] =
{
-9600, -8415, -7211, -6506, -6006, -5619, -5302, -5034,
-4802, -4598, -4415, -4249, -4098, -3959, -3830, -3710,
-3598, -3493, -3394, -3300, -3211, -3126, -3045, -2968,
-2894, -2823, -2755, -2689, -2626, -2565, -2506, -2449,
-2394, -2341, -2289, -2238, -2190, -2142, -2096, -2050,
-2006, -1964, -1922, -1881, -1841, -1802, -1764, -1726,
-1690, -1654, -1619, -1584, -1551, -1518, -1485, -1453,
-1422, -1391, -1361, -1331, -1302, -1273, -1245, -1217,
-1190, -1163, -1137, -1110, -1085, -1059, -1034, -1010,
-985, -961, -938, -914, -891, -869, -846, -824,
-802, -781, -759, -738, -718, -697, -677, -657,
-637, -617, -598, -579, -560, -541, -522, -504,
-486, -468, -450, -432, -415, -397, -380, -363,
-347, -330, -313, -297, -281, -265, -249, -233,
-218, -202, -187, -172, -157, -142, -127, -113,
-98, -84, -69, -55, -41, -27, -13, 0
};
VREL CMIDIRecorder::m_vrMIDIPercentToVREL[128] =
{
-9600, -4207, -3605, -3253, -3003, -2809, -2651, -2517,
-2401, -2299, -2207, -2124, -2049, -1979, -1915, -1855,
-1799, -1746, -1697, -1650, -1605, -1563, -1522, -1484,
-1447, -1411, -1377, -1344, -1313, -1282, -1253, -1224,
-1197, -1170, -1144, -1119, -1095, -1071, -1048, -1025,
-1003, -982, -961, -940, -920, -901, -882, -863,
-845, -827, -809, -792, -775, -759, -742, -726,
-711, -695, -680, -665, -651, -636, -622, -608,
-595, -581, -568, -555, -542, -529, -517, -505,
-492, -480, -469, -457, -445, -434, -423, -412,
-401, -390, -379, -369, -359, -348, -338, -328,
-318, -308, -299, -289, -280, -270, -261, -252,
-243, -234, -225, -216, -207, -198, -190, -181,
-173, -165, -156, -148, -140, -132, -124, -116,
-109, -101, -93, -86, -78, -71, -63, -56,
-49, -42, -34, -27, -20, -13, -6, 0
};
/*void CMIDIRecorder::Init()
{
int nIndex;
static BOOL fAlreadyDone = FALSE;
if (!fAlreadyDone)
{
m_sFreeList.RemoveAll();
for (nIndex = 0; nIndex < MAX_MIDI_EVENTS; nIndex++)
{
m_sFreeList.AddHead(&m_sEventBuffer[nIndex]);
}
fAlreadyDone = TRUE;*/
/* for (nIndex = 1; nIndex < 128; nIndex++)
{
double flTemp;
flTemp = nIndex;
flTemp /= 127.0;
flTemp = pow(flTemp,4.0);
flTemp = log10(flTemp);
flTemp *= 1000.0;
Trace(0,"%ld, ",(long)flTemp);
if ((nIndex % 8) == 7)
Trace(0,"\n");
m_vrMIDIToVREL[nIndex] = (VREL) flTemp;
}
Trace(0,"\n");
m_vrMIDIToVREL[0] = -9600;
for (nIndex = 1; nIndex < 128; nIndex++)
{
double flTemp;
flTemp = nIndex;
flTemp /= 127;
flTemp *= flTemp;
flTemp = log10(flTemp);
flTemp *= 1000.0;
m_vrMIDIPercentToVREL[nIndex] = (VREL) flTemp;
Trace(0,"%ld, ",(long)flTemp);
if ((nIndex % 8) == 7)
Trace(0,"\n");
}
m_vrMIDIPercentToVREL[0] = -9600;*/
/*}
}*/
BOOL CMIDIRecorder::FlushMIDI(STIME stTime)
{
CMIDIData *pMD;
CMIDIData *pLast = NULL;
for (pMD = m_EventList.GetHead();pMD != NULL;pMD = pMD->GetNext())
{
if (pMD->m_stTime >= stTime)
{
if (pLast == NULL)
{
m_EventList.RemoveAll();
}
else
{
pLast->SetNext(NULL);
}
m_sFreeList.Cat(pMD);
break;
}
pLast = pMD;
}
return m_EventList.IsEmpty();
}
BOOL CMIDIRecorder::ClearMIDI(STIME stTime)
{
CMIDIData *pMD;
for (;pMD = m_EventList.GetHead();)
{
if (pMD->m_stTime < stTime)
{
m_EventList.RemoveHead();
m_stCurrentTime = pMD->m_stTime;
m_lCurrentData = pMD->m_lData;
m_sFreeList.AddHead(pMD);
}
else break;
}
return m_EventList.IsEmpty();
}
VREL CMIDIRecorder::VelocityToVolume(WORD nVelocity)
{
return (m_vrMIDIToVREL[nVelocity]);
}
BOOL CMIDIRecorder::RecordMIDINote(STIME stTime, long lData)
{
CMIDIData *pMD = m_sFreeList.RemoveHead();
if (!pMD)
{
pMD = new CMIDIData;
}
CMIDIData *pScan = m_EventList.GetHead();
CMIDIData *pNext;
if (pMD)
{
pMD->m_stTime = stTime;
pMD->m_lData = lData;
if (pScan == NULL)
{
m_EventList.AddHead(pMD);
}
else
{
if (pScan->m_stTime > stTime)
{
m_EventList.AddHead(pMD);
}
else
{
for (;pScan != NULL; pScan = pNext)
{
pNext = pScan->GetNext();
if (pNext == NULL)
{
pScan->SetNext(pMD);
}
else
{
if (pNext->m_stTime > stTime)
{
pMD->SetNext(pNext);
pScan->SetNext(pMD);
break;
}
}
}
}
}
return (TRUE);
}
return (FALSE);
}
BOOL CMIDIRecorder::RecordMIDI(STIME stTime, long lData)
{
CMIDIData *pMD = m_sFreeList.RemoveHead();
if (!pMD)
{
pMD = new CMIDIData;
}
CMIDIData *pScan = m_EventList.GetHead();
CMIDIData *pNext;
if (pMD)
{
pMD->m_stTime = stTime;
pMD->m_lData = lData;
if (pScan == NULL)
{
m_EventList.AddHead(pMD);
}
else
{
if (pScan->m_stTime > stTime)
{
m_EventList.AddHead(pMD);
}
else
{
for (;pScan != NULL; pScan = pNext)
{
if ((pScan->m_stTime == stTime) &&
(pScan->m_lData == lData))
{
m_sFreeList.AddHead(pMD);
break;
}
pNext = pScan->GetNext();
if (pNext == NULL)
{
pScan->SetNext(pMD);
}
else
{
if (pNext->m_stTime > stTime)
{
pMD->SetNext(pNext);
pScan->SetNext(pMD);
break;
}
}
}
}
}
return (TRUE);
}
/*#ifdef DBG
static gWarnCount = 0;
if (!gWarnCount)
{
Trace(1,"Warning: MIDI Free event pool empty. This can be caused by time stamping problems, too much MIDI data, or too many PChannels.\n");
gWarnCount = 100;
}
gWarnCount--;
#endif*/
return (FALSE);
}
long CMIDIRecorder::GetData(STIME stTime)
{
CMIDIData *pMD = m_EventList.GetHead();
long lData = m_lCurrentData;
for (;pMD;pMD = pMD->GetNext())
{
if (pMD->m_stTime > stTime)
{
break;
}
lData = pMD->m_lData;
}
return (lData);
}
BOOL CNoteIn::RecordNote(STIME stTime, CNote * pNote)
{
long lData = pNote->m_bPart << 16;
lData |= pNote->m_bKey << 8;
lData |= pNote->m_bVelocity;
return (RecordMIDINote(stTime,lData));
}
BOOL CNoteIn::RecordEvent(STIME stTime, DWORD dwPart, DWORD dwCommand, BYTE bData)
{
long lData = dwPart;
lData <<= 8;
lData |= dwCommand;
lData <<= 8;
lData |= bData;
return (RecordMIDINote(stTime,lData));
}
BOOL CNoteIn::GetNote(STIME stTime, CNote * pNote)
{
CMIDIData *pMD = m_EventList.GetHead();
if (pMD != NULL)
{
if (pMD->m_stTime <= stTime)
{
pNote->m_stTime = pMD->m_stTime;
pNote->m_bPart = (BYTE) (pMD->m_lData >> 16);
pNote->m_bKey = (BYTE) (pMD->m_lData >> 8) & 0xFF;
pNote->m_bVelocity = (BYTE) pMD->m_lData & 0xFF;
m_EventList.RemoveHead();
m_sFreeList.AddHead(pMD);
return (TRUE);
}
}
return (FALSE);
}
void CNoteIn::FlushMIDI(STIME stTime)
{
CMIDIData *pMD;
for (pMD = m_EventList.GetHead();pMD != NULL;pMD = pMD->GetNext())
{
if (pMD->m_stTime >= stTime)
{
pMD->m_stTime = stTime; // Play now.
pMD->m_lData &= 0xFFFFFF00; // Clear velocity to make note off.
}
}
}
void CNoteIn::FlushPart(STIME stTime, BYTE bChannel)
{
CMIDIData *pMD;
for (pMD = m_EventList.GetHead();pMD != NULL;pMD = pMD->GetNext())
{
if (pMD->m_stTime >= stTime)
{
if (bChannel == (BYTE) (pMD->m_lData >> 16))
{
pMD->m_stTime = stTime; // Play now.
pMD->m_lData &= 0xFFFFFF00; // Clear velocity to make note off.
}
}
}
}
DWORD CModWheelIn::GetModulation(STIME stTime)
{
DWORD nResult = CMIDIRecorder::GetData(stTime);
return (nResult);
}
CPitchBendIn::CPitchBendIn()
{
m_lCurrentData = 0x2000; // initially at midpoint, no bend
m_prRange = 200; // whole tone range by default.
}
// note (davidmay 8/14/96): we don't keep a time-stamped range.
// if people are changing the pitch bend range often, this won't work right,
// but that didn't seem likely enough to warrant a new list.
PREL CPitchBendIn::GetPitch(STIME stTime)
{
PREL prResult = (PREL) CMIDIRecorder::GetData(stTime);
prResult -= 0x2000; // Subtract MIDI Midpoint.
prResult *= m_prRange; // adjust by current range
prResult >>= 13;
return (prResult);
}
CVolumeIn::CVolumeIn()
{
m_lCurrentData = 100;
}
VREL CVolumeIn::GetVolume(STIME stTime)
{
long lResult = CMIDIRecorder::GetData(stTime);
return (m_vrMIDIToVREL[lResult]);
}
CExpressionIn::CExpressionIn()
{
m_lCurrentData = 127;
}
VREL CExpressionIn::GetVolume(STIME stTime)
{
long lResult = CMIDIRecorder::GetData(stTime);
return (m_vrMIDIToVREL[lResult]);
}
CPanIn::CPanIn()
{
m_lCurrentData = 64;
}
long CPanIn::GetPan(STIME stTime)
{
long lResult = (long) CMIDIRecorder::GetData(stTime);
return (lResult);
}
//////////////////////////////////////////////////////////
// Directx8 Methods
DWORD CPressureIn::GetPressure(STIME stTime)
{
DWORD nResult = CMIDIRecorder::GetData(stTime);
return (nResult);
}
CReverbIn::CReverbIn()
{
m_lCurrentData = 40;
}
DWORD CReverbIn::GetVolume(STIME stTime)
{
return (m_vrMIDIPercentToVREL[CMIDIRecorder::GetData(stTime)]);
}
DWORD CChorusIn::GetVolume(STIME stTime)
{
return (m_vrMIDIPercentToVREL[CMIDIRecorder::GetData(stTime)]);
}
CCutOffFreqIn::CCutOffFreqIn()
{
m_lCurrentData = 64;
}
DWORD CCutOffFreqIn::GetFrequency(STIME stTime)
{
DWORD nResult = CMIDIRecorder::GetData(stTime);
return (nResult);
}