⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 musicsys.cpp

📁 游戏编程精粹2第六章源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	// (a more sophisticated pan function would do a dynmaic update of this track's voices)
	pTrack->m_State.m_Pan = nValue;

	TextBoxes_Output_Printf( OUTPUTMODE_EVENTS, "Pan = %3d tick = %d\n",
		nValue, pMSS->m_nWorkTick);
}

void SetInstrument_Function( MusicSequencerSystem_t *pMSS, Track_t *pTrack )
{
	EventData_t *pEventData = *pTrack->m_iEDPL;

	int nInstrument = pEventData->GetEventDataByte( 0 );
	InstrumentData_t *pInstrumentData = pMSS->FindInstrumentData( nInstrument );
	if( pInstrumentData )
	{
		pTrack->m_pInstrumentData = pInstrumentData;
	}

	TextBoxes_Output_Printf( OUTPUTMODE_EVENTS, "SetInstrument = %3d tick = %d\n",
		nInstrument, pMSS->m_nWorkTick);
}

void TrackEnd_Function( MusicSequencerSystem_t *pMSS, Track_t *pTrack )
{
	// we just loop to the beginning by doing this
	pTrack->m_iEDPL = pTrack->m_iEDPLStart;

	TextBoxes_Output_Printf( OUTPUTMODE_EVENTS, "TrackEnd tick = %d\n", pMSS->m_nWorkTick);
}

MusicSequencerSystem_t::EventFuncPtr_t MusicSequencerSystem_t::ms_aFP[EVENT_TYPE_COUNT] = {
	NoteOff_Function,
	NoteOn_Function,
	SetPan_Function,
	SetInstrument_Function,
	TrackEnd_Function,
};

bool MusicSequencerSystem_t::Update()
{
	CheckForFinishedVoices();

	PerformTargetStateChanges();

	SequencePtrList_t::iterator iSPL;
	for( iSPL = m_ActiveSequencePtrList.begin(); iSPL != m_ActiveSequencePtrList.end(); ++iSPL )
	{
		Sequence_t *pSequence = *iSPL;
		pSequence->m_TimeElapsedFrac += pSequence->m_TimeStep;
		TimeInt_t TimeAdd = pSequence->m_TimeElapsedFrac >> 16;
		pSequence->m_TimeElapsedFrac &= 0xffff;

		TrackPtrList_t::iterator iTPL;
		for( iTPL = pSequence->m_TrackPtrList.begin(); iTPL != pSequence->m_TrackPtrList.end(); ++iTPL )
		{
			Track_t *pTrack = *iTPL;
			pTrack->m_TimeElapsedInt += TimeAdd;

			EventData_t *pEventData = *pTrack->m_iEDPL;

			while( pEventData->m_nEventTime <= pTrack->m_TimeElapsedInt )
			{
				pTrack->m_TimeElapsedInt -= pEventData->m_nEventTime;

				// execute the event if it is a valid command
				u32 nCommand = pEventData->GetRuntimeCommand();
				if( nCommand < EVENT_TYPE_COUNT )
				{
					// this looks weird I know, but this calls the function we want
					// sure, we could use a switch statement, but if we add tons of
					// commands to our sequencer, this is a better way
					ms_aFP[nCommand](this,pTrack);
				}
				if( nCommand != EVENT_TYPE_TRACKEND )
				{
					++pTrack->m_iEDPL;
				}

				pEventData = *pTrack->m_iEDPL;
			}
		}
	}

#if 0
	// this is test code that plays instrument zero every 80 updates
	static int nCount = 0;
	nCount++;
	int offsetTime, releaseTime;
	offsetTime = ((int)CSyn_GetTickRate( m_CSynContext )) / 2;

	int pitch = 60;
	CSynFixedPoint frequency = CSynConvert_PitchToFrequency( ConvertIntegerToFixed( pitch ) );
	CSynFixedPoint amplitude = CSynConvert_VelocityToAmplitude( ConvertIntegerToFixed( 64 ) );

	CSynErr result;
	if( nCount > 80 )
	{
		TextBoxes_Output_Printf("Scheduled Beat at = %d\n", m_nWorkTick);
		InstrumentData_t *pInstrumentData = FindInstrumentData( 0 );
		if( pInstrumentData )
		{
			int nType = pInstrumentData->GetType();
			Voice_t *pVoice = MakeActiveVoice( nType );
			if( pVoice )
			{
				result = CSynVoice_SetSound( pVoice->m_SynVoice, pInstrumentData->GetCSynSound() );
				TEST_ERROR(result, "CSynVoice_SetSound");

				/* Schedule noteOn in immediate future. */
				result = CSynVoice_NoteOn( pVoice->m_SynVoice, m_nWorkTick, frequency, amplitude );
				TEST_ERROR(result, "CSynVoice_NoteOn");

				/* Schedule noteOff slightly later. */
				result = CSynVoice_NoteOff( pVoice->m_SynVoice, m_nWorkTick + offsetTime, &releaseTime );
				TEST_ERROR(result, "CSynVoice_NoteOn");
				pVoice->m_nReleaseTick = releaseTime + m_nWorkTick;
				TextBoxes_Output_Printf("WorkTick = %d\n", m_nWorkTick);
				TextBoxes_Output_Printf("ReleaseTime = %d\n", releaseTime);
			
			}
		}
		nCount = 0;
	}
#endif
	return true;
}

