Jack2 1.9.6

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 #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