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.

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