Sample Code

Windows Driver Samples/ DirectMusic Software Synthesizer Sample/ C++/ control.cpp/

//
//      Copyright (c) 1996-2000 Microsoft Corporation.  All rights reserved.
//      CControlLogic.cpp
//

#define STR_MODULENAME "DDKSynth.sys:Control: "

#include "common.h"

#pragma code_seg()
/*****************************************************************************
 * CControlLogic::CControlLogic()
 *****************************************************************************
 * Constructor for CControlLogic object.
 */
CControlLogic::CControlLogic()
{
    m_fCSInitialized = FALSE;
    InitializeCriticalSection(&m_CriticalSection);
    m_fCSInitialized = TRUE;

    m_pSynth = NULL;
	m_pInstruments = NULL;

    DWORD nIndex;
	GMReset();
	m_fGSActive = FALSE;
	m_fXGActive = FALSE;
    for (nIndex = 0;nIndex < 16;nIndex++)
    {
        m_fSustain[nIndex] = FALSE;
        m_dwProgram[nIndex] = 0;
    }
    m_fEmpty = TRUE;
}

/*****************************************************************************
 * CControlLogic::~CControlLogic()
 *****************************************************************************
 * Destructor for CControlLogic object.
 */
CControlLogic::~CControlLogic()
{
    if (m_fCSInitialized)
    {
        DeleteCriticalSection(&m_CriticalSection);
    }
}

/*****************************************************************************
 * CControlLogic::GMReset()
 *****************************************************************************
 * Performs a General MIDI reset, including resetting all the voice priorities,
 * GS, XG, master volume, etc.
 */
void CControlLogic::GMReset()
{
    static const int nPartToChannel[16] = { 
		9,0,1,2,3,4,5,6,7,8,10,11,12,13,14,15 
	};
	int nX;
	for (nX = 0; nX < 16; nX++)
	{
		int nY;
		m_nData[nX] = 0;
		m_prFineTune[nX] = 0;
		m_bDrums[nX] = 0;
		for (nY = 0; nY < 12; nY++)
		{
			m_prScaleTune[nX][nY] = 0;
		}
		m_nCurrentRPN[nX] = (short) 0x3FFF;
		m_prCoarseTune[nX] = 0;	
		m_bPartToChannel[nX] = (BYTE)nPartToChannel[nX];
		m_fMono[nX] = FALSE;
		m_dwPriority[nX] = DAUD_STANDARD_VOICE_PRIORITY + 
			((16 - nX) * DAUD_CHAN15_VOICE_PRIORITY_OFFSET);
        m_bBankH[nX] = 0;
        m_bBankL[nX] = 0;
	}
	m_bDrums[0] = 1;
	m_vrMasterVolume = 0;
	m_fGSActive = FALSE;
	m_fXGActive = FALSE;
}

/*****************************************************************************
 * CControlLogic::Init()
 *****************************************************************************
 * Initialize the CControlLogic object, and initialize all the child objects --
 * Note recorders, ModWheels, Volumes, Pan, Expression, PitchBend.
 */
HRESULT CControlLogic::Init(CInstManager *pInstruments, CSynth *pSynth)
{
	m_pSynth = pSynth;
	m_pInstruments = pInstruments;
    m_vrGainAdjust = 0;

    m_Notes.Init();

    int iRecIdx;
    for (iRecIdx = 0; iRecIdx < sizeof(m_ModWheel) / sizeof(*m_ModWheel); iRecIdx++)
    {
        m_ModWheel[iRecIdx].Init();
    }
    for (iRecIdx = 0; iRecIdx < sizeof(m_PitchBend) / sizeof(*m_PitchBend); iRecIdx++)
    {
        m_PitchBend[iRecIdx].Init();
    }
    for (iRecIdx = 0; iRecIdx < sizeof(m_Volume) / sizeof(*m_Volume); iRecIdx++)
    {
        m_Volume[iRecIdx].Init();
    }
    for (iRecIdx = 0; iRecIdx < sizeof(m_Expression) / sizeof(*m_Expression); iRecIdx++)
    {
        m_Expression[iRecIdx].Init();
    }
    for (iRecIdx = 0; iRecIdx < sizeof(m_Pan) / sizeof(*m_Pan); iRecIdx++)
    {
        m_Pan[iRecIdx].Init();
    }

	return S_OK;
}

