Jack2  1.9.8
JackAudioAdapterInterface.cpp
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