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

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 persson 379 #ifndef HAVE_JACK_CLIENT_NAME_SIZE
31     #define jack_client_name_size() 33
32     #endif
33    
34 schoenebeck 200 namespace LinuxSampler {
35    
36 schoenebeck 374 /// number of currently existing JACK audio output devices in LinuxSampler
37     static int existingJackDevices = 0;
38    
39     // *************** AudioChannelJack::ParameterName ***************
40 schoenebeck 226 // *
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 schoenebeck 227 if (jack_port_set_name(pChannel->hJackPort, s.c_str())) throw AudioOutputException("Failed to rename JACK port");
48 schoenebeck 226 }
49    
50    
51    
52 schoenebeck 374 // *************** AudioChannelJack::ParameterJackBindings ***************
53 schoenebeck 226 // *
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 schoenebeck 227 const char** pPortNames = jack_get_ports(pChannel->pDevice->hJackClient, NULL, NULL, JackPortIsInput);
69 schoenebeck 226 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 schoenebeck 227 // TODO: we should remove all existing bindings before we connect new ones here
78     String src_name = "LinuxSampler:" + ((DeviceRuntimeParameterString*)pChannel->Parameters["NAME"])->ValueAsString();
79 schoenebeck 226 for (int i = 0; i < vS.size(); i++) {
80     String dst_name = vS[i];
81 schoenebeck 227 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 schoenebeck 226 }
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 schoenebeck 227 String port_id = ToString(ChannelNr);
109 schoenebeck 226 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 schoenebeck 374 // *************** 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 schoenebeck 226 // *************** AudioOutputDeviceJack ***************
161     // *
162    
163 schoenebeck 200 /**
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 schoenebeck 226 AudioOutputDeviceJack::AudioOutputDeviceJack(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters) {
171 schoenebeck 374 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 schoenebeck 200 throw AudioOutputException("Seems Jack server not running.");
176    
177 schoenebeck 374 existingJackDevices++;
178    
179 schoenebeck 200 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 schoenebeck 226 // create audio channels
187     AcquireChannels(((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt());
188 schoenebeck 227
189     // finally activate device if desired
190     if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) Play();
191 schoenebeck 200 }
192    
193     AudioOutputDeviceJack::~AudioOutputDeviceJack() {
194     // destroy jack client
195     jack_client_close(hJackClient);
196 schoenebeck 374 existingJackDevices--;
197 schoenebeck 200 }
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 schoenebeck 226 AudioChannel* AudioOutputDeviceJack::CreateChannel(uint ChannelNr) {
227     return new AudioChannelJack(ChannelNr, this);
228 schoenebeck 200 }
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 schoenebeck 221 return "JACK";
240 schoenebeck 200 }
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 persson 379 String s = "$Revision: 1.16 $";
252 schoenebeck 200 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