Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/test/enginebufferscalelineartest.cpp

Go to the documentation of this file.
00001 #include <gmock/gmock.h>
00002 #include <gtest/gtest.h>
00003 
00004 #include <QtDebug>
00005 #include <QVector>
00006 
00007 #include "defs.h"
00008 #include "configobject.h"
00009 #include "engine/readaheadmanager.h"
00010 #include "engine/enginebufferscalelinear.h"
00011 
00012 using ::testing::StrictMock;
00013 using ::testing::Return;
00014 using ::testing::Invoke;
00015 using ::testing::_;
00016 
00017 namespace {
00018 
00019 class ReadAheadManagerMock : public ReadAheadManager {
00020   public:
00021     ReadAheadManagerMock()
00022             : ReadAheadManager(NULL),
00023               m_pBuffer(NULL),
00024               m_iBufferSize(0),
00025               m_iReadPosition(0),
00026               m_iSamplesRead(0) {
00027     }
00028 
00029     int getNextSamplesFake(double dRate, CSAMPLE* buffer, int requested_samples) {
00030         bool hasBuffer = m_pBuffer != NULL;
00031         // You forgot to set the mock read buffer.
00032         EXPECT_TRUE(hasBuffer);
00033 
00034         for (int i = 0; i < requested_samples; ++i) {
00035             buffer[i] = hasBuffer ? m_pBuffer[m_iReadPosition++ % m_iBufferSize] : 0;
00036         }
00037         m_iSamplesRead += requested_samples;
00038         return requested_samples;
00039     }
00040 
00041     void setReadBuffer(CSAMPLE* pBuffer, int iBufferSize) {
00042         m_pBuffer = pBuffer;
00043         m_iBufferSize = iBufferSize;
00044         m_iReadPosition = 0;
00045     }
00046 
00047     int getSamplesRead() {
00048         return m_iSamplesRead;
00049     }
00050 
00051     MOCK_METHOD3(getNextSamples, int(double dRate, CSAMPLE* buffer, int requested_samples));
00052 
00053     CSAMPLE* m_pBuffer;
00054     int m_iBufferSize;
00055     int m_iReadPosition;
00056     int m_iSamplesRead;
00057 };
00058 
00059 class EngineBufferScaleLinearTest : public testing::Test {
00060   protected:
00061     virtual void SetUp() {
00062         m_pConfig = new ConfigObject<ConfigValue>("");
00063         m_pReadAheadMock = new StrictMock<ReadAheadManagerMock>();
00064         m_pScaler = new EngineBufferScaleLinear(m_pReadAheadMock);
00065     }
00066 
00067     virtual void TearDown() {
00068         delete m_pConfig;
00069         delete m_pScaler;
00070         delete m_pReadAheadMock;
00071     }
00072 
00073     void SetRate(double rate) {
00074         m_pScaler->setTempo(1.0);
00075         m_pScaler->setBaseRate(rate);
00076     }
00077 
00078     void SetRateNoLerp(double rate) {
00079         // Set it twice to prevent rate LERP'ing
00080         SetRate(rate);
00081         SetRate(rate);
00082     }
00083 
00084     void ClearBuffer(CSAMPLE* pBuffer, int length) {
00085         memset(pBuffer, 0, sizeof(pBuffer[0])*length);
00086     }
00087 
00088     void FillBuffer(CSAMPLE* pBuffer, CSAMPLE value, int length) {
00089         for (int i = 0; i < length; ++i) {
00090             pBuffer[i] = value;
00091         }
00092     }
00093 
00094     void AssertWholeBufferEquals(const CSAMPLE* pBuffer, CSAMPLE value, int iBufferLen) {
00095         for (int i = 0; i < iBufferLen; ++i) {
00096             EXPECT_FLOAT_EQ(value, pBuffer[i]);
00097         }
00098     }
00099 
00100     void AssertBufferCycles(const CSAMPLE* pBuffer, int iBufferLen,
00101                             CSAMPLE* pCycleBuffer, int iCycleLength) {
00102         int cycleRead = 0;
00103         for (int i = 0; i < iBufferLen; ++i) {
00104             qDebug() << "i" << i << pBuffer[i] << pCycleBuffer[cycleRead % iCycleLength];
00105             EXPECT_FLOAT_EQ(pCycleBuffer[cycleRead++ % iCycleLength], pBuffer[i]);
00106         }
00107     }
00108 
00109     void AssertBufferMonotonicallyProgresses(const CSAMPLE* pBuffer,
00110                                              CSAMPLE start, CSAMPLE finish,
00111                                              int iBufferLen) {
00112         CSAMPLE currentLimit = start;
00113         bool increasing = (finish - start) > 0;
00114 
00115         for (int i = 0; i < iBufferLen; ++i) {
00116             if (increasing) {
00117                 //qDebug() << "i" << i << pBuffer[i] << currentLimit;
00118                 EXPECT_GE(pBuffer[i], currentLimit);
00119                 currentLimit = pBuffer[i];
00120             } else {
00121                 EXPECT_LE(pBuffer[i], currentLimit);
00122                 currentLimit = pBuffer[i];
00123             }
00124         }
00125     }
00126 
00127     ConfigObject<ConfigValue>* m_pConfig;
00128     StrictMock<ReadAheadManagerMock>* m_pReadAheadMock;
00129     EngineBufferScaleLinear* m_pScaler;
00130 };
00131 
00132 TEST_F(EngineBufferScaleLinearTest, ScaleConstant) {
00133     SetRateNoLerp(1.0);
00134 
00135     CSAMPLE readBuffer[1] = { 1.0f };
00136     m_pReadAheadMock->setReadBuffer(readBuffer, 1);
00137 
00138     // Tell the RAMAN mock to invoke getNextSamplesFake
00139     EXPECT_CALL(*m_pReadAheadMock, getNextSamples(_, _, _))
00140             .WillRepeatedly(Invoke(m_pReadAheadMock, &ReadAheadManagerMock::getNextSamplesFake));
00141 
00142     CSAMPLE* pOutput = m_pScaler->scale(0, kiLinearScaleReadAheadLength, 0, 0);
00143     // TODO(rryan) the LERP w/ the previous buffer causes samples 0 and 1 to be
00144     // 0, for now skip the first two.
00145     AssertWholeBufferEquals(pOutput+2, 1.0f, kiLinearScaleReadAheadLength-2);
00146 
00147     // Check that the total samples read from the RAMAN is equal to the samples
00148     // we requested.
00149     ASSERT_EQ(kiLinearScaleReadAheadLength, m_pReadAheadMock->getSamplesRead());
00150 }
00151 
00152 TEST_F(EngineBufferScaleLinearTest, UnityRateIsSamplePerfect) {
00153     SetRateNoLerp(1.0);
00154 
00155     // Tell the RAMAN mock to invoke getNextSamplesFake
00156     EXPECT_CALL(*m_pReadAheadMock, getNextSamples(_, _, _))
00157             .WillRepeatedly(Invoke(m_pReadAheadMock, &ReadAheadManagerMock::getNextSamplesFake));
00158 
00159     QVector<CSAMPLE> readBuffer;
00160     for (int i = 0; i < 1000; ++i) {
00161         readBuffer.push_back(i);
00162     }
00163     m_pReadAheadMock->setReadBuffer(readBuffer.data(), readBuffer.size());
00164 
00165     const int totalSamples = kiLinearScaleReadAheadLength;
00166     CSAMPLE* pOutput = m_pScaler->scale(0, totalSamples, 0, 0);
00167 
00168     // TODO(rryan) the LERP w/ the previous buffer causes samples 0 and 1 to be
00169     // 0, for now skip the first two.
00170     const int skip = 2;
00171     AssertBufferCycles(pOutput+skip, totalSamples-skip, readBuffer.data(), readBuffer.size());
00172 
00173     // Check that the total samples read from the RAMAN is equal to the samples
00174     // we requested.
00175     ASSERT_EQ(totalSamples, m_pReadAheadMock->getSamplesRead());
00176 }
00177 
00178 TEST_F(EngineBufferScaleLinearTest, TestRateLERPMonotonicallyProgresses) {
00179     // Starting from a rate of 0.0, we'll go to a rate of 1.0
00180     SetRate(0.0f);
00181     SetRate(1.0f);
00182 
00183     const int bufferSize = 1000; // kiLinearScaleReadAheadLength;
00184 
00185     // Read all 1's
00186     CSAMPLE readBuffer[] = { 1.0f };
00187     m_pReadAheadMock->setReadBuffer(readBuffer, 1);
00188 
00189     // Tell the RAMAN mock to invoke getNextSamplesFake
00190     EXPECT_CALL(*m_pReadAheadMock, getNextSamples(_, _, _))
00191             .WillRepeatedly(Invoke(m_pReadAheadMock, &ReadAheadManagerMock::getNextSamplesFake));
00192 
00193     CSAMPLE* pOutput = m_pScaler->scale(0, bufferSize, 0, 0);
00194 
00195     AssertBufferMonotonicallyProgresses(pOutput, 0.0f, 1.0f, bufferSize);
00196 }
00197 
00198 TEST_F(EngineBufferScaleLinearTest, TestDoubleSpeedSmoothlyHalvesSamples) {
00199     SetRateNoLerp(2.0f);
00200     const int bufferSize = 1000; // kiLinearScaleReadAheadLength;
00201 
00202     // To prove that the channels don't touch each other, we're using negative
00203     // values on the first channel and positive values on the second channel. If
00204     // a fraction of either channel were mixed into either, then we would see a
00205     // big shift in our desired values.
00206     CSAMPLE readBuffer[] = { 1.0, 1.0,
00207                              0.0, 0.0,
00208                              -1.0, -1.0,
00209                              0.0, 0.0 };
00210     m_pReadAheadMock->setReadBuffer(readBuffer, 8);
00211 
00212     // Tell the RAMAN mock to invoke getNextSamplesFake
00213     EXPECT_CALL(*m_pReadAheadMock, getNextSamples(_, _, _))
00214             .WillRepeatedly(Invoke(m_pReadAheadMock, &ReadAheadManagerMock::getNextSamplesFake));
00215 
00216     CSAMPLE* pOutput = m_pScaler->scale(0, bufferSize, 0, 0);
00217 
00218     CSAMPLE expectedResult[] = { 1.0, 1.0,
00219                                  -1.0, -1.0 };
00220 
00221     // TODO(rryan) the LERP w/ the previous buffer causes samples 0 and 1 to be
00222     // 0, for now skip the first two.
00223     const int skip = 2;
00224     AssertBufferCycles(pOutput+skip, bufferSize-skip, expectedResult, 4);
00225 
00226     // Check that the total samples read from the RAMAN is double the samples
00227     // we requested.
00228     ASSERT_EQ(bufferSize*2, m_pReadAheadMock->getSamplesRead());
00229 }
00230 
00231 TEST_F(EngineBufferScaleLinearTest, TestHalfSpeedSmoothlyDoublesSamples) {
00232     SetRateNoLerp(0.5f);
00233     const int bufferSize = 1000; // kiLinearScaleReadAheadLength;
00234 
00235     // To prove that the channels don't touch each other, we're using negative
00236     // values on the first channel and positive values on the second channel. If
00237     // a fraction of either channel were mixed into either, then we would see a
00238     // big shift in our desired values.
00239     CSAMPLE readBuffer[] = { -101.0, 101.0,
00240                              -99.0, 99.0 };
00241     m_pReadAheadMock->setReadBuffer(readBuffer, 4);
00242 
00243     // Tell the RAMAN mock to invoke getNextSamplesFake
00244     EXPECT_CALL(*m_pReadAheadMock, getNextSamples(_, _, _))
00245             .WillRepeatedly(Invoke(m_pReadAheadMock, &ReadAheadManagerMock::getNextSamplesFake));
00246 
00247     CSAMPLE* pOutput = m_pScaler->scale(0, bufferSize, 0, 0);
00248 
00249     CSAMPLE expectedResult[] = { -101.0, 101.0,
00250                                  -100.0, 100.0,
00251                                  -99.0, 99.0,
00252                                  -100.0, 100.0 };
00253 
00254     // TODO(rryan) strange hysteresis happens and it takes 12 samples to produce
00255     // the desired cycle. Need to investigate this.
00256     const int skip = 12;
00257     AssertBufferCycles(pOutput+skip, bufferSize-skip, expectedResult, 8);
00258 
00259     // Check that the total samples read from the RAMAN is half the samples
00260     // we requested.
00261     ASSERT_EQ(bufferSize/2, m_pReadAheadMock->getSamplesRead());
00262 }
00263 
00264 TEST_F(EngineBufferScaleLinearTest, TestRepeatedScaleCalls) {
00265     SetRateNoLerp(0.5f);
00266     const int bufferSize = 1000; // kiLinearScaleReadAheadLength;
00267 
00268     // To prove that the channels don't touch each other, we're using negative
00269     // values on the first channel and positive values on the second channel. If
00270     // a fraction of either channel were mixed into either, then we would see a
00271     // big shift in our desired values.
00272     CSAMPLE readBuffer[] = { -101.0, 101.0,
00273                              -99.0, 99.0 };
00274     m_pReadAheadMock->setReadBuffer(readBuffer, 4);
00275 
00276     // Tell the RAMAN mock to invoke getNextSamplesFake
00277     EXPECT_CALL(*m_pReadAheadMock, getNextSamples(_, _, _))
00278             .WillRepeatedly(Invoke(m_pReadAheadMock, &ReadAheadManagerMock::getNextSamplesFake));
00279 
00280     CSAMPLE expectedResult[] = { -101.0, 101.0,
00281                                  -100.0, 100.0,
00282                                  -99.0, 99.0,
00283                                  -100.0, 100.0 };
00284 
00285     // Process 12 off the bat, strange hysteresis happens so get that over with here.
00286     const int skip = 12;
00287     CSAMPLE* pOutput = m_pScaler->scale(0, skip, 0, 0);
00288 
00289     int samplesRemaining = bufferSize - skip;
00290     while (samplesRemaining > 0) {
00291         int toRead = math_min(8, samplesRemaining);
00292         pOutput = m_pScaler->scale(0, 8, 0, 0);
00293         samplesRemaining -= toRead;
00294         AssertBufferCycles(pOutput, toRead, expectedResult, toRead);
00295     }
00296 }
00297 
00298 }  // namespace
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines