/[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 483 by schoenebeck, Mon Mar 21 23:40:56 2005 UTC revision 1764 by persson, Sat Sep 6 14:55:18 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 Christian Schoenebeck                              *   *   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 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 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 129  namespace LinuxSampler { Line 130  namespace LinuxSampler {
130          InitWithDefault(); // use default name          InitWithDefault(); // use default name
131      }      }
132    
133      AudioOutputDeviceJack::ParameterName::ParameterName(String s) throw (LinuxSamplerException) : DeviceCreationParameterString(s) {      AudioOutputDeviceJack::ParameterName::ParameterName(String s) throw (Exception) : DeviceCreationParameterString(s) {
134      }      }
135    
136      String AudioOutputDeviceJack::ParameterName::Description() {      String AudioOutputDeviceJack::ParameterName::Description() {
# Line 156  namespace LinuxSampler { Line 157  namespace LinuxSampler {
157          return (existingJackDevices) ? "LinuxSampler" + ToString(existingJackDevices) : "LinuxSampler";          return (existingJackDevices) ? "LinuxSampler" + ToString(existingJackDevices) : "LinuxSampler";
158      }      }
159    
160      void AudioOutputDeviceJack::ParameterName::OnSetValue(String s) throw (LinuxSamplerException) {      void AudioOutputDeviceJack::ParameterName::OnSetValue(String s) throw (Exception) {
161          // not possible, as parameter is fix          // not possible, as parameter is fix
162      }      }
163    
# Line 177  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 (((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString().size() >= jack_client_name_size())          JackClient* 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.");  
   
182          existingJackDevices++;          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 200  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--;          existingJackDevices--;
198      }      }
199    
# Line 210  namespace LinuxSampler { Line 202  namespace LinuxSampler {
202       * libjack to demand transmission of further sample points.       * libjack to demand transmission of further sample points.
203       */       */
204      int AudioOutputDeviceJack::Process(uint Samples) {      int AudioOutputDeviceJack::Process(uint Samples) {
205            int res;
206          if (csIsPlaying.Pop()) {          if (csIsPlaying.Pop()) {
207              // let all connected engines render 'Samples' sample points              // let all connected engines render 'Samples' sample points
208              return RenderAudio(Samples);              res = RenderAudio(Samples);
209          }          }
210          else {          else {
211              // 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
212              return RenderSilence(Samples);              res = RenderSilence(Samples);
213          }          }
214            csIsPlaying.RttDone();
215            return res;
216      }      }
217    
218      void AudioOutputDeviceJack::Play() {      void AudioOutputDeviceJack::Play() {
# Line 225  namespace LinuxSampler { Line 220  namespace LinuxSampler {
220      }      }
221    
222      bool AudioOutputDeviceJack::IsPlaying() {      bool AudioOutputDeviceJack::IsPlaying() {
223          csIsPlaying.GetUnsafe();          return csIsPlaying.GetUnsafe();
224      }      }
225    
226      void AudioOutputDeviceJack::Stop() {      void AudioOutputDeviceJack::Stop() {
# Line 257  namespace LinuxSampler { Line 252  namespace LinuxSampler {
252      }      }
253    
254      String AudioOutputDeviceJack::Version() {      String AudioOutputDeviceJack::Version() {
255         String s = "$Revision: 1.18 $";         String s = "$Revision: 1.25 $";
256         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
257      }      }
258    
259    
260    
261    // *************** JackClient ***************
262    // *
263    
264      // libjack callback functions      // libjack callback functions
265    
266      int __libjack_process_callback(jack_nframes_t nframes, void* arg) {      int linuxsampler_libjack_process_callback(jack_nframes_t nframes, void* arg) {
267          AudioOutputDeviceJack* pAudioOutputDeviceJack = (AudioOutputDeviceJack*) arg;          return static_cast<JackClient*>(arg)->Process(nframes);
         return pAudioOutputDeviceJack->Process(nframes);  
268      }      }
269    
270      void __libjack_shutdown_callback(void* arg) {      void linuxsampler_libjack_shutdown_callback(void* arg) {
271          AudioOutputDeviceJack* pAudioOutputDeviceJack = (AudioOutputDeviceJack*) arg;          static_cast<JackClient*>(arg)->Stop();
         pAudioOutputDeviceJack->Stop();  
272          fprintf(stderr, "Jack: Jack server shutdown, exiting.\n");          fprintf(stderr, "Jack: Jack server shutdown, exiting.\n");
273      }      }
274    
275        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    #if HAVE_JACK_MIDI
298                config.MidiDevice = 0;
299    #endif
300            }
301            {
302                config_t& config = Config.SwitchConfig();
303                config.AudioDevice = 0;
304    #if HAVE_JACK_MIDI
305                config.MidiDevice = 0;
306    #endif
307            }
308            audio = midi = false;
309            if (Name.size() >= jack_client_name_size())
310                throw Exception("JACK client name too long");
311    #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                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    #if HAVE_JACK_MIDI
334        void JackClient::SetMidiInputDevice(MidiInputDeviceJack* device) {
335            Config.GetConfigForUpdate().MidiDevice = device;
336            Config.SwitchConfig().MidiDevice = device;
337        }
338    #endif
339    
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    #if HAVE_JACK_MIDI
381            client->SetMidiInputDevice(0);
382    #endif
383            client->midi = false;
384            if (!client->audio) {
385                Clients.erase(Name);
386                delete client;
387            }
388        }
389    
390  } // namespace LinuxSampler  } // namespace LinuxSampler
391    
392  #endif // HAVE_JACK  #endif // HAVE_JACK

Legend:
Removed from v.483  
changed lines
  Added in v.1764

  ViewVC Help
Powered by ViewVC