jack2 codebase
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.

285 lines
11KB

  1. /*
  2. Copyright (C) 2008 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  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 for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include "JackAudioAdapter.h"
  16. #include <TargetConditionals.h>
  17. #ifndef TARGET_OS_IPHONE
  18. #include "JackLibSampleRateResampler.h"
  19. #endif
  20. #include "JackTime.h"
  21. #include <stdio.h>
  22. namespace Jack
  23. {
  24. #ifdef JACK_MONITOR
  25. void MeasureTable::Write(int time1, int time2, float r1, float r2, int pos1, int pos2)
  26. {
  27. int pos = (++fCount) % TABLE_MAX;
  28. fTable[pos].time1 = time1;
  29. fTable[pos].time2 = time2;
  30. fTable[pos].r1 = r1;
  31. fTable[pos].r2 = r2;
  32. fTable[pos].pos1 = pos1;
  33. fTable[pos].pos2 = pos2;
  34. }
  35. void MeasureTable::Save(unsigned int fHostBufferSize, unsigned int fHostSampleRate, unsigned int fAdaptedSampleRate, unsigned int fAdaptedBufferSize)
  36. {
  37. char buffer[1024];
  38. FILE* file = fopen("JackAudioAdapter.log", "w");
  39. int max = (fCount) % TABLE_MAX - 1;
  40. for (int i = 1; i < max; i++)
  41. {
  42. fprintf(file, "%d \t %d \t %d \t %f \t %f \t %d \t %d \n",
  43. fTable[i].delta, fTable[i+1].time1 - fTable[i].time1,
  44. fTable[i+1].time2 - fTable[i].time2,
  45. fTable[i].r1, fTable[i].r2, fTable[i].pos1, fTable[i].pos2);
  46. }
  47. fclose(file);
  48. // Adapter timing 1
  49. file = fopen("AdapterTiming1.plot", "w");
  50. fprintf(file, "set multiplot\n");
  51. fprintf(file, "set grid\n");
  52. fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
  53. ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
  54. fprintf(file, "set xlabel \"audio cycles\"\n");
  55. fprintf(file, "set ylabel \"frames\"\n");
  56. fprintf(file, "plot ");
  57. sprintf(buffer, "\"JackAudioAdapter.log\" using 2 title \"Consumer interrupt period\" with lines,");
  58. fprintf(file, buffer);
  59. sprintf(buffer, "\"JackAudioAdapter.log\" using 3 title \"Producer interrupt period\" with lines");
  60. fprintf(file, buffer);
  61. fprintf(file, "\n unset multiplot\n");
  62. fprintf(file, "set output 'AdapterTiming1.pdf\n");
  63. fprintf(file, "set terminal pdf\n");
  64. fprintf(file, "set multiplot\n");
  65. fprintf(file, "set grid\n");
  66. fprintf(file, "set title \"Audio adapter timing\"\n");
  67. fprintf(file, "set xlabel \"audio cycles\"\n");
  68. fprintf(file, "set ylabel \"frames\"\n");
  69. fprintf(file, "plot ");
  70. sprintf(buffer, "\"JackAudioAdapter.log\" using 2 title \"Consumer interrupt period\" with lines,");
  71. fprintf(file, buffer);
  72. sprintf(buffer, "\"JackAudioAdapter.log\" using 3 title \"Producer interrupt period\" with lines");
  73. fprintf(file, buffer);
  74. fclose(file);
  75. // Adapter timing 2
  76. file = fopen("AdapterTiming2.plot", "w");
  77. fprintf(file, "set multiplot\n");
  78. fprintf(file, "set grid\n");
  79. fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
  80. ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
  81. fprintf(file, "set xlabel \"audio cycles\"\n");
  82. fprintf(file, "set ylabel \"resampling ratio\"\n");
  83. fprintf(file, "plot ");
  84. sprintf(buffer, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,");
  85. fprintf(file, buffer);
  86. sprintf(buffer, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines");
  87. fprintf(file, buffer);
  88. fprintf(file, "\n unset multiplot\n");
  89. fprintf(file, "set output 'AdapterTiming2.pdf\n");
  90. fprintf(file, "set terminal pdf\n");
  91. fprintf(file, "set multiplot\n");
  92. fprintf(file, "set grid\n");
  93. fprintf(file, "set title \"Audio adapter timing\"\n");
  94. fprintf(file, "set xlabel \"audio cycles\"\n");
  95. fprintf(file, "set ylabel \"resampling ratio\"\n");
  96. fprintf(file, "plot ");
  97. sprintf(buffer, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,");
  98. fprintf(file, buffer);
  99. sprintf(buffer, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines");
  100. fprintf(file, buffer);
  101. fclose(file);
  102. // Adapter timing 3
  103. file = fopen("AdapterTiming3.plot", "w");
  104. fprintf(file, "set multiplot\n");
  105. fprintf(file, "set grid\n");
  106. fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
  107. ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
  108. fprintf(file, "set xlabel \"audio cycles\"\n");
  109. fprintf(file, "set ylabel \"frames\"\n");
  110. fprintf(file, "plot ");
  111. sprintf(buffer, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,");
  112. fprintf(file, buffer);
  113. sprintf(buffer, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines");
  114. fprintf(file, buffer);
  115. fprintf(file, "\n unset multiplot\n");
  116. fprintf(file, "set output 'AdapterTiming3.pdf\n");
  117. fprintf(file, "set terminal pdf\n");
  118. fprintf(file, "set multiplot\n");
  119. fprintf(file, "set grid\n");
  120. fprintf(file, "set title \"Audio adapter timing\"\n");
  121. fprintf(file, "set xlabel \"audio cycles\"\n");
  122. fprintf(file, "set ylabel \"frames\"\n");
  123. fprintf(file, "plot ");
  124. sprintf(buffer, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,");
  125. fprintf(file, buffer);
  126. sprintf(buffer, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines");
  127. fprintf(file, buffer);
  128. fclose(file);
  129. }
  130. #endif
  131. void JackAudioAdapterInterface::ResetRingBuffers()
  132. {
  133. for (int i = 0; i < fCaptureChannels; i++)
  134. fCaptureRingBuffer[i]->Reset();
  135. for (int i = 0; i < fPlaybackChannels; i++)
  136. fPlaybackRingBuffer[i]->Reset();
  137. }
  138. void JackAudioAdapterInterface::ResampleFactor ( jack_time_t& frame1, jack_time_t& frame2 )
  139. {
  140. jack_time_t time = GetMicroSeconds();
  141. if (!fRunning) {
  142. // Init DLL
  143. fRunning = true;
  144. fHostDLL.Init(time);
  145. fAdaptedDLL.Init(time);
  146. frame1 = 1;
  147. frame2 = 1;
  148. } else {
  149. // DLL
  150. fAdaptedDLL.IncFrame(time);
  151. jack_nframes_t time1 = fHostDLL.Time2Frames(time);
  152. jack_nframes_t time2 = fAdaptedDLL.Time2Frames(time);
  153. frame1 = time1;
  154. frame2 = time2;
  155. jack_log("JackAudioAdapterInterface::ResampleFactor time1 = %ld time2 = %ld src_ratio_input = %f src_ratio_output = %f",
  156. long(time1), long(time2), double(time1) / double(time2), double(time2) / double(time1));
  157. }
  158. }
  159. void JackAudioAdapterInterface::Reset()
  160. {
  161. ResetRingBuffers();
  162. fRunning = false;
  163. }
  164. #ifdef TARGET_OS_IPHONE
  165. void JackAudioAdapterInterface::Create()
  166. {}
  167. #else
  168. void JackAudioAdapterInterface::Create()
  169. {
  170. //ringbuffers
  171. fCaptureRingBuffer = new JackResampler*[fCaptureChannels];
  172. fPlaybackRingBuffer = new JackResampler*[fPlaybackChannels];
  173. for (int i = 0; i < fCaptureChannels; i++ )
  174. fCaptureRingBuffer[i] = new JackLibSampleRateResampler(fQuality, fRingbufferSize);
  175. for (int i = 0; i < fPlaybackChannels; i++ )
  176. fPlaybackRingBuffer[i] = new JackLibSampleRateResampler(fQuality, fRingbufferSize);
  177. if (fCaptureChannels > 0)
  178. jack_log("ReadSpace = %ld", fCaptureRingBuffer[0]->ReadSpace());
  179. if (fPlaybackChannels > 0)
  180. jack_log("WriteSpace = %ld", fPlaybackRingBuffer[0]->WriteSpace());
  181. }
  182. #endif
  183. void JackAudioAdapterInterface::Destroy()
  184. {
  185. for (int i = 0; i < fCaptureChannels; i++ )
  186. delete ( fCaptureRingBuffer[i] );
  187. for (int i = 0; i < fPlaybackChannels; i++ )
  188. delete ( fPlaybackRingBuffer[i] );
  189. delete[] fCaptureRingBuffer;
  190. delete[] fPlaybackRingBuffer;
  191. }
  192. int JackAudioAdapterInterface::PushAndPull(float** inputBuffer, float** outputBuffer, unsigned int frames)
  193. {
  194. bool failure = false;
  195. jack_time_t time1, time2;
  196. ResampleFactor(time1, time2);
  197. // Push/pull from ringbuffer
  198. for (int i = 0; i < fCaptureChannels; i++) {
  199. fCaptureRingBuffer[i]->SetRatio(time1, time2);
  200. if (fCaptureRingBuffer[i]->WriteResample(inputBuffer[i], frames) < frames)
  201. failure = true;
  202. }
  203. for (int i = 0; i < fPlaybackChannels; i++) {
  204. fPlaybackRingBuffer[i]->SetRatio(time2, time1);
  205. if (fPlaybackRingBuffer[i]->ReadResample(outputBuffer[i], frames) < frames)
  206. failure = true;
  207. }
  208. #ifdef JACK_MONITOR
  209. fTable.Write(time1, time2, double(time1) / double(time2), double(time2) / double(time1),
  210. fCaptureRingBuffer[0]->ReadSpace(), fPlaybackRingBuffer[0]->WriteSpace());
  211. #endif
  212. // Reset all ringbuffers in case of failure
  213. if (failure) {
  214. jack_error("JackAudioAdapterInterface::PushAndPull ringbuffer failure... reset");
  215. ResetRingBuffers();
  216. return -1;
  217. } else {
  218. return 0;
  219. }
  220. }
  221. int JackAudioAdapterInterface::PullAndPush(float** inputBuffer, float** outputBuffer, unsigned int frames)
  222. {
  223. bool failure = false;
  224. fHostDLL.IncFrame(GetMicroSeconds());
  225. // Push/pull from ringbuffer
  226. for (int i = 0; i < fCaptureChannels; i++) {
  227. if (fCaptureRingBuffer[i]->Read(inputBuffer[i], frames) < frames)
  228. failure = true;
  229. }
  230. for (int i = 0; i < fPlaybackChannels; i++) {
  231. if (fPlaybackRingBuffer[i]->Write(outputBuffer[i], frames) < frames)
  232. failure = true;
  233. }
  234. // Reset all ringbuffers in case of failure
  235. if (failure) {
  236. jack_error("JackCallbackAudioAdapter::PullAndPush ringbuffer failure... reset");
  237. Reset();
  238. return -1;
  239. } else {
  240. return 0;
  241. }
  242. }
  243. } // namespace