1 /******************************************************************************\
2 * Copyright (c) 2004-2020
3 *
4 * Author(s):
5 * Volker Fischer
6 *
7 * This code is based on the simple_client example of the Jack audio interface.
8 *
9 ******************************************************************************
10 *
11 * This program is free software; you can redistribute it and/or modify it under
12 * the terms of the GNU General Public License as published by the Free Software
13 * Foundation; either version 2 of the License, or (at your option) any later
14 * version.
15 *
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
19 * details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 *
25 \******************************************************************************/
26
27 #include "sound.h"
28
29 #ifdef WITH_JACK
OpenJack(const bool bNoAutoJackConnect,const char * jackClientName)30 void CSound::OpenJack ( const bool bNoAutoJackConnect, const char* jackClientName )
31 {
32 jack_status_t JackStatus;
33 const char* serverName;
34
35 if ( ( serverName = getenv ( "JACK_DEFAULT_SERVER" ) ) == NULL )
36 {
37 serverName = "default";
38 }
39 qInfo() << qUtf8Printable (
40 QString ( "Connecting to JACK \"%1\" instance (use the JACK_DEFAULT_SERVER environment variable to change this)." ).arg ( serverName ) );
41
42 // try to become a client of the JACK server
43 pJackClient = jack_client_open ( jackClientName, JackNullOption, &JackStatus );
44
45 if ( pJackClient == nullptr )
46 {
47 throw CGenErr ( tr ( "JACK couldn't be started automatically. "
48 "Please start JACK manually and check for error messages." ) );
49 }
50
51 // tell the JACK server to call "process()" whenever
52 // there is work to be done
53 jack_set_process_callback ( pJackClient, process, this );
54
55 // register a "buffer size changed" callback function
56 jack_set_buffer_size_callback ( pJackClient, bufferSizeCallback, this );
57
58 // register shutdown callback function
59 jack_on_shutdown ( pJackClient, shutdownCallback, this );
60
61 // check sample rate, if not correct, just fire error
62 if ( jack_get_sample_rate ( pJackClient ) != SYSTEM_SAMPLE_RATE_HZ )
63 {
64 throw CGenErr ( QString ( tr ( "JACK isn't running at a sample rate of <b>%1 Hz</b>. Please use "
65 "a tool like <i><a href=\"https://qjackctl.sourceforge.io\">QjackCtl</a></i> to set the "
66 "the JACK sample rate to %1 Hz." ) )
67 .arg ( SYSTEM_SAMPLE_RATE_HZ ) );
68 }
69
70 // create four ports (two for input, two for output -> stereo)
71 input_port_left = jack_port_register ( pJackClient, "input left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );
72
73 input_port_right = jack_port_register ( pJackClient, "input right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );
74
75 output_port_left = jack_port_register ( pJackClient, "output left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
76
77 output_port_right = jack_port_register ( pJackClient, "output right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
78
79 if ( ( input_port_left == nullptr ) || ( input_port_right == nullptr ) || ( output_port_left == nullptr ) || ( output_port_right == nullptr ) )
80 {
81 throw CGenErr ( QString ( tr ( "The JACK port registration failed. This is probably an error with JACK. Please stop %1 and JACK. "
82 "Afterwards check if another program at a sample rate of %2 Hz can connect to JACK." ) )
83 .arg ( APP_NAME )
84 .arg ( SYSTEM_SAMPLE_RATE_HZ ) );
85 }
86
87 // optional MIDI initialization
88 if ( iCtrlMIDIChannel != INVALID_MIDI_CH )
89 {
90 input_port_midi = jack_port_register ( pJackClient, "input midi", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 );
91
92 if ( input_port_midi == nullptr )
93 {
94 throw CGenErr ( QString ( tr ( "The JACK port registration failed. This is probably an error with JACK. Please stop %1 and JACK. "
95 "Afterwards, check if another MIDI program can connect to JACK." ) )
96 .arg ( APP_NAME ) );
97 }
98 }
99 else
100 {
101 input_port_midi = nullptr;
102 }
103
104 // tell the JACK server that we are ready to roll
105 if ( jack_activate ( pJackClient ) )
106 {
107 throw CGenErr ( QString ( tr ( "Can't activate the JACK client. This is probably an error with JACK. Please check the JACK output." ) )
108 .arg ( APP_NAME ) );
109 }
110
111 if ( !bNoAutoJackConnect )
112 {
113 // connect the ports, note: you cannot do this before
114 // the client is activated, because we cannot allow
115 // connections to be made to clients that are not
116 // running
117 const char** ports;
118
119 // try to connect physical input ports
120 if ( ( ports = jack_get_ports ( pJackClient, nullptr, nullptr, JackPortIsPhysical | JackPortIsOutput ) ) != nullptr )
121 {
122 jack_connect ( pJackClient, ports[0], jack_port_name ( input_port_left ) );
123
124 // before connecting the second stereo channel, check if the input is not mono
125 if ( ports[1] )
126 {
127 jack_connect ( pJackClient, ports[1], jack_port_name ( input_port_right ) );
128 }
129
130 jack_free ( ports );
131 }
132
133 // try to connect physical output ports
134 if ( ( ports = jack_get_ports ( pJackClient, nullptr, nullptr, JackPortIsPhysical | JackPortIsInput ) ) != nullptr )
135 {
136 jack_connect ( pJackClient, jack_port_name ( output_port_left ), ports[0] );
137
138 // before connecting the second stereo channel, check if the output is not mono
139 if ( ports[1] )
140 {
141 jack_connect ( pJackClient, jack_port_name ( output_port_right ), ports[1] );
142 }
143
144 jack_free ( ports );
145 }
146
147 // input latency
148 jack_latency_range_t latrange;
149 latrange.min = 0;
150 latrange.max = 0;
151
152 jack_port_get_latency_range ( input_port_left, JackCaptureLatency, &latrange );
153 int inLatency = latrange.min; // be optimistic
154
155 // output latency
156 latrange.min = 0;
157 latrange.max = 0;
158
159 jack_port_get_latency_range ( output_port_left, JackPlaybackLatency, &latrange );
160 int outLatency = latrange.min; // be optimistic
161
162 // compute latency by using the first input and first output
163 // ports and using the most optimistic values
164 fInOutLatencyMs = static_cast<float> ( inLatency + outLatency ) * 1000 / SYSTEM_SAMPLE_RATE_HZ;
165 }
166 }
167
CloseJack()168 void CSound::CloseJack()
169 {
170 // deactivate client
171 jack_deactivate ( pJackClient );
172
173 // unregister ports
174 jack_port_unregister ( pJackClient, input_port_left );
175 jack_port_unregister ( pJackClient, input_port_right );
176 jack_port_unregister ( pJackClient, output_port_left );
177 jack_port_unregister ( pJackClient, output_port_right );
178
179 // close client connection to jack server
180 jack_client_close ( pJackClient );
181 }
182
Start()183 void CSound::Start()
184 {
185 // call base class
186 CSoundBase::Start();
187 }
188
Stop()189 void CSound::Stop()
190 {
191 // call base class
192 CSoundBase::Stop();
193 }
194
Init(const int)195 int CSound::Init ( const int /* iNewPrefMonoBufferSize */ )
196 {
197
198 // clang-format off
199 // try setting buffer size
200 // TODO seems not to work! -> no audio after this operation!
201 // Doesn't this give an infinite loop? The set buffer size function will call our
202 // registered callback which calls "EmitReinitRequestSignal()". In that function
203 // this CSound::Init() function is called...
204 //jack_set_buffer_size ( pJackClient, iNewPrefMonoBufferSize );
205 // clang-format on
206
207 // without a Jack server, Jamulus makes no sense to run, throw an error message
208 if ( bJackWasShutDown )
209 {
210 throw CGenErr ( QString ( tr ( "JACK was shut down. %1 "
211 "requires JACK to run. Please restart %1 to "
212 "start JACK again. " ) )
213 .arg ( APP_NAME ) );
214 }
215
216 // get actual buffer size
217 iJACKBufferSizeMono = jack_get_buffer_size ( pJackClient );
218
219 // init base class
220 CSoundBase::Init ( iJACKBufferSizeMono );
221
222 // set internal buffer size value and calculate stereo buffer size
223 iJACKBufferSizeStero = 2 * iJACKBufferSizeMono;
224
225 // create memory for intermediate audio buffer
226 vecsTmpAudioSndCrdStereo.Init ( iJACKBufferSizeStero );
227
228 return iJACKBufferSizeMono;
229 }
230
231 // JACK callbacks --------------------------------------------------------------
process(jack_nframes_t nframes,void * arg)232 int CSound::process ( jack_nframes_t nframes, void* arg )
233 {
234 CSound* pSound = static_cast<CSound*> ( arg );
235 int i;
236
237 // make sure we are locked during execution
238 QMutexLocker locker ( &pSound->MutexAudioProcessCallback );
239
240 if ( pSound->IsRunning() && ( nframes == static_cast<jack_nframes_t> ( pSound->iJACKBufferSizeMono ) ) )
241 {
242 // get input data pointer
243 jack_default_audio_sample_t* in_left = (jack_default_audio_sample_t*) jack_port_get_buffer ( pSound->input_port_left, nframes );
244
245 jack_default_audio_sample_t* in_right = (jack_default_audio_sample_t*) jack_port_get_buffer ( pSound->input_port_right, nframes );
246
247 // copy input audio data
248 if ( ( in_left != nullptr ) && ( in_right != nullptr ) )
249 {
250 for ( i = 0; i < pSound->iJACKBufferSizeMono; i++ )
251 {
252 pSound->vecsTmpAudioSndCrdStereo[2 * i] = Float2Short ( in_left[i] * _MAXSHORT );
253 pSound->vecsTmpAudioSndCrdStereo[2 * i + 1] = Float2Short ( in_right[i] * _MAXSHORT );
254 }
255 }
256
257 // call processing callback function
258 pSound->ProcessCallback ( pSound->vecsTmpAudioSndCrdStereo );
259
260 // get output data pointer
261 jack_default_audio_sample_t* out_left = (jack_default_audio_sample_t*) jack_port_get_buffer ( pSound->output_port_left, nframes );
262
263 jack_default_audio_sample_t* out_right = (jack_default_audio_sample_t*) jack_port_get_buffer ( pSound->output_port_right, nframes );
264
265 // copy output data
266 if ( ( out_left != nullptr ) && ( out_right != nullptr ) )
267 {
268 for ( i = 0; i < pSound->iJACKBufferSizeMono; i++ )
269 {
270 out_left[i] = (jack_default_audio_sample_t) pSound->vecsTmpAudioSndCrdStereo[2 * i] / _MAXSHORT;
271
272 out_right[i] = (jack_default_audio_sample_t) pSound->vecsTmpAudioSndCrdStereo[2 * i + 1] / _MAXSHORT;
273 }
274 }
275 }
276 else
277 {
278 // get output data pointer
279 jack_default_audio_sample_t* out_left = (jack_default_audio_sample_t*) jack_port_get_buffer ( pSound->output_port_left, nframes );
280
281 jack_default_audio_sample_t* out_right = (jack_default_audio_sample_t*) jack_port_get_buffer ( pSound->output_port_right, nframes );
282
283 // clear output data
284 if ( ( out_left != nullptr ) && ( out_right != nullptr ) )
285 {
286 memset ( out_left, 0, sizeof ( jack_default_audio_sample_t ) * nframes );
287
288 memset ( out_right, 0, sizeof ( jack_default_audio_sample_t ) * nframes );
289 }
290 }
291
292 // akt on MIDI data if MIDI is enabled
293 if ( pSound->input_port_midi != nullptr )
294 {
295 void* in_midi = jack_port_get_buffer ( pSound->input_port_midi, nframes );
296
297 if ( in_midi != 0 )
298 {
299 jack_nframes_t event_count = jack_midi_get_event_count ( in_midi );
300
301 for ( jack_nframes_t j = 0; j < event_count; j++ )
302 {
303 jack_midi_event_t in_event;
304
305 jack_midi_event_get ( &in_event, in_midi, j );
306
307 // copy packet and send it to the MIDI parser
308 // clang-format off
309 // TODO do not call malloc in real-time callback
310 // clang-format on
311 CVector<uint8_t> vMIDIPaketBytes ( in_event.size );
312
313 for ( i = 0; i < static_cast<int> ( in_event.size ); i++ )
314 {
315 vMIDIPaketBytes[i] = static_cast<uint8_t> ( in_event.buffer[i] );
316 }
317 pSound->ParseMIDIMessage ( vMIDIPaketBytes );
318 }
319 }
320 }
321
322 return 0; // zero on success, non-zero on error
323 }
324
bufferSizeCallback(jack_nframes_t,void * arg)325 int CSound::bufferSizeCallback ( jack_nframes_t, void* arg )
326 {
327 CSound* pSound = static_cast<CSound*> ( arg );
328
329 pSound->EmitReinitRequestSignal ( RS_ONLY_RESTART_AND_INIT );
330
331 return 0; // zero on success, non-zero on error
332 }
333
shutdownCallback(void * arg)334 void CSound::shutdownCallback ( void* arg )
335 {
336 CSound* pSound = static_cast<CSound*> ( arg );
337
338 pSound->bJackWasShutDown = true;
339 pSound->EmitReinitRequestSignal ( RS_ONLY_RESTART_AND_INIT );
340 }
341 #endif // WITH_JACK
342