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.

623 lines
18KB

  1. /*
  2. Copyright (C) 2006-2011 Nasca Octavian Paul
  3. Author: Nasca Octavian Paul
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of version 2 of the GNU General Public License
  6. as published by the Free Software Foundation.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License (version 2) for more details.
  11. You should have received a copy of the GNU General Public License (version 2)
  12. along with this program; if not, write to the Free Software Foundation,
  13. Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  14. */
  15. #include <math.h>
  16. #include <stdlib.h>
  17. #include "globals.h"
  18. #include "PaulStretchControl.h"
  19. #include "../WDL/resample.h"
  20. #include <thread>
  21. #ifdef WIN32
  22. #undef min
  23. #undef max
  24. #endif
  25. using namespace std;
  26. #ifdef USEPSCONTROL
  27. Control::Control(AudioFormatManager* afm) : m_afm(afm), m_bufferingthread("stretchbufferingthread")
  28. {
  29. m_stretch_source = std::make_unique<StretchAudioSource>(2,m_afm);
  30. wavinfo.samplerate=44100;
  31. wavinfo.nsamples=0;
  32. process.bufsize=16384;
  33. process.stretch=4.0;
  34. process.onset_detection_sensitivity=0.0;
  35. seek_pos=0.0;
  36. window_type=W_HANN;
  37. volume=1.0;
  38. gui_sliders.fftsize_s=0.5;
  39. gui_sliders.stretch_s=0.5;
  40. gui_sliders.mode_s=0;
  41. ///#warning test
  42. /// process.transient.enable=true;
  43. };
  44. Control::~Control()
  45. {
  46. m_bufferingthread.stopThread(1000);
  47. }
  48. void Control::processAudio(AudioBuffer<float>& buf)
  49. {
  50. jassert(m_buffering_source!=nullptr);
  51. jassert(m_bufferingthread.isThreadRunning());
  52. if (m_buffering_source != nullptr)
  53. {
  54. AudioSourceChannelInfo aif(buf);
  55. m_buffering_source->getNextAudioBlock(aif);
  56. }
  57. }
  58. void Control::setStretchAmount(double rate)
  59. {
  60. m_stretch_source->setRate(rate);
  61. }
  62. void Control::setFFTSize(double size)
  63. {
  64. if (m_prebuffer_amount == 5)
  65. m_fft_size_to_use = pow(2, 7.0 + size * 14.5);
  66. else m_fft_size_to_use = pow(2, 7.0 + size * 10.0); // chicken out from allowing huge FFT sizes if not enough prebuffering
  67. int optim = optimizebufsize(m_fft_size_to_use);
  68. m_fft_size_to_use = optim;
  69. m_stretch_source->setFFTSize(optim);
  70. //Logger::writeToLog(String(m_fft_size_to_use));
  71. }
  72. void Control::setOnsetDetection(double x)
  73. {
  74. m_stretch_source->setOnsetDetection(x);
  75. }
  76. void Control::set_input_file(File file, std::function<void(String)> cb)
  77. {
  78. auto task = [this,file,cb]()
  79. {
  80. auto ai = unique_from_raw(m_afm->createReaderFor(file));
  81. if (ai!=nullptr)
  82. {
  83. if (ai->numChannels > 32)
  84. {
  85. MessageManager::callAsync([cb,file](){ cb("Too many channels in file "+file.getFullPathName()); });
  86. return;
  87. }
  88. if (ai->bitsPerSample>32)
  89. {
  90. MessageManager::callAsync([cb,file](){ cb("Too high bit depth in file "+file.getFullPathName()); });
  91. return;
  92. }
  93. wavinfo.filename = file.getFullPathName();
  94. wavinfo.samplerate = ai->sampleRate;
  95. wavinfo.nsamples = ai->lengthInSamples;
  96. m_stretch_source->setAudioFile(file);
  97. MessageManager::callAsync([cb,file](){ cb(String()); });
  98. /// if (process.transient.enable) {
  99. /// pre_analyse_whole_audio(ai);
  100. /// };
  101. } else
  102. {
  103. wavinfo.filename="";
  104. wavinfo.samplerate=0;
  105. wavinfo.nsamples=0;
  106. MessageManager::callAsync([cb,file](){ cb("Could not open file "+file.getFullPathName()); });
  107. };
  108. };
  109. //std::thread th(task);
  110. //th.detach();
  111. task();
  112. };
  113. String Control::get_input_filename(){
  114. return wavinfo.filename;
  115. };
  116. String Control::get_stretch_info(Range<double> playrange)
  117. {
  118. double prate = m_stretch_source->getRate();
  119. double realduration = m_stretch_source->getOutputDurationSecondsForRange(playrange, m_fft_size_to_use);
  120. int64_t durintseconds = realduration;
  121. int64_t durintminutes = realduration / 60.0;
  122. int64_t durinthours = realduration / 3600.0;
  123. int64_t durintdays = realduration / (3600 * 24.0);
  124. String timestring;
  125. if (durintminutes < 1)
  126. timestring = String(realduration,3) +" seconds";
  127. if (durintminutes >= 1 && durinthours < 1)
  128. timestring = String(durintminutes) + " mins " + String(durintseconds % 60) + " secs";
  129. if (durinthours >= 1 && durintdays < 1)
  130. timestring = String(durinthours) + " hours " + String(durintminutes % 60) + " mins " + String(durintseconds % 60) + " secs";
  131. if (durintdays >= 1)
  132. timestring = String(durintdays) + " days " + String(durinthours % 24) + " hours " +
  133. String(durintminutes % 60) + " mins ";
  134. double fftwindowlenseconds = (double)m_fft_size_to_use / wavinfo.samplerate;
  135. double fftwindowfreqresol = (double)wavinfo.samplerate / 2 / m_fft_size_to_use;
  136. return "[Stretch " + String(prate, 1) + "x " + timestring + "] [FFT window "+String(fftwindowlenseconds,3)+" secs, frequency resolution "+
  137. String(fftwindowfreqresol,3)+" Hz]";
  138. #ifdef OLDSTRETCHINFO
  139. const int size=200;
  140. char tmp[size];tmp[size-1]=0;
  141. if (wavinfo.nsamples==0) return "Stretch: ";
  142. double realduration = m_stretch_source->getOutputDuration();
  143. if (realduration>(365.25*86400.0*1.0e12)){//more than 1 trillion years
  144. double duration=(realduration/(365.25*86400.0*1.0e12));//my
  145. snprintf(tmp,size,"Stretch: %.7gx (%g trillion years)",process.stretch,duration);
  146. return tmp;
  147. };
  148. if (realduration>(365.25*86400.0*1.0e9)){//more than 1 billion years
  149. double duration=(realduration/(365.25*86400.0*1.0e9));//my
  150. snprintf(tmp,size,"Stretch: %.7gx (%g billion years)",process.stretch,duration);
  151. return tmp;
  152. };
  153. if (realduration>(365.25*86400.0*1.0e6)){//more than 1 million years
  154. double duration=(realduration/(365.25*86400.0*1.0e6));//my
  155. snprintf(tmp,size,"Stretch: %.7gx (%g million years)",process.stretch,duration);
  156. return tmp;
  157. };
  158. if (realduration>(365.25*86400.0*2000.0)){//more than two millenniums
  159. int duration=(int)(realduration/(365.25*86400.0));//years
  160. int years=duration%1000;
  161. int milleniums=duration/1000;
  162. char stryears[size];stryears[0]=0;
  163. if (years!=0){
  164. if (years==1) snprintf(stryears,size," 1 year");
  165. else snprintf(stryears,size," %d years",years);
  166. };
  167. snprintf(tmp,size,"Stretch: %.7gx (%d milleniums%s)",process.stretch,milleniums,stryears);
  168. return tmp;
  169. };
  170. if (realduration>(365.25*86400.0)){//more than 1 year
  171. int duration=(int) (realduration/3600.0);//hours
  172. int hours=duration%24;
  173. int days=(duration/24)%365;
  174. int years=duration/(365*24);
  175. char stryears[size];stryears[0]=0;
  176. if (years==1) snprintf(stryears,size,"1 year ");
  177. else snprintf(stryears,size,"%d years ",years);
  178. char strdays[size];strdays[0]=0;
  179. if (days>0){
  180. if (days==1) snprintf(strdays,size,"1 day");
  181. else snprintf(strdays,size,"%d days",days);
  182. };
  183. if (years>=10) hours=0;
  184. char strhours[size];strhours[0]=0;
  185. if (hours>0){
  186. snprintf(strhours,size," %d h",hours);
  187. };
  188. snprintf(tmp,size,"Stretch: %.7gx (%s%s%s)",process.stretch,stryears,strdays,strhours);
  189. return tmp;
  190. }else{//less than 1 year
  191. int duration=(int)(realduration);//seconds
  192. char strdays[size];strdays[0]=0;
  193. int days=duration/86400;
  194. if (days>0){
  195. if (days==1) snprintf(strdays,size,"1 day ");
  196. else snprintf(strdays,size,"%d days ",duration/86400);
  197. };
  198. REALTYPE stretch=process.stretch;
  199. if (stretch>=1.0){
  200. stretch=((int) (stretch*100.0))*0.01;
  201. };
  202. snprintf(tmp,size,"Stretch: %.7gx (%s%.2d:%.2d:%.2d)",
  203. stretch,strdays,(duration/3600)%24,(duration/60)%60,duration%60);
  204. return tmp;
  205. };
  206. return "";
  207. #endif
  208. };
  209. /*
  210. string Control::get_fftresolution_info(){
  211. string resolution="Resolution: ";
  212. if (wavinfo.nsamples==0) return resolution;
  213. //todo: unctime and uncfreq are correct computed? Need to check later.
  214. REALTYPE unctime=process.bufsize/(REALTYPE)wavinfo.samplerate*sqrt(2.0);
  215. REALTYPE uncfreq=1.0/unctime*sqrt(2.0);
  216. char tmp[100];
  217. snprintf(tmp,100,"%.5g seconds",unctime);resolution+=tmp;
  218. snprintf(tmp,100," (%.5g Hz)",uncfreq);resolution+=tmp;
  219. return resolution;
  220. }
  221. */
  222. double Control::getPreBufferingPercent()
  223. {
  224. if (m_buffering_source == nullptr)
  225. return 0.0;
  226. return m_buffering_source->getPercentReady();
  227. }
  228. void Control::startplay(bool /*bypass*/, bool /*realtime*/, Range<double> playrange, int numoutchans, String& err)
  229. {
  230. m_stretch_source->setPlayRange(playrange, m_stretch_source->isLoopingEnabled());
  231. int bufamt = m_bufamounts[m_prebuffer_amount];
  232. if (m_buffering_source != nullptr && numoutchans != m_buffering_source->getNumberOfChannels())
  233. m_recreate_buffering_source = true;
  234. if (m_recreate_buffering_source == true)
  235. {
  236. m_buffering_source = std::make_unique<MyBufferingAudioSource>(m_stretch_source.get(),
  237. m_bufferingthread, false, bufamt, numoutchans, false);
  238. m_recreate_buffering_source = false;
  239. }
  240. if (m_bufferingthread.isThreadRunning() == false)
  241. m_bufferingthread.startThread();
  242. m_stretch_source->setNumOutChannels(numoutchans);
  243. m_stretch_source->setFFTSize(m_fft_size_to_use);
  244. update_process_parameters();
  245. m_last_outpos_pos = 0.0;
  246. m_last_in_pos = playrange.getStart()*m_stretch_source->getInfileLengthSeconds();
  247. m_buffering_source->prepareToPlay(1024, 44100.0);
  248. // sleep(100);
  249. // update_process_parameters();
  250. };
  251. void Control::stopplay()
  252. {
  253. //m_adm->removeAudioCallback(&m_test_callback);
  254. m_bufferingthread.stopThread(1000);
  255. };
  256. void Control::set_seek_pos(REALTYPE x)
  257. {
  258. seek_pos=x;
  259. m_stretch_source->seekPercent(x);
  260. };
  261. REALTYPE Control::get_seek_pos()
  262. {
  263. return 0.0;
  264. }
  265. double Control::getLivePlayPosition()
  266. {
  267. #ifndef USEOLDPLAYCURSOR
  268. double outpos = m_audiocallback.m_outpos;
  269. double rate = 1.0 / m_stretch_source->getRate();
  270. double outputdiff = (outpos - m_last_outpos_pos);
  271. double fftlenseconds = (double)m_stretch_source->getFFTSize() / 44100.0;
  272. //Logger::writeToLog("output diff " + String(outputdiff)+" fft len "+String(fftlenseconds));
  273. //jassert(outputdiff >= 0.0 && outputdiff<0.5);
  274. jassert(rate > 0.0);
  275. double inlenseconds = m_stretch_source->getInfileLengthSeconds();
  276. if (inlenseconds < 0.0001)
  277. return 0.0;
  278. double inposseconds = m_stretch_source->getInfilePositionSeconds();
  279. double playposseconds = m_last_in_pos + (outputdiff*rate) - fftlenseconds;
  280. if (outputdiff*rate >= fftlenseconds || outputdiff < 0.0001)
  281. {
  282. //Logger::writeToLog("juuh "+String(inposseconds));
  283. m_last_in_pos = inposseconds;
  284. m_last_outpos_pos = outpos;
  285. return 1.0 / inlenseconds*(m_last_in_pos-fftlenseconds-getPreBufferAmountSeconds()*rate);
  286. }
  287. //Logger::writeToLog("jaah " + String(inposseconds));
  288. return 1.0 / inlenseconds*(playposseconds-getPreBufferAmountSeconds()*rate);
  289. #else
  290. return m_stretch_source->getInfilePositionPercent();
  291. #endif
  292. }
  293. bool Control::playing()
  294. {
  295. return false;
  296. }
  297. void Control::set_stretch_controls(double stretch_s,int mode,double fftsize_s,double onset_detection_sensitivity)
  298. {
  299. gui_sliders.stretch_s=stretch_s;
  300. gui_sliders.mode_s=mode;
  301. gui_sliders.fftsize_s=fftsize_s;
  302. double stretch=1.0;
  303. switch(mode){
  304. case 0:
  305. stretch_s=pow(stretch_s,1.2);
  306. stretch=pow(10.0,stretch_s*4.0);
  307. break;
  308. case 1:
  309. stretch_s=pow(stretch_s,1.5);
  310. stretch=pow(10.0,stretch_s*18.0);
  311. break;
  312. case 2:
  313. stretch=1.0/pow(10.0,stretch_s*2.0);
  314. break;
  315. };
  316. fftsize_s=pow(fftsize_s,1.5);
  317. int bufsize=(int)(pow(2.0,fftsize_s*12.0)*512.0);
  318. bufsize=optimizebufsize(bufsize);
  319. process.stretch=stretch;
  320. process.bufsize=bufsize;
  321. process.onset_detection_sensitivity=onset_detection_sensitivity;
  322. };
  323. double Control::get_stretch_control(double stretch,int mode)
  324. {
  325. double result=1.0;
  326. switch(mode){
  327. case 0:
  328. if (stretch<1.0) return -1;
  329. stretch=(log(stretch)/log(10))*0.25;
  330. result=pow(stretch,1.0/1.2);
  331. break;
  332. case 1:
  333. if (stretch<1.0) return -1;
  334. stretch=(log(stretch)/log(10))/18.0;
  335. result=pow(stretch,1.0/1.5);
  336. break;
  337. case 2:
  338. if (stretch>1.0) return -1;
  339. result=2.0/(log(stretch)/log(10));
  340. break;
  341. };
  342. return result;
  343. };
  344. void Control::update_player_stretch()
  345. {
  346. return;
  347. //player->setrap(process.stretch);
  348. //player->set_onset_detection_sensitivity(process.onset_detection_sensitivity);
  349. };
  350. int abs_val(int x){
  351. if (x<0) return -x;
  352. else return x;
  353. };
  354. void Control::setPreBufferAmount(int x)
  355. {
  356. int temp = jlimit(0, 5, x);
  357. if (temp != m_prebuffer_amount)
  358. {
  359. m_prebuffer_amount = temp;
  360. m_recreate_buffering_source = true;
  361. }
  362. }
  363. double Control::getPreBufferAmountSeconds()
  364. {
  365. return 1.0;
  366. }
  367. void Control::setAudioVisualizer(AudioVisualiserComponent * comp)
  368. {
  369. //m_audiocallback.m_aviscomponent = comp;
  370. }
  371. void Control::setOutputAudioFileToRecord(File f)
  372. {
  373. m_audio_out_file = f;
  374. }
  375. int Control::get_optimized_updown(int n,bool up){
  376. int orig_n=n;
  377. while(true){
  378. n=orig_n;
  379. while (!(n%11)) n/=11;
  380. while (!(n%7)) n/=7;
  381. while (!(n%5)) n/=5;
  382. while (!(n%3)) n/=3;
  383. while (!(n%2)) n/=2;
  384. if (n<2) break;
  385. if (up) orig_n++;
  386. else orig_n--;
  387. if (orig_n<4) return 4;
  388. };
  389. return orig_n;
  390. };
  391. int Control::optimizebufsize(int n){
  392. int n1=get_optimized_updown(n,false);
  393. int n2=get_optimized_updown(n,true);
  394. if ((n-n1)<(n2-n)) return n1;
  395. else return n2;
  396. };
  397. void Control::set_window_type(FFTWindow window){
  398. window_type=window;
  399. //if (player) player->set_window_type(window);
  400. };
  401. RenderInfoRef Control::Render2(RenderParameters renpars)
  402. {
  403. RenderInfoRef rinfo = std::make_shared<RenderInfo>();
  404. auto bbparcopy = bbpar;
  405. auto processcopy = process;
  406. auto windowtypecopy = window_type;
  407. auto pparcopy = ppar;
  408. //auto volcopy = volume;
  409. auto ratecopy = m_stretch_source->getRate();
  410. auto fftsize = m_fft_size_to_use;
  411. AudioFormatManager* afm = m_afm;
  412. auto render_task = [rinfo,renpars,
  413. bbparcopy, processcopy, windowtypecopy, pparcopy, fftsize,ratecopy,afm]()mutable->void
  414. {
  415. double t0 = Time::getMillisecondCounterHiRes();
  416. if (renpars.pos2 < renpars.pos1)
  417. std::swap(renpars.pos1, renpars.pos2);
  418. if (renpars.pos2-renpars.pos1<0.0001)
  419. renpars.pos2+=0.0001;
  420. auto ai = std::make_unique<AInputS>(afm);
  421. if (!ai->openAudioFile(renpars.inaudio))
  422. {
  423. rinfo->m_txt = "Error: Could not open audio file (or file format not recognized) :" + renpars.inaudio.getFileName();
  424. return;
  425. }
  426. if (renpars.sampleRate == 0)
  427. renpars.sampleRate = ai->info.samplerate;
  428. WavAudioFormat audioformat;
  429. renpars.outaudio = renpars.outaudio.getNonexistentSibling();
  430. auto outstream = renpars.outaudio.createOutputStream();
  431. int wavbits = 16;
  432. if (renpars.wavformat == 1)
  433. wavbits = 24;
  434. if (renpars.wavformat == 2)
  435. wavbits = 32;
  436. renpars.numoutchans = jlimit(2, g_maxnumoutchans, renpars.numoutchans);
  437. StringPairArray metadata;
  438. metadata.set(WavAudioFormat::bwavOriginator,"PaulStretch3");
  439. /*
  440. metadata.set("NumCuePoints", "2");
  441. metadata.set("Cue0Offset", "44100");
  442. metadata.set("Cue0Identifier", "0");
  443. metadata.set("Cue1Offset", "88200");
  444. metadata.set("Cue1Identifier", "1");
  445. */
  446. AudioFormatWriter* writer = audioformat.createWriterFor(outstream, renpars.sampleRate, renpars.numoutchans, wavbits,
  447. metadata, 0);
  448. if (writer == nullptr)
  449. {
  450. delete outstream;
  451. rinfo->m_txt = "Could not create output file";
  452. return;
  453. }
  454. auto stretchsource = std::make_unique<StretchAudioSource>(renpars.numoutchans,afm);
  455. if (wavbits == 2)
  456. stretchsource->setClippingEnabled(renpars.clipFloatOutput);
  457. else stretchsource->setClippingEnabled(true);
  458. stretchsource->setAudioFile(renpars.inaudio);
  459. stretchsource->setPlayRange({renpars.pos1,renpars.pos2}, renpars.numLoops>0);
  460. stretchsource->setRate(ratecopy);
  461. stretchsource->val_MainVolume.setValue(renpars.voldb);
  462. stretchsource->setNumOutChannels(renpars.numoutchans);
  463. stretchsource->setProcessParameters(&pparcopy);
  464. stretchsource->setFFTSize(fftsize);
  465. int bufsize = 4096;
  466. AudioBuffer<float> procbuf(renpars.numoutchans,bufsize);
  467. AudioSourceChannelInfo asinfo(procbuf);
  468. stretchsource->prepareToPlay(bufsize, renpars.sampleRate);
  469. double render_time_limit = renpars.maxrenderlen;
  470. int64_t outputsamplecount = 0;
  471. int64_t outputlen = ai->info.samplerate*stretchsource->getOutputDurationSecondsForRange({ renpars.pos1,renpars.pos2 }, fftsize);
  472. rinfo->m_progress_percent = 0.01;
  473. stretchsource->setMaxLoops(renpars.numLoops);
  474. while(outputsamplecount<render_time_limit*renpars.sampleRate)
  475. {
  476. if (rinfo->m_cancel == true)
  477. {
  478. rinfo->m_txt = "Cancelled";
  479. break;
  480. }
  481. stretchsource->getNextAudioBlock(asinfo);
  482. writer->writeFromAudioSampleBuffer(procbuf, 0, bufsize);
  483. outputsamplecount +=bufsize;
  484. rinfo->m_progress_percent = 1.0 / outputlen*outputsamplecount;
  485. if (stretchsource->hasReachedEnd())
  486. {
  487. Logger::writeToLog("StretchSource has reached end");
  488. break;
  489. }
  490. if (outputsamplecount>=render_time_limit*ai->info.samplerate)
  491. {
  492. rinfo->m_txt = "Render stopped at time limit";
  493. break;
  494. }
  495. }
  496. delete writer;
  497. double t1 = Time::getMillisecondCounterHiRes();
  498. if (rinfo->m_cancel == false)
  499. {
  500. rinfo->m_elapsed_time = t1 - t0;
  501. if (rinfo->m_txt.isEmpty())
  502. rinfo->m_txt = "Done in "+String((t1-t0)/1000.0,1)+" seconds";
  503. }
  504. else rinfo->m_txt = "Cancelled";
  505. };
  506. std::thread th([rinfo,render_task, renpars]()mutable
  507. {
  508. render_task();
  509. MessageManager::callAsync([rinfo, renpars]()
  510. {
  511. renpars.completion_callback(rinfo);
  512. });
  513. });
  514. th.detach();
  515. return rinfo;
  516. }
  517. void Control::setPrebufferThreadPriority(int v)
  518. {
  519. m_prebufthreadprior = jlimit(4,6,v);
  520. }
  521. string Control::getfftsizestr(int fftsize){
  522. const int size=100;
  523. char tmp[size];tmp[size-1]=0;
  524. if (fftsize<1024.0) snprintf(tmp,size-1,"%d",fftsize);
  525. else if (fftsize<(1024.0*1024.0)) snprintf(tmp,size-1,"%.4gK",fftsize/1024.0);
  526. else if (fftsize<(1024.0*1024.0*1024.0)) snprintf(tmp,size-1,"%.4gM",fftsize/(1024.0*1024.0));
  527. else snprintf(tmp,size-1,"%.7gG",fftsize/(1024.0*1024.0*1024.0));
  528. return tmp;
  529. };
  530. void Control::update_process_parameters()
  531. {
  532. m_stretch_source->setProcessParameters(&ppar);
  533. //if (player)
  534. // player->set_process_parameters(&ppar,&bbpar);
  535. };
  536. #endif