📄 miniport.cpp
字号:
}
break;
} // if bVelocity.
//NOTE: no break specified here. On an else case we want to continue through and turn key off
case 0x80:
/* turn key off */
// we don't care what the velocity is on note off
if (bChannel == DRUMCHANNEL)
{
Opl3_NoteOff((BYTE) (bNote + 128),bNote, bChannel, 0);
}
else
{
Opl3_NoteOff ((BYTE) m_bPatch[bChannel],bNote, bChannel, m_bSustain[ bChannel ]);
}
break;
case 0xb0:
/* change control */
switch (bNote)
{
case 7:
/* change channel volume */
Opl3_ChannelVolume(bChannel,gbVelocityAtten[bVelocity >> 1]);
break;
case 8:
case 10:
/* change the pan level */
Opl3_SetPan(bChannel, bVelocity);
break;
case 64:
/* Change the sustain level */
Opl3_SetSustain(bChannel, bVelocity);
break;
default:
if (bNote >= 120) /* Channel mode messages */
{
Opl3_ChannelNotesOff(bChannel);
}
// else unknown controller
};
break;
case 0xc0:
if (bChannel != DRUMCHANNEL)
{
m_bPatch[ bChannel ] = bNote ;
}
break;
case 0xe0: // pitch bend
wTemp = ((WORD) bVelocity << 9) | ((WORD) bNote << 2);
m_iBend[bChannel] = (short) (WORD) (wTemp + 0x8000);
Opl3_PitchBend(bChannel, m_iBend[bChannel]);
break;
};
KeReleaseSpinLock(&m_Miniport->m_SpinLock,oldIrql);
return;
}
// ========================= opl3 specific methods ============================
#pragma code_seg()
// ==========================================================================
// Opl3_AllNotesOff - turn off all notes
// ==========================================================================
void
CMiniportMidiStreamFM::
Opl3_AllNotesOff()
{
BYTE i;
KIRQL oldIrql;
KeAcquireSpinLock(&m_Miniport->m_SpinLock,&oldIrql);
for (i = 0; i < NUM2VOICES; i++)
{
Opl3_NoteOff(m_Voice[i].bPatch, m_Voice[i].bNote, m_Voice[i].bChannel, 0);
}
KeReleaseSpinLock(&m_Miniport->m_SpinLock,oldIrql);
}
#pragma code_seg()
// ==========================================================================
// void Opl3_NoteOff
//
// Description:
// This turns off a note, including drums with a patch
// # of the drum note + 128, but the first drum instrument is at MIDI note _35_.
//
// Parameters:
// BYTE bPatch
// MIDI patch
//
// BYTE bNote
// MIDI note
//
// BYTE bChannel
// MIDI channel
//
// Return Value:
// Nothing.
//
//
// ==========================================================================
void
CMiniportMidiStreamFM::
Opl3_NoteOff
(
BYTE bPatch,
BYTE bNote,
BYTE bChannel,
BYTE bSustain
)
{
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
patchStruct FAR *lpPS ;
WORD wOffset, wTemp ;
// Find the note slot
wTemp = Opl3_FindFullSlot( bNote, bChannel ) ;
if (wTemp != 0xffff)
{
if (bSustain)
{
// This channel is sustained, don't really turn the note off,
// just flag it.
//
m_Voice[ wTemp ].bSusHeld = 1;
return;
}
// get a pointer to the patch
lpPS = glpPatch + (BYTE) m_Voice[ wTemp ].bPatch ;
// shut off the note portion
// we have the note slot, turn it off.
wOffset = wTemp;
if (wTemp >= (NUM2VOICES / 2))
wOffset += (0x100 - (NUM2VOICES / 2));
m_Miniport->SoundMidiSendFM(m_PortBase, AD_BLOCK + wOffset,
(BYTE)(m_Voice[ wTemp ].bBlock[ 0 ] & 0x1f) ) ;
// Note this...
m_Voice[ wTemp ].bOn = FALSE ;
m_Voice[ wTemp ].bBlock[ 0 ] &= 0x1f ;
m_Voice[ wTemp ].bBlock[ 1 ] &= 0x1f ;
m_Voice[ wTemp ].dwTime = m_dwCurTime ;
}
}
#pragma code_seg()
// ==========================================================================
// WORD Opl3_FindFullSlot
//
// Description:
// This finds a slot with a specific note, and channel.
// If it is not found then 0xFFFF is returned.
//
// Parameters:
// BYTE bNote
// MIDI note number
//
// BYTE bChannel
// MIDI channel #
//
// Return Value:
// WORD
// note slot #, or 0xFFFF if can't find it
//
//
// ==========================================================================
WORD
CMiniportMidiStreamFM::
Opl3_FindFullSlot
(
BYTE bNote,
BYTE bChannel
)
{
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
WORD i ;
for (i = 0; i < NUM2VOICES; i++)
{
if ((bChannel == m_Voice[ i ].bChannel)
&& (bNote == m_Voice[ i ].bNote)
&& (m_Voice[ i ].bOn))
{
return ( i ) ;
}
// couldn't find it
}
return ( 0xFFFF ) ;
}
#pragma code_seg()
//------------------------------------------------------------------------
// void Opl3_FMNote
//
// Description:
// Turns on an FM-synthesizer note.
//
// Parameters:
// WORD wNote
// the note number from 0 to NUMVOICES
//
// noteStruct FAR *lpSN
// structure containing information about what
// is to be played.
//
// Return Value:
// Nothing.
//------------------------------------------------------------------------
void
CMiniportMidiStreamFM::
Opl3_FMNote
(
WORD wNote,
noteStruct FAR * lpSN
)
{
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
WORD i ;
WORD wOffset ;
operStruct FAR *lpOS ;
// write out a note off, just to make sure...
wOffset = wNote;
if (wNote >= (NUM2VOICES / 2))
wOffset += (0x100 - (NUM2VOICES / 2));
m_Miniport->SoundMidiSendFM(m_PortBase, AD_BLOCK + wOffset, 0 ) ;
// writing the operator information
// for (i = 0; i < (WORD)((wNote < NUM4VOICES) ? NUMOPS : 2); i++)
for (i = 0; i < 2; i++)
{
lpOS = &lpSN -> op[ i ] ;
wOffset = gw2OpOffset[ wNote ][ i ] ;
m_Miniport->SoundMidiSendFM( m_PortBase, 0x20 + wOffset, lpOS -> bAt20) ;
m_Miniport->SoundMidiSendFM( m_PortBase, 0x40 + wOffset, lpOS -> bAt40) ;
m_Miniport->SoundMidiSendFM( m_PortBase, 0x60 + wOffset, lpOS -> bAt60) ;
m_Miniport->SoundMidiSendFM( m_PortBase, 0x80 + wOffset, lpOS -> bAt80) ;
m_Miniport->SoundMidiSendFM( m_PortBase, 0xE0 + wOffset, lpOS -> bAtE0) ;
}
// write out the voice information
wOffset = (wNote < 9) ? wNote : (wNote + 0x100 - 9) ;
m_Miniport->SoundMidiSendFM(m_PortBase, 0xa0 + wOffset, lpSN -> bAtA0[ 0 ] ) ;
m_Miniport->SoundMidiSendFM(m_PortBase, 0xc0 + wOffset, lpSN -> bAtC0[ 0 ] ) ;
// Note on...
m_Miniport->SoundMidiSendFM(m_PortBase, 0xb0 + wOffset,
(BYTE)(lpSN -> bAtB0[ 0 ] | 0x20) ) ;
} // end of Opl3_FMNote()
#pragma code_seg()
//=======================================================================
// WORD Opl3_NoteOn
//
// Description:
// This turns on a note, including drums with a patch # of the
// drum note + 0x80. The first GM drum instrument is mapped to note 35 instead of zero, though, so
// we expect 0 as the first drum patch (acoustic kick) if note 35 comes in.
//
// Parameters:
// BYTE bPatch
// MIDI patch
//
// BYTE bNote
// MIDI note
//
// BYTE bChannel
// MIDI channel
//
// BYTE bVelocity
// velocity value
//
// short iBend
// current pitch bend from -32768 to 32767
//
// Return Value:
// WORD
// note slot #, or 0xFFFF if it is inaudible
//=======================================================================
void
CMiniportMidiStreamFM::
Opl3_NoteOn
(
BYTE bPatch,
BYTE bNote,
BYTE bChannel,
BYTE bVelocity,
short iBend
)
{
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
WORD wTemp, i, j ;
BYTE b4Op, bTemp, bMode, bStereo ;
patchStruct FAR *lpPS ;
DWORD dwBasicPitch, dwPitch[ 2 ] ;
noteStruct NS ;
// Get a pointer to the patch
lpPS = glpPatch + bPatch ;
// Find out the basic pitch according to our
// note value. This may be adjusted because of
// pitch bends or special qualities for the note.
dwBasicPitch = gdwPitch[ bNote % 12 ] ;
bTemp = bNote / (BYTE) 12 ;
if (bTemp > (BYTE) (60 / 12))
dwBasicPitch = AsLSHL( dwBasicPitch, (BYTE)(bTemp - (BYTE)(60/12)) ) ;
else if (bTemp < (BYTE) (60/12))
dwBasicPitch = AsULSHR( dwBasicPitch, (BYTE)((BYTE) (60/12) - bTemp) ) ;
// Copy the note information over and modify
// the total level and pitch according to
// the velocity, midi volume, and tuning.
RtlCopyMemory( (LPSTR) &NS, (LPSTR) &lpPS -> note, sizeof( noteStruct ) ) ;
b4Op = (BYTE)(NS.bOp != PATCH_1_2OP) ;
for (j = 0; j < 2; j++)
{
// modify pitch
dwPitch[ j ] = dwBasicPitch ;
bTemp = (BYTE)((NS.bAtB0[ j ] >> 2) & 0x07) ;
if (bTemp > 4)
dwPitch[ j ] = AsLSHL( dwPitch[ j ], (BYTE)(bTemp - (BYTE)4) ) ;
else if (bTemp < 4)
dwPitch[ j ] = AsULSHR( dwPitch[ j ], (BYTE)((BYTE)4 - bTemp) ) ;
wTemp = Opl3_CalcFAndB( Opl3_CalcBend( dwPitch[ j ], iBend ) ) ;
NS.bAtA0[ j ] = (BYTE) wTemp ;
NS.bAtB0[ j ] = (BYTE) 0x20 | (BYTE) (wTemp >> 8) ;
}
// Modify level for each operator, but only
// if they are carrier waves
bMode = (BYTE) ((NS.bAtC0[ 0 ] & 0x01) * 2 + 4) ;
for (i = 0; i < 2; i++)
{
wTemp = (BYTE)
Opl3_CalcVolume( (BYTE)(NS.op[ i ].bAt40 & (BYTE) 0x3f),
bChannel,
bVelocity,
(BYTE) i,
bMode ) ;
NS.op[ i ].bAt40 = (NS.op[ i ].bAt40 & (BYTE)0xc0) | (BYTE) wTemp ;
}
// Do stereo panning, but cutting off a left or
// right channel if necessary...
bStereo = Opl3_CalcStereoMask( bChannel ) ;
NS.bAtC0[ 0 ] &= bStereo ;
// Find an empty slot, and use it...
wTemp = Opl3_FindEmptySlot( bPatch ) ;
Opl3_FMNote(wTemp, &NS ) ;
m_Voice[ wTemp ].bNote = bNote ;
m_Voice[ wTemp ].bChannel = bChannel ;
m_Voice[ wTemp ].bPatch = bPatch ;
m_Voice[ wTemp ].bVelocity = bVelocity ;
m_Voice[ wTemp ].bOn = TRUE ;
m_Voice[ wTemp ].dwTime = m_dwCurTime++ ;
m_Voice[ wTemp ].dwOrigPitch[0] = dwPitch[ 0 ] ; // not including bend
m_Voice[ wTemp ].dwOrigPitch[1] = dwPitch[ 1 ] ; // not including bend
m_Voice[ wTemp ].bBlock[0] = NS.bAtB0[ 0 ] ;
m_Voice[ wTemp ].bBlock[1] = NS.bAtB0[ 1 ] ;
m_Voice[ wTemp ].bSusHeld = 0;
} // end of Opl3_NoteOn()
#pragma code_seg()
//=============================
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -