2 Copyright (C) 2008 Grame
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.
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.
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.
21 #include <TargetConditionals.h>
24 #include "JackAudioAdapter.h"
25 #ifndef MY_TARGET_OS_IPHONE
26 #include "JackLibSampleRateResampler.h"
29 #include "JackError.h"
37 void MeasureTable::Write(int time1
, int time2
, float r1
, float r2
, int pos1
, int pos2
)
39 int pos
= (++fCount
) % TABLE_MAX
;
40 fTable
[pos
].time1
= time1
;
41 fTable
[pos
].time2
= time2
;
44 fTable
[pos
].pos1
= pos1
;
45 fTable
[pos
].pos2
= pos2
;
48 void MeasureTable::Save(unsigned int fHostBufferSize
, unsigned int fHostSampleRate
, unsigned int fAdaptedSampleRate
, unsigned int fAdaptedBufferSize
)
50 FILE* file
= fopen("JackAudioAdapter.log", "w");
52 int max
= (fCount
) % TABLE_MAX
- 1;
53 for (int i
= 1; i
< max
; i
++) {
54 fprintf(file
, "%d \t %d \t %d \t %f \t %f \t %d \t %d \n",
55 fTable
[i
].delta
, fTable
[i
].time1
, fTable
[i
].time2
,
56 fTable
[i
].r1
, fTable
[i
].r2
, fTable
[i
].pos1
, fTable
[i
].pos2
);
62 file
= fopen("AdapterTiming1.plot", "w");
63 fprintf(file
, "set multiplot\n");
64 fprintf(file
, "set grid\n");
65 fprintf(file
, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
66 ,float(fHostSampleRate
)/1000.f
, fHostBufferSize
, float(fAdaptedSampleRate
)/1000.f
, fAdaptedBufferSize
);
67 fprintf(file
, "set xlabel \"audio cycles\"\n");
68 fprintf(file
, "set ylabel \"frames\"\n");
69 fprintf(file
, "plot ");
70 fprintf(file
, "\"JackAudioAdapter.log\" using 2 title \"Ringbuffer error\" with lines,");
71 fprintf(file
, "\"JackAudioAdapter.log\" using 3 title \"Ringbuffer error with timing correction\" with lines");
73 fprintf(file
, "\n unset multiplot\n");
74 fprintf(file
, "set output 'AdapterTiming1.svg\n");
75 fprintf(file
, "set terminal svg\n");
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 \"frames\"\n");
83 fprintf(file
, "plot ");
84 fprintf(file
, "\"JackAudioAdapter.log\" using 2 title \"Consumer interrupt period\" with lines,");
85 fprintf(file
, "\"JackAudioAdapter.log\" using 3 title \"Producer interrupt period\" with lines\n");
86 fprintf(file
, "unset multiplot\n");
87 fprintf(file
, "unset output\n");
92 file
= fopen("AdapterTiming2.plot", "w");
93 fprintf(file
, "set multiplot\n");
94 fprintf(file
, "set grid\n");
95 fprintf(file
, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
96 ,float(fHostSampleRate
)/1000.f
, fHostBufferSize
, float(fAdaptedSampleRate
)/1000.f
, fAdaptedBufferSize
);
97 fprintf(file
, "set xlabel \"audio cycles\"\n");
98 fprintf(file
, "set ylabel \"resampling ratio\"\n");
99 fprintf(file
, "plot ");
100 fprintf(file
, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,");
101 fprintf(file
, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines");
103 fprintf(file
, "\n unset multiplot\n");
104 fprintf(file
, "set output 'AdapterTiming2.svg\n");
105 fprintf(file
, "set terminal svg\n");
107 fprintf(file
, "set multiplot\n");
108 fprintf(file
, "set grid\n");
109 fprintf(file
, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
110 ,float(fHostSampleRate
)/1000.f
, fHostBufferSize
, float(fAdaptedSampleRate
)/1000.f
, fAdaptedBufferSize
);
111 fprintf(file
, "set xlabel \"audio cycles\"\n");
112 fprintf(file
, "set ylabel \"resampling ratio\"\n");
113 fprintf(file
, "plot ");
114 fprintf(file
, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,");
115 fprintf(file
, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines\n");
116 fprintf(file
, "unset multiplot\n");
117 fprintf(file
, "unset output\n");
122 file
= fopen("AdapterTiming3.plot", "w");
123 fprintf(file
, "set multiplot\n");
124 fprintf(file
, "set grid\n");
125 fprintf(file
, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
126 ,float(fHostSampleRate
)/1000.f
, fHostBufferSize
, float(fAdaptedSampleRate
)/1000.f
, fAdaptedBufferSize
);
127 fprintf(file
, "set xlabel \"audio cycles\"\n");
128 fprintf(file
, "set ylabel \"frames\"\n");
129 fprintf(file
, "plot ");
130 fprintf(file
, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,");
131 fprintf(file
, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines");
133 fprintf(file
, "\n unset multiplot\n");
134 fprintf(file
, "set output 'AdapterTiming3.svg\n");
135 fprintf(file
, "set terminal svg\n");
137 fprintf(file
, "set multiplot\n");
138 fprintf(file
, "set grid\n");
139 fprintf(file
, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
140 ,float(fHostSampleRate
)/1000.f
, fHostBufferSize
, float(fAdaptedSampleRate
)/1000.f
, fAdaptedBufferSize
);
141 fprintf(file
, "set xlabel \"audio cycles\"\n");
142 fprintf(file
, "set ylabel \"frames\"\n");
143 fprintf(file
, "plot ");
144 fprintf(file
, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,");
145 fprintf(file
, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines\n");
146 fprintf(file
, "unset multiplot\n");
147 fprintf(file
, "unset output\n");
154 void JackAudioAdapterInterface::GrowRingBufferSize()
156 fRingbufferCurSize
*= 2;
159 void JackAudioAdapterInterface::AdaptRingBufferSize()
161 if (fHostBufferSize
> fAdaptedBufferSize
) {
162 fRingbufferCurSize
= 4 * fHostBufferSize
;
164 fRingbufferCurSize
= 4 * fAdaptedBufferSize
;
168 void JackAudioAdapterInterface::ResetRingBuffers()
170 if (fRingbufferCurSize
> DEFAULT_RB_SIZE
) {
171 fRingbufferCurSize
= DEFAULT_RB_SIZE
;
174 for (int i
= 0; i
< fCaptureChannels
; i
++) {
175 fCaptureRingBuffer
[i
]->Reset(fRingbufferCurSize
);
177 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
178 fPlaybackRingBuffer
[i
]->Reset(fRingbufferCurSize
);
182 void JackAudioAdapterInterface::Reset()
188 #ifdef MY_TARGET_OS_IPHONE
189 void JackAudioAdapterInterface::Create()
192 void JackAudioAdapterInterface::Create()
195 fCaptureRingBuffer
= new JackResampler
*[fCaptureChannels
];
196 fPlaybackRingBuffer
= new JackResampler
*[fPlaybackChannels
];
199 AdaptRingBufferSize();
200 jack_info("Ringbuffer automatic adaptative mode size = %d frames", fRingbufferCurSize
);
202 if (fRingbufferCurSize
> DEFAULT_RB_SIZE
) {
203 fRingbufferCurSize
= DEFAULT_RB_SIZE
;
205 jack_info("Fixed ringbuffer size = %d frames", fRingbufferCurSize
);
208 for (int i
= 0; i
< fCaptureChannels
; i
++ ) {
209 fCaptureRingBuffer
[i
] = new JackLibSampleRateResampler(fQuality
);
210 fCaptureRingBuffer
[i
]->Reset(fRingbufferCurSize
);
212 for (int i
= 0; i
< fPlaybackChannels
; i
++ ) {
213 fPlaybackRingBuffer
[i
] = new JackLibSampleRateResampler(fQuality
);
214 fPlaybackRingBuffer
[i
]->Reset(fRingbufferCurSize
);
217 if (fCaptureChannels
> 0) {
218 jack_log("ReadSpace = %ld", fCaptureRingBuffer
[0]->ReadSpace());
220 if (fPlaybackChannels
> 0) {
221 jack_log("WriteSpace = %ld", fPlaybackRingBuffer
[0]->WriteSpace());
226 void JackAudioAdapterInterface::Destroy()
228 for (int i
= 0; i
< fCaptureChannels
; i
++) {
229 delete(fCaptureRingBuffer
[i
]);
231 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
232 delete (fPlaybackRingBuffer
[i
]);
235 delete[] fCaptureRingBuffer
;
236 delete[] fPlaybackRingBuffer
;
239 int JackAudioAdapterInterface::PushAndPull(float** inputBuffer
, float** outputBuffer
, unsigned int frames
)
241 bool failure
= false;
244 // Finer estimation of the position in the ringbuffer
245 int delta_frames
= (fPullAndPushTime
> 0) ? (int)((float(long(GetMicroSeconds() - fPullAndPushTime
)) * float(fAdaptedSampleRate
)) / 1000000.f
) : 0;
249 // TODO : done like this just to avoid crash when input only or output only...
250 if (fCaptureChannels
> 0) {
251 ratio
= fPIControler
.GetRatio(fCaptureRingBuffer
[0]->GetError() - delta_frames
);
252 } else if (fPlaybackChannels
> 0) {
253 ratio
= fPIControler
.GetRatio(fPlaybackRingBuffer
[0]->GetError() - delta_frames
);
257 if (fCaptureRingBuffer
&& fCaptureRingBuffer
[0] != NULL
)
258 fTable
.Write(fCaptureRingBuffer
[0]->GetError(), fCaptureRingBuffer
[0]->GetError() - delta_frames
, ratio
, 1/ratio
, fCaptureRingBuffer
[0]->ReadSpace(), fCaptureRingBuffer
[0]->ReadSpace());
261 // Push/pull from ringbuffer
262 for (int i
= 0; i
< fCaptureChannels
; i
++) {
263 fCaptureRingBuffer
[i
]->SetRatio(ratio
);
264 if (inputBuffer
[i
]) {
265 if (fCaptureRingBuffer
[i
]->WriteResample(inputBuffer
[i
], frames
) < frames
) {
271 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
272 fPlaybackRingBuffer
[i
]->SetRatio(1/ratio
);
273 if (outputBuffer
[i
]) {
274 if (fPlaybackRingBuffer
[i
]->ReadResample(outputBuffer
[i
], frames
) < frames
) {
279 // Reset all ringbuffers in case of failure
281 jack_error("JackAudioAdapterInterface::PushAndPull ringbuffer failure... reset");
283 GrowRingBufferSize();
284 jack_info("Ringbuffer size = %d frames", fRingbufferCurSize
);
293 int JackAudioAdapterInterface::PullAndPush(float** inputBuffer
, float** outputBuffer
, unsigned int frames
)
295 fPullAndPushTime
= GetMicroSeconds();
302 // Push/pull from ringbuffer
303 for (int i
= 0; i
< fCaptureChannels
; i
++) {
304 if (inputBuffer
[i
]) {
305 if (fCaptureRingBuffer
[i
]->Read(inputBuffer
[i
], frames
) < frames
) {
311 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
312 if (outputBuffer
[i
]) {
313 if (fPlaybackRingBuffer
[i
]->Write(outputBuffer
[i
], frames
) < frames
) {
322 int JackAudioAdapterInterface::SetHostBufferSize(jack_nframes_t buffer_size
)
324 fHostBufferSize
= buffer_size
;
326 AdaptRingBufferSize();
331 int JackAudioAdapterInterface::SetAdaptedBufferSize(jack_nframes_t buffer_size
)
333 fAdaptedBufferSize
= buffer_size
;
335 AdaptRingBufferSize();
340 int JackAudioAdapterInterface::SetBufferSize(jack_nframes_t buffer_size
)
342 SetHostBufferSize(buffer_size
);
343 SetAdaptedBufferSize(buffer_size
);
347 int JackAudioAdapterInterface::SetHostSampleRate(jack_nframes_t sample_rate
)
349 fHostSampleRate
= sample_rate
;
350 fPIControler
.Init(double(fHostSampleRate
) / double(fAdaptedSampleRate
));
354 int JackAudioAdapterInterface::SetAdaptedSampleRate(jack_nframes_t sample_rate
)
356 fAdaptedSampleRate
= sample_rate
;
357 fPIControler
.Init(double(fHostSampleRate
) / double(fAdaptedSampleRate
));
361 int JackAudioAdapterInterface::SetSampleRate(jack_nframes_t sample_rate
)
363 SetHostSampleRate(sample_rate
);
364 SetAdaptedSampleRate(sample_rate
);
368 void JackAudioAdapterInterface::SetInputs(int inputs
)
370 jack_log("JackAudioAdapterInterface::SetInputs %d", inputs
);
371 fCaptureChannels
= inputs
;
374 void JackAudioAdapterInterface::SetOutputs(int outputs
)
376 jack_log("JackAudioAdapterInterface::SetOutputs %d", outputs
);
377 fPlaybackChannels
= outputs
;
380 int JackAudioAdapterInterface::GetInputs()
382 //jack_log("JackAudioAdapterInterface::GetInputs %d", fCaptureChannels);
383 return fCaptureChannels
;
386 int JackAudioAdapterInterface::GetOutputs()
388 //jack_log ("JackAudioAdapterInterface::GetOutputs %d", fPlaybackChannels);
389 return fPlaybackChannels
;