/[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 483 - (hide annotations) (download)
Mon Mar 21 23:40:56 2005 UTC (19 years ago) by schoenebeck
File size: 11210 byte(s)
* JACK audio driver: fixed handling of channel parameter 'JACK_BINDINGS'
* fixed parser bug of multiplicity parameters

1 schoenebeck 200 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 483 * Copyright (C) 2005 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 schoenebeck 227 const char** pPortNames = jack_get_ports(pChannel->pDevice->hJackClient, NULL, NULL, 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     //free(pPortNames); FIXME: pPortNames should be freed here
74     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     Parameters["NAME"] = new ParameterName(this);
109     Parameters["JACK_BINDINGS"] = new ParameterJackBindings(this);
110     }
111    
112     AudioOutputDeviceJack::AudioChannelJack::~AudioChannelJack() {
113     //TODO: delete JACK port
114     }
115    
116     float* AudioOutputDeviceJack::AudioChannelJack::CreateJackPort(uint ChannelNr, AudioOutputDeviceJack* pDevice) throw (AudioOutputException) {
117 schoenebeck 227 String port_id = ToString(ChannelNr);
118 schoenebeck 226 hJackPort = jack_port_register(pDevice->hJackClient, port_id.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
119     if (!hJackPort) throw AudioOutputException("Jack: Cannot register Jack output port.");
120     return (float*) jack_port_get_buffer(hJackPort, pDevice->uiMaxSamplesPerCycle);
121     }
122    
123    
124    
125 schoenebeck 374 // *************** AudioOutputDeviceJack::ParameterName ***************
126     // *
127    
128     AudioOutputDeviceJack::ParameterName::ParameterName() : DeviceCreationParameterString() {
129     InitWithDefault(); // use default name
130     }
131    
132     AudioOutputDeviceJack::ParameterName::ParameterName(String s) throw (LinuxSamplerException) : DeviceCreationParameterString(s) {
133     }
134    
135     String AudioOutputDeviceJack::ParameterName::Description() {
136     return "Arbitrary JACK client name";
137     }
138    
139     bool AudioOutputDeviceJack::ParameterName::Fix() {
140     return true;
141     }
142    
143     bool AudioOutputDeviceJack::ParameterName::Mandatory() {
144     return false;
145     }
146    
147     std::map<String,DeviceCreationParameter*> AudioOutputDeviceJack::ParameterName::DependsAsParameters() {
148     return std::map<String,DeviceCreationParameter*>(); // no dependencies
149     }
150    
151     std::vector<String> AudioOutputDeviceJack::ParameterName::PossibilitiesAsString(std::map<String,String> Parameters) {
152     return std::vector<String>();
153     }
154    
155     optional<String> AudioOutputDeviceJack::ParameterName::DefaultAsString(std::map<String,String> Parameters) {
156     return (existingJackDevices) ? "LinuxSampler" + ToString(existingJackDevices) : "LinuxSampler";
157     }
158    
159     void AudioOutputDeviceJack::ParameterName::OnSetValue(String s) throw (LinuxSamplerException) {
160     // not possible, as parameter is fix
161     }
162    
163     String AudioOutputDeviceJack::ParameterName::Name() {
164     return "NAME";
165     }
166    
167    
168    
169 schoenebeck 226 // *************** AudioOutputDeviceJack ***************
170     // *
171    
172 schoenebeck 200 /**
173     * Open and initialize connection to the JACK system.
174     *
175     * @param Parameters - optional parameters
176     * @throws AudioOutputException on error
177     * @see AcquireChannels()
178     */
179 schoenebeck 226 AudioOutputDeviceJack::AudioOutputDeviceJack(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters) {
180 schoenebeck 374 if (((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString().size() >= jack_client_name_size())
181     throw LinuxSamplerException("JACK client name too long");
182    
183     if ((hJackClient = jack_client_new(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString().c_str())) == 0)
184 schoenebeck 200 throw AudioOutputException("Seems Jack server not running.");
185    
186 schoenebeck 374 existingJackDevices++;
187    
188 schoenebeck 200 jack_set_process_callback(hJackClient, __libjack_process_callback, this);
189     jack_on_shutdown(hJackClient, __libjack_shutdown_callback, this);
190     if (jack_activate(hJackClient))
191     throw AudioOutputException("Jack: Cannot activate Jack client.");
192    
193     uiMaxSamplesPerCycle = jack_get_buffer_size(hJackClient);
194    
195 schoenebeck 226 // create audio channels
196     AcquireChannels(((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt());
197 schoenebeck 227
198     // finally activate device if desired
199     if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) Play();
200 schoenebeck 200 }
201    
202     AudioOutputDeviceJack::~AudioOutputDeviceJack() {
203     // destroy jack client
204     jack_client_close(hJackClient);
205 schoenebeck 374 existingJackDevices--;
206 schoenebeck 200 }
207    
208     /**
209     * This method should not be called directly! It will be called by
210     * libjack to demand transmission of further sample points.
211     */
212     int AudioOutputDeviceJack::Process(uint Samples) {
213     if (csIsPlaying.Pop()) {
214     // let all connected engines render 'Samples' sample points
215     return RenderAudio(Samples);
216     }
217     else {
218     // playback stop by zeroing output buffer(s) and not calling connected sampler engines to render audio
219     return RenderSilence(Samples);
220     }
221     }
222    
223     void AudioOutputDeviceJack::Play() {
224     csIsPlaying.PushAndUnlock(true);
225     }
226    
227     bool AudioOutputDeviceJack::IsPlaying() {
228     csIsPlaying.GetUnsafe();
229     }
230    
231     void AudioOutputDeviceJack::Stop() {
232     csIsPlaying.PushAndUnlock(false);
233     }
234    
235 schoenebeck 226 AudioChannel* AudioOutputDeviceJack::CreateChannel(uint ChannelNr) {
236     return new AudioChannelJack(ChannelNr, this);
237 schoenebeck 200 }
238    
239     uint AudioOutputDeviceJack::MaxSamplesPerCycle() {
240     return jack_get_buffer_size(hJackClient);
241     }
242    
243     uint AudioOutputDeviceJack::SampleRate() {
244     return jack_get_sample_rate(hJackClient);
245     }
246    
247     String AudioOutputDeviceJack::Name() {
248 schoenebeck 221 return "JACK";
249 schoenebeck 200 }
250    
251     String AudioOutputDeviceJack::Driver() {
252     return Name();
253     }
254    
255     String AudioOutputDeviceJack::Description() {
256     return "JACK Audio Connection Kit";
257     }
258    
259     String AudioOutputDeviceJack::Version() {
260 schoenebeck 483 String s = "$Revision: 1.18 $";
261 schoenebeck 200 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
262     }
263    
264     // libjack callback functions
265    
266     int __libjack_process_callback(jack_nframes_t nframes, void* arg) {
267     AudioOutputDeviceJack* pAudioOutputDeviceJack = (AudioOutputDeviceJack*) arg;
268     return pAudioOutputDeviceJack->Process(nframes);
269     }
270    
271     void __libjack_shutdown_callback(void* arg) {
272     AudioOutputDeviceJack* pAudioOutputDeviceJack = (AudioOutputDeviceJack*) arg;
273     pAudioOutputDeviceJack->Stop();
274     fprintf(stderr, "Jack: Jack server shutdown, exiting.\n");
275     }
276    
277     } // namespace LinuxSampler
278    
279     #endif // HAVE_JACK

  ViewVC Help
Powered by ViewVC