diff data/model/WaveFileModel.cpp @ 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 c022976d18e8
children 70a232b1f12a
line wrap: on
line diff
--- 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);