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.pdf\n");
72 fprintf(file
, "set terminal pdf\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");
84 fprintf(file
, buffer
);
89 file
= fopen("AdapterTiming2.plot", "w");
90 fprintf(file
, "set multiplot\n");
91 fprintf(file
, "set grid\n");
92 fprintf(file
, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
93 ,float(fHostSampleRate
)/1000.f
, fHostBufferSize
, float(fAdaptedSampleRate
)/1000.f
, fAdaptedBufferSize
);
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
);
102 fprintf(file
, "\n unset multiplot\n");
103 fprintf(file
, "set output 'AdapterTiming2.pdf\n");
104 fprintf(file
, "set terminal pdf\n");
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 sprintf(buffer
, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,");
114 fprintf(file
, buffer
);
115 sprintf(buffer
, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines");
116 fprintf(file
, buffer
);
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 sprintf(buffer
, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,");
130 fprintf(file
, buffer
);
131 sprintf(buffer
, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines");
132 fprintf(file
, buffer
);
134 fprintf(file
, "\n unset multiplot\n");
135 fprintf(file
, "set output 'AdapterTiming3.pdf\n");
136 fprintf(file
, "set terminal pdf\n");
138 fprintf(file
, "set multiplot\n");
139 fprintf(file
, "set grid\n");
140 fprintf(file
, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
141 ,float(fHostSampleRate
)/1000.f
, fHostBufferSize
, float(fAdaptedSampleRate
)/1000.f
, fAdaptedBufferSize
);
142 fprintf(file
, "set xlabel \"audio cycles\"\n");
143 fprintf(file
, "set ylabel \"frames\"\n");
144 fprintf(file
, "plot ");
145 sprintf(buffer
, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,");
146 fprintf(file
, buffer
);
147 sprintf(buffer
, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines");
148 fprintf(file
, buffer
);
155 void JackAudioAdapterInterface::GrowRingBufferSize()
157 fRingbufferCurSize
*= 2;
160 void JackAudioAdapterInterface::AdaptRingBufferSize()
162 if (fHostBufferSize
> fAdaptedBufferSize
)
163 fRingbufferCurSize
= 4 * fHostBufferSize
;
165 fRingbufferCurSize
= 4 * fAdaptedBufferSize
;
168 void JackAudioAdapterInterface::ResetRingBuffers()
170 if (fRingbufferCurSize
> DEFAULT_RB_SIZE
)
171 fRingbufferCurSize
= DEFAULT_RB_SIZE
;
173 for (int i
= 0; i
< fCaptureChannels
; i
++)
174 fCaptureRingBuffer
[i
]->Reset(fRingbufferCurSize
);
175 for (int i
= 0; i
< fPlaybackChannels
; i
++)
176 fPlaybackRingBuffer
[i
]->Reset(fRingbufferCurSize
);
179 void JackAudioAdapterInterface::Reset()
185 void JackAudioAdapterInterface::Create()
188 fCaptureRingBuffer
= new JackResampler
*[fCaptureChannels
];
189 fPlaybackRingBuffer
= new JackResampler
*[fPlaybackChannels
];
192 AdaptRingBufferSize();
193 jack_info("Ringbuffer automatic adaptative mode size = %d frames", fRingbufferCurSize
);
195 if (fRingbufferCurSize
> DEFAULT_RB_SIZE
)
196 fRingbufferCurSize
= DEFAULT_RB_SIZE
;
197 jack_info("Fixed ringbuffer size = %d frames", fRingbufferCurSize
);
200 for (int i
= 0; i
< fCaptureChannels
; i
++ ) {
201 fCaptureRingBuffer
[i
] = new JackLibSampleRateResampler(fQuality
);
202 fCaptureRingBuffer
[i
]->Reset(fRingbufferCurSize
);
204 for (int i
= 0; i
< fPlaybackChannels
; i
++ ) {
205 fPlaybackRingBuffer
[i
] = new JackLibSampleRateResampler(fQuality
);
206 fPlaybackRingBuffer
[i
]->Reset(fRingbufferCurSize
);
209 if (fCaptureChannels
> 0)
210 jack_log("ReadSpace = %ld", fCaptureRingBuffer
[0]->ReadSpace());
211 if (fPlaybackChannels
> 0)
212 jack_log("WriteSpace = %ld", fPlaybackRingBuffer
[0]->WriteSpace());
215 void JackAudioAdapterInterface::Destroy()
217 for (int i
= 0; i
< fCaptureChannels
; i
++ )
218 delete ( fCaptureRingBuffer
[i
] );
219 for (int i
= 0; i
< fPlaybackChannels
; i
++ )
220 delete ( fPlaybackRingBuffer
[i
] );
222 delete[] fCaptureRingBuffer
;
223 delete[] fPlaybackRingBuffer
;
226 int JackAudioAdapterInterface::PushAndPull(float** inputBuffer
, float** outputBuffer
, unsigned int frames
)
228 bool failure
= false;
231 // Finer estimation of the position in the ringbuffer
232 int delta_frames
= (fPullAndPushTime
> 0) ? (int)((float(long(GetMicroSeconds() - fPullAndPushTime
)) * float(fAdaptedSampleRate
)) / 1000000.f
) : 0;
236 // TODO : done like this just to avoid crash when input only or output only...
237 if (fCaptureChannels
> 0)
238 ratio
= fPIControler
.GetRatio(fCaptureRingBuffer
[0]->GetError() - delta_frames
);
239 else if (fPlaybackChannels
> 0)
240 ratio
= fPIControler
.GetRatio(fPlaybackRingBuffer
[0]->GetError() - delta_frames
);
243 if (fCaptureRingBuffer
[0] != NULL
)
244 fTable
.Write(fCaptureRingBuffer
[0]->GetError(), fCaptureRingBuffer
[0]->GetError() - delta_frames
, ratio
, 1/ratio
, fCaptureRingBuffer
[0]->ReadSpace(), fCaptureRingBuffer
[0]->ReadSpace());
247 // Push/pull from ringbuffer
248 for (int i
= 0; i
< fCaptureChannels
; i
++) {
249 fCaptureRingBuffer
[i
]->SetRatio(ratio
);
250 if (fCaptureRingBuffer
[i
]->WriteResample(inputBuffer
[i
], frames
) < frames
)
254 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
255 fPlaybackRingBuffer
[i
]->SetRatio(1/ratio
);
256 if (fPlaybackRingBuffer
[i
]->ReadResample(outputBuffer
[i
], frames
) < frames
)
259 // Reset all ringbuffers in case of failure
261 jack_error("JackAudioAdapterInterface::PushAndPull ringbuffer failure... reset");
263 GrowRingBufferSize();
264 jack_info("Ringbuffer size = %d frames", fRingbufferCurSize
);
273 int JackAudioAdapterInterface::PullAndPush(float** inputBuffer
, float** outputBuffer
, unsigned int frames
)
275 fPullAndPushTime
= GetMicroSeconds();
281 // Push/pull from ringbuffer
282 for (int i
= 0; i
< fCaptureChannels
; i
++) {
283 if (fCaptureRingBuffer
[i
]->Read(inputBuffer
[i
], frames
) < frames
)
287 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
288 if (fPlaybackRingBuffer
[i
]->Write(outputBuffer
[i
], frames
) < frames
)