![]() |
Mixxx
|
00001 // readaheadmanager.h 00002 // Created 8/2/2009 by RJ Ryan (rryan@mit.edu) 00003 00004 #ifndef READAHEADMANGER_H 00005 #define READAHEADMANGER_H 00006 00007 #include <QLinkedList> 00008 #include <QList> 00009 #include <QMutex> 00010 #include <QPair> 00011 00012 #include "defs.h" 00013 00014 struct Hint; 00015 class EngineControl; 00016 class CachingReader; 00017 00018 // ReadAheadManager is a tool for keeping track of the engine's current position 00019 // in a file. In the case that the engine needs to read ahead of the current 00020 // play position (for example, to feed more samples into a library like 00021 // SoundTouch) then this will keep track of how many samples the engine has 00022 // consumed. The getNextSamples() method encapsulates the logic of determining 00023 // whether to take a loop or jump into a single method. Whenever the Engine 00024 // seeks or the current play position is invalidated somehow, the Engine must 00025 // call notifySeek to inform the ReadAheadManager to reset itself to the seek 00026 // point. 00027 class ReadAheadManager { 00028 public: 00029 explicit ReadAheadManager(CachingReader* reader); 00030 virtual ~ReadAheadManager(); 00031 00032 // Call this method to fill buffer with requested_samples out of the 00033 // lookahead buffer. Provide rate as dRate so that the manager knows the 00034 // direction the audio is progressing in. Returns the total number of 00035 // samples read into buffer. Note that it is very common that the total 00036 // samples read is less than the requested number of samples. 00037 virtual int getNextSamples(double dRate, CSAMPLE* buffer, int requested_samples); 00038 00039 // Used to add a new EngineControl that ReadAheadManager will use to decide 00040 // which samples to return. 00041 virtual void addEngineControl(EngineControl* control); 00042 00043 // Notify the ReadAheadManager that the current playposition has 00044 // changed. Units are stereo samples. 00045 virtual void setNewPlaypos(int iNewPlaypos); 00046 00047 // Get the current read-ahead position in stereo samples. 00048 virtual inline int getPlaypos() const { 00049 return m_iCurrentPosition; 00050 } 00051 00052 virtual void notifySeek(int iSeekPosition); 00053 00054 // hintReader allows the ReadAheadManager to provide hints to the reader to 00055 // indicate that the given portion of a song is about to be read. 00056 virtual void hintReader(double dRate, QList<Hint>& hintList, 00057 int iSamplesPerBuffer); 00058 00059 00060 virtual int getEffectiveVirtualPlaypositionFromLog(double currentVirtualPlayposition, 00061 double numConsumedSamples); 00062 00063 private: 00064 // An entry in the read log indicates the virtual playposition the read 00065 // began at and the virtual playposition it ended at. 00066 struct ReadLogEntry { 00067 double virtualPlaypositionStart; 00068 double virtualPlaypositionEndNonInclusive; 00069 00070 ReadLogEntry(double virtualPlaypositionStart, 00071 double virtualPlaypositionEndNonInclusive) { 00072 this->virtualPlaypositionStart = virtualPlaypositionStart; 00073 this->virtualPlaypositionEndNonInclusive = 00074 virtualPlaypositionEndNonInclusive; 00075 } 00076 00077 bool direction() const { 00078 return virtualPlaypositionStart < virtualPlaypositionEndNonInclusive; 00079 } 00080 00081 double length() const { 00082 return abs(virtualPlaypositionEndNonInclusive - 00083 virtualPlaypositionStart); 00084 } 00085 00086 // Moves the start position forward or backward (depending on 00087 // direction()) by numSamples. Returns the total number of samples 00088 // consumed. Caller should check if length() is 0 after consumption in 00089 // order to expire the ReadLogEntry. 00090 double consume(double numSamples) { 00091 double available = math_min(numSamples, length()); 00092 virtualPlaypositionStart += (direction() ? 1 : -1) * available; 00093 return available; 00094 } 00095 00096 bool merge(const ReadLogEntry& other) { 00097 if (direction() == other.direction() && 00098 virtualPlaypositionEndNonInclusive == other.virtualPlaypositionStart) { 00099 virtualPlaypositionEndNonInclusive = 00100 other.virtualPlaypositionEndNonInclusive; 00101 return true; 00102 } 00103 return false; 00104 } 00105 }; 00106 00107 // virtualPlaypositionEnd is the first sample in the direction that was read 00108 // that was NOT read as part of this log entry. This is to simplify the 00109 void addReadLogEntry(double virtualPlaypositionStart, 00110 double virtualPlaypositionEndNonInclusive); 00111 00112 QMutex m_mutex; 00113 QList<EngineControl*> m_sEngineControls; 00114 QLinkedList<ReadLogEntry> m_readAheadLog; 00115 int m_iCurrentPosition; 00116 CachingReader* m_pReader; 00117 }; 00118 00119 #endif // READAHEADMANGER_H