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.

889 lines
24KB

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