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 &currentTime)
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