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.

881 lines
25KB

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