Jack2 1.9.6
|
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 #include "JackAudioAdapter.h" 00021 #include "JackLibSampleRateResampler.h" 00022 #include "JackTime.h" 00023 #include <stdio.h> 00024 00025 namespace Jack 00026 { 00027 00028 #ifdef JACK_MONITOR 00029 00030 void MeasureTable::Write(int time1, int time2, float r1, float r2, int pos1, int pos2) 00031 { 00032 int pos = (++fCount) % TABLE_MAX; 00033 fTable[pos].time1 = time1; 00034 fTable[pos].time2 = time2; 00035 fTable[pos].r1 = r1; 00036 fTable[pos].r2 = r2; 00037 fTable[pos].pos1 = pos1; 00038 fTable[pos].pos2 = pos2; 00039 } 00040 00041 void MeasureTable::Save(unsigned int fHostBufferSize, unsigned int fHostSampleRate, unsigned int fAdaptedSampleRate, unsigned int fAdaptedBufferSize) 00042 { 00043 char buffer[1024]; 00044 FILE* file = fopen("JackAudioAdapter.log", "w"); 00045 00046 int max = (fCount) % TABLE_MAX - 1; 00047 for (int i = 1; i < max; i++) 00048 { 00049 fprintf(file, "%d \t %d \t %d \t %f \t %f \t %d \t %d \n", 00050 fTable[i].delta, fTable[i].time1, fTable[i].time2, 00051 fTable[i].r1, fTable[i].r2, fTable[i].pos1, fTable[i].pos2); 00052 } 00053 fclose(file); 00054 00055 // No used for now 00056 // Adapter timing 1 00057 file = fopen("AdapterTiming1.plot", "w"); 00058 fprintf(file, "set multiplot\n"); 00059 fprintf(file, "set grid\n"); 00060 fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n" 00061 ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize); 00062 fprintf(file, "set xlabel \"audio cycles\"\n"); 00063 fprintf(file, "set ylabel \"frames\"\n"); 00064 fprintf(file, "plot "); 00065 sprintf(buffer, "\"JackAudioAdapter.log\" using 2 title \"Ringbuffer error\" with lines,"); 00066 fprintf(file, buffer); 00067 sprintf(buffer, "\"JackAudioAdapter.log\" using 3 title \"Ringbuffer error with timing correction\" with lines"); 00068 fprintf(file, buffer); 00069 00070 fprintf(file, "\n unset multiplot\n"); 00071 fprintf(file, "set output 'AdapterTiming1.svg\n"); 00072 fprintf(file, "set terminal svg\n"); 00073 00074 fprintf(file, "set multiplot\n"); 00075 fprintf(file, "set grid\n"); 00076 fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n" 00077 ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize); 00078 fprintf(file, "set xlabel \"audio cycles\"\n"); 00079 fprintf(file, "set ylabel \"frames\"\n"); 00080 fprintf(file, "plot "); 00081 sprintf(buffer, "\"JackAudioAdapter.log\" using 2 title \"Consumer interrupt period\" with lines,"); 00082 fprintf(file, buffer); 00083 sprintf(buffer, "\"JackAudioAdapter.log\" using 3 title \"Producer interrupt period\" with lines\n"); 00084 fprintf(file, buffer); 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 sprintf(buffer, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,"); 00100 fprintf(file, buffer); 00101 sprintf(buffer, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines"); 00102 fprintf(file, buffer); 00103 00104 fprintf(file, "\n unset multiplot\n"); 00105 fprintf(file, "set output 'AdapterTiming2.svg\n"); 00106 fprintf(file, "set terminal svg\n"); 00107 00108 fprintf(file, "set multiplot\n"); 00109 fprintf(file, "set grid\n"); 00110 fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n" 00111 ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize); 00112 fprintf(file, "set xlabel \"audio cycles\"\n"); 00113 fprintf(file, "set ylabel \"resampling ratio\"\n"); 00114 fprintf(file, "plot "); 00115 sprintf(buffer, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,"); 00116 fprintf(file, buffer); 00117 sprintf(buffer, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines\n"); 00118 fprintf(file, buffer); 00119 fprintf(file, "unset multiplot\n"); 00120 fprintf(file, "unset output\n"); 00121 00122 fclose(file); 00123 00124 // Adapter timing 3 00125 file = fopen("AdapterTiming3.plot", "w"); 00126 fprintf(file, "set multiplot\n"); 00127 fprintf(file, "set grid\n"); 00128 fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n" 00129 ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize); 00130 fprintf(file, "set xlabel \"audio cycles\"\n"); 00131 fprintf(file, "set ylabel \"frames\"\n"); 00132 fprintf(file, "plot "); 00133 sprintf(buffer, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,"); 00134 fprintf(file, buffer); 00135 sprintf(buffer, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines"); 00136 fprintf(file, buffer); 00137 00138 fprintf(file, "\n unset multiplot\n"); 00139 fprintf(file, "set output 'AdapterTiming3.svg\n"); 00140 fprintf(file, "set terminal svg\n"); 00141 00142 fprintf(file, "set multiplot\n"); 00143 fprintf(file, "set grid\n"); 00144 fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n" 00145 ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize); 00146 fprintf(file, "set xlabel \"audio cycles\"\n"); 00147 fprintf(file, "set ylabel \"frames\"\n"); 00148 fprintf(file, "plot "); 00149 sprintf(buffer, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,"); 00150 fprintf(file, buffer); 00151 sprintf(buffer, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines\n"); 00152 fprintf(file, buffer); 00153 fprintf(file, "unset multiplot\n"); 00154 fprintf(file, "unset output\n"); 00155 00156 fclose(file); 00157 } 00158 00159 #endif 00160 00161 void JackAudioAdapterInterface::GrowRingBufferSize() 00162 { 00163 fRingbufferCurSize *= 2; 00164 } 00165 00166 void JackAudioAdapterInterface::AdaptRingBufferSize() 00167 { 00168 if (fHostBufferSize > fAdaptedBufferSize) 00169 fRingbufferCurSize = 4 * fHostBufferSize; 00170 else 00171 fRingbufferCurSize = 4 * fAdaptedBufferSize; 00172 } 00173 00174 void JackAudioAdapterInterface::ResetRingBuffers() 00175 { 00176 if (fRingbufferCurSize > DEFAULT_RB_SIZE) 00177 fRingbufferCurSize = DEFAULT_RB_SIZE; 00178 00179 for (int i = 0; i < fCaptureChannels; i++) 00180 fCaptureRingBuffer[i]->Reset(fRingbufferCurSize); 00181 for (int i = 0; i < fPlaybackChannels; i++) 00182 fPlaybackRingBuffer[i]->Reset(fRingbufferCurSize); 00183 } 00184 00185 void JackAudioAdapterInterface::Reset() 00186 { 00187 ResetRingBuffers(); 00188 fRunning = false; 00189 } 00190 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 jack_info("Fixed ringbuffer size = %d frames", fRingbufferCurSize); 00204 } 00205 00206 for (int i = 0; i < fCaptureChannels; i++ ) { 00207 fCaptureRingBuffer[i] = new JackLibSampleRateResampler(fQuality); 00208 fCaptureRingBuffer[i]->Reset(fRingbufferCurSize); 00209 } 00210 for (int i = 0; i < fPlaybackChannels; i++ ) { 00211 fPlaybackRingBuffer[i] = new JackLibSampleRateResampler(fQuality); 00212 fPlaybackRingBuffer[i]->Reset(fRingbufferCurSize); 00213 } 00214 00215 if (fCaptureChannels > 0) 00216 jack_log("ReadSpace = %ld", fCaptureRingBuffer[0]->ReadSpace()); 00217 if (fPlaybackChannels > 0) 00218 jack_log("WriteSpace = %ld", fPlaybackRingBuffer[0]->WriteSpace()); 00219 } 00220 00221 void JackAudioAdapterInterface::Destroy() 00222 { 00223 for (int i = 0; i < fCaptureChannels; i++ ) 00224 delete ( fCaptureRingBuffer[i] ); 00225 for (int i = 0; i < fPlaybackChannels; i++ ) 00226 delete ( fPlaybackRingBuffer[i] ); 00227 00228 delete[] fCaptureRingBuffer; 00229 delete[] fPlaybackRingBuffer; 00230 } 00231 00232 int JackAudioAdapterInterface::PushAndPull(float** inputBuffer, float** outputBuffer, unsigned int frames) 00233 { 00234 bool failure = false; 00235 fRunning = true; 00236 00237 // Finer estimation of the position in the ringbuffer 00238 int delta_frames = (fPullAndPushTime > 0) ? (int)((float(long(GetMicroSeconds() - fPullAndPushTime)) * float(fAdaptedSampleRate)) / 1000000.f) : 0; 00239 00240 double ratio = 1; 00241 00242 // TODO : done like this just to avoid crash when input only or output only... 00243 if (fCaptureChannels > 0) 00244 ratio = fPIControler.GetRatio(fCaptureRingBuffer[0]->GetError() - delta_frames); 00245 else if (fPlaybackChannels > 0) 00246 ratio = fPIControler.GetRatio(fPlaybackRingBuffer[0]->GetError() - delta_frames); 00247 00248 #ifdef JACK_MONITOR 00249 if (fCaptureRingBuffer[0] != NULL) 00250 fTable.Write(fCaptureRingBuffer[0]->GetError(), fCaptureRingBuffer[0]->GetError() - delta_frames, ratio, 1/ratio, fCaptureRingBuffer[0]->ReadSpace(), fCaptureRingBuffer[0]->ReadSpace()); 00251 #endif 00252 00253 // Push/pull from ringbuffer 00254 for (int i = 0; i < fCaptureChannels; i++) { 00255 fCaptureRingBuffer[i]->SetRatio(ratio); 00256 if (fCaptureRingBuffer[i]->WriteResample(inputBuffer[i], frames) < frames) 00257 failure = true; 00258 } 00259 00260 for (int i = 0; i < fPlaybackChannels; i++) { 00261 fPlaybackRingBuffer[i]->SetRatio(1/ratio); 00262 if (fPlaybackRingBuffer[i]->ReadResample(outputBuffer[i], frames) < frames) 00263 failure = true; 00264 } 00265 // Reset all ringbuffers in case of failure 00266 if (failure) { 00267 jack_error("JackAudioAdapterInterface::PushAndPull ringbuffer failure... reset"); 00268 if (fAdaptative) { 00269 GrowRingBufferSize(); 00270 jack_info("Ringbuffer size = %d frames", fRingbufferCurSize); 00271 } 00272 ResetRingBuffers(); 00273 return -1; 00274 } else { 00275 return 0; 00276 } 00277 } 00278 00279 int JackAudioAdapterInterface::PullAndPush(float** inputBuffer, float** outputBuffer, unsigned int frames) 00280 { 00281 fPullAndPushTime = GetMicroSeconds(); 00282 if (!fRunning) 00283 return 0; 00284 00285 int res = 0; 00286 00287 // Push/pull from ringbuffer 00288 for (int i = 0; i < fCaptureChannels; i++) { 00289 if (fCaptureRingBuffer[i]->Read(inputBuffer[i], frames) < frames) 00290 res = -1; 00291 } 00292 00293 for (int i = 0; i < fPlaybackChannels; i++) { 00294 if (fPlaybackRingBuffer[i]->Write(outputBuffer[i], frames) < frames) 00295 res = -1; 00296 } 00297 00298 return res; 00299 } 00300 00301 } // namespace