Mercurial > hg > svcore
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(); |