1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
#ifndef ENGINE_CACHINGREADERWORKER_H
#define ENGINE_CACHINGREADERWORKER_H
#include <QtDebug>
#include <QMutex>
#include <QSemaphore>
#include <QThread>
#include <QString>
#include "engine/cachingreaderchunk.h"
#include "track/track.h"
#include "engine/engineworker.h"
#include "sources/audiosource.h"
#include "util/fifo.h"
// POD with trivial ctor/dtor/copy for passing through FIFO
typedef struct CachingReaderChunkReadRequest {
CachingReaderChunk* chunk;
void giveToWorker(CachingReaderChunkForOwner* chunkForOwner) {
DEBUG_ASSERT(chunkForOwner);
chunk = chunkForOwner;
chunkForOwner->giveToWorker();
}
} CachingReaderChunkReadRequest;
enum ReaderStatus {
INVALID,
TRACK_NOT_LOADED,
TRACK_LOADED,
CHUNK_READ_SUCCESS,
CHUNK_READ_EOF,
CHUNK_READ_INVALID
};
// POD with trivial ctor/dtor/copy for passing through FIFO
typedef struct ReaderStatusUpdate {
ReaderStatus status;
CachingReaderChunk* chunk;
SINT readableFrameIndexRangeStart;
SINT readableFrameIndexRangeEnd;
void init(
ReaderStatus statusArg = INVALID,
CachingReaderChunk* chunkArg = nullptr,
const mixxx::IndexRange& readableFrameIndexRangeArg = mixxx::IndexRange()) {
status = statusArg;
chunk = chunkArg;
readableFrameIndexRangeStart = readableFrameIndexRangeArg.start();
readableFrameIndexRangeEnd = readableFrameIndexRangeArg.end();
}
mixxx::IndexRange readableFrameIndexRange() const {
return mixxx::IndexRange::between(
readableFrameIndexRangeStart,
readableFrameIndexRangeEnd);
}
} ReaderStatusUpdate;
class CachingReaderWorker : public EngineWorker {
Q_OBJECT
public:
// Construct a CachingReader with the given group.
CachingReaderWorker(QString group,
FIFO<CachingReaderChunkReadRequest>* pChunkReadRequestFIFO,
FIFO<ReaderStatusUpdate>* pReaderStatusFIFO);
virtual ~CachingReaderWorker();
// Request to load a new track. wake() must be called afterwards.
virtual void newTrack(TrackPointer pTrack);
// Run upkeep operations like loading tracks and reading from file. Run by a
// thread pool via the EngineWorkerScheduler.
virtual void run();
void quitWait();
signals:
// Emitted once a new track is loaded and ready to be read from.
void trackLoading();
void trackLoaded(TrackPointer pTrack, int iSampleRate, int iNumSamples);
void trackLoadFailed(TrackPointer pTrack, QString reason);
private:
QString m_group;
QString m_tag;
// Thread-safe FIFOs for communication between the engine callback and
// reader thread.
FIFO<CachingReaderChunkReadRequest>* m_pChunkReadRequestFIFO;
FIFO<ReaderStatusUpdate>* m_pReaderStatusFIFO;
// Queue of Tracks to load, and the corresponding lock. Must acquire the
// lock to touch.
QMutex m_newTrackMutex;
bool m_newTrackAvailable;
TrackPointer m_pNewTrack;
// Internal method to load a track. Emits trackLoaded when finished.
void loadTrack(const TrackPointer& pTrack);
ReaderStatusUpdate processReadRequest(
const CachingReaderChunkReadRequest& request);
// The current audio source of the track loaded
mixxx::AudioSourcePointer m_pAudioSource;
// Temporary buffer for reading samples from all channels
// before conversion to a stereo signal.
mixxx::SampleBuffer m_tempReadBuffer;
// The maximum readable frame index of the AudioSource. Might
// be adjusted when decoding errors occur to prevent reading
// the same chunk(s) over and over again.
// This frame index references the frame that follows the
// last frame with readable sample data.
mixxx::IndexRange m_readableFrameIndexRange;
QAtomicInt m_stop;
};
#endif /* ENGINE_CACHINGREADERWORKER_H */
|