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.

803 lines
23KB

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