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.

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