JackAudioAdapterInterface.cpp 12 KB
Newer Older
sletz's avatar
sletz committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
Copyright (C) 2008 Grame

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

sletz's avatar
sletz committed
20
#include "JackAudioAdapter.h"
sletz's avatar
sletz committed
21
#ifdef __APPLE__
sletz's avatar
sletz committed
22
#include <TargetConditionals.h>
sletz's avatar
sletz committed
23
#endif
sletz's avatar
sletz committed
24
25
26
#ifndef TARGET_OS_IPHONE
#include "JackLibSampleRateResampler.h"
#endif
27
#include "JackTime.h"  
sletz's avatar
sletz committed
28
#include <stdio.h>
sletz's avatar
sletz committed
29
30
31
32

namespace Jack
{

33
34
#ifdef JACK_MONITOR

35
36
37
38
39
40
41
42
43
44
45
    void MeasureTable::Write(int time1, int time2, float r1, float r2, int pos1, int pos2)
    {
        int pos = (++fCount) % TABLE_MAX;
        fTable[pos].time1 = time1;
        fTable[pos].time2 = time2;
        fTable[pos].r1 = r1;
        fTable[pos].r2 = r2;
        fTable[pos].pos1 = pos1;
        fTable[pos].pos2 = pos2;
    }

sletz's avatar
sletz committed
46
    void MeasureTable::Save(unsigned int fHostBufferSize, unsigned int fHostSampleRate, unsigned int fAdaptedSampleRate, unsigned int fAdaptedBufferSize)
47
48
49
50
    {
        char buffer[1024];
        FILE* file = fopen("JackAudioAdapter.log", "w");

51
52
        int max = (fCount) % TABLE_MAX - 1;
        for (int i = 1; i < max; i++)
53
54
        {
            fprintf(file, "%d \t %d \t %d  \t %f \t %f \t %d \t %d \n",
sletz's avatar
sletz committed
55
                    fTable[i].delta, fTable[i].time1, fTable[i].time2,
56
57
58
59
                    fTable[i].r1, fTable[i].r2, fTable[i].pos1, fTable[i].pos2);
        }
        fclose(file);

sletz's avatar
sletz committed
60
        // No used for now
61
62
        // Adapter timing 1
        file = fopen("AdapterTiming1.plot", "w");
sletz's avatar
sletz committed
63
64
65
66
67
68
69
        fprintf(file, "set multiplot\n");
        fprintf(file, "set grid\n");
        fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
            ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
        fprintf(file, "set xlabel \"audio cycles\"\n");
        fprintf(file, "set ylabel \"frames\"\n");
        fprintf(file, "plot ");
sletz's avatar
sletz committed
70
        sprintf(buffer, "\"JackAudioAdapter.log\" using 2 title \"Ringbuffer error\" with lines,");
sletz's avatar
sletz committed
71
        fprintf(file, buffer);
sletz's avatar
sletz committed
72
        sprintf(buffer, "\"JackAudioAdapter.log\" using 3 title \"Ringbuffer error with timing correction\" with lines");
sletz's avatar
sletz committed
73
74
75
76
77
78
        fprintf(file, buffer);
        
        fprintf(file, "\n unset multiplot\n");  
        fprintf(file, "set output 'AdapterTiming1.pdf\n");
        fprintf(file, "set terminal pdf\n");
        
79
80
        fprintf(file, "set multiplot\n");
        fprintf(file, "set grid\n");
sletz's avatar
sletz committed
81
82
        fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
            ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
83
84
85
86
87
88
89
        fprintf(file, "set xlabel \"audio cycles\"\n");
        fprintf(file, "set ylabel \"frames\"\n");
        fprintf(file, "plot ");
        sprintf(buffer, "\"JackAudioAdapter.log\" using 2 title \"Consumer interrupt period\" with lines,");
        fprintf(file, buffer);
        sprintf(buffer, "\"JackAudioAdapter.log\" using 3 title \"Producer interrupt period\" with lines");
        fprintf(file, buffer);
sletz's avatar
sletz committed
90
        
91
        fclose(file);
sletz's avatar
sletz committed
92
   
93
94
        // Adapter timing 2
        file = fopen("AdapterTiming2.plot", "w");
sletz's avatar
sletz committed
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
        fprintf(file, "set multiplot\n");
        fprintf(file, "set grid\n");
        fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
            ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
        fprintf(file, "set xlabel \"audio cycles\"\n");
        fprintf(file, "set ylabel \"resampling ratio\"\n");
        fprintf(file, "plot ");
        sprintf(buffer, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,");
        fprintf(file, buffer);
        sprintf(buffer, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines");
        fprintf(file, buffer);
        
        fprintf(file, "\n unset multiplot\n");  
        fprintf(file, "set output 'AdapterTiming2.pdf\n");
        fprintf(file, "set terminal pdf\n");
        
111
112
        fprintf(file, "set multiplot\n");
        fprintf(file, "set grid\n");
sletz's avatar
sletz committed
113
114
        fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
            ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
115
116
117
118
119
120
121
        fprintf(file, "set xlabel \"audio cycles\"\n");
        fprintf(file, "set ylabel \"resampling ratio\"\n");
        fprintf(file, "plot ");
        sprintf(buffer, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,");
        fprintf(file, buffer);
        sprintf(buffer, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines");
        fprintf(file, buffer);
sletz's avatar
sletz committed
122
        
123
124
125
126
        fclose(file);

        // Adapter timing 3
        file = fopen("AdapterTiming3.plot", "w");
sletz's avatar
sletz committed
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
        fprintf(file, "set multiplot\n");
        fprintf(file, "set grid\n");
        fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
            ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
         fprintf(file, "set xlabel \"audio cycles\"\n");
        fprintf(file, "set ylabel \"frames\"\n");
        fprintf(file, "plot ");
        sprintf(buffer, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,");
        fprintf(file, buffer);
        sprintf(buffer, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines");
        fprintf(file, buffer);
        
        fprintf(file, "\n unset multiplot\n");  
        fprintf(file, "set output 'AdapterTiming3.pdf\n");
        fprintf(file, "set terminal pdf\n");
        
143
144
        fprintf(file, "set multiplot\n");
        fprintf(file, "set grid\n");
sletz's avatar
sletz committed
145
146
        fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
            ,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
147
148
149
150
151
152
153
        fprintf(file, "set xlabel \"audio cycles\"\n");
        fprintf(file, "set ylabel \"frames\"\n");
        fprintf(file, "plot ");
        sprintf(buffer, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,");
        fprintf(file, buffer);
        sprintf(buffer, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines");
        fprintf(file, buffer);
sletz's avatar
sletz committed
154
        
155
156
        fclose(file);
    }
sletz's avatar
sletz committed
157

158
#endif
sletz's avatar
sletz committed
159
160
161
162
163
164
165
166
167
168
169
170
171

    void JackAudioAdapterInterface::GrowRingBufferSize()
    {
        fRingbufferCurSize *= 2;
    }
    
    void JackAudioAdapterInterface::AdaptRingBufferSize()
    {
        if (fHostBufferSize > fAdaptedBufferSize)
            fRingbufferCurSize = 4 * fHostBufferSize;
        else 
            fRingbufferCurSize = 4 * fAdaptedBufferSize;
    }
sletz's avatar
sletz committed
172
        
173
174
    void JackAudioAdapterInterface::ResetRingBuffers()
    {
sletz's avatar
sletz committed
175
176
177
        if (fRingbufferCurSize > DEFAULT_RB_SIZE) 
            fRingbufferCurSize = DEFAULT_RB_SIZE;
        
sletz's avatar
sletz committed
178
        for (int i = 0; i < fCaptureChannels; i++)
sletz's avatar
sletz committed
179
            fCaptureRingBuffer[i]->Reset(fRingbufferCurSize);
sletz's avatar
sletz committed
180
        for (int i = 0; i < fPlaybackChannels; i++)
sletz's avatar
sletz committed
181
            fPlaybackRingBuffer[i]->Reset(fRingbufferCurSize);
sletz's avatar
sletz committed
182
    }
sletz's avatar
sletz committed
183
184
    
    void JackAudioAdapterInterface::Reset()
sletz's avatar
sletz committed
185
186
187
188
189
190
191
192
193
194
195
196
197
198
    {
        ResetRingBuffers();
        fRunning = false;
    }
    
#ifdef TARGET_OS_IPHONE
    void JackAudioAdapterInterface::Create()
    {}
#else
    void JackAudioAdapterInterface::Create()
    {
        //ringbuffers
        fCaptureRingBuffer = new JackResampler*[fCaptureChannels];
        fPlaybackRingBuffer = new JackResampler*[fPlaybackChannels];
sletz's avatar
sletz committed
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
        
        if (fAdaptative) {
            AdaptRingBufferSize();
            jack_info("Ringbuffer automatic adaptative mode size = %d frames", fRingbufferCurSize);
        } else {
            if (fRingbufferCurSize > DEFAULT_RB_SIZE) 
                fRingbufferCurSize = DEFAULT_RB_SIZE;
            jack_info("Fixed ringbuffer size = %d frames", fRingbufferCurSize);
        }
        
        for (int i = 0; i < fCaptureChannels; i++ ) {
            fCaptureRingBuffer[i] = new JackLibSampleRateResampler(fQuality);
            fCaptureRingBuffer[i]->Reset(fRingbufferCurSize);
        }
        for (int i = 0; i < fPlaybackChannels; i++ ) {
            fPlaybackRingBuffer[i] = new JackLibSampleRateResampler(fQuality);
            fPlaybackRingBuffer[i]->Reset(fRingbufferCurSize);
        }
     
sletz's avatar
sletz committed
218
219
220
221
222
223
224
225
226
227
228
229
230
        if (fCaptureChannels > 0)
            jack_log("ReadSpace = %ld", fCaptureRingBuffer[0]->ReadSpace());
        if (fPlaybackChannels > 0)
            jack_log("WriteSpace = %ld", fPlaybackRingBuffer[0]->WriteSpace());
    }
#endif
    
    void JackAudioAdapterInterface::Destroy()
    {
        for (int i = 0; i < fCaptureChannels; i++ )
            delete ( fCaptureRingBuffer[i] );
        for (int i = 0; i < fPlaybackChannels; i++ )
            delete ( fPlaybackRingBuffer[i] );
sletz's avatar
sletz committed
231

sletz's avatar
sletz committed
232
233
234
235
236
        delete[] fCaptureRingBuffer;
        delete[] fPlaybackRingBuffer;
    }
    
    int JackAudioAdapterInterface::PushAndPull(float** inputBuffer, float** outputBuffer, unsigned int frames)
237
    {
sletz's avatar
sletz committed
238
        bool failure = false;
sletz's avatar
sletz committed
239
        fRunning = true;
sletz's avatar
sletz committed
240
241
242
243
   
        // Finer estimation of the position in the ringbuffer
        int delta_frames = (fPullAndPushTime > 0) ? (int)((float(long(GetMicroSeconds() - fPullAndPushTime)) * float(fAdaptedSampleRate)) / 1000000.f) : 0;
        double ratio = fPIControler.GetRatio(fCaptureRingBuffer[0]->GetError() - delta_frames);
sletz's avatar
sletz committed
244
        
sletz's avatar
sletz committed
245
246
247
    #ifdef JACK_MONITOR
        fTable.Write(fCaptureRingBuffer[0]->GetError(), fCaptureRingBuffer[0]->GetError() - delta_frames, ratio, 1/ratio, fCaptureRingBuffer[0]->ReadSpace(), fCaptureRingBuffer[0]->ReadSpace());
    #endif
sletz's avatar
sletz committed
248
    
sletz's avatar
sletz committed
249
250
        // Push/pull from ringbuffer
        for (int i = 0; i < fCaptureChannels; i++) {
sletz's avatar
sletz committed
251
            fCaptureRingBuffer[i]->SetRatio(ratio);
sletz's avatar
sletz committed
252
253
254
255
256
            if (fCaptureRingBuffer[i]->WriteResample(inputBuffer[i], frames) < frames)
                failure = true;
        }

        for (int i = 0; i < fPlaybackChannels; i++) {
sletz's avatar
sletz committed
257
            fPlaybackRingBuffer[i]->SetRatio(1/ratio);
sletz's avatar
sletz committed
258
259
260
261
262
263
            if (fPlaybackRingBuffer[i]->ReadResample(outputBuffer[i], frames) < frames)
                 failure = true;
        }
        // Reset all ringbuffers in case of failure
        if (failure) {
            jack_error("JackAudioAdapterInterface::PushAndPull ringbuffer failure... reset");
sletz's avatar
sletz committed
264
265
266
267
            if (fAdaptative) {
                GrowRingBufferSize();
                jack_info("Ringbuffer size = %d frames", fRingbufferCurSize);
            }
sletz's avatar
sletz committed
268
269
270
271
272
            ResetRingBuffers();
            return -1;
        } else {
            return 0;
        }
sletz's avatar
sletz committed
273
274
    }

sletz's avatar
sletz committed
275
    int JackAudioAdapterInterface::PullAndPush(float** inputBuffer, float** outputBuffer, unsigned int frames) 
276
    {
sletz's avatar
sletz committed
277
        fPullAndPushTime = GetMicroSeconds();
sletz's avatar
sletz committed
278
279
280
281
282
        if (!fRunning)
            return 0;

        int res = 0;
    
sletz's avatar
sletz committed
283
284
285
        // Push/pull from ringbuffer
        for (int i = 0; i < fCaptureChannels; i++) {
            if (fCaptureRingBuffer[i]->Read(inputBuffer[i], frames) < frames)
sletz's avatar
sletz committed
286
                res = -1;
sletz's avatar
sletz committed
287
288
289
290
        }

        for (int i = 0; i < fPlaybackChannels; i++) {
            if (fPlaybackRingBuffer[i]->Write(outputBuffer[i], frames) < frames)
sletz's avatar
sletz committed
291
                res = -1;
sletz's avatar
sletz committed
292
        }
sletz's avatar
sletz committed
293
294
        
        return res;
295
    }
sletz's avatar
sletz committed
296
 
sletz's avatar
sletz committed
297
} // namespace