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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 227 by schoenebeck, Thu Aug 26 22:05:44 2004 UTC revision 1682 by schoenebeck, Wed Feb 13 15:31:56 2008 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6     *   Copyright (C) 2005 - 2008 Christian Schoenebeck                       *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 23  Line 24 
24  #include "AudioOutputDeviceJack.h"  #include "AudioOutputDeviceJack.h"
25  #include "AudioOutputDeviceFactory.h"  #include "AudioOutputDeviceFactory.h"
26    
27  #if HAVE_JACK  #include <errno.h>
   
 namespace LinuxSampler {  
28    
29      REGISTER_AUDIO_OUTPUT_DRIVER(AudioOutputDeviceJack);  #if HAVE_JACK
30    
31      /* Common parameters for now they'll have to be registered here. */  #ifndef HAVE_JACK_CLIENT_NAME_SIZE
32      REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceJack, ParameterActive);  #define jack_client_name_size() 33
33      REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceJack, ParameterChannels);  #endif
34    
35    namespace LinuxSampler {
36    
37        /// number of currently existing JACK audio output devices in LinuxSampler
38        static int existingJackDevices = 0;
39    
40  // *************** ParameterName ***************  // *************** AudioChannelJack::ParameterName ***************
41  // *  // *
42    
43      AudioOutputDeviceJack::AudioChannelJack::ParameterName::ParameterName(AudioChannelJack* pChannel) : AudioChannel::ParameterName(ToString(pChannel->ChannelNr)) {      AudioOutputDeviceJack::AudioChannelJack::ParameterName::ParameterName(AudioChannelJack* pChannel) : AudioChannel::ParameterName(ToString(pChannel->ChannelNr)) {
# Line 48  namespace LinuxSampler { Line 50  namespace LinuxSampler {
50    
51    
52    
53  // *************** ParameterJackBindings ***************  // *************** AudioChannelJack::ParameterJackBindings ***************
54  // *  // *
55    
56      AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::ParameterJackBindings(AudioChannelJack* pChannel) : DeviceRuntimeParameterStrings(std::vector<String>()) {      AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::ParameterJackBindings(AudioChannelJack* pChannel) : DeviceRuntimeParameterStrings(std::vector<String>()) {
# Line 64  namespace LinuxSampler { Line 66  namespace LinuxSampler {
66      }      }
67    
68      std::vector<String> AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::PossibilitiesAsString() {      std::vector<String> AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::PossibilitiesAsString() {
69          const char** pPortNames = jack_get_ports(pChannel->pDevice->hJackClient, NULL, NULL, JackPortIsInput);          const char** pPortNames = jack_get_ports(pChannel->pDevice->hJackClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput);
70          if (!pPortNames) return std::vector<String>();          if (!pPortNames) return std::vector<String>();
71          std::vector<String> result;          std::vector<String> result;
72          for (int i = 0; pPortNames[i]; i++) result.push_back(pPortNames[i]);          for (int i = 0; pPortNames[i]; i++) result.push_back(pPortNames[i]);
73          //free(pPortNames); FIXME: pPortNames should be freed here          free(pPortNames);
74          return result;          return result;
75      }      }
76    
77      void AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::OnSetValue(std::vector<String> vS) {      void AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::OnSetValue(std::vector<String> vS) {
78          // TODO: we should remove all existing bindings before we connect new ones here          String src_name = ((DeviceCreationParameterString*)pChannel->pDevice->Parameters["NAME"])->ValueAsString() + ":" +
79          String src_name = "LinuxSampler:" + ((DeviceRuntimeParameterString*)pChannel->Parameters["NAME"])->ValueAsString();                            ((DeviceRuntimeParameterString*)pChannel->Parameters["NAME"])->ValueAsString();
80            // 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          for (int i = 0; i < vS.size(); i++) {          for (int i = 0; i < vS.size(); i++) {
87              String dst_name = vS[i];              String dst_name = vS[i];
88              int res = jack_connect(pChannel->pDevice->hJackClient, src_name.c_str(), dst_name.c_str());              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");              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 + "'");              else if (res)      throw AudioOutputException("Jack: Cannot connect port '" + src_name + "' to port '" + dst_name + "'");
91          }          }
92            // remember bindings
93            Bindings = vS;
94      }      }
95    
96      String AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Name() {      String AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Name() {
# Line 95  namespace LinuxSampler { Line 105  namespace LinuxSampler {
105      AudioOutputDeviceJack::AudioChannelJack::AudioChannelJack(uint ChannelNr, AudioOutputDeviceJack* pDevice) throw (AudioOutputException) : AudioChannel(ChannelNr, CreateJackPort(ChannelNr, pDevice), pDevice->uiMaxSamplesPerCycle) {      AudioOutputDeviceJack::AudioChannelJack::AudioChannelJack(uint ChannelNr, AudioOutputDeviceJack* pDevice) throw (AudioOutputException) : AudioChannel(ChannelNr, CreateJackPort(ChannelNr, pDevice), pDevice->uiMaxSamplesPerCycle) {
106          this->pDevice   = pDevice;          this->pDevice   = pDevice;
107          this->ChannelNr = ChannelNr;          this->ChannelNr = ChannelNr;
108            delete Parameters["NAME"];
109          Parameters["NAME"]          = new ParameterName(this);          Parameters["NAME"]          = new ParameterName(this);
110          Parameters["JACK_BINDINGS"] = new ParameterJackBindings(this);          Parameters["JACK_BINDINGS"] = new ParameterJackBindings(this);
111      }      }
# Line 112  namespace LinuxSampler { Line 123  namespace LinuxSampler {
123    
124    
125    
126    // *************** AudioOutputDeviceJack::ParameterName ***************
127    // *
128    
129        AudioOutputDeviceJack::ParameterName::ParameterName() : DeviceCreationParameterString() {
130            InitWithDefault(); // use default name
131        }
132    
133        AudioOutputDeviceJack::ParameterName::ParameterName(String s) throw (Exception) : DeviceCreationParameterString(s) {
134        }
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        void AudioOutputDeviceJack::ParameterName::OnSetValue(String s) throw (Exception) {
161            // not possible, as parameter is fix
162        }
163    
164        String AudioOutputDeviceJack::ParameterName::Name() {
165            return "NAME";
166        }
167    
168    
169    
170  // *************** AudioOutputDeviceJack ***************  // *************** AudioOutputDeviceJack ***************
171  // *  // *
172    
# Line 123  namespace LinuxSampler { Line 178  namespace LinuxSampler {
178       * @see AcquireChannels()       * @see AcquireChannels()
179       */       */
180      AudioOutputDeviceJack::AudioOutputDeviceJack(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters) {      AudioOutputDeviceJack::AudioOutputDeviceJack(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters) {
181          if ((hJackClient = jack_client_new("LinuxSampler")) == 0)          JackClient* pJackClient = JackClient::CreateAudio(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString());
182              throw AudioOutputException("Seems Jack server not running.");          existingJackDevices++;
183            pJackClient->SetAudioOutputDevice(this);
184          jack_set_process_callback(hJackClient, __libjack_process_callback, this);          hJackClient = pJackClient->hJackClient;
         jack_on_shutdown(hJackClient, __libjack_shutdown_callback, this);  
         if (jack_activate(hJackClient))  
             throw AudioOutputException("Jack: Cannot activate Jack client.");  
   
185          uiMaxSamplesPerCycle = jack_get_buffer_size(hJackClient);          uiMaxSamplesPerCycle = jack_get_buffer_size(hJackClient);
186    
187          // create audio channels          // create audio channels
# Line 141  namespace LinuxSampler { Line 192  namespace LinuxSampler {
192      }      }
193    
194      AudioOutputDeviceJack::~AudioOutputDeviceJack() {      AudioOutputDeviceJack::~AudioOutputDeviceJack() {
195          // destroy jack client          // destroy jack client if there is no midi device associated with it
196          jack_client_close(hJackClient);          JackClient::ReleaseAudio(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString());
197            existingJackDevices--;
198      }      }
199    
200      /**      /**
# Line 165  namespace LinuxSampler { Line 217  namespace LinuxSampler {
217      }      }
218    
219      bool AudioOutputDeviceJack::IsPlaying() {      bool AudioOutputDeviceJack::IsPlaying() {
220          csIsPlaying.GetUnsafe();          return csIsPlaying.GetUnsafe();
221      }      }
222    
223      void AudioOutputDeviceJack::Stop() {      void AudioOutputDeviceJack::Stop() {
# Line 197  namespace LinuxSampler { Line 249  namespace LinuxSampler {
249      }      }
250    
251      String AudioOutputDeviceJack::Version() {      String AudioOutputDeviceJack::Version() {
252         String s = "$Revision: 1.12 $";         String s = "$Revision: 1.23 $";
253         return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword         return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
254      }      }
255    
256    
257    
258    // *************** JackClient ***************
259    // *
260    
261      // libjack callback functions      // libjack callback functions
262    
263      int __libjack_process_callback(jack_nframes_t nframes, void* arg) {      int linuxsampler_libjack_process_callback(jack_nframes_t nframes, void* arg) {
264          AudioOutputDeviceJack* pAudioOutputDeviceJack = (AudioOutputDeviceJack*) arg;          return static_cast<JackClient*>(arg)->Process(nframes);
         return pAudioOutputDeviceJack->Process(nframes);  
265      }      }
266    
267      void __libjack_shutdown_callback(void* arg) {      void linuxsampler_libjack_shutdown_callback(void* arg) {
268          AudioOutputDeviceJack* pAudioOutputDeviceJack = (AudioOutputDeviceJack*) arg;          static_cast<JackClient*>(arg)->Stop();
         pAudioOutputDeviceJack->Stop();  
269          fprintf(stderr, "Jack: Jack server shutdown, exiting.\n");          fprintf(stderr, "Jack: Jack server shutdown, exiting.\n");
270      }      }
271    
272        std::map<String, JackClient*> JackClient::Clients;
273    
274        int JackClient::Process(uint Samples) {
275            const config_t& config = ConfigReader.Lock();
276    #if HAVE_JACK_MIDI
277            if (config.MidiDevice) config.MidiDevice->Process(Samples);
278    #endif
279            int res = config.AudioDevice ? config.AudioDevice->Process(Samples) : 0;
280            ConfigReader.Unlock();
281            return res;
282        }
283    
284        void JackClient::Stop() {
285            const config_t& config = ConfigReader.Lock();
286            if (config.AudioDevice) config.AudioDevice->Stop();
287            ConfigReader.Unlock();
288        }
289    
290        JackClient::JackClient(String Name) : ConfigReader(Config) {
291            {
292                config_t& config = Config.GetConfigForUpdate();
293                config.AudioDevice = 0;
294    #if HAVE_JACK_MIDI
295                config.MidiDevice = 0;
296    #endif
297            }
298            {
299                config_t& config = Config.SwitchConfig();
300                config.AudioDevice = 0;
301    #if HAVE_JACK_MIDI
302                config.MidiDevice = 0;
303    #endif
304            }
305            audio = midi = false;
306            if (Name.size() >= jack_client_name_size())
307                throw Exception("JACK client name too long");
308            if ((hJackClient = jack_client_new(Name.c_str())) == 0)
309                throw Exception("Seems Jack server is not running.");
310            jack_set_process_callback(hJackClient, linuxsampler_libjack_process_callback, this);
311            jack_on_shutdown(hJackClient, linuxsampler_libjack_shutdown_callback, this);
312            if (jack_activate(hJackClient))
313                throw Exception("Jack: Cannot activate Jack client.");
314        }
315    
316        JackClient::~JackClient() {
317            jack_client_close(hJackClient);
318        }
319    
320        void JackClient::SetAudioOutputDevice(AudioOutputDeviceJack* device) {
321            Config.GetConfigForUpdate().AudioDevice = device;
322            Config.SwitchConfig().AudioDevice = device;
323        }
324    
325    #if HAVE_JACK_MIDI
326        void JackClient::SetMidiInputDevice(MidiInputDeviceJack* device) {
327            Config.GetConfigForUpdate().MidiDevice = device;
328            Config.SwitchConfig().MidiDevice = device;
329        }
330    #endif
331    
332        JackClient* JackClient::CreateAudio(String Name) { // static
333            JackClient* client;
334            std::map<String, JackClient*>::const_iterator it = Clients.find(Name);
335            if (it == Clients.end()) {
336                client = new JackClient(Name);
337                Clients[Name] = client;
338            } else {
339                client = it->second;
340                if (client->audio) throw Exception("Jack audio device '" + Name + "' already exists");
341            }
342            client->audio = true;
343            return client;
344        }
345    
346        JackClient* JackClient::CreateMidi(String Name) { // static
347            JackClient* client;
348            std::map<String, JackClient*>::const_iterator it = Clients.find(Name);
349            if (it == Clients.end()) {
350                client = new JackClient(Name);
351                Clients[Name] = client;
352            } else {
353                client = it->second;
354                if (client->midi) throw Exception("Jack MIDI device '" + Name + "' already exists");
355            }
356            client->midi = true;
357            return client;
358        }
359    
360        void JackClient::ReleaseAudio(String Name) { // static
361            JackClient* client = Clients[Name];
362            client->SetAudioOutputDevice(0);
363            client->audio = false;
364            if (!client->midi) {
365                Clients.erase(Name);
366                delete client;
367            }
368        }
369    
370        void JackClient::ReleaseMidi(String Name) { // static
371            JackClient* client = Clients[Name];
372    #if HAVE_JACK_MIDI
373            client->SetMidiInputDevice(0);
374    #endif
375            client->midi = false;
376            if (!client->audio) {
377                Clients.erase(Name);
378                delete client;
379            }
380        }
381    
382  } // namespace LinuxSampler  } // namespace LinuxSampler
383    
384  #endif // HAVE_JACK  #endif // HAVE_JACK

Legend:
Removed from v.227  
changed lines
  Added in v.1682

  ViewVC Help
Powered by ViewVC