Jack2  1.9.8
JackAudioAdapterInterface.cpp
1 /*
2 Copyright (C) 2008 Grame
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 
20 #ifdef __APPLE__
21 #include <TargetConditionals.h>
22 #endif
23 
24 #include "JackAudioAdapter.h"
25 #ifndef MY_TARGET_OS_IPHONE
26 #include "JackLibSampleRateResampler.h"
27 #endif
28 #include "JackTime.h"
29 #include <stdio.h>
30 
31 namespace Jack
32 {
33 
34 #ifdef JACK_MONITOR
35 
36  void MeasureTable::Write(int time1, int time2, float r1, float r2, int pos1, int pos2)
37  {
38  int pos = (++fCount) % TABLE_MAX;
39  fTable[pos].time1 = time1;
40  fTable[pos].time2 = time2;
41  fTable[pos].r1 = r1;
42  fTable[pos].r2 = r2;
43  fTable[pos].pos1 = pos1;
44  fTable[pos].pos2 = pos2;
45  }
46 
47  void MeasureTable::Save(unsigned int fHostBufferSize, unsigned int fHostSampleRate, unsigned int fAdaptedSampleRate, unsigned int fAdaptedBufferSize)
48  {
49  FILE* file = fopen("JackAudioAdapter.log", "w");
50 
51  int max = (fCount) % TABLE_MAX - 1;
52  for (int i = 1; i < max; i++) {
53  fprintf(file, "%d \t %d \t %d \t %f \t %f \t %d \t %d \n",
54  fTable[i].delta, fTable[i].time1, fTable[i].time2,
55  fTable[i].r1, fTable[i].r2, fTable[i].pos1, fTable[i].pos2);
56  }
57  fclose(file);
58 
59  // No used for now
60  // Adapter timing 1
61  file = fopen("AdapterTiming1.plot", "w");
62  fprintf(file, "set multiplot\n");
63  fprintf(file, "set grid\n");
64  fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
65  ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
66  fprintf(file, "set xlabel \"audio cycles\"\n");
67  fprintf(file, "set ylabel \"frames\"\n");
68  fprintf(file, "plot ");
69  fprintf(file, "\"JackAudioAdapter.log\" using 2 title \"Ringbuffer error\" with lines,");
70  fprintf(file, "\"JackAudioAdapter.log\" using 3 title \"Ringbuffer error with timing correction\" with lines");
71 
72  fprintf(file, "\n unset multiplot\n");
73  fprintf(file, "set output 'AdapterTiming1.svg\n");
74  fprintf(file, "set terminal svg\n");
75 
76  fprintf(file, "set multiplot\n");
77  fprintf(file, "set grid\n");
78  fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
79  ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
80  fprintf(file, "set xlabel \"audio cycles\"\n");
81  fprintf(file, "set ylabel \"frames\"\n");
82  fprintf(file, "plot ");
83  fprintf(file, "\"JackAudioAdapter.log\" using 2 title \"Consumer interrupt period\" with lines,");
84  fprintf(file, "\"JackAudioAdapter.log\" using 3 title \"Producer interrupt period\" with lines\n");
85  fprintf(file, "unset multiplot\n");
86  fprintf(file, "unset output\n");
87 
88  fclose(file);
89 
90  // Adapter timing 2
91  file = fopen("AdapterTiming2.plot", "w");
92  fprintf(file, "set multiplot\n");
93  fprintf(file, "set grid\n");
94  fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
95  ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
96  fprintf(file, "set xlabel \"audio cycles\"\n");
97  fprintf(file, "set ylabel \"resampling ratio\"\n");
98  fprintf(file, "plot ");
99  fprintf(file, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,");
100  fprintf(file, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines");
101 
102  fprintf(file, "\n unset multiplot\n");
103  fprintf(file, "set output 'AdapterTiming2.svg\n");
104  fprintf(file, "set terminal svg\n");
105 
106  fprintf(file, "set multiplot\n");
107  fprintf(file, "set grid\n");
108  fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
109  ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
110  fprintf(file, "set xlabel \"audio cycles\"\n");
111  fprintf(file, "set ylabel \"resampling ratio\"\n");
112  fprintf(file, "plot ");
113  fprintf(file, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,");
114  fprintf(file, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines\n");
115  fprintf(file, "unset multiplot\n");
116  fprintf(file, "unset output\n");
117 
118  fclose(file);
119 
120  // Adapter timing 3
121  file = fopen("AdapterTiming3.plot", "w");
122  fprintf(file, "set multiplot\n");
123  fprintf(file, "set grid\n");
124  fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
125  ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
126  fprintf(file, "set xlabel \"audio cycles\"\n");
127  fprintf(file, "set ylabel \"frames\"\n");
128  fprintf(file, "plot ");
129  fprintf(file, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,");
130  fprintf(file, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines");
131 
132  fprintf(file, "\n unset multiplot\n");
133  fprintf(file, "set output 'AdapterTiming3.svg\n");
134  fprintf(file, "set terminal svg\n");
135 
136  fprintf(file, "set multiplot\n");
137  fprintf(file, "set grid\n");
138  fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
139  ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
140  fprintf(file, "set xlabel \"audio cycles\"\n");
141  fprintf(file, "set ylabel \"frames\"\n");
142  fprintf(file, "plot ");
143  fprintf(file, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,");
144  fprintf(file, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines\n");
145  fprintf(file, "unset multiplot\n");
146  fprintf(file, "unset output\n");
147 
148  fclose(file);
149  }
150 
151 #endif
152 
153  void JackAudioAdapterInterface::GrowRingBufferSize()
154  {
155  fRingbufferCurSize *= 2;
156  }
157 
158  void JackAudioAdapterInterface::AdaptRingBufferSize()
159  {
160  if (fHostBufferSize > fAdaptedBufferSize) {
161  fRingbufferCurSize = 4 * fHostBufferSize;
162  } else {
163  fRingbufferCurSize = 4 * fAdaptedBufferSize;
164  }
165  }
166 
167  void JackAudioAdapterInterface::ResetRingBuffers()
168  {
169  if (fRingbufferCurSize > DEFAULT_RB_SIZE) {
170  fRingbufferCurSize = DEFAULT_RB_SIZE;
171  }
172 
173  for (int i = 0; i < fCaptureChannels; i++) {
174  fCaptureRingBuffer[i]->Reset(fRingbufferCurSize);
175  }
176  for (int i = 0; i < fPlaybackChannels; i++) {
177  fPlaybackRingBuffer[i]->Reset(fRingbufferCurSize);
178  }
179  }
180 
181  void JackAudioAdapterInterface::Reset()
182  {
183  ResetRingBuffers();
184  fRunning = false;
185  }
186 
187 #ifdef MY_TARGET_OS_IPHONE
188  void JackAudioAdapterInterface::Create()
189  {}
190 #else
191  void JackAudioAdapterInterface::Create()
192  {
193  //ringbuffers
194  fCaptureRingBuffer = new JackResampler*[fCaptureChannels];
195  fPlaybackRingBuffer = new JackResampler*[fPlaybackChannels];
196 
197  if (fAdaptative) {
198  AdaptRingBufferSize();
199  jack_info("Ringbuffer automatic adaptative mode size = %d frames", fRingbufferCurSize);
200  } else {
201  if (fRingbufferCurSize > DEFAULT_RB_SIZE) {
202  fRingbufferCurSize = DEFAULT_RB_SIZE;
203  }
204  jack_info("Fixed ringbuffer size = %d frames", fRingbufferCurSize);
205  }
206 
207  for (int i = 0; i < fCaptureChannels; i++ ) {
208  fCaptureRingBuffer[i] = new JackLibSampleRateResampler(fQuality);
209  fCaptureRingBuffer[i]->Reset(fRingbufferCurSize);
210  }
211  for (int i = 0; i < fPlaybackChannels; i++ ) {
212  fPlaybackRingBuffer[i] = new JackLibSampleRateResampler(fQuality);
213  fPlaybackRingBuffer[i]->Reset(fRingbufferCurSize);
214  }
215 
216  if (fCaptureChannels > 0) {
217  jack_log("ReadSpace = %ld", fCaptureRingBuffer[0]->ReadSpace());
218  }
219  if (fPlaybackChannels > 0) {
220  jack_log("WriteSpace = %ld", fPlaybackRingBuffer[0]->WriteSpace());
221  }
222  }
223 #endif
224 
225  void JackAudioAdapterInterface::Destroy()
226  {
227  for (int i = 0; i < fCaptureChannels; i++) {
228  delete(fCaptureRingBuffer[i]);
229  }
230  for (int i = 0; i < fPlaybackChannels; i++) {
231  delete (fPlaybackRingBuffer[i]);
232  }
233 
234  delete[] fCaptureRingBuffer;
235  delete[] fPlaybackRingBuffer;
236  }
237 
238  int JackAudioAdapterInterface::PushAndPull(float** inputBuffer, float** outputBuffer, unsigned int frames)
239  {
240  bool failure = false;
241  fRunning = true;
242 
243  // Finer estimation of the position in the ringbuffer
244  int delta_frames = (fPullAndPushTime > 0) ? (int)((float(long(GetMicroSeconds() - fPullAndPushTime)) * float(fAdaptedSampleRate)) / 1000000.f) : 0;
245 
246  double ratio = 1;
247 
248  // TODO : done like this just to avoid crash when input only or output only...
249  if (fCaptureChannels > 0) {
250  ratio = fPIControler.GetRatio(fCaptureRingBuffer[0]->GetError() - delta_frames);
251  } else if (fPlaybackChannels > 0) {
252  ratio = fPIControler.GetRatio(fPlaybackRingBuffer[0]->GetError() - delta_frames);
253  }
254 
255  #ifdef JACK_MONITOR
256  if (fCaptureRingBuffer && fCaptureRingBuffer[0] != NULL)
257  fTable.Write(fCaptureRingBuffer[0]->GetError(), fCaptureRingBuffer[0]->GetError() - delta_frames, ratio, 1/ratio, fCaptureRingBuffer[0]->ReadSpace(), fCaptureRingBuffer[0]->ReadSpace());
258  #endif
259 
260  // Push/pull from ringbuffer
261  for (int i = 0; i < fCaptureChannels; i++) {
262  fCaptureRingBuffer[i]->SetRatio(ratio);
263  if (inputBuffer[i]) {
264  if (fCaptureRingBuffer[i]->WriteResample(inputBuffer[i], frames) < frames) {
265  failure = true;
266  }
267  }
268  }
269 
270  for (int i = 0; i < fPlaybackChannels; i++) {
271  fPlaybackRingBuffer[i]->SetRatio(1/ratio);
272  if (outputBuffer[i]) {
273  if (fPlaybackRingBuffer[i]->ReadResample(outputBuffer[i], frames) < frames) {
274  failure = true;
275  }
276  }
277  }
278  // Reset all ringbuffers in case of failure
279  if (failure) {
280  jack_error("JackAudioAdapterInterface::PushAndPull ringbuffer failure... reset");
281  if (fAdaptative) {
282  GrowRingBufferSize();
283  jack_info("Ringbuffer size = %d frames", fRingbufferCurSize);
284  }
285  ResetRingBuffers();
286  return -1;
287  } else {
288  return 0;
289  }
290  }
291 
292  int JackAudioAdapterInterface::PullAndPush(float** inputBuffer, float** outputBuffer, unsigned int frames)
293  {
294  fPullAndPushTime = GetMicroSeconds();
295  if (!fRunning)
296  return 0;
297 
298  int res = 0;
299 
300  // Push/pull from ringbuffer
301  for (int i = 0; i < fCaptureChannels; i++) {
302  if (inputBuffer[i]) {
303  if (fCaptureRingBuffer[i]->Read(inputBuffer[i], frames) < frames) {
304  res = -1;
305  }
306  }
307  }
308 
309  for (int i = 0; i < fPlaybackChannels; i++) {
310  if (outputBuffer[i]) {
311  if (fPlaybackRingBuffer[i]->Write(outputBuffer[i], frames) < frames) {
312  res = -1;
313  }
314  }
315  }
316 
317  return res;
318  }
319 
320 } // namespace