/*****************************************************************************
 * CControlLogic::ClearMIDI()
 *****************************************************************************
 * Clears MIDI up to a certain time, and updates m_fEmpty.
 */
void CControlLogic::ClearMIDI(STIME stEndTime)
{
	DWORD dwIndex;
	::EnterCriticalSection(&m_CriticalSection);
    if (!m_fEmpty)
    {        
        m_fEmpty = TRUE;
        for (dwIndex = 0;dwIndex < 16; dwIndex++)
        {
            m_fEmpty = m_ModWheel[dwIndex].ClearMIDI(stEndTime)
                && m_PitchBend[dwIndex].ClearMIDI(stEndTime)
                && m_Volume[dwIndex].ClearMIDI(stEndTime)
                && m_Expression[dwIndex].ClearMIDI(stEndTime)
                && m_Pan[dwIndex].ClearMIDI(stEndTime);
        }
    }
	::LeaveCriticalSection(&m_CriticalSection);
}

/*****************************************************************************
 * CControlLogic::SetGainAdjust()
 *****************************************************************************
 * Sets the overall gain for this CControlLogic.
 */
void CControlLogic::SetGainAdjust(VREL vrGainAdjust)
{
    m_vrGainAdjust = vrGainAdjust;
}

/*****************************************************************************
 * CControlLogic::QueueNotes()
 *****************************************************************************
 * Retrieves notes from the note recorders, and dispatches them appropriately.
 * Called during the Mix.
 */
