/[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 497 by persson, Sun Apr 10 11:55:44 2005 UTC revision 2478 by persson, Sat Oct 19 07:52:33 2013 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 Christian Schoenebeck                              *   *   Copyright (C) 2005 - 2013 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 66  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    
# Line 80  namespace LinuxSampler { Line 80  namespace LinuxSampler {
80          // disconnect all current bindings first          // disconnect all current bindings first
81          for (int i = 0; i < Bindings.size(); i++) {          for (int i = 0; i < Bindings.size(); i++) {
82              String dst_name = Bindings[i];              String dst_name = Bindings[i];
83              int res = jack_disconnect(pChannel->pDevice->hJackClient, src_name.c_str(), dst_name.c_str());              /*int res =*/ jack_disconnect(pChannel->pDevice->hJackClient, src_name.c_str(), dst_name.c_str());
84          }          }
85          // connect new bindings          // connect new bindings
86          for (int i = 0; i < vS.size(); i++) {          for (int i = 0; i < vS.size(); i++) {
# Line 105  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 119  namespace LinuxSampler { Line 120  namespace LinuxSampler {
120          if (!hJackPort) throw AudioOutputException("Jack: Cannot register Jack output port.");          if (!hJackPort) throw AudioOutputException("Jack: Cannot register Jack output port.");
121          return (float*) jack_port_get_buffer(hJackPort, pDevice->uiMaxSamplesPerCycle);          return (float*) jack_port_get_buffer(hJackPort, pDevice->uiMaxSamplesPerCycle);
122      }      }
123        
124        void AudioOutputDeviceJack::AudioChannelJack::UpdateJackBuffer(uint size) {
125            SetBuffer(
126               (float*)jack_port_get_buffer(hJackPort, size)
127            );
128        }
129    
130    
131    
# Line 129  namespace LinuxSampler { Line 136  namespace LinuxSampler {
136          InitWithDefault(); // use default name          InitWithDefault(); // use default name
137      }      }
138    
139      AudioOutputDeviceJack::ParameterName::ParameterName(String s) throw (LinuxSamplerException) : DeviceCreationParameterString(s) {      AudioOutputDeviceJack::ParameterName::ParameterName(String s) throw (Exception) : DeviceCreationParameterString(s) {
140      }      }
141    
142      String AudioOutputDeviceJack::ParameterName::Description() {      String AudioOutputDeviceJack::ParameterName::Description() {
# Line 156  namespace LinuxSampler { Line 163  namespace LinuxSampler {
163          return (existingJackDevices) ? "LinuxSampler" + ToString(existingJackDevices) : "LinuxSampler";          return (existingJackDevices) ? "LinuxSampler" + ToString(existingJackDevices) : "LinuxSampler";
164      }      }
165    
166      void AudioOutputDeviceJack::ParameterName::OnSetValue(String s) throw (LinuxSamplerException) {      void AudioOutputDeviceJack::ParameterName::OnSetValue(String s) throw (Exception) {
167          // not possible, as parameter is fix          // not possible, as parameter is fix
168      }      }
169    
# Line 177  namespace LinuxSampler { Line 184  namespace LinuxSampler {
184       * @see AcquireChannels()       * @see AcquireChannels()
185       */       */
186      AudioOutputDeviceJack::AudioOutputDeviceJack(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters) {      AudioOutputDeviceJack::AudioOutputDeviceJack(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters) {
187          if (((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString().size() >= jack_client_name_size())          pJackClient = JackClient::CreateAudio(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString());
             throw LinuxSamplerException("JACK client name too long");  
   
         if ((hJackClient = jack_client_new(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString().c_str())) == 0)  
             throw AudioOutputException("Seems Jack server not running.");  
   
188          existingJackDevices++;          existingJackDevices++;
189            pJackClient->SetAudioOutputDevice(this);
190          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.");  
   
191          uiMaxSamplesPerCycle = jack_get_buffer_size(hJackClient);          uiMaxSamplesPerCycle = jack_get_buffer_size(hJackClient);
192    
193          // create audio channels          // create audio channels
# Line 200  namespace LinuxSampler { Line 198  namespace LinuxSampler {
198      }      }
199    
200      AudioOutputDeviceJack::~AudioOutputDeviceJack() {      AudioOutputDeviceJack::~AudioOutputDeviceJack() {
201          // destroy jack client          // destroy jack client if there is no midi device associated with it
202          jack_client_close(hJackClient);          JackClient::ReleaseAudio(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString());
203          existingJackDevices--;          existingJackDevices--;
204      }      }
205    
# Line 210  namespace LinuxSampler { Line 208  namespace LinuxSampler {
208       * libjack to demand transmission of further sample points.       * libjack to demand transmission of further sample points.
209       */       */
210      int AudioOutputDeviceJack::Process(uint Samples) {      int AudioOutputDeviceJack::Process(uint Samples) {
211            int res;
212            
213            // in recent versions of JACK2 and JACk1, we are forced to
214            // re-retrieve the audio buffer pointers in each process period
215            UpdateJackBuffers(Samples);
216            
217          if (csIsPlaying.Pop()) {          if (csIsPlaying.Pop()) {
218              // let all connected engines render 'Samples' sample points              // let all connected engines render 'Samples' sample points
219              return RenderAudio(Samples);              res = RenderAudio(Samples);
220          }          }
221          else {          else {
222              // playback stop by zeroing output buffer(s) and not calling connected sampler engines to render audio              // playback stop by zeroing output buffer(s) and not calling connected sampler engines to render audio
223              return RenderSilence(Samples);              res = RenderSilence(Samples);
224          }          }
225            csIsPlaying.RttDone();
226            return res;
227        }
228        
229        void AudioOutputDeviceJack::UpdateJackBuffers(uint size) {
230            for (int i = 0; i < Channels.size(); ++i)
231                static_cast<AudioChannelJack*>(Channels[i])->UpdateJackBuffer(size);
232        }
233        
234        float AudioOutputDeviceJack::latency() {
235            if (!hJackClient) return -1;
236            const float size = jack_get_buffer_size(hJackClient);
237            const float rate = jack_get_sample_rate(hJackClient);
238            return size / rate;
239        }
240        
241        jack_client_t* AudioOutputDeviceJack::jackClientHandle() {
242            return hJackClient;
243      }      }
244    
245      void AudioOutputDeviceJack::Play() {      void AudioOutputDeviceJack::Play() {
# Line 243  namespace LinuxSampler { Line 265  namespace LinuxSampler {
265      uint AudioOutputDeviceJack::SampleRate() {      uint AudioOutputDeviceJack::SampleRate() {
266          return jack_get_sample_rate(hJackClient);          return jack_get_sample_rate(hJackClient);
267      }      }
268        
269        void AudioOutputDeviceJack::addListener(JackListener* listener) {
270            pJackClient->addListener(listener);
271        }
272    
273      String AudioOutputDeviceJack::Name() {      String AudioOutputDeviceJack::Name() {
274          return "JACK";          return "JACK";
# Line 257  namespace LinuxSampler { Line 283  namespace LinuxSampler {
283      }      }
284    
285      String AudioOutputDeviceJack::Version() {      String AudioOutputDeviceJack::Version() {
286         String s = "$Revision: 1.19 $";         String s = "$Revision: 1.25 $";
287         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
288      }      }
289    
290    
291    
292    // *************** JackClient ***************
293    // *
294    
295      // libjack callback functions      // libjack callback functions
296    
297      int __libjack_process_callback(jack_nframes_t nframes, void* arg) {      int linuxsampler_libjack_process_callback(jack_nframes_t nframes, void* arg) {
298          AudioOutputDeviceJack* pAudioOutputDeviceJack = (AudioOutputDeviceJack*) arg;          return static_cast<JackClient*>(arg)->Process(nframes);
         return pAudioOutputDeviceJack->Process(nframes);  
299      }      }
300    
301      void __libjack_shutdown_callback(void* arg) {  #if HAVE_JACK_ON_INFO_SHUTDOWN
302          AudioOutputDeviceJack* pAudioOutputDeviceJack = (AudioOutputDeviceJack*) arg;      void JackClient::libjackShutdownCallback(jack_status_t code, const char* reason, void *arg)
303          pAudioOutputDeviceJack->Stop();  #else
304        void JackClient::libjackShutdownCallback(void *arg)
305    #endif
306        {
307            JackClient* jackClient = static_cast<JackClient*>(arg);
308            jackClient->Stop();
309          fprintf(stderr, "Jack: Jack server shutdown, exiting.\n");          fprintf(stderr, "Jack: Jack server shutdown, exiting.\n");
310            for (int i = 0; i < jackClient->jackListeners.size(); ++i) {
311                JackListener* listener = jackClient->jackListeners[i];
312    #if HAVE_JACK_ON_INFO_SHUTDOWN
313                listener->onJackShutdown(code, reason);
314    #else
315                listener->onJackShutdown(JackFailure, "unknown");
316    #endif
317            }
318        }
319        
320        int JackClient::libjackSampleRateCallback(jack_nframes_t nframes, void *arg) {
321            JackClient* client = static_cast<JackClient*>(arg);
322            const config_t& config = client->ConfigReader.Lock();
323            if (config.AudioDevice)
324                config.AudioDevice->ReconnectAll();
325            client->ConfigReader.Unlock();
326            return 0;
327        }
328        
329        int JackClient::libjackBufferSizeCallback(jack_nframes_t nframes, void *arg) {
330            dmsg(1,("libjackBufferSizeCallback(%d)\n",nframes));
331            JackClient* client = static_cast<JackClient*>(arg);
332            const config_t& config = client->ConfigReader.Lock();
333            if (config.AudioDevice) {
334                config.AudioDevice->UpdateJackBuffers(nframes);
335                config.AudioDevice->ReconnectAll();
336            }
337            client->ConfigReader.Unlock();
338            return 0;
339        }
340        
341        void JackClient::addListener(JackListener* listener) {
342            jackListeners.push_back(listener);
343        }
344    
345        std::map<String, JackClient*> JackClient::Clients;
346    
347        int JackClient::Process(uint Samples) {
348            const config_t& config = ConfigReader.Lock();
349    #if HAVE_JACK_MIDI
350            if (config.MidiDevice) config.MidiDevice->Process(Samples);
351    #endif
352            int res = config.AudioDevice ? config.AudioDevice->Process(Samples) : 0;
353            ConfigReader.Unlock();
354            return res;
355        }
356    
357        void JackClient::Stop() {
358            const config_t& config = ConfigReader.Lock();
359            if (config.AudioDevice) config.AudioDevice->Stop();
360            ConfigReader.Unlock();
361        }
362    
363        JackClient::JackClient(String Name) : ConfigReader(Config) {
364            {
365                config_t& config = Config.GetConfigForUpdate();
366                config.AudioDevice = 0;
367    #if HAVE_JACK_MIDI
368                config.MidiDevice = 0;
369    #endif
370            }
371            {
372                config_t& config = Config.SwitchConfig();
373                config.AudioDevice = 0;
374    #if HAVE_JACK_MIDI
375                config.MidiDevice = 0;
376    #endif
377            }
378            audio = midi = false;
379            if (Name.size() >= jack_client_name_size())
380                throw Exception("JACK client name too long");
381    #if HAVE_JACK_CLIENT_OPEN
382            hJackClient = jack_client_open(Name.c_str(), JackNullOption, NULL);
383    #else
384            hJackClient = jack_client_new(Name.c_str());
385    #endif
386            if (!hJackClient)
387                throw Exception("Seems Jack server is not running.");
388            jack_set_process_callback(hJackClient, linuxsampler_libjack_process_callback, this);
389    #if HAVE_JACK_ON_INFO_SHUTDOWN
390            jack_on_info_shutdown(hJackClient, libjackShutdownCallback, this);
391    #else
392            jack_on_shutdown(hJackClient, libjackShutdownCallback, this);
393    #endif
394            jack_set_buffer_size_callback(hJackClient, libjackBufferSizeCallback, this);
395            jack_set_sample_rate_callback(hJackClient, libjackSampleRateCallback, this);
396            
397            if (jack_activate(hJackClient))
398                throw Exception("Jack: Cannot activate Jack client.");
399        }
400    
401        JackClient::~JackClient() {
402            jack_client_close(hJackClient);
403        }
404    
405        void JackClient::SetAudioOutputDevice(AudioOutputDeviceJack* device) {
406            Config.GetConfigForUpdate().AudioDevice = device;
407            Config.SwitchConfig().AudioDevice = device;
408        }
409    
410    #if HAVE_JACK_MIDI
411        void JackClient::SetMidiInputDevice(MidiInputDeviceJack* device) {
412            Config.GetConfigForUpdate().MidiDevice = device;
413            Config.SwitchConfig().MidiDevice = device;
414        }
415    #endif
416    
417        JackClient* JackClient::CreateAudio(String Name) { // static
418            JackClient* client;
419            std::map<String, JackClient*>::const_iterator it = Clients.find(Name);
420            if (it == Clients.end()) {
421                client = new JackClient(Name);
422                Clients[Name] = client;
423            } else {
424                client = it->second;
425                if (client->audio) throw Exception("Jack audio device '" + Name + "' already exists");
426            }
427            client->audio = true;
428            return client;
429        }
430    
431        JackClient* JackClient::CreateMidi(String Name) { // static
432            JackClient* client;
433            std::map<String, JackClient*>::const_iterator it = Clients.find(Name);
434            if (it == Clients.end()) {
435                client = new JackClient(Name);
436                Clients[Name] = client;
437            } else {
438                client = it->second;
439                if (client->midi) throw Exception("Jack MIDI device '" + Name + "' already exists");
440            }
441            client->midi = true;
442            return client;
443        }
444    
445        void JackClient::ReleaseAudio(String Name) { // static
446            JackClient* client = Clients[Name];
447            client->SetAudioOutputDevice(0);
448            client->audio = false;
449            if (!client->midi) {
450                Clients.erase(Name);
451                delete client;
452            }
453        }
454    
455        void JackClient::ReleaseMidi(String Name) { // static
456            JackClient* client = Clients[Name];
457    #if HAVE_JACK_MIDI
458            client->SetMidiInputDevice(0);
459    #endif
460            client->midi = false;
461            if (!client->audio) {
462                Clients.erase(Name);
463                delete client;
464            }
465      }      }
466    
467  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.497  
changed lines
  Added in v.2478

  ViewVC Help
Powered by ViewVC