1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Rosegarden
5 A sequencer and musical notation editor.
6 Copyright 2000-2021 the Rosegarden development team.
7 See the AUTHORS file for more details.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version. See the file
13 COPYING included with this distribution for more information.
14 */
15
16 #include "PlayableAudioFile.h"
17
18 namespace Rosegarden
19 {
20
21 //#define DEBUG_RING_BUFFER_POOL 1
22 //#define DEBUG_PLAYABLE 1
23 //#define DEBUG_PLAYABLE_READ 1
24
25 class RingBufferPool
26 {
27 public:
28 typedef float sample_t;
29
30 RingBufferPool(size_t bufferSize);
31 virtual ~RingBufferPool();
32
33 /**
34 * Set the default size for buffers. Buffers currently allocated
35 * will not be resized until they are returned.
36 */
37 void setBufferSize(size_t n);
38
getBufferSize() const39 size_t getBufferSize() const
40 {
41 return m_bufferSize;
42 }
43
44 /**
45 * Discard or create buffers as necessary so as to have n buffers
46 * in the pool. This will not discard any buffers that are
47 * currently allocated, so if more than n are allocated, more than
48 * n will remain.
49 */
50 void setPoolSize(size_t n);
51
getPoolSize() const52 size_t getPoolSize() const
53 {
54 return m_buffers.size();
55 }
56
57 /**
58 * Return true if n buffers available, false otherwise.
59 */
60 bool getBuffers(size_t n, RingBuffer<sample_t> **buffers);
61
62 /**
63 * Return a buffer to the pool.
64 */
65 void returnBuffer(RingBuffer<sample_t> *buffer);
66
67 protected:
68 // Want to avoid memory allocation if possible when marking a buffer
69 // unallocated or allocated, so we use a single container for all
70
71 typedef std::pair<RingBuffer<sample_t> *, bool> AllocPair;
72 typedef std::vector<AllocPair> AllocList;
73 AllocList m_buffers;
74
75 size_t m_bufferSize;
76 size_t m_available;
77
78 pthread_mutex_t m_lock;
79 };
80
81
RingBufferPool(size_t bufferSize)82 RingBufferPool::RingBufferPool(size_t bufferSize) :
83 m_bufferSize(bufferSize),
84 m_available(0)
85 {
86 pthread_mutex_t initialisingMutex = PTHREAD_MUTEX_INITIALIZER;
87 memcpy(&m_lock, &initialisingMutex, sizeof(pthread_mutex_t));
88 }
89
~RingBufferPool()90 RingBufferPool::~RingBufferPool()
91 {
92 size_t allocatedCount = 0;
93 for (AllocList::iterator i = m_buffers.begin(); i != m_buffers.end(); ++i) {
94 if (i->second)
95 ++allocatedCount;
96 }
97
98 if (allocatedCount > 0) {
99 std::cerr << "WARNING: RingBufferPool::~RingBufferPool: deleting pool with " << allocatedCount << " allocated buffers" << std::endl;
100 }
101
102 for (AllocList::iterator i = m_buffers.begin(); i != m_buffers.end(); ++i) {
103 delete i->first;
104 }
105
106 m_buffers.clear();
107
108 pthread_mutex_destroy(&m_lock);
109 }
110
111 void
setBufferSize(size_t n)112 RingBufferPool::setBufferSize(size_t n)
113 {
114 if (m_bufferSize == n)
115 return ;
116
117 pthread_mutex_lock(&m_lock);
118
119 #ifdef DEBUG_RING_BUFFER_POOL
120
121 std::cerr << "RingBufferPool::setBufferSize: from " << m_bufferSize
122 << " to " << n << std::endl;
123 int c = 0;
124 #endif
125
126 for (AllocList::iterator i = m_buffers.begin(); i != m_buffers.end(); ++i) {
127 if (!i->second) {
128 delete i->first;
129 i->first = new RingBuffer<sample_t>(n);
130 #ifdef DEBUG_RING_BUFFER_POOL
131
132 std::cerr << "Resized buffer " << c++ << std::endl;
133 #endif
134
135 } else {
136 #ifdef DEBUG_RING_BUFFER_POOL
137 std::cerr << "Buffer " << c++ << " is already in use, resizing in place" << std::endl;
138 #endif
139
140 i->first->resize(n);
141 }
142 }
143
144 m_bufferSize = n;
145 pthread_mutex_unlock(&m_lock);
146 }
147
148 void
setPoolSize(size_t n)149 RingBufferPool::setPoolSize(size_t n)
150 {
151 pthread_mutex_lock(&m_lock);
152
153 #ifdef DEBUG_RING_BUFFER_POOL
154
155 std::cerr << "RingBufferPool::setPoolSize: from " << m_buffers.size()
156 << " to " << n << std::endl;
157 #endif
158
159 size_t allocatedCount = 0, count = 0;
160
161 for (AllocList::iterator i = m_buffers.begin(); i != m_buffers.end(); ++i) {
162 if (i->second)
163 ++allocatedCount;
164 ++count;
165 }
166
167 if (count > n) {
168 for (AllocList::iterator i = m_buffers.begin(); i != m_buffers.end(); ) {
169 if (!i->second) {
170 delete i->first;
171 m_buffers.erase(i);
172 if (--count == n)
173 break;
174 } else {
175 ++i;
176 }
177 }
178 }
179
180 while (count < n) {
181 m_buffers.push_back(AllocPair(new RingBuffer<sample_t>(m_bufferSize),
182 false));
183 ++count;
184 }
185
186 m_available = std::max(allocatedCount, n) - allocatedCount;
187
188 #ifdef DEBUG_RING_BUFFER_POOL
189
190 std::cerr << "RingBufferPool::setPoolSize: have " << m_buffers.size()
191 << " buffers (" << allocatedCount << " allocated, " << m_available << " available)" << std::endl;
192 #endif
193
194 pthread_mutex_unlock(&m_lock);
195 }
196
197 bool
getBuffers(size_t n,RingBuffer<sample_t> ** buffers)198 RingBufferPool::getBuffers(size_t n, RingBuffer<sample_t> **buffers)
199 {
200 pthread_mutex_lock(&m_lock);
201
202 size_t count = 0;
203
204 for (AllocList::iterator i = m_buffers.begin(); i != m_buffers.end(); ++i) {
205 if (!i->second && ++count == n)
206 break;
207 }
208
209 if (count < n) {
210 #ifdef DEBUG_RING_BUFFER_POOL
211 std::cerr << "RingBufferPool::getBuffers(" << n << "): not available (in pool of " << m_buffers.size() << "), resizing" << std::endl;
212 #endif
213
214 AllocList newBuffers;
215
216 while (count < n) {
217 for (size_t i = 0; i < m_buffers.size(); ++i) {
218 newBuffers.push_back(m_buffers[i]);
219 }
220 for (size_t i = 0; i < m_buffers.size(); ++i) {
221 newBuffers.push_back(AllocPair(new RingBuffer<sample_t>(m_bufferSize),
222 false));
223 }
224 count += m_buffers.size();
225 m_available += m_buffers.size();
226 }
227
228 m_buffers = newBuffers;
229 }
230
231 count = 0;
232
233 #ifdef DEBUG_RING_BUFFER_POOL
234
235 std::cerr << "RingBufferPool::getBuffers(" << n << "): available" << std::endl;
236 #endif
237
238 for (AllocList::iterator i = m_buffers.begin(); i != m_buffers.end(); ++i) {
239 if (!i->second) {
240 i->second = true;
241 i->first->reset();
242 i->first->mlock();
243 buffers[count] = i->first;
244 --m_available;
245 if (++count == n)
246 break;
247 }
248 }
249
250 #ifdef DEBUG_RING_BUFFER_POOL
251 std::cerr << "RingBufferPool::getBuffers: " << m_available << " remain in pool of " << m_buffers.size() << std::endl;
252 #endif
253
254 pthread_mutex_unlock(&m_lock);
255 return true;
256 }
257
258 void
returnBuffer(RingBuffer<sample_t> * buffer)259 RingBufferPool::returnBuffer(RingBuffer<sample_t> *buffer)
260 {
261 pthread_mutex_lock(&m_lock);
262
263 #ifdef DEBUG_RING_BUFFER_POOL
264
265 std::cerr << "RingBufferPool::returnBuffer" << std::endl;
266 #endif
267
268 buffer->munlock();
269
270 for (AllocList::iterator i = m_buffers.begin(); i != m_buffers.end(); ++i) {
271 if (i->first == buffer) {
272 i->second = false;
273 ++m_available;
274 if (buffer->getSize() != m_bufferSize) {
275 delete buffer;
276 i->first = new RingBuffer<sample_t>(m_bufferSize);
277 }
278 }
279 }
280
281 #ifdef DEBUG_RING_BUFFER_POOL
282 std::cerr << "RingBufferPool::returnBuffer: " << m_available << " remain in pool of " << m_buffers.size() << std::endl;
283 #endif
284
285 pthread_mutex_unlock(&m_lock);
286 }
287
288
289 AudioCache PlayableAudioFile::m_smallFileCache;
290
291 std::vector<PlayableAudioFile::sample_t *> PlayableAudioFile::m_workBuffers;
292 size_t PlayableAudioFile::m_workBufferSize = 0;
293
294 char *PlayableAudioFile::m_rawFileBuffer;
295 size_t PlayableAudioFile::m_rawFileBufferSize = 0;
296
297 RingBufferPool *PlayableAudioFile::m_ringBufferPool = nullptr;
298
299 size_t PlayableAudioFile::m_xfadeFrames = 30;
300
PlayableAudioFile(InstrumentId instrumentId,AudioFile * audioFile,const RealTime & startTime,const RealTime & startIndex,const RealTime & duration,size_t bufferSize,size_t smallFileSize,int targetChannels,int targetSampleRate)301 PlayableAudioFile::PlayableAudioFile(InstrumentId instrumentId,
302 AudioFile *audioFile,
303 const RealTime &startTime,
304 const RealTime &startIndex,
305 const RealTime &duration,
306 size_t bufferSize,
307 size_t smallFileSize,
308 int targetChannels,
309 int targetSampleRate) :
310 m_startTime(startTime),
311 m_startIndex(startIndex),
312 m_duration(duration),
313 m_file(nullptr),
314 m_audioFile(audioFile),
315 m_instrumentId(instrumentId),
316 m_targetChannels(targetChannels),
317 m_targetSampleRate(targetSampleRate),
318 m_fileEnded(false),
319 m_firstRead(true),
320 m_runtimeSegmentId( -1),
321 m_isSmallFile(false),
322 m_currentScanPoint(RealTime::zeroTime),
323 m_smallFileScanFrame(0),
324 m_autoFade(false),
325 m_fadeInTime(RealTime::zeroTime),
326 m_fadeOutTime(RealTime::zeroTime)
327 {
328 #ifdef DEBUG_PLAYABLE
329 std::cerr << "PlayableAudioFile::PlayableAudioFile - creating " << this << " for instrument " << instrumentId << " with file " << (m_audioFile ? m_audioFile->getShortFilename() : "(none)") << std::endl;
330 #endif
331
332 if (!m_ringBufferPool) {
333 //!!! Problematic -- how do we deal with different playable audio
334 // files requiring different buffer sizes? That shouldn't be the
335 // usual case, but it's not unthinkable.
336 m_ringBufferPool = new RingBufferPool(bufferSize);
337 } else {
338 m_ringBufferPool->setBufferSize
339 (std::max(bufferSize, m_ringBufferPool->getBufferSize()));
340 }
341
342 initialise(bufferSize, smallFileSize);
343 }
344
345
346 void
setRingBufferPoolSizes(size_t n,size_t nframes)347 PlayableAudioFile::setRingBufferPoolSizes(size_t n, size_t nframes)
348 {
349 if (!m_ringBufferPool) {
350 m_ringBufferPool = new RingBufferPool(nframes);
351 } else {
352 m_ringBufferPool->setBufferSize
353 (std::max(nframes, m_ringBufferPool->getBufferSize()));
354 }
355 m_ringBufferPool->setPoolSize(n);
356 }
357
358
359 void
initialise(size_t bufferSize,size_t smallFileSize)360 PlayableAudioFile::initialise(size_t bufferSize, size_t smallFileSize)
361 {
362 #ifdef DEBUG_PLAYABLE
363 std::cerr << "PlayableAudioFile::initialise() " << this << std::endl;
364 #endif
365
366 checkSmallFileCache(smallFileSize);
367
368 if (!m_isSmallFile) {
369
370 m_file = new std::ifstream(m_audioFile->getFilename().toLocal8Bit(),
371 std::ios::in | std::ios::binary);
372
373 if (!*m_file) {
374 std::cerr << "ERROR: PlayableAudioFile::initialise: Failed to open audio file " << m_audioFile->getFilename() << std::endl;
375 delete m_file;
376 m_file = nullptr;
377 }
378 }
379
380 // Scan to the beginning of the data chunk we need
381 //
382 #ifdef DEBUG_PLAYABLE
383 std::cerr << "PlayableAudioFile::initialise - scanning to " << m_startIndex << std::endl;
384 #endif
385
386 if (m_file) {
387 scanTo(m_startIndex);
388 } else {
389 m_fileEnded = false;
390 m_currentScanPoint = m_startIndex;
391 m_smallFileScanFrame = (size_t)RealTime::realTime2Frame
392 (m_currentScanPoint, m_audioFile->getSampleRate());
393 }
394
395 #ifdef DEBUG_PLAYABLE
396 std::cerr << "PlayableAudioFile::initialise: buffer size is " << bufferSize << " frames, file size is " << m_audioFile->getSize() << std::endl;
397 #else
398 (void)bufferSize;
399 #endif
400
401 if (m_targetChannels <= 0)
402 m_targetChannels = m_audioFile->getChannels();
403 if (m_targetSampleRate <= 0)
404 m_targetSampleRate = m_audioFile->getSampleRate();
405
406 m_ringBuffers = new RingBuffer<sample_t> *[m_targetChannels];
407 for (int ch = 0; ch < m_targetChannels; ++ch) {
408 m_ringBuffers[ch] = nullptr;
409 }
410 }
411
~PlayableAudioFile()412 PlayableAudioFile::~PlayableAudioFile()
413 {
414 if (m_file) {
415 m_file->close();
416 delete m_file;
417 }
418
419 returnRingBuffers();
420 delete[] m_ringBuffers;
421 m_ringBuffers = nullptr;
422
423 if (m_isSmallFile) {
424 m_smallFileCache.decrementReference(m_audioFile);
425 }
426
427 #ifdef DEBUG_PLAYABLE
428 // std::cerr << "PlayableAudioFile::~PlayableAudioFile - destroying - " << this << std::endl;
429 #endif
430 }
431
432 void
returnRingBuffers()433 PlayableAudioFile::returnRingBuffers()
434 {
435 for (int i = 0; i < m_targetChannels; ++i) {
436 if (m_ringBuffers[i]) {
437 m_ringBufferPool->returnBuffer(m_ringBuffers[i]);
438 m_ringBuffers[i] = nullptr;
439 }
440 }
441 }
442
443 bool
scanTo(const RealTime & time)444 PlayableAudioFile::scanTo(const RealTime &time)
445 {
446 #ifdef DEBUG_PLAYABLE_READ
447 std::cerr << "PlayableAudioFile::scanTo(" << time << ")" << std::endl;
448 #endif
449
450 m_fileEnded = false; // until we know otherwise -- this flag is an
451 // optimisation, not a reliable record
452
453 bool ok = false;
454
455 if (m_isSmallFile) {
456
457 m_currentScanPoint = time;
458 m_smallFileScanFrame = (size_t)RealTime::realTime2Frame
459 (time, m_audioFile->getSampleRate());
460 #ifdef DEBUG_PLAYABLE_READ
461 std::cerr << "... maps to frame " << m_smallFileScanFrame << std::endl;
462 #endif
463 ok = true;
464
465 } else {
466
467 ok = m_audioFile->scanTo(m_file, time);
468 if (ok) {
469 m_currentScanPoint = time;
470 }
471 }
472
473 #ifdef DEBUG_PLAYABLE_READ
474 std::cerr << "PlayableAudioFile::scanTo(" << time << "): set m_currentScanPoint to " << m_currentScanPoint << std::endl;
475 #endif
476
477 m_firstRead = true; // so we know to xfade in
478
479 return ok;
480 }
481
482
483 size_t
getSampleFramesAvailable()484 PlayableAudioFile::getSampleFramesAvailable()
485 {
486 size_t actual = 0;
487
488 if (m_isSmallFile) {
489 size_t cchannels;
490 size_t cframes;
491 (void)m_smallFileCache.getData(m_audioFile, cchannels, cframes);
492 if (cframes > m_smallFileScanFrame)
493 return cframes - m_smallFileScanFrame;
494 else
495 return 0;
496 }
497
498 for (int ch = 0; ch < m_targetChannels; ++ch) {
499 if (!m_ringBuffers[ch])
500 return 0;
501 size_t thisChannel = m_ringBuffers[ch]->getReadSpace();
502 if (ch == 0 || thisChannel < actual)
503 actual = thisChannel;
504 }
505
506 #ifdef DEBUG_PLAYABLE
507 std::cerr << "PlayableAudioFile(" << (m_audioFile ? m_audioFile->getShortFilename() : "(none)") << " " << this << ")::getSampleFramesAvailable: have " << actual << std::endl;
508 #endif
509
510 return actual;
511 }
512
513 size_t
addSamples(std::vector<sample_t * > & destination,size_t channels,size_t nframes,size_t offset)514 PlayableAudioFile::addSamples(std::vector<sample_t *> &destination,
515 size_t channels, size_t nframes, size_t offset)
516 {
517 #ifdef DEBUG_PLAYABLE_READ
518 std::cerr << "PlayableAudioFile::addSamples(" << nframes << "): channels " << channels << ", my target channels " << m_targetChannels << std::endl;
519 #endif
520
521 if (!m_isSmallFile) {
522
523 size_t qty = 0;
524 bool done = m_fileEnded;
525
526 for (int ch = 0; ch < int(channels) && ch < m_targetChannels; ++ch) {
527 if (!m_ringBuffers[ch])
528 return 0; //!!! fatal
529 size_t here = m_ringBuffers[ch]->readAdding(destination[ch] + offset, nframes);
530 if (ch == 0 || here < qty)
531 qty = here;
532 if (done && (m_ringBuffers[ch]->getReadSpace() > 0))
533 done = false;
534 }
535
536 for (int ch = channels; ch < m_targetChannels; ++ch) {
537 m_ringBuffers[ch]->skip(nframes);
538 }
539
540 if (done) {
541 #ifdef DEBUG_PLAYABLE_READ
542 std::cerr << "PlayableAudioFile::addSamples(" << nframes << "): reached end, returning buffers" << std::endl;
543 #endif
544
545 returnRingBuffers();
546 }
547
548 #ifdef DEBUG_PLAYABLE_READ
549 std::cerr << "PlayableAudioFile::addSamples(" << nframes << "): returning " << qty << " frames (at least " << (m_ringBuffers[0] ? m_ringBuffers[0]->getReadSpace() : 0) << " remaining)" << std::endl;
550 #endif
551
552 return qty;
553
554 } else {
555
556 size_t cchannels;
557 size_t cframes;
558 float **cached = m_smallFileCache.getData(m_audioFile, cchannels, cframes);
559
560 if (!cached) {
561 std::cerr << "WARNING: PlayableAudioFile::addSamples: Failed to find small file in cache" << std::endl;
562 m_isSmallFile = false;
563 } else {
564
565 size_t scanFrame = m_smallFileScanFrame;
566
567 if (scanFrame >= cframes) {
568 m_fileEnded = true;
569 return 0;
570 }
571
572 size_t endFrame = scanFrame + nframes;
573 size_t n = nframes;
574
575 if (endFrame >= cframes) {
576 m_fileEnded = true;
577 n = cframes - scanFrame;
578 }
579
580 #ifdef DEBUG_PLAYABLE_READ
581 std::cerr << "PlayableAudioFile::addSamples: it's a small file: want frames " << scanFrame << " to " << endFrame << " of " << cframes << std::endl;
582 #endif
583
584 // size_t xfadeIn = (m_firstRead ? m_xfadeFrames : 0);
585 // size_t xfadeOut = (m_fileEnded ? m_xfadeFrames : 0);
586
587 // all this could be neater!
588
589 if (channels == 1 && cchannels == 2) { // mix
590 for (size_t i = 0; i < n; ++i) {
591 sample_t v =
592 cached[0][scanFrame + i] +
593 cached[1][scanFrame + i];
594 //if ((i + 1) < xfadeIn)
595 // v = (v * (i + 1)) / xfadeIn;
596 //if ((n - i) < xfadeOut)
597 // v = (v * (n - i)) / xfadeOut;
598 destination[0][i + offset] += v;
599 }
600 } else {
601 for (size_t ch = 0; ch < channels; ++ch) {
602 int sch = ch;
603 if (ch >= cchannels) {
604 if (channels == 2 && cchannels == 1)
605 sch = 0;
606 else
607 break;
608 } else {
609 for (size_t i = 0; i < n; ++i) {
610 sample_t v = cached[sch][scanFrame + i];
611 //if ((i + 1) < xfadeIn)
612 // v = (v * (i + 1)) / xfadeIn;
613 //if ((n - i) < xfadeOut)
614 // v = (v * (n - i)) / xfadeOut;
615 destination[ch][i + offset] += v;
616 }
617 }
618 }
619 }
620
621 m_smallFileScanFrame += nframes;
622 m_currentScanPoint = m_currentScanPoint +
623 RealTime::frame2RealTime(nframes, m_targetSampleRate);
624 return nframes;
625 }
626 }
627
628 return 0;
629 }
630
631 void
checkSmallFileCache(size_t smallFileSize)632 PlayableAudioFile::checkSmallFileCache(size_t smallFileSize)
633 {
634 if (m_smallFileCache.has(m_audioFile)) {
635
636 #ifdef DEBUG_PLAYABLE
637 std::cerr << "PlayableAudioFile::checkSmallFileCache: Found file in small file cache" << std::endl;
638 #endif
639
640 m_smallFileCache.incrementReference(m_audioFile);
641 m_isSmallFile = true;
642
643 } else if (m_audioFile->getSize() <= smallFileSize) {
644
645 std::ifstream file(m_audioFile->getFilename().toLocal8Bit(),
646 std::ios::in | std::ios::binary);
647
648 if (!file) {
649 std::cerr << "ERROR: PlayableAudioFile::checkSmallFileCache: Failed to open audio file " << m_audioFile->getFilename() << std::endl;
650 return ;
651 }
652
653 #ifdef DEBUG_PLAYABLE
654 std::cerr << "PlayableAudioFile::checkSmallFileCache: Adding file to small file cache" << std::endl;
655 #endif
656
657 // We always encache files with their original number of
658 // channels (because they might be called for in any channel
659 // configuration subsequently) but with the current sample
660 // rate, not their original one.
661
662 m_audioFile->scanTo(&file, RealTime::zeroTime);
663
664 size_t reqd = m_audioFile->getSize() / m_audioFile->getBytesPerFrame();
665 unsigned char *buffer = new unsigned char[m_audioFile->getSize()];
666 size_t obtained = m_audioFile->getSampleFrames(&file, (char *)buffer, reqd);
667
668 // std::cerr <<"obtained=" << obtained << std::endl;
669
670 size_t nch = getSourceChannels();
671 size_t nframes = obtained;
672 if (int(getSourceSampleRate()) != m_targetSampleRate) {
673 #ifdef DEBUG_PLAYABLE
674 std::cerr << "PlayableAudioFile::checkSmallFileCache: Resampling badly from " << getSourceSampleRate() << " to " << m_targetSampleRate << std::endl;
675 #endif
676 nframes = size_t(float(nframes) * float(m_targetSampleRate) /
677 float(getSourceSampleRate()));
678 }
679
680 std::vector<sample_t *> samples;
681 for (size_t ch = 0; ch < nch; ++ch) {
682 samples.push_back(new sample_t[nframes]);
683 }
684
685 if (!m_audioFile->decode(buffer,
686 obtained * m_audioFile->getBytesPerFrame(),
687 m_targetSampleRate,
688 nch,
689 nframes,
690 samples)) {
691 std::cerr << "PlayableAudioFile::checkSmallFileCache: failed to decode file" << std::endl;
692 } else {
693 sample_t **toCache = new sample_t * [nch];
694 for (size_t ch = 0; ch < nch; ++ch) {
695 toCache[ch] = samples[ch];
696 }
697 m_smallFileCache.addData(m_audioFile, nch, nframes, toCache);
698 m_isSmallFile = true;
699 }
700
701 delete[] buffer;
702
703 file.close();
704 }
705
706 if (m_isSmallFile) {
707 if (m_file) {
708 m_file->close();
709 delete m_file;
710 m_file = nullptr;
711 }
712 }
713 }
714
715
716 void
fillBuffers()717 PlayableAudioFile::fillBuffers()
718 {
719 #ifdef DEBUG_PLAYABLE
720 if (m_audioFile) {
721 std::cerr << "PlayableAudioFile(" << m_audioFile->getShortFilename() << ")::fillBuffers() [async] -- scanning to " << m_startIndex << std::endl;
722 } else {
723 std::cerr << "PlayableAudioFile::fillBuffers() [async] -- scanning to " << m_startIndex << std::endl;
724 }
725 #endif
726
727 if (!m_isSmallFile && (!m_file || !*m_file)) {
728 m_file = new std::ifstream(m_audioFile->getFilename().toLocal8Bit(),
729 std::ios::in | std::ios::binary);
730 if (!*m_file) {
731 std::cerr << "ERROR: PlayableAudioFile::fillBuffers: Failed to open audio file " << m_audioFile->getFilename() << std::endl;
732 delete m_file;
733 m_file = nullptr;
734 return ;
735 }
736 }
737
738 scanTo(m_startIndex);
739 updateBuffers();
740 }
741
742 void
clearBuffers()743 PlayableAudioFile::clearBuffers()
744 {
745 returnRingBuffers();
746 }
747
748 bool
fillBuffers(const RealTime & currentTime)749 PlayableAudioFile::fillBuffers(const RealTime ¤tTime)
750 {
751 #ifdef DEBUG_PLAYABLE
752 if (!m_isSmallFile) {
753 if (m_audioFile) {
754 std::cerr << "PlayableAudioFile(" << m_audioFile->getShortFilename() << " " << this << ")::fillBuffers(" << currentTime << "):\n my start time " << m_startTime << ", start index " << m_startIndex << ", duration " << m_duration << std::endl;
755 } else {
756 std::cerr << "PlayableAudioFile::fillBuffers(" << currentTime << "): my start time " << m_startTime << ", start index " << m_startIndex << ", duration " << m_duration << std::endl;
757 }
758 }
759 #endif
760
761 if (currentTime > m_startTime + m_duration) {
762
763 #ifdef DEBUG_PLAYABLE
764 std::cerr << "PlayableAudioFile::fillBuffers: seeking past end, returning buffers" << std::endl;
765 #endif
766
767 returnRingBuffers();
768 return true;
769 }
770
771 if (!m_isSmallFile && (!m_file || !*m_file)) {
772 m_file = new std::ifstream(m_audioFile->getFilename().toLocal8Bit(),
773 std::ios::in | std::ios::binary);
774 if (!*m_file) {
775 std::cerr << "ERROR: PlayableAudioFile::fillBuffers: Failed to open audio file " << m_audioFile->getFilename() << std::endl;
776 delete m_file;
777 m_file = nullptr;
778 return false;
779 }
780 scanTo(m_startIndex);
781 }
782
783 RealTime scanTime = m_startIndex;
784
785 if (currentTime > m_startTime) {
786 scanTime = m_startIndex + currentTime - m_startTime;
787 }
788
789 // size_t scanFrames = (size_t)RealTime::realTime2Frame
790 // (scanTime,
791 // m_isSmallFile ? m_targetSampleRate : m_audioFile->getSampleRate());
792
793 if (scanTime != m_currentScanPoint) {
794 scanTo(scanTime);
795 }
796
797 if (!m_isSmallFile) {
798 for (int i = 0; i < m_targetChannels; ++i) {
799 if (m_ringBuffers[i])
800 m_ringBuffers[i]->reset();
801 }
802 updateBuffers();
803 }
804
805 return true;
806 }
807
808 bool
updateBuffers()809 PlayableAudioFile::updateBuffers()
810 {
811 if (m_isSmallFile)
812 return false;
813 if (!m_file)
814 return false;
815
816 if (m_fileEnded) {
817 #ifdef DEBUG_PLAYABLE_READ
818 std::cerr << "PlayableAudioFile::updateBuffers: at end of file already" << std::endl;
819 #endif
820
821 return false;
822 }
823
824 if (!m_ringBuffers[0]) {
825
826 if (m_targetChannels < 0) {
827 std::cerr << "WARNING: PlayableAudioFile::updateBuffers: m_targetChannels < 0, can't allocate ring buffers" << std::endl;
828 return false;
829 }
830
831 // need a buffer: can we get one?
832 if (!m_ringBufferPool->getBuffers(m_targetChannels, m_ringBuffers)) {
833 std::cerr << "WARNING: PlayableAudioFile::updateBuffers: no ring buffers available" << std::endl;
834 return false;
835 }
836 }
837
838 size_t nframes = 0;
839
840 for (int ch = 0; ch < m_targetChannels; ++ch) {
841 if (!m_ringBuffers[ch])
842 continue;
843 size_t writeSpace = m_ringBuffers[ch]->getWriteSpace();
844 if (ch == 0 || writeSpace < nframes)
845 nframes = writeSpace;
846 }
847
848 if (nframes == 0) {
849 #ifdef DEBUG_PLAYABLE_READ
850 std::cerr << "PlayableAudioFile::updateBuffers: frames == 0, ignoring" << std::endl;
851 #endif
852
853 return false;
854 }
855
856 #ifdef DEBUG_PLAYABLE_READ
857 std::cerr << "PlayableAudioFile::updateBuffers: want " << nframes << " frames" << std::endl;
858 #endif
859
860
861 RealTime block = RealTime::frame2RealTime(nframes, m_targetSampleRate);
862 if (m_currentScanPoint + block >= m_startIndex + m_duration) {
863 block = m_startIndex + m_duration - m_currentScanPoint;
864 if (block <= RealTime::zeroTime)
865 nframes = 0;
866 else
867 nframes = (size_t)RealTime::realTime2Frame(block, m_targetSampleRate);
868 m_fileEnded = true;
869 }
870
871 size_t fileFrames = nframes;
872 if (m_targetSampleRate != int(getSourceSampleRate())) {
873 fileFrames = size_t(float(fileFrames) * float(getSourceSampleRate()) /
874 float(m_targetSampleRate));
875 }
876
877 #ifdef DEBUG_PLAYABLE_READ
878 std::cerr << "Want " << fileFrames << " (" << block << ") from file (" << (m_duration + m_startIndex - m_currentScanPoint - block) << " to go)" << std::endl;
879 #endif
880
881 //!!! need to be doing this in initialise, want to avoid allocations here
882 if ((getBytesPerFrame() * fileFrames) > m_rawFileBufferSize) {
883 delete[] m_rawFileBuffer;
884 m_rawFileBufferSize = getBytesPerFrame() * fileFrames;
885 #ifdef DEBUG_PLAYABLE_READ
886
887 std::cerr << "Expanding raw file buffer to " << m_rawFileBufferSize << " chars" << std::endl;
888 #endif
889
890 m_rawFileBuffer = new char[m_rawFileBufferSize];
891 }
892
893 size_t obtained =
894 m_audioFile->getSampleFrames(m_file, m_rawFileBuffer, fileFrames);
895
896 if (obtained < fileFrames || m_file->eof()) {
897 m_fileEnded = true;
898 }
899
900 #ifdef DEBUG_PLAYABLE
901 std::cerr << "requested " << fileFrames << " frames from file for " << nframes << " frames, got " << obtained << " frames" << std::endl;
902 #endif
903
904 if (nframes > m_workBufferSize) {
905
906 for (size_t i = 0; i < m_workBuffers.size(); ++i) {
907 delete[] m_workBuffers[i];
908 }
909
910 m_workBuffers.clear();
911 m_workBufferSize = nframes;
912 #ifdef DEBUG_PLAYABLE_READ
913
914 std::cerr << "Expanding work buffer to " << m_workBufferSize << " frames" << std::endl;
915 #endif
916
917 for (int i = 0; i < m_targetChannels; ++i) {
918 m_workBuffers.push_back(new sample_t[m_workBufferSize]);
919 }
920
921 } else {
922
923 while (m_targetChannels > (int)m_workBuffers.size()) {
924 m_workBuffers.push_back(new sample_t[m_workBufferSize]);
925 }
926 }
927
928 if (m_audioFile->decode((const unsigned char *)m_rawFileBuffer,
929 obtained * getBytesPerFrame(),
930 m_targetSampleRate,
931 m_targetChannels,
932 nframes,
933 m_workBuffers,
934 false)) {
935
936 /*!!! No -- GUI and notification side of things isn't up to this yet,
937 so comment it out just in case
938
939 if (m_autoFade) {
940
941 if (m_currentScanPoint < m_startIndex + m_fadeInTime) {
942
943 size_t fadeSamples =
944 (size_t)RealTime::realTime2Frame(m_fadeInTime, getTargetSampleRate());
945 size_t originSamples =
946 (size_t)RealTime::realTime2Frame(m_currentScanPoint - m_startIndex, // is x - y strictly non-negative?
947 getTargetSampleRate());
948
949 for (size_t i = 0; i < nframes; ++i) {
950 if (i + originSamples > fadeSamples) {
951 break;
952 }
953 float gain = float(i + originSamples) / float(fadeSamples);
954 for (int ch = 0; ch < m_targetChannels; ++ch) {
955 m_workBuffers[ch][i] *= gain;
956 }
957 }
958 }
959
960 if (m_currentScanPoint + block >
961 m_startIndex + m_duration - m_fadeOutTime) {
962
963 size_t fadeSamples =
964 (size_t)RealTime::realTime2Frame(m_fadeOutTime, getTargetSampleRate());
965 size_t originSamples = // counting from end
966 (size_t)RealTime::realTime2Frame
967 (m_startIndex + m_duration - m_currentScanPoint, // is x - y strictly non-negative?
968 getTargetSampleRate());
969
970 for (size_t i = 0; i < nframes; ++i) {
971 float gain = 1.0;
972 if (originSamples < i) gain = 0.0;
973 else {
974 size_t fromEnd = originSamples - i;
975 if (fromEnd < fadeSamples) {
976 gain = float(fromEnd) / float(fadeSamples);
977 }
978 }
979 for (int ch = 0; ch < m_targetChannels; ++ch) {
980 m_workBuffers[ch][i] *= gain;
981 }
982 }
983 }
984 }
985 */
986
987 m_currentScanPoint = m_currentScanPoint + block;
988
989 for (int ch = 0; ch < m_targetChannels; ++ch) {
990
991 if (m_firstRead || m_fileEnded) {
992 float xfade = std::min(m_xfadeFrames, nframes);
993 if (m_firstRead) {
994 for (size_t i = 0; i < xfade; ++i) {
995 m_workBuffers[ch][i] *= float(i + 1) / xfade;
996 }
997 }
998 if (m_fileEnded) {
999 for (size_t i = 0; i < xfade; ++i) {
1000 m_workBuffers[ch][nframes - i - 1] *=
1001 float(i + 1) / xfade;
1002 }
1003 }
1004 }
1005
1006 if (m_ringBuffers[ch]) {
1007 m_ringBuffers[ch]->write(m_workBuffers[ch], nframes);
1008 }
1009 }
1010 }
1011
1012 m_firstRead = false;
1013
1014 if (obtained < fileFrames) {
1015 if (m_file) {
1016 m_file->close();
1017 delete m_file;
1018 m_file = nullptr;
1019 }
1020 }
1021
1022 return true;
1023 }
1024
1025
1026 // How many channels in the base AudioFile?
1027 //
1028 unsigned int
getSourceChannels()1029 PlayableAudioFile::getSourceChannels()
1030 {
1031 if (m_audioFile) {
1032 return m_audioFile->getChannels();
1033 }
1034 return 0;
1035 }
1036
1037 unsigned int
getTargetChannels()1038 PlayableAudioFile::getTargetChannels()
1039 {
1040 return m_targetChannels;
1041 }
1042
1043 unsigned int
getBytesPerFrame()1044 PlayableAudioFile::getBytesPerFrame()
1045 {
1046 if (m_audioFile) {
1047 return m_audioFile->getBytesPerFrame();
1048 }
1049 return 0;
1050 }
1051
1052 unsigned int
getSourceSampleRate()1053 PlayableAudioFile::getSourceSampleRate()
1054 {
1055 if (m_audioFile) {
1056 return m_audioFile->getSampleRate();
1057 }
1058 return 0;
1059 }
1060
1061 unsigned int
getTargetSampleRate()1062 PlayableAudioFile::getTargetSampleRate()
1063 {
1064 return m_targetSampleRate;
1065 }
1066
1067
1068 // How many bits per sample in the base AudioFile?
1069 //
1070 unsigned int
getBitsPerSample()1071 PlayableAudioFile::getBitsPerSample()
1072 {
1073 if (m_audioFile) {
1074 return m_audioFile->getBitsPerSample();
1075 }
1076 return 0;
1077 }
1078
1079
1080 }
1081
1082