/[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 374 - (hide annotations) (download)
Sat Feb 12 00:36:08 2005 UTC (19 years, 1 month 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 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 capela 268 #include <errno.h>
27    
28 schoenebeck 200 #if HAVE_JACK
29    
30     namespace LinuxSampler {
31    
32 schoenebeck 374 /// number of currently existing JACK audio output devices in LinuxSampler
33     static int existingJackDevices = 0;
34    
35     // *************** AudioChannelJack::ParameterName ***************
36 schoenebeck 226 // *
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 schoenebeck 227 if (jack_port_set_name(pChannel->hJackPort, s.c_str())) throw AudioOutputException("Failed to rename JACK port");
44 schoenebeck 226 }
45    
46    
47    
48 schoenebeck 374 // *************** AudioChannelJack::ParameterJackBindings ***************
49 schoenebeck 226 // *
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 schoenebeck 227 const char** pPortNames = jack_get_ports(pChannel->pDevice->hJackClient, NULL, NULL, JackPortIsInput);
65 schoenebeck 226 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 schoenebeck 227 // TODO: we should remove all existing bindings before we connect new ones here
74     String src_name = "LinuxSampler:" + ((DeviceRuntimeParameterString*)pChannel->Parameters["NAME"])->ValueAsString();
75 schoenebeck 226 for (int i = 0; i < vS.size(); i++) {
76     String dst_name = vS[i];
77 schoenebeck 227 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 schoenebeck 226 }
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 schoenebeck 227 String port_id = ToString(ChannelNr);
105 schoenebeck 226 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 schoenebeck 374 // *************** 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 schoenebeck 226 // *************** AudioOutputDeviceJack ***************
157     // *
158    
159 schoenebeck 200 /**
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 schoenebeck 226 AudioOutputDeviceJack::AudioOutputDeviceJack(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters) {
167 schoenebeck 374 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 schoenebeck 200 throw AudioOutputException("Seems Jack server not running.");
172    
173 schoenebeck 374 existingJackDevices++;
174    
175 schoenebeck 200 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 schoenebeck 226 // create audio channels
183     AcquireChannels(((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt());
184 schoenebeck 227
185     // finally activate device if desired
186     if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) Play();
187 schoenebeck 200 }
188    
189     AudioOutputDeviceJack::~AudioOutputDeviceJack() {
190     // destroy jack client
191     jack_client_close(hJackClient);
192 schoenebeck 374 existingJackDevices--;
193 schoenebeck 200 }
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 schoenebeck 226 AudioChannel* AudioOutputDeviceJack::CreateChannel(uint ChannelNr) {
223     return new AudioChannelJack(ChannelNr, this);
224 schoenebeck 200 }
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 schoenebeck 221 return "JACK";
236 schoenebeck 200 }
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 schoenebeck 374 String s = "$Revision: 1.15 $";
248 schoenebeck 200 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