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.

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