SoundTouchDLL.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. //////////////////////////////////////////////////////////////////////////////
  2. ///
  3. /// SoundTouch DLL wrapper - wraps SoundTouch routines into a Dynamic Load
  4. /// Library interface.
  5. ///
  6. /// Author : Copyright (c) Olli Parviainen
  7. /// Author e-mail : oparviai 'at' iki.fi
  8. /// SoundTouch WWW: http://www.surina.net/soundtouch
  9. ///
  10. ////////////////////////////////////////////////////////////////////////////////
  11. //
  12. // License :
  13. //
  14. // SoundTouch audio processing library
  15. // Copyright (c) Olli Parviainen
  16. //
  17. // This library is free software; you can redistribute it and/or
  18. // modify it under the terms of the GNU Lesser General Public
  19. // License as published by the Free Software Foundation; either
  20. // version 2.1 of the License, or (at your option) any later version.
  21. //
  22. // This library is distributed in the hope that it will be useful,
  23. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  25. // Lesser General Public License for more details.
  26. //
  27. // You should have received a copy of the GNU Lesser General Public
  28. // License along with this library; if not, write to the Free Software
  29. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  30. //
  31. ////////////////////////////////////////////////////////////////////////////////
  32. #if defined(_WIN32) || defined(WIN32)
  33. #include <windows.h>
  34. // DLL main in Windows compilation
  35. BOOL APIENTRY DllMain( HANDLE hModule,
  36. DWORD ul_reason_for_call,
  37. LPVOID lpReserved
  38. )
  39. {
  40. switch (ul_reason_for_call)
  41. {
  42. case DLL_PROCESS_ATTACH:
  43. case DLL_THREAD_ATTACH:
  44. case DLL_THREAD_DETACH:
  45. case DLL_PROCESS_DETACH:
  46. break;
  47. }
  48. return TRUE;
  49. }
  50. #endif
  51. #include <limits.h>
  52. #include <string.h>
  53. #include "SoundTouchDLL.h"
  54. #include "SoundTouch.h"
  55. #include "BPMDetect.h"
  56. using namespace soundtouch;
  57. #ifdef SOUNDTOUCH_INTEGER_SAMPLES
  58. #error "error - compile the dll version with float samples"
  59. #endif // SOUNDTOUCH_INTEGER_SAMPLES
  60. //////////////
  61. typedef struct
  62. {
  63. DWORD dwMagic;
  64. SoundTouch *pst;
  65. } STHANDLE;
  66. typedef struct
  67. {
  68. DWORD dwMagic;
  69. BPMDetect *pbpm;
  70. uint numChannels;
  71. } BPMHANDLE;
  72. #define STMAGIC 0x1770C001
  73. #define BPMMAGIC 0x1771C10a
  74. SOUNDTOUCHDLL_API HANDLE __cdecl soundtouch_createInstance()
  75. {
  76. STHANDLE *tmp = new STHANDLE;
  77. if (tmp)
  78. {
  79. tmp->dwMagic = STMAGIC;
  80. tmp->pst = new SoundTouch();
  81. if (tmp->pst == NULL)
  82. {
  83. delete tmp;
  84. tmp = NULL;
  85. }
  86. }
  87. return (HANDLE)tmp;
  88. }
  89. SOUNDTOUCHDLL_API void __cdecl soundtouch_destroyInstance(HANDLE h)
  90. {
  91. STHANDLE *sth = (STHANDLE*)h;
  92. if (sth->dwMagic != STMAGIC) return;
  93. sth->dwMagic = 0;
  94. if (sth->pst) delete sth->pst;
  95. sth->pst = NULL;
  96. delete sth;
  97. }
  98. /// Get SoundTouch library version string
  99. SOUNDTOUCHDLL_API const char *__cdecl soundtouch_getVersionString()
  100. {
  101. return SoundTouch::getVersionString();
  102. }
  103. /// Get SoundTouch library version string - alternative function for
  104. /// environments that can't properly handle character string as return value
  105. SOUNDTOUCHDLL_API void __cdecl soundtouch_getVersionString2(char* versionString, int bufferSize)
  106. {
  107. strncpy(versionString, SoundTouch::getVersionString(), bufferSize - 1);
  108. versionString[bufferSize - 1] = 0;
  109. }
  110. /// Get SoundTouch library version Id
  111. SOUNDTOUCHDLL_API uint __cdecl soundtouch_getVersionId()
  112. {
  113. return SoundTouch::getVersionId();
  114. }
  115. /// Sets new rate control value. Normal rate = 1.0, smaller values
  116. /// represent slower rate, larger faster rates.
  117. SOUNDTOUCHDLL_API void __cdecl soundtouch_setRate(HANDLE h, float newRate)
  118. {
  119. STHANDLE *sth = (STHANDLE*)h;
  120. if (sth->dwMagic != STMAGIC) return;
  121. sth->pst->setRate(newRate);
  122. }
  123. /// Sets new tempo control value. Normal tempo = 1.0, smaller values
  124. /// represent slower tempo, larger faster tempo.
  125. SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempo(HANDLE h, float newTempo)
  126. {
  127. STHANDLE *sth = (STHANDLE*)h;
  128. if (sth->dwMagic != STMAGIC) return;
  129. sth->pst->setTempo(newTempo);
  130. }
  131. /// Sets new rate control value as a difference in percents compared
  132. /// to the original rate (-50 .. +100 %)
  133. SOUNDTOUCHDLL_API void __cdecl soundtouch_setRateChange(HANDLE h, float newRate)
  134. {
  135. STHANDLE *sth = (STHANDLE*)h;
  136. if (sth->dwMagic != STMAGIC) return;
  137. sth->pst->setRateChange(newRate);
  138. }
  139. /// Sets new tempo control value as a difference in percents compared
  140. /// to the original tempo (-50 .. +100 %)
  141. SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempoChange(HANDLE h, float newTempo)
  142. {
  143. STHANDLE *sth = (STHANDLE*)h;
  144. if (sth->dwMagic != STMAGIC) return;
  145. sth->pst->setTempoChange(newTempo);
  146. }
  147. /// Sets new pitch control value. Original pitch = 1.0, smaller values
  148. /// represent lower pitches, larger values higher pitch.
  149. SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitch(HANDLE h, float newPitch)
  150. {
  151. STHANDLE *sth = (STHANDLE*)h;
  152. if (sth->dwMagic != STMAGIC) return;
  153. sth->pst->setPitch(newPitch);
  154. }
  155. /// Sets pitch change in octaves compared to the original pitch
  156. /// (-1.00 .. +1.00)
  157. SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchOctaves(HANDLE h, float newPitch)
  158. {
  159. STHANDLE *sth = (STHANDLE*)h;
  160. if (sth->dwMagic != STMAGIC) return;
  161. sth->pst->setPitchOctaves(newPitch);
  162. }
  163. /// Sets pitch change in semi-tones compared to the original pitch
  164. /// (-12 .. +12)
  165. SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchSemiTones(HANDLE h, float newPitch)
  166. {
  167. STHANDLE *sth = (STHANDLE*)h;
  168. if (sth->dwMagic != STMAGIC) return;
  169. sth->pst->setPitchSemiTones(newPitch);
  170. }
  171. /// Sets the number of channels, 1 = mono, 2 = stereo
  172. SOUNDTOUCHDLL_API void __cdecl soundtouch_setChannels(HANDLE h, uint numChannels)
  173. {
  174. STHANDLE *sth = (STHANDLE*)h;
  175. if (sth->dwMagic != STMAGIC) return;
  176. sth->pst->setChannels(numChannels);
  177. }
  178. /// Sets sample rate.
  179. SOUNDTOUCHDLL_API void __cdecl soundtouch_setSampleRate(HANDLE h, uint srate)
  180. {
  181. STHANDLE *sth = (STHANDLE*)h;
  182. if (sth->dwMagic != STMAGIC) return;
  183. sth->pst->setSampleRate(srate);
  184. }
  185. /// Flushes the last samples from the processing pipeline to the output.
  186. /// Clears also the internal processing buffers.
  187. //
  188. /// Note: This function is meant for extracting the last samples of a sound
  189. /// stream. This function may introduce additional blank samples in the end
  190. /// of the sound stream, and thus it's not recommended to call this function
  191. /// in the middle of a sound stream.
  192. SOUNDTOUCHDLL_API void __cdecl soundtouch_flush(HANDLE h)
  193. {
  194. STHANDLE *sth = (STHANDLE*)h;
  195. if (sth->dwMagic != STMAGIC) return;
  196. sth->pst->flush();
  197. }
  198. /// Adds 'numSamples' pcs of samples from the 'samples' memory position into
  199. /// the input of the object. Notice that sample rate _has_to_ be set before
  200. /// calling this function, otherwise throws a runtime_error exception.
  201. SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples(HANDLE h,
  202. const SAMPLETYPE *samples, ///< Pointer to sample buffer.
  203. unsigned int numSamples ///< Number of samples in buffer. Notice
  204. ///< that in case of stereo-sound a single sample
  205. ///< contains data for both channels.
  206. )
  207. {
  208. STHANDLE *sth = (STHANDLE*)h;
  209. if (sth->dwMagic != STMAGIC) return;
  210. sth->pst->putSamples(samples, numSamples);
  211. }
  212. /// int16 version of soundtouch_putSamples(): This accept int16 (short) sample data
  213. /// and internally converts it to float format before processing
  214. SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples_i16(HANDLE h,
  215. const short *samples, ///< Pointer to sample buffer.
  216. unsigned int numSamples ///< Number of sample frames in buffer. Notice
  217. ///< that in case of multi-channel sound a single sample
  218. ///< contains data for all channels.
  219. )
  220. {
  221. STHANDLE *sth = (STHANDLE*)h;
  222. if (sth->dwMagic != STMAGIC) return;
  223. uint numChannels = sth->pst->numChannels();
  224. // iterate until all samples converted & put to SoundTouch object
  225. while (numSamples > 0)
  226. {
  227. float convert[8192]; // allocate temporary conversion buffer from stack
  228. // how many multichannel samples fit into 'convert' buffer:
  229. uint convSamples = 8192 / numChannels;
  230. // convert max 'nround' values at a time to guarantee that these fit in the 'convert' buffer
  231. uint n = (numSamples > convSamples) ? convSamples : numSamples;
  232. for (uint i = 0; i < n * numChannels; i++)
  233. {
  234. convert[i] = samples[i];
  235. }
  236. // put the converted samples into SoundTouch
  237. sth->pst->putSamples(convert, n);
  238. numSamples -= n;
  239. samples += n * numChannels;
  240. }
  241. }
  242. /// Clears all the samples in the object's output and internal processing
  243. /// buffers.
  244. SOUNDTOUCHDLL_API void __cdecl soundtouch_clear(HANDLE h)
  245. {
  246. STHANDLE *sth = (STHANDLE*)h;
  247. if (sth->dwMagic != STMAGIC) return;
  248. sth->pst->clear();
  249. }
  250. /// Changes a setting controlling the processing system behaviour. See the
  251. /// 'SETTING_...' defines for available setting ID's.
  252. ///
  253. /// \return 'nonzero' if the setting was successfully changed
  254. SOUNDTOUCHDLL_API int __cdecl soundtouch_setSetting(HANDLE h,
  255. int settingId, ///< Setting ID number. see SETTING_... defines.
  256. int value ///< New setting value.
  257. )
  258. {
  259. STHANDLE *sth = (STHANDLE*)h;
  260. if (sth->dwMagic != STMAGIC) return FALSE;
  261. return sth->pst->setSetting(settingId, value);
  262. }
  263. /// Reads a setting controlling the processing system behaviour. See the
  264. /// 'SETTING_...' defines for available setting ID's.
  265. ///
  266. /// \return the setting value.
  267. SOUNDTOUCHDLL_API int __cdecl soundtouch_getSetting(HANDLE h,
  268. int settingId ///< Setting ID number, see SETTING_... defines.
  269. )
  270. {
  271. STHANDLE *sth = (STHANDLE*)h;
  272. if (sth->dwMagic != STMAGIC) return -1;
  273. return sth->pst->getSetting(settingId);
  274. }
  275. /// Returns number of samples currently unprocessed.
  276. SOUNDTOUCHDLL_API uint __cdecl soundtouch_numUnprocessedSamples(HANDLE h)
  277. {
  278. STHANDLE *sth = (STHANDLE*)h;
  279. if (sth->dwMagic != STMAGIC) return 0;
  280. return sth->pst->numUnprocessedSamples();
  281. }
  282. /// Adjusts book-keeping so that given number of samples are removed from beginning of the
  283. /// sample buffer without copying them anywhere.
  284. ///
  285. /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
  286. /// with 'ptrBegin' function.
  287. SOUNDTOUCHDLL_API uint __cdecl soundtouch_receiveSamples(HANDLE h,
  288. SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples.
  289. unsigned int maxSamples ///< How many samples to receive at max.
  290. )
  291. {
  292. STHANDLE *sth = (STHANDLE*)h;
  293. if (sth->dwMagic != STMAGIC) return 0;
  294. if (outBuffer)
  295. {
  296. return sth->pst->receiveSamples(outBuffer, maxSamples);
  297. }
  298. else
  299. {
  300. return sth->pst->receiveSamples(maxSamples);
  301. }
  302. }
  303. /// int16 version of soundtouch_receiveSamples(): This converts internal float samples
  304. /// into int16 (short) return data type
  305. SOUNDTOUCHDLL_API uint __cdecl soundtouch_receiveSamples_i16(HANDLE h,
  306. short *outBuffer, ///< Buffer where to copy output samples.
  307. unsigned int maxSamples ///< How many samples to receive at max.
  308. )
  309. {
  310. STHANDLE *sth = (STHANDLE*)h;
  311. if (sth->dwMagic != STMAGIC) return 0;
  312. uint outTotal = 0;
  313. if (outBuffer == NULL)
  314. {
  315. // only reduce sample count, not receive samples
  316. return sth->pst->receiveSamples(maxSamples);
  317. }
  318. uint numChannels = sth->pst->numChannels();
  319. // iterate until all samples converted & put to SoundTouch object
  320. while (maxSamples > 0)
  321. {
  322. float convert[8192]; // allocate temporary conversion buffer from stack
  323. // how many multichannel samples fit into 'convert' buffer:
  324. uint convSamples = 8192 / numChannels;
  325. // request max 'nround' values at a time to guarantee that these fit in the 'convert' buffer
  326. uint n = (maxSamples > convSamples) ? convSamples : maxSamples;
  327. uint out = sth->pst->receiveSamples(convert, n);
  328. // convert & saturate received samples to int16
  329. for (uint i = 0; i < out * numChannels; i++)
  330. {
  331. // first convert value to int32, then saturate to int16 min/max limits
  332. int value = (int)convert[i];
  333. value = (value < SHRT_MIN) ? SHRT_MIN : (value > SHRT_MAX) ? SHRT_MAX : value;
  334. outBuffer[i] = (short)value;
  335. }
  336. outTotal += out;
  337. if (out < n) break; // didn't get as many as asked => no more samples available => break here
  338. maxSamples -= n;
  339. outBuffer += out * numChannels;
  340. }
  341. // return number of processed samples
  342. return outTotal;
  343. }
  344. /// Returns number of samples currently available.
  345. SOUNDTOUCHDLL_API uint __cdecl soundtouch_numSamples(HANDLE h)
  346. {
  347. STHANDLE *sth = (STHANDLE*)h;
  348. if (sth->dwMagic != STMAGIC) return 0;
  349. return sth->pst->numSamples();
  350. }
  351. /// Returns nonzero if there aren't any samples available for outputting.
  352. SOUNDTOUCHDLL_API int __cdecl soundtouch_isEmpty(HANDLE h)
  353. {
  354. STHANDLE *sth = (STHANDLE*)h;
  355. if (sth->dwMagic != STMAGIC) return -1;
  356. return sth->pst->isEmpty();
  357. }
  358. SOUNDTOUCHDLL_API HANDLE __cdecl bpm_createInstance(int numChannels, int sampleRate)
  359. {
  360. BPMHANDLE *tmp = new BPMHANDLE;
  361. if (tmp)
  362. {
  363. tmp->dwMagic = BPMMAGIC;
  364. tmp->pbpm = new BPMDetect(numChannels, sampleRate);
  365. if (tmp->pbpm == NULL)
  366. {
  367. delete tmp;
  368. tmp = NULL;
  369. }
  370. }
  371. return (HANDLE)tmp;
  372. }
  373. SOUNDTOUCHDLL_API void __cdecl bpm_destroyInstance(HANDLE h)
  374. {
  375. BPMHANDLE *sth = (BPMHANDLE*)h;
  376. if (sth->dwMagic != BPMMAGIC) return;
  377. sth->dwMagic = 0;
  378. if (sth->pbpm) delete sth->pbpm;
  379. sth->pbpm = NULL;
  380. delete sth;
  381. }
  382. /// Feed 'numSamples' sample frames from 'samples' into the BPM detection handler
  383. SOUNDTOUCHDLL_API void __cdecl bpm_putSamples(HANDLE h,
  384. const float *samples,
  385. unsigned int numSamples)
  386. {
  387. BPMHANDLE *bpmh = (BPMHANDLE*)h;
  388. if (bpmh->dwMagic != BPMMAGIC) return;
  389. bpmh->pbpm->inputSamples(samples, numSamples);
  390. }
  391. /// Feed 'numSamples' sample frames from 'samples' into the BPM detection handler.
  392. /// 16bit int sample format version.
  393. SOUNDTOUCHDLL_API void __cdecl bpm_putSamples_i16(HANDLE h,
  394. const short *samples,
  395. unsigned int numSamples)
  396. {
  397. BPMHANDLE *bpmh = (BPMHANDLE*)h;
  398. if (bpmh->dwMagic != BPMMAGIC) return;
  399. uint numChannels = bpmh->numChannels;
  400. // iterate until all samples converted & put to SoundTouch object
  401. while (numSamples > 0)
  402. {
  403. float convert[8192]; // allocate temporary conversion buffer from stack
  404. // how many multichannel samples fit into 'convert' buffer:
  405. uint convSamples = 8192 / numChannels;
  406. // convert max 'nround' values at a time to guarantee that these fit in the 'convert' buffer
  407. uint n = (numSamples > convSamples) ? convSamples : numSamples;
  408. for (uint i = 0; i < n * numChannels; i++)
  409. {
  410. convert[i] = samples[i];
  411. }
  412. // put the converted samples into SoundTouch
  413. bpmh->pbpm->inputSamples(convert, n);
  414. numSamples -= n;
  415. samples += n * numChannels;
  416. }
  417. }
  418. /// Analyzes the results and returns the BPM rate. Use this function to read result
  419. /// after whole song data has been input to the class by consecutive calls of
  420. /// 'inputSamples' function.
  421. ///
  422. /// \return Beats-per-minute rate, or zero if detection failed.
  423. SOUNDTOUCHDLL_API float __cdecl bpm_getBpm(HANDLE h)
  424. {
  425. BPMHANDLE *bpmh = (BPMHANDLE*)h;
  426. if (bpmh->dwMagic != BPMMAGIC) return 0;
  427. return bpmh->pbpm->getBpm();
  428. }