bool MusicSequencerSystem_t::Shutdown()
{
	// CSyn Shutdown
	//UnloadInstruments(); // also deletes the CSynSounds
	//UnloadSequences();

	/* Stop the engine when we are done. */
	if( m_CSynMix ) CSynMix_Delete( m_CSynMix ); /* Delete everything. */

	CSyn_StopEngine( m_CSynContext  );

	CSyn_DeleteContext( m_CSynContext );

	return true;
}

bool MusicSequencerSystem_t::LoadInstrument( InstrumentData_t *pInstrumentData )
{
	CSynErr result;
	CSynSound sound;
	AudioSample *pAudioSample;

	int nID = pInstrumentData->GetID();

	// only load if the nID is not already in the map
	if( m_IntToInstrumentDataPtrMap.find( nID ) == m_IntToInstrumentDataPtrMap.end() )
	{
		// load to appropriate CSyn architecture
		int nType = pInstrumentData->GetType();

		switch( nType )
		{
		case 0:
			/* Load sound template that we can use to make voices. */
			result = CSynSound_Load( m_CSynMix, CIRCTYPE_BASIC_SAMPLER, pInstrumentData->GetFileName().c_str(), &sound );
			TEST_ERROR(result, "CSynSound_Load");
			if( result < 0 ) return false;

			pInstrumentData->SetCSynSound( sound );

			pAudioSample = CSynSound_GetAudioSample( sound );
			pInstrumentData->SetSampleInfoPtr( pAudioSample );
			// some of the stuff available
			// pAudioSample->sampleRate;
			// pAudioSample->bitsPerSample;
			// pAudioSample->baseNote;
			// pAudioSample->detune;
			// pAudioSample->highNote;
			// pAudioSample->lowNote;
			// pAudioSample->highVelocity;
			// pAudioSample->lowVelocity;

			break;
		case 1:
			/* Load sound template that we can use to make voices. */
			result = CSynSound_Load( m_CSynMix, CIRCTYPE_AMPENV_SAMPLER, pInstrumentData->GetFileName().c_str(), &sound );
			TEST_ERROR(result, "CSynSound_Load");
			if( result < 0 ) return false;

			pInstrumentData->SetCSynSound( sound );

			pAudioSample = CSynSound_GetAudioSample( sound );
			pInstrumentData->SetSampleInfoPtr( pAudioSample );
			// some of the stuff available
			// pAudioSample->sampleRate;
			// pAudioSample->bitsPerSample;
			// pAudioSample->baseNote;
			// pAudioSample->detune;
			// pAudioSample->highNote;
			// pAudioSample->lowNote;
			// pAudioSample->highVelocity;
			// pAudioSample->lowVelocity;

			break;
		default:
			return false;
		}

		// put this nID in our map
		m_IntToInstrumentDataPtrMap[nID] = pInstrumentData;
	}

	return true;
}

void MusicSequencerSystem_t::SetSlowInstrumentEnvelope( int nID )
{
	CSynErr result;
	InstrumentData_t *pInstrumentData = FindInstrumentData( nID );
	if( pInstrumentData )
	{
		EnvelopeFrame frames[] = {
			{ 0.0, 0.0 }, // force it to start at zero so we get full attack
			{ 0.3, 1.0 }, // attack frame
			{ 0.2, 0.5 }, // decay and sustain here
			{ 1.0, 0.0 }  // slow release frame
		};
		CSynEnvelopeInfo     envInfo =
		{
			frames, sizeof(frames)/sizeof(EnvelopeFrame),
			2, 0,  /* Sustain before frames[2] */
			-1, 0,
			0
		};
		result = CSynSound_SetAmpEnvelope( pInstrumentData->GetCSynSound(), &envInfo );
		TEST_ERROR(result, "CSynSound_SetAmpEnvelope");
	}
}

InstrumentData_t *MusicSequencerSystem_t::FindInstrumentData( int nID )
{
	IntToInstrumentDataPtrMap_t::iterator iIIDPM;
	if( (iIIDPM = m_IntToInstrumentDataPtrMap.find( nID )) != m_IntToInstrumentDataPtrMap.end() )
	{
		return (*iIIDPM).second;
	}
	return 0;
}

