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.

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