/[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 227 - (hide annotations) (download)
Thu Aug 26 22:05:44 2004 UTC (19 years, 8 months ago) by schoenebeck
File size: 9023 byte(s)
* ALSA audio driver: bugfix in device parameter 'CARD' which caused an
  error message if used in conjunction with 'CREATE AUDIO_OUTPUT_DEVICE'
  LSCP command
* JACK audio driver: fixed minor JACK port name issue and the device was
  not activated by default on creation which caused it to render solely
  silence
* src/network/lscpserver.cpp: retry to bind socket for 3 minutes if bind
  failed

1 schoenebeck 200 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6     * *
7     * This program is free software; you can redistribute it and/or modify *
8     * it under the terms of the GNU General Public License as published by *
9     * the Free Software Foundation; either version 2 of the License, or *
10     * (at your option) any later version. *
11     * *
12     * This program is distributed in the hope that it will be useful, *
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15     * GNU General Public License for more details. *
16     * *
17     * You should have received a copy of the GNU General Public License *
18     * along with this program; if not, write to the Free Software *
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
20     * MA 02111-1307 USA *
21     ***************************************************************************/
22    
23     #include "AudioOutputDeviceJack.h"
24     #include "AudioOutputDeviceFactory.h"
25    
26     #if HAVE_JACK
27    
28     namespace LinuxSampler {
29    
30     REGISTER_AUDIO_OUTPUT_DRIVER(AudioOutputDeviceJack);
31    
32     /* Common parameters for now they'll have to be registered here. */
33     REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceJack, ParameterActive);
34     REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceJack, ParameterChannels);
35    
36 schoenebeck 226
37    
38     // *************** ParameterName ***************
39     // *
40    
41     AudioOutputDeviceJack::AudioChannelJack::ParameterName::ParameterName(AudioChannelJack* pChannel) : AudioChannel::ParameterName(ToString(pChannel->ChannelNr)) {
42     this->pChannel = pChannel;
43     }
44    
45     void AudioOutputDeviceJack::AudioChannelJack::ParameterName::OnSetValue(String s) {
46 schoenebeck 227 if (jack_port_set_name(pChannel->hJackPort, s.c_str())) throw AudioOutputException("Failed to rename JACK port");
47 schoenebeck 226 }
48    
49    
50    
51     // *************** ParameterJackBindings ***************
52     // *
53    
54     AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::ParameterJackBindings(AudioChannelJack* pChannel) : DeviceRuntimeParameterStrings(std::vector<String>()) {
55     this->pChannel = pChannel;
56     }
57    
58     String AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Description() {
59     return "Bindings to other JACK clients";
60     }
61    
62     bool AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Fix() {
63     return false;
64     }
65    
66     std::vector<String> AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::PossibilitiesAsString() {
67 schoenebeck 227 const char** pPortNames = jack_get_ports(pChannel->pDevice->hJackClient, NULL, NULL, JackPortIsInput);
68 schoenebeck 226 if (!pPortNames) return std::vector<String>();
69     std::vector<String> result;
70     for (int i = 0; pPortNames[i]; i++) result.push_back(pPortNames[i]);
71     //free(pPortNames); FIXME: pPortNames should be freed here
72     return result;
73     }
74    
75     void AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::OnSetValue(std::vector<String> vS) {
76 schoenebeck 227 // TODO: we should remove all existing bindings before we connect new ones here
77     String src_name = "LinuxSampler:" + ((DeviceRuntimeParameterString*)pChannel->Parameters["NAME"])->ValueAsString();
78 schoenebeck 226 for (int i = 0; i < vS.size(); i++) {
79     String dst_name = vS[i];
80 schoenebeck 227 int res = jack_connect(pChannel->pDevice->hJackClient, src_name.c_str(), dst_name.c_str());
81     if (res == EEXIST) throw AudioOutputException("Jack: Connection to port '" + dst_name + "' already established");
82     else if (res) throw AudioOutputException("Jack: Cannot connect port '" + src_name + "' to port '" + dst_name + "'");
83 schoenebeck 226 }
84     }
85    
86     String AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Name() {
87     return "JACK_BINDINGS";
88     }
89    
90    
91    
92     // *************** AudioChannelJack ***************
93     // *
94    
95     AudioOutputDeviceJack::AudioChannelJack::AudioChannelJack(uint ChannelNr, AudioOutputDeviceJack* pDevice) throw (AudioOutputException) : AudioChannel(ChannelNr, CreateJackPort(ChannelNr, pDevice), pDevice->uiMaxSamplesPerCycle) {
96     this->pDevice = pDevice;
97     this->ChannelNr = ChannelNr;
98     Parameters["NAME"] = new ParameterName(this);
99     Parameters["JACK_BINDINGS"] = new ParameterJackBindings(this);
100     }
101    
102     AudioOutputDeviceJack::AudioChannelJack::~AudioChannelJack() {
103     //TODO: delete JACK port
104     }
105    
106     float* AudioOutputDeviceJack::AudioChannelJack::CreateJackPort(uint ChannelNr, AudioOutputDeviceJack* pDevice) throw (AudioOutputException) {
107 schoenebeck 227 String port_id = ToString(ChannelNr);
108 schoenebeck 226 hJackPort = jack_port_register(pDevice->hJackClient, port_id.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
109     if (!hJackPort) throw AudioOutputException("Jack: Cannot register Jack output port.");
110     return (float*) jack_port_get_buffer(hJackPort, pDevice->uiMaxSamplesPerCycle);
111     }
112    
113    
114    
115     // *************** AudioOutputDeviceJack ***************
116     // *
117    
118 schoenebeck 200 /**
119     * Open and initialize connection to the JACK system.
120     *
121     * @param Parameters - optional parameters
122     * @throws AudioOutputException on error
123     * @see AcquireChannels()
124     */
125 schoenebeck 226 AudioOutputDeviceJack::AudioOutputDeviceJack(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters) {
126 schoenebeck 200 if ((hJackClient = jack_client_new("LinuxSampler")) == 0)
127     throw AudioOutputException("Seems Jack server not running.");
128    
129     jack_set_process_callback(hJackClient, __libjack_process_callback, this);
130     jack_on_shutdown(hJackClient, __libjack_shutdown_callback, this);
131     if (jack_activate(hJackClient))
132     throw AudioOutputException("Jack: Cannot activate Jack client.");
133    
134     uiMaxSamplesPerCycle = jack_get_buffer_size(hJackClient);
135    
136 schoenebeck 226 // create audio channels
137     AcquireChannels(((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt());
138 schoenebeck 227
139     // finally activate device if desired
140     if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) Play();
141 schoenebeck 200 }
142    
143     AudioOutputDeviceJack::~AudioOutputDeviceJack() {
144     // destroy jack client
145     jack_client_close(hJackClient);
146     }
147    
148     /**
149     * This method should not be called directly! It will be called by
150     * libjack to demand transmission of further sample points.
151     */
152     int AudioOutputDeviceJack::Process(uint Samples) {
153     if (csIsPlaying.Pop()) {
154     // let all connected engines render 'Samples' sample points
155     return RenderAudio(Samples);
156     }
157     else {
158     // playback stop by zeroing output buffer(s) and not calling connected sampler engines to render audio
159     return RenderSilence(Samples);
160     }
161     }
162    
163     void AudioOutputDeviceJack::Play() {
164     csIsPlaying.PushAndUnlock(true);
165     }
166    
167     bool AudioOutputDeviceJack::IsPlaying() {
168     csIsPlaying.GetUnsafe();
169     }
170    
171     void AudioOutputDeviceJack::Stop() {
172     csIsPlaying.PushAndUnlock(false);
173     }
174    
175 schoenebeck 226 AudioChannel* AudioOutputDeviceJack::CreateChannel(uint ChannelNr) {
176     return new AudioChannelJack(ChannelNr, this);
177 schoenebeck 200 }
178    
179     uint AudioOutputDeviceJack::MaxSamplesPerCycle() {
180     return jack_get_buffer_size(hJackClient);
181     }
182    
183     uint AudioOutputDeviceJack::SampleRate() {
184     return jack_get_sample_rate(hJackClient);
185     }
186    
187     String AudioOutputDeviceJack::Name() {
188 schoenebeck 221 return "JACK";
189 schoenebeck 200 }
190    
191     String AudioOutputDeviceJack::Driver() {
192     return Name();
193     }
194    
195     String AudioOutputDeviceJack::Description() {
196     return "JACK Audio Connection Kit";
197     }
198    
199     String AudioOutputDeviceJack::Version() {
200 schoenebeck 227 String s = "$Revision: 1.12 $";
201 schoenebeck 200 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
202     }
203    
204     // libjack callback functions
205    
206     int __libjack_process_callback(jack_nframes_t nframes, void* arg) {
207     AudioOutputDeviceJack* pAudioOutputDeviceJack = (AudioOutputDeviceJack*) arg;
208     return pAudioOutputDeviceJack->Process(nframes);
209     }
210    
211     void __libjack_shutdown_callback(void* arg) {
212     AudioOutputDeviceJack* pAudioOutputDeviceJack = (AudioOutputDeviceJack*) arg;
213     pAudioOutputDeviceJack->Stop();
214     fprintf(stderr, "Jack: Jack server shutdown, exiting.\n");
215     }
216    
217     } // namespace LinuxSampler
218    
219     #endif // HAVE_JACK

  ViewVC Help
Powered by ViewVC