bool MusicSequencerSystem_t::UnloadInstruments()
{
	// delete all from our map
	IntToInstrumentDataPtrMap_t::iterator iIIDPM;
	for( iIIDPM = m_IntToInstrumentDataPtrMap.begin(); iIIDPM != m_IntToInstrumentDataPtrMap.end(); ++iIIDPM )
	{
		delete (*iIIDPM).second;
	}
	// clear the pairs
	m_IntToInstrumentDataPtrMap.clear();
	return true;
}

bool MusicSequencerSystem_t::LoadSequence( SequenceData_t *pSequenceData )
{
	int nID = pSequenceData->GetID();

	// only load if the nID is not already in the map
	if( m_IntToSequenceDataPtrMap.find( nID ) == m_IntToSequenceDataPtrMap.end() )
	{
		if( !pSequenceData->Load( pSequenceData->GetFileName().c_str() ) )
		{
			return false;
		}
		// put this nID in our map
		m_IntToSequenceDataPtrMap[nID] = pSequenceData;

		return true;
	}

	return false;
}

void MusicSequencerSystem_t::SetSequenceMixes( SequenceData_t *pSequenceData, IntVectorVector_t *pTrackVolumeVectorVector )
{
	if( pSequenceData )
	{
		pSequenceData->m_pTrackVolumeVectorVector = pTrackVolumeVectorVector;
	}
}

SequenceData_t *MusicSequencerSystem_t::FindSequenceData( int nID )
{
	IntToSequenceDataPtrMap_t::iterator iISDPM;
	if( (iISDPM = m_IntToSequenceDataPtrMap.find( nID )) != m_IntToSequenceDataPtrMap.end() )
	{
		return (*iISDPM).second;
	}
	return 0;
}

bool MusicSequencerSystem_t::UnloadSequences()
{
	// delete all from our map
	IntToSequenceDataPtrMap_t::iterator iISDPM;
	for( iISDPM = m_IntToSequenceDataPtrMap.begin(); iISDPM != m_IntToSequenceDataPtrMap.end(); ++iISDPM )
	{
		delete (*iISDPM).second;
	}
	// clear the pairs
	m_IntToSequenceDataPtrMap.clear();
	return true;
}

bool MusicSequencerSystem_t::PlaySequence( int nID, int nMixID )
{
	SequenceData_t *pSequenceData = FindSequenceData( nID );
	if( !pSequenceData )
	{
		// if not found, return false
		return false;
	}

	Sequence_t *pSequence = MakeActiveSequence();
	if( !pSequence )
	{
		// if not available, return false
		return false;
	}

	pSequence->m_nID = nID;
	pSequence->m_pTrackVolumeVectorVector = pSequenceData->m_pTrackVolumeVectorVector;
	pSequence->m_Ppq = pSequenceData->GetPpq();
	pSequence->m_State.m_Tempo = pSequenceData->GetTempo();
	pSequence->m_TimeElapsedFrac = 0;
	pSequence->m_TimeStep = CalcTimeStep( pSequence->m_State.m_Tempo, pSequence->m_Ppq, MUSICSYS_UPDATES_PER_SECOND );

	TrackDataPtrList_t::iterator iTDPL;
	for( iTDPL = pSequenceData->m_TrackDataPtrList.begin(); iTDPL != pSequenceData->m_TrackDataPtrList.end(); ++iTDPL )
	{
		TrackData_t *pTrackData = *iTDPL;

		if( !pTrackData->IsTempoTrack() )
		{
			Track_t *pTrack = MakeActiveTrack();
			if( !pTrack ) break;
			pTrack->m_pOwner = pSequence;
			pTrack->m_TimeElapsedInt = 0;
			pTrack->m_iEDPL = pTrack->m_iEDPLStart = pTrackData->m_EventDataPtrList.begin();
			pTrack->m_iEDPLEnd = pTrackData->m_EventDataPtrList.end();
			pTrack->m_pInstrumentData = FindInstrumentData( 0 );
			pSequence->m_TrackPtrList.push_back( pTrack );
		}
	}

	pSequence->SetMix( nMixID );

	return false;
}

void MusicSequencerSystem_t::UpdateSequenceMix( int nID, int nMixID )
{

	SequencePtrList_t::iterator iSPL;
	for( iSPL = m_ActiveSequencePtrList.begin(); iSPL != m_ActiveSequencePtrList.end(); ++iSPL )
	{
		Sequence_t *pSequence = *iSPL;
		if( pSequence->m_nID == nID )
		{
			pSequence->SetTargetMix( nMixID );
		}
	}
}

void Track_AllNotesOff( MusicSequencerSystem_t *pMSS, Track_t *pTrack )
{
	CSynErr result;
	int releaseTime;

	// find all voices to send a note off to
	VoicePtrList_t::iterator iVPL;
	for( iVPL = pTrack->m_VoicePtrList.begin(); iVPL != pTrack->m_VoicePtrList.end(); ++iVPL )
	{
		Voice_t *pVoice = *iVPL;
		if( !pVoice->m_nReleaseTick )
		{
			result = CSynVoice_NoteOff( pVoice->m_SynVoice, pMSS->m_nWorkTick, &releaseTime );
			TEST_ERROR(result, "CSynVoice_NoteOff");

			pVoice->m_nReleaseTick = releaseTime + pMSS->m_nWorkTick;
			TextBoxes_Output_Printf( OUTPUTMODE_RELEASES, "NoteOff Key = %3d relTime = %d tick = %d\n",
				pVoice->m_nKey, releaseTime, pMSS->m_nWorkTick);
		}
	}

	TextBoxes_Output_Printf( OUTPUTMODE_EVENTS, "AllNotesOff WorkTick = %d\n", pMSS->m_nWorkTick);
}

void MusicSequencerSystem_t::StopSequences()
{
	SequencePtrList_t::iterator iSPL;
	iSPL = m_ActiveSequencePtrList.begin();
	while( iSPL != m_ActiveSequencePtrList.end() )
	{
		Sequence_t *pSequence = *iSPL;
		++iSPL;

		TrackPtrList_t::iterator iTPL;
		iTPL = pSequence->m_TrackPtrList.begin();
		while( iTPL != pSequence->m_TrackPtrList.end() )
		{
			Track_t *pTrack = *iTPL;
			++iTPL;

			VoicePtrList_t::iterator iVPL;
			iVPL = pTrack->m_VoicePtrList.begin();
			while( iVPL != pTrack->m_VoicePtrList.end() )
			{
				Voice_t *pVoice = *iVPL;
				++iVPL;

				if( !pVoice->m_nReleaseTick )
				{
					Track_AllNotesOff( this, pTrack );
					pTrack->m_VoicePtrList.remove( pVoice );
					FreeActiveVoice( pVoice );
				}
			}

			pSequence->m_TrackPtrList.remove( pTrack );
			FreeActiveTrack( pTrack );
		}

		FreeActiveSequence( pSequence );
	}
}

Sequence_t *MusicSequencerSystem_t::MakeActiveSequence()
{
	if( m_FreeSequencePtrList.size() > 0 )
	{
		Sequence_t *pSequence = m_FreeSequencePtrList.front();
		m_FreeSequencePtrList.pop_front();
		pSequence->m_bActive = true;
		m_ActiveSequencePtrList.push_back( pSequence );
		return pSequence;
	}
	return 0;
}

void MusicSequencerSystem_t::FreeActiveSequence( Sequence_t *pSequence )
{
	m_ActiveSequencePtrList.remove( pSequence );
	pSequence->m_bActive = false;
	m_FreeSequencePtrList.push_back( pSequence );
}

Track_t *MusicSequencerSystem_t::MakeActiveTrack()
{
	if( m_FreeTrackPtrList.size() > 0 )
	{
		Track_t *pTrack = m_FreeTrackPtrList.front();
		m_FreeTrackPtrList.pop_front();
		pTrack->m_bActive = true;
		m_ActiveTrackPtrList.push_back( pTrack );
		return pTrack;
	}
	return 0;
}

void MusicSequencerSystem_t::FreeActiveTrack( Track_t *pTrack )
{
	m_ActiveTrackPtrList.remove( pTrack );
	pTrack->m_bActive = false;
	m_FreeTrackPtrList.push_back( pTrack );
}

Voice_t *MusicSequencerSystem_t::MakeActiveVoice( int nVoiceArchitectureType )
{
	if( m_FreeVoicePtrListVector[nVoiceArchitectureType].size() > 0 )
	{
		Voice_t *pVoice = m_FreeVoicePtrListVector[nVoiceArchitectureType].front();
		m_FreeVoicePtrListVector[nVoiceArchitectureType].pop_front();
		pVoice->m_bActive = true;
		pVoice->m_nReleaseTick = 0;
		m_ActiveVoicePtrListVector[nVoiceArchitectureType].push_back( pVoice );
		return pVoice;
	}
	return 0;
}

void MusicSequencerSystem_t::FreeActiveVoice( Voice_t *pVoice )
{
	int nVoiceArchitectureType = pVoice->m_nVoiceArchitectureType;
	m_ActiveVoicePtrListVector[nVoiceArchitectureType].remove( pVoice );
	pVoice->m_bActive = false;
	m_FreeVoicePtrListVector[nVoiceArchitectureType].push_back( pVoice );
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -