📄 musicsys.cpp
字号:
// (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 + -