2929#include " ../../Audio/AudioComponent.h"
3030#include " ../PluginManager/PluginManager.h"
3131#include " BinaryFileSource/BinaryFileSource.h"
32+ #include < cmath>
3233#include < stdio.h>
3334
3435#include " ../Settings/DataStream.h"
@@ -417,6 +418,43 @@ float FileReader::getDefaultSampleRate() const
417418 return 44100.0 ;
418419}
419420
421+ void FileReader::resetBufferSchedule ()
422+ {
423+ if (m_sysSampleRate > 0 .0f && currentSampleRate > 0 .0f && m_bufferSize > 0 )
424+ m_samplesPerCallbackExact = double (m_bufferSize) * (double (getDefaultSampleRate ()) / double (m_sysSampleRate));
425+ else
426+ m_samplesPerCallbackExact = 0.0 ;
427+
428+ m_samplesPerCallbackRemainder = 0.0 ;
429+ bufferAInfo = BufferWindowInfo {};
430+ bufferBInfo = BufferWindowInfo {};
431+ }
432+
433+ void FileReader::updateBufferWindowInfo (BufferWindowInfo& info)
434+ {
435+ info = BufferWindowInfo {};
436+
437+ if (m_samplesPerCallbackExact <= 0.0 || stopSample <= startSample)
438+ return ;
439+
440+ constexpr double roundingEpsilon = 1.0e-9 ;
441+ double remainder = m_samplesPerCallbackRemainder;
442+
443+ for (int windowIndex = 0 ; windowIndex < BUFFER_WINDOW_CACHE_SIZE ; ++windowIndex)
444+ {
445+ info.sampleOffsets [(size_t ) windowIndex] = info.totalSamples ;
446+
447+ const double exactSamples = m_samplesPerCallbackExact + remainder;
448+ const int scheduledSamples = jmax (0 , int (std::floor (exactSamples + roundingEpsilon)));
449+
450+ info.sampleCounts [(size_t ) windowIndex] = scheduledSamples;
451+ info.totalSamples += scheduledSamples;
452+ remainder = exactSamples - double (scheduledSamples);
453+ }
454+
455+ m_samplesPerCallbackRemainder = remainder;
456+ }
457+
420458bool FileReader::startAcquisition ()
421459{
422460 if (! isEnabled)
@@ -426,8 +464,9 @@ bool FileReader::startAcquisition()
426464
427465 {
428466 const ScopedLock sl (bufferLock);
429- readAndFillBufferCache (bufferA);
467+ readAndFillBufferCache (bufferA, bufferAInfo );
430468 readBuffer = &bufferA;
469+ readBufferInfo = &bufferAInfo;
431470 bufferCacheWindow = 0 ;
432471 needsBufferReset.set (false );
433472 m_shouldFillBackBuffer.set (true );
@@ -470,6 +509,7 @@ void FileReader::setCurrentSample(int64 sampleNumber)
470509
471510 currentSample = sampleNumber;
472511 playbackSamplePos.set (sampleNumber);
512+ resetBufferSchedule ();
473513
474514 // Reset file position
475515 input->seekTo (sampleNumber);
@@ -478,7 +518,8 @@ void FileReader::setCurrentSample(int64 sampleNumber)
478518 {
479519 // Get the current back buffer without switching
480520 HeapBlock<float >* backBuffer = getBackBuffer ();
481- readAndFillBufferCache (*backBuffer);
521+ BufferWindowInfo* backBufferInfo = getBackBufferInfo ();
522+ readAndFillBufferCache (*backBuffer, *backBufferInfo);
482523 }
483524
484525 if (wasThreadRunning)
@@ -496,6 +537,7 @@ void FileReader::setCurrentSample(int64 sampleNumber)
496537 bufferCacheWindow.set (0 );
497538 needsBufferReset.set (false );
498539 readBuffer = &bufferA;
540+ readBufferInfo = &bufferAInfo;
499541 m_shouldFillBackBuffer.set (false );
500542 }
501543
@@ -643,7 +685,7 @@ void FileReader::updateSettings()
643685 if (m_bufferSize == 0 )
644686 m_bufferSize = 1024 ;
645687
646- m_samplesPerBuffer. set (m_bufferSize * ( getDefaultSampleRate () / m_sysSampleRate) );
688+ resetBufferSchedule ( );
647689
648690 bufferA.malloc (currentNumChannels * m_bufferSize * BUFFER_WINDOW_CACHE_SIZE );
649691 bufferB.malloc (currentNumChannels * m_bufferSize * BUFFER_WINDOW_CACHE_SIZE );
@@ -653,6 +695,7 @@ void FileReader::updateSettings()
653695 currentSample = startSample;
654696
655697 readBuffer = &bufferA;
698+ readBufferInfo = &bufferAInfo;
656699 bufferCacheWindow = 0 ;
657700 m_shouldFillBackBuffer.set (false );
658701
@@ -672,7 +715,7 @@ void FileReader::checkAudioDevice()
672715 m_bufferSize = ads.bufferSize ;
673716 if (m_bufferSize == 0 )
674717 m_bufferSize = 1024 ;
675- m_samplesPerBuffer. set (m_bufferSize * ( getDefaultSampleRate () / m_sysSampleRate) );
718+ resetBufferSchedule ( );
676719
677720 bufferA.malloc (currentNumChannels * m_bufferSize * BUFFER_WINDOW_CACHE_SIZE );
678721 bufferB.malloc (currentNumChannels * m_bufferSize * BUFFER_WINDOW_CACHE_SIZE );
@@ -682,6 +725,7 @@ void FileReader::checkAudioDevice()
682725 currentSample = startSample;
683726
684727 readBuffer = &bufferA;
728+ readBufferInfo = &bufferAInfo;
685729 bufferCacheWindow = 0 ;
686730 needsBufferReset.set (false );
687731 m_shouldFillBackBuffer.set (false );
@@ -741,18 +785,22 @@ void FileReader::process (AudioBuffer<float>& buffer)
741785 bufferCacheWindow.set (0 );
742786 }
743787
744- int samplesNeededPerBuffer = int (float (buffer.getNumSamples ()) * (getDefaultSampleRate () / m_sysSampleRate));
745- m_samplesPerBuffer.set (samplesNeededPerBuffer);
746-
747788 // Handle buffer switching
748789 if (firstProcess && bufferCacheWindow.get () == 0 )
749790 {
750791 switchBuffer ();
751792 }
752793
794+ BufferWindowInfo* frontBufferInfo = readBufferInfo;
795+ if (frontBufferInfo == nullptr )
796+ return ;
797+
798+ const int windowIndex = bufferCacheWindow.get ();
799+ const int samplesNeededPerBuffer = frontBufferInfo->sampleCounts [(size_t ) windowIndex];
800+ const int sampleOffset = frontBufferInfo->sampleOffsets [(size_t ) windowIndex];
801+
753802 // Get current buffer position
754- const float * tempReadBuffer = readBuffer->getData () +
755- (samplesNeededPerBuffer * currentNumChannels * bufferCacheWindow.get ());
803+ const float * tempReadBuffer = readBuffer->getData () + (sampleOffset * currentNumChannels);
756804
757805 // Copy data to output buffer
758806 for (int ch = 0 ; ch < currentNumChannels; ++ch)
@@ -827,9 +875,15 @@ void FileReader::switchBuffer()
827875 const ScopedLock sl (bufferLock);
828876
829877 if (readBuffer == &bufferA)
878+ {
830879 readBuffer = &bufferB;
880+ readBufferInfo = &bufferBInfo;
881+ }
831882 else
883+ {
832884 readBuffer = &bufferA;
885+ readBufferInfo = &bufferAInfo;
886+ }
833887
834888 m_shouldFillBackBuffer.set (true );
835889 notify ();
@@ -848,23 +902,32 @@ HeapBlock<float>* FileReader::getBackBuffer()
848902 return &bufferA;
849903}
850904
905+ FileReader::BufferWindowInfo* FileReader::getBackBufferInfo ()
906+ {
907+ if (readBuffer == &bufferA)
908+ return &bufferBInfo;
909+
910+ return &bufferAInfo;
911+ }
912+
851913void FileReader::run ()
852914{
853915 while (! threadShouldExit ())
854916 {
855917 if (m_shouldFillBackBuffer.compareAndSetBool (false , true ))
856918 {
857- readAndFillBufferCache (*getBackBuffer ());
919+ readAndFillBufferCache (*getBackBuffer (), * getBackBufferInfo () );
858920 }
859921
860922 wait (30 );
861923 }
862924}
863925
864- void FileReader::readAndFillBufferCache (HeapBlock<float >& cacheBuffer)
926+ void FileReader::readAndFillBufferCache (HeapBlock<float >& cacheBuffer, BufferWindowInfo& bufferInfo )
865927{
866- const int samplesNeededPerBuffer = m_samplesPerBuffer.get ();
867- const int samplesNeeded = samplesNeededPerBuffer * BUFFER_WINDOW_CACHE_SIZE ;
928+ updateBufferWindowInfo (bufferInfo);
929+
930+ const int samplesNeeded = bufferInfo.totalSamples ;
868931 if (samplesNeeded <= 0 || stopSample <= startSample)
869932 return ;
870933
0 commit comments