Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/cachingreader.h

Go to the documentation of this file.
00001 // cachingreader.h
00002 // Created 7/9/2009 by RJ Ryan (rryan@mit.edu)
00003 
00004 #ifndef CACHINGREADER_H
00005 #define CACHINGREADER_H
00006 
00007 #include <QDebug>
00008 #include <QMutex>
00009 #include <QQueue>
00010 #include <QWaitCondition>
00011 #include <QList>
00012 #include <QVector>
00013 #include <QLinkedList>
00014 #include <QHash>
00015 #include <QThread>
00016 
00017 #include "defs.h"
00018 #include "configobject.h"
00019 #include "trackinfoobject.h"
00020 #include "engine/engineworker.h"
00021 #include "util/fifo.h"
00022 
00023 class ControlObjectThread;
00024 namespace Mixxx {
00025     class SoundSource;
00026 }
00027 
00028 // A Hint is an indication to the CachingReader that a certain section of a
00029 // SoundSource will be used 'soon' and so it should be brought into memory by
00030 // the reader work thread.
00031 typedef struct Hint {
00032     // The sample to ensure is present in memory.
00033     int sample;
00034     // If a range of samples should be present, use length to indicate that the
00035     // range (sample, sample+length) should be present in memory.
00036     int length;
00037     // Currently unused -- but in the future could be used to prioritize certain
00038     // hints over others. A priority of 1 is the highest priority and should be
00039     // used for samples that will be read imminently. Hints for samples that
00040     // have the potential to be read (i.e. a cue point) should be issued with
00041     // priority >10.
00042     int priority;
00043 } Hint;
00044 
00045 // A Chunk is a section of audio that is being cached. The chunk_number can be
00046 // used to figure out the sample number of the first sample in data by using
00047 // sampleForChunk()
00048 typedef struct Chunk {
00049     int chunk_number;
00050     int length;
00051     CSAMPLE* data;
00052     Chunk* prev_lru;
00053     Chunk* next_lru;
00054 } Chunk;
00055 
00056 typedef struct ChunkReadRequest {
00057     Chunk* chunk;
00058 
00059     ChunkReadRequest() { chunk = NULL; }
00060 } ChunkReadRequest;
00061 
00062 enum ReaderStatus {
00063     INVALID,
00064     TRACK_NOT_LOADED,
00065     TRACK_LOADED,
00066     CHUNK_READ_SUCCESS,
00067     CHUNK_READ_EOF,
00068     CHUNK_READ_INVALID
00069 };
00070 
00071 typedef struct ReaderStatusUpdate {
00072     ReaderStatus status;
00073     Chunk* chunk;
00074     int trackNumSamples;
00075     ReaderStatusUpdate() {
00076         status = INVALID;
00077         chunk = NULL;
00078     }
00079 } ReaderStatusUpdate;
00080 
00081 // CachingReader provides a layer on top of a SoundSource for reading samples
00082 // from a file. A cache is provided so that repeated reads to a certain section
00083 // of a song do not cause disk seeks or unnecessary SoundSource
00084 // calls. CachingReader provides a worker thread that can be used to prepare the
00085 // cache so that areas of a file that will soon be read are present in memory
00086 // once they are needed. This can be accomplished by issueing 'hints' to the
00087 // reader of areas of a SoundSource that will be read soon.
00088 class CachingReader : public EngineWorker {
00089     Q_OBJECT
00090 
00091   public:
00092     // Construct a CachingReader with the given group.
00093     CachingReader(const char* _group,
00094                   ConfigObject<ConfigValue>* _config);
00095     virtual ~CachingReader();
00096 
00097     void process();
00098 
00099     // Read num_samples from the SoundSource starting with sample into
00100     // buffer. Returns the total number of samples actually written to buffer.
00101     int read(int sample, int num_samples, CSAMPLE* buffer);
00102 
00103     // Issue a list of hints, but check whether any of the hints request a chunk
00104     // that is not in the cache. If any hints do request a chunk not in cache,
00105     // then wake the reader so that it can process them. Must only be called
00106     // from the engine callback.
00107     void hintAndMaybeWake(QList<Hint>& hintList);
00108 
00109     // Request that the CachingReader load a new track. These requests are
00110     // processed in the work thread, so the reader must be woken up via wake()
00111     // for this to take effect.
00112     void newTrack(TrackPointer pTrack);
00113 
00114     // Wake the reader up so that it will process newTrack requests and hints.
00115     void wake();
00116 
00117     // Run upkeep operations like loading tracks and reading from file. Run by a
00118     // thread pool via the EngineWorkerScheduler.
00119     void run();
00120 
00121     // A Chunk is a memory-resident section of audio that has been cached. Each
00122     // chunk holds a fixed number of samples given by kSamplesPerChunk.
00123     const static int kChunkLength, kSamplesPerChunk;
00124 
00125   signals:
00126     // Emitted once a new track is loaded and ready to be read from.
00127     void trackLoaded(TrackPointer pTrack, int iSampleRate, int iNumSamples);
00128     void trackLoadFailed(TrackPointer pTrack, QString reason);
00129 
00130   private:
00131     // Removes a chunk from the LRU list
00132     static Chunk* removeFromLRUList(Chunk* chunk, Chunk* head);
00133     // Inserts a chunk into the LRU list
00134     static Chunk* insertIntoLRUList(Chunk* chunk, Chunk* head);
00135 
00136     // Given a sample number, return the chunk number corresponding to it.
00137     inline static int chunkForSample(int sample_number) {
00138         return sample_number / kSamplesPerChunk;
00139     }
00140 
00141     // Given a chunk number, return the start sample number for the chunk.
00142     inline static int sampleForChunk(int chunk_number) {
00143         return chunk_number * kSamplesPerChunk;
00144     }
00145 
00146     // Initialize the reader by creating all the chunks from the RAM provided to
00147     // the CachingReader.
00148     void initialize();
00149 
00150     const char* m_pGroup;
00151     const ConfigObject<ConfigValue>* m_pConfig;
00152 
00153     // Thread-safe FIFOs for communication between the engine callback and
00154     // reader thread.
00155     FIFO<ChunkReadRequest> m_chunkReadRequestFIFO;
00156     FIFO<ReaderStatusUpdate> m_readerStatusFIFO;
00157 
00158     // Queue of Tracks to load, and the corresponding lock. Must acquire the
00159     // lock to touch.
00160     QMutex m_trackQueueMutex;
00161     QQueue<TrackWeakPointer> m_trackQueue;
00162 
00164     // The following may /only/ be called within the engine callback
00166 
00167     // Looks for the provided chunk number in the index of in-memory chunks and
00168     // returns it if it is present. If not, returns NULL.
00169     Chunk* lookupChunk(int chunk_number);
00170 
00171     // Returns a Chunk to the free list
00172     void freeChunk(Chunk* pChunk);
00173 
00174     // Returns all allocated chunks to the free list
00175     void freeAllChunks();
00176 
00177     // Gets a chunk from the free list. Returns NULL if none available.
00178     Chunk* allocateChunk();
00179 
00180     // Gets a chunk from the free list, frees the LRU Chunk if none available.
00181     Chunk* allocateChunkExpireLRU();
00182 
00183     ReaderStatus m_readerStatus;
00184 
00185     // Keeps track of free Chunks we've allocated
00186     QVector<Chunk*> m_chunks;
00187     // List of free chunks available for use.
00188     QList<Chunk*> m_freeChunks;
00189     // List of reserved chunks with reads in progress
00190     QHash<int, Chunk*> m_chunksBeingRead;
00191 
00192     // Keeps track of what Chunks we've allocated and indexes them based on what
00193     // chunk number they are allocated to.
00194     QHash<int, Chunk*> m_allocatedChunks;
00195 
00196     // The linked list of recently-used chunks.
00197     Chunk* m_mruChunk;
00198     Chunk* m_lruChunk;
00199 
00200     // The raw memory buffer which is divided up into chunks.
00201     CSAMPLE* m_pRawMemoryBuffer;
00202 
00204     // The following may /only/ be called within the reader thread
00206 
00207     // Internal method to load a track. Emits trackLoaded when finished.
00208     void loadTrack(TrackPointer pTrack);
00209 
00210     // Read the given chunk_number from the file into pChunk's data
00211     // buffer. Fills length/sample information about Chunk* as well.
00212     void processChunkReadRequest(ChunkReadRequest* request,
00213                                  ReaderStatusUpdate* update);
00214 
00215     // The current sound source of the track loaded
00216     Mixxx::SoundSource* m_pCurrentSoundSource;
00217     int m_iTrackSampleRate;
00218     int m_iTrackNumSamples;
00219     int m_iTrackNumSamplesCallbackSafe;
00220 
00221     // Temporary buffer for reading from SoundSources
00222     SAMPLE* m_pSample;
00223 };
00224 
00225 
00226 #endif /* CACHINGREADER_H */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines