Mercurial > hg > svapp
comparison audio/AudioCallbackPlaySource.cpp @ 546:4de547a5905c 3.0-integration
Update for bqaudioio changes
author | Chris Cannam |
---|---|
date | Tue, 06 Dec 2016 15:59:06 +0000 |
parents | 699db455a3e1 |
children | c732251237b1 |
comparison
equal
deleted
inserted
replaced
543:699db455a3e1 | 546:4de547a5905c |
---|---|
75 m_stretchRatio(1.0), | 75 m_stretchRatio(1.0), |
76 m_stretchMono(false), | 76 m_stretchMono(false), |
77 m_stretcherInputCount(0), | 77 m_stretcherInputCount(0), |
78 m_stretcherInputs(0), | 78 m_stretcherInputs(0), |
79 m_stretcherInputSizes(0), | 79 m_stretcherInputSizes(0), |
80 m_fillThread(0), | 80 m_fillThread(0) |
81 m_resampler(0) | |
82 { | 81 { |
83 m_viewManager->setAudioPlaySource(this); | 82 m_viewManager->setAudioPlaySource(this); |
84 | 83 |
85 connect(m_viewManager, SIGNAL(selectionChanged()), | 84 connect(m_viewManager, SIGNAL(selectionChanged()), |
86 this, SLOT(selectionChanged())); | 85 this, SLOT(selectionChanged())); |
228 } else { | 227 } else { |
229 if (willPlay) clearRingBuffers(true); | 228 if (willPlay) clearRingBuffers(true); |
230 } | 229 } |
231 | 230 |
232 if (buffersChanged || srChanged) { | 231 if (buffersChanged || srChanged) { |
233 if (m_resampler) { | 232 |
234 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 233 // There are more channels than there were before, or the |
235 cerr << "AudioCallbackPlaySource::addModel: Buffers or sample rate changed, deleting existing resampler" << endl; | 234 // source sample rate has changed |
236 #endif | 235 |
237 delete m_resampler; | 236 //!!! |
238 m_resampler = 0; | 237 |
239 } | |
240 } | 238 } |
241 | 239 |
242 rebuildRangeLists(); | 240 rebuildRangeLists(); |
243 | 241 |
244 m_mutex.unlock(); | 242 m_mutex.unlock(); |
245 | 243 |
246 initialiseResampler(); | 244 //!!! |
247 | 245 |
248 m_audioGenerator->setTargetChannelCount(getTargetChannelCount()); | 246 m_audioGenerator->setTargetChannelCount(getTargetChannelCount()); |
249 | 247 |
250 if (!m_fillThread) { | 248 if (!m_fillThread) { |
251 m_fillThread = new FillThread(*this); | 249 m_fillThread = new FillThread(*this); |
299 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t))); | 297 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t))); |
300 | 298 |
301 m_models.erase(model); | 299 m_models.erase(model); |
302 | 300 |
303 if (m_models.empty()) { | 301 if (m_models.empty()) { |
304 if (m_resampler) { | |
305 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
306 cerr << "AudioCallbackPlaySource::removeModel: No models left, deleting resampler" << endl; | |
307 #endif | |
308 delete m_resampler; | |
309 m_resampler = 0; | |
310 } | |
311 m_sourceSampleRate = 0; | 302 m_sourceSampleRate = 0; |
312 } | 303 } |
313 | 304 |
314 sv_frame_t lastEnd = 0; | 305 sv_frame_t lastEnd = 0; |
315 for (std::set<Model *>::const_iterator i = m_models.begin(); | 306 for (std::set<Model *>::const_iterator i = m_models.begin(); |
341 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 332 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
342 cout << "AudioCallbackPlaySource::clearModels()" << endl; | 333 cout << "AudioCallbackPlaySource::clearModels()" << endl; |
343 #endif | 334 #endif |
344 | 335 |
345 m_models.clear(); | 336 m_models.clear(); |
346 | |
347 if (m_resampler) { | |
348 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
349 cerr << "AudioCallbackPlaySource::clearModels: Deleting resampler" << endl; | |
350 #endif | |
351 delete m_resampler; | |
352 m_resampler = 0; | |
353 } | |
354 | 337 |
355 m_lastModelEndFrame = 0; | 338 m_lastModelEndFrame = 0; |
356 | 339 |
357 m_sourceSampleRate = 0; | 340 m_sourceSampleRate = 0; |
358 | 341 |
469 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 452 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
470 cerr << "reset ring buffer for channel " << c << endl; | 453 cerr << "reset ring buffer for channel " << c << endl; |
471 #endif | 454 #endif |
472 if (rb) rb->reset(); | 455 if (rb) rb->reset(); |
473 } | 456 } |
474 } | |
475 if (m_resampler) { | |
476 m_resampler->reset(); | |
477 } | 457 } |
478 | 458 |
479 m_mutex.unlock(); | 459 m_mutex.unlock(); |
480 | 460 |
481 m_audioGenerator->reset(); | 461 m_audioGenerator->reset(); |
945 AudioCallbackPlaySource::setSystemPlaybackSampleRate(int sr) | 925 AudioCallbackPlaySource::setSystemPlaybackSampleRate(int sr) |
946 { | 926 { |
947 bool first = (m_targetSampleRate == 0); | 927 bool first = (m_targetSampleRate == 0); |
948 | 928 |
949 m_targetSampleRate = sr; | 929 m_targetSampleRate = sr; |
950 initialiseResampler(); | |
951 | 930 |
952 if (first && (m_stretchRatio != 1.f)) { | 931 if (first && (m_stretchRatio != 1.f)) { |
953 // couldn't create a stretcher before because we had no sample | 932 // couldn't create a stretcher before because we had no sample |
954 // rate: make one now | 933 // rate: make one now |
955 setTimeStretch(m_stretchRatio); | 934 setTimeStretch(m_stretchRatio); |
956 } | 935 } |
957 } | 936 } |
958 | 937 |
959 void | 938 void |
960 AudioCallbackPlaySource::initialiseResampler() | 939 AudioCallbackPlaySource::setSystemPlaybackChannelCount(int c) |
961 { | 940 { |
962 m_mutex.lock(); | |
963 | |
964 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
965 cerr << "AudioCallbackPlaySource::initialiseResampler(): from " | |
966 << getSourceSampleRate() << " to " << getTargetSampleRate() << endl; | |
967 #endif | |
968 | |
969 if (m_resampler) { | |
970 delete m_resampler; | |
971 m_resampler = 0; | |
972 } | |
973 | |
974 if (getSourceSampleRate() != getTargetSampleRate()) { | |
975 | |
976 m_resampler = new breakfastquay::Resampler | |
977 (breakfastquay::Resampler::FastestTolerable, | |
978 getTargetChannelCount()); | |
979 | |
980 m_mutex.unlock(); | |
981 | |
982 emit sampleRateMismatch(getSourceSampleRate(), | |
983 getTargetSampleRate(), | |
984 true); | |
985 } else { | |
986 m_mutex.unlock(); | |
987 } | |
988 } | 941 } |
989 | 942 |
990 void | 943 void |
991 AudioCallbackPlaySource::setAuditioningEffect(Auditionable *a) | 944 AudioCallbackPlaySource::setAuditioningEffect(Auditionable *a) |
992 { | 945 { |
1368 | 1321 |
1369 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1322 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1370 cout << "buffered to " << f << " already" << endl; | 1323 cout << "buffered to " << f << " already" << endl; |
1371 #endif | 1324 #endif |
1372 | 1325 |
1373 bool resample = (getSourceSampleRate() != getTargetSampleRate()); | |
1374 | |
1375 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
1376 cout << (resample ? "" : "not ") << "resampling (source " << getSourceSampleRate() << ", target " << getTargetSampleRate() << ")" << endl; | |
1377 #endif | |
1378 | |
1379 int channels = getTargetChannelCount(); | 1326 int channels = getTargetChannelCount(); |
1380 | 1327 |
1381 sv_frame_t orig = space; | 1328 sv_frame_t orig = space; |
1382 sv_frame_t got = 0; | |
1383 | 1329 |
1384 static float **bufferPtrs = 0; | 1330 static float **bufferPtrs = 0; |
1385 static int bufferPtrCount = 0; | 1331 static int bufferPtrCount = 0; |
1386 | 1332 |
1387 if (bufferPtrCount < channels) { | 1333 if (bufferPtrCount < channels) { |
1390 bufferPtrCount = channels; | 1336 bufferPtrCount = channels; |
1391 } | 1337 } |
1392 | 1338 |
1393 sv_frame_t generatorBlockSize = m_audioGenerator->getBlockSize(); | 1339 sv_frame_t generatorBlockSize = m_audioGenerator->getBlockSize(); |
1394 | 1340 |
1395 if (resample && !m_resampler) { | 1341 // space must be a multiple of generatorBlockSize |
1396 throw std::logic_error("Sample rates differ, but no resampler available!"); | 1342 sv_frame_t reqSpace = space; |
1397 } | 1343 space = (reqSpace / generatorBlockSize) * generatorBlockSize; |
1398 | 1344 if (space == 0) { |
1399 if (resample && m_resampler) { | 1345 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1400 | 1346 cout << "requested fill of " << reqSpace |
1401 double ratio = | 1347 << " is less than generator block size of " |
1402 double(getTargetSampleRate()) / double(getSourceSampleRate()); | 1348 << generatorBlockSize << ", leaving it" << endl; |
1403 orig = sv_frame_t(double(orig) / ratio + 0.1); | 1349 #endif |
1404 | 1350 return false; |
1405 // orig must be a multiple of generatorBlockSize | 1351 } |
1406 orig = (orig / generatorBlockSize) * generatorBlockSize; | 1352 |
1407 if (orig == 0) return false; | 1353 if (tmpSize < channels * space) { |
1408 | 1354 delete[] tmp; |
1409 sv_frame_t work = std::max(orig, space); | 1355 tmp = new float[channels * space]; |
1410 | 1356 tmpSize = channels * space; |
1411 // We only allocate one buffer, but we use it in two halves. | 1357 } |
1412 // We place the non-interleaved values in the second half of | 1358 |
1413 // the buffer (orig samples for channel 0, orig samples for | 1359 for (int c = 0; c < channels; ++c) { |
1414 // channel 1 etc), and then interleave them into the first | 1360 |
1415 // half of the buffer. Then we resample back into the second | 1361 bufferPtrs[c] = tmp + c * space; |
1416 // half (interleaved) and de-interleave the results back to | |
1417 // the start of the buffer for insertion into the ringbuffers. | |
1418 // What a faff -- especially as we've already de-interleaved | |
1419 // the audio data from the source file elsewhere before we | |
1420 // even reach this point. | |
1421 | |
1422 if (tmpSize < channels * work * 2) { | |
1423 delete[] tmp; | |
1424 tmp = new float[channels * work * 2]; | |
1425 tmpSize = channels * work * 2; | |
1426 } | |
1427 | |
1428 float *nonintlv = tmp + channels * work; | |
1429 float *intlv = tmp; | |
1430 float *srcout = tmp + channels * work; | |
1431 | |
1432 for (int c = 0; c < channels; ++c) { | |
1433 for (int i = 0; i < orig; ++i) { | |
1434 nonintlv[channels * i + c] = 0.0f; | |
1435 } | |
1436 } | |
1437 | |
1438 for (int c = 0; c < channels; ++c) { | |
1439 bufferPtrs[c] = nonintlv + c * orig; | |
1440 } | |
1441 | |
1442 got = mixModels(f, orig, bufferPtrs); // also modifies f | |
1443 | |
1444 // and interleave into first half | |
1445 for (int c = 0; c < channels; ++c) { | |
1446 for (int i = 0; i < got; ++i) { | |
1447 float sample = nonintlv[c * got + i]; | |
1448 intlv[channels * i + c] = sample; | |
1449 } | |
1450 } | |
1451 | |
1452 SRC_DATA data; | |
1453 data.data_in = intlv; | |
1454 data.data_out = srcout; | |
1455 data.input_frames = long(got); | |
1456 data.output_frames = long(work); | |
1457 data.src_ratio = ratio; | |
1458 data.end_of_input = 0; | |
1459 | |
1460 int err = src_process(m_converter, &data); | |
1461 | |
1462 sv_frame_t toCopy = sv_frame_t(double(got) * ratio + 0.1); | |
1463 | |
1464 if (err) { | |
1465 cerr | |
1466 << "AudioCallbackPlaySourceFillThread: ERROR in samplerate conversion: " | |
1467 << src_strerror(err) << endl; | |
1468 //!!! Then what? | |
1469 } else { | |
1470 got = data.input_frames_used; | |
1471 toCopy = data.output_frames_gen; | |
1472 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
1473 cout << "Resampled " << got << " frames to " << toCopy << " frames" << endl; | |
1474 #endif | |
1475 } | |
1476 | |
1477 for (int c = 0; c < channels; ++c) { | |
1478 for (int i = 0; i < toCopy; ++i) { | |
1479 tmp[i] = srcout[channels * i + c]; | |
1480 } | |
1481 RingBuffer<float> *wb = getWriteRingBuffer(c); | |
1482 if (wb) wb->write(tmp, int(toCopy)); | |
1483 } | |
1484 | |
1485 m_writeBufferFill = f; | |
1486 if (readWriteEqual) m_readBufferFill = f; | |
1487 | |
1488 } else { | |
1489 | |
1490 // space must be a multiple of generatorBlockSize | |
1491 sv_frame_t reqSpace = space; | |
1492 space = (reqSpace / generatorBlockSize) * generatorBlockSize; | |
1493 if (space == 0) { | |
1494 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
1495 cout << "requested fill of " << reqSpace | |
1496 << " is less than generator block size of " | |
1497 << generatorBlockSize << ", leaving it" << endl; | |
1498 #endif | |
1499 return false; | |
1500 } | |
1501 | |
1502 if (tmpSize < channels * space) { | |
1503 delete[] tmp; | |
1504 tmp = new float[channels * space]; | |
1505 tmpSize = channels * space; | |
1506 } | |
1507 | |
1508 for (int c = 0; c < channels; ++c) { | |
1509 | |
1510 bufferPtrs[c] = tmp + c * space; | |
1511 | 1362 |
1512 for (int i = 0; i < space; ++i) { | 1363 for (int i = 0; i < space; ++i) { |
1513 tmp[c * space + i] = 0.0f; | 1364 tmp[c * space + i] = 0.0f; |
1514 } | 1365 } |
1515 } | 1366 } |
1516 | 1367 |
1517 sv_frame_t got = mixModels(f, space, bufferPtrs); // also modifies f | 1368 sv_frame_t got = mixModels(f, space, bufferPtrs); // also modifies f |
1518 | 1369 |
1519 for (int c = 0; c < channels; ++c) { | 1370 for (int c = 0; c < channels; ++c) { |
1520 | 1371 |
1521 RingBuffer<float> *wb = getWriteRingBuffer(c); | 1372 RingBuffer<float> *wb = getWriteRingBuffer(c); |
1522 if (wb) { | 1373 if (wb) { |
1523 int actual = wb->write(bufferPtrs[c], int(got)); | 1374 int actual = wb->write(bufferPtrs[c], int(got)); |
1524 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1375 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1525 cout << "Wrote " << actual << " samples for ch " << c << ", now " | 1376 cout << "Wrote " << actual << " samples for ch " << c << ", now " |
1526 << wb->getReadSpace() << " to read" | 1377 << wb->getReadSpace() << " to read" |
1527 << endl; | 1378 << endl; |
1528 #endif | 1379 #endif |
1529 if (actual < got) { | 1380 if (actual < got) { |
1530 cerr << "WARNING: Buffer overrun in channel " << c | 1381 cerr << "WARNING: Buffer overrun in channel " << c |
1531 << ": wrote " << actual << " of " << got | 1382 << ": wrote " << actual << " of " << got |
1532 << " samples" << endl; | 1383 << " samples" << endl; |
1533 } | |
1534 } | 1384 } |
1535 } | 1385 } |
1536 | 1386 } |
1537 m_writeBufferFill = f; | 1387 |
1538 if (readWriteEqual) m_readBufferFill = f; | 1388 m_writeBufferFill = f; |
1539 | 1389 if (readWriteEqual) m_readBufferFill = f; |
1540 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1390 |
1541 cout << "Read buffer fill is now " << m_readBufferFill << endl; | 1391 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1542 #endif | 1392 cout << "Read buffer fill is now " << m_readBufferFill << endl; |
1543 | 1393 #endif |
1544 //!!! how do we know when ended? need to mark up a fully-buffered flag and check this if we find the buffers empty in getSourceSamples | 1394 |
1545 } | 1395 //!!! how do we know when ended? need to mark up a fully-buffered flag and check this if we find the buffers empty in getSourceSamples |
1546 | 1396 |
1547 return true; | 1397 return true; |
1548 } | 1398 } |
1549 | 1399 |
1550 sv_frame_t | 1400 sv_frame_t |