/[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 227 - (show annotations) (download)
Thu Aug 26 22:05:44 2004 UTC (19 years, 7 months ago) by schoenebeck
File size: 9023 byte(s)
* ALSA audio driver: bugfix in device parameter 'CARD' which caused an
  error message if used in conjunction with 'CREATE AUDIO_OUTPUT_DEVICE'
  LSCP command
* JACK audio driver: fixed minor JACK port name issue and the device was
  not activated by default on creation which caused it to render solely
  silence
* src/network/lscpserver.cpp: retry to bind socket for 3 minutes if bind
  failed

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

  ViewVC Help
Powered by ViewVC