2 Jack audio driver interface.
3 Copyright (c) 2003-2006 stefan kersten.
5 ====================================================================
7 SuperCollider real time audio synthesis system
8 Copyright (c) 2002 James McCartney. All rights reserved.
9 http://www.audiosynth.com
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 #include "SC_CoreAudio.h"
27 #include "SC_HiddenWorld.h"
28 #include "SC_Prototypes.h"
29 #include "SC_StringParser.h"
30 #include "SC_WorldOptions.h"
32 #include <jack/jack.h>
37 #include <sys/types.h>
40 // =====================================================================
43 static const char* kJackDriverIdent
= "JackDriver";
44 static const char* kJackDefaultClientName
= "SuperCollider";
46 // =====================================================================
49 // =====================================================================
52 // Delay-Locked-Loop after
53 // Fons Adriaensen, "Using a DLL to filter time"
55 #define SC_JACK_DLL_BW 0.012
62 m_t0(0.), m_t1(0.), m_e2(0.),
63 m_np(0), m_ei(0.), m_ec(0)
66 void Reset(double sampleRate
, jack_nframes_t periodFrames
, double bandWidth
, double t
)
68 // compute coefficients
70 m_b
= 2*M_PI
*bandWidth
*m_np
/sampleRate
;
73 double tp
= m_np
/sampleRate
;
77 // initialize statistics
85 double e
= m_e
= t
- m_t1
;
88 m_t1
+= m_b
* e
+ m_e2
;
95 double PeriodTime() const { return m_t0
; }
96 double NextPeriodTime() const { return m_t1
; }
97 double Period() const { return m_t1
- m_t0
; }
98 double SampleRate() const { return m_np
/Period(); }
99 double Error() const { return m_e
; }
100 double AvgError() const { return m_ec
> 0 ? m_ei
/m_ec
: 0; }
104 double m_t0
, m_t1
, m_e
, m_e2
;
110 static inline int64
sc_JackOSCTime(const struct timeval
& tv
)
112 return ((int64
)(tv
.tv_sec
+ kSECONDS_FROM_1900_to_1970
) << 32)
113 + (int64
)(tv
.tv_usec
* kMicrosToOSCunits
);
116 static inline int64
sc_JackOSCTime()
119 gettimeofday(&tv
, 0);
120 return sc_JackOSCTime(tv
);
123 static inline double sc_JackOSCTimeSeconds()
125 return (uint64
)sc_JackOSCTime() * kOSCtoSecs
;
128 int32
server_timeseed()
130 static int32 count
= 0;
132 gettimeofday(&tv
, 0);
133 return (int32
)tv
.tv_sec
^ (int32
)tv
.tv_usec
^ count
--;
138 return sc_JackOSCTime();
141 void initializeScheduler()
145 // =====================================================================
148 static int sc_jack_process_cb(jack_nframes_t numFrames
, void *arg
);
149 static int sc_jack_bufsize_cb(jack_nframes_t numSamples
, void *arg
);
150 static int sc_jack_srate_cb(jack_nframes_t sampleRate
, void *arg
);
151 static int sc_jack_graph_order_cb(void *arg
);
152 static void sc_jack_shutdown_cb(void *arg
);
154 typedef jack_default_audio_sample_t sc_jack_sample_t
;
156 struct SC_JackPortList
159 jack_port_t
** mPorts
;
160 sc_jack_sample_t
** mBuffers
;
162 SC_JackPortList(jack_client_t
*client
, int numPorts
, int type
);
166 class SC_JackDriver
: public SC_AudioDriver
168 jack_client_t
*mClient
;
169 SC_JackPortList
*mInputList
;
170 SC_JackPortList
*mOutputList
;
171 double mMaxOutputLatency
;
175 // driver interface methods
176 virtual bool DriverSetup(int* outNumSamplesPerCallback
, double* outSampleRate
);
177 virtual bool DriverStart();
178 virtual bool DriverStop();
181 SC_JackDriver(struct World
*inWorld
);
182 virtual ~SC_JackDriver();
188 void Reset(double sampleRate
, int bufferSize
);
191 bool BufferSizeChanged(int numSamples
);
192 bool SampleRateChanged(double sampleRate
);
193 bool GraphOrderChanged();
197 void ConnectPorts(const char * src
, const char * dst
)
199 int err
= jack_connect(mClient
, src
, dst
);
200 scprintf("%s: %s %s to %s\n",
202 err
? "couldn't connect " : "connected ",
206 void ConnectClientInputs(const char * pattern
);
207 void ConnectClientOutputs(const char * pattern
);
210 SC_AudioDriver
* SC_NewAudioDriver(struct World
*inWorld
)
212 return new SC_JackDriver(inWorld
);
215 // =====================================================================
218 SC_JackPortList::SC_JackPortList(jack_client_t
*client
, int numPorts
, int type
)
219 : mSize(numPorts
), mPorts(0), mBuffers(0)
221 const char *fmt
= (type
== JackPortIsInput
? "in_%d" : "out_%d");
224 mPorts
= new jack_port_t
*[mSize
];
225 mBuffers
= new float*[mSize
];
227 for (int i
= 0; i
< mSize
; i
++) {
228 snprintf(portname
, 32, fmt
, i
+1);
229 mPorts
[i
] = jack_port_register(
231 JACK_DEFAULT_AUDIO_TYPE
,
237 SC_JackPortList::~SC_JackPortList()
243 // =====================================================================
246 int sc_jack_process_cb(jack_nframes_t numFrames
, void *arg
)
248 ((SC_JackDriver
*)arg
)->Run();
252 int sc_jack_bufsize_cb(jack_nframes_t numSamples
, void *arg
)
254 return !((SC_JackDriver
*)arg
)->BufferSizeChanged((int)numSamples
);
257 int sc_jack_srate_cb(jack_nframes_t sampleRate
, void *arg
)
259 return !((SC_JackDriver
*)arg
)->SampleRateChanged((double)sampleRate
);
262 int sc_jack_graph_order_cb(void* arg
)
264 return !((SC_JackDriver
*)arg
)->GraphOrderChanged();
267 int sc_jack_xrun_cb(void* arg
)
269 return !((SC_JackDriver
*)arg
)->XRun();
272 void sc_jack_shutdown_cb(void* arg
)
274 scprintf("%s: killed by jack\n", kJackDriverIdent
);
275 World
* world
= (World
*)arg
;
276 world
->hw
->mTerminating
= true;
277 world
->hw
->mQuitProgram
->Release();
280 // =====================================================================
281 // SC_JackDriver (JACK)
283 SC_JackDriver::SC_JackDriver(struct World
*inWorld
)
284 : SC_AudioDriver(inWorld
),
288 mMaxOutputLatency(0.)
291 SC_JackDriver::~SC_JackDriver()
294 jack_client_close(mClient
);
301 // ====================================================================
302 // NOTE: for now, in lieu of a mechanism that passes generic options to
303 // the platform driver, we rely on environment variables:
305 // SC_JACK_DEFAULT_INPUTS: which outports to connect to
306 // SC_JACK_DEFAULT_OUTPUTS: which inports to connect to
307 // ====================================================================
309 bool SC_JackDriver::DriverSetup(int* outNumSamples
, double* outSampleRate
)
311 char* clientName
= 0;
312 char* serverName
= 0;
314 if (mWorld
->hw
->mInDeviceName
&& (strlen(mWorld
->hw
->mInDeviceName
) > 0)) {
315 // parse string <serverName>:<clientName>
316 SC_StringParser
sp(mWorld
->hw
->mInDeviceName
, ':');
317 if (!sp
.AtEnd()) serverName
= strdup(sp
.NextToken());
318 if (!sp
.AtEnd()) clientName
= strdup(sp
.NextToken());
319 if (clientName
== 0) {
320 // no semicolon found
321 clientName
= serverName
;
323 } else if (strlen(clientName
) == 0) {
329 #ifdef SC_USE_JACK_CLIENT_NEW
330 // old style client startup for Jack <0.100 -- AG
332 mClient
= jack_client_new(clientName
);
334 clientName
= strdup("SuperCollider");
335 mClient
= jack_client_new(clientName
);
338 sprintf(uniqueName
, "SuperCollider-%d", getpid());
339 clientName
= strdup(uniqueName
);
340 mClient
= jack_client_new(uniqueName
);
343 if (mClient
) scprintf("%s: client name is '%s'\n", kJackDriverIdent
, clientName
);
344 if (serverName
) free(serverName
); if (clientName
) free(clientName
);
345 if (mClient
== 0) return false;
347 mClient
= jack_client_open(
348 clientName
? clientName
: kJackDefaultClientName
,
349 serverName
? JackServerName
: JackNullOption
,
351 if (serverName
) free(serverName
); if (clientName
) free(clientName
);
352 if (mClient
== 0) return false;
354 scprintf("%s: client name is '%s'\n", kJackDriverIdent
, jack_get_client_name(mClient
));
357 // create jack I/O ports
358 mInputList
= new SC_JackPortList(mClient
, mWorld
->mNumInputs
, JackPortIsInput
);
359 mOutputList
= new SC_JackPortList(mClient
, mWorld
->mNumOutputs
, JackPortIsOutput
);
361 // register callbacks
362 jack_set_process_callback(mClient
, sc_jack_process_cb
, this);
363 jack_set_buffer_size_callback(mClient
, sc_jack_bufsize_cb
, this);
364 jack_set_sample_rate_callback(mClient
, sc_jack_srate_cb
, this);
365 jack_set_graph_order_callback(mClient
, sc_jack_graph_order_cb
, this);
366 jack_set_xrun_callback(mClient
, sc_jack_xrun_cb
, this);
367 jack_on_shutdown(mClient
, sc_jack_shutdown_cb
, mWorld
);
369 *outNumSamples
= (int)jack_get_buffer_size(mClient
);
370 *outSampleRate
= (double)jack_get_sample_rate(mClient
);
375 void SC_JackDriver::ConnectClientInputs(const char * pattern
)
377 const char **ports
= jack_get_ports (mClient
, pattern
, NULL
, JackPortIsOutput
);
378 jack_port_t
** ourports
= mInputList
->mPorts
;
385 if (i
== mInputList
->mSize
)
388 const char * src
= ports
[i
];
389 const char * dst
= jack_port_name(ourports
[i
]);
391 ConnectPorts(src
, dst
);
398 void SC_JackDriver::ConnectClientOutputs(const char * pattern
)
400 const char **ports
= jack_get_ports (mClient
, pattern
, NULL
, JackPortIsInput
);
401 jack_port_t
** ourports
= mOutputList
->mPorts
;
408 if (i
== mOutputList
->mSize
)
411 const char * src
= jack_port_name(ourports
[i
]);
412 const char * dst
= ports
[i
];
414 ConnectPorts(src
, dst
);
421 bool SC_JackDriver::DriverStart()
423 if (!mClient
) return false;
431 err
= jack_activate(mClient
);
433 scprintf("%s: couldn't activate jack client\n", kJackDriverIdent
);
437 // connect default inputs
438 sp
= SC_StringParser(getenv("SC_JACK_DEFAULT_INPUTS"), ',');
439 ports
= mInputList
->mPorts
;
440 numPorts
= mInputList
->mSize
;
441 for (int i
= 0; !sp
.AtEnd() && (i
< numPorts
); i
++) {
442 const char *thatPortName
= sp
.NextToken();
444 if (i
== 0 && sp
.AtEnd() && (strchr(thatPortName
, ':') == 0)) {
445 ConnectClientInputs(thatPortName
);
449 const char *thisPortName
= jack_port_name(ports
[i
]);
450 if (thisPortName
&& thatPortName
)
451 ConnectPorts(thatPortName
, thisPortName
);
454 // connect default outputs
455 sp
= SC_StringParser(getenv("SC_JACK_DEFAULT_OUTPUTS"), ',');
456 ports
= mOutputList
->mPorts
;
457 numPorts
= mOutputList
->mSize
;
458 for (int i
= 0; !sp
.AtEnd() && (i
< numPorts
); i
++) {
459 const char *thatPortName
= sp
.NextToken();
461 if (i
== 0 && sp
.AtEnd() && (strchr(thatPortName
, ':') == 0)) {
462 ConnectClientOutputs(thatPortName
);
466 const char *thisPortName
= jack_port_name(ports
[i
]);
467 if (thisPortName
&& thatPortName
)
468 ConnectPorts(thisPortName
, thatPortName
);
474 bool SC_JackDriver::DriverStop()
477 if (mClient
) err
= jack_deactivate(mClient
);
481 void SC_JackDriver::Run()
483 jack_client_t
* client
= mClient
;
484 World
* world
= mWorld
;
487 mDLL
.Update(sc_JackOSCTimeSeconds());
488 #if SC_JACK_DEBUG_DLL
492 scprintf("DLL: t %.6f p %.9f sr %.6f e %.9f avg(e) %.9f inc %.9f\n",
493 mDLL
.PeriodTime(), mDLL
.Period(), mDLL
.SampleRate(),
494 mDLL
.Error(), mDLL
.AvgError(), mOSCincrement
* kOSCtoSecs
);
498 struct timeval hostTime
;
499 gettimeofday(&hostTime
, 0);
501 double hostSecs
= (double)hostTime
.tv_sec
+ (double)hostTime
.tv_usec
* 1e-6;
502 double sampleTime
= (double)(jack_frame_time(client
) + jack_frames_since_cycle_start(client
));
504 if (mStartHostSecs
== 0) {
505 mStartHostSecs
= hostSecs
;
506 mStartSampleTime
= sampleTime
;
508 double instSampleRate
= (sampleTime
- mPrevSampleTime
) / (hostSecs
- mPrevHostSecs
);
509 double smoothSampleRate
= mSmoothSampleRate
;
510 smoothSampleRate
= smoothSampleRate
+ 0.002 * (instSampleRate
- smoothSampleRate
);
511 if (fabs(smoothSampleRate
- mSampleRate
) > 10.) {
512 smoothSampleRate
= mSampleRate
;
514 mOSCincrement
= (int64
)(mOSCincrementNumerator
/ smoothSampleRate
);
515 mSmoothSampleRate
= smoothSampleRate
;
517 double avgSampleRate
= (sampleTime
- mStartSampleTime
)/(hostSecs
- mStartHostSecs
);
518 double jitter
= (smoothSampleRate
* (hostSecs
- mPrevHostSecs
)) - (sampleTime
- mPrevSampleTime
);
519 double drift
= (smoothSampleRate
- mSampleRate
) * (hostSecs
- mStartHostSecs
);
523 mPrevHostSecs
= hostSecs
;
524 mPrevSampleTime
= sampleTime
;
530 mOscPacketsToEngine
.Perform();
532 int numInputs
= mInputList
->mSize
;
533 int numOutputs
= mOutputList
->mSize
;
534 jack_port_t
**inPorts
= mInputList
->mPorts
;
535 jack_port_t
**outPorts
= mOutputList
->mPorts
;
536 sc_jack_sample_t
**inBuffers
= mInputList
->mBuffers
;
537 sc_jack_sample_t
**outBuffers
= mOutputList
->mBuffers
;
539 int numSamples
= NumSamplesPerCallback();
540 int bufFrames
= mWorld
->mBufLength
;
541 int numBufs
= numSamples
/ bufFrames
;
543 float *inBuses
= mWorld
->mAudioBus
+ mWorld
->mNumOutputs
* bufFrames
;
544 float *outBuses
= mWorld
->mAudioBus
;
545 int32
*inTouched
= mWorld
->mAudioBusTouched
+ mWorld
->mNumOutputs
;
546 int32
*outTouched
= mWorld
->mAudioBusTouched
;
548 int minInputs
= sc_min(numInputs
, (int)mWorld
->mNumInputs
);
549 int minOutputs
= sc_min(numOutputs
, (int)mWorld
->mNumOutputs
);
554 for (int i
= 0; i
< minInputs
; ++i
) {
555 inBuffers
[i
] = (sc_jack_sample_t
*)jack_port_get_buffer(inPorts
[i
], numSamples
);
558 for (int i
= 0; i
< minOutputs
; ++i
) {
559 outBuffers
[i
] = (sc_jack_sample_t
*)jack_port_get_buffer(outPorts
[i
], numSamples
);
564 int64 oscTime
= mOSCbuftime
= (int64
)((mDLL
.PeriodTime() - mMaxOutputLatency
) * kSecondsToOSCunits
+ .5);
565 // int64 oscInc = mOSCincrement = (int64)(mOSCincrementNumerator / mDLL.SampleRate());
566 int64 oscInc
= mOSCincrement
= (int64
)((mDLL
.Period() / numBufs
) * kSecondsToOSCunits
+ .5);
567 mSmoothSampleRate
= mDLL
.SampleRate();
568 double oscToSamples
= mOSCtoSamples
= mSmoothSampleRate
* kOSCtoSecs
/* 1/pow(2,32) */;
570 int64 oscTime
= mOSCbuftime
= sc_JackOSCTime(hostTime
) - (int64
)(mMaxOutputLatency
* kSecondsToOSCunits
+ .5);
571 int64 oscInc
= mOSCincrement
;
572 double oscToSamples
= mOSCtoSamples
;
575 for (int i
= 0; i
< numBufs
; ++i
, mWorld
->mBufCounter
++, bufFramePos
+= bufFrames
) {
576 int32 bufCounter
= mWorld
->mBufCounter
;
581 for (int k
= 0; k
< minInputs
; ++k
) {
582 sc_jack_sample_t
*src
= inBuffers
[k
] + bufFramePos
;
583 float *dst
= inBuses
+ k
* bufFrames
;
584 for (int n
= 0; n
< bufFrames
; ++n
) {
592 int64 nextTime
= oscTime
+ oscInc
;
594 while ((schedTime
= mScheduler
.NextTime()) <= nextTime
) {
595 float diffTime
= (float)(schedTime
- oscTime
) * oscToSamples
+ 0.5;
596 float diffTimeFloor
= floor(diffTime
);
597 world
->mSampleOffset
= (int)diffTimeFloor
;
598 world
->mSubsampleOffset
= diffTime
- diffTimeFloor
;
600 if (world
->mSampleOffset
< 0) world
->mSampleOffset
= 0;
601 else if (world
->mSampleOffset
>= world
->mBufLength
) world
->mSampleOffset
= world
->mBufLength
-1;
603 SC_ScheduledEvent event
= mScheduler
.Remove();
607 world
->mSampleOffset
= 0;
608 world
->mSubsampleOffset
= 0.f
;
611 // copy touched outputs
613 for (int k
= 0; k
< minOutputs
; ++k
) {
614 sc_jack_sample_t
*dst
= outBuffers
[k
] + bufFramePos
;
615 if (*tch
++ == bufCounter
) {
616 float *src
= outBuses
+ k
* bufFrames
;
617 for (int n
= 0; n
< bufFrames
; ++n
) {
621 for (int n
= 0; n
< bufFrames
; ++n
) {
628 mOSCbuftime
= oscTime
= nextTime
;
630 } catch (std::exception
& exc
) {
631 scprintf("%s: exception in real time: %s\n", kJackDriverIdent
, exc
.what());
633 scprintf("%s: unknown exception in real time\n", kJackDriverIdent
);
636 double cpuUsage
= (double)jack_cpu_load(mClient
);
637 mAvgCPU
= mAvgCPU
+ 0.1 * (cpuUsage
- mAvgCPU
);
638 if (cpuUsage
> mPeakCPU
|| --mPeakCounter
<= 0) {
640 mPeakCounter
= mMaxPeakCounter
;
646 void SC_JackDriver::Reset(double sampleRate
, int bufferSize
)
648 mSampleRate
= mSmoothSampleRate
= sampleRate
;
649 mNumSamplesPerCallback
= bufferSize
;
651 World_SetSampleRate(mWorld
, mSampleRate
);
652 mBuffersPerSecond
= mSampleRate
/ mNumSamplesPerCallback
;
653 mMaxPeakCounter
= (int)mBuffersPerSecond
;
654 mOSCincrement
= (int64
)(mOSCincrementNumerator
/ mSampleRate
);
659 mNumSamplesPerCallback
,
661 sc_JackOSCTimeSeconds());
665 bool SC_JackDriver::BufferSizeChanged(int numSamples
)
667 Reset(jack_get_sample_rate(mClient
), numSamples
);
671 bool SC_JackDriver::SampleRateChanged(double sampleRate
)
673 Reset(sampleRate
, jack_get_buffer_size(mClient
));
677 bool SC_JackDriver::GraphOrderChanged()
679 SC_JackPortList
* outputs
= mOutputList
;
680 jack_nframes_t lat
= 0;
682 for (int i
=0; i
< outputs
->mSize
; ++i
) {
683 jack_nframes_t portLat
= jack_port_get_total_latency(mClient
, outputs
->mPorts
[i
]);
684 if (portLat
> lat
) lat
= portLat
;
687 double maxLat
= (double)lat
/ mSampleRate
;
689 if (maxLat
!= mMaxOutputLatency
) {
690 mMaxOutputLatency
= maxLat
;
691 scprintf("%s: max output latency %.1f ms\n", kJackDriverIdent
, maxLat
* 1e3
);
697 bool SC_JackDriver::XRun()
699 Reset(mSampleRate
, mNumSamplesPerCallback
);