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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 403 - (show annotations) (download)
Tue Feb 22 20:37:59 2005 UTC (19 years ago) by schoenebeck
File size: 10876 byte(s)
* JACK driver: fixed channel parameter 'JACK_BINDINGS' which did not work
  for a multi JACK device setup

1 /***************************************************************************
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 #include <errno.h>
27
28 #if HAVE_JACK
29
30 #ifndef HAVE_JACK_CLIENT_NAME_SIZE
31 #define jack_client_name_size() 33
32 #endif
33
34 namespace LinuxSampler {
35
36 /// number of currently existing JACK audio output devices in LinuxSampler
37 static int existingJackDevices = 0;
38
39 // *************** AudioChannelJack::ParameterName ***************
40 // *
41
42 AudioOutputDeviceJack::AudioChannelJack::ParameterName::ParameterName(AudioChannelJack* pChannel) : AudioChannel::ParameterName(ToString(pChannel->ChannelNr)) {
43 this->pChannel = pChannel;
44 }
45
46 void AudioOutputDeviceJack::AudioChannelJack::ParameterName::OnSetValue(String s) {
47 if (jack_port_set_name(pChannel->hJackPort, s.c_str())) throw AudioOutputException("Failed to rename JACK port");
48 }
49
50
51
52 // *************** AudioChannelJack::ParameterJackBindings ***************
53 // *
54
55 AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::ParameterJackBindings(AudioChannelJack* pChannel) : DeviceRuntimeParameterStrings(std::vector<String>()) {
56 this->pChannel = pChannel;
57 }
58
59 String AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Description() {
60 return "Bindings to other JACK clients";
61 }
62
63 bool AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Fix() {
64 return false;
65 }
66
67 std::vector<String> AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::PossibilitiesAsString() {
68 const char** pPortNames = jack_get_ports(pChannel->pDevice->hJackClient, NULL, NULL, JackPortIsInput);
69 if (!pPortNames) return std::vector<String>();
70 std::vector<String> result;
71 for (int i = 0; pPortNames[i]; i++) result.push_back(pPortNames[i]);
72 //free(pPortNames); FIXME: pPortNames should be freed here
73 return result;
74 }
75
76 void AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::OnSetValue(std::vector<String> vS) {
77 // TODO: we should remove all existing bindings before we connect new ones here
78 String src_name = ((DeviceCreationParameterString*)pChannel->pDevice->Parameters["NAME"])->ValueAsString() + ":" +
79 ((DeviceRuntimeParameterString*)pChannel->Parameters["NAME"])->ValueAsString();
80 for (int i = 0; i < vS.size(); i++) {
81 String dst_name = vS[i];
82 int res = jack_connect(pChannel->pDevice->hJackClient, src_name.c_str(), dst_name.c_str());
83 if (res == EEXIST) throw AudioOutputException("Jack: Connection to port '" + dst_name + "' already established");
84 else if (res) throw AudioOutputException("Jack: Cannot connect port '" + src_name + "' to port '" + dst_name + "'");
85 }
86 }
87
88 String AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Name() {
89 return "JACK_BINDINGS";
90 }
91
92
93
94 // *************** AudioChannelJack ***************
95 // *
96
97 AudioOutputDeviceJack::AudioChannelJack::AudioChannelJack(uint ChannelNr, AudioOutputDeviceJack* pDevice) throw (AudioOutputException) : AudioChannel(ChannelNr, CreateJackPort(ChannelNr, pDevice), pDevice->uiMaxSamplesPerCycle) {
98 this->pDevice = pDevice;
99 this->ChannelNr = ChannelNr;
100 Parameters["NAME"] = new ParameterName(this);
101 Parameters["JACK_BINDINGS"] = new ParameterJackBindings(this);
102 }
103
104 AudioOutputDeviceJack::AudioChannelJack::~AudioChannelJack() {
105 //TODO: delete JACK port
106 }
107
108 float* AudioOutputDeviceJack::AudioChannelJack::CreateJackPort(uint ChannelNr, AudioOutputDeviceJack* pDevice) throw (AudioOutputException) {
109 String port_id = ToString(ChannelNr);
110 hJackPort = jack_port_register(pDevice->hJackClient, port_id.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
111 if (!hJackPort) throw AudioOutputException("Jack: Cannot register Jack output port.");
112 return (float*) jack_port_get_buffer(hJackPort, pDevice->uiMaxSamplesPerCycle);
113 }
114
115
116
117 // *************** AudioOutputDeviceJack::ParameterName ***************
118 // *
119
120 AudioOutputDeviceJack::ParameterName::ParameterName() : DeviceCreationParameterString() {
121 InitWithDefault(); // use default name
122 }
123
124 AudioOutputDeviceJack::ParameterName::ParameterName(String s) throw (LinuxSamplerException) : DeviceCreationParameterString(s) {
125 }
126
127 String AudioOutputDeviceJack::ParameterName::Description() {
128 return "Arbitrary JACK client name";
129 }
130
131 bool AudioOutputDeviceJack::ParameterName::Fix() {
132 return true;
133 }
134
135 bool AudioOutputDeviceJack::ParameterName::Mandatory() {
136 return false;
137 }
138
139 std::map<String,DeviceCreationParameter*> AudioOutputDeviceJack::ParameterName::DependsAsParameters() {
140 return std::map<String,DeviceCreationParameter*>(); // no dependencies
141 }
142
143 std::vector<String> AudioOutputDeviceJack::ParameterName::PossibilitiesAsString(std::map<String,String> Parameters) {
144 return std::vector<String>();
145 }
146
147 optional<String> AudioOutputDeviceJack::ParameterName::DefaultAsString(std::map<String,String> Parameters) {
148 return (existingJackDevices) ? "LinuxSampler" + ToString(existingJackDevices) : "LinuxSampler";
149 }
150
151 void AudioOutputDeviceJack::ParameterName::OnSetValue(String s) throw (LinuxSamplerException) {
152 // not possible, as parameter is fix
153 }
154
155 String AudioOutputDeviceJack::ParameterName::Name() {
156 return "NAME";
157 }
158
159
160
161 // *************** AudioOutputDeviceJack ***************
162 // *
163
164 /**
165 * Open and initialize connection to the JACK system.
166 *
167 * @param Parameters - optional parameters
168 * @throws AudioOutputException on error
169 * @see AcquireChannels()
170 */
171 AudioOutputDeviceJack::AudioOutputDeviceJack(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters) {
172 if (((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString().size() >= jack_client_name_size())
173 throw LinuxSamplerException("JACK client name too long");
174
175 if ((hJackClient = jack_client_new(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString().c_str())) == 0)
176 throw AudioOutputException("Seems Jack server not running.");
177
178 existingJackDevices++;
179
180 jack_set_process_callback(hJackClient, __libjack_process_callback, this);
181 jack_on_shutdown(hJackClient, __libjack_shutdown_callback, this);
182 if (jack_activate(hJackClient))
183 throw AudioOutputException("Jack: Cannot activate Jack client.");
184
185 uiMaxSamplesPerCycle = jack_get_buffer_size(hJackClient);
186
187 // create audio channels
188 AcquireChannels(((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt());
189
190 // finally activate device if desired
191 if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) Play();
192 }
193
194 AudioOutputDeviceJack::~AudioOutputDeviceJack() {
195 // destroy jack client
196 jack_client_close(hJackClient);
197 existingJackDevices--;
198 }
199
200 /**
201 * This method should not be called directly! It will be called by
202 * libjack to demand transmission of further sample points.
203 */
204 int AudioOutputDeviceJack::Process(uint Samples) {
205 if (csIsPlaying.Pop()) {
206 // let all connected engines render 'Samples' sample points
207 return RenderAudio(Samples);
208 }
209 else {
210 // playback stop by zeroing output buffer(s) and not calling connected sampler engines to render audio
211 return RenderSilence(Samples);
212 }
213 }
214
215 void AudioOutputDeviceJack::Play() {
216 csIsPlaying.PushAndUnlock(true);
217 }
218
219 bool AudioOutputDeviceJack::IsPlaying() {
220 csIsPlaying.GetUnsafe();
221 }
222
223 void AudioOutputDeviceJack::Stop() {
224 csIsPlaying.PushAndUnlock(false);
225 }
226
227 AudioChannel* AudioOutputDeviceJack::CreateChannel(uint ChannelNr) {
228 return new AudioChannelJack(ChannelNr, this);
229 }
230
231 uint AudioOutputDeviceJack::MaxSamplesPerCycle() {
232 return jack_get_buffer_size(hJackClient);
233 }
234
235 uint AudioOutputDeviceJack::SampleRate() {
236 return jack_get_sample_rate(hJackClient);
237 }
238
239 String AudioOutputDeviceJack::Name() {
240 return "JACK";
241 }
242
243 String AudioOutputDeviceJack::Driver() {
244 return Name();
245 }
246
247 String AudioOutputDeviceJack::Description() {
248 return "JACK Audio Connection Kit";
249 }
250
251 String AudioOutputDeviceJack::Version() {
252 String s = "$Revision: 1.17 $";
253 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
254 }
255
256 // libjack callback functions
257
258 int __libjack_process_callback(jack_nframes_t nframes, void* arg) {
259 AudioOutputDeviceJack* pAudioOutputDeviceJack = (AudioOutputDeviceJack*) arg;
260 return pAudioOutputDeviceJack->Process(nframes);
261 }
262
263 void __libjack_shutdown_callback(void* arg) {
264 AudioOutputDeviceJack* pAudioOutputDeviceJack = (AudioOutputDeviceJack*) arg;
265 pAudioOutputDeviceJack->Stop();
266 fprintf(stderr, "Jack: Jack server shutdown, exiting.\n");
267 }
268
269 } // namespace LinuxSampler
270
271 #endif // HAVE_JACK

  ViewVC Help
Powered by ViewVC