comparison data/model/WaveFileModel.cpp @ 1096:4d9816ba0ebe simple-fft-model

Rework audio file reader API to prefer using std containers
author Chris Cannam
date Mon, 15 Jun 2015 12:19:47 +0100
parents 9f4505ac9072
children 5cbf71022679
comparison
equal deleted inserted replaced
1095:b66734b5f806 1096:4d9816ba0ebe
29 #include <unistd.h> 29 #include <unistd.h>
30 #include <cmath> 30 #include <cmath>
31 #include <sndfile.h> 31 #include <sndfile.h>
32 32
33 #include <cassert> 33 #include <cassert>
34
35 using namespace std;
34 36
35 //#define DEBUG_WAVE_FILE_MODEL 1 37 //#define DEBUG_WAVE_FILE_MODEL 1
36 38
37 PowerOfSqrtTwoZoomConstraint 39 PowerOfSqrtTwoZoomConstraint
38 WaveFileModel::m_zoomConstraint; 40 WaveFileModel::m_zoomConstraint;
105 if (completion) { 107 if (completion) {
106 *completion = int(c * 100.0 + 0.01); 108 *completion = int(c * 100.0 + 0.01);
107 if (m_reader) { 109 if (m_reader) {
108 int decodeCompletion = m_reader->getDecodeCompletion(); 110 int decodeCompletion = m_reader->getDecodeCompletion();
109 if (decodeCompletion < 90) *completion = decodeCompletion; 111 if (decodeCompletion < 90) *completion = decodeCompletion;
110 else *completion = std::min(*completion, decodeCompletion); 112 else *completion = min(*completion, decodeCompletion);
111 } 113 }
112 if (*completion != 0 && 114 if (*completion != 0 &&
113 *completion != 100 && 115 *completion != 100 &&
114 prevCompletion != 0 && 116 prevCompletion != 0 &&
115 prevCompletion > *completion) { 117 prevCompletion > *completion) {
182 { 184 {
183 if (m_reader) return m_reader->getLocalFilename(); 185 if (m_reader) return m_reader->getLocalFilename();
184 return ""; 186 return "";
185 } 187 }
186 188
187 sv_frame_t 189 vector<float>
188 WaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count, 190 WaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count) const
189 float *buffer) const
190 { 191 {
191 // Always read these directly from the file. 192 // Always read these directly from the file.
192 // This is used for e.g. audio playback. 193 // This is used for e.g. audio playback or input to transforms.
193 // Could be much more efficient (although compiler optimisation will help)
194 194
195 #ifdef DEBUG_WAVE_FILE_MODEL 195 #ifdef DEBUG_WAVE_FILE_MODEL
196 cout << "WaveFileModel::getData[" << this << "]: " << channel << ", " << start << ", " << count << ", " << buffer << endl; 196 cout << "WaveFileModel::getData[" << this << "]: " << channel << ", " << start << ", " << count << ", " << buffer << endl;
197 #endif 197 #endif
198 198
199 if (start >= m_startFrame) {
200 start -= m_startFrame;
201 } else {
202 for (sv_frame_t i = 0; i < count; ++i) {
203 buffer[i] = 0.f;
204 }
205 if (count <= m_startFrame - start) {
206 return 0;
207 } else {
208 count -= (m_startFrame - start);
209 start = 0;
210 }
211 }
212
213 if (!m_reader || !m_reader->isOK() || count == 0) { 199 if (!m_reader || !m_reader->isOK() || count == 0) {
214 for (sv_frame_t i = 0; i < count; ++i) buffer[i] = 0.f; 200 return {};
215 return 0; 201 }
216 } 202
217 203 if (channel != -1) {
218 #ifdef DEBUG_WAVE_FILE_MODEL 204 // get a single channel
219 // SVDEBUG << "WaveFileModel::getValues(" << channel << ", " 205 auto data = getMultiChannelData(channel, channel, start, count);
220 // << start << ", " << end << "): calling reader" << endl; 206 if (data.empty()) return {};
221 #endif 207 else return data[0];
222 208 }
223 int channels = getChannelCount(); 209
224 210 // channel == -1, mix down all channels
225 SampleBlock frames = m_reader->getInterleavedFrames(start, count); 211
226 212 auto all = getMultiChannelData(0, getChannelCount()-1, start, count);
227 sv_frame_t i = 0; 213 if (all.empty()) return {};
228 214
229 int ch0 = channel, ch1 = channel; 215 sv_frame_t n = all[0].size();
230 if (channel == -1) { 216 vector<float> result(n, 0.f);
231 ch0 = 0; 217
232 ch1 = channels - 1; 218 for (int c = 0; in_range_for(all, c); ++c) {
233 } 219 for (sv_frame_t i = 0; i < n; ++i) {
234 220 result[i] += all[c][i];
235 while (i < count) { 221 }
236 222 }
237 buffer[i] = 0.0; 223
238 224 return result;
239 for (int ch = ch0; ch <= ch1; ++ch) { 225 }
240 226
241 sv_frame_t index = i * channels + ch; 227 vector<vector<float>>
242 if (index >= (sv_frame_t)frames.size()) break;
243
244 float sample = frames[index];
245 buffer[i] += sample;
246 }
247
248 ++i;
249 }
250
251 return i;
252 }
253
254 sv_frame_t
255 WaveFileModel::getMultiChannelData(int fromchannel, int tochannel, 228 WaveFileModel::getMultiChannelData(int fromchannel, int tochannel,
256 sv_frame_t start, sv_frame_t count, 229 sv_frame_t start, sv_frame_t count) const
257 float **buffer) const
258 { 230 {
259 #ifdef DEBUG_WAVE_FILE_MODEL 231 #ifdef DEBUG_WAVE_FILE_MODEL
260 cout << "WaveFileModel::getData[" << this << "]: " << fromchannel << "," << tochannel << ", " << start << ", " << count << ", " << buffer << endl; 232 cout << "WaveFileModel::getData[" << this << "]: " << fromchannel << "," << tochannel << ", " << start << ", " << count << ", " << buffer << endl;
261 #endif 233 #endif
262 234
264 236
265 if (fromchannel > tochannel) { 237 if (fromchannel > tochannel) {
266 cerr << "ERROR: WaveFileModel::getData: fromchannel (" 238 cerr << "ERROR: WaveFileModel::getData: fromchannel ("
267 << fromchannel << ") > tochannel (" << tochannel << ")" 239 << fromchannel << ") > tochannel (" << tochannel << ")"
268 << endl; 240 << endl;
269 return 0; 241 return {};
270 } 242 }
271 243
272 if (tochannel >= channels) { 244 if (tochannel >= channels) {
273 cerr << "ERROR: WaveFileModel::getData: tochannel (" 245 cerr << "ERROR: WaveFileModel::getData: tochannel ("
274 << tochannel << ") >= channel count (" << channels << ")" 246 << tochannel << ") >= channel count (" << channels << ")"
275 << endl; 247 << endl;
276 return 0; 248 return {};
277 } 249 }
278 250
279 if (fromchannel == tochannel) { 251 if (!m_reader || !m_reader->isOK() || count == 0) {
280 return getData(fromchannel, start, count, buffer[0]); 252 return {};
281 } 253 }
282 254
283 int reqchannels = (tochannel - fromchannel) + 1; 255 int reqchannels = (tochannel - fromchannel) + 1;
284
285 // Always read these directly from the file.
286 // This is used for e.g. audio playback.
287 // Could be much more efficient (although compiler optimisation will help)
288 256
289 if (start >= m_startFrame) { 257 if (start >= m_startFrame) {
290 start -= m_startFrame; 258 start -= m_startFrame;
291 } else { 259 } else {
292 for (int c = 0; c < reqchannels; ++c) {
293 for (sv_frame_t i = 0; i < count; ++i) buffer[c][i] = 0.f;
294 }
295 if (count <= m_startFrame - start) { 260 if (count <= m_startFrame - start) {
296 return 0; 261 return {};
297 } else { 262 } else {
298 count -= (m_startFrame - start); 263 count -= (m_startFrame - start);
299 start = 0; 264 start = 0;
300 } 265 }
301 } 266 }
302 267
303 if (!m_reader || !m_reader->isOK() || count == 0) { 268 vector<float> interleaved = m_reader->getInterleavedFrames(start, count);
304 for (int c = 0; c < reqchannels; ++c) { 269 if (channels == 1) return { interleaved };
305 for (sv_frame_t i = 0; i < count; ++i) buffer[c][i] = 0.f; 270
306 } 271 sv_frame_t obtained = interleaved.size() / channels;
307 return 0; 272 vector<vector<float>> result(reqchannels, vector<float>(obtained, 0.f));
308 } 273
309 274 for (int c = fromchannel; c <= tochannel; ++c) {
310 SampleBlock frames = m_reader->getInterleavedFrames(start, count); 275 int destc = c - fromchannel;
311 276 for (int i = 0; i < obtained; ++i) {
312 sv_frame_t i = 0; 277 result[destc][i] = interleaved[i * channels + c];
313 278 }
314 sv_frame_t index = 0, available = frames.size(); 279 }
315 280
316 while (i < count) { 281 return result;
317
318 if (index >= available) break;
319
320 int destc = 0;
321
322 for (int c = 0; c < channels; ++c) {
323
324 if (c >= fromchannel && c <= tochannel) {
325 buffer[destc][i] = frames[index];
326 ++destc;
327 }
328
329 ++index;
330 }
331
332 ++i;
333 }
334
335 return i;
336 } 282 }
337 283
338 int 284 int
339 WaveFileModel::getSummaryBlockSize(int desired) const 285 WaveFileModel::getSummaryBlockSize(int desired) const
340 { 286 {
519 } 465 }
520 } 466 }
521 467
522 if (blockStart > start) { 468 if (blockStart > start) {
523 Range startRange = getSummary(channel, start, blockStart - start); 469 Range startRange = getSummary(channel, start, blockStart - start);
524 range.setMin(std::min(range.min(), startRange.min())); 470 range.setMin(min(range.min(), startRange.min()));
525 range.setMax(std::max(range.max(), startRange.max())); 471 range.setMax(max(range.max(), startRange.max()));
526 range.setAbsmean(std::min(range.absmean(), startRange.absmean())); 472 range.setAbsmean(min(range.absmean(), startRange.absmean()));
527 } 473 }
528 474
529 if (blockEnd < start + count) { 475 if (blockEnd < start + count) {
530 Range endRange = getSummary(channel, blockEnd, start + count - blockEnd); 476 Range endRange = getSummary(channel, blockEnd, start + count - blockEnd);
531 range.setMin(std::min(range.min(), endRange.min())); 477 range.setMin(min(range.min(), endRange.min()));
532 range.setMax(std::max(range.max(), endRange.max())); 478 range.setMax(max(range.max(), endRange.max()));
533 range.setAbsmean(std::min(range.absmean(), endRange.absmean())); 479 range.setAbsmean(min(range.absmean(), endRange.absmean()));
534 } 480 }
535 481
536 return range; 482 return range;
537 } 483 }
538 484
603 cacheBlockSize[1] = (int((1 << m_model.m_zoomConstraint.getMinCachePower()) * 549 cacheBlockSize[1] = (int((1 << m_model.m_zoomConstraint.getMinCachePower()) *
604 sqrt(2.) + 0.01)); 550 sqrt(2.) + 0.01));
605 551
606 sv_frame_t frame = 0; 552 sv_frame_t frame = 0;
607 const sv_frame_t readBlockSize = 16384; 553 const sv_frame_t readBlockSize = 16384;
608 SampleBlock block; 554 vector<float> block;
609 555
610 if (!m_model.isOK()) return; 556 if (!m_model.isOK()) return;
611 557
612 int channels = m_model.getChannelCount(); 558 int channels = m_model.getChannelCount();
613 bool updating = m_model.m_reader->isUpdating(); 559 bool updating = m_model.m_reader->isUpdating();