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.

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