Mercurial > hg > sonic-visualiser
comparison audioio/AudioCallbackPlaySource.cpp @ 106:f8e362511b2f
* Probable fix to occasional channel misalignment during playback
author | Chris Cannam |
---|---|
date | Mon, 26 Feb 2007 16:32:37 +0000 |
parents | 0581d552481d |
children | b4110b17bca8 |
comparison
equal
deleted
inserted
replaced
105:0581d552481d | 106:f8e362511b2f |
---|---|
124 if (dtvm) modelChannels = dtvm->getChannelCount(); | 124 if (dtvm) modelChannels = dtvm->getChannelCount(); |
125 if (modelChannels > m_sourceChannelCount) { | 125 if (modelChannels > m_sourceChannelCount) { |
126 m_sourceChannelCount = modelChannels; | 126 m_sourceChannelCount = modelChannels; |
127 } | 127 } |
128 | 128 |
129 // std::cerr << "Adding model with " << modelChannels << " channels " << std::endl; | 129 // std::cout << "Adding model with " << modelChannels << " channels " << std::endl; |
130 | 130 |
131 if (m_sourceSampleRate == 0) { | 131 if (m_sourceSampleRate == 0) { |
132 | 132 |
133 m_sourceSampleRate = model->getSampleRate(); | 133 m_sourceSampleRate = model->getSampleRate(); |
134 srChanged = true; | 134 srChanged = true; |
193 m_fillThread = new AudioCallbackPlaySourceFillThread(*this); | 193 m_fillThread = new AudioCallbackPlaySourceFillThread(*this); |
194 m_fillThread->start(); | 194 m_fillThread->start(); |
195 } | 195 } |
196 | 196 |
197 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 197 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
198 std::cerr << "AudioCallbackPlaySource::addModel: emitting modelReplaced" << std::endl; | 198 std::cout << "AudioCallbackPlaySource::addModel: emitting modelReplaced" << std::endl; |
199 #endif | 199 #endif |
200 | 200 |
201 if (buffersChanged || srChanged) { | 201 if (buffersChanged || srChanged) { |
202 emit modelReplaced(); | 202 emit modelReplaced(); |
203 } | 203 } |
223 } | 223 } |
224 | 224 |
225 size_t lastEnd = 0; | 225 size_t lastEnd = 0; |
226 for (std::set<Model *>::const_iterator i = m_models.begin(); | 226 for (std::set<Model *>::const_iterator i = m_models.begin(); |
227 i != m_models.end(); ++i) { | 227 i != m_models.end(); ++i) { |
228 // std::cerr << "AudioCallbackPlaySource::removeModel(" << model << "): checking end frame on model " << *i << std::endl; | 228 // std::cout << "AudioCallbackPlaySource::removeModel(" << model << "): checking end frame on model " << *i << std::endl; |
229 if ((*i)->getEndFrame() > lastEnd) lastEnd = (*i)->getEndFrame(); | 229 if ((*i)->getEndFrame() > lastEnd) lastEnd = (*i)->getEndFrame(); |
230 // std::cerr << "(done, lastEnd now " << lastEnd << ")" << std::endl; | 230 // std::cout << "(done, lastEnd now " << lastEnd << ")" << std::endl; |
231 } | 231 } |
232 m_lastModelEndFrame = lastEnd; | 232 m_lastModelEndFrame = lastEnd; |
233 | 233 |
234 m_mutex.unlock(); | 234 m_mutex.unlock(); |
235 | 235 |
291 | 291 |
292 for (size_t i = 0; i < count; ++i) { | 292 for (size_t i = 0; i < count; ++i) { |
293 m_writeBuffers->push_back(new RingBuffer<float>(m_ringBufferSize)); | 293 m_writeBuffers->push_back(new RingBuffer<float>(m_ringBufferSize)); |
294 } | 294 } |
295 | 295 |
296 // std::cerr << "AudioCallbackPlaySource::clearRingBuffers: Created " | 296 // std::cout << "AudioCallbackPlaySource::clearRingBuffers: Created " |
297 // << count << " write buffers" << std::endl; | 297 // << count << " write buffers" << std::endl; |
298 | 298 |
299 if (!haveLock) { | 299 if (!haveLock) { |
300 m_mutex.unlock(); | 300 m_mutex.unlock(); |
301 } | 301 } |
411 } | 411 } |
412 | 412 |
413 void | 413 void |
414 AudioCallbackPlaySource::setTargetBlockSize(size_t size) | 414 AudioCallbackPlaySource::setTargetBlockSize(size_t size) |
415 { | 415 { |
416 // std::cerr << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl; | 416 // std::cout << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl; |
417 assert(size < m_ringBufferSize); | 417 assert(size < m_ringBufferSize); |
418 m_blockSize = size; | 418 m_blockSize = size; |
419 } | 419 } |
420 | 420 |
421 size_t | 421 size_t |
422 AudioCallbackPlaySource::getTargetBlockSize() const | 422 AudioCallbackPlaySource::getTargetBlockSize() const |
423 { | 423 { |
424 // std::cerr << "AudioCallbackPlaySource::getTargetBlockSize() -> " << m_blockSize << std::endl; | 424 // std::cout << "AudioCallbackPlaySource::getTargetBlockSize() -> " << m_blockSize << std::endl; |
425 return m_blockSize; | 425 return m_blockSize; |
426 } | 426 } |
427 | 427 |
428 void | 428 void |
429 AudioCallbackPlaySource::setTargetPlayLatency(size_t latency) | 429 AudioCallbackPlaySource::setTargetPlayLatency(size_t latency) |
507 if (i->contains(bufferedFrame)) break; | 507 if (i->contains(bufferedFrame)) break; |
508 } | 508 } |
509 | 509 |
510 size_t f = bufferedFrame; | 510 size_t f = bufferedFrame; |
511 | 511 |
512 // std::cerr << "getCurrentPlayingFrame: f=" << f << ", latency=" << latency << ", rangeEnd=" << rangeEnd << std::endl; | 512 // std::cout << "getCurrentPlayingFrame: f=" << f << ", latency=" << latency << ", rangeEnd=" << rangeEnd << std::endl; |
513 | 513 |
514 if (i == selections.end()) { | 514 if (i == selections.end()) { |
515 --i; | 515 --i; |
516 if (i->getEndFrame() + latency < f) { | 516 if (i->getEndFrame() + latency < f) { |
517 // std::cerr << "framePlaying = " << framePlaying << ", rangeEnd = " << rangeEnd << std::endl; | 517 // std::cout << "framePlaying = " << framePlaying << ", rangeEnd = " << rangeEnd << std::endl; |
518 | 518 |
519 if (!looping && (framePlaying > rangeEnd)) { | 519 if (!looping && (framePlaying > rangeEnd)) { |
520 // std::cerr << "STOPPING" << std::endl; | 520 // std::cout << "STOPPING" << std::endl; |
521 stop(); | 521 stop(); |
522 return rangeEnd; | 522 return rangeEnd; |
523 } else { | 523 } else { |
524 return framePlaying; | 524 return framePlaying; |
525 } | 525 } |
526 } else { | 526 } else { |
527 // std::cerr << "latency <- " << latency << "-(" << f << "-" << i->getEndFrame() << ")" << std::endl; | 527 // std::cout << "latency <- " << latency << "-(" << f << "-" << i->getEndFrame() << ")" << std::endl; |
528 latency -= (f - i->getEndFrame()); | 528 latency -= (f - i->getEndFrame()); |
529 f = i->getEndFrame(); | 529 f = i->getEndFrame(); |
530 } | 530 } |
531 } | 531 } |
532 | 532 |
533 // std::cerr << "i=(" << i->getStartFrame() << "," << i->getEndFrame() << ") f=" << f << ", latency=" << latency << std::endl; | 533 // std::cout << "i=(" << i->getStartFrame() << "," << i->getEndFrame() << ") f=" << f << ", latency=" << latency << std::endl; |
534 | 534 |
535 while (latency > 0) { | 535 while (latency > 0) { |
536 size_t offset = f - i->getStartFrame(); | 536 size_t offset = f - i->getStartFrame(); |
537 if (offset >= latency) { | 537 if (offset >= latency) { |
538 if (f > latency) { | 538 if (f > latency) { |
743 } | 743 } |
744 } | 744 } |
745 return 0; | 745 return 0; |
746 } | 746 } |
747 | 747 |
748 // Ensure that all buffers have at least the amount of data we | |
749 // need -- else reduce the size of our requests correspondingly | |
750 | |
751 for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { | |
752 | |
753 RingBuffer<float> *rb = getReadRingBuffer(ch); | |
754 | |
755 if (!rb) { | |
756 std::cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: " | |
757 << "No ring buffer available for channel " << ch | |
758 << ", returning no data here" << std::endl; | |
759 count = 0; | |
760 break; | |
761 } | |
762 | |
763 size_t rs = rb->getReadSpace(); | |
764 if (rs < count) { | |
765 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
766 std::cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: " | |
767 << "Ring buffer for channel " << ch << " has only " | |
768 << rs << " (of " << count << ") samples available, " | |
769 << "reducing request size" << std::endl; | |
770 #endif | |
771 count = rs; | |
772 } | |
773 } | |
774 | |
775 if (count == 0) return 0; | |
776 | |
748 PhaseVocoderTimeStretcher *ts = m_timeStretcher; | 777 PhaseVocoderTimeStretcher *ts = m_timeStretcher; |
749 | 778 |
750 if (!ts || ts->getRatio() == 1) { | 779 if (!ts || ts->getRatio() == 1) { |
751 | 780 |
752 size_t got = 0; | 781 size_t got = 0; |
763 if (ch > 0) request = got; | 792 if (ch > 0) request = got; |
764 | 793 |
765 got = rb->read(buffer[ch], request); | 794 got = rb->read(buffer[ch], request); |
766 | 795 |
767 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING | 796 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING |
768 std::cout << "AudioCallbackPlaySource::getSamples: got " << got << " samples on channel " << ch << ", signalling for more (possibly)" << std::endl; | 797 std::cout << "AudioCallbackPlaySource::getSamples: got " << got << " (of " << count << ") samples on channel " << ch << ", signalling for more (possibly)" << std::endl; |
769 #endif | 798 #endif |
770 } | 799 } |
771 | 800 |
772 for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { | 801 for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { |
773 for (size_t i = got; i < count; ++i) { | 802 for (size_t i = got; i < count; ++i) { |
1040 | 1069 |
1041 int err = 0; | 1070 int err = 0; |
1042 | 1071 |
1043 if (m_timeStretcher && m_timeStretcher->getRatio() < 0.4) { | 1072 if (m_timeStretcher && m_timeStretcher->getRatio() < 0.4) { |
1044 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1073 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1045 std::cerr << "Using crappy converter" << std::endl; | 1074 std::cout << "Using crappy converter" << std::endl; |
1046 #endif | 1075 #endif |
1047 src_process(m_crapConverter, &data); | 1076 src_process(m_crapConverter, &data); |
1048 } else { | 1077 } else { |
1049 src_process(m_converter, &data); | 1078 src_process(m_converter, &data); |
1050 } | 1079 } |
1058 //!!! Then what? | 1087 //!!! Then what? |
1059 } else { | 1088 } else { |
1060 got = data.input_frames_used; | 1089 got = data.input_frames_used; |
1061 toCopy = data.output_frames_gen; | 1090 toCopy = data.output_frames_gen; |
1062 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1091 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1063 std::cerr << "Resampled " << got << " frames to " << toCopy << " frames" << std::endl; | 1092 std::cout << "Resampled " << got << " frames to " << toCopy << " frames" << std::endl; |
1064 #endif | 1093 #endif |
1065 } | 1094 } |
1066 | 1095 |
1067 for (size_t c = 0; c < channels; ++c) { | 1096 for (size_t c = 0; c < channels; ++c) { |
1068 for (size_t i = 0; i < toCopy; ++i) { | 1097 for (size_t i = 0; i < toCopy; ++i) { |
1099 size_t got = mixModels(f, space, bufferPtrs); | 1128 size_t got = mixModels(f, space, bufferPtrs); |
1100 | 1129 |
1101 for (size_t c = 0; c < channels; ++c) { | 1130 for (size_t c = 0; c < channels; ++c) { |
1102 | 1131 |
1103 RingBuffer<float> *wb = getWriteRingBuffer(c); | 1132 RingBuffer<float> *wb = getWriteRingBuffer(c); |
1104 if (wb) wb->write(bufferPtrs[c], got); | 1133 if (wb) { |
1105 | 1134 size_t actual = wb->write(bufferPtrs[c], got); |
1106 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1135 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1107 if (wb) | 1136 std::cout << "Wrote " << actual << " samples for ch " << c << ", now " |
1108 std::cerr << "Wrote " << got << " frames for ch " << c << ", now " | |
1109 << wb->getReadSpace() << " to read" | 1137 << wb->getReadSpace() << " to read" |
1110 << std::endl; | 1138 << std::endl; |
1111 #endif | 1139 #endif |
1140 if (actual < got) { | |
1141 std::cerr << "WARNING: Buffer overrun in channel " << c | |
1142 << ": wrote " << actual << " of " << got | |
1143 << " samples" << std::endl; | |
1144 } | |
1145 } | |
1112 } | 1146 } |
1113 | 1147 |
1114 m_writeBufferFill = f; | 1148 m_writeBufferFill = f; |
1115 if (readWriteEqual) m_readBufferFill = f; | 1149 if (readWriteEqual) m_readBufferFill = f; |
1116 | 1150 |
1136 static float **chunkBufferPtrs = 0; | 1170 static float **chunkBufferPtrs = 0; |
1137 static size_t chunkBufferPtrCount = 0; | 1171 static size_t chunkBufferPtrCount = 0; |
1138 size_t channels = getTargetChannelCount(); | 1172 size_t channels = getTargetChannelCount(); |
1139 | 1173 |
1140 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1174 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1141 std::cerr << "Selection playback: start " << frame << ", size " << count <<", channels " << channels << std::endl; | 1175 std::cout << "Selection playback: start " << frame << ", size " << count <<", channels " << channels << std::endl; |
1142 #endif | 1176 #endif |
1143 | 1177 |
1144 if (chunkBufferPtrCount < channels) { | 1178 if (chunkBufferPtrCount < channels) { |
1145 if (chunkBufferPtrs) delete[] chunkBufferPtrs; | 1179 if (chunkBufferPtrs) delete[] chunkBufferPtrs; |
1146 chunkBufferPtrs = new float *[channels]; | 1180 chunkBufferPtrs = new float *[channels]; |
1207 chunkSize = m_lastModelEndFrame - chunkStart; | 1241 chunkSize = m_lastModelEndFrame - chunkStart; |
1208 } | 1242 } |
1209 nextChunkStart = chunkStart + chunkSize; | 1243 nextChunkStart = chunkStart + chunkSize; |
1210 } | 1244 } |
1211 | 1245 |
1212 // std::cerr << "chunkStart " << chunkStart << ", chunkSize " << chunkSize << ", nextChunkStart " << nextChunkStart << ", frame " << frame << ", count " << count << ", processed " << processed << std::endl; | 1246 // std::cout << "chunkStart " << chunkStart << ", chunkSize " << chunkSize << ", nextChunkStart " << nextChunkStart << ", frame " << frame << ", count " << count << ", processed " << processed << std::endl; |
1213 | 1247 |
1214 if (!chunkSize) { | 1248 if (!chunkSize) { |
1215 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1249 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1216 std::cerr << "Ending selection playback at " << nextChunkStart << std::endl; | 1250 std::cout << "Ending selection playback at " << nextChunkStart << std::endl; |
1217 #endif | 1251 #endif |
1218 // We need to maintain full buffers so that the other | 1252 // We need to maintain full buffers so that the other |
1219 // thread can tell where it's got to in the playback -- so | 1253 // thread can tell where it's got to in the playback -- so |
1220 // return the full amount here | 1254 // return the full amount here |
1221 frame = frame + count; | 1255 frame = frame + count; |
1222 return count; | 1256 return count; |
1223 } | 1257 } |
1224 | 1258 |
1225 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1259 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1226 std::cerr << "Selection playback: chunk at " << chunkStart << " -> " << nextChunkStart << " (size " << chunkSize << ")" << std::endl; | 1260 std::cout << "Selection playback: chunk at " << chunkStart << " -> " << nextChunkStart << " (size " << chunkSize << ")" << std::endl; |
1227 #endif | 1261 #endif |
1228 | 1262 |
1229 size_t got = 0; | 1263 size_t got = 0; |
1230 | 1264 |
1231 if (selectionSize < 100) { | 1265 if (selectionSize < 100) { |
1263 processed += chunkSize; | 1297 processed += chunkSize; |
1264 chunkStart = nextChunkStart; | 1298 chunkStart = nextChunkStart; |
1265 } | 1299 } |
1266 | 1300 |
1267 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1301 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1268 std::cerr << "Returning selection playback " << processed << " frames to " << nextChunkStart << std::endl; | 1302 std::cout << "Returning selection playback " << processed << " frames to " << nextChunkStart << std::endl; |
1269 #endif | 1303 #endif |
1270 | 1304 |
1271 frame = nextChunkStart; | 1305 frame = nextChunkStart; |
1272 return processed; | 1306 return processed; |
1273 } | 1307 } |
1296 size_t rf = m_readBufferFill; | 1330 size_t rf = m_readBufferFill; |
1297 RingBuffer<float> *rb = getReadRingBuffer(0); | 1331 RingBuffer<float> *rb = getReadRingBuffer(0); |
1298 if (rb) { | 1332 if (rb) { |
1299 size_t rs = rb->getReadSpace(); | 1333 size_t rs = rb->getReadSpace(); |
1300 //!!! incorrect when in non-contiguous selection, see comments elsewhere | 1334 //!!! incorrect when in non-contiguous selection, see comments elsewhere |
1301 // std::cerr << "rs = " << rs << std::endl; | 1335 // std::cout << "rs = " << rs << std::endl; |
1302 if (rs < rf) rf -= rs; | 1336 if (rs < rf) rf -= rs; |
1303 else rf = 0; | 1337 else rf = 0; |
1304 } | 1338 } |
1305 | 1339 |
1306 //std::cerr << "m_readBufferFill = " << m_readBufferFill << ", rf = " << rf << ", m_writeBufferFill = " << m_writeBufferFill << std::endl; | 1340 //std::cout << "m_readBufferFill = " << m_readBufferFill << ", rf = " << rf << ", m_writeBufferFill = " << m_writeBufferFill << std::endl; |
1307 | 1341 |
1308 size_t wf = m_writeBufferFill; | 1342 size_t wf = m_writeBufferFill; |
1309 size_t skip = 0; | 1343 size_t skip = 0; |
1310 for (size_t c = 0; c < getTargetChannelCount(); ++c) { | 1344 for (size_t c = 0; c < getTargetChannelCount(); ++c) { |
1311 RingBuffer<float> *wb = getWriteRingBuffer(c); | 1345 RingBuffer<float> *wb = getWriteRingBuffer(c); |
1312 if (wb) { | 1346 if (wb) { |
1313 if (c == 0) { | 1347 if (c == 0) { |
1314 | 1348 |
1315 size_t wrs = wb->getReadSpace(); | 1349 size_t wrs = wb->getReadSpace(); |
1316 // std::cerr << "wrs = " << wrs << std::endl; | 1350 // std::cout << "wrs = " << wrs << std::endl; |
1317 | 1351 |
1318 if (wrs < wf) wf -= wrs; | 1352 if (wrs < wf) wf -= wrs; |
1319 else wf = 0; | 1353 else wf = 0; |
1320 // std::cerr << "wf = " << wf << std::endl; | 1354 // std::cout << "wf = " << wf << std::endl; |
1321 | 1355 |
1322 if (wf < rf) skip = rf - wf; | 1356 if (wf < rf) skip = rf - wf; |
1323 if (skip == 0) break; | 1357 if (skip == 0) break; |
1324 } | 1358 } |
1325 | 1359 |
1326 // std::cerr << "skipping " << skip << std::endl; | 1360 // std::cout << "skipping " << skip << std::endl; |
1327 wb->skip(skip); | 1361 wb->skip(skip); |
1328 } | 1362 } |
1329 } | 1363 } |
1330 | 1364 |
1331 m_bufferScavenger.claim(m_readBuffers); | 1365 m_bufferScavenger.claim(m_readBuffers); |
1332 m_readBuffers = m_writeBuffers; | 1366 m_readBuffers = m_writeBuffers; |
1333 m_readBufferFill = m_writeBufferFill; | 1367 m_readBufferFill = m_writeBufferFill; |
1334 // std::cerr << "unified" << std::endl; | 1368 // std::cout << "unified" << std::endl; |
1335 } | 1369 } |
1336 | 1370 |
1337 void | 1371 void |
1338 AudioCallbackPlaySource::AudioCallbackPlaySourceFillThread::run() | 1372 AudioCallbackPlaySource::AudioCallbackPlaySourceFillThread::run() |
1339 { | 1373 { |
1340 AudioCallbackPlaySource &s(m_source); | 1374 AudioCallbackPlaySource &s(m_source); |
1341 | 1375 |
1342 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1376 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1343 std::cerr << "AudioCallbackPlaySourceFillThread starting" << std::endl; | 1377 std::cout << "AudioCallbackPlaySourceFillThread starting" << std::endl; |
1344 #endif | 1378 #endif |
1345 | 1379 |
1346 s.m_mutex.lock(); | 1380 s.m_mutex.lock(); |
1347 | 1381 |
1348 bool previouslyPlaying = s.m_playing; | 1382 bool previouslyPlaying = s.m_playing; |
1370 if (s.getSourceSampleRate() > 0) { | 1404 if (s.getSourceSampleRate() > 0) { |
1371 ms = float(m_ringBufferSize) / float(s.getSourceSampleRate()) * 1000.0; | 1405 ms = float(m_ringBufferSize) / float(s.getSourceSampleRate()) * 1000.0; |
1372 } | 1406 } |
1373 | 1407 |
1374 if (s.m_playing) ms /= 10; | 1408 if (s.m_playing) ms /= 10; |
1375 | 1409 |
1376 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1410 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1411 if (!s.m_playing) std::cout << std::endl; | |
1377 std::cout << "AudioCallbackPlaySourceFillThread: waiting for " << ms << "ms..." << std::endl; | 1412 std::cout << "AudioCallbackPlaySourceFillThread: waiting for " << ms << "ms..." << std::endl; |
1378 #endif | 1413 #endif |
1379 | 1414 |
1380 s.m_condition.wait(&s.m_mutex, size_t(ms)); | 1415 s.m_condition.wait(&s.m_mutex, size_t(ms)); |
1381 } | 1416 } |