Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/engine/enginebufferscalest.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           enginebufferscalest.cpp  -  description
00003                              -------------------
00004     begin                : November 2004
00005     copyright            : (C) 2004 by Tue Haste Andersen
00006     email                : haste@diku.dk
00007 ***************************************************************************/
00008 
00009 /***************************************************************************
00010 *                                                                         *
00011 *   This program is free software; you can redistribute it and/or modify  *
00012 *   it under the terms of the GNU General Public License as published by  *
00013 *   the Free Software Foundation; either version 2 of the License, or     *
00014 *   (at your option) any later version.                                   *
00015 *                                                                         *
00016 ***************************************************************************/
00017 
00018 #include <QtCore>
00019 
00020 #include "enginebufferscalest.h"
00021 
00022 #include "SoundTouch.h"
00023 #include "mathstuff.h"
00024 #include "controlobject.h"
00025 #include "engine/readaheadmanager.h"
00026 #include "engine/engineobject.h"
00027 
00028 using namespace soundtouch;
00029 
00030 EngineBufferScaleST::EngineBufferScaleST(ReadAheadManager *pReadAheadManager) :
00031     EngineBufferScale(),
00032     m_bBackwards(false),
00033     m_bPitchIndpTimeStretch(false),
00034     m_bClear(true),
00035     m_pReadAheadManager(pReadAheadManager)
00036 {
00037     m_qMutex.lock();
00038     m_pSoundTouch = new soundtouch::SoundTouch();
00039     m_dBaseRate = 1.;
00040     m_dTempo = 1.;
00041 
00042     m_pSoundTouch->setChannels(2);
00043     m_pSoundTouch->setRate(m_dBaseRate);
00044     m_pSoundTouch->setTempo(m_dTempo);
00045     m_pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, 1);
00046     m_qMutex.unlock();
00047 
00048     slotSetSamplerate(44100.);
00049     ControlObject * p = ControlObject::getControl(ConfigKey("[Master]","samplerate"));
00050     connect(p, SIGNAL(valueChanged(double)), this, SLOT(slotSetSamplerate(double)));
00051 
00052     buffer_back = new CSAMPLE[kiSoundTouchReadAheadLength*2];
00053 }
00054 
00055 EngineBufferScaleST::~EngineBufferScaleST()
00056 {
00057     delete m_pSoundTouch;
00058     delete [] buffer_back;
00059 }
00060 
00061 void EngineBufferScaleST::setPitchIndpTimeStretch(bool b)
00062 {
00063     m_bPitchIndpTimeStretch = b;
00064     m_qMutex.lock();
00065     if (m_bPitchIndpTimeStretch)
00066         m_pSoundTouch->setRate(1.);
00067     else
00068         m_pSoundTouch->setTempo(1.);
00069     m_qMutex.unlock();
00070 }
00071 
00072 bool EngineBufferScaleST::getPitchIndpTimeStretch(void)
00073 {
00074     return m_bPitchIndpTimeStretch;
00075 }
00076 
00077 
00078 void EngineBufferScaleST::setBaseRate(double dBaseRate)
00079 {
00080     m_dBaseRate = dBaseRate;
00081 
00082     m_qMutex.lock();
00083     if (m_bPitchIndpTimeStretch) {
00084         m_pSoundTouch->setRate(m_dBaseRate);
00085     }
00086     //or if if we use ST for linear interpolation...
00087     else if (m_dBaseRate >= MIN_SEEK_SPEED) {
00088         m_pSoundTouch->setRate(m_dBaseRate*m_dTempo);
00089     }
00090     //It's an error to pass a rate or tempo smaller than MIN_SEEK_SPEED to SoundTouch.
00091     //if (m_dBaseRate <= MIN_SEEK_SPEED)
00092     //    m_pSoundTouch->setRate(0.010f);
00093     //else if(m_dBaseRate >= MIN_SEEK_SPEED)
00094     //    m_pSoundTouch->setRate(m_dBaseRate*m_dTempo);
00095     m_qMutex.unlock();
00096 }
00097 
00098 
00099 void EngineBufferScaleST::clear()
00100 {
00101     m_qMutex.lock();
00102     m_pSoundTouch->clear();
00103     m_bClear = true;
00104     m_qMutex.unlock();
00105 }
00106 
00107 void EngineBufferScaleST::slotSetSamplerate(double dSampleRate)
00108 {
00109     int iSrate = (int)dSampleRate;
00110 
00111     m_qMutex.lock();
00112     if (iSrate>0)
00113         m_pSoundTouch->setSampleRate(iSrate);
00114     else
00115         m_pSoundTouch->setSampleRate(44100);
00116     m_qMutex.unlock();
00117 }
00118 
00119 double EngineBufferScaleST::setTempo(double dTempo)
00120 {
00121     double dTempoOld = m_dTempo;
00122     m_dTempo = fabs(dTempo);
00123 
00124     if (m_dTempo>MAX_SEEK_SPEED)
00125         m_dTempo = MAX_SEEK_SPEED;
00126     else if (m_dTempo<MIN_SEEK_SPEED)
00127         m_dTempo = 0.0;
00128 
00129     m_qMutex.lock();
00130     //It's an error to pass a rate or tempo smaller than MIN_SEEK_SPEED to SoundTouch.
00131     if (dTempoOld != m_dTempo && m_dTempo != 0.0)
00132     {
00133         if (m_bPitchIndpTimeStretch)
00134             m_pSoundTouch->setTempo(m_dTempo);
00135         else
00136             m_pSoundTouch->setRate(m_dBaseRate*m_dTempo);
00137     }
00138     m_qMutex.unlock();
00139 
00140     if (dTempo<0.)
00141     {
00142         if (!m_bBackwards)
00143             clear();
00144 
00145         m_bBackwards = true;
00146         return -m_dTempo;
00147     }
00148     else
00149     {
00150         if (m_bBackwards)
00151             clear();
00152 
00153         m_bBackwards = false;
00154         return m_dTempo;
00155     }
00156 }
00157 
00164 CSAMPLE* EngineBufferScaleST::scale(double playpos, unsigned long buf_size,
00165                                     CSAMPLE* pBase, unsigned long iBaseLength) {
00166     Q_UNUSED (pBase);
00167     Q_UNUSED (iBaseLength);
00168     new_playpos = 0.0;
00169 
00170     m_qMutex.lock();
00171 
00172     int iCurPos = playpos;
00173     if (!even(iCurPos)) {
00174         iCurPos--;
00175     }
00176 
00177     //If we've just cleared SoundTouch's FIFO of unprocessed samples,
00178     //then reset our "read ahead position" because we probably need
00179     //to read backwards instead of forwards or something like that.
00180     // if (true || m_bClear)
00181     // {
00182     //     m_iReadAheadPos = (unsigned long)playpos;
00183     //     if (!even(m_iReadAheadPos))
00184     //         m_iReadAheadPos--;
00185     //         //m_iReadAheadPos = (m_iReadAheadPos+1)%iBaseLength;
00186     //     m_bClear = false;
00187     // }
00188     //Q_ASSERT(m_iReadAheadPos >= 0);
00189 
00190     unsigned long total_received_frames = 0;
00191     unsigned long total_read_frames = 0;
00192 
00193     unsigned long remaining_frames = buf_size/2;
00194     //long remaining_source_frames = iBaseLength/2;
00195     CSAMPLE* read = buffer;
00196     bool last_read_failed = false;
00197     while (remaining_frames > 0) {
00198         unsigned long received_frames = m_pSoundTouch->receiveSamples((SAMPLETYPE*)read, remaining_frames);
00199         remaining_frames -= received_frames;
00200         total_received_frames += received_frames;
00201         read += received_frames*2;
00202 
00203         if (remaining_frames > 0) {
00204             // math_min(kiSoundTouchReadAheadLength,remaining_source_frames);
00205             unsigned long iLenFrames = kiSoundTouchReadAheadLength;
00206             unsigned long iAvailSamples = m_pReadAheadManager
00207                 ->getNextSamples((m_bBackwards ? -1.0f : 1.0f) * m_dBaseRate * m_dTempo,
00208                                  buffer_back,
00209                                  iLenFrames * 2);
00210             unsigned long iAvailFrames = iAvailSamples / 2;
00211 
00212             if (iAvailFrames > 0) {
00213                 last_read_failed = false;
00214                 total_read_frames += iAvailFrames;
00215                 m_pSoundTouch->putSamples(buffer_back, iAvailFrames);
00216             } else {
00217                 if (last_read_failed)
00218                     break;
00219                 last_read_failed = true;
00220                 m_pSoundTouch->flush();
00221             }
00222         }
00223     }
00224 
00225     //Feed more samples into SoundTouch until it has processed enough to
00226     //fill the audio buffer that we need to fill.
00227     //SoundTouch::numSamples() returns the number of _FRAMES_ that
00228     //are in its FIFO audio buffer...
00229 
00230 
00231     // Calculate new playpos
00232 
00233     //Get the stretched _frames_ (not Samples, as the function call
00234     //erroroneously implies)
00235     //long receivedFrames = m_pSoundTouch->receiveSamples((SAMPLETYPE*)buffer, buf_size/2);
00236 
00237     // qDebug() << "Fed ST" << total_read_frames*2
00238     //          << "samples to get" << total_received_frames*2 << "samples";
00239     if (total_received_frames != buf_size/2)
00240     {
00241         qDebug() << __FILE__ << "- only wrote" << total_received_frames << "frames instead of requested" << buf_size;
00242     }
00243 
00244     //for (unsigned long i = 0; i < buf_size; i++)
00245     //    qDebug() << buffer[i];
00246 
00247     // new_playpos is now interpreted as the total number of virtual samples
00248     // consumed to produce the scaled buffer. Due to this, we do not take into
00249     // account directionality or starting point.
00250     new_playpos = m_dTempo*m_dBaseRate*total_received_frames*2;
00251 
00252     m_qMutex.unlock();
00253 
00254     return buffer;
00255 }
00256 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines