void CMidiFile::WriteHeader(short Tracks, short PPQ, double Tempo, const TIME_SIGNATURE* TimeSig, const KEY_SIGNATURE* KeySig) { // write file header UINT ChunkID = MAKEFOURCC('M', 'T', 'h', 'd'); // header chunk ID Write(&ChunkID, sizeof(ChunkID)); // write chunk ID WriteInt(FILE_HEADER_LEN); // write chunk size WriteShort(MF_MULTI); // write MIDI file format WriteShort(Tracks + 1); // write track count; one extra for song track WriteShort(PPQ); // write pulses per quarter note // write song track FILE_POS StartPos = BeginTrack(); // write track header if (Tempo > 0) { // if tempo specified WriteMeta(ME_SET_TEMPO, TEMPO_LEN); // write meta header int mspq = round(60000000 / Tempo); // microseconds per quarter note BYTE TempoBuf[TEMPO_LEN]; Reverse(TempoBuf, &mspq, TEMPO_LEN); // convert tempo to big endian Write(TempoBuf, TEMPO_LEN); // write tempo } if (TimeSig != NULL) { // if time signature specified WriteMeta(ME_TIME_SIGNATURE, TIME_SIG_LEN); // write meta header Write(TimeSig, TIME_SIG_LEN); // write time signature } if (KeySig != NULL) { // if key signature specified WriteMeta(ME_KEY_SIGNATURE, KEY_SIG_LEN); // write meta header Write(KeySig, KEY_SIG_LEN); // write key signature } EndTrack(StartPos); // finish track and fix header }
void CMidiFile::WriteTrack(const CMidiEventArray& Event, LPCTSTR Name) { static bool HasP2[8] = {1, 1, 1, 1, 0, 0, 1, 1}; FILE_POS StartPos = BeginTrack(); // write track header USES_CONVERSION; if (Name != NULL) { // if track name specified int len = UINT64TO32(_tcslen(Name)); if (len) { // if track name has non-zero length WriteMeta(ME_TRACK_NAME, len); // write meta header Write(T2CA(Name), len); // write track name } } BYTE RunningStatus = 0; // init running status int nEvents = Event.GetSize(); for (int iEvent = 0; iEvent < nEvents; iEvent++) { // for each event const MIDI_EVENT& ev = Event[iEvent]; WriteVarLen(ev.DeltaT); // write variable-length delta time BYTE status = MIDI_STAT(ev.Msg); // get message status if (status != RunningStatus) { // if status changed WriteByte(status); RunningStatus = status; } WriteByte(MIDI_P1(ev.Msg)); // write message 1st parameter if (HasP2[(status >> 4) - 8]) // if message has 2nd parameter WriteByte(MIDI_P2(ev.Msg)); // write message 2nd parameter } EndTrack(StartPos); // finish track and fix header }
void RemoteSourceStreamInfo::DetachMedia_m() { for (auto& webrtcIdAndTrack : mTracks) { EndTrack(mMediaStream->GetInputStream(), webrtcIdAndTrack.second); } SourceStreamInfo::DetachMedia_m(); }
void RemoteSourceStreamInfo::RemoveTrack(const std::string& trackId) { auto it = mTracks.find(trackId); if (it != mTracks.end()) { EndTrack(mMediaStream->GetInputStream(), it->second); } SourceStreamInfo::RemoveTrack(trackId); }
void TrackUnionStream::RemoveInput(MediaInputPort* aPort) { for (int32_t i = mTrackMap.Length() - 1; i >= 0; --i) { if (mTrackMap[i].mInputPort == aPort) { EndTrack(i); mTrackMap.RemoveElementAt(i); } } ProcessedMediaStream::RemoveInput(aPort); }
void TrackUnionStream::RemoveInput(MediaInputPort* aPort) { STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p removing input %p", this, aPort)); for (int32_t i = mTrackMap.Length() - 1; i >= 0; --i) { if (mTrackMap[i].mInputPort == aPort) { STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p removing trackmap entry %d", this, i)); EndTrack(i); mTrackMap.RemoveElementAt(i); } } ProcessedMediaStream::RemoveInput(aPort); }
void TrackUnionStream::RemoveInput(MediaInputPort* aPort) { STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p removing input %p", this, aPort)); for (int32_t i = mTrackMap.Length() - 1; i >= 0; --i) { if (mTrackMap[i].mInputPort == aPort) { STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p removing trackmap entry %d", this, i)); EndTrack(i); for (auto listener : mTrackMap[i].mOwnedDirectListeners) { // Remove listeners while the entry still exists. RemoveDirectTrackListenerImpl(listener, mTrackMap[i].mOutputTrackID); } mTrackMap.RemoveElementAt(i); } } ProcessedMediaStream::RemoveInput(aPort); }
void TrackUnionStream::ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) { if (IsFinishedOnGraphThread()) { return; } nsAutoTArray<bool,8> mappedTracksFinished; nsAutoTArray<bool,8> mappedTracksWithMatchingInputTracks; for (uint32_t i = 0; i < mTrackMap.Length(); ++i) { mappedTracksFinished.AppendElement(true); mappedTracksWithMatchingInputTracks.AppendElement(false); } bool allFinished = !mInputs.IsEmpty(); bool allHaveCurrentData = !mInputs.IsEmpty(); for (uint32_t i = 0; i < mInputs.Length(); ++i) { MediaStream* stream = mInputs[i]->GetSource(); if (!stream->IsFinishedOnGraphThread()) { // XXX we really should check whether 'stream' has finished within time aTo, // not just that it's finishing when all its queued data eventually runs // out. allFinished = false; } if (!stream->HasCurrentData()) { allHaveCurrentData = false; } bool trackAdded = false; for (StreamBuffer::TrackIter tracks(stream->GetStreamBuffer()); !tracks.IsEnded(); tracks.Next()) { bool found = false; for (uint32_t j = 0; j < mTrackMap.Length(); ++j) { TrackMapEntry* map = &mTrackMap[j]; if (map->mInputPort == mInputs[i] && map->mInputTrackID == tracks->GetID()) { bool trackFinished; StreamBuffer::Track* outputTrack = mBuffer.FindTrack(map->mOutputTrackID); if (!outputTrack || outputTrack->IsEnded()) { trackFinished = true; } else { CopyTrackData(tracks.get(), j, aFrom, aTo, &trackFinished); } mappedTracksFinished[j] = trackFinished; mappedTracksWithMatchingInputTracks[j] = true; found = true; break; } } if (!found && (!mFilterCallback || mFilterCallback(tracks.get()))) { bool trackFinished = false; trackAdded = true; uint32_t mapIndex = AddTrack(mInputs[i], tracks.get(), aFrom); CopyTrackData(tracks.get(), mapIndex, aFrom, aTo, &trackFinished); mappedTracksFinished.AppendElement(trackFinished); mappedTracksWithMatchingInputTracks.AppendElement(true); } } if (trackAdded) { for (MediaStreamListener* l : mListeners) { l->NotifyFinishedTrackCreation(Graph()); } } } for (int32_t i = mTrackMap.Length() - 1; i >= 0; --i) { if (mappedTracksFinished[i]) { EndTrack(i); } else { allFinished = false; } if (!mappedTracksWithMatchingInputTracks[i]) { mTrackMap.RemoveElementAt(i); } } if (allFinished && mAutofinish && (aFlags & ALLOW_FINISH)) { // All streams have finished and won't add any more tracks, and // all our tracks have actually finished and been removed from our map, // so we're finished now. FinishOnGraphThread(); } else { mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTime(aTo)); } if (allHaveCurrentData) { // We can make progress if we're not blocked mHasCurrentData = true; } }
void TrackUnionStream::ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) { TRACE_AUDIO_CALLBACK_COMMENT("TrackUnionStream %p", this); if (IsFinishedOnGraphThread()) { return; } AutoTArray<bool, 8> mappedTracksFinished; AutoTArray<bool, 8> mappedTracksWithMatchingInputTracks; for (uint32_t i = 0; i < mTrackMap.Length(); ++i) { mappedTracksFinished.AppendElement(true); mappedTracksWithMatchingInputTracks.AppendElement(false); } AutoTArray<MediaInputPort*, 32> inputs(mInputs); inputs.AppendElements(mSuspendedInputs); bool allFinished = !inputs.IsEmpty(); bool allHaveCurrentData = !inputs.IsEmpty(); for (uint32_t i = 0; i < inputs.Length(); ++i) { MediaStream* stream = inputs[i]->GetSource(); if (!stream->IsFinishedOnGraphThread()) { // XXX we really should check whether 'stream' has finished within time // aTo, not just that it's finishing when all its queued data eventually // runs out. allFinished = false; } if (!stream->HasCurrentData()) { allHaveCurrentData = false; } for (StreamTracks::TrackIter tracks(stream->GetStreamTracks()); !tracks.IsEnded(); tracks.Next()) { bool found = false; for (uint32_t j = 0; j < mTrackMap.Length(); ++j) { TrackMapEntry* map = &mTrackMap[j]; if (map->mInputPort == inputs[i] && map->mInputTrackID == tracks->GetID()) { bool trackFinished = false; StreamTracks::Track* outputTrack = mTracks.FindTrack(map->mOutputTrackID); found = true; if (!outputTrack || outputTrack->IsEnded() || !inputs[i]->PassTrackThrough(tracks->GetID())) { trackFinished = true; } else { CopyTrackData(tracks.get(), j, aFrom, aTo, &trackFinished); } mappedTracksFinished[j] = trackFinished; mappedTracksWithMatchingInputTracks[j] = true; break; } } if (!found && inputs[i]->AllowCreationOf(tracks->GetID())) { bool trackFinished = false; uint32_t mapIndex = AddTrack(inputs[i], tracks.get(), aFrom); CopyTrackData(tracks.get(), mapIndex, aFrom, aTo, &trackFinished); mappedTracksFinished.AppendElement(trackFinished); mappedTracksWithMatchingInputTracks.AppendElement(true); } } } for (int32_t i = mTrackMap.Length() - 1; i >= 0; --i) { if (mappedTracksFinished[i]) { EndTrack(i); } else { allFinished = false; } if (!mappedTracksWithMatchingInputTracks[i]) { for (auto listener : mTrackMap[i].mOwnedDirectListeners) { // Remove listeners while the entry still exists. RemoveDirectTrackListenerImpl(listener, mTrackMap[i].mOutputTrackID); } mTrackMap.RemoveElementAt(i); } } if (allFinished && mAutofinish && (aFlags & ALLOW_FINISH)) { // All streams have finished and won't add any more tracks, and // all our tracks have actually finished and been removed from our map, // so we're finished now. FinishOnGraphThread(); } if (allHaveCurrentData) { // We can make progress if we're not blocked mHasCurrentData = true; } }