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.

762 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. 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. Logger::writeToLog("<**");
  70. for (auto& e : m_specproc_order)
  71. Logger::writeToLog(e.m_enabled->name + " " + String(e.m_index));
  72. Logger::writeToLog("**>");
  73. for (int i = 0; i < m_stretchers.size(); ++i)
  74. {
  75. m_stretchers[i]->m_spectrum_processes = order;
  76. }
  77. }
  78. std::pair<Range<double>, Range<double>> StretchAudioSource::getFileCachedRangesNormalized()
  79. {
  80. if (m_inputfile == nullptr)
  81. return {};
  82. return m_inputfile->getCachedRangesNormalized();
  83. }
  84. void StretchAudioSource::setFreeFilterEnvelope(shared_envelope env)
  85. {
  86. ScopedLock locker(m_cs);
  87. m_free_filter_envelope = env;
  88. for (int i = 0; i < m_stretchers.size(); ++i)
  89. {
  90. m_stretchers[i]->setFreeFilterEnvelope(env);
  91. }
  92. }
  93. ValueTree StretchAudioSource::getStateTree()
  94. {
  95. ValueTree tree("stretchsourcestate");
  96. storeToTreeProperties(tree, nullptr, "pitch_shift", m_ppar.pitch_shift.cents,
  97. "octaves_minus2", m_ppar.octave.om2,
  98. "octaves_minus1",m_ppar.octave.om1,
  99. "octave0",m_ppar.octave.o0,
  100. "octave_plus1",m_ppar.octave.o1,
  101. "octaves_plus15",m_ppar.octave.o15,
  102. "octaves_plus2",m_ppar.octave.o2);
  103. return tree;
  104. }
  105. void StretchAudioSource::setStateTree(ValueTree state)
  106. {
  107. ScopedLock locker(m_cs);
  108. getFromTreeProperties(state, "pitch_shift", m_ppar.pitch_shift.cents,
  109. "octaves_minus2", m_ppar.octave.om2,
  110. "octaves_minus1", m_ppar.octave.om1,
  111. "octave0", m_ppar.octave.o0,
  112. "octave_plus1", m_ppar.octave.o1,
  113. "octaves_plus15", m_ppar.octave.o15,
  114. "octaves_plus2", m_ppar.octave.o2);
  115. for (int i = 0; i < m_stretchers.size(); ++i)
  116. {
  117. m_stretchers[i]->set_parameters(&m_ppar);
  118. }
  119. }
  120. bool StretchAudioSource::isLoopingEnabled()
  121. {
  122. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  123. return false;
  124. return m_inputfile->isLooping();
  125. }
  126. void StretchAudioSource::setLoopingEnabled(bool b)
  127. {
  128. ScopedLock locker(m_cs);
  129. if (m_inputfile != nullptr)
  130. {
  131. m_inputfile->setLoopEnabled(b);
  132. }
  133. }
  134. void StretchAudioSource::setAudioBufferAsInputSource(AudioBuffer<float>* buf, int sr, int len)
  135. {
  136. ScopedLock locker(m_cs);
  137. m_inputfile->setAudioBuffer(buf, sr, len);
  138. m_seekpos = 0.0;
  139. m_curfile = File();
  140. if (m_playrange.isEmpty())
  141. setPlayRange({ 0.0,1.0 }, true);
  142. ++m_param_change_count;
  143. }
  144. void StretchAudioSource::setMainVolume(double decibels)
  145. {
  146. if (decibels == m_main_volume)
  147. return;
  148. if (m_cs.tryEnter())
  149. {
  150. m_main_volume = jlimit(-144.0, 12.0, decibels);
  151. ++m_param_change_count;
  152. m_cs.exit();
  153. }
  154. }
  155. #ifdef OLDMODULE_ENAB
  156. void StretchAudioSource::setSpectralModulesEnabled(const std::array<AudioParameterBool*, 9>& params)
  157. {
  158. jassert(m_specprocmap.size() > 0);
  159. /*
  160. bool changed = false;
  161. for (int i = 0; i < m_specproc_order.size(); ++i)
  162. {
  163. int index = m_specprocmap[i];
  164. if (*params[index] != *m_specproc_order[i].m_enabled)
  165. {
  166. changed = true;
  167. break;
  168. }
  169. }
  170. if (changed == false)
  171. return;
  172. */
  173. if (m_cs.tryEnter())
  174. {
  175. for (int i = 0; i < m_specproc_order.size(); ++i)
  176. {
  177. int index = m_specprocmap[i];
  178. *m_specproc_order[i].m_enabled = (bool)(*params[index]);
  179. }
  180. for (int i = 0; i < m_stretchers.size(); ++i)
  181. {
  182. m_stretchers[i]->m_spectrum_processes = m_specproc_order;
  183. }
  184. ++m_param_change_count;
  185. m_cs.exit();
  186. }
  187. }
  188. #endif
  189. void StretchAudioSource::setSpectralModuleEnabled(int index, bool b)
  190. {
  191. Logger::writeToLog(String(index));
  192. ScopedLock locker(m_cs);
  193. for (int i = 0; i < m_stretchers.size(); ++i)
  194. {
  195. m_stretchers[i]->m_spectrum_processes = m_specproc_order;
  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. return String();
  442. }
  443. return "Could not open file";
  444. }
  445. File StretchAudioSource::getAudioFile()
  446. {
  447. return m_curfile;
  448. }
  449. void StretchAudioSource::setNumOutChannels(int chans)
  450. {
  451. jassert(chans > 0 && chans < g_maxnumoutchans);
  452. m_num_outchans = chans;
  453. }
  454. void StretchAudioSource::initObjects()
  455. {
  456. ScopedLock locker(m_cs);
  457. m_inputfile->setActiveRange(m_playrange);
  458. if (m_inputfile->getActiveRange().contains(m_inputfile->getCurrentPositionPercent())==false)
  459. m_inputfile->seek(m_playrange.getStart());
  460. m_firstbuffer = true;
  461. if (m_stretchoutringbuf.getSize() < m_num_outchans*m_process_fftsize)
  462. {
  463. int newsize = m_num_outchans*m_process_fftsize*2;
  464. //Logger::writeToLog("Resizing circular buffer to " + String(newsize));
  465. m_stretchoutringbuf.resize(newsize);
  466. }
  467. m_stretchoutringbuf.clear();
  468. m_resampler->Reset();
  469. m_resampler->SetRates(m_inputfile->info.samplerate, m_outsr);
  470. REALTYPE stretchratio = m_playrate;
  471. FFTWindow windowtype = W_HAMMING;
  472. if (m_fft_window_type>=0)
  473. windowtype = (FFTWindow)m_fft_window_type;
  474. int inbufsize = m_process_fftsize;
  475. double onsetsens = m_onsetdetection;
  476. m_stretchers.resize(m_num_outchans);
  477. for (int i = 0; i < m_stretchers.size(); ++i)
  478. {
  479. if (m_stretchers[i] == nullptr)
  480. {
  481. //Logger::writeToLog("Creating stretch instance " + String(i));
  482. m_stretchers[i] = std::make_shared<ProcessedStretch>(stretchratio,
  483. m_process_fftsize, windowtype, false, (float)m_inputfile->info.samplerate, i + 1);
  484. }
  485. m_stretchers[i]->setBufferSize(m_process_fftsize);
  486. m_stretchers[i]->setSampleRate(m_inputfile->info.samplerate);
  487. m_stretchers[i]->set_onset_detection_sensitivity(onsetsens);
  488. m_stretchers[i]->set_parameters(&m_ppar);
  489. m_stretchers[i]->set_freezing(m_freezing);
  490. m_stretchers[i]->setFreeFilterEnvelope(m_free_filter_envelope);
  491. fill_container(m_stretchers[i]->out_buf, 0.0f);
  492. m_stretchers[i]->m_spectrum_processes = m_specproc_order;
  493. }
  494. m_file_inbuf.setSize(m_num_outchans, 3 * inbufsize);
  495. int poolsize = m_stretchers[0]->get_max_bufsize();
  496. }
  497. void StretchAudioSource::playDrySound(const AudioSourceChannelInfo & bufferToFill)
  498. {
  499. double maingain = Decibels::decibelsToGain(m_main_volume);
  500. m_inputfile->setXFadeLenSeconds(m_loopxfadelen);
  501. double* rsinbuf = nullptr;
  502. m_resampler->SetRates(m_inputfile->info.samplerate, m_outsr);
  503. int wanted = m_resampler->ResamplePrepare(bufferToFill.numSamples, m_num_outchans, &rsinbuf);
  504. m_inputfile->readNextBlock(m_drypreviewbuf, wanted, m_num_outchans);
  505. for (int i = 0; i < wanted; ++i)
  506. for (int j = 0; j < m_num_outchans; ++j)
  507. rsinbuf[i*m_num_outchans + j] = m_drypreviewbuf.getSample(j, i);
  508. m_resampler->ResampleOut(m_resampler_outbuf.data(), wanted, bufferToFill.numSamples, m_num_outchans);
  509. for (int i = 0; i < m_num_outchans; ++i)
  510. for (int j = 0; j < bufferToFill.numSamples; ++j)
  511. bufferToFill.buffer->setSample(i, j + bufferToFill.startSample, maingain * m_resampler_outbuf[j*m_num_outchans + i]);
  512. }
  513. double StretchAudioSource::getInfilePositionPercent()
  514. {
  515. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  516. return 0.0;
  517. return 1.0/m_inputfile->info.nsamples*m_inputfile->getCurrentPosition();
  518. }
  519. double StretchAudioSource::getInfilePositionSeconds()
  520. {
  521. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  522. return 0.0;
  523. //return m_lastinpos*m_inputfile->getLengthSeconds();
  524. return (double)m_inputfile->getCurrentPosition() / m_inputfile->info.samplerate;
  525. }
  526. double StretchAudioSource::getInfileLengthSeconds()
  527. {
  528. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  529. return 0.0;
  530. return (double)m_inputfile->info.nsamples / m_inputfile->info.samplerate;
  531. }
  532. void StretchAudioSource::setRate(double rate)
  533. {
  534. if (rate == m_playrate)
  535. return;
  536. if (m_cs.tryEnter())
  537. {
  538. m_playrate = rate;
  539. for (int i = 0; i < m_stretchers.size(); ++i)
  540. {
  541. m_stretchers[i]->set_rap((float)rate);
  542. }
  543. ++m_param_change_count;
  544. m_cs.exit();
  545. }
  546. }
  547. void StretchAudioSource::setProcessParameters(ProcessParameters * pars)
  548. {
  549. if (*pars == m_ppar)
  550. return;
  551. if (m_cs.tryEnter())
  552. {
  553. m_ppar = *pars;
  554. for (int i = 0; i < m_stretchers.size(); ++i)
  555. {
  556. m_stretchers[i]->set_parameters(pars);
  557. }
  558. ++m_param_change_count;
  559. m_cs.exit();
  560. }
  561. }
  562. const ProcessParameters& StretchAudioSource::getProcessParameters()
  563. {
  564. return m_ppar;
  565. }
  566. void StretchAudioSource::setFFTWindowingType(int windowtype)
  567. {
  568. if (windowtype==m_fft_window_type)
  569. return;
  570. if (m_cs.tryEnter())
  571. {
  572. m_fft_window_type = windowtype;
  573. for (int i = 0; i < m_stretchers.size(); ++i)
  574. {
  575. m_stretchers[i]->window_type = (FFTWindow)windowtype;
  576. }
  577. ++m_param_change_count;
  578. m_cs.exit();
  579. }
  580. }
  581. void StretchAudioSource::setFFTSize(int size)
  582. {
  583. jassert(size>0);
  584. if (m_xfadetask.state == 0 && (m_process_fftsize == 0 || size != m_process_fftsize))
  585. {
  586. ScopedLock locker(m_cs);
  587. if (m_xfadetask.buffer.getNumChannels() < m_num_outchans)
  588. {
  589. m_xfadetask.buffer.setSize(m_num_outchans, m_xfadetask.buffer.getNumSamples());
  590. }
  591. if (m_process_fftsize > 0)
  592. {
  593. m_xfadetask.state = 1;
  594. m_xfadetask.counter = 0;
  595. m_xfadetask.xfade_len = 16384;
  596. m_xfadetask.requested_fft_size = size;
  597. }
  598. else
  599. {
  600. m_process_fftsize = size;
  601. initObjects();
  602. }
  603. ++m_param_change_count;
  604. }
  605. }
  606. void StretchAudioSource::setPaused(bool b)
  607. {
  608. if (b == true && m_pause_state>0)
  609. return;
  610. if (b == false && m_pause_state == 0)
  611. return;
  612. ScopedLock locker(m_cs);
  613. if (b == true && m_pause_state == 0)
  614. {
  615. m_pause_state = 1;
  616. return;
  617. }
  618. if (b == false && m_pause_state == 2)
  619. {
  620. m_pause_state = 3;
  621. return;
  622. }
  623. }
  624. bool StretchAudioSource::isPaused() const
  625. {
  626. return m_pause_state > 0;
  627. }
  628. void StretchAudioSource::seekPercent(double pos)
  629. {
  630. ScopedLock locker(m_cs);
  631. m_seekpos = pos;
  632. //m_resampler->Reset();
  633. m_inputfile->seek(pos);
  634. ++m_param_change_count;
  635. }
  636. double StretchAudioSource::getOutputDurationSecondsForRange(Range<double> range, int fftsize)
  637. {
  638. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  639. return 0.0;
  640. if (m_preview_dry==true)
  641. return (double)range.getLength()*m_inputfile->info.nsamples/m_inputfile->info.samplerate;
  642. int64_t play_end_pos = (fftsize * 2)+range.getLength()*m_playrate*m_inputfile->info.nsamples;
  643. return (double)play_end_pos / m_inputfile->info.samplerate;
  644. }
  645. void StretchAudioSource::setOnsetDetection(double x)
  646. {
  647. if (x == m_onsetdetection)
  648. return;
  649. if (m_cs.tryEnter())
  650. {
  651. m_onsetdetection = x;
  652. for (int i = 0; i < m_stretchers.size(); ++i)
  653. {
  654. m_stretchers[i]->set_onset_detection_sensitivity((float)x);
  655. }
  656. ++m_param_change_count;
  657. m_cs.exit();
  658. }
  659. }
  660. void StretchAudioSource::setPlayRange(Range<double> playrange, bool isloop)
  661. {
  662. if (m_playrange.isEmpty() == false && playrange == m_playrange)
  663. return;
  664. if (m_cs.tryEnter())
  665. {
  666. if (playrange.isEmpty())
  667. m_playrange = { 0.0,1.0 };
  668. else
  669. m_playrange = playrange;
  670. m_stream_end_reached = false;
  671. m_inputfile->setActiveRange(m_playrange);
  672. m_inputfile->setLoopEnabled(isloop);
  673. //if (m_playrange.contains(m_seekpos) == false)
  674. // m_inputfile->seek(m_playrange.getStart());
  675. m_seekpos = m_playrange.getStart();
  676. ++m_param_change_count;
  677. m_cs.exit();
  678. }
  679. }
  680. bool StretchAudioSource::isLoopEnabled()
  681. {
  682. if (m_inputfile == nullptr)
  683. return false;
  684. return m_inputfile->isLooping();
  685. }
  686. bool StretchAudioSource::hasReachedEnd()
  687. {
  688. if (m_inputfile == nullptr)
  689. return false;
  690. if (m_inputfile->isLooping() && m_maxloops == 0)
  691. return false;
  692. if (m_inputfile->isLooping() && m_inputfile->getLoopCount() > m_maxloops)
  693. return true;
  694. //return m_output_counter>=m_process_fftsize*2;
  695. return m_output_silence_counter>=65536;
  696. }