LCOV - code coverage report
Current view: top level - media/libsoundtouch/src - SoundTouch.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 149 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 23 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //////////////////////////////////////////////////////////////////////////////
       2             : ///
       3             : /// SoundTouch - main class for tempo/pitch/rate adjusting routines. 
       4             : ///
       5             : /// Notes:
       6             : /// - Initialize the SoundTouch object instance by setting up the sound stream 
       7             : ///   parameters with functions 'setSampleRate' and 'setChannels', then set 
       8             : ///   desired tempo/pitch/rate settings with the corresponding functions.
       9             : ///
      10             : /// - The SoundTouch class behaves like a first-in-first-out pipeline: The 
      11             : ///   samples that are to be processed are fed into one of the pipe by calling
      12             : ///   function 'putSamples', while the ready processed samples can be read 
      13             : ///   from the other end of the pipeline with function 'receiveSamples'.
      14             : /// 
      15             : /// - The SoundTouch processing classes require certain sized 'batches' of 
      16             : ///   samples in order to process the sound. For this reason the classes buffer 
      17             : ///   incoming samples until there are enough of samples available for 
      18             : ///   processing, then they carry out the processing step and consequently
      19             : ///   make the processed samples available for outputting.
      20             : /// 
      21             : /// - For the above reason, the processing routines introduce a certain 
      22             : ///   'latency' between the input and output, so that the samples input to
      23             : ///   SoundTouch may not be immediately available in the output, and neither 
      24             : ///   the amount of outputtable samples may not immediately be in direct 
      25             : ///   relationship with the amount of previously input samples.
      26             : ///
      27             : /// - The tempo/pitch/rate control parameters can be altered during processing.
      28             : ///   Please notice though that they aren't currently protected by semaphores,
      29             : ///   so in multi-thread application external semaphore protection may be
      30             : ///   required.
      31             : ///
      32             : /// - This class utilizes classes 'TDStretch' for tempo change (without modifying
      33             : ///   pitch) and 'RateTransposer' for changing the playback rate (that is, both 
      34             : ///   tempo and pitch in the same ratio) of the sound. The third available control 
      35             : ///   'pitch' (change pitch but maintain tempo) is produced by a combination of
      36             : ///   combining the two other controls.
      37             : ///
      38             : /// Author        : Copyright (c) Olli Parviainen
      39             : /// Author e-mail : oparviai 'at' iki.fi
      40             : /// SoundTouch WWW: http://www.surina.net/soundtouch
      41             : ///
      42             : ////////////////////////////////////////////////////////////////////////////////
      43             : //
      44             : // Last changed  : $Date: 2014-10-08 15:26:57 +0000 (Wed, 08 Oct 2014) $
      45             : // File revision : $Revision: 4 $
      46             : //
      47             : // $Id: SoundTouch.cpp 201 2014-10-08 15:26:57Z oparviai $
      48             : //
      49             : ////////////////////////////////////////////////////////////////////////////////
      50             : //
      51             : // License :
      52             : //
      53             : //  SoundTouch audio processing library
      54             : //  Copyright (c) Olli Parviainen
      55             : //
      56             : //  This library is free software; you can redistribute it and/or
      57             : //  modify it under the terms of the GNU Lesser General Public
      58             : //  License as published by the Free Software Foundation; either
      59             : //  version 2.1 of the License, or (at your option) any later version.
      60             : //
      61             : //  This library is distributed in the hope that it will be useful,
      62             : //  but WITHOUT ANY WARRANTY; without even the implied warranty of
      63             : //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      64             : //  Lesser General Public License for more details.
      65             : //
      66             : //  You should have received a copy of the GNU Lesser General Public
      67             : //  License along with this library; if not, write to the Free Software
      68             : //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      69             : //
      70             : ////////////////////////////////////////////////////////////////////////////////
      71             : 
      72             : #include <assert.h>
      73             : #include <stdlib.h>
      74             : #include <memory.h>
      75             : #include <math.h>
      76             : #include <stdio.h>
      77             : 
      78             : #include "SoundTouch.h"
      79             : #include "TDStretch.h"
      80             : #include "RateTransposer.h"
      81             : #include "cpu_detect.h"
      82             : 
      83             : using namespace soundtouch;
      84             :     
      85             : /// test if two floating point numbers are equal
      86             : #define TEST_FLOAT_EQUAL(a, b)  (fabs(a - b) < 1e-10)
      87             : 
      88             : 
      89             : /// Print library version string for autoconf
      90           0 : extern "C" void soundtouch_ac_test()
      91             : {
      92           0 :     printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION);
      93           0 : } 
      94             : 
      95             : 
      96           0 : SoundTouch::SoundTouch()
      97             : {
      98             :     // Initialize rate transposer and tempo changer instances
      99             : 
     100           0 :     pRateTransposer = new RateTransposer();
     101           0 :     pTDStretch = TDStretch::newInstance();
     102             : 
     103           0 :     setOutPipe(pTDStretch);
     104             : 
     105           0 :     rate = tempo = 0;
     106             : 
     107           0 :     virtualPitch = 
     108           0 :     virtualRate = 
     109           0 :     virtualTempo = 1.0;
     110             : 
     111           0 :     calcEffectiveRateAndTempo();
     112             : 
     113           0 :     channels = 0;
     114           0 :     bSrateSet = false;
     115           0 : }
     116             : 
     117             : 
     118             : 
     119           0 : SoundTouch::~SoundTouch()
     120             : {
     121           0 :     delete pRateTransposer;
     122           0 :     delete pTDStretch;
     123           0 : }
     124             : 
     125             : 
     126             : 
     127             : /// Get SoundTouch library version string
     128           0 : const char *SoundTouch::getVersionString()
     129             : {
     130             :     static const char *_version = SOUNDTOUCH_VERSION;
     131             : 
     132           0 :     return _version;
     133             : }
     134             : 
     135             : 
     136             : /// Get SoundTouch library version Id
     137           0 : uint SoundTouch::getVersionId()
     138             : {
     139           0 :     return SOUNDTOUCH_VERSION_ID;
     140             : }
     141             : 
     142             : 
     143             : // Sets the number of channels, 1 = mono, 2 = stereo
     144           0 : void SoundTouch::setChannels(uint numChannels)
     145             : {
     146             :     /*if (numChannels != 1 && numChannels != 2) 
     147             :     {
     148             :         //ST_THROW_RT_ERROR("Illegal number of channels");
     149             :                 return;
     150             :     }*/
     151           0 :     channels = numChannels;
     152           0 :     pRateTransposer->setChannels((int)numChannels);
     153           0 :     pTDStretch->setChannels((int)numChannels);
     154           0 : }
     155             : 
     156             : 
     157             : 
     158             : // Sets new rate control value. Normal rate = 1.0, smaller values
     159             : // represent slower rate, larger faster rates.
     160           0 : void SoundTouch::setRate(float newRate)
     161             : {
     162           0 :     virtualRate = newRate;
     163           0 :     calcEffectiveRateAndTempo();
     164           0 : }
     165             : 
     166             : 
     167             : 
     168             : // Sets new rate control value as a difference in percents compared
     169             : // to the original rate (-50 .. +100 %)
     170           0 : void SoundTouch::setRateChange(float newRate)
     171             : {
     172           0 :     virtualRate = 1.0f + 0.01f * newRate;
     173           0 :     calcEffectiveRateAndTempo();
     174           0 : }
     175             : 
     176             : 
     177             : 
     178             : // Sets new tempo control value. Normal tempo = 1.0, smaller values
     179             : // represent slower tempo, larger faster tempo.
     180           0 : void SoundTouch::setTempo(float newTempo)
     181             : {
     182           0 :     virtualTempo = newTempo;
     183           0 :     calcEffectiveRateAndTempo();
     184           0 : }
     185             : 
     186             : 
     187             : 
     188             : // Sets new tempo control value as a difference in percents compared
     189             : // to the original tempo (-50 .. +100 %)
     190           0 : void SoundTouch::setTempoChange(float newTempo)
     191             : {
     192           0 :     virtualTempo = 1.0f + 0.01f * newTempo;
     193           0 :     calcEffectiveRateAndTempo();
     194           0 : }
     195             : 
     196             : 
     197             : 
     198             : // Sets new pitch control value. Original pitch = 1.0, smaller values
     199             : // represent lower pitches, larger values higher pitch.
     200           0 : void SoundTouch::setPitch(float newPitch)
     201             : {
     202           0 :     virtualPitch = newPitch;
     203           0 :     calcEffectiveRateAndTempo();
     204           0 : }
     205             : 
     206             : 
     207             : 
     208             : // Sets pitch change in octaves compared to the original pitch
     209             : // (-1.00 .. +1.00)
     210           0 : void SoundTouch::setPitchOctaves(float newPitch)
     211             : {
     212           0 :     virtualPitch = (float)exp(0.69314718056f * newPitch);
     213           0 :     calcEffectiveRateAndTempo();
     214           0 : }
     215             : 
     216             : 
     217             : 
     218             : // Sets pitch change in semi-tones compared to the original pitch
     219             : // (-12 .. +12)
     220           0 : void SoundTouch::setPitchSemiTones(int newPitch)
     221             : {
     222           0 :     setPitchOctaves((float)newPitch / 12.0f);
     223           0 : }
     224             : 
     225             : 
     226             : 
     227           0 : void SoundTouch::setPitchSemiTones(float newPitch)
     228             : {
     229           0 :     setPitchOctaves(newPitch / 12.0f);
     230           0 : }
     231             : 
     232             : 
     233             : // Calculates 'effective' rate and tempo values from the
     234             : // nominal control values.
     235           0 : void SoundTouch::calcEffectiveRateAndTempo()
     236             : {
     237           0 :     float oldTempo = tempo;
     238           0 :     float oldRate = rate;
     239             : 
     240           0 :     tempo = virtualTempo / virtualPitch;
     241           0 :     rate = virtualPitch * virtualRate;
     242             : 
     243           0 :     if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate);
     244           0 :     if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo);
     245             : 
     246             : #ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
     247           0 :     if (rate <= 1.0f) 
     248             :     {
     249           0 :         if (output != pTDStretch) 
     250             :         {
     251             :             FIFOSamplePipe *tempoOut;
     252             : 
     253           0 :             assert(output == pRateTransposer);
     254             :             // move samples in the current output buffer to the output of pTDStretch
     255           0 :             tempoOut = pTDStretch->getOutput();
     256           0 :             tempoOut->moveSamples(*output);
     257             :             // move samples in pitch transposer's store buffer to tempo changer's input
     258             :             // deprecated : pTDStretch->moveSamples(*pRateTransposer->getStore());
     259             : 
     260           0 :             output = pTDStretch;
     261             :         }
     262             :     }
     263             :     else
     264             : #endif
     265             :     {
     266           0 :         if (output != pRateTransposer) 
     267             :         {
     268             :             FIFOSamplePipe *transOut;
     269             : 
     270           0 :             assert(output == pTDStretch);
     271             :             // move samples in the current output buffer to the output of pRateTransposer
     272           0 :             transOut = pRateTransposer->getOutput();
     273           0 :             transOut->moveSamples(*output);
     274             :             // move samples in tempo changer's input to pitch transposer's input
     275           0 :             pRateTransposer->moveSamples(*pTDStretch->getInput());
     276             : 
     277           0 :             output = pRateTransposer;
     278             :         }
     279             :     } 
     280           0 : }
     281             : 
     282             : 
     283             : // Sets sample rate.
     284           0 : void SoundTouch::setSampleRate(uint srate)
     285             : {
     286           0 :     bSrateSet = true;
     287             :     // set sample rate, leave other tempo changer parameters as they are.
     288           0 :     pTDStretch->setParameters((int)srate);
     289           0 : }
     290             : 
     291             : 
     292             : // Adds 'numSamples' pcs of samples from the 'samples' memory position into
     293             : // the input of the object.
     294           0 : void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples)
     295             : {
     296           0 :     if (bSrateSet == false) 
     297             :     {
     298             :         ST_THROW_RT_ERROR("SoundTouch : Sample rate not defined");
     299             :     } 
     300           0 :     else if (channels == 0) 
     301             :     {
     302             :         ST_THROW_RT_ERROR("SoundTouch : Number of channels not defined");
     303             :     }
     304             : 
     305             :     // Transpose the rate of the new samples if necessary
     306             :     /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value...
     307             :     if (rate == 1.0f) 
     308             :     {
     309             :         // The rate value is same as the original, simply evaluate the tempo changer. 
     310             :         assert(output == pTDStretch);
     311             :         if (pRateTransposer->isEmpty() == 0) 
     312             :         {
     313             :             // yet flush the last samples in the pitch transposer buffer
     314             :             // (may happen if 'rate' changes from a non-zero value to zero)
     315             :             pTDStretch->moveSamples(*pRateTransposer);
     316             :         }
     317             :         pTDStretch->putSamples(samples, nSamples);
     318             :     } 
     319             :     */
     320             : #ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
     321           0 :     else if (rate <= 1.0f) 
     322             :     {
     323             :         // transpose the rate down, output the transposed sound to tempo changer buffer
     324           0 :         assert(output == pTDStretch);
     325           0 :         pRateTransposer->putSamples(samples, nSamples);
     326           0 :         pTDStretch->moveSamples(*pRateTransposer);
     327             :     } 
     328             :     else 
     329             : #endif
     330             :     {
     331             :         // evaluate the tempo changer, then transpose the rate up, 
     332           0 :         assert(output == pRateTransposer);
     333           0 :         pTDStretch->putSamples(samples, nSamples);
     334           0 :         pRateTransposer->moveSamples(*pTDStretch);
     335             :     }
     336           0 : }
     337             : 
     338             : 
     339             : // Flushes the last samples from the processing pipeline to the output.
     340             : // Clears also the internal processing buffers.
     341             : //
     342             : // Note: This function is meant for extracting the last samples of a sound
     343             : // stream. This function may introduce additional blank samples in the end
     344             : // of the sound stream, and thus it's not recommended to call this function
     345             : // in the middle of a sound stream.
     346           0 : void SoundTouch::flush()
     347             : {
     348             :     int i;
     349             :     int nUnprocessed;
     350             :     int nOut;
     351           0 :     SAMPLETYPE *buff = new SAMPLETYPE[64 * channels];
     352             :     
     353             :     // check how many samples still await processing, and scale
     354             :     // that by tempo & rate to get expected output sample count
     355           0 :     nUnprocessed = numUnprocessedSamples();
     356           0 :     nUnprocessed = (int)((double)nUnprocessed / (tempo * rate) + 0.5);
     357             : 
     358           0 :     nOut = numSamples();        // ready samples currently in buffer ...
     359           0 :     nOut += nUnprocessed;       // ... and how many we expect there to be in the end
     360             :     
     361           0 :     memset(buff, 0, 64 * channels * sizeof(SAMPLETYPE));
     362             :     // "Push" the last active samples out from the processing pipeline by
     363             :     // feeding blank samples into the processing pipeline until new, 
     364             :     // processed samples appear in the output (not however, more than 
     365             :     // 8ksamples in any case)
     366           0 :     for (i = 0; i < 128; i ++) 
     367             :     {
     368           0 :         putSamples(buff, 64);
     369           0 :         if ((int)numSamples() >= nOut) 
     370             :         {
     371             :             // Enough new samples have appeared into the output!
     372             :             // As samples come from processing with bigger chunks, now truncate it
     373             :             // back to maximum "nOut" samples to improve duration accuracy 
     374           0 :             adjustAmountOfSamples(nOut);
     375             : 
     376             :             // finish
     377           0 :             break;  
     378             :         }
     379             :     }
     380             : 
     381           0 :     delete[] buff;
     382             : 
     383             :     // Clear working buffers
     384           0 :     pRateTransposer->clear();
     385           0 :     pTDStretch->clearInput();
     386             :     // yet leave the 'tempoChanger' output intouched as that's where the
     387             :     // flushed samples are!
     388           0 : }
     389             : 
     390             : 
     391             : // Changes a setting controlling the processing system behaviour. See the
     392             : // 'SETTING_...' defines for available setting ID's.
     393           0 : bool SoundTouch::setSetting(int settingId, int value)
     394             : {
     395             :     int sampleRate, sequenceMs, seekWindowMs, overlapMs;
     396             : 
     397             :     // read current tdstretch routine parameters
     398           0 :     pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs);
     399             : 
     400           0 :     switch (settingId) 
     401             :     {
     402             :         case SETTING_USE_AA_FILTER :
     403             :             // enables / disabless anti-alias filter
     404           0 :             pRateTransposer->enableAAFilter((value != 0) ? true : false);
     405           0 :             return true;
     406             : 
     407             :         case SETTING_AA_FILTER_LENGTH :
     408             :             // sets anti-alias filter length
     409           0 :             pRateTransposer->getAAFilter()->setLength(value);
     410           0 :             return true;
     411             : 
     412             :         case SETTING_USE_QUICKSEEK :
     413             :             // enables / disables tempo routine quick seeking algorithm
     414           0 :             pTDStretch->enableQuickSeek((value != 0) ? true : false);
     415           0 :             return true;
     416             : 
     417             :         case SETTING_SEQUENCE_MS:
     418             :             // change time-stretch sequence duration parameter
     419           0 :             pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs);
     420           0 :             return true;
     421             : 
     422             :         case SETTING_SEEKWINDOW_MS:
     423             :             // change time-stretch seek window length parameter
     424           0 :             pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs);
     425           0 :             return true;
     426             : 
     427             :         case SETTING_OVERLAP_MS:
     428             :             // change time-stretch overlap length parameter
     429           0 :             pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value);
     430           0 :             return true;
     431             : 
     432             :         default :
     433           0 :             return false;
     434             :     }
     435             : }
     436             : 
     437             : 
     438             : // Reads a setting controlling the processing system behaviour. See the
     439             : // 'SETTING_...' defines for available setting ID's.
     440             : //
     441             : // Returns the setting value.
     442           0 : int SoundTouch::getSetting(int settingId) const
     443             : {
     444             :     int temp;
     445             : 
     446           0 :     switch (settingId) 
     447             :     {
     448             :         case SETTING_USE_AA_FILTER :
     449           0 :             return (uint)pRateTransposer->isAAFilterEnabled();
     450             : 
     451             :         case SETTING_AA_FILTER_LENGTH :
     452           0 :             return pRateTransposer->getAAFilter()->getLength();
     453             : 
     454             :         case SETTING_USE_QUICKSEEK :
     455           0 :             return (uint)   pTDStretch->isQuickSeekEnabled();
     456             : 
     457             :         case SETTING_SEQUENCE_MS:
     458           0 :             pTDStretch->getParameters(NULL, &temp, NULL, NULL);
     459           0 :             return temp;
     460             : 
     461             :         case SETTING_SEEKWINDOW_MS:
     462           0 :             pTDStretch->getParameters(NULL, NULL, &temp, NULL);
     463           0 :             return temp;
     464             : 
     465             :         case SETTING_OVERLAP_MS:
     466           0 :             pTDStretch->getParameters(NULL, NULL, NULL, &temp);
     467           0 :             return temp;
     468             : 
     469             :                 case SETTING_NOMINAL_INPUT_SEQUENCE :
     470           0 :                         return pTDStretch->getInputSampleReq();
     471             : 
     472             :                 case SETTING_NOMINAL_OUTPUT_SEQUENCE :
     473           0 :                         return pTDStretch->getOutputBatchSize();
     474             : 
     475             :                 default :
     476           0 :             return 0;
     477             :     }
     478             : }
     479             : 
     480             : 
     481             : // Clears all the samples in the object's output and internal processing
     482             : // buffers.
     483           0 : void SoundTouch::clear()
     484             : {
     485           0 :     pRateTransposer->clear();
     486           0 :     pTDStretch->clear();
     487           0 : }
     488             : 
     489             : 
     490             : 
     491             : /// Returns number of samples currently unprocessed.
     492           0 : uint SoundTouch::numUnprocessedSamples() const
     493             : {
     494             :     FIFOSamplePipe * psp;
     495           0 :     if (pTDStretch)
     496             :     {
     497           0 :         psp = pTDStretch->getInput();
     498           0 :         if (psp)
     499             :         {
     500           0 :             return psp->numSamples();
     501             :         }
     502             :     }
     503           0 :     return 0;
     504             : }

Generated by: LCOV version 1.13