outputbuffer.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. This file is part of QTau
  3. Copyright (C) 2013-2018 Tobias "Tomoko" Platen <tplaten@posteo.de>
  4. Copyright (C) 2013 digited <https://github.com/digited>
  5. Copyright (C) 2010-2013 HAL@ShurabaP <https://github.com/haruneko>
  6. QTau is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. SPDX-License-Identifier: GPL-3.0+
  17. */
  18. #include "audio/outputbuffer.h"
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22. #include <stdint.h>
  23. #include <sys/time.h>
  24. #define __devloglevel__ 4
  25. #define debugperf 0
  26. #define debugperf2 0
  27. uint32_t getTime() {
  28. struct timeval tv;
  29. gettimeofday(&tv, NULL);
  30. uint32_t ret = static_cast<uint32_t>(tv.tv_usec / 1000 + tv.tv_sec * 1000);
  31. return ret;
  32. }
  33. OutputBuffer::OutputBuffer(JackAudio* jack)
  34. {
  35. _buffersize=64*1024;
  36. _jackSamplerate = jack->getSamplerate();
  37. _ringbuffer = jack_ringbuffer_create(_buffersize);
  38. _sndfile = nullptr;
  39. _datacount=0;
  40. start();
  41. }
  42. void OutputBuffer::scheduleSynth(ISynth *synth)
  43. {
  44. if(_scheduledSynth) return;
  45. _datacount = 0;
  46. _runtime = 0;
  47. jack_ringbuffer_reset(_ringbuffer);
  48. open("/tmp/test.wav",44100);
  49. _scheduledSynth=synth;
  50. }
  51. void OutputBuffer::run()
  52. {
  53. int data_size = 1024*2;
  54. float* data = new float[data_size];
  55. uint32_t lasttime = getTime();
  56. while(1)
  57. {
  58. if(_scheduledSynth)
  59. {
  60. int end = _scheduledSynth->readData(data,data_size);
  61. if(end==0)
  62. {
  63. _scheduledSynth->readData(nullptr,0);
  64. _scheduledSynth= nullptr;
  65. close();
  66. continue;
  67. }
  68. int writespace = jack_ringbuffer_write_space(_ringbuffer);
  69. int size2 = data_size*sizeof(float);
  70. int sleepcount=0;
  71. while(writespace<2*size2)
  72. {
  73. if(!_playbackIsStable) emit startPlayback();
  74. _playbackIsStable = true;
  75. usleep(1000);
  76. sleepcount++;
  77. writespace = jack_ringbuffer_write_space(_ringbuffer);
  78. }
  79. uint32_t currenttime = getTime();
  80. uint32_t timedelta = currenttime-lasttime;
  81. lasttime=currenttime;
  82. if(debugperf) DEVLOG_DEBUG("sleepcount "+STR(sleepcount)+" writespace "+STR(writespace)+" timedelta "+STR(timedelta));
  83. _runtime += timedelta;
  84. uint32_t timedelta_max = (int)(data_size*1000/44100);
  85. if(debugperf2) if(timedelta>timedelta_max) DEVLOG_DEBUG("timedelta_max "+STR(timedelta_max)+" timedelta "+STR(timedelta-sleepcount));
  86. jack_ringbuffer_write(_ringbuffer,(char*)data,size2);
  87. sf_write_float(_sndfile,data,data_size);
  88. }
  89. else
  90. {
  91. usleep(20000); //nothing to do
  92. }
  93. }
  94. }
  95. //on synth start
  96. void OutputBuffer::open(QString fileName,int samplerate){
  97. if(_sndfile) sf_close(_sndfile);
  98. SF_INFO info;
  99. memset(&info,0,sizeof(info));
  100. info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
  101. info.samplerate = samplerate;
  102. info.channels = 1;
  103. _sndfile = sf_open(fileName.toUtf8().data(),SFM_WRITE,&info);
  104. if(_jackSamplerate!=samplerate)
  105. {
  106. DEVLOG_ERROR("resampler TODO\n");
  107. exit(1);
  108. }
  109. }
  110. void OutputBuffer::openReadFile(QString fileName)
  111. {
  112. SF_INFO info;
  113. memset(&info,0,sizeof(info));
  114. _sndfile = sf_open(fileName.toUtf8().data(),SFM_READ,&info);
  115. _offline = true;
  116. }
  117. //on synth end
  118. void OutputBuffer::close()
  119. {
  120. if(_sndfile) sf_close(_sndfile);
  121. _sndfile = nullptr;
  122. jack_ringbuffer_reset(_ringbuffer);
  123. _datacount = 0;
  124. }
  125. //other thread -- copy engine
  126. void OutputBuffer::readData(float *data, int size)
  127. {
  128. if(_offline && _sndfile)
  129. {
  130. int count = sf_readf_float(_sndfile,data,size);
  131. if(count==0)
  132. {
  133. DEVLOG_DEBUG("offline mode: stop playback");
  134. emit stopPlayback();
  135. close();
  136. }
  137. return;
  138. }
  139. //if(!_playbackIsStable) return; //do nothing
  140. unsigned int data_size = (unsigned int)size*sizeof(float);
  141. memset(data,0,data_size);
  142. unsigned int readspace = jack_ringbuffer_read_space(_ringbuffer);
  143. float filled = readspace*1.0/_buffersize;
  144. if(filled<0.5 && debugperf) DEVLOG_DEBUG("reading data "+STR(filled));
  145. if(!_playbackIsStable) return;
  146. if(readspace>=data_size)
  147. {
  148. jack_ringbuffer_read(_ringbuffer,(char*)data,data_size);
  149. }
  150. else
  151. {
  152. if(_scheduledSynth)
  153. {
  154. if(debugperf) DEVLOG_DEBUG("XRUN - cannot read from buffer");
  155. _xruncount++;
  156. }
  157. else
  158. {
  159. if(_playbackIsStable)
  160. {
  161. DEVLOG_DEBUG("end reached xruncount="+STR(_xruncount)+" cputime="+STR(_runtime));
  162. stopPlayback();
  163. _playbackIsStable=false;
  164. }
  165. }
  166. }
  167. }
  168. void OutputBuffer::reset()
  169. {
  170. jack_ringbuffer_reset(_ringbuffer);
  171. _datacount = 0;
  172. }