/[svn]/linuxsampler/trunk/src/drivers/audio/AudioOutputDeviceJack.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/drivers/audio/AudioOutputDeviceJack.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2512 - (hide annotations) (download)
Sun Jan 26 17:47:43 2014 UTC (10 years, 2 months ago) by schoenebeck
File size: 18773 byte(s)
* JACK audio driver: return JACK server's current sample rate
  as default value for audio device parameter "SAMPLERATE"
  (fixes #166).
* Bumped version (1.0.0.svn27).

1 schoenebeck 200 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 2512 * Copyright (C) 2005 - 2014 Christian Schoenebeck *
7 schoenebeck 200 * *
8     * This program is free software; you can redistribute it and/or modify *
9     * it under the terms of the GNU General Public License as published by *
10     * the Free Software Foundation; either version 2 of the License, or *
11     * (at your option) any later version. *
12     * *
13     * This program is distributed in the hope that it will be useful, *
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16     * GNU General Public License for more details. *
17     * *
18     * You should have received a copy of the GNU General Public License *
19     * along with this program; if not, write to the Free Software *
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21     * MA 02111-1307 USA *
22     ***************************************************************************/
23    
24     #include "AudioOutputDeviceJack.h"
25     #include "AudioOutputDeviceFactory.h"
26    
27 capela 268 #include <errno.h>
28    
29 schoenebeck 200 #if HAVE_JACK
30    
31 persson 379 #ifndef HAVE_JACK_CLIENT_NAME_SIZE
32     #define jack_client_name_size() 33
33     #endif
34    
35 schoenebeck 200 namespace LinuxSampler {
36    
37 schoenebeck 374 /// number of currently existing JACK audio output devices in LinuxSampler
38     static int existingJackDevices = 0;
39    
40     // *************** AudioChannelJack::ParameterName ***************
41 schoenebeck 226 // *
42    
43     AudioOutputDeviceJack::AudioChannelJack::ParameterName::ParameterName(AudioChannelJack* pChannel) : AudioChannel::ParameterName(ToString(pChannel->ChannelNr)) {
44     this->pChannel = pChannel;
45     }
46    
47     void AudioOutputDeviceJack::AudioChannelJack::ParameterName::OnSetValue(String s) {
48 schoenebeck 227 if (jack_port_set_name(pChannel->hJackPort, s.c_str())) throw AudioOutputException("Failed to rename JACK port");
49 schoenebeck 226 }
50    
51    
52    
53 schoenebeck 374 // *************** AudioChannelJack::ParameterJackBindings ***************
54 schoenebeck 226 // *
55    
56     AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::ParameterJackBindings(AudioChannelJack* pChannel) : DeviceRuntimeParameterStrings(std::vector<String>()) {
57     this->pChannel = pChannel;
58     }
59    
60     String AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Description() {
61     return "Bindings to other JACK clients";
62     }
63    
64     bool AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Fix() {
65     return false;
66     }
67    
68     std::vector<String> AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::PossibilitiesAsString() {
69 persson 1651 const char** pPortNames = jack_get_ports(pChannel->pDevice->hJackClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput);
70 schoenebeck 226 if (!pPortNames) return std::vector<String>();
71     std::vector<String> result;
72     for (int i = 0; pPortNames[i]; i++) result.push_back(pPortNames[i]);
73 persson 1651 free(pPortNames);
74 schoenebeck 226 return result;
75     }
76    
77     void AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::OnSetValue(std::vector<String> vS) {
78 schoenebeck 403 String src_name = ((DeviceCreationParameterString*)pChannel->pDevice->Parameters["NAME"])->ValueAsString() + ":" +
79     ((DeviceRuntimeParameterString*)pChannel->Parameters["NAME"])->ValueAsString();
80 schoenebeck 483 // disconnect all current bindings first
81     for (int i = 0; i < Bindings.size(); i++) {
82     String dst_name = Bindings[i];
83 schoenebeck 2412 /*int res =*/ jack_disconnect(pChannel->pDevice->hJackClient, src_name.c_str(), dst_name.c_str());
84 schoenebeck 483 }
85     // connect new bindings
86 schoenebeck 226 for (int i = 0; i < vS.size(); i++) {
87     String dst_name = vS[i];
88 schoenebeck 227 int res = jack_connect(pChannel->pDevice->hJackClient, src_name.c_str(), dst_name.c_str());
89     if (res == EEXIST) throw AudioOutputException("Jack: Connection to port '" + dst_name + "' already established");
90     else if (res) throw AudioOutputException("Jack: Cannot connect port '" + src_name + "' to port '" + dst_name + "'");
91 schoenebeck 226 }
92 schoenebeck 483 // remember bindings
93     Bindings = vS;
94 schoenebeck 226 }
95    
96     String AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Name() {
97     return "JACK_BINDINGS";
98     }
99    
100    
101    
102     // *************** AudioChannelJack ***************
103     // *
104    
105     AudioOutputDeviceJack::AudioChannelJack::AudioChannelJack(uint ChannelNr, AudioOutputDeviceJack* pDevice) throw (AudioOutputException) : AudioChannel(ChannelNr, CreateJackPort(ChannelNr, pDevice), pDevice->uiMaxSamplesPerCycle) {
106     this->pDevice = pDevice;
107     this->ChannelNr = ChannelNr;
108 persson 1248 delete Parameters["NAME"];
109 schoenebeck 226 Parameters["NAME"] = new ParameterName(this);
110     Parameters["JACK_BINDINGS"] = new ParameterJackBindings(this);
111     }
112    
113     AudioOutputDeviceJack::AudioChannelJack::~AudioChannelJack() {
114     //TODO: delete JACK port
115     }
116    
117     float* AudioOutputDeviceJack::AudioChannelJack::CreateJackPort(uint ChannelNr, AudioOutputDeviceJack* pDevice) throw (AudioOutputException) {
118 schoenebeck 227 String port_id = ToString(ChannelNr);
119 schoenebeck 226 hJackPort = jack_port_register(pDevice->hJackClient, port_id.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
120     if (!hJackPort) throw AudioOutputException("Jack: Cannot register Jack output port.");
121     return (float*) jack_port_get_buffer(hJackPort, pDevice->uiMaxSamplesPerCycle);
122     }
123 schoenebeck 2410
124     void AudioOutputDeviceJack::AudioChannelJack::UpdateJackBuffer(uint size) {
125     SetBuffer(
126     (float*)jack_port_get_buffer(hJackPort, size)
127     );
128     }
129 schoenebeck 226
130    
131    
132 schoenebeck 374 // *************** AudioOutputDeviceJack::ParameterName ***************
133     // *
134    
135     AudioOutputDeviceJack::ParameterName::ParameterName() : DeviceCreationParameterString() {
136     InitWithDefault(); // use default name
137     }
138    
139 schoenebeck 880 AudioOutputDeviceJack::ParameterName::ParameterName(String s) throw (Exception) : DeviceCreationParameterString(s) {
140 schoenebeck 374 }
141    
142     String AudioOutputDeviceJack::ParameterName::Description() {
143     return "Arbitrary JACK client name";
144     }
145    
146     bool AudioOutputDeviceJack::ParameterName::Fix() {
147     return true;
148     }
149    
150     bool AudioOutputDeviceJack::ParameterName::Mandatory() {
151     return false;
152     }
153    
154     std::map<String,DeviceCreationParameter*> AudioOutputDeviceJack::ParameterName::DependsAsParameters() {
155     return std::map<String,DeviceCreationParameter*>(); // no dependencies
156     }
157    
158     std::vector<String> AudioOutputDeviceJack::ParameterName::PossibilitiesAsString(std::map<String,String> Parameters) {
159     return std::vector<String>();
160     }
161    
162     optional<String> AudioOutputDeviceJack::ParameterName::DefaultAsString(std::map<String,String> Parameters) {
163     return (existingJackDevices) ? "LinuxSampler" + ToString(existingJackDevices) : "LinuxSampler";
164     }
165    
166 schoenebeck 880 void AudioOutputDeviceJack::ParameterName::OnSetValue(String s) throw (Exception) {
167 schoenebeck 374 // not possible, as parameter is fix
168     }
169    
170     String AudioOutputDeviceJack::ParameterName::Name() {
171     return "NAME";
172     }
173    
174    
175    
176 schoenebeck 2512 // *************** AudioOutputDeviceJack::ParameterSampleRate ***************
177     // *
178    
179     AudioOutputDeviceJack::ParameterSampleRate::ParameterSampleRate() : AudioOutputDevice::ParameterSampleRate() {
180     }
181    
182     AudioOutputDeviceJack::ParameterSampleRate::ParameterSampleRate(String s) : AudioOutputDevice::ParameterSampleRate(s) {
183     }
184    
185     optional<int> AudioOutputDeviceJack::ParameterSampleRate::DefaultAsInt(std::map<String,String> Parameters) {
186     static int i = 0;
187     // arbitrary JACK client name, that shall not clash with other ones
188     String name = "LinSmPSR" + ToString(i++);
189     #if HAVE_JACK_CLIENT_OPEN
190     jack_client_t* hClient = jack_client_open(name.c_str(), JackNullOption, NULL);
191     #else
192     jack_client_t* hClient = jack_client_new(name.c_str());
193     #endif
194     // Better return "nothing" instead of i.e. 44100 here, so a frontend
195     // like QSampler will not be tempted to pass SAMPLERATE as creation
196     // parameter when creating a new JACK audio device instance.
197     if (!hClient) return optional<int>::nothing;
198     int sampleRate = jack_get_sample_rate(hClient);
199     jack_client_close(hClient);
200     return sampleRate;
201     }
202    
203     void AudioOutputDeviceJack::ParameterSampleRate::OnSetValue(int i) throw (Exception) {
204     // nothing to do: the JACK API does currently not allow JACK clients to
205     // change the sample rate
206     }
207    
208    
209    
210 schoenebeck 226 // *************** AudioOutputDeviceJack ***************
211     // *
212    
213 schoenebeck 200 /**
214     * Open and initialize connection to the JACK system.
215     *
216     * @param Parameters - optional parameters
217     * @throws AudioOutputException on error
218     * @see AcquireChannels()
219     */
220 schoenebeck 226 AudioOutputDeviceJack::AudioOutputDeviceJack(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters) {
221 schoenebeck 2412 pJackClient = JackClient::CreateAudio(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString());
222 schoenebeck 374 existingJackDevices++;
223 persson 1651 pJackClient->SetAudioOutputDevice(this);
224     hJackClient = pJackClient->hJackClient;
225 schoenebeck 200 uiMaxSamplesPerCycle = jack_get_buffer_size(hJackClient);
226    
227 schoenebeck 226 // create audio channels
228     AcquireChannels(((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt());
229 schoenebeck 227
230     // finally activate device if desired
231     if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) Play();
232 schoenebeck 200 }
233    
234     AudioOutputDeviceJack::~AudioOutputDeviceJack() {
235 persson 1651 // destroy jack client if there is no midi device associated with it
236     JackClient::ReleaseAudio(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString());
237 schoenebeck 374 existingJackDevices--;
238 schoenebeck 200 }
239    
240     /**
241     * This method should not be called directly! It will be called by
242     * libjack to demand transmission of further sample points.
243     */
244     int AudioOutputDeviceJack::Process(uint Samples) {
245 persson 1764 int res;
246 schoenebeck 2410
247     // in recent versions of JACK2 and JACk1, we are forced to
248     // re-retrieve the audio buffer pointers in each process period
249     UpdateJackBuffers(Samples);
250    
251 schoenebeck 200 if (csIsPlaying.Pop()) {
252     // let all connected engines render 'Samples' sample points
253 persson 1764 res = RenderAudio(Samples);
254 schoenebeck 200 }
255     else {
256     // playback stop by zeroing output buffer(s) and not calling connected sampler engines to render audio
257 persson 1764 res = RenderSilence(Samples);
258 schoenebeck 200 }
259 persson 1764 csIsPlaying.RttDone();
260     return res;
261 schoenebeck 200 }
262 schoenebeck 2410
263     void AudioOutputDeviceJack::UpdateJackBuffers(uint size) {
264     for (int i = 0; i < Channels.size(); ++i)
265     static_cast<AudioChannelJack*>(Channels[i])->UpdateJackBuffer(size);
266     }
267    
268     float AudioOutputDeviceJack::latency() {
269     if (!hJackClient) return -1;
270     const float size = jack_get_buffer_size(hJackClient);
271     const float rate = jack_get_sample_rate(hJackClient);
272     return size / rate;
273     }
274 schoenebeck 2412
275     jack_client_t* AudioOutputDeviceJack::jackClientHandle() {
276     return hJackClient;
277     }
278 schoenebeck 200
279     void AudioOutputDeviceJack::Play() {
280     csIsPlaying.PushAndUnlock(true);
281     }
282    
283     bool AudioOutputDeviceJack::IsPlaying() {
284 persson 497 return csIsPlaying.GetUnsafe();
285 schoenebeck 200 }
286    
287     void AudioOutputDeviceJack::Stop() {
288     csIsPlaying.PushAndUnlock(false);
289     }
290    
291 schoenebeck 226 AudioChannel* AudioOutputDeviceJack::CreateChannel(uint ChannelNr) {
292     return new AudioChannelJack(ChannelNr, this);
293 schoenebeck 200 }
294    
295     uint AudioOutputDeviceJack::MaxSamplesPerCycle() {
296     return jack_get_buffer_size(hJackClient);
297     }
298    
299     uint AudioOutputDeviceJack::SampleRate() {
300     return jack_get_sample_rate(hJackClient);
301     }
302 schoenebeck 2412
303     void AudioOutputDeviceJack::addListener(JackListener* listener) {
304     pJackClient->addListener(listener);
305     }
306 schoenebeck 200
307     String AudioOutputDeviceJack::Name() {
308 schoenebeck 221 return "JACK";
309 schoenebeck 200 }
310    
311     String AudioOutputDeviceJack::Driver() {
312     return Name();
313     }
314    
315     String AudioOutputDeviceJack::Description() {
316     return "JACK Audio Connection Kit";
317     }
318    
319     String AudioOutputDeviceJack::Version() {
320 schoenebeck 2494 String s = "$Revision$";
321 schoenebeck 200 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
322     }
323    
324 persson 1651
325    
326     // *************** JackClient ***************
327     // *
328    
329 schoenebeck 200 // libjack callback functions
330    
331 persson 1651 int linuxsampler_libjack_process_callback(jack_nframes_t nframes, void* arg) {
332     return static_cast<JackClient*>(arg)->Process(nframes);
333 schoenebeck 200 }
334    
335 persson 2478 #if HAVE_JACK_ON_INFO_SHUTDOWN
336     void JackClient::libjackShutdownCallback(jack_status_t code, const char* reason, void *arg)
337     #else
338     void JackClient::libjackShutdownCallback(void *arg)
339     #endif
340     {
341 schoenebeck 2412 JackClient* jackClient = static_cast<JackClient*>(arg);
342     jackClient->Stop();
343 schoenebeck 200 fprintf(stderr, "Jack: Jack server shutdown, exiting.\n");
344 schoenebeck 2412 for (int i = 0; i < jackClient->jackListeners.size(); ++i) {
345     JackListener* listener = jackClient->jackListeners[i];
346 persson 2478 #if HAVE_JACK_ON_INFO_SHUTDOWN
347 schoenebeck 2444 listener->onJackShutdown(code, reason);
348 persson 2478 #else
349     listener->onJackShutdown(JackFailure, "unknown");
350     #endif
351 schoenebeck 2412 }
352 schoenebeck 200 }
353 schoenebeck 2410
354     int JackClient::libjackSampleRateCallback(jack_nframes_t nframes, void *arg) {
355     JackClient* client = static_cast<JackClient*>(arg);
356     const config_t& config = client->ConfigReader.Lock();
357     if (config.AudioDevice)
358     config.AudioDevice->ReconnectAll();
359     client->ConfigReader.Unlock();
360     return 0;
361     }
362    
363     int JackClient::libjackBufferSizeCallback(jack_nframes_t nframes, void *arg) {
364     dmsg(1,("libjackBufferSizeCallback(%d)\n",nframes));
365     JackClient* client = static_cast<JackClient*>(arg);
366     const config_t& config = client->ConfigReader.Lock();
367     if (config.AudioDevice) {
368     config.AudioDevice->UpdateJackBuffers(nframes);
369     config.AudioDevice->ReconnectAll();
370     }
371     client->ConfigReader.Unlock();
372     return 0;
373     }
374 schoenebeck 2412
375     void JackClient::addListener(JackListener* listener) {
376     jackListeners.push_back(listener);
377     }
378 schoenebeck 200
379 persson 1651 std::map<String, JackClient*> JackClient::Clients;
380    
381     int JackClient::Process(uint Samples) {
382     const config_t& config = ConfigReader.Lock();
383     #if HAVE_JACK_MIDI
384     if (config.MidiDevice) config.MidiDevice->Process(Samples);
385     #endif
386     int res = config.AudioDevice ? config.AudioDevice->Process(Samples) : 0;
387     ConfigReader.Unlock();
388     return res;
389     }
390    
391     void JackClient::Stop() {
392     const config_t& config = ConfigReader.Lock();
393     if (config.AudioDevice) config.AudioDevice->Stop();
394     ConfigReader.Unlock();
395     }
396    
397     JackClient::JackClient(String Name) : ConfigReader(Config) {
398     {
399     config_t& config = Config.GetConfigForUpdate();
400     config.AudioDevice = 0;
401 schoenebeck 1682 #if HAVE_JACK_MIDI
402 persson 1651 config.MidiDevice = 0;
403 schoenebeck 1682 #endif
404 persson 1651 }
405     {
406     config_t& config = Config.SwitchConfig();
407     config.AudioDevice = 0;
408 schoenebeck 1682 #if HAVE_JACK_MIDI
409 persson 1651 config.MidiDevice = 0;
410 schoenebeck 1682 #endif
411 persson 1651 }
412     audio = midi = false;
413     if (Name.size() >= jack_client_name_size())
414     throw Exception("JACK client name too long");
415 persson 1748 #if HAVE_JACK_CLIENT_OPEN
416     hJackClient = jack_client_open(Name.c_str(), JackNullOption, NULL);
417     #else
418     hJackClient = jack_client_new(Name.c_str());
419     #endif
420     if (!hJackClient)
421 persson 1651 throw Exception("Seems Jack server is not running.");
422     jack_set_process_callback(hJackClient, linuxsampler_libjack_process_callback, this);
423 persson 2478 #if HAVE_JACK_ON_INFO_SHUTDOWN
424 schoenebeck 2444 jack_on_info_shutdown(hJackClient, libjackShutdownCallback, this);
425 persson 2478 #else
426     jack_on_shutdown(hJackClient, libjackShutdownCallback, this);
427     #endif
428 schoenebeck 2410 jack_set_buffer_size_callback(hJackClient, libjackBufferSizeCallback, this);
429     jack_set_sample_rate_callback(hJackClient, libjackSampleRateCallback, this);
430    
431 persson 1651 if (jack_activate(hJackClient))
432     throw Exception("Jack: Cannot activate Jack client.");
433     }
434    
435     JackClient::~JackClient() {
436     jack_client_close(hJackClient);
437     }
438    
439     void JackClient::SetAudioOutputDevice(AudioOutputDeviceJack* device) {
440     Config.GetConfigForUpdate().AudioDevice = device;
441     Config.SwitchConfig().AudioDevice = device;
442     }
443    
444 schoenebeck 1682 #if HAVE_JACK_MIDI
445 persson 1651 void JackClient::SetMidiInputDevice(MidiInputDeviceJack* device) {
446     Config.GetConfigForUpdate().MidiDevice = device;
447     Config.SwitchConfig().MidiDevice = device;
448     }
449 schoenebeck 1682 #endif
450 persson 1651
451     JackClient* JackClient::CreateAudio(String Name) { // static
452     JackClient* client;
453     std::map<String, JackClient*>::const_iterator it = Clients.find(Name);
454     if (it == Clients.end()) {
455     client = new JackClient(Name);
456     Clients[Name] = client;
457     } else {
458     client = it->second;
459     if (client->audio) throw Exception("Jack audio device '" + Name + "' already exists");
460     }
461     client->audio = true;
462     return client;
463     }
464    
465     JackClient* JackClient::CreateMidi(String Name) { // static
466     JackClient* client;
467     std::map<String, JackClient*>::const_iterator it = Clients.find(Name);
468     if (it == Clients.end()) {
469     client = new JackClient(Name);
470     Clients[Name] = client;
471     } else {
472     client = it->second;
473     if (client->midi) throw Exception("Jack MIDI device '" + Name + "' already exists");
474     }
475     client->midi = true;
476     return client;
477     }
478    
479     void JackClient::ReleaseAudio(String Name) { // static
480     JackClient* client = Clients[Name];
481     client->SetAudioOutputDevice(0);
482     client->audio = false;
483     if (!client->midi) {
484     Clients.erase(Name);
485     delete client;
486     }
487     }
488    
489     void JackClient::ReleaseMidi(String Name) { // static
490     JackClient* client = Clients[Name];
491 schoenebeck 1682 #if HAVE_JACK_MIDI
492 persson 1651 client->SetMidiInputDevice(0);
493 schoenebeck 1682 #endif
494 persson 1651 client->midi = false;
495     if (!client->audio) {
496     Clients.erase(Name);
497     delete client;
498     }
499     }
500    
501 schoenebeck 200 } // namespace LinuxSampler
502    
503     #endif // HAVE_JACK

Properties

Name Value
svn:keywords Revision

  ViewVC Help
Powered by ViewVC