void CControlLogic::QueueNotes(STIME stEndTime)
{
    CNote note;
    
    while (m_Notes.GetNote(stEndTime,&note))
    {
		if (note.m_bKey > 0x7F)	// Special command events.
		{
			long lTemp;
			DWORD dwPart = note.m_bPart;
			DWORD dwCommand = note.m_bKey;
			BYTE bData = note.m_bVelocity;
			switch (dwCommand)
			{
            case NOTE_PROGRAMCHANGE:
                m_dwProgram[dwPart] = bData |
                    (m_bBankH[dwPart] << 16) | 
                    (m_bBankL[dwPart] << 8);
                break;
			case NOTE_CC_BANKSELECTH:
				m_bBankH[dwPart] = bData;
				break;
			case NOTE_CC_BANKSELECTL:
				m_bBankL[dwPart] = bData;
				break;
			case NOTE_CC_POLYMODE:
				m_fMono[dwPart] = FALSE;
				break;
			case NOTE_CC_MONOMODE:
				m_fMono[dwPart] = TRUE;
				break;
			case NOTE_CC_RPN_MSB:
				m_nCurrentRPN[dwPart] = (m_nCurrentRPN[dwPart] & 0x7f) + (bData << 7);
				break;
			case NOTE_CC_RPN_LSB:
				m_nCurrentRPN[dwPart] = (m_nCurrentRPN[dwPart] & 0x3f80) + bData;
				break;
			case NOTE_CC_NRPN:
				m_nCurrentRPN[dwPart] = 0x3FFF;
				break;
			case NOTE_CC_DATAENTRYLSB:
				m_nData[dwPart] &= ~0x7F;
				m_nData[dwPart] |= bData;
				switch (m_nCurrentRPN[dwPart])
				{
				case RPN_PITCHBEND: // Don't do anything, Roland ignores lsb
					break;
				case RPN_FINETUNE:
					lTemp = m_nData[dwPart];
					lTemp -= 8192;
					lTemp *= 100;
					lTemp /= 8192;
					m_prFineTune[dwPart] = lTemp;
					break;
				case RPN_COARSETUNE: // Ignore lsb
					break;            
				}
				break;
			case NOTE_CC_DATAENTRYMSB:
				m_nData[dwPart] &= ~(0x7F << 7);
				m_nData[dwPart] |= bData << 7;
				switch (m_nCurrentRPN[dwPart])
				{
				case RPN_PITCHBEND:
					m_PitchBend[dwPart].m_prRange = bData * 100;
					break;
				case RPN_FINETUNE:
					lTemp = m_nData[dwPart];
					lTemp -= 8192;
					lTemp *= 100;
					lTemp /= 8192;
					m_prFineTune[dwPart] = lTemp;
					break;
				case RPN_COARSETUNE:
					m_prCoarseTune[dwPart] = 100 * (bData - 64);
					break;        
				}
				break;
			case NOTE_SUSTAIN: // special sustain marker
	            m_fSustain[dwPart] = (BOOL) bData;
				if (bData == FALSE)
				{
					CVoice * pVoice = m_pSynth->m_VoicesInUse.GetHead();
					for (;pVoice != NULL;pVoice = pVoice->GetNext())
					{
						if (pVoice->m_fSustainOn &&
							(pVoice->m_nPart == dwPart) &&
							(pVoice->m_pControl == this))
						{
							pVoice->StopVoice(note.m_stTime);
						}
					}
				} 
				break;
			case NOTE_ALLOFF:
				{
					CVoice *pVoice = m_pSynth->m_VoicesInUse.GetHead();
					for (;pVoice != NULL; pVoice = pVoice->GetNext())
					{
						if (pVoice->m_fNoteOn && !pVoice->m_fSustainOn &&
							(pVoice->m_nPart == dwPart) &&
							(pVoice->m_pControl == this))
						{
							if (m_fSustain[dwPart])
							{
								pVoice->m_fSustainOn = TRUE;
							}
							else
							{
								pVoice->StopVoice(note.m_stTime);
							}
						}
					}
				}
				break;
			case NOTE_SOUNDSOFF:
				{
					CVoice *pVoice = m_pSynth->m_VoicesInUse.GetHead();
					for (;pVoice != NULL; pVoice = pVoice->GetNext())
					{
						if (pVoice->m_fNoteOn &&
							(pVoice->m_nPart == dwPart) &&
							(pVoice->m_pControl == this))
						{
							pVoice->StopVoice(note.m_stTime);
						}
					}
				}
				break;
			case NOTE_ASSIGNRECEIVE:
				m_bPartToChannel[dwPart] = (BYTE) bData;
				break;
			case NOTE_MASTERVOLUME:
				m_vrMasterVolume = CMIDIRecorder::VelocityToVolume(bData);
				break;
			}
		}
        else if (note.m_bVelocity == 0)  // Note Off.
        {
            CVoice * pVoice = m_pSynth->m_VoicesInUse.GetHead();
            WORD nPart = note.m_bPart;
            for (;pVoice != NULL;pVoice = pVoice->GetNext())
            {
                if (pVoice->m_fNoteOn && !pVoice->m_fSustainOn &&
                    (pVoice->m_nKey == (WORD) note.m_bKey) &&
                    (pVoice->m_nPart == nPart) &&
					(pVoice->m_pControl == this)) 
                {
                    if (m_fSustain[nPart])
                    {
                        pVoice->m_fSustainOn = TRUE;
                    }
                    else
                    {
                        pVoice->StopVoice(note.m_stTime);
                    }
                    break;
                }
            }
        }
        else   // Note On.
        {
            DWORD dwProgram = m_dwProgram[note.m_bPart];
            if (m_bDrums[note.m_bPart])
            {
                dwProgram |= F_INSTRUMENT_DRUMS;
            }
			if (m_fMono[note.m_bPart])
			{
				CVoice * pVoice = m_pSynth->m_VoicesInUse.GetHead();
				WORD nPart = note.m_bPart;
				for (;pVoice != NULL;pVoice = pVoice->GetNext())
				{
					if (pVoice->m_fNoteOn && (pVoice->m_nPart == nPart) &&
						(pVoice->m_pControl == this)) 
					{
						pVoice->StopVoice(note.m_stTime);
					}
				}
			}
			// While we are working with the instrument, including copying
			// the data over from the region, we have to make sure it
			// can not be removed from the instrument list.
			EnterCriticalSection(&m_pInstruments->m_CriticalSection);
            CInstrument * pInstrument = 
                m_pInstruments->GetInstrument(dwProgram,note.m_bKey);
            if (!pInstrument) 
			{
				if (dwProgram & F_INSTRUMENT_DRUMS)
				{
					dwProgram = F_INSTRUMENT_DRUMS;
					pInstrument = 
						m_pInstruments->GetInstrument(dwProgram,note.m_bKey);
				}
				else if (m_fXGActive)
				{
					if ((dwProgram & 0x7F0000) == 0x7F0000)	// Drum?
					{
						dwProgram &= 0x7F007F;				// Enforce 0 LSB
						pInstrument = 
							m_pInstruments->GetInstrument(dwProgram,note.m_bKey);
                        if (!pInstrument)
                        {
                            dwProgram = 0x7F0000;
						    pInstrument = 
							    m_pInstruments->GetInstrument(dwProgram,note.m_bKey);
                        }
					}
                    else
                    {
						dwProgram &= 0x7F;	// Fall back to GM set.
						pInstrument = 
							m_pInstruments->GetInstrument(dwProgram,note.m_bKey);
					}
				}
			}
            if (pInstrument != NULL)
            {
                CSourceRegion * pRegion = 
                    pInstrument->ScanForRegion(note.m_bKey);
                if (pRegion != NULL)
                {
                    WORD nPart = note.m_bPart;
                    CVoice * pVoice = m_pSynth->m_VoicesInUse.GetHead();
                    if (!pRegion->m_bAllowOverlap)
                    {
                        for (;pVoice != NULL; pVoice = pVoice->GetNext())
                        {
                            if ((pVoice->m_nPart == nPart) &&
                                (pVoice->m_nKey == note.m_bKey) &&
								(pVoice->m_pControl == this))
                            {
                                pVoice->QuickStopVoice(note.m_stTime);
                            }
                        }    
                    }

                    if (pRegion->m_bGroup != 0)
                    {
                        pVoice = m_pSynth->m_VoicesInUse.GetHead();
                        for (;pVoice != NULL;pVoice = pVoice->GetNext())
                        {
                            if ((pVoice->m_dwGroup == pRegion->m_bGroup) &&
                                (pVoice->m_nPart == nPart) &&
                                (pVoice->m_dwProgram == dwProgram) &&
								(pVoice->m_pControl == this))
                            {
                                pVoice->QuickStopVoice(note.m_stTime);
                            }
                        }
                    }
                    
                    pVoice = m_pSynth->m_VoicesFree.RemoveHead();
                    if (pVoice == NULL)
                    {
                        pVoice = m_pSynth->m_VoicesExtra.RemoveHead();
                    }

                    if (pVoice == NULL)
                    {
                        pVoice = m_pSynth->StealVoice(m_dwPriority[nPart]);
                    }

                    if (pVoice != NULL)
                    {
						PREL prPitch = m_prFineTune[nPart] + m_prScaleTune[nPart][note.m_bKey % 12];
						if (!m_bDrums[nPart]) 
						{
							if (m_fXGActive)
							{
								if ((dwProgram & 0x7F0000) != 0x7F0000)
								{
									prPitch += m_prCoarseTune[nPart];
								}
							}
							else
							{
								prPitch += m_prCoarseTune[nPart];
							}
                        }
						pVoice->m_nKey = note.m_bKey;
                        pVoice->m_nPart = nPart;
                        pVoice->m_dwProgram = dwProgram;
                        pVoice->m_dwPriority = m_dwPriority[nPart];
						pVoice->m_pControl = this;

                        if (pVoice->StartVoice( m_pSynth,
                                                pRegion, note.m_stTime, 
                                                &m_ModWheel[nPart],     
                                                &m_PitchBend[nPart],
                                                &m_Expression[nPart],   
                                                &m_Volume[nPart],
                                                &m_Pan[nPart],          
                                                (WORD)note.m_bKey,
							                    (WORD)note.m_bVelocity, 
                                                m_vrMasterVolume, 
							                    prPitch))
                        {
                            pVoice->m_fInUse = TRUE;

                            m_pSynth->QueueVoice(pVoice);
                        }
                        else
                        {
                            m_pSynth->m_VoicesFree.AddHead(pVoice);
                        }
                    } 
                    else 
                    {
                        m_pSynth->m_BuildStats.dwNotesLost++;
                    }
                } 
                else 
                {
                    m_pSynth->m_BuildStats.dwNotesLost++;
                }
            } 
            else 
            {
                Trace(1, "No instrument/region was found for patch # %lx, note %ld\n",
                          dwProgram, (long) note.m_bKey);
            }
			LeaveCriticalSection(&m_pInstruments->m_CriticalSection);
        }
    }
}

