/[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 374 - (show annotations) (download)
Sat Feb 12 00:36:08 2005 UTC (19 years, 2 months ago) by schoenebeck
File size: 10693 byte(s)
* JACK audio driver: added device creation parameter 'NAME' which can be
  used to assign an arbitrary name to the JACK client, it's now possible to
  create multiple JACK audio output devices simultaniously for LS
* src/network/lscpserver.cpp: fixed little bug in
  'SET CHANNEL AUDIO_OUTPUT_CHANNEL' (altering of audio routing)
  implementation, cleanup of error messages

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

  ViewVC Help
Powered by ViewVC