/external/pysoundtouch14/libsoundtouch/SoundTouch.cpp

http://echo-nest-remix.googlecode.com/ · C++ · 478 lines · 238 code · 93 blank · 147 comment · 33 complexity · a9ef58b16475db710c09c2d9c0d454ea MD5 · raw file

  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: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $
  45. // File revision : $Revision: 4 $
  46. //
  47. // $Id: SoundTouch.cpp 11 2008-02-10 16:26:55Z 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. #include <assert.h>
  72. #include <stdlib.h>
  73. #include <memory.h>
  74. #include <math.h>
  75. #include <stdexcept>
  76. #include <stdio.h>
  77. #include "SoundTouch.h"
  78. #include "TDStretch.h"
  79. #include "RateTransposer.h"
  80. #include "cpu_detect.h"
  81. using namespace soundtouch;
  82. /// test if two floating point numbers are equal
  83. #define TEST_FLOAT_EQUAL(a, b) (fabs(a - b) < 1e-10)
  84. /// Print library version string
  85. extern "C" void soundtouch_ac_test()
  86. {
  87. printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION);
  88. }
  89. SoundTouch::SoundTouch()
  90. {
  91. // Initialize rate transposer and tempo changer instances
  92. pRateTransposer = RateTransposer::newInstance();
  93. pTDStretch = TDStretch::newInstance();
  94. setOutPipe(pTDStretch);
  95. rate = tempo = 0;
  96. virtualPitch =
  97. virtualRate =
  98. virtualTempo = 1.0;
  99. calcEffectiveRateAndTempo();
  100. channels = 0;
  101. bSrateSet = FALSE;
  102. }
  103. SoundTouch::~SoundTouch()
  104. {
  105. delete pRateTransposer;
  106. delete pTDStretch;
  107. }
  108. /// Get SoundTouch library version string
  109. const char *SoundTouch::getVersionString()
  110. {
  111. static const char *_version = SOUNDTOUCH_VERSION;
  112. return _version;
  113. }
  114. /// Get SoundTouch library version Id
  115. uint SoundTouch::getVersionId()
  116. {
  117. return SOUNDTOUCH_VERSION_ID;
  118. }
  119. // Sets the number of channels, 1 = mono, 2 = stereo
  120. void SoundTouch::setChannels(uint numChannels)
  121. {
  122. if (numChannels != 1 && numChannels != 2)
  123. {
  124. throw std::runtime_error("Illegal number of channels");
  125. }
  126. channels = numChannels;
  127. pRateTransposer->setChannels(numChannels);
  128. pTDStretch->setChannels(numChannels);
  129. }
  130. // Sets new rate control value. Normal rate = 1.0, smaller values
  131. // represent slower rate, larger faster rates.
  132. void SoundTouch::setRate(float newRate)
  133. {
  134. virtualRate = newRate;
  135. calcEffectiveRateAndTempo();
  136. }
  137. // Sets new rate control value as a difference in percents compared
  138. // to the original rate (-50 .. +100 %)
  139. void SoundTouch::setRateChange(float newRate)
  140. {
  141. virtualRate = 1.0f + 0.01f * newRate;
  142. calcEffectiveRateAndTempo();
  143. }
  144. // Sets new tempo control value. Normal tempo = 1.0, smaller values
  145. // represent slower tempo, larger faster tempo.
  146. void SoundTouch::setTempo(float newTempo)
  147. {
  148. virtualTempo = newTempo;
  149. calcEffectiveRateAndTempo();
  150. }
  151. // Sets new tempo control value as a difference in percents compared
  152. // to the original tempo (-50 .. +100 %)
  153. void SoundTouch::setTempoChange(float newTempo)
  154. {
  155. virtualTempo = 1.0f + 0.01f * newTempo;
  156. calcEffectiveRateAndTempo();
  157. }
  158. // Sets new pitch control value. Original pitch = 1.0, smaller values
  159. // represent lower pitches, larger values higher pitch.
  160. void SoundTouch::setPitch(float newPitch)
  161. {
  162. virtualPitch = newPitch;
  163. calcEffectiveRateAndTempo();
  164. }
  165. // Sets pitch change in octaves compared to the original pitch
  166. // (-1.00 .. +1.00)
  167. void SoundTouch::setPitchOctaves(float newPitch)
  168. {
  169. virtualPitch = (float)exp(0.69314718056f * newPitch);
  170. calcEffectiveRateAndTempo();
  171. }
  172. // Sets pitch change in semi-tones compared to the original pitch
  173. // (-12 .. +12)
  174. void SoundTouch::setPitchSemiTones(int newPitch)
  175. {
  176. setPitchOctaves((float)newPitch / 12.0f);
  177. }
  178. void SoundTouch::setPitchSemiTones(float newPitch)
  179. {
  180. setPitchOctaves(newPitch / 12.0f);
  181. }
  182. // Calculates 'effective' rate and tempo values from the
  183. // nominal control values.
  184. void SoundTouch::calcEffectiveRateAndTempo()
  185. {
  186. float oldTempo = tempo;
  187. float oldRate = rate;
  188. tempo = virtualTempo / virtualPitch;
  189. rate = virtualPitch * virtualRate;
  190. if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate);
  191. if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo);
  192. if (rate > 1.0f)
  193. {
  194. if (output != pRateTransposer)
  195. {
  196. FIFOSamplePipe *transOut;
  197. assert(output == pTDStretch);
  198. // move samples in the current output buffer to the output of pRateTransposer
  199. transOut = pRateTransposer->getOutput();
  200. transOut->moveSamples(*output);
  201. // move samples in tempo changer's input to pitch transposer's input
  202. pRateTransposer->moveSamples(*pTDStretch->getInput());
  203. output = pRateTransposer;
  204. }
  205. }
  206. else
  207. {
  208. if (output != pTDStretch)
  209. {
  210. FIFOSamplePipe *tempoOut;
  211. assert(output == pRateTransposer);
  212. // move samples in the current output buffer to the output of pTDStretch
  213. tempoOut = pTDStretch->getOutput();
  214. tempoOut->moveSamples(*output);
  215. // move samples in pitch transposer's store buffer to tempo changer's input
  216. pTDStretch->moveSamples(*pRateTransposer->getStore());
  217. output = pTDStretch;
  218. }
  219. }
  220. }
  221. // Sets sample rate.
  222. void SoundTouch::setSampleRate(uint srate)
  223. {
  224. bSrateSet = TRUE;
  225. // set sample rate, leave other tempo changer parameters as they are.
  226. pTDStretch->setParameters(srate);
  227. }
  228. // Adds 'numSamples' pcs of samples from the 'samples' memory position into
  229. // the input of the object.
  230. void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples)
  231. {
  232. if (bSrateSet == FALSE)
  233. {
  234. throw std::runtime_error("SoundTouch : Sample rate not defined");
  235. }
  236. else if (channels == 0)
  237. {
  238. throw std::runtime_error("SoundTouch : Number of channels not defined");
  239. }
  240. // Transpose the rate of the new samples if necessary
  241. /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value...
  242. if (rate == 1.0f)
  243. {
  244. // The rate value is same as the original, simply evaluate the tempo changer.
  245. assert(output == pTDStretch);
  246. if (pRateTransposer->isEmpty() == 0)
  247. {
  248. // yet flush the last samples in the pitch transposer buffer
  249. // (may happen if 'rate' changes from a non-zero value to zero)
  250. pTDStretch->moveSamples(*pRateTransposer);
  251. }
  252. pTDStretch->putSamples(samples, nSamples);
  253. }
  254. */
  255. else if (rate <= 1.0f)
  256. {
  257. // transpose the rate down, output the transposed sound to tempo changer buffer
  258. assert(output == pTDStretch);
  259. pRateTransposer->putSamples(samples, nSamples);
  260. pTDStretch->moveSamples(*pRateTransposer);
  261. }
  262. else
  263. {
  264. assert(rate > 1.0f);
  265. // evaluate the tempo changer, then transpose the rate up,
  266. assert(output == pRateTransposer);
  267. pTDStretch->putSamples(samples, nSamples);
  268. pRateTransposer->moveSamples(*pTDStretch);
  269. }
  270. }
  271. // Flushes the last samples from the processing pipeline to the output.
  272. // Clears also the internal processing buffers.
  273. //
  274. // Note: This function is meant for extracting the last samples of a sound
  275. // stream. This function may introduce additional blank samples in the end
  276. // of the sound stream, and thus it's not recommended to call this function
  277. // in the middle of a sound stream.
  278. void SoundTouch::flush()
  279. {
  280. int i;
  281. uint nOut;
  282. SAMPLETYPE buff[128];
  283. nOut = numSamples();
  284. memset(buff, 0, 128 * sizeof(SAMPLETYPE));
  285. // "Push" the last active samples out from the processing pipeline by
  286. // feeding blank samples into the processing pipeline until new,
  287. // processed samples appear in the output (not however, more than
  288. // 8ksamples in any case)
  289. for (i = 0; i < 128; i ++)
  290. {
  291. putSamples(buff, 64);
  292. if (numSamples() != nOut) break; // new samples have appeared in the output!
  293. }
  294. // Clear working buffers
  295. pRateTransposer->clear();
  296. pTDStretch->clearInput();
  297. // yet leave the 'tempoChanger' output intouched as that's where the
  298. // flushed samples are!
  299. }
  300. // Changes a setting controlling the processing system behaviour. See the
  301. // 'SETTING_...' defines for available setting ID's.
  302. BOOL SoundTouch::setSetting(uint settingId, uint value)
  303. {
  304. int sampleRate, sequenceMs, seekWindowMs, overlapMs;
  305. // read current tdstretch routine parameters
  306. pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs);
  307. switch (settingId)
  308. {
  309. case SETTING_USE_AA_FILTER :
  310. // enables / disabless anti-alias filter
  311. pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE);
  312. return TRUE;
  313. case SETTING_AA_FILTER_LENGTH :
  314. // sets anti-alias filter length
  315. pRateTransposer->getAAFilter()->setLength(value);
  316. return TRUE;
  317. case SETTING_USE_QUICKSEEK :
  318. // enables / disables tempo routine quick seeking algorithm
  319. pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE);
  320. return TRUE;
  321. case SETTING_SEQUENCE_MS:
  322. // change time-stretch sequence duration parameter
  323. pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs);
  324. return TRUE;
  325. case SETTING_SEEKWINDOW_MS:
  326. // change time-stretch seek window length parameter
  327. pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs);
  328. return TRUE;
  329. case SETTING_OVERLAP_MS:
  330. // change time-stretch overlap length parameter
  331. pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value);
  332. return TRUE;
  333. default :
  334. return FALSE;
  335. }
  336. }
  337. // Reads a setting controlling the processing system behaviour. See the
  338. // 'SETTING_...' defines for available setting ID's.
  339. //
  340. // Returns the setting value.
  341. int SoundTouch::getSetting(int settingId) const
  342. {
  343. int temp;
  344. switch (settingId)
  345. {
  346. case SETTING_USE_AA_FILTER :
  347. return (uint)pRateTransposer->isAAFilterEnabled();
  348. case SETTING_AA_FILTER_LENGTH :
  349. return pRateTransposer->getAAFilter()->getLength();
  350. case SETTING_USE_QUICKSEEK :
  351. return (uint) pTDStretch->isQuickSeekEnabled();
  352. case SETTING_SEQUENCE_MS:
  353. pTDStretch->getParameters(NULL, &temp, NULL, NULL);
  354. return temp;
  355. case SETTING_SEEKWINDOW_MS:
  356. pTDStretch->getParameters(NULL, NULL, &temp, NULL);
  357. return temp;
  358. case SETTING_OVERLAP_MS:
  359. pTDStretch->getParameters(NULL, NULL, NULL, &temp);
  360. return temp;
  361. default :
  362. return 0;
  363. }
  364. }
  365. // Clears all the samples in the object's output and internal processing
  366. // buffers.
  367. void SoundTouch::clear()
  368. {
  369. pRateTransposer->clear();
  370. pTDStretch->clear();
  371. }
  372. /// Returns number of samples currently unprocessed.
  373. uint SoundTouch::numUnprocessedSamples() const
  374. {
  375. FIFOSamplePipe * psp;
  376. if (pTDStretch)
  377. {
  378. psp = pTDStretch->getInput();
  379. if (psp)
  380. {
  381. return psp->numSamples();
  382. }
  383. }
  384. return 0;
  385. }