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.

755 lines
20KB

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