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.

729 lines
19KB

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