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.
20 #include "JackAudioAdapter.h"
21 #include "JackLibSampleRateResampler.h"
30 void MeasureTable::Write(int time1
, int time2
, float r1
, float r2
, int pos1
, int pos2
)
32 int pos
= (++fCount
) % TABLE_MAX
;
33 fTable
[pos
].time1
= time1
;
34 fTable
[pos
].time2
= time2
;
37 fTable
[pos
].pos1
= pos1
;
38 fTable
[pos
].pos2
= pos2
;
41 void MeasureTable::Save(unsigned int fHostBufferSize
, unsigned int fHostSampleRate
, unsigned int fAdaptedSampleRate
, unsigned int fAdaptedBufferSize
)
44 FILE* file
= fopen("JackAudioAdapter.log", "w");
46 int max
= (fCount
) % TABLE_MAX
- 1;
47 for (int i
= 1; i
< max
; i
++)
49 fprintf(file
, "%d \t %d \t %d \t %f \t %f \t %d \t %d \n",
50 fTable
[i
].delta
, fTable
[i
].time1
, fTable
[i
].time2
,
51 fTable
[i
].r1
, fTable
[i
].r2
, fTable
[i
].pos1
, fTable
[i
].pos2
);
57 file
= fopen("AdapterTiming1.plot", "w");
58 fprintf(file
, "set multiplot\n");
59 fprintf(file
, "set grid\n");
60 fprintf(file
, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
61 ,float(fHostSampleRate
)/1000.f
, fHostBufferSize
, float(fAdaptedSampleRate
)/1000.f
, fAdaptedBufferSize
);
62 fprintf(file
, "set xlabel \"audio cycles\"\n");
63 fprintf(file
, "set ylabel \"frames\"\n");
64 fprintf(file
, "plot ");
65 sprintf(buffer
, "\"JackAudioAdapter.log\" using 2 title \"Ringbuffer error\" with lines,");
66 fprintf(file
, buffer
);
67 sprintf(buffer
, "\"JackAudioAdapter.log\" using 3 title \"Ringbuffer error with timing correction\" with lines");
68 fprintf(file
, buffer
);
70 fprintf(file
, "\n unset multiplot\n");
71 fprintf(file
, "set output 'AdapterTiming1.svg\n");
72 fprintf(file
, "set terminal svg\n");
74 fprintf(file
, "set multiplot\n");
75 fprintf(file
, "set grid\n");
76 fprintf(file
, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
77 ,float(fHostSampleRate
)/1000.f
, fHostBufferSize
, float(fAdaptedSampleRate
)/1000.f
, fAdaptedBufferSize
);
78 fprintf(file
, "set xlabel \"audio cycles\"\n");
79 fprintf(file
, "set ylabel \"frames\"\n");
80 fprintf(file
, "plot ");
81 sprintf(buffer
, "\"JackAudioAdapter.log\" using 2 title \"Consumer interrupt period\" with lines,");
82 fprintf(file
, buffer
);
83 sprintf(buffer
, "\"JackAudioAdapter.log\" using 3 title \"Producer interrupt period\" with lines\n");
84 fprintf(file
, buffer
);
85 fprintf(file
, "unset multiplot\n");
86 fprintf(file
, "unset output\n");
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 sprintf(buffer
, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,");
100 fprintf(file
, buffer
);
101 sprintf(buffer
, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines");
102 fprintf(file
, buffer
);
104 fprintf(file
, "\n unset multiplot\n");
105 fprintf(file
, "set output 'AdapterTiming2.svg\n");
106 fprintf(file
, "set terminal svg\n");
108 fprintf(file
, "set multiplot\n");
109 fprintf(file
, "set grid\n");
110 fprintf(file
, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
111 ,float(fHostSampleRate
)/1000.f
, fHostBufferSize
, float(fAdaptedSampleRate
)/1000.f
, fAdaptedBufferSize
);
112 fprintf(file
, "set xlabel \"audio cycles\"\n");
113 fprintf(file
, "set ylabel \"resampling ratio\"\n");
114 fprintf(file
, "plot ");
115 sprintf(buffer
, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,");
116 fprintf(file
, buffer
);
117 sprintf(buffer
, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines\n");
118 fprintf(file
, buffer
);
119 fprintf(file
, "unset multiplot\n");
120 fprintf(file
, "unset output\n");
125 file
= fopen("AdapterTiming3.plot", "w");
126 fprintf(file
, "set multiplot\n");
127 fprintf(file
, "set grid\n");
128 fprintf(file
, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
129 ,float(fHostSampleRate
)/1000.f
, fHostBufferSize
, float(fAdaptedSampleRate
)/1000.f
, fAdaptedBufferSize
);
130 fprintf(file
, "set xlabel \"audio cycles\"\n");
131 fprintf(file
, "set ylabel \"frames\"\n");
132 fprintf(file
, "plot ");
133 sprintf(buffer
, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,");
134 fprintf(file
, buffer
);
135 sprintf(buffer
, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines");
136 fprintf(file
, buffer
);
138 fprintf(file
, "\n unset multiplot\n");
139 fprintf(file
, "set output 'AdapterTiming3.svg\n");
140 fprintf(file
, "set terminal svg\n");
142 fprintf(file
, "set multiplot\n");
143 fprintf(file
, "set grid\n");
144 fprintf(file
, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
145 ,float(fHostSampleRate
)/1000.f
, fHostBufferSize
, float(fAdaptedSampleRate
)/1000.f
, fAdaptedBufferSize
);
146 fprintf(file
, "set xlabel \"audio cycles\"\n");
147 fprintf(file
, "set ylabel \"frames\"\n");
148 fprintf(file
, "plot ");
149 sprintf(buffer
, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,");
150 fprintf(file
, buffer
);
151 sprintf(buffer
, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines\n");
152 fprintf(file
, buffer
);
153 fprintf(file
, "unset multiplot\n");
154 fprintf(file
, "unset output\n");
161 void JackAudioAdapterInterface::GrowRingBufferSize()
163 fRingbufferCurSize
*= 2;
166 void JackAudioAdapterInterface::AdaptRingBufferSize()
168 if (fHostBufferSize
> fAdaptedBufferSize
)
169 fRingbufferCurSize
= 4 * fHostBufferSize
;
171 fRingbufferCurSize
= 4 * fAdaptedBufferSize
;
174 void JackAudioAdapterInterface::ResetRingBuffers()
176 if (fRingbufferCurSize
> DEFAULT_RB_SIZE
)
177 fRingbufferCurSize
= DEFAULT_RB_SIZE
;
179 for (int i
= 0; i
< fCaptureChannels
; i
++)
180 fCaptureRingBuffer
[i
]->Reset(fRingbufferCurSize
);
181 for (int i
= 0; i
< fPlaybackChannels
; i
++)
182 fPlaybackRingBuffer
[i
]->Reset(fRingbufferCurSize
);
185 void JackAudioAdapterInterface::Reset()
191 void JackAudioAdapterInterface::Create()
194 fCaptureRingBuffer
= new JackResampler
*[fCaptureChannels
];
195 fPlaybackRingBuffer
= new JackResampler
*[fPlaybackChannels
];
198 AdaptRingBufferSize();
199 jack_info("Ringbuffer automatic adaptative mode size = %d frames", fRingbufferCurSize
);
201 if (fRingbufferCurSize
> DEFAULT_RB_SIZE
)
202 fRingbufferCurSize
= DEFAULT_RB_SIZE
;
203 jack_info("Fixed ringbuffer size = %d frames", fRingbufferCurSize
);
206 for (int i
= 0; i
< fCaptureChannels
; i
++ ) {
207 fCaptureRingBuffer
[i
] = new JackLibSampleRateResampler(fQuality
);
208 fCaptureRingBuffer
[i
]->Reset(fRingbufferCurSize
);
210 for (int i
= 0; i
< fPlaybackChannels
; i
++ ) {
211 fPlaybackRingBuffer
[i
] = new JackLibSampleRateResampler(fQuality
);
212 fPlaybackRingBuffer
[i
]->Reset(fRingbufferCurSize
);
215 if (fCaptureChannels
> 0)
216 jack_log("ReadSpace = %ld", fCaptureRingBuffer
[0]->ReadSpace());
217 if (fPlaybackChannels
> 0)
218 jack_log("WriteSpace = %ld", fPlaybackRingBuffer
[0]->WriteSpace());
221 void JackAudioAdapterInterface::Destroy()
223 for (int i
= 0; i
< fCaptureChannels
; i
++ )
224 delete ( fCaptureRingBuffer
[i
] );
225 for (int i
= 0; i
< fPlaybackChannels
; i
++ )
226 delete ( fPlaybackRingBuffer
[i
] );
228 delete[] fCaptureRingBuffer
;
229 delete[] fPlaybackRingBuffer
;
232 int JackAudioAdapterInterface::PushAndPull(float** inputBuffer
, float** outputBuffer
, unsigned int frames
)
234 bool failure
= false;
237 // Finer estimation of the position in the ringbuffer
238 int delta_frames
= (fPullAndPushTime
> 0) ? (int)((float(long(GetMicroSeconds() - fPullAndPushTime
)) * float(fAdaptedSampleRate
)) / 1000000.f
) : 0;
242 // TODO : done like this just to avoid crash when input only or output only...
243 if (fCaptureChannels
> 0)
244 ratio
= fPIControler
.GetRatio(fCaptureRingBuffer
[0]->GetError() - delta_frames
);
245 else if (fPlaybackChannels
> 0)
246 ratio
= fPIControler
.GetRatio(fPlaybackRingBuffer
[0]->GetError() - delta_frames
);
249 if (fCaptureRingBuffer
[0] != NULL
)
250 fTable
.Write(fCaptureRingBuffer
[0]->GetError(), fCaptureRingBuffer
[0]->GetError() - delta_frames
, ratio
, 1/ratio
, fCaptureRingBuffer
[0]->ReadSpace(), fCaptureRingBuffer
[0]->ReadSpace());
253 // Push/pull from ringbuffer
254 for (int i
= 0; i
< fCaptureChannels
; i
++) {
255 fCaptureRingBuffer
[i
]->SetRatio(ratio
);
256 if (fCaptureRingBuffer
[i
]->WriteResample(inputBuffer
[i
], frames
) < frames
)
260 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
261 fPlaybackRingBuffer
[i
]->SetRatio(1/ratio
);
262 if (fPlaybackRingBuffer
[i
]->ReadResample(outputBuffer
[i
], frames
) < frames
)
265 // Reset all ringbuffers in case of failure
267 jack_error("JackAudioAdapterInterface::PushAndPull ringbuffer failure... reset");
269 GrowRingBufferSize();
270 jack_info("Ringbuffer size = %d frames", fRingbufferCurSize
);
279 int JackAudioAdapterInterface::PullAndPush(float** inputBuffer
, float** outputBuffer
, unsigned int frames
)
281 fPullAndPushTime
= GetMicroSeconds();
287 // Push/pull from ringbuffer
288 for (int i
= 0; i
< fCaptureChannels
; i
++) {
289 if (fCaptureRingBuffer
[i
]->Read(inputBuffer
[i
], frames
) < frames
)
293 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
294 if (fPlaybackRingBuffer
[i
]->Write(outputBuffer
[i
], frames
) < frames
)