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.

790 lines
22KB

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