![]() |
Mixxx
|
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 }