/*****************************************************************************
 * CControlLogic::Flush()
 *****************************************************************************
 * Clears events and notes up to a given time.
 */
void CControlLogic::Flush(STIME stTime)
{
    DWORD dwIndex;
    ::EnterCriticalSection(&m_CriticalSection);
    if (!m_fEmpty)
    {        
        m_fEmpty = TRUE;
        for (dwIndex = 0;dwIndex < 16; dwIndex++)
        {
            m_fEmpty = m_ModWheel[dwIndex].FlushMIDI(stTime)
                && m_PitchBend[dwIndex].FlushMIDI(stTime)
                && m_Volume[dwIndex].FlushMIDI(stTime)
                && m_Expression[dwIndex].FlushMIDI(stTime)
                && m_Pan[dwIndex].FlushMIDI(stTime);
        }
        m_Notes.FlushMIDI(stTime);
    }
    ::LeaveCriticalSection(&m_CriticalSection);
}

/*****************************************************************************
 * CControlLogic::RecordMIDI()
 *****************************************************************************
 * Record a MIDI short message into this channel group.  
 * This dispatches the different MIDI
 * messages to the different receptor objects.
 */
BOOL CControlLogic::RecordMIDI(STIME stTime,BYTE bStatus, BYTE bData1, BYTE bData2)
{
    WORD nPreChannel = bStatus & 0xF; 
    CNote note;
    bStatus = bStatus & 0xF0;
    BOOL bReturn = TRUE;
	WORD nPart;

    ::EnterCriticalSection(&m_CriticalSection);

    for (nPart = 0;nPart < 16; nPart++)
	{
		if (nPreChannel == m_bPartToChannel[nPart])
		{
			switch (bStatus)
			{
			case MIDI_NOTEOFF :
				bData2 = 0;
			case MIDI_NOTEON :
				note.m_bPart = (BYTE) nPart;
				note.m_bKey = bData1;
				note.m_bVelocity = bData2;
				bReturn = m_Notes.RecordNote(stTime,&note);
				break;
			case MIDI_CCHANGE :
				switch (bData1)
				{
				case CC_BANKSELECTH :
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_BANKSELECTH, bData2);
					break;
				case CC_MODWHEEL :
                    m_fEmpty = FALSE;
					bReturn = m_ModWheel[nPart].RecordMIDI(stTime,(long) bData2);
					break;
				case CC_VOLUME :
                    m_fEmpty = FALSE;
					bReturn = m_Volume[nPart].RecordMIDI(stTime,(long) bData2);
					break;
				case CC_PAN :
                    m_fEmpty = FALSE;
					bReturn = m_Pan[nPart].RecordMIDI(stTime,(long) bData2);
					break;
				case CC_EXPRESSION :
                    m_fEmpty = FALSE;
					bReturn = m_Expression[nPart].RecordMIDI(stTime,(long)bData2);
					break;
				case CC_BANKSELECTL :
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_BANKSELECTL, bData2);
					break;
				case CC_RESETALL:
                    m_fEmpty = FALSE;
					if (bData2)
					{
						bReturn = bReturn && m_Volume[nPart].RecordMIDI(stTime, 100);
						bReturn = bReturn && m_Pan[nPart].RecordMIDI(stTime, 64);
					}
					bReturn = bReturn && m_Expression[nPart].RecordMIDI(stTime, 127);
					bReturn = bReturn && m_PitchBend[nPart].RecordMIDI(stTime, 0x2000);
					bReturn = m_ModWheel[nPart].RecordMIDI(stTime, 0);
					bData2 = 0;
					// fall through into Sustain Off case....
        
				case CC_SUSTAIN :
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_SUSTAIN, bData2);
					break;
				case CC_ALLSOUNDSOFF:
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_SOUNDSOFF, 0);
					break;
				case CC_ALLNOTESOFF:
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_ALLOFF, 0);
					break;
				case CC_DATAENTRYMSB:
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_DATAENTRYMSB, bData2);
					break;
				case CC_DATAENTRYLSB:
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_DATAENTRYLSB, bData2);
					break;
				case CC_NRPN_LSB :
				case CC_NRPN_MSB :
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_NRPN, bData2);
					break;
				case CC_RPN_LSB:
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_RPN_LSB, bData2);
					break; 
				case CC_RPN_MSB:
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_RPN_MSB, bData2);
					break;
				case CC_MONOMODE :
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_MONOMODE, bData2);
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_SOUNDSOFF, 0);
					break;
				case CC_POLYMODE :
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_CC_POLYMODE, bData2);
					bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_SOUNDSOFF, 0);
					break;
				default:
					break;
				}
				break;

			case MIDI_PCHANGE :
				bReturn = m_Notes.RecordEvent(stTime, nPart, NOTE_PROGRAMCHANGE, bData1);
				break;
        
			case MIDI_PBEND :
                m_fEmpty = FALSE;
				{
					WORD nBend;
					nBend = bData2 << 7;
					nBend |= bData1;
					bReturn = m_PitchBend[nPart].RecordMIDI(stTime,(long)nBend);
				}
				break;
			}
		}
	}
    ::LeaveCriticalSection(&m_CriticalSection);

    return bReturn;
}

