#include "munga.h" #pragma hdrstop #include "audsrc.h" #include "audrend.h" #include "objstrm.h" #include "app.h" #include "namelist.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioSourceStartState ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // //############################################################################# //############################################################################# // #define DEFAULT_NOTE (60) AudioSourceStartState::AudioSourceStartState() { noteValue = DEFAULT_NOTE; isDurationSet = False; hasDuration = False; duration = 0.0f; startTime = 0.0f; endTime = 0.0f; } // //############################################################################# //############################################################################# // AudioSourceStartState::~AudioSourceStartState() { } // //############################################################################# //############################################################################# // Logical AudioSourceStartState::TestInstance() const { if (isDurationSet || hasDuration) { Verify(duration >= 0.0f); } if (hasDuration) { Verify(endTime >= startTime); } return True; } // //############################################################################# //############################################################################# // void AudioSourceStartState::CalculateDuration(AudioControlValue control_value) { // // Calculate duration // if (control_value > 0.0f) { hasDuration = True; endTime = AudioTime::Now(); endTime += control_value; } else if (isDurationSet) { hasDuration = True; endTime = AudioTime::Now(); endTime += duration; isDurationSet = False; } else { hasDuration = False; endTime = 0.0f; } } #if 0 // //############################################################################# //############################################################################# // AudioTime AudioSourceStartState::GetCurrentRunningTime() { Check(this); AudioTime current_duration = AudioTime::Now(); return (current_duration -= startTime); } #endif //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioSource ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // //############################################################################# //############################################################################# // const Receiver::HandlerEntry AudioSource::MessageHandlerEntries[]= { { AudioSource::StartMessageID, "Start", (AudioSource::Handler)&AudioSource::StartMessageHandler }, { AudioSource::StopMessageID, "Stop", (AudioSource::Handler)&AudioSource::StopMessageHandler } }; AudioSource::MessageHandlerSet& AudioSource::GetMessageHandlers() { static AudioSource::MessageHandlerSet messageHandlers(ELEMENTS(AudioSource::MessageHandlerEntries), AudioSource::MessageHandlerEntries, AudioComponent::GetMessageHandlers()); return messageHandlers; } // //############################################################################# //############################################################################# // Derivation* AudioSource::GetClassDerivations() { static Derivation classDerivations(AudioComponent::GetClassDerivations(), "AudioSource"); return &classDerivations; } AudioSource::SharedData AudioSource::DefaultData( AudioSource::GetClassDerivations(), AudioSource::GetMessageHandlers() ); // //############################################################################# //############################################################################# // AudioSource::AudioSource( PlugStream *stream, Entity *entity ): AudioComponent(stream, DefaultData) { AudioResource *audio_resource; AudioLocation *audio_location; AudioSourcePriority priority; AudioSourceMixPresence mix_presence; AudioControlValue volume_mix_level; AudioPitchCents pitch_mix_offset; AudioControlValue brightness_mix_level; Logical has_compression_curve; Scalar seconds; AudioTime compression_duration; Logical use_brightness_scale; Logical use_attack_time_scale; PlugStream_ReadObjectIDAndFindPlug(stream, &audio_resource); PlugStream_ReadObjectIDAndFindPlug(stream, &audio_location); MemoryStream_Read(stream, &priority); MemoryStream_Read(stream, &mix_presence); MemoryStream_Read(stream, &volume_mix_level); MemoryStream_Read(stream, &pitch_mix_offset); MemoryStream_Read(stream, &brightness_mix_level); MemoryStream_Read(stream, &has_compression_curve); MemoryStream_Read(stream, &seconds); compression_duration = seconds; MemoryStream_Read(stream, &use_brightness_scale); MemoryStream_Read(stream, &use_attack_time_scale); AudioSourceX( audio_resource, audio_location, entity, priority, mix_presence, volume_mix_level, pitch_mix_offset, brightness_mix_level, has_compression_curve, compression_duration, use_brightness_scale, use_attack_time_scale ); } // //############################################################################# //############################################################################# // void AudioSource::BuildFromPage( PlugStream *stream, NameList *name_list, ClassID class_ID, ObjectID object_ID ) { AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID); // // Store fields // CString audio_resource_name("resource"); PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_resource_name); CString audio_location_name("location"); PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_location_name); MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, priority); MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, mix_presence); MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioControlValue, volume_mix_level); MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioPitchCents, pitch_mix_offset); MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioControlValue, brightness_mix_level); MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, has_compression_curve); MEM_STRM_WRITE_ENTRY(*stream, name_list, Scalar, compression_duration); MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, use_brightness_scale); MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, use_attack_time_scale); } // //############################################################################# //############################################################################# // void AudioSource::AudioSourceX( AudioResource *audio_resource, AudioLocation *audio_location, Entity *entity, AudioSourcePriority priority, AudioSourceMixPresence mix_presence, AudioControlValue volume_mix_level, AudioPitchCents pitch_mix_offset, AudioControlValue brightness_mix_level, Logical has_compression_curve, const AudioTime &compression_duration, Logical use_brightness_scale, Logical use_attack_time_scale ) { Check(audio_resource); Check(audio_location); Check(entity); audioLocation = audio_location; audioResource = audio_resource; audioSourceState = StoppedAudioSourceState; attackVolumeScale = 1.0f; useAttackTimeScale = use_attack_time_scale; attackTimeScale = 0.0f; audioSourcePriority = priority; audioSourceMixPresence = mix_presence; volumeCompressionScale = 1.0f; hasCompressionCurve = has_compression_curve; compressionDuration = compression_duration; volumeMixScale = volume_mix_level; pitchMixOffset = pitch_mix_offset; useBrightnessScale = use_brightness_scale; brightnessMixScale = brightness_mix_level; volumeScale = 1.0f; pitchOffset = 0.0f; brightnessScale = 1.0f; nextExecuteFrame = NullAudioFrameCount; suspendFinishedFrame = NullAudioFrameCount; entity->AddAudioComponent(this); } // //############################################################################# //############################################################################# // AudioSource::~AudioSource() { Verify(audioSourceState == StoppedAudioSourceState); } // //############################################################################# //############################################################################# // Logical AudioSource::TestInstance() const { AudioComponent::TestInstance(); return True; } // // Resource methods // // //############################################################################# //############################################################################# // void AudioSource::SetAudioResource(AudioResource *audio_resource) { Check(this); Check(audio_resource); Verify(audioSourceState == StoppedAudioSourceState); Check(audioResource); audioResource = audio_resource; } // // Current State/Status Accessors // // //############################################################################# //############################################################################# // void AudioSource::AssignAudioSourceState(AudioSourceState audio_source_state) { Check(this); // // Initialize the next start state if the source is now running // if (audio_source_state == RunningAudioSourceState) { AudioSourceStartState null_state; nextStartState = null_state; } audioSourceState = audio_source_state; } // // Mixing & Logical compression methods // // //############################################################################# //############################################################################# // AudioControlValue AudioSource::CalculateSourceCompressionEffect() { Check(this); // // Get current volume level // AudioControlValue current_volume_level; current_volume_level = CalculateSourceVolumeScale(); Verify(current_volume_level >= 0.0f && current_volume_level <= 1.0f); // // Calculate the amount of this to apply to compression // if (hasCompressionCurve) { // // scale = 1 / (1 + ((1/comp_dur) * duration)^2) // Scalar current_running_time = GetCurrentRunningTime(); Scalar compression_duration = compressionDuration; Scalar duration_factor; Scalar denominator; AudioControlValue compression_effect; Verify(!Small_Enough(compression_duration)); duration_factor = pow((1.0f/compression_duration) * current_running_time, 2.0f); // Warn(!(duration_factor > 0.0f)); denominator = 1.0f + duration_factor; Verify(!Small_Enough(denominator)); compression_effect = 1.0f / denominator; Verify(compression_effect >= 0.0f && compression_effect <=1.0f); return compression_effect * current_volume_level; } return current_volume_level; } // //############################################################################# //############################################################################# // AudioControlValue AudioSource::CalculateSourceVolumeScale() { Check(this); // // Execute the watchers that will update the volume related // member parameters // ExecuteWatchers(); // // Calculate the resulting volume scale // AudioControlValue volume_scale; volume_scale = volumeScale * volumeMixScale * volumeCompressionScale; Clamp(volume_scale, MinAudioVolume, MaxAudioVolume); return volume_scale; } // //############################################################################# //############################################################################# // AudioControlValue AudioSource::CalculateSourceBrightnessScale() { Check(this); AudioControlValue brightness_mix_scale; brightness_mix_scale = brightnessScale * brightnessMixScale; Clamp(brightness_mix_scale, MinAudioBrightness, MaxAudioBrightness); return brightness_mix_scale; } // //############################################################################# //############################################################################# // void AudioSource::ReceiveControl( AudioControlID control_ID, AudioControlValue control_value ) { Check(this); switch (control_ID) { // //---------------------------------------------------------------------- // StartAudioControlID //---------------------------------------------------------------------- // case StartAudioControlID: { StartMessage message(control_value); Check(application); Check(application->GetAudioRenderer()); application->GetAudioRenderer()->PostAudioRequestMessage( this, &message ); } break; // //---------------------------------------------------------------------- // StopAudioControlID //---------------------------------------------------------------------- // case StopAudioControlID: { StopMessage message; Check(application); Check(application->GetAudioRenderer()); application->GetAudioRenderer()->PostAudioRequestMessage( this, &message ); } break; // //---------------------------------------------------------------------- // Misc... //---------------------------------------------------------------------- // case VolumeAudioControlID: VolumeAudioHandler(control_value); break; case PitchAudioControlID: PitchAudioHandler(control_value); break; case BrightnessAudioControlID: BrightnessAudioHandler(control_value); break; case AttackVolumeAudioControlID: AttackVolumeAudioHandler(control_value); break; case AttackTimeAudioControlID: AttackTimeAudioHandler(control_value); break; case NoteAudioControlID: NoteAudioHandler(control_value); break; case DurationAudioControlID: DurationAudioHandler(control_value); break; case FlushMessagesAudioControlID: Check(application); Check(application->GetAudioRenderer()); application->GetAudioRenderer()->FlushAudioMessages(this); break; case NullAudioControlID: case IdleAudioControlID: break; default: Fail("AudioSource::ReceiveControl - Should never reach here"); break; } } // //############################################################################# //############################################################################# // void AudioSource::StartMessageHandler(StartMessage *message) { SET_AUDIO_RENDERER(); SET_AUDIO_RENDERER_START_HANDLER(); Check(this); Check(message); Verify(message->messageID == StartMessageID); // //-------------------------------------------------------------------------- // if double trigger condition exists // then return //-------------------------------------------------------------------------- // AudioTime double_trigger_cutoff(AudioDoubleTriggerCutoff); #if 0 double_trigger_cutoff = AudioDoubleTriggerCutoff; #endif if ( audioSourceState == RunningAudioSourceState && GetCurrentRunningTime() <= double_trigger_cutoff ) { #ifdef LAB_ONLY Check(application); Check(application->GetAudioRenderer()); application->GetAudioRenderer()->doubleTriggerCount++; #endif CLEAR_AUDIO_RENDERER_START_HANDLER(); CLEAR_AUDIO_RENDERER(); return; } // //-------------------------------------------------------------------------- // If the source is not stopped then stop it //-------------------------------------------------------------------------- // if (audioSourceState != StoppedAudioSourceState) { StopMessage stop_message; StopMessageHandler(&stop_message); } // //-------------------------------------------------------------------------- // Verify that the state is stopped // Copy the next start state into the current start state // Calculate duration //-------------------------------------------------------------------------- // Verify(audioSourceState == StoppedAudioSourceState); currentStartState = nextStartState; currentStartState.CalculateDuration(message->controlValue); // //-------------------------------------------------------------------------- // Implementation specific start request //-------------------------------------------------------------------------- // StartMessageImplementation(); CLEAR_AUDIO_RENDERER_START_HANDLER(); CLEAR_AUDIO_RENDERER(); } // //############################################################################# //############################################################################# // void #if DEBUG_LEVEL>0 AudioSource::StopMessageHandler(StopMessage *message) #else AudioSource::StopMessageHandler(StopMessage*) #endif { SET_AUDIO_RENDERER(); SET_AUDIO_RENDERER_STOP_HANDLER(); Check(this); Check(message); Verify(message->messageID == StopMessageID); // // if the source is stopped // then return // if (audioSourceState == StoppedAudioSourceState) { CLEAR_AUDIO_RENDERER_STOP_HANDLER(); CLEAR_AUDIO_RENDERER(); return; } // // Implementation specific stop request // StopMessageImplementation(); CLEAR_AUDIO_RENDERER_STOP_HANDLER(); CLEAR_AUDIO_RENDERER(); } // //############################################################################# //############################################################################# // void AudioSource::VolumeAudioHandler(AudioControlValue control_value) { Check(this); Clamp(control_value, MinAudioVolume, MaxAudioVolume); volumeScale = control_value / (MaxAudioVolume - MinAudioVolume); } // //############################################################################# //############################################################################# // void AudioSource::PitchAudioHandler(AudioControlValue control_value) { Check(this); pitchOffset = control_value; } // //############################################################################# //############################################################################# // void AudioSource::BrightnessAudioHandler(AudioControlValue control_value) { Check(this); Clamp(control_value, MinAudioBrightness, MaxAudioBrightness); brightnessScale = control_value / (MaxAudioBrightness - MinAudioBrightness); } // //############################################################################# //############################################################################# // void AudioSource::AttackVolumeAudioHandler(AudioControlValue control_value) { Check(this); Clamp(control_value, MinAudioAttack, MaxAudioAttack); attackVolumeScale = control_value / (MaxAudioAttack - MinAudioAttack); } // //############################################################################# //############################################################################# // void AudioSource::AttackTimeAudioHandler(AudioControlValue control_value) { Check(this); Clamp(control_value, MinAudioAttack, MaxAudioAttack); attackTimeScale = control_value / (MaxAudioAttack - MinAudioAttack); } // //############################################################################# //############################################################################# // void AudioSource::NoteAudioHandler(AudioControlValue control_value) { Check(this); nextStartState.SetNoteValue(control_value); } // //############################################################################# //############################################################################# // void AudioSource::DurationAudioHandler(AudioControlValue control_value) { Check(this); nextStartState.SetDurationValue(control_value); } // //############################################################################# //############################################################################# // void AudioSource::StartImplementation() { currentStartState.Start(); } // //############################################################################# //############################################################################# // void AudioSource::StopImplementation() { Fail("AudioSource::StopImplementation - Should never reach here"); } // //############################################################################# //############################################################################# // void AudioSource::SuspendImplementation() { StopImplementation(); Check(application); Check(application->GetAudioRenderer()); Check(audioResource); suspendFinishedFrame = application->GetAudioRenderer()->GetAudioFrameCount() + audioResource->GetSuspendDelay(); #ifdef LAB_ONLY application->GetAudioRenderer()->sourceSuspendCount++; #endif } // //############################################################################# //############################################################################# // void AudioSource::ResumeImplementation() { StartImplementation(); suspendFinishedFrame = NullAudioFrameCount; #ifdef LAB_ONLY Check(application); Check(application->GetAudioRenderer()); application->GetAudioRenderer()->sourceResumeCount++; #endif } // //############################################################################# //############################################################################# // void AudioSource::Execute() { Check(this); // // Execute source if this is the next execution frame // AudioRenderer *audio_renderer; Check(application); audio_renderer = application->GetAudioRenderer(); Check(audio_renderer); if (nextExecuteFrame <= audio_renderer->GetAudioFrameCount()) { nextExecuteFrame = audio_renderer->GetAudioFrameCount() + DefaultAudioFrameDelay; // // Update the sources spatial model // Execute inherited method // Execute this sources sound model // UpdateSpatialModel(audio_renderer->GetAudioHead()); AudioComponent::Execute(); ExecuteModel(False); } }