26 #include <QTextStream> 42 m_path(source.getLocation()),
50 m_lastDirectReadStart(0),
51 m_lastDirectReadCount(0)
59 SVDEBUG <<
"WaveFileModel::WaveFileModel: reader rate: " 64 if (objectName() ==
"") setObjectName(QFileInfo(
m_path).fileName());
70 m_path(source.getLocation()),
81 if (objectName() ==
"") setObjectName(QFileInfo(
m_path).fileName());
104 static int prevCompletion = 0;
106 *completion = int(c * 100.0 + 0.01);
109 if (decodeCompletion < 90) *completion = decodeCompletion;
110 else *completion = std::min(*completion, decodeCompletion);
112 if (*completion != 0 &&
113 *completion != 100 &&
114 prevCompletion != 0 &&
115 prevCompletion > *completion) {
117 *completion = prevCompletion;
119 prevCompletion = *completion;
121 #ifdef DEBUG_WAVE_FILE_MODEL 122 SVDEBUG <<
"WaveFileModel::isReady(): ready = " <<
ready <<
", completion = " << (completion ? *completion : -1) << endl;
169 if (title ==
"") title = objectName();
195 #ifdef DEBUG_WAVE_FILE_MODEL 196 cout <<
"WaveFileModel::getData[" <<
this <<
"]: " << channel <<
", " << start <<
", " << count <<
", " << buffer << endl;
202 for (
int i = 0; i < count; ++i) {
214 for (
int i = 0; i < count; ++i) buffer[i] = 0.f;
218 #ifdef DEBUG_WAVE_FILE_MODEL 230 int ch0 = channel, ch1 = channel;
240 for (
int ch = ch0; ch <= ch1; ++ch) {
242 int index = i * channels + ch;
243 if (index >= (
int)frames.size())
break;
245 float sample = frames[index];
257 double *buffer)
const 259 #ifdef DEBUG_WAVE_FILE_MODEL 260 cout <<
"WaveFileModel::getData(double)[" <<
this <<
"]: " << channel <<
", " << start <<
", " << count <<
", " << buffer << endl;
266 for (
int i = 0; i < count; ++i) buffer[i] = 0.0;
276 for (
int i = 0; i < count; ++i) buffer[i] = 0.0;
287 int ch0 = channel, ch1 = channel;
297 for (
int ch = ch0; ch <= ch1; ++ch) {
299 int index = i * channels + ch;
300 if (index >= (
int)frames.size())
break;
302 float sample = frames[index];
314 int start,
int count,
315 float **buffer)
const 317 #ifdef DEBUG_WAVE_FILE_MODEL 318 cout <<
"WaveFileModel::getData[" <<
this <<
"]: " << fromchannel <<
"," << tochannel <<
", " << start <<
", " << count <<
", " << buffer << endl;
323 if (fromchannel > tochannel) {
324 cerr <<
"ERROR: WaveFileModel::getData: fromchannel (" 325 << fromchannel <<
") > tochannel (" << tochannel <<
")" 330 if (tochannel >= channels) {
331 cerr <<
"ERROR: WaveFileModel::getData: tochannel (" 332 << tochannel <<
") >= channel count (" << channels <<
")" 337 if (fromchannel == tochannel) {
338 return getData(fromchannel, start, count, buffer[0]);
341 int reqchannels = (tochannel - fromchannel) + 1;
350 for (
int c = 0; c < reqchannels; ++c) {
351 for (
int i = 0; i < count; ++i) buffer[c][i] = 0.f;
362 for (
int c = 0; c < reqchannels; ++c) {
363 for (
int i = 0; i < count; ++i) buffer[c][i] = 0.f;
373 int index = 0, available = frames.size();
377 if (index >= available)
break;
381 for (
int c = 0; c < channels; ++c) {
383 if (c >= fromchannel && c <= tochannel) {
384 buffer[destc][i] = frames[index];
404 if (cacheType != 0 && cacheType != 1) {
409 return roundedBlockSize;
419 ranges.reserve((count / blockSize) + 1);
435 if (cacheType != 0 && cacheType != 1) {
456 float max = 0.0, min = 0.0, total = 0.0;
461 int index = i * channels + channel;
465 if (sample > max || got == 0) max = sample;
466 if (sample < min || got == 0) min = sample;
467 total += fabsf(sample);
472 if (got == blockSize) {
473 ranges.push_back(
Range(min, max, total / got));
474 min = max = total = 0.0f;
482 ranges.push_back(
Range(min, max, total / got));
493 blockSize = roundedBlockSize;
497 if (cacheType == 0) {
499 div = (1 << power) / cacheBlock;
502 div = ((
unsigned int)((1 << power) * sqrt(2.) + 0.01)) / cacheBlock;
505 int startIndex = start / cacheBlock;
506 int endIndex = (start + count) / cacheBlock;
508 float max = 0.0, min = 0.0, total = 0.0;
511 #ifdef DEBUG_WAVE_FILE_MODEL 512 cerr <<
"blockSize is " << blockSize <<
", cacheBlock " << cacheBlock <<
", start " << start <<
", count " << count <<
" (frame count " <<
getFrameCount() <<
"), power is " << power <<
", div is " << div <<
", startIndex " << startIndex <<
", endIndex " << endIndex << endl;
515 for (i = 0; i <= endIndex - startIndex; ) {
517 int index = (i + startIndex) * channels + channel;
518 if (index >= (
int)cache.size())
break;
520 const Range &range = cache[index];
521 if (range.
max() > max || got == 0) max = range.
max();
522 if (range.
min() < min || got == 0) min = range.
min();
529 ranges.push_back(
Range(min, max, total / got));
530 min = max = total = 0.0f;
536 ranges.push_back(
Range(min, max, total / got));
540 #ifdef DEBUG_WAVE_FILE_MODEL 541 SVDEBUG <<
"returning " << ranges.size() <<
" ranges" << endl;
550 if (!
isOK())
return range;
560 for (blockSize = 1; blockSize <= count; blockSize *= 2);
561 if (blockSize > 1) blockSize /= 2;
565 int blockStart = (start / blockSize) * blockSize;
566 int blockEnd = ((start + count) / blockSize) * blockSize;
568 if (blockStart < start) blockStart += blockSize;
570 if (blockEnd > blockStart) {
572 getSummaries(channel, blockStart, blockEnd - blockStart, ranges, blockSize);
573 for (
int i = 0; i < (int)ranges.size(); ++i) {
574 if (first || ranges[i].min() < range.
min()) range.
setMin(ranges[i].min());
575 if (first || ranges[i].max() > range.
max()) range.
setMax(ranges[i].max());
576 if (first || ranges[i].absmean() < range.
absmean()) range.
setAbsmean(ranges[i].absmean());
581 if (blockStart > start) {
588 if (blockEnd < start + count) {
589 Range endRange =
getSummary(channel, blockEnd, start + count - blockEnd);
613 #ifdef DEBUG_WAVE_FILE_MODEL 614 SVDEBUG <<
"WaveFileModel::fillCache: started fill thread" << endl;
623 #ifdef DEBUG_WAVE_FILE_MODEL 624 SVDEBUG <<
"WaveFileModel::fillTimerTimedOut: extent = " << fillExtent << endl;
631 #ifdef DEBUG_WAVE_FILE_MODEL 632 SVDEBUG <<
"WaveFileModel::fillTimerTimedOut: no thread" << endl;
652 #ifdef DEBUG_WAVE_FILE_MODEL 653 SVDEBUG <<
"WaveFileModel::cacheFilled" << endl;
660 int cacheBlockSize[2];
666 int readBlockSize = 16384;
683 float *means =
new float[2 * channels];
685 count[0] = count[1] = 0;
686 for (
int i = 0; i < 2 * channels; ++i) {
692 while (first || updating) {
703 if (updating && (frame + readBlockSize >
m_frameCount))
break;
709 for (
int i = 0; i < readBlockSize; ++i) {
711 if (channels * i + channels > (
int)block.size())
break;
713 for (
int ch = 0; ch < channels; ++ch) {
715 int index = channels * i + ch;
716 float sample = block[index];
718 for (
int ct = 0; ct < 2; ++ct) {
720 int rangeIndex = ch * 2 + ct;
722 if (sample > range[rangeIndex].max() || count[ct] == 0) {
723 range[rangeIndex].
setMax(sample);
725 if (sample < range[rangeIndex].min() || count[ct] == 0) {
726 range[rangeIndex].
setMin(sample);
729 means[rangeIndex] += fabsf(sample);
735 for (
int ct = 0; ct < 2; ++ct) {
737 if (++count[ct] == cacheBlockSize[ct]) {
739 for (
int ch = 0; ch < int(channels); ++ch) {
740 int rangeIndex = ch * 2 + ct;
741 means[rangeIndex] /= count[ct];
742 range[rangeIndex].
setAbsmean(means[rangeIndex]);
744 range[rangeIndex] =
Range();
745 means[rangeIndex] = 0.f;
774 for (
int ct = 0; ct < 2; ++ct) {
778 for (
int ch = 0; ch < int(channels); ++ch) {
779 int rangeIndex = ch * 2 + ct;
780 means[rangeIndex] /= count[ct];
781 range[rangeIndex].
setAbsmean(means[rangeIndex]);
783 range[rangeIndex] =
Range();
784 means[rangeIndex] = 0.f;
800 #ifdef DEBUG_WAVE_FILE_MODEL 801 for (
int ct = 0; ct < 2; ++ct) {
802 cerr <<
"Cache type " << ct <<
" now contains " <<
m_model.
m_cache[ct].size() <<
" ranges" << endl;
810 QString extraAttributes)
const 813 QString(
"type=\"wavefile\" file=\"%1\" %2")
static AudioFileReader * createThreadingReader(FileSource source, int targetRate=0, bool normalised=false, ProgressReporter *reporter=0)
Return an audio file reader initialised to the file at the given path, or NULL if no suitable reader ...
AudioFileReader * m_reader
int getChannelCount() const
virtual int getMinCachePower() const
virtual int getEndFrame() const
Return the last audio frame spanned by the model.
int getSampleRate() const
Return the frame rate in frames per second.
int getNativeRate() const
Return the frame rate of the underlying material, if the model itself has already been resampled.
std::vector< float > SampleBlock
WaveFileModel(FileSource source, int targetRate=0)
std::vector< Range > RangeBlock
virtual QString getMaker() const
Return the "maker" of the work in the audio file, if known.
void ready()
Emitted when internal processing is complete (i.e.
void modelChangedWithin(int startFrame, int endFrame)
Emitted when a model has been edited (or more data retrieved from cache, in the case of a cached mode...
RangeCacheFillThread * m_fillThread
static Preferences * getInstance()
virtual void getInterleavedFrames(int start, int count, SampleBlock &frames) const =0
Return interleaved samples for count frames from index start.
void waitForData()
Block on a sub-event-loop until the whole of the data has been retrieved (if it is remote).
int m_lastDirectReadCount
int getFrameCount() const
bool isOK() const
Return true if the FileSource object is valid and neither error nor cancellation occurred while retri...
virtual void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const
Stream this exportable object out to XML on a text stream.
static QString encodeEntities(QString)
virtual Model * clone() const
Return a copy of this model.
bool isReady(int *) const
Return true if the model has finished loading or calculating all its data, for a model that is capabl...
int getFrameCount() const
virtual int getData(int channel, int start, int count, float *buffer) const
Get the specified set of samples from the given channel of the model in single-precision floating-poi...
static PowerOfSqrtTwoZoomConstraint m_zoomConstraint
int getFillExtent() const
virtual int getStartFrame() const
Return the first audio frame spanned by the model.
virtual void toXml(QTextStream &out, QString indent="", QString extraAttributes="") const
Stream this exportable object out to XML on a text stream.
void modelChanged()
Emitted when a model has been edited (or more data retrieved from cache, in the case of a cached mode...
virtual QString getLocation() const
Return the location of the audio data in the reader (as passed in to the FileSource constructor,...
virtual int getDecodeCompletion() const
QString getMaker() const
Return the "artist" or "maker" of the model, if known.
Model is the base class for all data models that represent any sort of data on a time scale based on ...
virtual void getSummaries(int channel, int start, int count, RangeBlock &ranges, int &blockSize) const
Return ranges from the given start frame, corresponding to the given number of underlying sample fram...
FileSource is a class used to refer to the contents of a file that may be either local or at a remote...
virtual int getNearestBlockSize(int requestedBlockSize, RoundingDirection dir=RoundNearest) const
Given the "ideal" block size (frames per pixel) for a given zoom level, return the nearest viable blo...
void setAbsmean(float absmean)
int getChannelCount() const
Return the number of distinct channels for this model.
QString getTitle() const
Return the "work title" of the model, if known.
virtual int getNativeRate() const
virtual Range getSummary(int channel, int start, int count) const
Return the range from the given start frame, corresponding to the given number of underlying sample f...
int m_lastDirectReadStart
int getSampleRate() const
bool isOK() const
Return true if the model was constructed successfully.
bool getNormaliseAudio() const
True if audio files should be loaded with normalisation (max == 1)
virtual bool isUpdating() const
QString getLocation() const
Return the location of the data in this model (e.g.
virtual int getSummaryBlockSize(int desired) const
virtual QString getTitle() const
Return the title of the work in the audio file, if known.