summaryrefslogtreecommitdiffstats
path: root/src/sound/AudioPlayQueue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sound/AudioPlayQueue.cpp')
-rw-r--r--src/sound/AudioPlayQueue.cpp501
1 files changed, 501 insertions, 0 deletions
diff --git a/src/sound/AudioPlayQueue.cpp b/src/sound/AudioPlayQueue.cpp
new file mode 100644
index 0000000..2bd07c3
--- /dev/null
+++ b/src/sound/AudioPlayQueue.cpp
@@ -0,0 +1,501 @@
+
+// -*- c-basic-offset: 4 -*-
+
+/*
+ Rosegarden
+ A sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <bownie@bownie.com>
+
+ The moral right of the authors to claim authorship of this work
+ has been asserted.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#include "AudioPlayQueue.h"
+#include "misc/Debug.h"
+#include "PlayableAudioFile.h"
+#include "Profiler.h"
+
+//#define DEBUG_AUDIO_PLAY_QUEUE 1
+//#define FINE_DEBUG_AUDIO_PLAY_QUEUE 1
+
+namespace Rosegarden
+{
+
+
+static inline unsigned int instrumentId2Index(InstrumentId id)
+{
+ if (id < AudioInstrumentBase)
+ return 0;
+ else
+ return (id - AudioInstrumentBase);
+}
+
+bool
+AudioPlayQueue::FileTimeCmp::operator()(const PlayableAudioFile &f1,
+ const PlayableAudioFile &f2) const
+{
+ return operator()(&f1, &f2);
+}
+
+bool
+AudioPlayQueue::FileTimeCmp::operator()(const PlayableAudioFile *f1,
+ const PlayableAudioFile *f2) const
+{
+ RealTime t1 = f1->getStartTime(), t2 = f2->getStartTime();
+ if (t1 < t2)
+ return true;
+ else if (t2 < t1)
+ return false;
+ else
+ return f1 < f2;
+}
+
+
+AudioPlayQueue::AudioPlayQueue() :
+ m_maxBuffers(0)
+{
+ // nothing to do
+}
+
+AudioPlayQueue::~AudioPlayQueue()
+{
+ std::cerr << "AudioPlayQueue::~AudioPlayQueue()" << std::endl;
+ clear();
+}
+
+void
+AudioPlayQueue::addScheduled(PlayableAudioFile *file)
+{
+ if (m_files.find(file) != m_files.end()) {
+ std::cerr << "WARNING: AudioPlayQueue::addScheduled("
+ << file << "): already in queue" << std::endl;
+ return ;
+ }
+
+ m_files.insert(file);
+
+ RealTime startTime = file->getStartTime();
+ RealTime endTime = file->getStartTime() + file->getDuration();
+
+ InstrumentId instrument = file->getInstrument();
+ unsigned int index = instrumentId2Index(instrument);
+
+ while (m_instrumentIndex.size() <= index) {
+ m_instrumentIndex.push_back(ReverseFileMap());
+ }
+
+#ifdef DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << "AudioPlayQueue[" << this << "]::addScheduled(" << file << "): start " << file->getStartTime() << ", end " << file->getEndTime() << ", slots: " << std::endl;
+#endif
+
+ for (int i = startTime.sec; i <= endTime.sec; ++i) {
+ m_index[i].push_back(file);
+ m_instrumentIndex[index][i].push_back(file);
+ if (!file->isSmallFile()) {
+ m_counts[i] += file->getTargetChannels();
+ if (m_counts[i] > m_maxBuffers) {
+ m_maxBuffers = m_counts[i];
+ }
+ }
+#ifdef DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << i << " ";
+#endif
+
+ }
+
+#ifdef DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << std::endl << "(max buffers now "
+ << m_maxBuffers << ")" << std::endl;
+#endif
+}
+
+void
+AudioPlayQueue::addUnscheduled(PlayableAudioFile *file)
+{
+#ifdef DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << "AudioPlayQueue[" << this << "]::addUnscheduled(" << file << "): start " << file->getStartTime() << ", end " << file->getEndTime() << ", instrument " << file->getInstrument() << std::endl;
+#endif
+
+ m_unscheduled.push_back(file);
+
+#ifdef DEBUG_AUDIO_PLAY_QUEUE
+
+ std::cerr << "AudioPlayQueue[" << this << "]::addUnscheduled: now " << m_unscheduled.size() << " unscheduled files" << std::endl;
+#endif
+
+}
+
+void
+AudioPlayQueue::erase(PlayableAudioFile *file)
+{
+#ifdef DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << "AudioPlayQueue::erase(" << file << "): start " << file->getStartTime() << ", end " << file->getEndTime() << std::endl;
+#endif
+
+ FileSet::iterator fi = m_files.find(file);
+ if (fi == m_files.end()) {
+ for (FileList::iterator fli = m_unscheduled.begin();
+ fli != m_unscheduled.end(); ++fli) {
+ if (*fli == file) {
+ m_unscheduled.erase(fli);
+ delete file;
+ return ;
+ }
+ }
+ return ;
+ }
+ m_files.erase(fi);
+
+ InstrumentId instrument = file->getInstrument();
+ unsigned int index = instrumentId2Index(instrument);
+
+ for (ReverseFileMap::iterator mi = m_instrumentIndex[index].begin();
+ mi != m_instrumentIndex[index].end(); ++mi) {
+
+ for (FileVector::iterator fi = mi->second.begin();
+ fi != mi->second.end(); ++fi) {
+
+ if (*fi == file) {
+ mi->second.erase(fi);
+ if (m_counts[mi->first] > 0)
+ --m_counts[mi->first];
+ break;
+ }
+ }
+ }
+
+ for (ReverseFileMap::iterator mi = m_index.begin();
+ mi != m_index.end(); ++mi) {
+
+ for (FileVector::iterator fi = mi->second.begin();
+ fi != mi->second.end(); ++fi) {
+
+ if (*fi == file) {
+ mi->second.erase(fi);
+ if (m_counts[mi->first] > 0)
+ --m_counts[mi->first];
+ break;
+ }
+ }
+ }
+
+ delete file;
+}
+
+void
+AudioPlayQueue::clear()
+{
+#ifdef DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << "AudioPlayQueue::clear()" << std::endl;
+#endif
+
+ while (m_files.begin() != m_files.end()) {
+ delete *m_files.begin();
+ m_files.erase(m_files.begin());
+ }
+
+ while (m_unscheduled.begin() != m_unscheduled.end()) {
+ delete *m_unscheduled.begin();
+ m_unscheduled.erase(m_unscheduled.begin());
+ }
+
+ m_instrumentIndex.clear();
+ m_index.clear();
+ m_counts.clear();
+ m_maxBuffers = 0;
+}
+
+bool
+AudioPlayQueue::empty() const
+{
+ return m_unscheduled.empty() && m_files.empty();
+}
+
+size_t
+AudioPlayQueue::size() const
+{
+ return m_unscheduled.size() + m_files.size();
+}
+
+void
+AudioPlayQueue::getPlayingFiles(const RealTime &sliceStart,
+ const RealTime &sliceDuration,
+ FileSet &playing) const
+{
+ // Profiler profiler("AudioPlayQueue::getPlayingFiles");
+
+ // This one needs to be quick.
+
+ playing.clear();
+
+ RealTime sliceEnd = sliceStart + sliceDuration;
+
+ for (int i = sliceStart.sec; i <= sliceEnd.sec; ++i) {
+
+ ReverseFileMap::const_iterator mi(m_index.find(i));
+ if (mi == m_index.end())
+ continue;
+
+ for (FileVector::const_iterator fi = mi->second.begin();
+ fi != mi->second.end(); ++fi) {
+
+ PlayableAudioFile *f = *fi;
+
+ if (f->getStartTime() > sliceEnd ||
+ f->getStartTime() + f->getDuration() <= sliceStart)
+ continue;
+
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+
+ std::cerr << "... found " << f << " in slot " << i << std::endl;
+#endif
+
+ playing.insert(f);
+ }
+ }
+
+ for (FileList::const_iterator fli = m_unscheduled.begin();
+ fli != m_unscheduled.end(); ++fli) {
+ PlayableAudioFile *file = *fli;
+ if (file->getStartTime() <= sliceEnd &&
+ file->getStartTime() + file->getDuration() > sliceStart) {
+ playing.insert(file);
+ }
+ }
+
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+ if (playing.size() > 0) {
+ std::cerr << "AudioPlayQueue::getPlayingFiles(" << sliceStart << ","
+ << sliceDuration << "): total "
+ << playing.size() << " files" << std::endl;
+ }
+#endif
+}
+
+void
+AudioPlayQueue::getPlayingFilesForInstrument(const RealTime &sliceStart,
+ const RealTime &sliceDuration,
+ InstrumentId instrumentId,
+ PlayableAudioFile **playing,
+ size_t &size) const
+{
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+ bool printed = false;
+ Profiler profiler("AudioPlayQueue::getPlayingFilesForInstrument", true);
+#endif
+
+ // This one needs to be quick.
+
+ size_t written = 0;
+
+ RealTime sliceEnd = sliceStart + sliceDuration;
+
+ unsigned int index = instrumentId2Index(instrumentId);
+ if (index >= m_instrumentIndex.size()) {
+ goto unscheduled; // nothing scheduled here
+ }
+
+ for (int i = sliceStart.sec; i <= sliceEnd.sec; ++i) {
+
+ ReverseFileMap::const_iterator mi
+ (m_instrumentIndex[index].find(i));
+
+ if (mi == m_instrumentIndex[index].end())
+ continue;
+
+ for (FileVector::const_iterator fi = mi->second.begin();
+ fi != mi->second.end(); ++fi) {
+
+ PlayableAudioFile *f = *fi;
+
+ if (f->getInstrument() != instrumentId)
+ continue;
+
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+
+ if (!printed) {
+ std::cerr << "AudioPlayQueue::getPlayingFilesForInstrument(" << sliceStart
+ << ", " << sliceDuration << ", " << instrumentId << ")"
+ << std::endl;
+ printed = true;
+ }
+#endif
+
+ if (f->getStartTime() > sliceEnd ||
+ f->getEndTime() <= sliceStart) {
+
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << "... rejected " << f << " in slot " << i << std::endl;
+ if (f->getStartTime() > sliceEnd) {
+ std::cerr << "(" << f->getStartTime() << " > " << sliceEnd
+ << ")" << std::endl;
+ } else {
+ std::cerr << "(" << f->getEndTime() << " <= " << sliceStart
+ << ")" << std::endl;
+ }
+#endif
+
+ continue;
+ }
+
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << "... found " << f << " in slot " << i << " ("
+ << f->getStartTime() << " -> " << f->getEndTime()
+ << ")" << std::endl;
+#endif
+
+ size_t j = 0;
+ for (j = 0; j < written; ++j) {
+ if (playing[j] == f)
+ break;
+ }
+ if (j < written)
+ break; // already have it
+
+ if (written >= size) {
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << "No room to write it!" << std::endl;
+#endif
+
+ break;
+ }
+
+ playing[written++] = f;
+ }
+ }
+
+unscheduled:
+
+ for (FileList::const_iterator fli = m_unscheduled.begin();
+ fli != m_unscheduled.end(); ++fli) {
+
+ PlayableAudioFile *f = *fli;
+
+ if (f->getInstrument() != instrumentId) {
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << "rejecting unscheduled " << f << " as wrong instrument ("
+ << f->getInstrument() << " != " << instrumentId << ")" << std::endl;
+#endif
+
+ continue;
+ }
+
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+ if (!printed) {
+ std::cerr << "AudioPlayQueue::getPlayingFilesForInstrument(" << sliceStart
+ << ", " << sliceDuration << ", " << instrumentId << ")"
+ << std::endl;
+ printed = true;
+ }
+#endif
+
+ if (f->getStartTime() <= sliceEnd &&
+ f->getStartTime() + f->getDuration() > sliceStart) {
+
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << "... found " << f << " in unscheduled list ("
+ << f->getStartTime() << " -> " << f->getEndTime()
+ << ")" << std::endl;
+#endif
+
+ if (written >= size)
+ break;
+ playing[written++] = f;
+
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+
+ } else {
+
+ std::cerr << "... rejected " << f << " in unscheduled list" << std::endl;
+ if (f->getStartTime() > sliceEnd) {
+ std::cerr << "(" << f->getStartTime() << " > " << sliceEnd
+ << ")" << std::endl;
+ } else {
+ std::cerr << "(" << f->getEndTime() << " <= " << sliceStart
+ << ")" << std::endl;
+ }
+#endif
+
+ }
+ }
+
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+ if (written > 0) {
+ std::cerr << "AudioPlayQueue::getPlayingFilesForInstrument: total "
+ << written << " files" << std::endl;
+ }
+#endif
+
+ size = written;
+}
+
+bool
+AudioPlayQueue::haveFilesForInstrument(InstrumentId instrumentId) const
+{
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << "AudioPlayQueue::haveFilesForInstrument(" << instrumentId << ")...";
+#endif
+
+ unsigned int index = instrumentId2Index(instrumentId);
+
+ if (index < m_instrumentIndex.size() &&
+ !m_instrumentIndex[index].empty()) {
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << " yes (scheduled)" << std::endl;
+#endif
+
+ return true;
+ }
+
+ for (FileList::const_iterator fli = m_unscheduled.begin();
+ fli != m_unscheduled.end(); ++fli) {
+ PlayableAudioFile *file = *fli;
+ if (file->getInstrument() == instrumentId) {
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << " yes (unscheduled)" << std::endl;
+#endif
+
+ return true;
+ }
+ }
+
+#ifdef FINE_DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << " no" << std::endl;
+#endif
+
+ return false;
+}
+
+const AudioPlayQueue::FileSet &
+AudioPlayQueue::getAllScheduledFiles() const
+{
+#ifdef DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << "AudioPlayQueue[" << this << "]::getAllScheduledFiles: have " << m_files.size() << " files" << std::endl;
+#endif
+
+ return m_files;
+}
+
+const AudioPlayQueue::FileList &
+AudioPlayQueue::getAllUnscheduledFiles() const
+{
+#ifdef DEBUG_AUDIO_PLAY_QUEUE
+ std::cerr << "AudioPlayQueue[" << this << "]::getAllUnscheduledFiles: have " << m_unscheduled.size() << " files" << std::endl;
+#endif
+
+ return m_unscheduled;
+}
+
+
+}
+