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.

640 lines
16KB

  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,false} , { 1, false} ,{2,true},{3,true},{4,true},{5,false},{6,true},{7,true} };
  14. setNumOutChannels(initialnumoutchans);
  15. m_xfadetask.buffer.setSize(8, 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. AudioBuffer<float>* StretchAudioSource::getSourceAudioBuffer()
  38. {
  39. if (m_inputfile==nullptr)
  40. return nullptr;
  41. return m_inputfile->getAudioBuffer();
  42. }
  43. bool StretchAudioSource::isResampling()
  44. {
  45. if (m_inputfile==nullptr || m_inputfile->info.samplerate==0)
  46. return false;
  47. return (int)m_outsr!=m_inputfile->info.samplerate;
  48. }
  49. std::vector<SpectrumProcess> StretchAudioSource::getSpectrumProcessOrder()
  50. {
  51. return m_specproc_order;
  52. }
  53. void StretchAudioSource::setSpectrumProcessOrder(std::vector<SpectrumProcess> order)
  54. {
  55. ScopedLock locker(m_cs);
  56. m_specproc_order = order;
  57. for (int i = 0; i < m_stretchers.size(); ++i)
  58. {
  59. m_stretchers[i]->m_spectrum_processes = order;
  60. }
  61. }
  62. std::pair<Range<double>, Range<double>> StretchAudioSource::getFileCachedRangesNormalized()
  63. {
  64. if (m_inputfile == nullptr)
  65. return {};
  66. return m_inputfile->getCachedRangesNormalized();
  67. }
  68. ValueTree StretchAudioSource::getStateTree()
  69. {
  70. ValueTree tree("stretchsourcestate");
  71. storeToTreeProperties(tree, nullptr, "pitch_shift", m_ppar.pitch_shift.cents,
  72. "octaves_minus2", m_ppar.octave.om2,
  73. "octaves_minus1",m_ppar.octave.om1,
  74. "octave0",m_ppar.octave.o0,
  75. "octave_plus1",m_ppar.octave.o1,
  76. "octaves_plus15",m_ppar.octave.o15,
  77. "octaves_plus2",m_ppar.octave.o2);
  78. return tree;
  79. }
  80. void StretchAudioSource::setStateTree(ValueTree state)
  81. {
  82. ScopedLock locker(m_cs);
  83. getFromTreeProperties(state, "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. for (int i = 0; i < m_stretchers.size(); ++i)
  91. {
  92. m_stretchers[i]->set_parameters(&m_ppar);
  93. }
  94. }
  95. bool StretchAudioSource::isLoopingEnabled()
  96. {
  97. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  98. return false;
  99. return m_inputfile->isLooping();
  100. }
  101. void StretchAudioSource::setLoopingEnabled(bool b)
  102. {
  103. ScopedLock locker(m_cs);
  104. if (m_inputfile != nullptr)
  105. {
  106. m_inputfile->setLoopEnabled(b);
  107. }
  108. }
  109. void StretchAudioSource::setAudioBufferAsInputSource(AudioBuffer<float>* buf, int sr, int len)
  110. {
  111. ScopedLock locker(m_cs);
  112. m_inputfile->setAudioBuffer(buf, sr, len);
  113. m_seekpos = 0.0;
  114. m_curfile = File();
  115. if (m_playrange.isEmpty())
  116. setPlayRange({ 0.0,1.0 }, true);
  117. ++m_param_change_count;
  118. }
  119. void StretchAudioSource::setMainVolume(double decibels)
  120. {
  121. if (decibels == m_main_volume)
  122. return;
  123. if (m_cs.tryEnter())
  124. {
  125. m_main_volume = jlimit(-144.0, 12.0, decibels);
  126. ++m_param_change_count;
  127. m_cs.exit();
  128. }
  129. }
  130. void StretchAudioSource::setLoopXFadeLength(double lenseconds)
  131. {
  132. if (lenseconds == m_loopxfadelen)
  133. return;
  134. if (m_cs.tryEnter())
  135. {
  136. m_loopxfadelen = jlimit(0.0, 1.0, lenseconds);
  137. ++m_param_change_count;
  138. m_cs.exit();
  139. }
  140. }
  141. void StretchAudioSource::getNextAudioBlock(const AudioSourceChannelInfo & bufferToFill)
  142. {
  143. ScopedLock locker(m_cs);
  144. if (m_pause_state == 2)
  145. {
  146. bufferToFill.buffer->clear(bufferToFill.startSample,bufferToFill.numSamples);
  147. return;
  148. }
  149. if (m_stretchoutringbuf.available() > 0)
  150. m_output_has_begun = true;
  151. bool freezing = m_freezing;
  152. if (m_stretchers[0]->isFreezing() != freezing)
  153. {
  154. if (freezing == true && m_inputfile!=nullptr)
  155. m_freeze_pos = 1.0/m_inputfile->info.nsamples*m_inputfile->getCurrentPosition();
  156. for (auto& e : m_stretchers)
  157. e->set_freezing(m_freezing);
  158. }
  159. double maingain = Decibels::decibelsToGain(m_main_volume);
  160. if (m_vol_smoother.getTargetValue() != maingain)
  161. m_vol_smoother.setValue(maingain);
  162. FloatVectorOperations::disableDenormalisedNumberSupport();
  163. float** outarrays = bufferToFill.buffer->getArrayOfWritePointers();
  164. int outbufchans = m_num_outchans; // bufferToFill.buffer->getNumChannels();
  165. int offset = bufferToFill.startSample;
  166. if (m_stretchers.size() == 0)
  167. return;
  168. if (m_inputfile == nullptr)
  169. return;
  170. if (m_inputfile->info.nsamples == 0)
  171. return;
  172. m_inputfile->setXFadeLenSeconds(m_loopxfadelen);
  173. double silencethreshold = Decibels::decibelsToGain(-70.0);
  174. bool tempfirst = true;
  175. auto foofilepos0 = m_inputfile->getCurrentPosition();
  176. auto ringbuffilltask = [this](int framestoproduce)
  177. {
  178. while (m_stretchoutringbuf.available() < framestoproduce*m_num_outchans)
  179. {
  180. int readsize = 0;
  181. double in_pos = (double)m_inputfile->getCurrentPosition() / (double)m_inputfile->info.nsamples;
  182. if (m_firstbuffer)
  183. {
  184. readsize = m_stretchers[0]->get_nsamples_for_fill();
  185. m_firstbuffer = false;
  186. }
  187. else
  188. {
  189. readsize = m_stretchers[0]->get_nsamples(in_pos*100.0);
  190. };
  191. int readed = 0;
  192. if (readsize != 0)
  193. {
  194. readed = m_inputfile->readNextBlock(m_file_inbuf, readsize, m_num_outchans);
  195. }
  196. auto inbufptrs = m_file_inbuf.getArrayOfWritePointers();
  197. REALTYPE onset_max = std::numeric_limits<REALTYPE>::min();
  198. #ifdef USE_PPL_TO_PROCESS_STRETCHERS
  199. std::array<REALTYPE, 16> onset_values_arr;
  200. Concurrency::parallel_for(0, (int)m_stretchers.size(), [this, readed, &onset_values_arr](int i)
  201. {
  202. REALTYPE onset_val = m_stretchers[i]->process(m_inbufs[i].data(), readed);
  203. onset_values_arr[i] = onset_val;
  204. });
  205. for (int i = 0; i < m_stretchers.size(); ++i)
  206. onset_max = std::max(onset_max, onset_values_arr[i]);
  207. #else
  208. for (int i = 0; i < m_stretchers.size(); ++i)
  209. {
  210. REALTYPE onset_l = m_stretchers[i]->process(inbufptrs[i], readed);
  211. onset_max = std::max(onset_max, onset_l);
  212. }
  213. #endif
  214. for (int i = 0; i < m_stretchers.size(); ++i)
  215. m_stretchers[i]->here_is_onset(onset_max);
  216. int outbufsize = m_stretchers[0]->get_bufsize();
  217. int nskip = m_stretchers[0]->get_skip_nsamples();
  218. if (nskip > 0)
  219. m_inputfile->skip(nskip);
  220. for (int i = 0; i < outbufsize; i++)
  221. {
  222. for (int ch = 0; ch < m_num_outchans; ++ch)
  223. {
  224. REALTYPE outsa = m_stretchers[ch]->out_buf[i];
  225. m_stretchoutringbuf.push(outsa);
  226. }
  227. }
  228. }
  229. };
  230. int previousxfadestate = m_xfadetask.state;
  231. auto resamplertask = [this, &ringbuffilltask, &bufferToFill]()
  232. {
  233. double* rsinbuf = nullptr;
  234. int outsamplestoproduce = bufferToFill.numSamples;
  235. if (m_xfadetask.state == 1)
  236. outsamplestoproduce = m_xfadetask.xfade_len;
  237. int wanted = m_resampler->ResamplePrepare(outsamplestoproduce, m_num_outchans, &rsinbuf);
  238. ringbuffilltask(wanted);
  239. for (int i = 0; i < wanted*m_num_outchans; ++i)
  240. {
  241. double sample = m_stretchoutringbuf.get();
  242. rsinbuf[i] = sample;
  243. }
  244. if (outsamplestoproduce*m_num_outchans > m_resampler_outbuf.size())
  245. {
  246. m_resampler_outbuf.resize(outsamplestoproduce*m_num_outchans);
  247. }
  248. /*int produced =*/ m_resampler->ResampleOut(m_resampler_outbuf.data(), wanted, outsamplestoproduce, m_num_outchans);
  249. if (m_xfadetask.state == 1)
  250. {
  251. //Logger::writeToLog("Filling xfade buffer");
  252. for (int i = 0; i < outsamplestoproduce; ++i)
  253. {
  254. for (int j = 0; j < m_num_outchans; ++j)
  255. {
  256. m_xfadetask.buffer.setSample(j, i, m_resampler_outbuf[i*m_num_outchans + j]);
  257. }
  258. }
  259. if (m_process_fftsize != m_xfadetask.requested_fft_size)
  260. {
  261. m_process_fftsize = m_xfadetask.requested_fft_size;
  262. //Logger::writeToLog("Initing stretcher objects");
  263. initObjects();
  264. }
  265. m_xfadetask.state = 2;
  266. }
  267. };
  268. resamplertask();
  269. if (previousxfadestate == 1 && m_xfadetask.state == 2)
  270. {
  271. //Logger::writeToLog("Rerunning resampler task");
  272. resamplertask();
  273. }
  274. bool source_ended = m_inputfile->hasEnded();
  275. double samplelimit = 16384.0;
  276. if (m_clip_output == true)
  277. samplelimit = 1.0;
  278. for (int i = 0; i < bufferToFill.numSamples; ++i)
  279. {
  280. double smoothed_gain = m_vol_smoother.getNextValue();
  281. double mixed = 0.0;
  282. for (int j = 0; j < outbufchans; ++j)
  283. {
  284. double outsample = m_resampler_outbuf[i*m_num_outchans + j];
  285. if (m_xfadetask.state == 2)
  286. {
  287. double xfadegain = 1.0 / m_xfadetask.xfade_len*m_xfadetask.counter;
  288. jassert(xfadegain >= 0.0 && xfadegain <= 1.0);
  289. double outsample2 = m_xfadetask.buffer.getSample(j, m_xfadetask.counter);
  290. outsample = xfadegain * outsample + (1.0 - xfadegain)*outsample2;
  291. }
  292. outarrays[j][i + offset] = jlimit(-samplelimit,samplelimit , outsample * smoothed_gain);
  293. mixed += outsample;
  294. }
  295. if (m_xfadetask.state == 2)
  296. {
  297. ++m_xfadetask.counter;
  298. if (m_xfadetask.counter >= m_xfadetask.xfade_len)
  299. m_xfadetask.state = 0;
  300. }
  301. if (source_ended && m_output_counter>=2*m_process_fftsize)
  302. {
  303. if (fabs(mixed) < silencethreshold)
  304. ++m_output_silence_counter;
  305. else
  306. m_output_silence_counter = 0;
  307. }
  308. }
  309. if (m_pause_state == 1)
  310. {
  311. bufferToFill.buffer->applyGainRamp(bufferToFill.startSample, bufferToFill.numSamples, 1.0f, 0.0f);
  312. m_pause_state = 2;
  313. }
  314. if (m_pause_state == 3)
  315. {
  316. bufferToFill.buffer->applyGainRamp(bufferToFill.startSample, bufferToFill.numSamples, 0.0f, 1.0f);
  317. m_pause_state = 0;
  318. }
  319. m_output_counter += bufferToFill.numSamples;
  320. }
  321. void StretchAudioSource::setNextReadPosition(int64 /*newPosition*/)
  322. {
  323. }
  324. int64 StretchAudioSource::getNextReadPosition() const
  325. {
  326. return int64();
  327. }
  328. int64 StretchAudioSource::getTotalLength() const
  329. {
  330. if (m_inputfile == nullptr)
  331. return 0;
  332. return m_inputfile->info.nsamples;
  333. }
  334. bool StretchAudioSource::isLooping() const
  335. {
  336. return false;
  337. }
  338. String StretchAudioSource::setAudioFile(File file)
  339. {
  340. ScopedLock locker(m_cs);
  341. if (m_inputfile->openAudioFile(file))
  342. {
  343. m_curfile = file;
  344. return String();
  345. }
  346. return "Could not open file";
  347. }
  348. File StretchAudioSource::getAudioFile()
  349. {
  350. return m_curfile;
  351. }
  352. void StretchAudioSource::setNumOutChannels(int chans)
  353. {
  354. jassert(chans > 0 && chans < g_maxnumoutchans);
  355. m_num_outchans = chans;
  356. }
  357. void StretchAudioSource::initObjects()
  358. {
  359. ScopedLock locker(m_cs);
  360. m_inputfile->setActiveRange(m_playrange);
  361. if (m_inputfile->getActiveRange().contains(m_inputfile->getCurrentPositionPercent())==false)
  362. m_inputfile->seek(m_playrange.getStart());
  363. m_firstbuffer = true;
  364. if (m_stretchoutringbuf.getSize() < m_num_outchans*m_process_fftsize)
  365. {
  366. int newsize = m_num_outchans*m_process_fftsize*2;
  367. //Logger::writeToLog("Resizing circular buffer to " + String(newsize));
  368. m_stretchoutringbuf.resize(newsize);
  369. }
  370. m_stretchoutringbuf.clear();
  371. m_resampler->Reset();
  372. m_resampler->SetRates(m_inputfile->info.samplerate, m_outsr);
  373. REALTYPE stretchratio = m_playrate;
  374. FFTWindow windowtype = W_HAMMING;
  375. if (m_fft_window_type>=0)
  376. windowtype = (FFTWindow)m_fft_window_type;
  377. int inbufsize = m_process_fftsize;
  378. double onsetsens = m_onsetdetection;
  379. m_stretchers.resize(m_num_outchans);
  380. for (int i = 0; i < m_stretchers.size(); ++i)
  381. {
  382. if (m_stretchers[i] == nullptr)
  383. {
  384. //Logger::writeToLog("Creating stretch instance " + String(i));
  385. m_stretchers[i] = std::make_shared<ProcessedStretch>(stretchratio,
  386. m_process_fftsize, windowtype, false, (float)m_inputfile->info.samplerate, i + 1);
  387. }
  388. m_stretchers[i]->setBufferSize(m_process_fftsize);
  389. m_stretchers[i]->setSampleRate(m_inputfile->info.samplerate);
  390. m_stretchers[i]->set_onset_detection_sensitivity(onsetsens);
  391. m_stretchers[i]->set_parameters(&m_ppar);
  392. m_stretchers[i]->set_freezing(m_freezing);
  393. fill_container(m_stretchers[i]->out_buf, 0.0f);
  394. m_stretchers[i]->m_spectrum_processes = m_specproc_order;
  395. }
  396. m_file_inbuf.setSize(m_num_outchans, 3 * inbufsize);
  397. int poolsize = m_stretchers[0]->get_max_bufsize();
  398. }
  399. double StretchAudioSource::getInfilePositionPercent()
  400. {
  401. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  402. return 0.0;
  403. return 1.0/m_inputfile->info.nsamples*m_inputfile->getCurrentPosition();
  404. }
  405. double StretchAudioSource::getInfilePositionSeconds()
  406. {
  407. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  408. return 0.0;
  409. //return m_lastinpos*m_inputfile->getLengthSeconds();
  410. return (double)m_inputfile->getCurrentPosition() / m_inputfile->info.samplerate;
  411. }
  412. double StretchAudioSource::getInfileLengthSeconds()
  413. {
  414. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  415. return 0.0;
  416. return (double)m_inputfile->info.nsamples / m_inputfile->info.samplerate;
  417. }
  418. void StretchAudioSource::setRate(double rate)
  419. {
  420. if (rate == m_playrate)
  421. return;
  422. if (m_cs.tryEnter())
  423. {
  424. m_playrate = rate;
  425. for (int i = 0; i < m_stretchers.size(); ++i)
  426. {
  427. m_stretchers[i]->set_rap((float)rate);
  428. }
  429. ++m_param_change_count;
  430. m_cs.exit();
  431. }
  432. }
  433. void StretchAudioSource::setProcessParameters(ProcessParameters * pars)
  434. {
  435. if (*pars == m_ppar)
  436. return;
  437. if (m_cs.tryEnter())
  438. {
  439. m_ppar = *pars;
  440. for (int i = 0; i < m_stretchers.size(); ++i)
  441. {
  442. m_stretchers[i]->set_parameters(pars);
  443. }
  444. ++m_param_change_count;
  445. m_cs.exit();
  446. }
  447. }
  448. const ProcessParameters& StretchAudioSource::getProcessParameters()
  449. {
  450. return m_ppar;
  451. }
  452. void StretchAudioSource::setFFTWindowingType(int windowtype)
  453. {
  454. if (windowtype==m_fft_window_type)
  455. return;
  456. if (m_cs.tryEnter())
  457. {
  458. m_fft_window_type = windowtype;
  459. for (int i = 0; i < m_stretchers.size(); ++i)
  460. {
  461. m_stretchers[i]->window_type = (FFTWindow)windowtype;
  462. }
  463. ++m_param_change_count;
  464. m_cs.exit();
  465. }
  466. }
  467. void StretchAudioSource::setFFTSize(int size)
  468. {
  469. jassert(size>0);
  470. if (m_xfadetask.state == 0 && (m_process_fftsize == 0 || size != m_process_fftsize))
  471. {
  472. ScopedLock locker(m_cs);
  473. if (m_xfadetask.buffer.getNumChannels() < m_num_outchans)
  474. {
  475. m_xfadetask.buffer.setSize(m_num_outchans, m_xfadetask.buffer.getNumSamples());
  476. }
  477. if (m_process_fftsize > 0)
  478. {
  479. m_xfadetask.state = 1;
  480. m_xfadetask.counter = 0;
  481. m_xfadetask.xfade_len = 16384;
  482. m_xfadetask.requested_fft_size = size;
  483. }
  484. else
  485. {
  486. m_process_fftsize = size;
  487. initObjects();
  488. }
  489. ++m_param_change_count;
  490. }
  491. }
  492. void StretchAudioSource::setPaused(bool b)
  493. {
  494. if (b == true && m_pause_state>0)
  495. return;
  496. if (b == false && m_pause_state == 0)
  497. return;
  498. ScopedLock locker(m_cs);
  499. if (b == true && m_pause_state == 0)
  500. {
  501. m_pause_state = 1;
  502. return;
  503. }
  504. if (b == false && m_pause_state == 2)
  505. {
  506. m_pause_state = 3;
  507. return;
  508. }
  509. }
  510. bool StretchAudioSource::isPaused() const
  511. {
  512. return m_pause_state > 0;
  513. }
  514. void StretchAudioSource::seekPercent(double pos)
  515. {
  516. ScopedLock locker(m_cs);
  517. m_seekpos = pos;
  518. m_inputfile->seek(pos);
  519. ++m_param_change_count;
  520. }
  521. double StretchAudioSource::getOutputDurationSecondsForRange(Range<double> range, int fftsize)
  522. {
  523. if (m_inputfile == nullptr || m_inputfile->info.nsamples == 0)
  524. return 0.0;
  525. int64_t play_end_pos = (fftsize * 2)+range.getLength()*m_playrate*m_inputfile->info.nsamples;
  526. return (double)play_end_pos / m_inputfile->info.samplerate;
  527. }
  528. void StretchAudioSource::setOnsetDetection(double x)
  529. {
  530. if (x == m_onsetdetection)
  531. return;
  532. if (m_cs.tryEnter())
  533. {
  534. m_onsetdetection = x;
  535. for (int i = 0; i < m_stretchers.size(); ++i)
  536. {
  537. m_stretchers[i]->set_onset_detection_sensitivity((float)x);
  538. }
  539. ++m_param_change_count;
  540. m_cs.exit();
  541. }
  542. }
  543. void StretchAudioSource::setPlayRange(Range<double> playrange, bool isloop)
  544. {
  545. if (m_playrange.isEmpty() == false && playrange == m_playrange)
  546. return;
  547. if (m_cs.tryEnter())
  548. {
  549. if (playrange.isEmpty())
  550. m_playrange = { 0.0,1.0 };
  551. else
  552. m_playrange = playrange;
  553. m_stream_end_reached = false;
  554. m_inputfile->setActiveRange(m_playrange);
  555. m_inputfile->setLoopEnabled(isloop);
  556. if (m_playrange.contains(m_seekpos) == false)
  557. m_inputfile->seek(m_playrange.getStart());
  558. m_seekpos = m_playrange.getStart();
  559. ++m_param_change_count;
  560. m_cs.exit();
  561. }
  562. }
  563. bool StretchAudioSource::isLoopEnabled()
  564. {
  565. if (m_inputfile == nullptr)
  566. return false;
  567. return m_inputfile->isLooping();
  568. }
  569. bool StretchAudioSource::hasReachedEnd()
  570. {
  571. if (m_inputfile == nullptr)
  572. return false;
  573. if (m_inputfile->isLooping() && m_maxloops == 0)
  574. return false;
  575. if (m_inputfile->isLooping() && m_inputfile->getLoopCount() > m_maxloops)
  576. return true;
  577. //return m_output_counter>=m_process_fftsize*2;
  578. return m_output_silence_counter>=65536;
  579. }