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.

905 lines
25KB

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