/[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 379 - (show annotations) (download)
Sun Feb 13 18:02:29 2005 UTC (19 years, 1 month ago) by persson
File size: 10771 byte(s)
* small fix for building with old JACK versions (0.94 and earlier)

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

  ViewVC Help
Powered by ViewVC