Jack2 1.9.8
|
00001 /* 00002 Copyright (C) 2008 Grame 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 00018 */ 00019 00020 #ifdef __APPLE__ 00021 #include <TargetConditionals.h> 00022 #endif 00023 00024 #include "JackAudioAdapter.h" 00025 #ifndef MY_TARGET_OS_IPHONE 00026 #include "JackLibSampleRateResampler.h" 00027 #endif 00028 #include "JackTime.h" 00029 #include <stdio.h> 00030 00031 namespace Jack 00032 { 00033 00034 #ifdef JACK_MONITOR 00035 00036 void MeasureTable::Write(int time1, int time2, float r1, float r2, int pos1, int pos2) 00037 { 00038 int pos = (++fCount) % TABLE_MAX; 00039 fTable[pos].time1 = time1; 00040 fTable[pos].time2 = time2; 00041 fTable[pos].r1 = r1; 00042 fTable[pos].r2 = r2; 00043 fTable[pos].pos1 = pos1; 00044 fTable[pos].pos2 = pos2; 00045 } 00046 00047 void MeasureTable::Save(unsigned int fHostBufferSize, unsigned int fHostSampleRate, unsigned int fAdaptedSampleRate, unsigned int fAdaptedBufferSize) 00048 { 00049 FILE* file = fopen("JackAudioAdapter.log", "w"); 00050 00051 int max = (fCount) % TABLE_MAX - 1; 00052 for (int i = 1; i < max; i++) { 00053 fprintf(file, "%d \t %d \t %d \t %f \t %f \t %d \t %d \n", 00054 fTable[i].delta, fTable[i].time1, fTable[i].time2, 00055 fTable[i].r1, fTable[i].r2, fTable[i].pos1, fTable[i].pos2); 00056 } 00057 fclose(file); 00058 00059 // No used for now 00060 // Adapter timing 1 00061 file = fopen("AdapterTiming1.plot", "w"); 00062 fprintf(file, "set multiplot\n"); 00063 fprintf(file, "set grid\n"); 00064 fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n" 00065 ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize); 00066 fprintf(file, "set xlabel \"audio cycles\"\n"); 00067 fprintf(file, "set ylabel \"frames\"\n"); 00068 fprintf(file, "plot "); 00069 fprintf(file, "\"JackAudioAdapter.log\" using 2 title \"Ringbuffer error\" with lines,"); 00070 fprintf(file, "\"JackAudioAdapter.log\" using 3 title \"Ringbuffer error with timing correction\" with lines"); 00071 00072 fprintf(file, "\n unset multiplot\n"); 00073 fprintf(file, "set output 'AdapterTiming1.svg\n"); 00074 fprintf(file, "set terminal svg\n"); 00075 00076 fprintf(file, "set multiplot\n"); 00077 fprintf(file, "set grid\n"); 00078 fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n" 00079 ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize); 00080 fprintf(file, "set xlabel \"audio cycles\"\n"); 00081 fprintf(file, "set ylabel \"frames\"\n"); 00082 fprintf(file, "plot "); 00083 fprintf(file, "\"JackAudioAdapter.log\" using 2 title \"Consumer interrupt period\" with lines,"); 00084 fprintf(file, "\"JackAudioAdapter.log\" using 3 title \"Producer interrupt period\" with lines\n"); 00085 fprintf(file, "unset multiplot\n"); 00086 fprintf(file, "unset output\n"); 00087 00088 fclose(file); 00089 00090 // Adapter timing 2 00091 file = fopen("AdapterTiming2.plot", "w"); 00092 fprintf(file, "set multiplot\n"); 00093 fprintf(file, "set grid\n"); 00094 fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n" 00095 ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize); 00096 fprintf(file, "set xlabel \"audio cycles\"\n"); 00097 fprintf(file, "set ylabel \"resampling ratio\"\n"); 00098 fprintf(file, "plot "); 00099 fprintf(file, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,"); 00100 fprintf(file, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines"); 00101 00102 fprintf(file, "\n unset multiplot\n"); 00103 fprintf(file, "set output 'AdapterTiming2.svg\n"); 00104 fprintf(file, "set terminal svg\n"); 00105 00106 fprintf(file, "set multiplot\n"); 00107 fprintf(file, "set grid\n"); 00108 fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n" 00109 ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize); 00110 fprintf(file, "set xlabel \"audio cycles\"\n"); 00111 fprintf(file, "set ylabel \"resampling ratio\"\n"); 00112 fprintf(file, "plot "); 00113 fprintf(file, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,"); 00114 fprintf(file, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines\n"); 00115 fprintf(file, "unset multiplot\n"); 00116 fprintf(file, "unset output\n"); 00117 00118 fclose(file); 00119 00120 // Adapter timing 3 00121 file = fopen("AdapterTiming3.plot", "w"); 00122 fprintf(file, "set multiplot\n"); 00123 fprintf(file, "set grid\n"); 00124 fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n" 00125 ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize); 00126 fprintf(file, "set xlabel \"audio cycles\"\n"); 00127 fprintf(file, "set ylabel \"frames\"\n"); 00128 fprintf(file, "plot "); 00129 fprintf(file, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,"); 00130 fprintf(file, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines"); 00131 00132 fprintf(file, "\n unset multiplot\n"); 00133 fprintf(file, "set output 'AdapterTiming3.svg\n"); 00134 fprintf(file, "set terminal svg\n"); 00135 00136 fprintf(file, "set multiplot\n"); 00137 fprintf(file, "set grid\n"); 00138 fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n" 00139 ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize); 00140 fprintf(file, "set xlabel \"audio cycles\"\n"); 00141 fprintf(file, "set ylabel \"frames\"\n"); 00142 fprintf(file, "plot "); 00143 fprintf(file, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,"); 00144 fprintf(file, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines\n"); 00145 fprintf(file, "unset multiplot\n"); 00146 fprintf(file, "unset output\n"); 00147 00148 fclose(file); 00149 } 00150 00151 #endif 00152 00153 void JackAudioAdapterInterface::GrowRingBufferSize() 00154 { 00155 fRingbufferCurSize *= 2; 00156 } 00157 00158 void JackAudioAdapterInterface::AdaptRingBufferSize() 00159 { 00160 if (fHostBufferSize > fAdaptedBufferSize) { 00161 fRingbufferCurSize = 4 * fHostBufferSize; 00162 } else { 00163 fRingbufferCurSize = 4 * fAdaptedBufferSize; 00164 } 00165 } 00166 00167 void JackAudioAdapterInterface::ResetRingBuffers() 00168 { 00169 if (fRingbufferCurSize > DEFAULT_RB_SIZE) { 00170 fRingbufferCurSize = DEFAULT_RB_SIZE; 00171 } 00172 00173 for (int i = 0; i < fCaptureChannels; i++) { 00174 fCaptureRingBuffer[i]->Reset(fRingbufferCurSize); 00175 } 00176 for (int i = 0; i < fPlaybackChannels; i++) { 00177 fPlaybackRingBuffer[i]->Reset(fRingbufferCurSize); 00178 } 00179 } 00180 00181 void JackAudioAdapterInterface::Reset() 00182 { 00183 ResetRingBuffers(); 00184 fRunning = false; 00185 } 00186 00187 #ifdef MY_TARGET_OS_IPHONE 00188 void JackAudioAdapterInterface::Create() 00189 {} 00190 #else 00191 void JackAudioAdapterInterface::Create() 00192 { 00193 //ringbuffers 00194 fCaptureRingBuffer = new JackResampler*[fCaptureChannels]; 00195 fPlaybackRingBuffer = new JackResampler*[fPlaybackChannels]; 00196 00197 if (fAdaptative) { 00198 AdaptRingBufferSize(); 00199 jack_info("Ringbuffer automatic adaptative mode size = %d frames", fRingbufferCurSize); 00200 } else { 00201 if (fRingbufferCurSize > DEFAULT_RB_SIZE) { 00202 fRingbufferCurSize = DEFAULT_RB_SIZE; 00203 } 00204 jack_info("Fixed ringbuffer size = %d frames", fRingbufferCurSize); 00205 } 00206 00207 for (int i = 0; i < fCaptureChannels; i++ ) { 00208 fCaptureRingBuffer[i] = new JackLibSampleRateResampler(fQuality); 00209 fCaptureRingBuffer[i]->Reset(fRingbufferCurSize); 00210 } 00211 for (int i = 0; i < fPlaybackChannels; i++ ) { 00212 fPlaybackRingBuffer[i] = new JackLibSampleRateResampler(fQuality); 00213 fPlaybackRingBuffer[i]->Reset(fRingbufferCurSize); 00214 } 00215 00216 if (fCaptureChannels > 0) { 00217 jack_log("ReadSpace = %ld", fCaptureRingBuffer[0]->ReadSpace()); 00218 } 00219 if (fPlaybackChannels > 0) { 00220 jack_log("WriteSpace = %ld", fPlaybackRingBuffer[0]->WriteSpace()); 00221 } 00222 } 00223 #endif 00224 00225 void JackAudioAdapterInterface::Destroy() 00226 { 00227 for (int i = 0; i < fCaptureChannels; i++) { 00228 delete(fCaptureRingBuffer[i]); 00229 } 00230 for (int i = 0; i < fPlaybackChannels; i++) { 00231 delete (fPlaybackRingBuffer[i]); 00232 } 00233 00234 delete[] fCaptureRingBuffer; 00235 delete[] fPlaybackRingBuffer; 00236 } 00237 00238 int JackAudioAdapterInterface::PushAndPull(float** inputBuffer, float** outputBuffer, unsigned int frames) 00239 { 00240 bool failure = false; 00241 fRunning = true; 00242 00243 // Finer estimation of the position in the ringbuffer 00244 int delta_frames = (fPullAndPushTime > 0) ? (int)((float(long(GetMicroSeconds() - fPullAndPushTime)) * float(fAdaptedSampleRate)) / 1000000.f) : 0; 00245 00246 double ratio = 1; 00247 00248 // TODO : done like this just to avoid crash when input only or output only... 00249 if (fCaptureChannels > 0) { 00250 ratio = fPIControler.GetRatio(fCaptureRingBuffer[0]->GetError() - delta_frames); 00251 } else if (fPlaybackChannels > 0) { 00252 ratio = fPIControler.GetRatio(fPlaybackRingBuffer[0]->GetError() - delta_frames); 00253 } 00254 00255 #ifdef JACK_MONITOR 00256 if (fCaptureRingBuffer && fCaptureRingBuffer[0] != NULL) 00257 fTable.Write(fCaptureRingBuffer[0]->GetError(), fCaptureRingBuffer[0]->GetError() - delta_frames, ratio, 1/ratio, fCaptureRingBuffer[0]->ReadSpace(), fCaptureRingBuffer[0]->ReadSpace()); 00258 #endif 00259 00260 // Push/pull from ringbuffer 00261 for (int i = 0; i < fCaptureChannels; i++) { 00262 fCaptureRingBuffer[i]->SetRatio(ratio); 00263 if (inputBuffer[i]) { 00264 if (fCaptureRingBuffer[i]->WriteResample(inputBuffer[i], frames) < frames) { 00265 failure = true; 00266 } 00267 } 00268 } 00269 00270 for (int i = 0; i < fPlaybackChannels; i++) { 00271 fPlaybackRingBuffer[i]->SetRatio(1/ratio); 00272 if (outputBuffer[i]) { 00273 if (fPlaybackRingBuffer[i]->ReadResample(outputBuffer[i], frames) < frames) { 00274 failure = true; 00275 } 00276 } 00277 } 00278 // Reset all ringbuffers in case of failure 00279 if (failure) { 00280 jack_error("JackAudioAdapterInterface::PushAndPull ringbuffer failure... reset"); 00281 if (fAdaptative) { 00282 GrowRingBufferSize(); 00283 jack_info("Ringbuffer size = %d frames", fRingbufferCurSize); 00284 } 00285 ResetRingBuffers(); 00286 return -1; 00287 } else { 00288 return 0; 00289 } 00290 } 00291 00292 int JackAudioAdapterInterface::PullAndPush(float** inputBuffer, float** outputBuffer, unsigned int frames) 00293 { 00294 fPullAndPushTime = GetMicroSeconds(); 00295 if (!fRunning) 00296 return 0; 00297 00298 int res = 0; 00299 00300 // Push/pull from ringbuffer 00301 for (int i = 0; i < fCaptureChannels; i++) { 00302 if (inputBuffer[i]) { 00303 if (fCaptureRingBuffer[i]->Read(inputBuffer[i], frames) < frames) { 00304 res = -1; 00305 } 00306 } 00307 } 00308 00309 for (int i = 0; i < fPlaybackChannels; i++) { 00310 if (outputBuffer[i]) { 00311 if (fPlaybackRingBuffer[i]->Write(outputBuffer[i], frames) < frames) { 00312 res = -1; 00313 } 00314 } 00315 } 00316 00317 return res; 00318 } 00319 00320 } // namespace