You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

802 lines
21KB

  1. /*
  2. Copyright (C) 2017 Xenakios
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of version 3 of the GNU General Public License
  5. as published by the Free Software Foundation.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License (version 3) for more details.
  10. www.gnu.org/licenses
  11. */
  12. #include "StretchSource.h"
  13. #include <set>
  14. #ifdef WIN32
  15. #include <ppl.h>
  16. //#define USE_PPL_TO_PROCESS_STRETCHERS
  17. #undef min
  18. #undef max
  19. #endif
  20. std::vector<SpectrumProcessType> g_specorderpresets[3] = {
  21. {SPT_Harmonics,SPT_PitchShift,SPT_FreqShift,SPT_Spread,SPT_TonalVsNoise,SPT_Filter,SPT_FreeFilter,SPT_RatioMix,SPT_Compressor},
  22. {SPT_PitchShift,SPT_Harmonics,SPT_FreqShift,SPT_Spread,SPT_TonalVsNoise,SPT_Filter,SPT_FreeFilter,SPT_RatioMix,SPT_Compressor},
  23. {SPT_RatioMix,SPT_PitchShift,SPT_Harmonics,SPT_FreqShift,SPT_Spread,SPT_TonalVsNoise,SPT_Filter,SPT_FreeFilter,SPT_Compressor}
  24. };
  25. StretchAudioSource::StretchAudioSource(int initialnumoutchans,
  26. AudioFormatManager* afm,
  27. std::array<AudioParameterBool*,9>& enab_pars) : m_afm(afm)
  28. {
  29. m_resampler = std::make_unique<WDL_Resampler>(4*65536);
  30. m_resampler_outbuf.resize(1024*1024);
  31. m_inputfile = std::make_unique<AInputS>(m_afm);
  32. for (int i = 0; i < enab_pars.size(); ++i)
  33. {
  34. m_specproc_order.emplace_back((SpectrumProcessType)i, enab_pars[i]);
  35. }
  36. //m_specproc_order = { {0,false} , { 1, false} ,{2,true},{3,true},{4,true},{5,false},{6,true},{7,true},{8,false} };
  37. setNumOutChannels(initialnumoutchans);
  38. m_xfadetask.buffer.setSize(8, 65536);
  39. m_xfadetask.buffer.clear();
  40. }
  41. StretchAudioSource::~StretchAudioSource()
  42. {
  43. }
  44. void StretchAudioSource::prepareToPlay(int samplesPerBlockExpected, double sampleRate)
  45. {
  46. m_outsr = sampleRate;
  47. m_vol_smoother.reset(sampleRate, 0.5);
  48. m_lastplayrate = -1.0;
  49. m_stop_play_requested = false;
  50. m_output_counter = 0;
  51. m_output_silence_counter = 0;
  52. m_stream_end_reached = false;
  53. m_firstbuffer = true;
  54. m_output_has_begun = false;
  55. m_drypreviewbuf.setSize(m_num_outchans, 65536);
  56. initObjects();
  57. }
  58. void StretchAudioSource::releaseResources()
  59. {
  60. }
  61. AudioBuffer<float>* StretchAudioSource::getSourceAudioBuffer()
  62. {
  63. if (m_inputfile==nullptr)
  64. return nullptr;
  65. return m_inputfile->getAudioBuffer();
  66. }
  67. bool StretchAudioSource::isResampling()
  68. {
  69. if (m_inputfile==nullptr || m_inputfile->info.samplerate==0)
  70. return false;
  71. return (int)m_outsr!=m_inputfile->info.samplerate;
  72. }
  73. int64_t StretchAudioSource::getDiskReadSampleCount() const
  74. {
  75. if (m_inputfile == nullptr)
  76. return 0;
  77. return m_inputfile->getDiskReadSampleCount();
  78. }
  79. std::vector<SpectrumProcess> StretchAudioSource::getSpectrumProcessOrder()
  80. {
  81. return m_specproc_order;
  82. }
  83. void StretchAudioSource::setSpectrumProcessOrder(std::vector<SpectrumProcess> order)
  84. {
  85. ScopedLock locker(m_cs);
  86. m_specproc_order = order;
  87. /*
  88. Logger::writeToLog("<**");
  89. for (auto& e : m_specproc_order)
  90. Logger::writeToLog(e.m_enabled->name + " " + String(e.m_index));
  91. Logger::writeToLog("**>");
  92. */
  93. for (int i = 0; i < m_stretchers.size(); ++i)
  94. {
  95. m_stretchers[i]->m_spectrum_processes = order;
  96. }
  97. }
  98. std::pair<Range<double>, Range<double>> StretchAudioSource::getFileCachedRangesNormalized()
  99. {
  100. if (m_inputfile == nullptr)
  101. return {};
  102. return m_inputfile->getCachedRangesNormalized();
  103. }
  104. void StretchAudioSource::setFreeFilterEnvelope(shared_envelope env)
  105. {
  106. ScopedLock locker(m_cs);
  107. m_free_filter_envelope = env;
  108. for (int i = 0; i < m_stretchers.size(); ++i)
  109. {
  110. m_stretchers[i]->setFreeFilterEnvelope(env);
  111. }
  112. }
  113. bool StretchAudioSource::isLoopingEnabled()
  114. {
  115. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  116. return false;
  117. return m_inputfile->isLooping();
  118. }
  119. void StretchAudioSource::setLoopingEnabled(bool b)
  120. {
  121. ScopedLock locker(m_cs);
  122. if (m_inputfile != nullptr)
  123. {
  124. if (m_inputfile->isLooping() == false && b == true)
  125. seekPercent(m_inputfile->getActiveRange().getStart());
  126. m_inputfile->setLoopEnabled(b);
  127. }
  128. }
  129. void StretchAudioSource::setAudioBufferAsInputSource(AudioBuffer<float>* buf, int sr, int len)
  130. {
  131. ScopedLock locker(m_cs);
  132. m_inputfile->setAudioBuffer(buf, sr, len);
  133. m_seekpos = 0.0;
  134. m_curfile = File();
  135. if (m_playrange.isEmpty())
  136. setPlayRange({ 0.0,1.0 });
  137. ++m_param_change_count;
  138. }
  139. void StretchAudioSource::setMainVolume(double decibels)
  140. {
  141. if (decibels == m_main_volume)
  142. return;
  143. if (m_cs.tryEnter())
  144. {
  145. m_main_volume = jlimit(-144.0, 12.0, decibels);
  146. ++m_param_change_count;
  147. m_cs.exit();
  148. }
  149. }
  150. #ifdef OLDMODULE_ENAB
  151. void StretchAudioSource::setSpectralModulesEnabled(const std::array<AudioParameterBool*, 9>& params)
  152. {
  153. jassert(m_specprocmap.size() > 0);
  154. /*
  155. bool changed = false;
  156. for (int i = 0; i < m_specproc_order.size(); ++i)
  157. {
  158. int index = m_specprocmap[i];
  159. if (*params[index] != *m_specproc_order[i].m_enabled)
  160. {
  161. changed = true;
  162. break;
  163. }
  164. }
  165. if (changed == false)
  166. return;
  167. */
  168. if (m_cs.tryEnter())
  169. {
  170. for (int i = 0; i < m_specproc_order.size(); ++i)
  171. {
  172. int index = m_specprocmap[i];
  173. *m_specproc_order[i].m_enabled = (bool)(*params[index]);
  174. }
  175. for (int i = 0; i < m_stretchers.size(); ++i)
  176. {
  177. m_stretchers[i]->m_spectrum_processes = m_specproc_order;
  178. }
  179. ++m_param_change_count;
  180. m_cs.exit();
  181. }
  182. }
  183. #endif
  184. void StretchAudioSource::setSpectralModuleEnabled(int index, bool b)
  185. {
  186. ++m_param_change_count;
  187. }
  188. void StretchAudioSource::setLoopXFadeLength(double lenseconds)
  189. {
  190. if (lenseconds == m_loopxfadelen)
  191. return;
  192. if (m_cs.tryEnter())
  193. {
  194. m_loopxfadelen = jlimit(0.0, 1.0, lenseconds);
  195. ++m_param_change_count;
  196. m_cs.exit();
  197. }
  198. }
  199. void StretchAudioSource::setPreviewDry(bool b)
  200. {
  201. if (b == m_preview_dry)
  202. return;
  203. if (m_cs.tryEnter())
  204. {
  205. m_resampler->Reset();
  206. if (m_preview_dry == true && b == false && m_inputfile->info.nsamples>0)
  207. m_resampler->SetRates(m_inputfile->info.samplerate, m_outsr);
  208. m_preview_dry = b;
  209. ++m_param_change_count;
  210. m_cs.exit();
  211. }
  212. }
  213. bool StretchAudioSource::isPreviewingDry() const
  214. {
  215. return m_preview_dry;
  216. }
  217. void StretchAudioSource::setDryPlayrate(double rate)
  218. {
  219. if (rate == m_dryplayrate)
  220. return;
  221. if (m_cs.tryEnter())
  222. {
  223. m_dryplayrate = rate;
  224. ++m_param_change_count;
  225. m_cs.exit();
  226. }
  227. }
  228. double StretchAudioSource::getDryPlayrate() const
  229. {
  230. return m_dryplayrate;
  231. }
  232. void StretchAudioSource::setSpectralOrderPreset(int id)
  233. {
  234. if (id == m_current_spec_order_preset)
  235. return;
  236. if (m_cs.tryEnter())
  237. {
  238. m_current_spec_order_preset = id;
  239. ++m_param_change_count;
  240. m_cs.exit();
  241. }
  242. }
  243. void StretchAudioSource::getNextAudioBlock(const AudioSourceChannelInfo & bufferToFill)
  244. {
  245. ScopedLock locker(m_cs);
  246. if (m_preview_dry == true && m_inputfile!=nullptr && m_inputfile->info.nsamples>0)
  247. {
  248. playDrySound(bufferToFill);
  249. return;
  250. }
  251. double maingain = Decibels::decibelsToGain(m_main_volume);
  252. if (m_pause_state == 2)
  253. {
  254. bufferToFill.buffer->clear(bufferToFill.startSample,bufferToFill.numSamples);
  255. return;
  256. }
  257. if (m_stretchoutringbuf.available() > 0)
  258. m_output_has_begun = true;
  259. bool freezing = m_freezing;
  260. if (m_stretchers[0]->isFreezing() != freezing)
  261. {
  262. if (freezing == true && m_inputfile!=nullptr)
  263. m_freeze_pos = 1.0/m_inputfile->info.nsamples*m_inputfile->getCurrentPosition();
  264. for (auto& e : m_stretchers)
  265. {
  266. e->set_freezing(freezing);
  267. }
  268. }
  269. if (m_vol_smoother.getTargetValue() != maingain)
  270. m_vol_smoother.setValue(maingain);
  271. FloatVectorOperations::disableDenormalisedNumberSupport();
  272. float** outarrays = bufferToFill.buffer->getArrayOfWritePointers();
  273. int outbufchans = m_num_outchans; // bufferToFill.buffer->getNumChannels();
  274. int offset = bufferToFill.startSample;
  275. if (m_stretchers.size() == 0)
  276. return;
  277. if (m_inputfile == nullptr)
  278. return;
  279. if (m_inputfile->info.nsamples == 0)
  280. return;
  281. m_inputfile->setXFadeLenSeconds(m_loopxfadelen);
  282. double silencethreshold = Decibels::decibelsToGain(-70.0);
  283. auto ringbuffilltask = [this](int framestoproduce)
  284. {
  285. while (m_stretchoutringbuf.available() < framestoproduce*m_num_outchans)
  286. {
  287. int readsize = 0;
  288. double in_pos = (double)m_inputfile->getCurrentPosition() / (double)m_inputfile->info.nsamples;
  289. if (m_firstbuffer)
  290. {
  291. readsize = m_stretchers[0]->get_nsamples_for_fill();
  292. m_firstbuffer = false;
  293. }
  294. else
  295. {
  296. readsize = m_stretchers[0]->get_nsamples(in_pos*100.0);
  297. };
  298. int readed = 0;
  299. if (readsize != 0)
  300. {
  301. m_last_filepos = m_inputfile->getCurrentPosition();
  302. readed = m_inputfile->readNextBlock(m_file_inbuf, readsize, m_num_outchans);
  303. }
  304. if (m_rand_count % (int)m_free_filter_envelope->m_transform_y_random_rate == 0)
  305. {
  306. m_free_filter_envelope->updateRandomState();
  307. }
  308. ++m_rand_count;
  309. auto inbufptrs = m_file_inbuf.getArrayOfWritePointers();
  310. REALTYPE onset_max = std::numeric_limits<REALTYPE>::min();
  311. #ifdef USE_PPL_TO_PROCESS_STRETCHERS
  312. std::array<REALTYPE, 16> onset_values_arr;
  313. Concurrency::parallel_for(0, (int)m_stretchers.size(), [this, readed, &onset_values_arr](int i)
  314. {
  315. REALTYPE onset_val = m_stretchers[i]->process(m_inbufs[i].data(), readed);
  316. onset_values_arr[i] = onset_val;
  317. });
  318. for (int i = 0; i < m_stretchers.size(); ++i)
  319. onset_max = std::max(onset_max, onset_values_arr[i]);
  320. #else
  321. for (int i = 0; i < m_stretchers.size(); ++i)
  322. {
  323. REALTYPE onset_l = m_stretchers[i]->process(inbufptrs[i], readed);
  324. onset_max = std::max(onset_max, onset_l);
  325. }
  326. #endif
  327. for (int i = 0; i < m_stretchers.size(); ++i)
  328. m_stretchers[i]->here_is_onset(onset_max);
  329. int outbufsize = m_stretchers[0]->get_bufsize();
  330. int nskip = m_stretchers[0]->get_skip_nsamples();
  331. if (nskip > 0)
  332. m_inputfile->skip(nskip);
  333. for (int i = 0; i < outbufsize; i++)
  334. {
  335. for (int ch = 0; ch < m_num_outchans; ++ch)
  336. {
  337. REALTYPE outsa = m_stretchers[ch]->out_buf[i];
  338. m_stretchoutringbuf.push(outsa);
  339. }
  340. }
  341. }
  342. };
  343. int previousxfadestate = m_xfadetask.state;
  344. auto resamplertask = [this, &ringbuffilltask, &bufferToFill]()
  345. {
  346. double* rsinbuf = nullptr;
  347. int outsamplestoproduce = bufferToFill.numSamples;
  348. if (m_xfadetask.state == 1)
  349. outsamplestoproduce = m_xfadetask.xfade_len;
  350. int wanted = m_resampler->ResamplePrepare(outsamplestoproduce, m_num_outchans, &rsinbuf);
  351. ringbuffilltask(wanted);
  352. for (int i = 0; i < wanted*m_num_outchans; ++i)
  353. {
  354. double sample = m_stretchoutringbuf.get();
  355. rsinbuf[i] = sample;
  356. }
  357. if (outsamplestoproduce*m_num_outchans > m_resampler_outbuf.size())
  358. {
  359. m_resampler_outbuf.resize(outsamplestoproduce*m_num_outchans);
  360. }
  361. /*int produced =*/ m_resampler->ResampleOut(m_resampler_outbuf.data(), wanted, outsamplestoproduce, m_num_outchans);
  362. if (m_xfadetask.state == 1)
  363. {
  364. //Logger::writeToLog("Filling xfade buffer");
  365. for (int i = 0; i < outsamplestoproduce; ++i)
  366. {
  367. for (int j = 0; j < m_num_outchans; ++j)
  368. {
  369. m_xfadetask.buffer.setSample(j, i, m_resampler_outbuf[i*m_num_outchans + j]);
  370. }
  371. }
  372. if (m_process_fftsize != m_xfadetask.requested_fft_size)
  373. {
  374. m_process_fftsize = m_xfadetask.requested_fft_size;
  375. //Logger::writeToLog("Initing stretcher objects");
  376. initObjects();
  377. }
  378. m_xfadetask.state = 2;
  379. }
  380. };
  381. resamplertask();
  382. if (previousxfadestate == 1 && m_xfadetask.state == 2)
  383. {
  384. //Logger::writeToLog("Rerunning resampler task");
  385. resamplertask();
  386. }
  387. bool source_ended = m_inputfile->hasEnded();
  388. double samplelimit = 16384.0;
  389. if (m_clip_output == true)
  390. samplelimit = 1.0;
  391. for (int i = 0; i < bufferToFill.numSamples; ++i)
  392. {
  393. double smoothed_gain = m_vol_smoother.getNextValue();
  394. double mixed = 0.0;
  395. for (int j = 0; j < outbufchans; ++j)
  396. {
  397. double outsample = m_resampler_outbuf[i*m_num_outchans + j];
  398. if (m_xfadetask.state == 2)
  399. {
  400. double xfadegain = 1.0 / m_xfadetask.xfade_len*m_xfadetask.counter;
  401. jassert(xfadegain >= 0.0 && xfadegain <= 1.0);
  402. double outsample2 = m_xfadetask.buffer.getSample(j, m_xfadetask.counter);
  403. outsample = xfadegain * outsample + (1.0 - xfadegain)*outsample2;
  404. }
  405. outarrays[j][i + offset] = jlimit(-samplelimit,samplelimit , outsample * smoothed_gain);
  406. mixed += outsample;
  407. }
  408. if (m_xfadetask.state == 2)
  409. {
  410. ++m_xfadetask.counter;
  411. if (m_xfadetask.counter >= m_xfadetask.xfade_len)
  412. m_xfadetask.state = 0;
  413. }
  414. if (source_ended && m_output_counter>=2*m_process_fftsize)
  415. {
  416. if (fabs(mixed) < silencethreshold)
  417. ++m_output_silence_counter;
  418. else
  419. m_output_silence_counter = 0;
  420. }
  421. }
  422. if (m_pause_state == 1)
  423. {
  424. bufferToFill.buffer->applyGainRamp(bufferToFill.startSample, bufferToFill.numSamples, 1.0f, 0.0f);
  425. m_pause_state = 2;
  426. }
  427. if (m_pause_state == 3)
  428. {
  429. bufferToFill.buffer->applyGainRamp(bufferToFill.startSample, bufferToFill.numSamples, 0.0f, 1.0f);
  430. m_pause_state = 0;
  431. }
  432. m_output_counter += bufferToFill.numSamples;
  433. }
  434. void StretchAudioSource::setNextReadPosition(int64 /*newPosition*/)
  435. {
  436. }
  437. int64 StretchAudioSource::getNextReadPosition() const
  438. {
  439. return int64();
  440. }
  441. int64 StretchAudioSource::getTotalLength() const
  442. {
  443. if (m_inputfile == nullptr)
  444. return 0;
  445. return m_inputfile->info.nsamples;
  446. }
  447. bool StretchAudioSource::isLooping() const
  448. {
  449. return false;
  450. }
  451. String StretchAudioSource::setAudioFile(File file)
  452. {
  453. ScopedLock locker(m_cs);
  454. if (m_inputfile->openAudioFile(file))
  455. {
  456. m_curfile = file;
  457. m_firstbuffer = true;
  458. return String();
  459. }
  460. return "Could not open file";
  461. }
  462. File StretchAudioSource::getAudioFile()
  463. {
  464. return m_curfile;
  465. }
  466. void StretchAudioSource::setNumOutChannels(int chans)
  467. {
  468. jassert(chans > 0 && chans < g_maxnumoutchans);
  469. m_num_outchans = chans;
  470. }
  471. void StretchAudioSource::initObjects()
  472. {
  473. ScopedLock locker(m_cs);
  474. m_inputfile->setActiveRange(m_playrange);
  475. if (m_inputfile->getActiveRange().contains(m_inputfile->getCurrentPositionPercent())==false)
  476. m_inputfile->seek(m_playrange.getStart(), true);
  477. m_firstbuffer = true;
  478. if (m_stretchoutringbuf.getSize() < m_num_outchans*m_process_fftsize)
  479. {
  480. int newsize = m_num_outchans*m_process_fftsize*2;
  481. //Logger::writeToLog("Resizing circular buffer to " + String(newsize));
  482. m_stretchoutringbuf.resize(newsize);
  483. }
  484. m_stretchoutringbuf.clear();
  485. m_resampler->Reset();
  486. m_resampler->SetRates(m_inputfile->info.samplerate, m_outsr);
  487. REALTYPE stretchratio = m_playrate;
  488. FFTWindow windowtype = W_HAMMING;
  489. if (m_fft_window_type>=0)
  490. windowtype = (FFTWindow)m_fft_window_type;
  491. int inbufsize = m_process_fftsize;
  492. double onsetsens = m_onsetdetection;
  493. m_stretchers.resize(m_num_outchans);
  494. for (int i = 0; i < m_stretchers.size(); ++i)
  495. {
  496. if (m_stretchers[i] == nullptr)
  497. {
  498. //Logger::writeToLog("Creating stretch instance " + String(i));
  499. m_stretchers[i] = std::make_shared<ProcessedStretch>(stretchratio,
  500. m_process_fftsize, windowtype, false, (float)m_inputfile->info.samplerate, i + 1);
  501. }
  502. m_stretchers[i]->setBufferSize(m_process_fftsize);
  503. m_stretchers[i]->setSampleRate(m_inputfile->info.samplerate);
  504. m_stretchers[i]->set_onset_detection_sensitivity(onsetsens);
  505. m_stretchers[i]->set_parameters(&m_ppar);
  506. m_stretchers[i]->set_freezing(m_freezing);
  507. m_stretchers[i]->setFreeFilterEnvelope(m_free_filter_envelope);
  508. fill_container(m_stretchers[i]->out_buf, 0.0f);
  509. m_stretchers[i]->m_spectrum_processes = m_specproc_order;
  510. }
  511. m_file_inbuf.setSize(m_num_outchans, 3 * inbufsize);
  512. }
  513. void StretchAudioSource::playDrySound(const AudioSourceChannelInfo & bufferToFill)
  514. {
  515. auto bufs = bufferToFill.buffer->getArrayOfWritePointers();
  516. double maingain = Decibels::decibelsToGain(m_main_volume);
  517. m_inputfile->setXFadeLenSeconds(m_loopxfadelen);
  518. double* rsinbuf = nullptr;
  519. m_resampler->SetRates(m_inputfile->info.samplerate*m_dryplayrate, m_outsr);
  520. int wanted = m_resampler->ResamplePrepare(bufferToFill.numSamples, m_num_outchans, &rsinbuf);
  521. m_inputfile->readNextBlock(m_drypreviewbuf, wanted, m_num_outchans);
  522. for (int i = 0; i < wanted; ++i)
  523. for (int j = 0; j < m_num_outchans; ++j)
  524. rsinbuf[i*m_num_outchans + j] = m_drypreviewbuf.getSample(j, i);
  525. m_resampler->ResampleOut(m_resampler_outbuf.data(), wanted, bufferToFill.numSamples, m_num_outchans);
  526. for (int i = 0; i < m_num_outchans; ++i)
  527. for (int j = 0; j < bufferToFill.numSamples; ++j)
  528. bufs[i][j + bufferToFill.startSample] = maingain * m_resampler_outbuf[j*m_num_outchans + i];
  529. }
  530. double StretchAudioSource::getInfilePositionPercent()
  531. {
  532. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  533. return 0.0;
  534. return 1.0/m_inputfile->info.nsamples*m_inputfile->getCurrentPosition();
  535. }
  536. double StretchAudioSource::getInfilePositionSeconds()
  537. {
  538. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  539. return 0.0;
  540. //return m_lastinpos*m_inputfile->getLengthSeconds();
  541. return (double)m_inputfile->getCurrentPosition() / m_inputfile->info.samplerate;
  542. }
  543. double StretchAudioSource::getInfileLengthSeconds()
  544. {
  545. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  546. return 0.0;
  547. return (double)m_inputfile->info.nsamples / m_inputfile->info.samplerate;
  548. }
  549. double StretchAudioSource::getInfileSamplerate()
  550. {
  551. if (m_inputfile == nullptr)
  552. return 0.0;
  553. return m_inputfile->info.samplerate;
  554. }
  555. void StretchAudioSource::setRate(double rate)
  556. {
  557. if (rate == m_playrate)
  558. return;
  559. if (m_cs.tryEnter())
  560. {
  561. m_playrate = rate;
  562. for (int i = 0; i < m_stretchers.size(); ++i)
  563. {
  564. m_stretchers[i]->set_rap((float)rate);
  565. }
  566. ++m_param_change_count;
  567. m_cs.exit();
  568. }
  569. }
  570. void StretchAudioSource::setProcessParameters(ProcessParameters * pars)
  571. {
  572. if (*pars == m_ppar)
  573. return;
  574. if (m_cs.tryEnter())
  575. {
  576. m_ppar = *pars;
  577. for (int i = 0; i < m_stretchers.size(); ++i)
  578. {
  579. m_stretchers[i]->set_parameters(pars);
  580. }
  581. ++m_param_change_count;
  582. m_cs.exit();
  583. }
  584. }
  585. const ProcessParameters& StretchAudioSource::getProcessParameters()
  586. {
  587. return m_ppar;
  588. }
  589. void StretchAudioSource::setFFTWindowingType(int windowtype)
  590. {
  591. if (windowtype==m_fft_window_type)
  592. return;
  593. if (m_cs.tryEnter())
  594. {
  595. m_fft_window_type = windowtype;
  596. for (int i = 0; i < m_stretchers.size(); ++i)
  597. {
  598. m_stretchers[i]->window_type = (FFTWindow)windowtype;
  599. }
  600. ++m_param_change_count;
  601. m_cs.exit();
  602. }
  603. }
  604. void StretchAudioSource::setFFTSize(int size)
  605. {
  606. jassert(size>0);
  607. if (m_xfadetask.state == 0 && (m_process_fftsize == 0 || size != m_process_fftsize))
  608. {
  609. ScopedLock locker(m_cs);
  610. if (m_xfadetask.buffer.getNumChannels() < m_num_outchans)
  611. {
  612. m_xfadetask.buffer.setSize(m_num_outchans, m_xfadetask.buffer.getNumSamples());
  613. }
  614. if (m_process_fftsize > 0)
  615. {
  616. m_xfadetask.state = 1;
  617. m_xfadetask.counter = 0;
  618. m_xfadetask.xfade_len = 16384;
  619. m_xfadetask.requested_fft_size = size;
  620. }
  621. else
  622. {
  623. m_process_fftsize = size;
  624. initObjects();
  625. }
  626. ++m_param_change_count;
  627. }
  628. }
  629. void StretchAudioSource::setPaused(bool b)
  630. {
  631. if (b == true && m_pause_state>0)
  632. return;
  633. if (b == false && m_pause_state == 0)
  634. return;
  635. ScopedLock locker(m_cs);
  636. if (b == true && m_pause_state == 0)
  637. {
  638. m_pause_state = 1;
  639. return;
  640. }
  641. if (b == false && m_pause_state == 2)
  642. {
  643. m_pause_state = 3;
  644. return;
  645. }
  646. }
  647. bool StretchAudioSource::isPaused() const
  648. {
  649. return m_pause_state > 0;
  650. }
  651. void StretchAudioSource::seekPercent(double pos)
  652. {
  653. ScopedLock locker(m_cs);
  654. m_seekpos = pos;
  655. //m_firstbuffer = true;
  656. //m_resampler->Reset();
  657. m_inputfile->seek(pos, true);
  658. ++m_param_change_count;
  659. }
  660. double StretchAudioSource::getOutputDurationSecondsForRange(Range<double> range, int fftsize)
  661. {
  662. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  663. return 0.0;
  664. if (m_preview_dry==true)
  665. return (double)range.getLength()*m_inputfile->info.nsamples/m_inputfile->info.samplerate;
  666. int64_t play_end_pos = (fftsize * 2)+range.getLength()*m_playrate*m_inputfile->info.nsamples;
  667. return (double)play_end_pos / m_inputfile->info.samplerate;
  668. }
  669. void StretchAudioSource::setOnsetDetection(double x)
  670. {
  671. if (x == m_onsetdetection)
  672. return;
  673. if (m_cs.tryEnter())
  674. {
  675. m_onsetdetection = x;
  676. for (int i = 0; i < m_stretchers.size(); ++i)
  677. {
  678. m_stretchers[i]->set_onset_detection_sensitivity((float)x);
  679. }
  680. ++m_param_change_count;
  681. m_cs.exit();
  682. }
  683. }
  684. void StretchAudioSource::setPlayRange(Range<double> playrange)
  685. {
  686. if (playrange == m_playrange || playrange == m_inputfile->getActiveRange())
  687. return;
  688. if (m_cs.tryEnter())
  689. {
  690. if (playrange.isEmpty())
  691. m_playrange = { 0.0,1.0 };
  692. else
  693. m_playrange = playrange;
  694. m_stream_end_reached = false;
  695. m_inputfile->setActiveRange(m_playrange);
  696. //if (m_playrange.contains(m_seekpos) == false)
  697. // m_inputfile->seek(m_playrange.getStart());
  698. m_seekpos = m_playrange.getStart();
  699. ++m_param_change_count;
  700. m_cs.exit();
  701. }
  702. }
  703. bool StretchAudioSource::isLoopEnabled()
  704. {
  705. if (m_inputfile == nullptr)
  706. return false;
  707. return m_inputfile->isLooping();
  708. }
  709. bool StretchAudioSource::hasReachedEnd()
  710. {
  711. if (m_inputfile == nullptr)
  712. return false;
  713. if (m_inputfile->isLooping() && m_maxloops == 0)
  714. return false;
  715. if (m_inputfile->isLooping() && m_inputfile->getLoopCount() > m_maxloops)
  716. return true;
  717. //return m_output_counter>=m_process_fftsize*2;
  718. return m_output_silence_counter>=65536;
  719. }