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"
31 #include <jack/jack.h>
36 #include <sys/types.h>
39 // =====================================================================
42 static const char* kJackDriverIdent
= "JackDriver";
43 static const char* kJackDefaultClientName
= "SuperCollider";
45 // =====================================================================
48 // =====================================================================
51 // Delay-Locked-Loop after
52 // Fons Adriaensen, "Using a DLL to filter time"
54 #define SC_JACK_DLL_BW 0.012
61 m_t0(0.), m_t1(0.), m_e2(0.),
62 m_np(0), m_ei(0.), m_ec(0)
65 void Reset(double sampleRate
, jack_nframes_t periodFrames
, double bandWidth
, double t
)
67 // compute coefficients
69 m_b
= 2*M_PI
*bandWidth
*m_np
/sampleRate
;
72 double tp
= m_np
/sampleRate
;
76 // initialize statistics
84 double e
= m_e
= t
- m_t1
;
87 m_t1
+= m_b
* e
+ m_e2
;
94 double PeriodTime() const { return m_t0
; }
95 double NextPeriodTime() const { return m_t1
; }
96 double Period() const { return m_t1
- m_t0
; }
97 double SampleRate() const { return m_np
/Period(); }
98 double Error() const { return m_e
; }
99 double AvgError() const { return m_ec
> 0 ? m_ei
/m_ec
: 0; }
103 double m_t0
, m_t1
, m_e
, m_e2
;
109 static inline int64
sc_JackOSCTime(const struct timeval
& tv
)
111 return ((int64
)(tv
.tv_sec
+ kSECONDS_FROM_1900_to_1970
) << 32)
112 + (int64
)(tv
.tv_usec
* kMicrosToOSCunits
);
115 static inline int64
sc_JackOSCTime()
118 gettimeofday(&tv
, 0);
119 return sc_JackOSCTime(tv
);
122 static inline double sc_JackOSCTimeSeconds()
124 return (uint64
)sc_JackOSCTime() * kOSCtoSecs
;
127 int32
server_timeseed()
129 static int32 count
= 0;
131 gettimeofday(&tv
, 0);
132 return (int32
)tv
.tv_sec
^ (int32
)tv
.tv_usec
^ count
--;
137 return sc_JackOSCTime();
140 void initializeScheduler()
144 // =====================================================================
147 static int sc_jack_process_cb(jack_nframes_t numFrames
, void *arg
);
148 static int sc_jack_bufsize_cb(jack_nframes_t numSamples
, void *arg
);
149 static int sc_jack_srate_cb(jack_nframes_t sampleRate
, void *arg
);
150 static int sc_jack_graph_order_cb(void *arg
);
151 static void sc_jack_shutdown_cb(void *arg
);
153 typedef jack_default_audio_sample_t sc_jack_sample_t
;
155 struct SC_JackPortList
158 jack_port_t
** mPorts
;
159 sc_jack_sample_t
** mBuffers
;
161 SC_JackPortList(jack_client_t
*client
, int numPorts
, int type
);
165 class SC_JackDriver
: public SC_AudioDriver
167 jack_client_t
*mClient
;
168 SC_JackPortList
*mInputList
;
169 SC_JackPortList
*mOutputList
;
170 double mMaxOutputLatency
;
174 // driver interface methods
175 virtual bool DriverSetup(int* outNumSamplesPerCallback
, double* outSampleRate
);
176 virtual bool DriverStart();
177 virtual bool DriverStop();
180 SC_JackDriver(struct World
*inWorld
);
181 virtual ~SC_JackDriver();
187 void Reset(double sampleRate
, int bufferSize
);
190 bool BufferSizeChanged(int numSamples
);
191 bool SampleRateChanged(double sampleRate
);
192 bool GraphOrderChanged();
196 void ConnectPorts(const char * src
, const char * dst
)
198 int err
= jack_connect(mClient
, src
, dst
);
199 scprintf("%s: %s %s to %s\n",
201 err
? "couldn't connect " : "connected ",
205 void ConnectClientInputs(const char * pattern
);
206 void ConnectClientOutputs(const char * pattern
);
209 SC_AudioDriver
* SC_NewAudioDriver(struct World
*inWorld
)
211 return new SC_JackDriver(inWorld
);
214 // =====================================================================
217 SC_JackPortList::SC_JackPortList(jack_client_t
*client
, int numPorts
, int type
)
218 : mSize(numPorts
), mPorts(0), mBuffers(0)
220 const char *fmt
= (type
== JackPortIsInput
? "in_%d" : "out_%d");
223 mPorts
= new jack_port_t
*[mSize
];
224 mBuffers
= new float*[mSize
];
226 for (int i
= 0; i
< mSize
; i
++) {
227 snprintf(portname
, 32, fmt
, i
+1);
228 mPorts
[i
] = jack_port_register(
230 JACK_DEFAULT_AUDIO_TYPE
,
236 SC_JackPortList::~SC_JackPortList()
242 // =====================================================================
245 int sc_jack_process_cb(jack_nframes_t numFrames
, void *arg
)
247 ((SC_JackDriver
*)arg
)->Run();
251 int sc_jack_bufsize_cb(jack_nframes_t numSamples
, void *arg
)
253 return !((SC_JackDriver
*)arg
)->BufferSizeChanged((int)numSamples
);
256 int sc_jack_srate_cb(jack_nframes_t sampleRate
, void *arg
)
258 return !((SC_JackDriver
*)arg
)->SampleRateChanged((double)sampleRate
);
261 int sc_jack_graph_order_cb(void* arg
)
263 return !((SC_JackDriver
*)arg
)->GraphOrderChanged();
266 int sc_jack_xrun_cb(void* arg
)
268 return !((SC_JackDriver
*)arg
)->XRun();
271 void sc_jack_shutdown_cb(void* arg
)
273 scprintf("%s: killed by jack\n", kJackDriverIdent
);
274 World
* world
= (World
*)arg
;
275 world
->hw
->mTerminating
= true;
276 world
->hw
->mQuitProgram
->Release();
279 // =====================================================================
280 // SC_JackDriver (JACK)
282 SC_JackDriver::SC_JackDriver(struct World
*inWorld
)
283 : SC_AudioDriver(inWorld
),
287 mMaxOutputLatency(0.)
290 SC_JackDriver::~SC_JackDriver()
293 jack_client_close(mClient
);
300 // ====================================================================
301 // NOTE: for now, in lieu of a mechanism that passes generic options to
302 // the platform driver, we rely on environment variables:
304 // SC_JACK_DEFAULT_INPUTS: which outports to connect to
305 // SC_JACK_DEFAULT_OUTPUTS: which inports to connect to
306 // ====================================================================
308 bool SC_JackDriver::DriverSetup(int* outNumSamples
, double* outSampleRate
)
310 char* clientName
= 0;
311 char* serverName
= 0;
313 if (mWorld
->hw
->mInDeviceName
&& (strlen(mWorld
->hw
->mInDeviceName
) > 0)) {
314 // parse string <serverName>:<clientName>
315 SC_StringParser
sp(mWorld
->hw
->mInDeviceName
, ':');
316 if (!sp
.AtEnd()) serverName
= strdup(sp
.NextToken());
317 if (!sp
.AtEnd()) clientName
= strdup(sp
.NextToken());
318 if (clientName
== 0) {
319 // no semicolon found
320 clientName
= serverName
;
322 } else if (strlen(clientName
) == 0) {
328 #ifdef SC_USE_JACK_CLIENT_NEW
329 // old style client startup for Jack <0.100 -- AG
331 mClient
= jack_client_new(clientName
);
333 clientName
= strdup("SuperCollider");
334 mClient
= jack_client_new(clientName
);
337 sprintf(uniqueName
, "SuperCollider-%d", getpid());
338 clientName
= strdup(uniqueName
);
339 mClient
= jack_client_new(uniqueName
);
342 if (mClient
) scprintf("%s: client name is '%s'\n", kJackDriverIdent
, clientName
);
343 if (serverName
) free(serverName
); if (clientName
) free(clientName
);
344 if (mClient
== 0) return false;
346 mClient
= jack_client_open(
347 clientName
? clientName
: kJackDefaultClientName
,
348 serverName
? JackServerName
: JackNullOption
,
350 if (serverName
) free(serverName
); if (clientName
) free(clientName
);
351 if (mClient
== 0) return false;
353 scprintf("%s: client name is '%s'\n", kJackDriverIdent
, jack_get_client_name(mClient
));
356 // create jack I/O ports
357 mInputList
= new SC_JackPortList(mClient
, mWorld
->mNumInputs
, JackPortIsInput
);
358 mOutputList
= new SC_JackPortList(mClient
, mWorld
->mNumOutputs
, JackPortIsOutput
);
360 // register callbacks
361 jack_set_process_callback(mClient
, sc_jack_process_cb
, this);
362 jack_set_buffer_size_callback(mClient
, sc_jack_bufsize_cb
, this);
363 jack_set_sample_rate_callback(mClient
, sc_jack_srate_cb
, this);
364 jack_set_graph_order_callback(mClient
, sc_jack_graph_order_cb
, this);
365 jack_set_xrun_callback(mClient
, sc_jack_xrun_cb
, this);
366 jack_on_shutdown(mClient
, sc_jack_shutdown_cb
, mWorld
);
368 *outNumSamples
= (int)jack_get_buffer_size(mClient
);
369 *outSampleRate
= (double)jack_get_sample_rate(mClient
);
374 void SC_JackDriver::ConnectClientInputs(const char * pattern
)
376 const char **ports
= jack_get_ports (mClient
, pattern
, NULL
, JackPortIsOutput
);
377 jack_port_t
** ourports
= mInputList
->mPorts
;
384 if (i
== mInputList
->mSize
)
387 const char * src
= ports
[i
];
388 const char * dst
= jack_port_name(ourports
[i
]);
390 ConnectPorts(src
, dst
);
397 void SC_JackDriver::ConnectClientOutputs(const char * pattern
)
399 const char **ports
= jack_get_ports (mClient
, pattern
, NULL
, JackPortIsInput
);
400 jack_port_t
** ourports
= mOutputList
->mPorts
;
407 if (i
== mOutputList
->mSize
)
410 const char * src
= jack_port_name(ourports
[i
]);
411 const char * dst
= ports
[i
];
413 ConnectPorts(src
, dst
);
420 bool SC_JackDriver::DriverStart()
422 if (!mClient
) return false;
430 err
= jack_activate(mClient
);
432 scprintf("%s: couldn't activate jack client\n", kJackDriverIdent
);
436 // connect default inputs
437 sp
= SC_StringParser(getenv("SC_JACK_DEFAULT_INPUTS"), ',');
438 ports
= mInputList
->mPorts
;
439 numPorts
= mInputList
->mSize
;
440 for (int i
= 0; !sp
.AtEnd() && (i
< numPorts
); i
++) {
441 const char *thatPortName
= sp
.NextToken();
443 if (i
== 0 && sp
.AtEnd() && (strchr(thatPortName
, ':') == 0)) {
444 ConnectClientInputs(thatPortName
);
448 const char *thisPortName
= jack_port_name(ports
[i
]);
449 if (thisPortName
&& thatPortName
)
450 ConnectPorts(thatPortName
, thisPortName
);
453 // connect default outputs
454 sp
= SC_StringParser(getenv("SC_JACK_DEFAULT_OUTPUTS"), ',');
455 ports
= mOutputList
->mPorts
;
456 numPorts
= mOutputList
->mSize
;
457 for (int i
= 0; !sp
.AtEnd() && (i
< numPorts
); i
++) {
458 const char *thatPortName
= sp
.NextToken();
460 if (i
== 0 && sp
.AtEnd() && (strchr(thatPortName
, ':') == 0)) {
461 ConnectClientOutputs(thatPortName
);
465 const char *thisPortName
= jack_port_name(ports
[i
]);
466 if (thisPortName
&& thatPortName
)
467 ConnectPorts(thisPortName
, thatPortName
);
473 bool SC_JackDriver::DriverStop()
476 if (mClient
) err
= jack_deactivate(mClient
);
480 void SC_JackDriver::Run()
482 jack_client_t
* client
= mClient
;
483 World
* world
= mWorld
;
486 mDLL
.Update(sc_JackOSCTimeSeconds());
487 #if SC_JACK_DEBUG_DLL
491 scprintf("DLL: t %.6f p %.9f sr %.6f e %.9f avg(e) %.9f inc %.9f\n",
492 mDLL
.PeriodTime(), mDLL
.Period(), mDLL
.SampleRate(),
493 mDLL
.Error(), mDLL
.AvgError(), mOSCincrement
* kOSCtoSecs
);
497 struct timeval hostTime
;
498 gettimeofday(&hostTime
, 0);
500 double hostSecs
= (double)hostTime
.tv_sec
+ (double)hostTime
.tv_usec
* 1e-6;
501 double sampleTime
= (double)(jack_frame_time(client
) + jack_frames_since_cycle_start(client
));
503 if (mStartHostSecs
== 0) {
504 mStartHostSecs
= hostSecs
;
505 mStartSampleTime
= sampleTime
;
507 double instSampleRate
= (sampleTime
- mPrevSampleTime
) / (hostSecs
- mPrevHostSecs
);
508 double smoothSampleRate
= mSmoothSampleRate
;
509 smoothSampleRate
= smoothSampleRate
+ 0.002 * (instSampleRate
- smoothSampleRate
);
510 if (fabs(smoothSampleRate
- mSampleRate
) > 10.) {
511 smoothSampleRate
= mSampleRate
;
513 mOSCincrement
= (int64
)(mOSCincrementNumerator
/ smoothSampleRate
);
514 mSmoothSampleRate
= smoothSampleRate
;
516 double avgSampleRate
= (sampleTime
- mStartSampleTime
)/(hostSecs
- mStartHostSecs
);
517 double jitter
= (smoothSampleRate
* (hostSecs
- mPrevHostSecs
)) - (sampleTime
- mPrevSampleTime
);
518 double drift
= (smoothSampleRate
- mSampleRate
) * (hostSecs
- mStartHostSecs
);
522 mPrevHostSecs
= hostSecs
;
523 mPrevSampleTime
= sampleTime
;
529 mOscPacketsToEngine
.Perform();
531 int numInputs
= mInputList
->mSize
;
532 int numOutputs
= mOutputList
->mSize
;
533 jack_port_t
**inPorts
= mInputList
->mPorts
;
534 jack_port_t
**outPorts
= mOutputList
->mPorts
;
535 sc_jack_sample_t
**inBuffers
= mInputList
->mBuffers
;
536 sc_jack_sample_t
**outBuffers
= mOutputList
->mBuffers
;
538 int numSamples
= NumSamplesPerCallback();
539 int bufFrames
= mWorld
->mBufLength
;
540 int numBufs
= numSamples
/ bufFrames
;
542 float *inBuses
= mWorld
->mAudioBus
+ mWorld
->mNumOutputs
* bufFrames
;
543 float *outBuses
= mWorld
->mAudioBus
;
544 int32
*inTouched
= mWorld
->mAudioBusTouched
+ mWorld
->mNumOutputs
;
545 int32
*outTouched
= mWorld
->mAudioBusTouched
;
547 int minInputs
= sc_min(numInputs
, (int)mWorld
->mNumInputs
);
548 int minOutputs
= sc_min(numOutputs
, (int)mWorld
->mNumOutputs
);
553 for (int i
= 0; i
< minInputs
; ++i
) {
554 inBuffers
[i
] = (sc_jack_sample_t
*)jack_port_get_buffer(inPorts
[i
], numSamples
);
557 for (int i
= 0; i
< minOutputs
; ++i
) {
558 outBuffers
[i
] = (sc_jack_sample_t
*)jack_port_get_buffer(outPorts
[i
], numSamples
);
563 int64 oscTime
= mOSCbuftime
= (int64
)((mDLL
.PeriodTime() - mMaxOutputLatency
) * kSecondsToOSCunits
+ .5);
564 // int64 oscInc = mOSCincrement = (int64)(mOSCincrementNumerator / mDLL.SampleRate());
565 int64 oscInc
= mOSCincrement
= (int64
)((mDLL
.Period() / numBufs
) * kSecondsToOSCunits
+ .5);
566 mSmoothSampleRate
= mDLL
.SampleRate();
567 double oscToSamples
= mOSCtoSamples
= mSmoothSampleRate
* kOSCtoSecs
/* 1/pow(2,32) */;
569 int64 oscTime
= mOSCbuftime
= sc_JackOSCTime(hostTime
) - (int64
)(mMaxOutputLatency
* kSecondsToOSCunits
+ .5);
570 int64 oscInc
= mOSCincrement
;
571 double oscToSamples
= mOSCtoSamples
;
574 for (int i
= 0; i
< numBufs
; ++i
, mWorld
->mBufCounter
++, bufFramePos
+= bufFrames
) {
575 int32 bufCounter
= mWorld
->mBufCounter
;
580 for (int k
= 0; k
< minInputs
; ++k
) {
581 sc_jack_sample_t
*src
= inBuffers
[k
] + bufFramePos
;
582 float *dst
= inBuses
+ k
* bufFrames
;
583 for (int n
= 0; n
< bufFrames
; ++n
) {
591 int64 nextTime
= oscTime
+ oscInc
;
593 while ((schedTime
= mScheduler
.NextTime()) <= nextTime
) {
594 float diffTime
= (float)(schedTime
- oscTime
) * oscToSamples
+ 0.5;
595 float diffTimeFloor
= floor(diffTime
);
596 world
->mSampleOffset
= (int)diffTimeFloor
;
597 world
->mSubsampleOffset
= diffTime
- diffTimeFloor
;
599 if (world
->mSampleOffset
< 0) world
->mSampleOffset
= 0;
600 else if (world
->mSampleOffset
>= world
->mBufLength
) world
->mSampleOffset
= world
->mBufLength
-1;
602 SC_ScheduledEvent event
= mScheduler
.Remove();
606 world
->mSampleOffset
= 0;
607 world
->mSubsampleOffset
= 0.f
;
610 // copy touched outputs
612 for (int k
= 0; k
< minOutputs
; ++k
) {
613 sc_jack_sample_t
*dst
= outBuffers
[k
] + bufFramePos
;
614 if (*tch
++ == bufCounter
) {
615 float *src
= outBuses
+ k
* bufFrames
;
616 for (int n
= 0; n
< bufFrames
; ++n
) {
620 for (int n
= 0; n
< bufFrames
; ++n
) {
627 mOSCbuftime
= oscTime
= nextTime
;
629 } catch (std::exception
& exc
) {
630 scprintf("%s: exception in real time: %s\n", kJackDriverIdent
, exc
.what());
632 scprintf("%s: unknown exception in real time\n", kJackDriverIdent
);
635 double cpuUsage
= (double)jack_cpu_load(mClient
);
636 mAvgCPU
= mAvgCPU
+ 0.1 * (cpuUsage
- mAvgCPU
);
637 if (cpuUsage
> mPeakCPU
|| --mPeakCounter
<= 0) {
639 mPeakCounter
= mMaxPeakCounter
;
645 void SC_JackDriver::Reset(double sampleRate
, int bufferSize
)
647 mSampleRate
= mSmoothSampleRate
= sampleRate
;
648 mNumSamplesPerCallback
= bufferSize
;
650 World_SetSampleRate(mWorld
, mSampleRate
);
651 mBuffersPerSecond
= mSampleRate
/ mNumSamplesPerCallback
;
652 mMaxPeakCounter
= (int)mBuffersPerSecond
;
653 mOSCincrement
= (int64
)(mOSCincrementNumerator
/ mSampleRate
);
658 mNumSamplesPerCallback
,
660 sc_JackOSCTimeSeconds());
664 bool SC_JackDriver::BufferSizeChanged(int numSamples
)
666 Reset(jack_get_sample_rate(mClient
), numSamples
);
670 bool SC_JackDriver::SampleRateChanged(double sampleRate
)
672 Reset(sampleRate
, jack_get_buffer_size(mClient
));
676 bool SC_JackDriver::GraphOrderChanged()
678 SC_JackPortList
* outputs
= mOutputList
;
679 jack_nframes_t lat
= 0;
681 for (int i
=0; i
< outputs
->mSize
; ++i
) {
682 jack_nframes_t portLat
= jack_port_get_total_latency(mClient
, outputs
->mPorts
[i
]);
683 if (portLat
> lat
) lat
= portLat
;
686 double maxLat
= (double)lat
/ mSampleRate
;
688 if (maxLat
!= mMaxOutputLatency
) {
689 mMaxOutputLatency
= maxLat
;
690 scprintf("%s: max output latency %.1f ms\n", kJackDriverIdent
, maxLat
* 1e3
);
696 bool SC_JackDriver::XRun()
698 Reset(mSampleRate
, mNumSamplesPerCallback
);