/*****************************************************************************
 * CControlLogic::RecordSysEx()
 *****************************************************************************
 * Record a MIDI SysEx message into this channel group.  
 * This dispatches the different MIDI
 * messages to the different receptor objects.
 */
HRESULT	CControlLogic::RecordSysEx(DWORD dwSysExLength,BYTE *pSysExData, STIME stTime)
{
	HRESULT hSuccess = S_OK;
	int nPart;
	int nTune;
	DWORD dwAddress;
	
    BOOL fClearAll = FALSE;
	BOOL fResetPatches = FALSE;
	if (dwSysExLength < 6)
    {
        return E_FAIL;
    }

	switch (pSysExData[1])	// ID number
	{
	case 0x7E :	// General purpose ID
		if (pSysExData[3] == 0x09) 
		{
			GMReset();
			fClearAll = TRUE;
			fResetPatches = TRUE;
		}
		break;
	case 0x7F : // Real time ID
		if (pSysExData[3] == 0x04)
		{
			if (pSysExData[4] == 1)	// Master Volume
			{
				m_Notes.RecordEvent(stTime, 0, NOTE_MASTERVOLUME, pSysExData[6]);
			}
		}
		break;
	case 0x41 : // Roland
		if (dwSysExLength < 11)
        {
            return E_FAIL;
        }
		if (pSysExData[3] != 0x42) break;
		if (pSysExData[4] != 0x12) break;
		nPart = pSysExData[6] & 0xF;
		dwAddress = (pSysExData[5] << 16) |
			((pSysExData[6] & 0xF0) << 8) | pSysExData[7];
		switch (dwAddress)
		{
		case 0x40007F :		// GS Reset.
			GMReset();
			m_fXGActive = FALSE;
			fClearAll = TRUE;
			m_fGSActive = TRUE;
			fResetPatches = TRUE;
			break;
		case 0x401002 :		// Set Receive Channel.
			if (m_fGSActive)
			{
				if (pSysExData[8])
				{
					m_Notes.RecordEvent(stTime, nPart, NOTE_ASSIGNRECEIVE, pSysExData[8] - 1);
				}
			}
			break;
		case 0x401015 :		// Use for Rhythm.
			if (m_fGSActive)
			{
				m_bDrums[nPart] = pSysExData[8];
				fClearAll = TRUE;
			}
			break;
		case 0x401040 :		// Scale Tuning.
			if (m_fGSActive)
			{
				for (nTune = 0;nTune < 12; nTune++)
				{
					if (pSysExData[9 + nTune] & 0x80) break;
					m_prScaleTune[nPart][nTune] = 
						(PREL) pSysExData[8 + nTune] - (PREL) 64;
				}
			}
			break;
		}
		break;
	case 0x43 : // Yamaha
		if ((pSysExData[3] == 0x4C) &&
			(pSysExData[4] == 0) &&
			(pSysExData[5] == 0) &&
			(pSysExData[6] == 0x7E) &&
			(pSysExData[7] == 0))
		{	// XG System On
			m_fXGActive = TRUE;
			m_fGSActive = FALSE;
			GMReset();
			m_fXGActive = TRUE;
			m_bDrums[0] = 0;
			m_bBankH[0] = 127;
			fClearAll = TRUE;
			fResetPatches = TRUE;
		}
		break;
	}
	if (fClearAll)
	{
		m_pSynth->AllNotesOff();
		Flush(0);
		for (nPart = 0;nPart < 16;nPart++)
		{        
			m_Notes.RecordEvent(stTime, nPart, NOTE_SUSTAIN, 0);
			m_Volume[nPart].RecordMIDI(stTime, 100);
			m_Pan[nPart].RecordMIDI(stTime, 64);
			m_Expression[nPart].RecordMIDI(stTime, 127);
			m_PitchBend[nPart].RecordMIDI(stTime, 0x2000);
			m_ModWheel[nPart].RecordMIDI(stTime, 0);
		}
	}
	if (fResetPatches)
	{
		for (nPart = 0;nPart < 16;nPart++)
		{     
			if ((nPart == 0) && (m_fXGActive))
			{
				m_Notes.RecordEvent(stTime-1, nPart, NOTE_CC_BANKSELECTH, 127);
			}
			else
			{
				m_Notes.RecordEvent(stTime-1, nPart, NOTE_CC_BANKSELECTH, 0);
			}
			m_Notes.RecordEvent(stTime-1, nPart, NOTE_CC_BANKSELECTL, 0);
			m_Notes.RecordEvent(stTime, nPart, NOTE_PROGRAMCHANGE, 0);
		}
	}

	return hSuccess;
}

/*****************************************************************************
 * CControlLogic::SetChannelPriority()
 *****************************************************************************
 * Set the priority for a given channel, within this channel group.
 */
HRESULT	CControlLogic::SetChannelPriority(DWORD dwChannel,DWORD dwPriority)
{
    DWORD dwPart;
	for (dwPart = 0;dwPart < 16; dwPart++)
	{
		if (m_bPartToChannel[dwPart] == dwChannel)
		{
        	m_dwPriority[dwPart] = dwPriority;
        }
	}
	return S_OK;
}

/*****************************************************************************
 * CControlLogic::GetChannelPriority()
 *****************************************************************************
 * Retrieve the priority for a given channel, within this channel group.
 */
HRESULT	CControlLogic::GetChannelPriority(DWORD dwChannel,LPDWORD pdwPriority)
{
    DWORD dwPart;
	for (dwPart = 0;dwPart < 16; dwPart++)
	{
		if (m_bPartToChannel[dwPart] == dwChannel)
		{
        	*pdwPriority = m_dwPriority[dwPart];
			break;
        }
	}
	return S_OK;
}

Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS