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