Mercurial > hg > svcore
changeset 300:5877d68815c7
* Change WaveFileModel API from getValues(start,end) to getData(start,count).
It's much less error-prone to pass in frame counts instead of start/end
locations. Should have done this ages ago. This closes #1794563.
* Add option to apply a transform to only the selection region, instead of
the whole audio.
* (to make the above work properly) Add start frame offset to wave models
author | Chris Cannam |
---|---|
date | Mon, 01 Oct 2007 13:48:38 +0000 |
parents | 576be0d0d218 |
children | 73537d900d4b |
files | base/Selection.cpp base/Selection.h data/fft/FFTDataServer.cpp data/fileio/WavFileWriter.cpp data/model/AggregateWaveModel.cpp data/model/AggregateWaveModel.h data/model/DenseTimeValueModel.h data/model/RangeSummarisableTimeValueModel.h data/model/WaveFileModel.cpp data/model/WaveFileModel.h data/model/WritableWaveFileModel.cpp data/model/WritableWaveFileModel.h |
diffstat | 12 files changed, 202 insertions(+), 136 deletions(-) [+] |
line wrap: on
line diff
--- a/base/Selection.cpp Fri Sep 28 16:15:06 2007 +0000 +++ b/base/Selection.cpp Mon Oct 01 13:48:38 2007 +0000 @@ -172,6 +172,25 @@ } } +void +MultiSelection::getExtents(size_t &startFrame, size_t &endFrame) const +{ + startFrame = 0; + endFrame = 0; + + for (SelectionList::const_iterator i = m_selections.begin(); + i != m_selections.end(); ++i) { + + if (i == m_selections.begin() || i->getStartFrame() < startFrame) { + startFrame = i->getStartFrame(); + } + + if (i == m_selections.begin() || i->getEndFrame() > endFrame) { + endFrame = i->getEndFrame(); + } + } +} + Selection MultiSelection::getContainingSelection(size_t frame, bool defaultToFollowing) const {
--- a/base/Selection.h Fri Sep 28 16:15:06 2007 +0000 +++ b/base/Selection.h Mon Oct 01 13:48:38 2007 +0000 @@ -57,6 +57,8 @@ void removeSelection(const Selection &selection); void clearSelections(); + void getExtents(size_t &startFrame, size_t &endFrame) const; + /** * Return the selection that contains a given frame. * If defaultToFollowing is true, and if the frame is not in a
--- a/data/fft/FFTDataServer.cpp Fri Sep 28 16:15:06 2007 +0000 +++ b/data/fft/FFTDataServer.cpp Mon Oct 01 13:48:38 2007 +0000 @@ -1056,8 +1056,11 @@ << " from channel " << m_channel << std::endl; #endif - size_t got = m_model->getValues(m_channel, startFrame + pfx, - endFrame, m_fftInput + off + pfx); + size_t count = 0; + if (endFrame > startFrame + pfx) count = endFrame - (startFrame + pfx); + + size_t got = m_model->getData(m_channel, startFrame + pfx, + count, m_fftInput + off + pfx); while (got + pfx < m_windowSize) { m_fftInput[off + got + pfx] = 0.0;
--- a/data/fileio/WavFileWriter.cpp Fri Sep 28 16:15:06 2007 +0000 +++ b/data/fileio/WavFileWriter.cpp Mon Oct 01 13:48:38 2007 +0000 @@ -103,7 +103,7 @@ size_t n = std::min(bs, f1 - f); for (int c = 0; c < int(m_channels); ++c) { - source->getValues(c, f, f + n, ub); + source->getData(c, f, n, ub); for (size_t i = 0; i < n; ++i) { ib[i * m_channels + c] = ub[i]; }
--- a/data/model/AggregateWaveModel.cpp Fri Sep 28 16:15:06 2007 +0000 +++ b/data/model/AggregateWaveModel.cpp Mon Oct 01 13:48:38 2007 +0000 @@ -97,8 +97,8 @@ } size_t -AggregateWaveModel::getValues(int channel, size_t start, size_t end, - float *buffer) const +AggregateWaveModel::getData(int channel, size_t start, size_t count, + float *buffer) const { int ch0 = channel, ch1 = channel; bool mixing = false; @@ -110,22 +110,22 @@ float *readbuf = buffer; if (mixing) { - readbuf = new float[end - start]; - for (size_t i = 0; i < end - start; ++i) { + readbuf = new float[count]; + for (size_t i = 0; i < count; ++i) { buffer[i] = 0.f; } } - size_t sz = end - start; - + size_t sz = count; + for (int c = ch0; c <= ch1; ++c) { size_t szHere = - m_components[c].model->getValues(m_components[c].channel, - start, end, - readbuf); + m_components[c].model->getData(m_components[c].channel, + start, count, + readbuf); if (szHere < sz) sz = szHere; if (mixing) { - for (size_t i = 0; i < end - start; ++i) { + for (size_t i = 0; i < count; ++i) { buffer[i] += readbuf[i]; } } @@ -136,8 +136,8 @@ } size_t -AggregateWaveModel::getValues(int channel, size_t start, size_t end, - double *buffer) const +AggregateWaveModel::getData(int channel, size_t start, size_t count, + double *buffer) const { int ch0 = channel, ch1 = channel; bool mixing = false; @@ -149,22 +149,22 @@ double *readbuf = buffer; if (mixing) { - readbuf = new double[end - start]; - for (size_t i = 0; i < end - start; ++i) { - buffer[i] = 0.f; + readbuf = new double[count]; + for (size_t i = 0; i < count; ++i) { + buffer[i] = 0.0; } } - size_t sz = end - start; + size_t sz = count; for (int c = ch0; c <= ch1; ++c) { size_t szHere = - m_components[c].model->getValues(m_components[c].channel, - start, end, - readbuf); + m_components[c].model->getData(m_components[c].channel, + start, count, + readbuf); if (szHere < sz) sz = szHere; if (mixing) { - for (size_t i = 0; i < end - start; ++i) { + for (size_t i = 0; i < count; ++i) { buffer[i] += readbuf[i]; } } @@ -175,14 +175,14 @@ } void -AggregateWaveModel::getRanges(size_t channel, size_t start, size_t end, - RangeBlock &ranges, size_t &blockSize) const +AggregateWaveModel::getSummaries(size_t channel, size_t start, size_t count, + RangeBlock &ranges, size_t &blockSize) const { //!!! complete } AggregateWaveModel::Range -AggregateWaveModel::getRange(size_t channel, size_t start, size_t end) const +AggregateWaveModel::getSummary(size_t channel, size_t start, size_t count) const { //!!! complete return Range();
--- a/data/model/AggregateWaveModel.h Fri Sep 28 16:15:06 2007 +0000 +++ b/data/model/AggregateWaveModel.h Mon Oct 01 13:48:38 2007 +0000 @@ -59,17 +59,17 @@ virtual size_t getStartFrame() const { return 0; } virtual size_t getEndFrame() const { return getFrameCount(); } - virtual size_t getValues(int channel, size_t start, size_t end, - float *buffer) const; + virtual size_t getData(int channel, size_t start, size_t count, + float *buffer) const; - virtual size_t getValues(int channel, size_t start, size_t end, - double *buffer) const; + virtual size_t getData(int channel, size_t start, size_t count, + double *buffer) const; - virtual void getRanges(size_t channel, size_t start, size_t end, - RangeBlock &ranges, - size_t &blockSize) const; + virtual void getSummaries(size_t channel, size_t start, size_t count, + RangeBlock &ranges, + size_t &blockSize) const; - virtual Range getRange(size_t channel, size_t start, size_t end) const; + virtual Range getSummary(size_t channel, size_t start, size_t count) const; virtual void toXml(QTextStream &out, QString indent = "",
--- a/data/model/DenseTimeValueModel.h Fri Sep 28 16:15:06 2007 +0000 +++ b/data/model/DenseTimeValueModel.h Mon Oct 01 13:48:38 2007 +0000 @@ -58,8 +58,8 @@ * If the channel is given as -1, mix all available channels and * return the result. */ - virtual size_t getValues(int channel, size_t start, size_t end, - float *buffer) const = 0; + virtual size_t getData(int channel, size_t start, size_t count, + float *buffer) const = 0; /** * Get the specified set of samples from the given channel of the @@ -68,8 +68,8 @@ * If the channel is given as -1, mix all available channels and * return the result. */ - virtual size_t getValues(int channel, size_t start, size_t end, - double *buffer) const = 0; + virtual size_t getData(int channel, size_t start, size_t count, + double *buffer) const = 0; }; #endif
--- a/data/model/RangeSummarisableTimeValueModel.h Fri Sep 28 16:15:06 2007 +0000 +++ b/data/model/RangeSummarisableTimeValueModel.h Mon Oct 01 13:48:38 2007 +0000 @@ -53,25 +53,26 @@ typedef std::vector<Range> RangeBlock; /** - * Return ranges between the given start and end frames, - * summarised at the given block size. ((end - start + 1) / - * blockSize) ranges should ideally be returned. + * Return ranges from the given start frame, corresponding to the + * given number of underlying sample frames, summarised at the + * given block size. duration / blockSize ranges should ideally + * be returned. * * If the given block size is not supported by this model * (according to its zoom constraint), also modify the blockSize * parameter so as to return the block size that was actually * obtained. */ - virtual void getRanges(size_t channel, size_t start, size_t end, - RangeBlock &ranges, - size_t &blockSize) const = 0; + virtual void getSummaries(size_t channel, size_t start, size_t count, + RangeBlock &ranges, + size_t &blockSize) const = 0; /** - * Return the range between the given start and end frames, - * summarised at a block size equal to the distance between start - * and end frames. + * Return the range from the given start frame, corresponding to + * the given number of underlying sample frames, summarised at a + * block size equal to the distance between start and end frames. */ - virtual Range getRange(size_t channel, size_t start, size_t end) const = 0; + virtual Range getSummary(size_t channel, size_t start, size_t count) const = 0; virtual void setAlignment(AlignmentModel *alignment); // I take ownership virtual const Model *getAlignmentReference() const;
--- a/data/model/WaveFileModel.cpp Fri Sep 28 16:15:06 2007 +0000 +++ b/data/model/WaveFileModel.cpp Mon Oct 01 13:48:38 2007 +0000 @@ -41,6 +41,7 @@ WaveFileModel::WaveFileModel(QString path, size_t targetRate) : m_path(path), m_myReader(true), + m_startFrame(0), m_fillThread(0), m_updateTimer(0), m_lastFillExtent(0), @@ -56,6 +57,7 @@ WaveFileModel::WaveFileModel(QString path, QString originalLocation, size_t targetRate) : m_path(originalLocation), m_myReader(true), + m_startFrame(0), m_fillThread(0), m_updateTimer(0), m_lastFillExtent(0), @@ -71,6 +73,7 @@ WaveFileModel::WaveFileModel(QString path, AudioFileReader *reader) : m_path(path), m_myReader(false), + m_startFrame(0), m_fillThread(0), m_updateTimer(0), m_lastFillExtent(0), @@ -162,20 +165,29 @@ } size_t -WaveFileModel::getValues(int channel, size_t start, size_t end, - float *buffer) const +WaveFileModel::getData(int channel, size_t start, size_t count, + float *buffer) const { // Always read these directly from the file. // This is used for e.g. audio playback. // Could be much more efficient (although compiler optimisation will help) - if (end < start) { - std::cerr << "ERROR: WaveFileModel::getValues[float]: end < start (" - << end << " < " << start << ")" << std::endl; - assert(end >= start); + if (start > m_startFrame) { + start -= m_startFrame; + } else { + for (size_t i = 0; i < count; ++i) buffer[i] = 0.f; + if (count <= m_startFrame - start) { + return 0; + } else { + count -= (m_startFrame - start); + start = 0; + } } - if (!m_reader || !m_reader->isOK()) return 0; + if (!m_reader || !m_reader->isOK() || count == 0) { + for (size_t i = 0; i < count; ++i) buffer[i] = 0.f; + return 0; + } #ifdef DEBUG_WAVE_FILE_MODEL // std::cerr << "WaveFileModel::getValues(" << channel << ", " @@ -183,7 +195,7 @@ #endif SampleBlock frames; - m_reader->getInterleavedFrames(start, end - start, frames); + m_reader->getInterleavedFrames(start, count, frames); size_t i = 0; @@ -193,7 +205,7 @@ ch1 = channels - 1; } - while (i < end - start) { + while (i < count) { buffer[i] = 0.0; @@ -213,19 +225,28 @@ } size_t -WaveFileModel::getValues(int channel, size_t start, size_t end, - double *buffer) const +WaveFileModel::getData(int channel, size_t start, size_t count, + double *buffer) const { - if (end < start) { - std::cerr << "ERROR: WaveFileModel::getValues[double]: end < start (" - << end << " < " << start << ")" << std::endl; - assert(end >= start); + if (start > m_startFrame) { + start -= m_startFrame; + } else { + for (size_t i = 0; i < count; ++i) buffer[i] = 0.0; + if (count <= m_startFrame - start) { + return 0; + } else { + count -= (m_startFrame - start); + start = 0; + } } - if (!m_reader || !m_reader->isOK()) return 0; + if (!m_reader || !m_reader->isOK() || count == 0) { + for (size_t i = 0; i < count; ++i) buffer[i] = 0.0; + return 0; + } SampleBlock frames; - m_reader->getInterleavedFrames(start, end - start, frames); + m_reader->getInterleavedFrames(start, count, frames); size_t i = 0; @@ -235,7 +256,7 @@ ch1 = channels - 1; } - while (i < end - start) { + while (i < count) { buffer[i] = 0.0; @@ -255,15 +276,17 @@ } void -WaveFileModel::getRanges(size_t channel, size_t start, size_t end, - RangeBlock &ranges, size_t &blockSize) const +WaveFileModel::getSummaries(size_t channel, size_t start, size_t count, + RangeBlock &ranges, size_t &blockSize) const { ranges.clear(); if (!isOK()) return; - if (end <= start) { - std::cerr << "WARNING: Internal error: end <= start in WaveFileModel::getRanges (end = " << end << ", start = " << start << ", blocksize = " << blockSize << ")" << std::endl; - return; + if (start > m_startFrame) start -= m_startFrame; + else if (count <= m_startFrame - start) return; + else { + count -= (m_startFrame - start); + start = 0; } int cacheType = 0; @@ -284,32 +307,32 @@ // for short queries. SampleBlock frames; - m_reader->getInterleavedFrames(start, end - start, frames); + m_reader->getInterleavedFrames(start, count, frames); float max = 0.0, min = 0.0, total = 0.0; - size_t i = 0, count = 0; + size_t i = 0, got = 0; - while (i < end - start) { + while (i < count) { size_t index = i * channels + channel; if (index >= frames.size()) break; float sample = frames[index]; - if (sample > max || count == 0) max = sample; - if (sample < min || count == 0) min = sample; + if (sample > max || got == 0) max = sample; + if (sample < min || got == 0) min = sample; total += fabsf(sample); ++i; - ++count; + ++got; - if (count == blockSize) { - ranges.push_back(Range(min, max, total / count)); + if (got == blockSize) { + ranges.push_back(Range(min, max, total / got)); min = max = total = 0.0f; - count = 0; + got = 0; } } - if (count > 0) { - ranges.push_back(Range(min, max, total / count)); + if (got > 0) { + ranges.push_back(Range(min, max, total / got)); } return; @@ -331,37 +354,37 @@ } size_t startIndex = start / cacheBlock; - size_t endIndex = end / cacheBlock; + size_t endIndex = (start + count) / cacheBlock; float max = 0.0, min = 0.0, total = 0.0; - size_t i = 0, count = 0; + size_t i = 0, got = 0; #ifdef DEBUG_WAVE_FILE_MODEL - cerr << "blockSize is " << blockSize << ", cacheBlock " << cacheBlock << ", start " << start << ", end " << end << " (frame count " << getFrameCount() << "), power is " << power << ", div is " << div << ", startIndex " << startIndex << ", endIndex " << endIndex << endl; + cerr << "blockSize is " << blockSize << ", cacheBlock " << cacheBlock << ", start " << start << ", count " << count << " (frame count " << getFrameCount() << "), power is " << power << ", div is " << div << ", startIndex " << startIndex << ", endIndex " << endIndex << endl; #endif - for (i = 0; i < endIndex - startIndex; ) { + for (i = 0; i <= endIndex - startIndex; ) { size_t index = (i + startIndex) * channels + channel; if (index >= cache.size()) break; const Range &range = cache[index]; - if (range.max > max || count == 0) max = range.max; - if (range.min < min || count == 0) min = range.min; + if (range.max > max || got == 0) max = range.max; + if (range.min < min || got == 0) min = range.min; total += range.absmean; ++i; - ++count; + ++got; - if (count == div) { - ranges.push_back(Range(min, max, total / count)); + if (got == div) { + ranges.push_back(Range(min, max, total / got)); min = max = total = 0.0f; - count = 0; + got = 0; } } - if (count > 0) { - ranges.push_back(Range(min, max, total / count)); + if (got > 0) { + ranges.push_back(Range(min, max, total / got)); } } @@ -372,30 +395,32 @@ } WaveFileModel::Range -WaveFileModel::getRange(size_t channel, size_t start, size_t end) const +WaveFileModel::getSummary(size_t channel, size_t start, size_t count) const { Range range; if (!isOK()) return range; - if (end <= start) { - std::cerr << "WARNING: Internal error: end <= start in WaveFileModel::getRange (end = " << end << ", start = " << start << ")" << std::endl; - return range; + if (start > m_startFrame) start -= m_startFrame; + else if (count <= m_startFrame - start) return range; + else { + count -= (m_startFrame - start); + start = 0; } size_t blockSize; - for (blockSize = 1; blockSize <= end - start; blockSize *= 2); - blockSize /= 2; + for (blockSize = 1; blockSize <= count; blockSize *= 2); + if (blockSize > 1) blockSize /= 2; bool first = false; size_t blockStart = (start / blockSize) * blockSize; - size_t blockEnd = (end / blockSize) * blockSize; + size_t blockEnd = ((start + count) / blockSize) * blockSize; if (blockStart < start) blockStart += blockSize; if (blockEnd > blockStart) { RangeBlock ranges; - getRanges(channel, blockStart, blockEnd, ranges, blockSize); + getSummaries(channel, blockStart, blockEnd - blockStart, ranges, blockSize); for (size_t i = 0; i < ranges.size(); ++i) { if (first || ranges[i].min < range.min) range.min = ranges[i].min; if (first || ranges[i].max > range.max) range.max = ranges[i].max; @@ -405,14 +430,14 @@ } if (blockStart > start) { - Range startRange = getRange(channel, start, blockStart); + Range startRange = getSummary(channel, start, blockStart - start); range.min = std::min(range.min, startRange.min); range.max = std::max(range.max, startRange.max); range.absmean = std::min(range.absmean, startRange.absmean); } - if (blockEnd < end) { - Range endRange = getRange(channel, blockEnd, end); + if (blockEnd < start + count) { + Range endRange = getSummary(channel, blockEnd, start + count - blockEnd); range.min = std::min(range.min, endRange.min); range.max = std::max(range.max, endRange.max); range.absmean = std::min(range.absmean, endRange.absmean);
--- a/data/model/WaveFileModel.h Fri Sep 28 16:15:06 2007 +0000 +++ b/data/model/WaveFileModel.h Mon Oct 01 13:48:38 2007 +0000 @@ -52,20 +52,22 @@ float getValueMinimum() const { return -1.0f; } float getValueMaximum() const { return 1.0f; } - virtual size_t getStartFrame() const { return 0; } - virtual size_t getEndFrame() const { return getFrameCount(); } + virtual size_t getStartFrame() const { return m_startFrame; } + virtual size_t getEndFrame() const { return m_startFrame + getFrameCount(); } - virtual size_t getValues(int channel, size_t start, size_t end, - float *buffer) const; + void setStartFrame(size_t startFrame) { m_startFrame = startFrame; } - virtual size_t getValues(int channel, size_t start, size_t end, - double *buffer) const; + virtual size_t getData(int channel, size_t start, size_t count, + float *buffer) const; - virtual void getRanges(size_t channel, size_t start, size_t end, - RangeBlock &ranges, - size_t &blockSize) const; + virtual size_t getData(int channel, size_t start, size_t count, + double *buffer) const; - virtual Range getRange(size_t channel, size_t start, size_t end) const; + virtual void getSummaries(size_t channel, size_t start, size_t count, + RangeBlock &ranges, + size_t &blockSize) const; + + virtual Range getSummary(size_t channel, size_t start, size_t count) const; virtual void toXml(QTextStream &out, QString indent = "", @@ -105,6 +107,8 @@ AudioFileReader *m_reader; bool m_myReader; + size_t m_startFrame; + RangeBlock m_cache[2]; // interleaved at two base resolutions mutable QMutex m_mutex; RangeCacheFillThread *m_fillThread;
--- a/data/model/WritableWaveFileModel.cpp Fri Sep 28 16:15:06 2007 +0000 +++ b/data/model/WritableWaveFileModel.cpp Mon Oct 01 13:48:38 2007 +0000 @@ -37,6 +37,7 @@ m_sampleRate(sampleRate), m_channels(channels), m_frameCount(0), + m_startFrame(0), m_completion(0) { if (path.isEmpty()) { @@ -75,6 +76,7 @@ m_reader = 0; return; } + m_model->setStartFrame(m_startFrame); connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged())); connect(m_model, SIGNAL(modelChanged(size_t, size_t)), @@ -88,6 +90,13 @@ delete m_reader; } +void +WritableWaveFileModel::setStartFrame(size_t startFrame) +{ + m_startFrame = startFrame; + if (m_model) m_model->setStartFrame(startFrame); +} + bool WritableWaveFileModel::addSamples(float **samples, size_t count) { @@ -161,38 +170,38 @@ } size_t -WritableWaveFileModel::getValues(int channel, size_t start, size_t end, - float *buffer) const +WritableWaveFileModel::getData(int channel, size_t start, size_t count, + float *buffer) const { if (!m_model || m_model->getChannelCount() == 0) return 0; - return m_model->getValues(channel, start, end, buffer); + return m_model->getData(channel, start, count, buffer); } size_t -WritableWaveFileModel::getValues(int channel, size_t start, size_t end, - double *buffer) const +WritableWaveFileModel::getData(int channel, size_t start, size_t count, + double *buffer) const { if (!m_model || m_model->getChannelCount() == 0) return 0; // std::cerr << "WritableWaveFileModel::getValues(" << channel << ", " // << start << ", " << end << "): calling model" << std::endl; - return m_model->getValues(channel, start, end, buffer); + return m_model->getData(channel, start, count, buffer); } void -WritableWaveFileModel::getRanges(size_t channel, size_t start, size_t end, - RangeBlock &ranges, - size_t &blockSize) const +WritableWaveFileModel::getSummaries(size_t channel, size_t start, size_t count, + RangeBlock &ranges, + size_t &blockSize) const { ranges.clear(); if (!m_model || m_model->getChannelCount() == 0) return; - m_model->getRanges(channel, start, end, ranges, blockSize); + m_model->getSummaries(channel, start, count, ranges, blockSize); } WritableWaveFileModel::Range -WritableWaveFileModel::getRange(size_t channel, size_t start, size_t end) const +WritableWaveFileModel::getSummary(size_t channel, size_t start, size_t count) const { if (!m_model || m_model->getChannelCount() == 0) return Range(); - return m_model->getRange(channel, start, end); + return m_model->getSummary(channel, start, count); } void
--- a/data/model/WritableWaveFileModel.h Fri Sep 28 16:15:06 2007 +0000 +++ b/data/model/WritableWaveFileModel.h Mon Oct 01 13:48:38 2007 +0000 @@ -57,19 +57,21 @@ float getValueMinimum() const { return -1.0f; } float getValueMaximum() const { return 1.0f; } - virtual size_t getStartFrame() const { return 0; } - virtual size_t getEndFrame() const { return getFrameCount(); } + virtual size_t getStartFrame() const { return m_startFrame; } + virtual size_t getEndFrame() const { return m_startFrame + getFrameCount(); } - virtual size_t getValues(int channel, size_t start, size_t end, - float *buffer) const; + void setStartFrame(size_t startFrame); - virtual size_t getValues(int channel, size_t start, size_t end, - double *buffer) const; + virtual size_t getData(int channel, size_t start, size_t count, + float *buffer) const; - virtual void getRanges(size_t channel, size_t start, size_t end, - RangeBlock &ranges, size_t &blockSize) const; + virtual size_t getData(int channel, size_t start, size_t count, + double *buffer) const; - virtual Range getRange(size_t channel, size_t start, size_t end) const; + virtual void getSummaries(size_t channel, size_t start, size_t count, + RangeBlock &ranges, size_t &blockSize) const; + + virtual Range getSummary(size_t channel, size_t start, size_t count) const; virtual void toXml(QTextStream &out, QString indent = "", @@ -82,6 +84,7 @@ size_t m_sampleRate; size_t m_channels; size_t m_frameCount; + size_t m_startFrame; int m_completion; };