/[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 1764 - (hide annotations) (download)
Sat Sep 6 14:55:18 2008 UTC (15 years, 7 months ago) by persson
File size: 14608 byte(s)
* rewrote the ConditionServer class to make it possible to create
  multiple sample channels when the audio thread isn't running

1 schoenebeck 200 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 persson 1651 * Copyright (C) 2005 - 2008 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     int res = jack_disconnect(pChannel->pDevice->hJackClient, src_name.c_str(), dst_name.c_str());
84     }
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    
124    
125    
126 schoenebeck 374 // *************** AudioOutputDeviceJack::ParameterName ***************
127     // *
128    
129     AudioOutputDeviceJack::ParameterName::ParameterName() : DeviceCreationParameterString() {
130     InitWithDefault(); // use default name
131     }
132    
133 schoenebeck 880 AudioOutputDeviceJack::ParameterName::ParameterName(String s) throw (Exception) : DeviceCreationParameterString(s) {
134 schoenebeck 374 }
135    
136     String AudioOutputDeviceJack::ParameterName::Description() {
137     return "Arbitrary JACK client name";
138     }
139    
140     bool AudioOutputDeviceJack::ParameterName::Fix() {
141     return true;
142     }
143    
144     bool AudioOutputDeviceJack::ParameterName::Mandatory() {
145     return false;
146     }
147    
148     std::map<String,DeviceCreationParameter*> AudioOutputDeviceJack::ParameterName::DependsAsParameters() {
149     return std::map<String,DeviceCreationParameter*>(); // no dependencies
150     }
151    
152     std::vector<String> AudioOutputDeviceJack::ParameterName::PossibilitiesAsString(std::map<String,String> Parameters) {
153     return std::vector<String>();
154     }
155    
156     optional<String> AudioOutputDeviceJack::ParameterName::DefaultAsString(std::map<String,String> Parameters) {
157     return (existingJackDevices) ? "LinuxSampler" + ToString(existingJackDevices) : "LinuxSampler";
158     }
159    
160 schoenebeck 880 void AudioOutputDeviceJack::ParameterName::OnSetValue(String s) throw (Exception) {
161 schoenebeck 374 // not possible, as parameter is fix
162     }
163    
164     String AudioOutputDeviceJack::ParameterName::Name() {
165     return "NAME";
166     }
167    
168    
169    
170 schoenebeck 226 // *************** AudioOutputDeviceJack ***************
171     // *
172    
173 schoenebeck 200 /**
174     * Open and initialize connection to the JACK system.
175     *
176     * @param Parameters - optional parameters
177     * @throws AudioOutputException on error
178     * @see AcquireChannels()
179     */
180 schoenebeck 226 AudioOutputDeviceJack::AudioOutputDeviceJack(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters) {
181 persson 1651 JackClient* pJackClient = JackClient::CreateAudio(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString());
182 schoenebeck 374 existingJackDevices++;
183 persson 1651 pJackClient->SetAudioOutputDevice(this);
184     hJackClient = pJackClient->hJackClient;
185 schoenebeck 200 uiMaxSamplesPerCycle = jack_get_buffer_size(hJackClient);
186    
187 schoenebeck 226 // create audio channels
188     AcquireChannels(((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt());
189 schoenebeck 227
190     // finally activate device if desired
191     if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) Play();
192 schoenebeck 200 }
193    
194     AudioOutputDeviceJack::~AudioOutputDeviceJack() {
195 persson 1651 // destroy jack client if there is no midi device associated with it
196     JackClient::ReleaseAudio(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString());
197 schoenebeck 374 existingJackDevices--;
198 schoenebeck 200 }
199    
200     /**
201     * This method should not be called directly! It will be called by
202     * libjack to demand transmission of further sample points.
203     */
204     int AudioOutputDeviceJack::Process(uint Samples) {
205 persson 1764 int res;
206 schoenebeck 200 if (csIsPlaying.Pop()) {
207     // let all connected engines render 'Samples' sample points
208 persson 1764 res = RenderAudio(Samples);
209 schoenebeck 200 }
210     else {
211     // playback stop by zeroing output buffer(s) and not calling connected sampler engines to render audio
212 persson 1764 res = RenderSilence(Samples);
213 schoenebeck 200 }
214 persson 1764 csIsPlaying.RttDone();
215     return res;
216 schoenebeck 200 }
217    
218     void AudioOutputDeviceJack::Play() {
219     csIsPlaying.PushAndUnlock(true);
220     }
221    
222     bool AudioOutputDeviceJack::IsPlaying() {
223 persson 497 return csIsPlaying.GetUnsafe();
224 schoenebeck 200 }
225    
226     void AudioOutputDeviceJack::Stop() {
227     csIsPlaying.PushAndUnlock(false);
228     }
229    
230 schoenebeck 226 AudioChannel* AudioOutputDeviceJack::CreateChannel(uint ChannelNr) {
231     return new AudioChannelJack(ChannelNr, this);
232 schoenebeck 200 }
233    
234     uint AudioOutputDeviceJack::MaxSamplesPerCycle() {
235     return jack_get_buffer_size(hJackClient);
236     }
237    
238     uint AudioOutputDeviceJack::SampleRate() {
239     return jack_get_sample_rate(hJackClient);
240     }
241    
242     String AudioOutputDeviceJack::Name() {
243 schoenebeck 221 return "JACK";
244 schoenebeck 200 }
245    
246     String AudioOutputDeviceJack::Driver() {
247     return Name();
248     }
249    
250     String AudioOutputDeviceJack::Description() {
251     return "JACK Audio Connection Kit";
252     }
253    
254     String AudioOutputDeviceJack::Version() {
255 persson 1764 String s = "$Revision: 1.25 $";
256 schoenebeck 200 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
257     }
258    
259 persson 1651
260    
261     // *************** JackClient ***************
262     // *
263    
264 schoenebeck 200 // libjack callback functions
265    
266 persson 1651 int linuxsampler_libjack_process_callback(jack_nframes_t nframes, void* arg) {
267     return static_cast<JackClient*>(arg)->Process(nframes);
268 schoenebeck 200 }
269    
270 persson 1651 void linuxsampler_libjack_shutdown_callback(void* arg) {
271     static_cast<JackClient*>(arg)->Stop();
272 schoenebeck 200 fprintf(stderr, "Jack: Jack server shutdown, exiting.\n");
273     }
274    
275 persson 1651 std::map<String, JackClient*> JackClient::Clients;
276    
277     int JackClient::Process(uint Samples) {
278     const config_t& config = ConfigReader.Lock();
279     #if HAVE_JACK_MIDI
280     if (config.MidiDevice) config.MidiDevice->Process(Samples);
281     #endif
282     int res = config.AudioDevice ? config.AudioDevice->Process(Samples) : 0;
283     ConfigReader.Unlock();
284     return res;
285     }
286    
287     void JackClient::Stop() {
288     const config_t& config = ConfigReader.Lock();
289     if (config.AudioDevice) config.AudioDevice->Stop();
290     ConfigReader.Unlock();
291     }
292    
293     JackClient::JackClient(String Name) : ConfigReader(Config) {
294     {
295     config_t& config = Config.GetConfigForUpdate();
296     config.AudioDevice = 0;
297 schoenebeck 1682 #if HAVE_JACK_MIDI
298 persson 1651 config.MidiDevice = 0;
299 schoenebeck 1682 #endif
300 persson 1651 }
301     {
302     config_t& config = Config.SwitchConfig();
303     config.AudioDevice = 0;
304 schoenebeck 1682 #if HAVE_JACK_MIDI
305 persson 1651 config.MidiDevice = 0;
306 schoenebeck 1682 #endif
307 persson 1651 }
308     audio = midi = false;
309     if (Name.size() >= jack_client_name_size())
310     throw Exception("JACK client name too long");
311 persson 1748 #if HAVE_JACK_CLIENT_OPEN
312     hJackClient = jack_client_open(Name.c_str(), JackNullOption, NULL);
313     #else
314     hJackClient = jack_client_new(Name.c_str());
315     #endif
316     if (!hJackClient)
317 persson 1651 throw Exception("Seems Jack server is not running.");
318     jack_set_process_callback(hJackClient, linuxsampler_libjack_process_callback, this);
319     jack_on_shutdown(hJackClient, linuxsampler_libjack_shutdown_callback, this);
320     if (jack_activate(hJackClient))
321     throw Exception("Jack: Cannot activate Jack client.");
322     }
323    
324     JackClient::~JackClient() {
325     jack_client_close(hJackClient);
326     }
327    
328     void JackClient::SetAudioOutputDevice(AudioOutputDeviceJack* device) {
329     Config.GetConfigForUpdate().AudioDevice = device;
330     Config.SwitchConfig().AudioDevice = device;
331     }
332    
333 schoenebeck 1682 #if HAVE_JACK_MIDI
334 persson 1651 void JackClient::SetMidiInputDevice(MidiInputDeviceJack* device) {
335     Config.GetConfigForUpdate().MidiDevice = device;
336     Config.SwitchConfig().MidiDevice = device;
337     }
338 schoenebeck 1682 #endif
339 persson 1651
340     JackClient* JackClient::CreateAudio(String Name) { // static
341     JackClient* client;
342     std::map<String, JackClient*>::const_iterator it = Clients.find(Name);
343     if (it == Clients.end()) {
344     client = new JackClient(Name);
345     Clients[Name] = client;
346     } else {
347     client = it->second;
348     if (client->audio) throw Exception("Jack audio device '" + Name + "' already exists");
349     }
350     client->audio = true;
351     return client;
352     }
353    
354     JackClient* JackClient::CreateMidi(String Name) { // static
355     JackClient* client;
356     std::map<String, JackClient*>::const_iterator it = Clients.find(Name);
357     if (it == Clients.end()) {
358     client = new JackClient(Name);
359     Clients[Name] = client;
360     } else {
361     client = it->second;
362     if (client->midi) throw Exception("Jack MIDI device '" + Name + "' already exists");
363     }
364     client->midi = true;
365     return client;
366     }
367    
368     void JackClient::ReleaseAudio(String Name) { // static
369     JackClient* client = Clients[Name];
370     client->SetAudioOutputDevice(0);
371     client->audio = false;
372     if (!client->midi) {
373     Clients.erase(Name);
374     delete client;
375     }
376     }
377    
378     void JackClient::ReleaseMidi(String Name) { // static
379     JackClient* client = Clients[Name];
380 schoenebeck 1682 #if HAVE_JACK_MIDI
381 persson 1651 client->SetMidiInputDevice(0);
382 schoenebeck 1682 #endif
383 persson 1651 client->midi = false;
384     if (!client->audio) {
385     Clients.erase(Name);
386     delete client;
387     }
388     }
389    
390 schoenebeck 200 } // namespace LinuxSampler
391    
392     #endif // HAVE_JACK

  ViewVC Help
Powered by ViewVC