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.

747 lines
19KB

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