#include #include "munga.h" #pragma hdrstop #include "audseq.h" #include "objstrm.h" #include "namelist.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlEvent ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // //############################################################################# //############################################################################# // AudioControlEvent::AudioControlEvent( AudioTick start_tick, AudioControlID audio_control_ID, AudioControlValue audio_control_value ): Plug(AudioControlEventClassID) { startTick = start_tick; audioControlID = audio_control_ID; audioControlValue = audio_control_value; } // //############################################################################# //############################################################################# // AudioControlEvent::AudioControlEvent(): Plug(AudioControlEventClassID) { startTick = 0; audioControlID = NullAudioControlID; audioControlValue = 0.0f; } // //############################################################################# //############################################################################# // AudioControlEvent::~AudioControlEvent() { } // //############################################################################# //############################################################################# // Logical AudioControlEvent::TestInstance() const { Plug::TestInstance(); Verify( (Enumeration)audioControlID >= (Enumeration)0 && (Enumeration)audioControlID < (Enumeration)AudioControlIDCount ); return True; } // //############################################################################# //############################################################################# // void AudioControlEvent::Send(AudioComponent *audio_component) { Check(this); Check(audio_component); if (getenv("BT_AUDIO_SPATIAL")) { static int s_ev=0; if (s_ev++<200) DEBUG_STREAM << "[seqev] tgt=" << (void*)audio_component << " ctl=" << (int)audioControlID << "/" << audioControlValue << "\n" << std::flush; } audio_component->ReceiveControl(audioControlID, audioControlValue); } // //############################################################################# //############################################################################# // Logical AudioControlEvent::Chase(AudioComponent *audio_component) { Check(this); Check(audio_component); switch (audioControlID) { case StartAudioControlID: return False; case StopAudioControlID: Send(audio_component); return False; default: break; } return True; } // //############################################################################# //############################################################################# // MemoryStream& MemoryStream_Read( MemoryStream *stream, AudioControlEvent *control_event ) { Check(stream); Check_Signature(control_event); MemoryStream_Read(stream, &control_event->startTick); MemoryStream_Read(stream, &control_event->audioControlID); MemoryStream_Read(stream, &control_event->audioControlValue); Check(control_event); return *stream; } // //############################################################################# //############################################################################# // MemoryStream& MemoryStream_Write( MemoryStream *stream, const AudioControlEvent *control_event ) { Check(stream); Check(control_event); MemoryStream_Write(stream, &control_event->startTick); MemoryStream_Write(stream, &control_event->audioControlID); MemoryStream_Write(stream, &control_event->audioControlValue); return *stream; } // //############################################################################# //############################################################################# // std::ostream& operator << (std::ostream &strm, const AudioControlEvent &control_event) { Check(&control_event); strm << "[" ; strm << control_event.startTick << ","; strm << control_event.audioControlID << ","; strm << control_event.audioControlValue; strm << "]"; return strm; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlSequence ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // //############################################################################# //############################################################################# // AudioControlSequence::AudioControlSequence( PlugStream *stream, Entity *entity ): AudioComponent(stream), audioComponentSocket(NULL), audioControlEventSocket(NULL) { Logical dump_value; Logical is_looped; AudioComponent *audio_component; AudioControlEvent *audio_control_event; CollectionSize i, number_of_control_events; AudioDivisionsPerBeat divisions_per_beat; AudioTempo tempo; MemoryStream_Read(stream, &dump_value); MemoryStream_Read(stream, &is_looped); PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component); MemoryStream_Read(stream, &divisions_per_beat); MemoryStream_Read(stream, &tempo); MemoryStream_Read(stream, &number_of_control_events); for (i = 0; i < number_of_control_events; i++) { audio_control_event = new AudioControlEvent; Register_Object(audio_control_event); MemoryStream_Read(stream, audio_control_event); audioControlEventSocket.Add(audio_control_event); } AudioControlSequenceX( audio_component, entity, is_looped, divisions_per_beat, tempo, dump_value ); } // //############################################################################# //############################################################################# // #if DEBUG_LEVEL>0 void AudioControlSequence::AudioControlSequenceX( AudioComponent *audio_component, Entity *entity, Logical is_looped, AudioDivisionsPerBeat divisions_per_beat, AudioTempo the_tempo, Logical dump_value ) #else void AudioControlSequence::AudioControlSequenceX( AudioComponent *audio_component, Entity *entity, Logical is_looped, AudioDivisionsPerBeat divisions_per_beat, AudioTempo the_tempo, Logical ) #endif { Check(audio_component); audioComponentSocket.Add(audio_component); isLooped = is_looped; isRunning = False; startTime = AudioTime::Null; audioControlEventIterator = NULL; divisionsPerBeat = divisions_per_beat; tempo = the_tempo; #if DEBUG_LEVEL>0 dumpValue = dump_value; #endif audio_component->AddWatcher(this); Check(entity); entity->AddAudioComponent(this); } // //############################################################################# //############################################################################# // AudioControlSequence::~AudioControlSequence() { StopSequence(); Verify(!isRunning); Verify(audioControlEventIterator == NULL); AudioControlEventIterator iterator(&audioControlEventSocket); Check(&iterator); iterator.DeletePlugs(); } // //############################################################################# //############################################################################# // void AudioControlSequence::BuildFromPage( PlugStream *stream, NameList *name_list, ClassID class_ID, ObjectID object_ID ) { AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID); MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, dump_value); MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, is_looped); // // Write audio component // CString audio_component_name("audio_component"); PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name); // // Read tempo // AudioTempo tempo = 100; if (name_list->FindData("tempo") != NULL) { Check_Pointer(name_list->FindData("tempo")); Convert_From_Ascii((const char *)name_list->FindData("tempo"), &tempo); } // // Read midi file // DynamicMemoryStream midi_file_stream; { CString midi_file_name; Check_Pointer(name_list->FindData("midi_file")); midi_file_name = (const char*)name_list->FindData("midi_file"); std::ifstream input_midi_file(midi_file_name, std::ios::in | std::ios::binary); #if DEBUG_LEVEL>0 if (!input_midi_file) { Dump(midi_file_name); } #endif MemoryStream_Write(&midi_file_stream, &input_midi_file); midi_file_stream.Rewind(); } // // Parse midi stream // DynamicMemoryStream control_event_stream; CreateAudioControlEventStream midi_parser; Check(&midi_file_stream); Check(&control_event_stream); Check(&midi_parser); midi_parser.Parse(&midi_file_stream, &control_event_stream, tempo); control_event_stream.Rewind(); // // Write the divisions per beat and tempo // AudioDivisionsPerBeat divisions_per_beat; divisions_per_beat = midi_parser.GetDivisionsPerBeat(); tempo = midi_parser.GetTempo(); MemoryStream_Write(stream, &divisions_per_beat); MemoryStream_Write(stream, &tempo); // // Write control event stream // CollectionSize number_of_control_events; number_of_control_events = midi_parser.GetNumberOfEvents(); MemoryStream_Write(stream, &number_of_control_events); MemoryStream_Write(stream, &control_event_stream); } // //############################################################################# //############################################################################# // Logical AudioControlSequence::TestInstance() const { AudioComponent::TestInstance(); Check(&audioComponentSocket); Check(&audioControlEventSocket); if (isRunning) { Check(audioControlEventIterator); } else { Verify(audioControlEventIterator == NULL); } Verify(tempo >= 1 && tempo <= 600); return True; } // //############################################################################# //############################################################################# // void AudioControlSequence::StartSequence() { Check(this); // // If already running, stop sequence // if (isRunning) { StopSequence(); } // // Make an iterator for the control sequence // Verify(audioControlEventIterator == NULL); audioControlEventIterator = new AudioControlEventIterator(&audioControlEventSocket); Register_Object(audioControlEventIterator); startTime = AudioTime::Now(); isRunning = True; } // //############################################################################# //############################################################################# // void AudioControlSequence::StopSequence() { Check(this); // // If not running, return // if (!isRunning) return; // // Find next on or off event // AudioControlEvent *control_event; Check(audioControlEventIterator); while ((control_event = audioControlEventIterator->ReadAndNext()) != NULL) { Check(control_event); if (!control_event->Chase(audioComponentSocket.GetCurrent())) break; } // // Destroy the iterator for the control sequence // Unregister_Object(audioControlEventIterator); delete audioControlEventIterator; audioControlEventIterator = NULL; isRunning = False; } // //############################################################################# //############################################################################# // void AudioControlSequence::RunSequence() { Check(this); // // If the sequence is not running, then return // if (!isRunning) return; // // Play events which have a start time less then the // current time // AudioControlEvent *control_event; Check(audioControlEventIterator); control_event = audioControlEventIterator->GetCurrent(); while ( control_event != NULL && IsEventReady(control_event) ) { #if DEBUG_LEVEL>0 if (dumpValue) { Dump(*control_event); } #endif #if 0 // // HACK - convert start control to use duration // Verify(control_event->audioControlID != StopAudioControlID); if (control_event->audioControlID == StartAudioControlID) { // // Convert ticks to seconds // seconds = ticks / (divisionsPerBeat (t/b) * tempo (b/60s)) // Scalar denominator = (Scalar)divisionsPerBeat * (Scalar)tempo / 60.0f; Verify(!Small_Enough(denominator)); control_event->audioControlValue = control_event->audioControlValue / denominator; } #endif // // Send the controller to the connected audio component // Check(control_event); control_event->Send(audioComponentSocket.GetCurrent()); // // Step to next event // audioControlEventIterator->Next(); control_event = audioControlEventIterator->GetCurrent(); } // // If there are no more events to be played then stop running // if (control_event == NULL) { StopSequence(); if (isLooped) { StartSequence(); } } } // //############################################################################# //############################################################################# // void AudioControlSequence::ReceiveControl( AudioControlID control_ID, AudioControlValue control_value ) { Check(this); switch(control_ID) { case StartAudioControlID: StartSequence(); break; case StopAudioControlID: StopSequence(); break; case IdleAudioControlID: RunSequence(); break; case TempoAudioControlID: tempo = control_value; Verify(tempo >= 1 && tempo <= 600); break; default: break; } } // //############################################################################# //############################################################################# // Logical AudioControlSequence::IsEventReady(AudioControlEvent *audio_control_event) { Check(this); AudioTime offset_time(startTime); offset_time += CalculateEventSeconds(audio_control_event); return (offset_time <= AudioTime::Now()); } // //############################################################################# //############################################################################# // Scalar AudioControlSequence::CalculateEventSeconds( AudioControlEvent *audio_control_event ) { Check(this); Check(audio_control_event); // // Convert ticks to seconds // seconds = ticks / (divisionsPerBeat (t/b) * tempo (b/60s)) // Scalar denominator = (Scalar)divisionsPerBeat * (Scalar)tempo / 60.0f; Verify(!Small_Enough(denominator)); return (Scalar)audio_control_event->GetStartTick() / denominator; } //############################################################################# //#################### CreateAudioControlEventStream #################### //############################################################################# CreateAudioControlEventStream::CreateAudioControlEventStream(): audioControlEventSocket(NULL, False) { inputStream = NULL; outputStream = NULL; divisionsPerBeat = 120; tempo = 100; } // //############################################################################# //############################################################################# // CreateAudioControlEventStream::~CreateAudioControlEventStream(void) { AudioControlEventIterator iterator(&audioControlEventSocket); Check(&iterator); iterator.DeletePlugs(); } // //############################################################################# //############################################################################# // Logical CreateAudioControlEventStream::TestInstance() const { MidiParse::TestInstance(); Check(&audioControlEventSocket); return True; } // //############################################################################# //############################################################################# // void CreateAudioControlEventStream::Parse( MemoryStream *input_stream, MemoryStream *output_stream, SignedLongWord tempo_argument ) { Check(this); Check(input_stream); Check(output_stream); inputStream = input_stream; outputStream = output_stream; // // Parse the stream // tempo = tempo_argument; Verify(GetNumberOfEvents() == 0); MidiParse::Parse(); // // Write the events // AudioControlEventIterator iterator(&audioControlEventSocket); AudioControlEvent *control_event; Check(&iterator); while ((control_event = iterator.ReadAndNext()) != NULL) { Check(control_event); MemoryStream_Write(outputStream, control_event); } } // //############################################################################# //############################################################################# // CollectionSize CreateAudioControlEventStream::GetNumberOfEvents() { Check(this); AudioControlEventIterator iterator(&audioControlEventSocket); Check(&iterator); return iterator.GetSize(); } // //############################################################################# //############################################################################# // MidiParse::SignedWord CreateAudioControlEventStream::Mf_getc() { Check(this); unsigned char c; MemoryStream_Read(inputStream, &c); return c; } // //############################################################################# //############################################################################# // void CreateAudioControlEventStream::Mf_error(char *str) { Check(this); Check_Pointer(str); Fail(str); } // //############################################################################# //############################################################################# // void CreateAudioControlEventStream::Mf_header( SignedWord, SignedWord, SignedWord division ) { Check(this); divisionsPerBeat = division; } // //############################################################################# //############################################################################# // void CreateAudioControlEventStream::Mf_on( SignedWord channel, SignedWord pitch, SignedWord vol ) { Check(this); // // Interpret vol 0 as note off // if (vol == 0) { Mf_off(channel, pitch, vol); return; } // // Verify that last event was a stop // #if DEBUG_LEVEL>0 { AudioControlEventIterator iterator(&audioControlEventSocket); AudioControlEvent *last_control_event; iterator.Last(); if ((last_control_event = iterator.GetCurrent()) != NULL) { Check(last_control_event); Verify(last_control_event->audioControlID == StopAudioControlID); } } #endif AudioTick current_ticks = CurTime(); AudioControlEvent *audio_control_event; // // Add note value event // audio_control_event = new AudioControlEvent( current_ticks, NoteAudioControlID, (Scalar)pitch ); Register_Object(audio_control_event); audioControlEventSocket.AddValue(audio_control_event, current_ticks); // // Add velocity event // audio_control_event = new AudioControlEvent( current_ticks, AttackVolumeAudioControlID, (Scalar)vol / (Scalar)127 ); Register_Object(audio_control_event); audioControlEventSocket.AddValue(audio_control_event, current_ticks); // // Add start event // audio_control_event = new AudioControlEvent( current_ticks, StartAudioControlID, 0.0f ); Register_Object(audio_control_event); audioControlEventSocket.AddValue(audio_control_event, current_ticks); } // //############################################################################# //############################################################################# // void CreateAudioControlEventStream::Mf_off( SignedWord, SignedWord pitch, SignedWord ) { Check(this); AudioTick current_ticks = CurTime(); AudioControlEvent *audio_control_event; #if 0 // // HACK - convert start control to use duration // AudioControlEventIterator iterator(&audioControlEventSocket); iterator.Last(); audio_control_event = iterator.GetCurrent(); Check(audio_control_event); Verify(audio_control_event->audioControlID == StartAudioControlID); audio_control_event->audioControlValue = current_ticks - audio_control_event->startTick; #else // // Add note value event // audio_control_event = new AudioControlEvent( current_ticks, NoteAudioControlID, (Scalar)pitch ); Register_Object(audio_control_event); audioControlEventSocket.AddValue(audio_control_event, current_ticks); // // Add stop event // audio_control_event = new AudioControlEvent( current_ticks, StopAudioControlID, 0.0f ); Register_Object(audio_control_event); audioControlEventSocket.AddValue(audio_control_event, current_ticks); #endif } // //############################################################################# //############################################################################# // void CreateAudioControlEventStream::Mf_tempo(SignedLongWord) { Check(this); // tempo = i1; // HACK - Cakewalk appears to produce bogus tempo }