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.

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