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.

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