Mixxx

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

Go to the documentation of this file.
00001 /***************************************************************************
00002                           enginebufferscalelinear.cpp  -  description
00003                             -------------------
00004     begin                : Mon Apr 14 2003
00005     copyright            : (C) 2003 by Tue & Ken 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 #include "engine/enginebufferscalelinear.h"
00020 #include "mathstuff.h"
00021 #include "sampleutil.h"
00022 
00023 EngineBufferScaleLinear::EngineBufferScaleLinear(ReadAheadManager *pReadAheadManager) :
00024     EngineBufferScale(),
00025     m_pReadAheadManager(pReadAheadManager)
00026 {
00027     m_dBaseRate = 0.0f;
00028     m_dTempo = 0.0f;
00029     m_fOldTempo = 1.0f;
00030     m_fOldBaseRate = 1.0f;
00031     m_dCurSampleIndex = 0.0f;
00032     m_dNextSampleIndex = 0.0f;
00033 
00034     for (int i=0; i<2; i++)
00035         m_fPrevSample[i] = 0.0f;
00036 
00037     buffer_int = new CSAMPLE[kiLinearScaleReadAheadLength];
00038     buffer_int_size = 0;
00039 
00040     /*df.setFileName("mixxx-debug-scaler.csv");
00041     df.open(QIODevice::WriteOnly | QIODevice::Text);
00042     writer.setDevice(&df);
00043     buffer_count=0;*/
00044     SampleUtil::applyGain(buffer_int, 0.0, kiLinearScaleReadAheadLength);
00045 }
00046 
00047 EngineBufferScaleLinear::~EngineBufferScaleLinear()
00048 {
00049     //df.close();
00050     delete [] buffer_int;
00051 }
00052 
00053 double EngineBufferScaleLinear::setTempo(double _tempo)
00054 {
00055 //    if (m_fOldTempo != m_dTempo)
00056         m_fOldTempo = m_dTempo; //Save the old tempo when the tempo changes
00057 
00058     m_dTempo = _tempo;
00059 
00060     if (m_dTempo>MAX_SEEK_SPEED) {
00061         m_dTempo = MAX_SEEK_SPEED;
00062     } else if (m_dTempo < -MAX_SEEK_SPEED) {
00063         m_dTempo = -MAX_SEEK_SPEED;
00064     }
00065 
00066     // Determine playback direction
00067     if (m_dTempo<0.) {
00068         m_bBackwards = true;
00069     } else {
00070         m_bBackwards = false;
00071     }
00072 
00073     return m_dTempo;
00074 }
00075 
00076 void EngineBufferScaleLinear::setBaseRate(double dBaseRate)
00077 {
00078 //    if (m_fOldBaseRate != m_dBaseRate)
00079         m_fOldBaseRate = m_dBaseRate; //Save the old baserate when it changes
00080 
00081     m_dBaseRate = dBaseRate*m_dTempo;
00082 }
00083 
00084 void EngineBufferScaleLinear::clear()
00085 {
00086     m_bClear = true;
00087 }
00088 
00089 
00090 // laurent de soras - punked from musicdsp.org (mad props)
00091 inline float hermite4(float frac_pos, float xm1, float x0, float x1, float x2)
00092 {
00093     const float c = (x1 - xm1) * 0.5f;
00094     const float v = x0 - x1;
00095     const float w = c + v;
00096     const float a = w + v + (x2 - x0) * 0.5f;
00097     const float b_neg = w + a;
00098     return ((((a * frac_pos) - b_neg) * frac_pos + c) * frac_pos + x0);
00099 }
00100 
00103 CSAMPLE * EngineBufferScaleLinear::scale(double playpos, unsigned long buf_size,
00104                                          CSAMPLE* pBase, unsigned long iBaseLength)
00105 {
00106     float rate_add_new = m_dBaseRate;
00107     float rate_add_old = m_fOldBaseRate; //Smoothly interpolate to new playback rate
00108     int samples_read = 0;
00109     new_playpos = 0;
00110 
00111     // Guard against buf_size == 0
00112     if ((int)buf_size == 0)
00113         return buffer;
00114 
00115     if (rate_add_new * rate_add_old < 0) {
00116         //calculate half buffer going one way, and half buffer going
00117         //the other way.
00118 
00119         //first half: rate goes from old rate to zero
00120         m_fOldBaseRate = rate_add_old;
00121         m_dBaseRate = 0.0;
00122         buffer = do_scale(buffer, buf_size/2, pBase, iBaseLength, &samples_read);
00123 
00124         //reset prev sample so we can now read in the other direction
00125         //(may not be necessary?)
00126         if ((int)ceil(m_dCurSampleIndex)*2+1 < buffer_int_size) {
00127             m_fPrevSample[0] = buffer_int[(int)ceil(m_dNextSampleIndex)*2];
00128             m_fPrevSample[1] = buffer_int[(int)ceil(m_dNextSampleIndex)*2+1];
00129         }
00130 
00131         //if the buffer has extra samples, do a read so RAMAN ends up back where
00132         //it should be
00133         int extra_samples = buffer_int_size - (int)ceil(m_dCurSampleIndex)*2 - 2;
00134         if (extra_samples > 0) {
00135             if (extra_samples % 2 != 0)
00136                 extra_samples++;
00137             //qDebug() << "extra samples" << extra_samples;
00138 
00139             samples_read += m_pReadAheadManager->getNextSamples(
00140                 rate_add_new, buffer_int, extra_samples);
00141         }
00142         //force a buffer read:
00143         buffer_int_size=0;
00144         //make sure the indexes stay correct for interpolation
00145         m_dCurSampleIndex = 0 - m_dCurSampleIndex + floor(m_dCurSampleIndex);
00146         m_dNextSampleIndex = 1.0 - (m_dNextSampleIndex - floor(m_dNextSampleIndex));
00147 
00148         //second half: rate goes from zero to new rate
00149         m_fOldBaseRate = 0.0;
00150         m_dBaseRate = rate_add_new;
00151         //pass the address of the sample at the halfway point
00152         do_scale(&buffer[buf_size/2], buf_size/2, pBase, iBaseLength, &samples_read);
00153 
00154         new_playpos = samples_read;
00155         return buffer;
00156     }
00157 
00158     CSAMPLE* result = do_scale(buffer, buf_size, pBase, iBaseLength, &samples_read);
00159     new_playpos = samples_read;
00160     return result;
00161 }
00162 
00164 CSAMPLE * EngineBufferScaleLinear::do_scale(CSAMPLE* buf, unsigned long buf_size,
00165                                             CSAMPLE* pBase, unsigned long iBaseLength,
00166                                             int* samples_read)
00167 {
00168 
00169     long unscaled_samples_needed;
00170     float rate_add_new = m_dBaseRate;
00171     float rate_add_old = m_fOldBaseRate; //Smoothly interpolate to new playback rate
00172     float rate_add = rate_add_new;
00173     float rate_add_diff = rate_add_new - rate_add_old;
00174     double rate_add_abs;
00175     int original_raman_playposition = m_pReadAheadManager->getPlaypos();
00176 
00177     //Update the old base rate because we only need to
00178     //interpolate/ramp up the pitch changes once.
00179     m_fOldBaseRate = m_dBaseRate;
00180 
00181     // Determine position in read_buffer to start from. (This is always 0 with
00182     // the new EngineBuffer implementation)
00183 
00184     int iRateLerpLength = (int)buf_size;
00185 
00186     // Guard against buf_size == 0
00187     if (iRateLerpLength == 0)
00188         return buf;
00189 
00190 
00191     //We check for scratch condition in the public function, so this
00192     //shouldn't happen
00193     Q_ASSERT(rate_add_new * rate_add_old >= 0);
00194 
00195     // Simulate the loop to estimate how many samples we need
00196     double samples = 0;
00197 
00198     for (int j = 0; j < iRateLerpLength; j += 2) {
00199         rate_add = (rate_add_diff) / (float)iRateLerpLength * (float)j + rate_add_old;
00200         samples += fabs(rate_add);
00201     }
00202 
00203     rate_add = rate_add_new;
00204     rate_add_abs = fabs(rate_add);
00205 
00206     //we're calculating mono samples, so divide remaining buffer by 2;
00207     samples += (rate_add_abs * ((float)(buf_size - iRateLerpLength)/2));
00208        unscaled_samples_needed = floor(samples);
00209 
00210        //if the current position fraction plus the future position fraction
00211        //loops over 1.0, we need to round up
00212     if (m_dNextSampleIndex - floor(m_dNextSampleIndex) + samples - floor(samples) > 1.0) {
00213         unscaled_samples_needed++;
00214     }
00215 
00216     // Multiply by 2 because it is predicting mono rates, while we want a stereo
00217     // number of samples.
00218     unscaled_samples_needed *= 2;
00219 
00220     //0 is never the right answer
00221     unscaled_samples_needed = math_max(2,unscaled_samples_needed);
00222 
00223     bool last_read_failed = false;
00224     CSAMPLE prev_sample[2];
00225     CSAMPLE cur_sample[2];
00226     double prevIndex=0;
00227 
00228     prev_sample[0]=0;
00229     prev_sample[1]=0;
00230     cur_sample[0]=0;
00231     cur_sample[1]=0;
00232 
00233     int i = 0;
00234     int screwups = 0;
00235     while(i < buf_size) {
00236         //shift indicies
00237         prevIndex = m_dCurSampleIndex;
00238         m_dCurSampleIndex = m_dNextSampleIndex;
00239 
00240         //we're going to be interpolating between two samples, a lower (prev)
00241         //and upper (cur) sample.  If the lower sample is off the end of the buffer,
00242         //load it from the saved globals
00243 
00244         if ((int)floor(m_dCurSampleIndex)*2+1 < buffer_int_size && m_dCurSampleIndex >= 0.0) {
00245             m_fPrevSample[0] = prev_sample[0] = buffer_int[(int)floor(m_dCurSampleIndex)*2];
00246             m_fPrevSample[1] = prev_sample[1] = buffer_int[(int)floor(m_dCurSampleIndex)*2+1];
00247         } else {
00248             prev_sample[0] = m_fPrevSample[0];
00249             prev_sample[1] = m_fPrevSample[1];
00250         }
00251 
00252         //Smooth any changes in the playback rate over iRateLerpLength
00253         //samples. This prevents the change from being discontinuous and helps
00254         //improve sound quality.
00255         if (i < iRateLerpLength) {
00256             rate_add = (float)i * (rate_add_diff) / (float)iRateLerpLength + rate_add_old;
00257             //rate_add = sigmoid_zero((float)i,(float)iRateLerpLength) * rate_add_diff + rate_add_old;
00258         } else {
00259             rate_add = rate_add_new;
00260         }
00261 
00262         // if we don't have enough samples, load some more
00263         while ((int)ceil(m_dCurSampleIndex)*2+1 >= buffer_int_size) {
00264             int old_bufsize = buffer_int_size;
00265             //qDebug() << "buffer" << buffer_count << rate_add_old << rate_add_new << rate_add << i << m_dCurSampleIndex << buffer_int_size << unscaled_samples_needed;
00266             //Q_ASSERT(unscaled_samples_needed > 0);
00267             if (unscaled_samples_needed == 0) {
00268                 //qDebug() << "screwup" << m_dCurSampleIndex << (int)ceil(m_dCurSampleIndex)*2+1 << buffer_int_size;
00269                 unscaled_samples_needed = 2;
00270                 screwups++;
00271             }
00272 
00273             int samples_to_read = math_min(kiLinearScaleReadAheadLength,
00274                                            unscaled_samples_needed);
00275 
00276             if(rate_add_new == 0) {
00277                 //qDebug() << "new rate was zero";
00278                 buffer_int_size = m_pReadAheadManager
00279                                 ->getNextSamples(rate_add_old,buffer_int,
00280                                                  samples_to_read);
00281                 *samples_read += buffer_int_size;
00282             } else {
00283                 buffer_int_size = m_pReadAheadManager
00284                                 ->getNextSamples(rate_add_new,buffer_int,
00285                                                  samples_to_read);
00286                 *samples_read += buffer_int_size;
00287             }
00288 
00289             if (buffer_int_size == 0 && last_read_failed) {
00290                 break;
00291             }
00292             last_read_failed = buffer_int_size == 0;
00293 
00294             unscaled_samples_needed -= buffer_int_size;
00295             //shift the index by the size of the old buffer
00296             m_dCurSampleIndex -= old_bufsize / 2;
00297             prevIndex -= old_bufsize / 2;
00298             //fractions below 0 is ok, the ceil will bring it up to 0
00299             //this happens sometimes, somehow?
00300             //Q_ASSERT(m_dCurSampleIndex > -1.0);
00301 
00302             //not sure this actually does anything, but it seems to help
00303             if ((int)floor(m_dCurSampleIndex)*2 >= 0.0) {
00304                 m_fPrevSample[0] = prev_sample[0] = buffer_int[(int)floor(m_dCurSampleIndex)*2];
00305                 m_fPrevSample[1] = prev_sample[1] = buffer_int[(int)floor(m_dCurSampleIndex)*2+1];
00306             }
00307         }
00308         //I guess?
00309         if (last_read_failed)
00310             break;
00311 
00312         cur_sample[0] = buffer_int[(int)ceil(m_dCurSampleIndex)*2];
00313         cur_sample[1] = buffer_int[(int)ceil(m_dCurSampleIndex)*2+1];
00314 
00315         //rate_add was here
00316 
00317         //for the current index, what percentage is it between the previous and the next?
00318         CSAMPLE frac = m_dCurSampleIndex - floor(m_dCurSampleIndex);
00319 
00320         //Perform linear interpolation
00321         buf[i] = (float)prev_sample[0] + frac * ((float)cur_sample[0] - (float)prev_sample[0]);
00322         buf[i+1] = (float)prev_sample[1] + frac * ((float)cur_sample[1] - (float)prev_sample[1]);
00323 
00324         //at extremely low speeds, dampen the gain to hide pops and clicks
00325         //this does cause odd-looking linear waveforms that go to zero and back
00326 
00327         /*writer << QString("%1,%2,%3,%4\n").arg(buffer_count)
00328                                          .arg(buffer[i])
00329                                            .arg(prev_sample[0])
00330                                            .arg(cur_sample[0]);
00331         buffer_count++;*/
00332 
00333         //increment the index for the next loop
00334         if (i < iRateLerpLength)
00335             m_dNextSampleIndex = m_dCurSampleIndex + fabs(rate_add);
00336         else
00337             m_dNextSampleIndex = m_dCurSampleIndex + rate_add_abs;
00338 
00339         i+=2;
00340 
00341     }
00342     // If we broke out of the loop, zero the remaining samples
00343     // TODO(XXX) memset
00344     //for (; i < buf_size; i += 2) {
00345     //    buf[i] = 0.0f;
00346     //    buf[i+1] = 0.0f;
00347     //}
00348 
00349     //Q_ASSERT(i>=buf_size);
00350     SampleUtil::applyGain(&buf[i], 0.0f, buf_size-i);
00351 
00352     // It's possible that we will exit this function without having satisfied
00353     // this requirement. We may be trying to read past the end of the file.
00354     //Q_ASSERT(unscaled_samples_needed == 0);
00355 
00356     return buf;
00357 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines