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.

416 lines
13KB

  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. #pragma once
  16. #include <string>
  17. #include "../JuceLibraryCode/JuceHeader.h"
  18. #include "InputS.h"
  19. #include <mutex>
  20. inline double ramp(int64_t pos, int64_t totallen, int64_t rampinlen, int64_t rampoutlen)
  21. {
  22. if (totallen < rampinlen + rampoutlen)
  23. return 1.0;
  24. if (pos < rampinlen)
  25. return 1.0 / rampinlen*pos;
  26. if (pos >= totallen - rampoutlen)
  27. return 1.0 - 1.0 / rampoutlen*(pos - totallen + rampoutlen);
  28. return 1.0;
  29. }
  30. class AInputS final : public InputS
  31. {
  32. public:
  33. AInputS(AudioFormatManager* mana) : m_manager(mana)
  34. {
  35. m_readbuf.setSize(2, 65536*2);
  36. m_readbuf.clear();
  37. m_crossfadebuf.setSize(2, 44100);
  38. m_crossfadebuf.clear();
  39. PlayRangeEndCallback=[](AInputS*){};
  40. }
  41. ~AInputS() {}
  42. void setAudioBuffer(AudioBuffer<float>* buf, int samplerate, int len)
  43. {
  44. ScopedLock locker(m_mutex);
  45. m_afreader = nullptr;
  46. m_using_memory_buffer = true;
  47. m_readbuf = *buf;
  48. info.nchannels = buf->getNumChannels();
  49. info.nsamples = len;
  50. info.samplerate = samplerate;
  51. m_currentsample = 0;
  52. m_loop_enabled = true;
  53. m_crossfadebuf.setSize(info.nchannels, m_crossfadebuf.getNumSamples());
  54. m_cached_file_range = { 0,len };
  55. seek(m_activerange.getStart(), true);
  56. updateXFadeCache();
  57. }
  58. virtual AudioBuffer<float>* getAudioBuffer() override
  59. {
  60. if (m_using_memory_buffer)
  61. return &m_readbuf;
  62. return nullptr;
  63. }
  64. bool openAudioFile(File file) override
  65. {
  66. m_silenceoutputted = 0;
  67. AudioFormatReader* reader = m_manager->createReaderFor(file);
  68. if (reader)
  69. {
  70. ScopedLock locker(m_mutex);
  71. m_using_memory_buffer = false;
  72. m_afreader = std::unique_ptr<AudioFormatReader>(reader);
  73. if (m_activerange.isEmpty())
  74. m_activerange = { 0.0,1.0 };
  75. m_currentsample = m_activerange.getStart()*info.nsamples;
  76. info.samplerate = (int)m_afreader->sampleRate;
  77. info.nchannels = m_afreader->numChannels;
  78. info.nsamples = m_afreader->lengthInSamples;
  79. if (m_readbuf.getNumChannels() < info.nchannels)
  80. {
  81. m_readbuf.setSize(info.nchannels, m_readbuf.getNumSamples());
  82. m_crossfadebuf.setSize(info.nchannels, m_crossfadebuf.getNumSamples());
  83. }
  84. updateXFadeCache();
  85. m_readbuf.clear();
  86. return true;
  87. }
  88. return false;
  89. }
  90. void close() override
  91. {
  92. m_afreader = nullptr;
  93. m_currentsample = 0;
  94. info.nchannels = 0;
  95. info.nsamples = 0;
  96. info.samplerate = 0;
  97. }
  98. int readNextBlock(AudioBuffer<float>& abuf, int nsmps, int numchans) override
  99. {
  100. ScopedLock locker(m_mutex);
  101. if (m_afreader == nullptr && m_using_memory_buffer == false)
  102. {
  103. jassert(false);
  104. return 0;
  105. }
  106. int inchans = 0;
  107. if (m_afreader)
  108. inchans = m_afreader->numChannels;
  109. else inchans = m_readbuf.getNumChannels();
  110. int64_t subsect_t0 = 0;
  111. int64_t subsect_t1 = 0;
  112. int64_t subsectlen = 0;
  113. int xfadelen = 0;
  114. auto updatesamplepositions = [&,this]()
  115. {
  116. subsect_t0 = (int64_t)(m_activerange.getStart()*info.nsamples);
  117. subsect_t1 = (int64_t)(m_activerange.getEnd()*info.nsamples);
  118. subsectlen = subsect_t1 - subsect_t0;
  119. xfadelen = m_xfadelen;
  120. if (xfadelen >= subsectlen)
  121. xfadelen = int(subsectlen - 2);
  122. };
  123. updatesamplepositions();
  124. auto getSampleLambda=[this](int64_t pos, int ch)
  125. {
  126. if (m_cached_file_range.contains(pos))
  127. return m_readbuf.getSample(ch, int(pos - m_cached_file_range.getStart()));
  128. else
  129. {
  130. Range<int64_t> activerange((int64_t)(m_activerange.getStart()*info.nsamples),
  131. (int64_t)(m_activerange.getEnd()*info.nsamples+1));
  132. Range<int64_t> possiblerange(pos, pos + m_readbuf.getNumSamples() + 0);
  133. m_cached_file_range = activerange.getIntersectionWith(possiblerange);
  134. m_afreader->read(&m_readbuf, 0, (int)m_cached_file_range.getLength(), pos, true, true);
  135. m_disk_read_count += m_cached_file_range.getLength()*m_afreader->numChannels;
  136. return m_readbuf.getSample(ch, int(pos - m_cached_file_range.getStart()));
  137. }
  138. };
  139. auto getCrossFadedSampleLambda=[this,&getSampleLambda](int64_t playpos, int chan, int64_t subt0, int64_t subt1, int xfadelen)
  140. {
  141. if (m_loop_enabled == false && playpos >= subt1)
  142. {
  143. return 0.0f;
  144. }
  145. if (playpos >= subt0 && playpos <= subt1 - xfadelen)
  146. return getSampleLambda(playpos, chan);
  147. if (playpos > (subt1 - xfadelen) && playpos<subt1)
  148. {
  149. int64_t fadeindex = playpos - subt1 + xfadelen;
  150. double fadeoutgain = 1.0 - (1.0 / (xfadelen - 0))*fadeindex;
  151. float s0 = (float)(getSampleLambda(playpos, chan)*fadeoutgain);
  152. double fadeingain = (1.0 / (xfadelen - 0))*fadeindex;
  153. int64_t playpos2 = playpos - subt1 + xfadelen;
  154. jassert(playpos2>=0 && playpos2<=xfadelen);
  155. float s1 = (float)(m_crossfadebuf.getSample(chan, (int)playpos2)*fadeingain);
  156. return s0 + s1;
  157. }
  158. ++m_silenceoutputted;
  159. return 0.0f;
  160. };
  161. float** smps = abuf.getArrayOfWritePointers();
  162. int readinc = 1;
  163. if (m_reverseplay)
  164. readinc = -1;
  165. for (int i = 0; i < nsmps; ++i)
  166. {
  167. float seekfadegain = 1.0f;
  168. if (m_seekfade.state == 1)
  169. {
  170. //Logger::writeToLog("Seek requested to pos " + String(m_seekfade.requestedpos));
  171. m_seekfade.state = 2;
  172. }
  173. if (m_seekfade.state == 2)
  174. {
  175. seekfadegain = 1.0 - (1.0 / m_seekfade.length*m_seekfade.counter);
  176. ++m_seekfade.counter;
  177. if (m_seekfade.counter >= m_seekfade.length)
  178. {
  179. //Logger::writeToLog("Doing seek " + String(m_seekfade.requestedpos));
  180. m_seekfade.counter = 0;
  181. m_seekfade.state = 3;
  182. if (m_seekfade.requestedrange.isEmpty() == false)
  183. {
  184. setActiveRangeImpl(m_seekfade.requestedrange);
  185. updatesamplepositions();
  186. if (m_activerange.contains(getCurrentPositionPercent()) == false)
  187. seekImpl(m_activerange.getStart());
  188. }
  189. }
  190. }
  191. if (m_seekfade.state == 3)
  192. {
  193. seekfadegain = 1.0 / m_seekfade.length*m_seekfade.counter;
  194. ++m_seekfade.counter;
  195. if (m_seekfade.counter >= m_seekfade.length)
  196. {
  197. //Logger::writeToLog("Seek cycle finished");
  198. m_seekfade.counter = 0;
  199. m_seekfade.state = 0;
  200. m_seekfade.requestedpos = 0.0;
  201. m_seekfade.requestedrange = Range<double>();
  202. }
  203. }
  204. jassert(seekfadegain >= 0.0f && seekfadegain<=1.0f);
  205. if (inchans == 1 && numchans > 0)
  206. {
  207. float sig = getCrossFadedSampleLambda(m_currentsample, 0, subsect_t0, subsect_t1, xfadelen);
  208. for (int j = 0; j < numchans; ++j)
  209. {
  210. smps[j][i] = sig*seekfadegain;
  211. }
  212. }
  213. else if (inchans > 1 && numchans > 1)
  214. {
  215. for (int j = 0; j < numchans; ++j)
  216. {
  217. int inchantouse = j % inchans;
  218. smps[j][i] = seekfadegain*getCrossFadedSampleLambda(m_currentsample, inchantouse,
  219. subsect_t0, subsect_t1,xfadelen);
  220. }
  221. }
  222. m_currentsample += readinc;
  223. if (m_loop_enabled == true)
  224. {
  225. if (m_reverseplay == false && m_currentsample >= subsect_t1)
  226. {
  227. m_currentsample = subsect_t0+xfadelen;
  228. ++m_loopcount;
  229. }
  230. else if (m_reverseplay == true && m_currentsample < subsect_t0)
  231. {
  232. m_currentsample = subsect_t1 - 1;
  233. }
  234. } else
  235. {
  236. if (m_reverseplay == false && m_currentsample == subsect_t1)
  237. PlayRangeEndCallback(this);
  238. else if (m_reverseplay == true && m_currentsample == subsect_t0)
  239. PlayRangeEndCallback(this);
  240. }
  241. }
  242. return nsmps;
  243. }
  244. void seekImpl(double pos)
  245. {
  246. if (m_using_memory_buffer == true)
  247. {
  248. jassert(m_readbuf.getNumSamples() > 0 && m_afreader == nullptr);
  249. m_loopcount = 0;
  250. m_silenceoutputted = 0;
  251. m_cache_misses = 0;
  252. m_currentsample = (int64_t)(pos*m_readbuf.getNumSamples());
  253. m_currentsample = jlimit<int64_t>(0, m_readbuf.getNumSamples(), m_currentsample);
  254. m_cached_file_range = { 0,m_readbuf.getNumSamples() };
  255. return;
  256. }
  257. //jassert(m_afreader!=nullptr);
  258. if (m_afreader == nullptr)
  259. return;
  260. m_loopcount = 0;
  261. m_silenceoutputted = 0;
  262. m_cache_misses = 0;
  263. m_currentsample = (int64_t)(pos*m_afreader->lengthInSamples);
  264. m_currentsample = jlimit<int64_t>(0, m_afreader->lengthInSamples, m_currentsample);
  265. //Logger::writeToLog("Seeking to " + String(m_currentsample));
  266. //if (m_cached_file_range.contains(info.currentsample)==false)
  267. m_cached_file_range = Range<int64_t>();
  268. updateXFadeCache();
  269. //m_cached_crossfade_range = Range<int64_t>();
  270. }
  271. void seek(double pos, bool immediate) override //0=start,1.0=end
  272. {
  273. ScopedLock locker(m_mutex);
  274. if (immediate == true)
  275. {
  276. seekImpl(pos);
  277. return;
  278. }
  279. if (m_seekfade.state == 0)
  280. {
  281. m_seekfade.state = 1;
  282. m_seekfade.counter = 0;
  283. }
  284. m_seekfade.length = 16384;
  285. m_seekfade.requestedpos = pos;
  286. }
  287. std::pair<Range<double>,Range<double>> getCachedRangesNormalized()
  288. {
  289. if (m_afreader == nullptr)
  290. return {};
  291. return { { jmap<double>((double)m_cached_file_range.getStart(),0,(double)info.nsamples,0.0,1.0),
  292. jmap<double>((double)m_cached_file_range.getEnd(), 0, (double)info.nsamples, 0.0, 1.0) },
  293. { jmap<double>((double)m_cached_crossfade_range.getStart(),0,(double)info.nsamples,0.0,1.0),
  294. jmap<double>((double)m_cached_crossfade_range.getEnd(), 0, (double)info.nsamples, 0.0, 1.0) } };
  295. }
  296. int getNumCacheMisses() { return m_cache_misses; }
  297. void updateXFadeCache()
  298. {
  299. if (m_xfadelen>m_crossfadebuf.getNumSamples())
  300. m_crossfadebuf.setSize(info.nchannels,m_xfadelen);
  301. if (m_afreader != nullptr && m_using_memory_buffer == false)
  302. m_afreader->read(&m_crossfadebuf, 0, m_xfadelen, (int64_t)(m_activerange.getStart()*info.nsamples), true, true);
  303. if (m_afreader == nullptr && m_using_memory_buffer == true)
  304. {
  305. for (int i=0;i<info.nchannels;++i)
  306. m_crossfadebuf.copyFrom(i, 0, m_readbuf, i, (int64_t)(m_activerange.getStart()*info.nsamples), m_xfadelen);
  307. }
  308. m_cached_crossfade_range =
  309. Range<int64_t>((int64_t)(m_activerange.getStart()*info.nsamples),(int64_t)(m_activerange.getStart()*info.nsamples+m_xfadelen));
  310. }
  311. void setActiveRangeImpl(Range<double> rng)
  312. {
  313. if (rng.getEnd() < rng.getStart())
  314. rng = { 0.0,1.0 };
  315. if (rng.isEmpty())
  316. rng = { 0.0,1.0 };
  317. m_activerange = rng;
  318. m_loopcount = 0;
  319. updateXFadeCache();
  320. }
  321. void setActiveRange(Range<double> rng) override
  322. {
  323. ScopedLock locker(m_mutex);
  324. /*
  325. if (rng.contains(getCurrentPositionPercent()))
  326. {
  327. setActiveRangeImpl(rng);
  328. return;
  329. }
  330. */
  331. m_seekfade.requestedrange = rng;
  332. if (m_seekfade.state == 0)
  333. {
  334. m_seekfade.counter = 0;
  335. m_seekfade.state = 1;
  336. }
  337. else
  338. {
  339. m_seekfade.state = 0;
  340. setActiveRangeImpl(rng);
  341. }
  342. m_seekfade.length = 2048;
  343. }
  344. void setLoopEnabled(bool b) override
  345. {
  346. m_loop_enabled = b;
  347. m_loopcount = 0;
  348. updateXFadeCache();
  349. }
  350. void setXFadeLenSeconds(double len)
  351. {
  352. if (info.samplerate==0)
  353. return;
  354. len = jlimit(0.0,1.0,len);
  355. int temp = (int)(len*info.samplerate);
  356. if (m_xfadelen!=temp)
  357. {
  358. m_xfadelen = temp;
  359. updateXFadeCache();
  360. }
  361. }
  362. Range<int64_t> getActiveRangeFrames()
  363. {
  364. if (info.nsamples == 0)
  365. return Range<int64_t>();
  366. return Range<int64_t>((int64_t)(m_activerange.getStart()*info.nsamples), (int64_t)(m_activerange.getEnd()*info.nsamples));
  367. }
  368. void setReversePlay(bool b)
  369. {
  370. m_reverseplay = b;
  371. }
  372. bool isReversed() { return m_reverseplay; }
  373. int64_t getLoopCount() { return m_loopcount; }
  374. private:
  375. std::function<void(AInputS*)> PlayRangeEndCallback;
  376. std::unique_ptr<AudioFormatReader> m_afreader;
  377. AudioBuffer<float> m_readbuf;
  378. AudioBuffer<float> m_crossfadebuf;
  379. Range<int64_t> m_cached_file_range;
  380. Range<int64_t> m_cached_crossfade_range;
  381. int m_cache_misses = 0;
  382. int m_fade_in = 512;
  383. int m_fade_out = 512;
  384. int m_xfadelen = 0;
  385. bool m_reverseplay = false;
  386. int64_t m_loopcount = 0;
  387. bool m_using_memory_buffer = true;
  388. AudioFormatManager* m_manager = nullptr;
  389. CriticalSection m_mutex;
  390. struct
  391. {
  392. int state = 0; // 0 inactive, 1 seek requested, 2 fade out, 3 fade in
  393. int counter = 0;
  394. int length = 44100;
  395. double requestedpos = 0.0;
  396. Range<double> requestedrange;
  397. } m_seekfade;
  398. };