comparison audioio/AudioJACKTarget.cpp @ 0:db6fcbd4405c

initial import
author Chris Cannam
date Tue, 10 Jan 2006 16:33:16 +0000
parents
children df5923e33d01
comparison
equal deleted inserted replaced
-1:000000000000 0:db6fcbd4405c
1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 A waveform viewer and audio annotation editor.
5 Chris Cannam, Queen Mary University of London, 2005
6
7 This is experimental software. Not for distribution.
8 */
9
10 #ifdef HAVE_JACK
11
12 #include "AudioJACKTarget.h"
13 #include "AudioCallbackPlaySource.h"
14
15 #include <iostream>
16
17 //#define DEBUG_AUDIO_JACK_TARGET 1
18
19 AudioJACKTarget::AudioJACKTarget(AudioCallbackPlaySource *source) :
20 AudioCallbackPlayTarget(source),
21 m_client(0),
22 m_bufferSize(0),
23 m_sampleRate(0)
24 {
25 char name[20];
26 strcpy(name, "Sonic Visualiser");
27 m_client = jack_client_new(name);
28
29 if (!m_client) {
30 sprintf(name, "Sonic Visualiser (%d)", (int)getpid());
31 m_client = jack_client_new(name);
32 if (!m_client) {
33 std::cerr
34 << "ERROR: AudioJACKTarget: Failed to connect to JACK server"
35 << std::endl;
36 }
37 }
38
39 if (!m_client) return;
40
41 m_bufferSize = jack_get_buffer_size(m_client);
42 m_sampleRate = jack_get_sample_rate(m_client);
43
44 jack_set_process_callback(m_client, processStatic, this);
45
46 if (jack_activate(m_client)) {
47 std::cerr << "ERROR: AudioJACKTarget: Failed to activate JACK client"
48 << std::endl;
49 }
50
51 if (m_source) {
52 sourceModelReplaced();
53 }
54 }
55
56 AudioJACKTarget::~AudioJACKTarget()
57 {
58 if (m_client) {
59 jack_deactivate(m_client);
60 jack_client_close(m_client);
61 }
62 }
63
64 bool
65 AudioJACKTarget::isOK() const
66 {
67 return (m_client != 0);
68 }
69
70 int
71 AudioJACKTarget::processStatic(jack_nframes_t nframes, void *arg)
72 {
73 return ((AudioJACKTarget *)arg)->process(nframes);
74 }
75
76 void
77 AudioJACKTarget::sourceModelReplaced()
78 {
79 m_mutex.lock();
80
81 m_source->setTargetBlockSize(m_bufferSize);
82 m_source->setTargetSampleRate(m_sampleRate);
83
84 size_t channels = m_source->getSourceChannelCount();
85
86 if (channels == m_outputs.size() || !m_client) {
87 m_mutex.unlock();
88 return;
89 }
90
91 const char **ports =
92 jack_get_ports(m_client, NULL, NULL,
93 JackPortIsPhysical | JackPortIsInput);
94 size_t physicalPortCount = 0;
95 while (ports[physicalPortCount]) ++physicalPortCount;
96
97 #ifdef DEBUG_AUDIO_JACK_TARGET
98 std::cerr << "AudioJACKTarget::sourceModelReplaced: have " << channels << " channels and " << physicalPortCount << " physical ports" << std::endl;
99 #endif
100
101 while (m_outputs.size() < channels) {
102
103 char name[20];
104 jack_port_t *port;
105
106 sprintf(name, "out %d", m_outputs.size() + 1);
107
108 port = jack_port_register(m_client,
109 name,
110 JACK_DEFAULT_AUDIO_TYPE,
111 JackPortIsOutput,
112 0);
113
114 if (!port) {
115 std::cerr
116 << "ERROR: AudioJACKTarget: Failed to create JACK output port "
117 << m_outputs.size() << std::endl;
118 } else {
119 m_source->setTargetPlayLatency(jack_port_get_latency(port));
120 }
121
122 if (m_outputs.size() < physicalPortCount) {
123 jack_connect(m_client, jack_port_name(port), ports[m_outputs.size()]);
124 }
125
126 m_outputs.push_back(port);
127 }
128
129 while (m_outputs.size() > channels) {
130 std::vector<jack_port_t *>::iterator itr = m_outputs.end();
131 --itr;
132 jack_port_t *port = *itr;
133 if (port) jack_port_unregister(m_client, port);
134 m_outputs.erase(itr);
135 }
136
137 m_mutex.unlock();
138 }
139
140 int
141 AudioJACKTarget::process(jack_nframes_t nframes)
142 {
143 if (!m_mutex.tryLock()) {
144 return 0;
145 }
146
147 if (m_outputs.empty()) {
148 m_mutex.unlock();
149 return 0;
150 }
151
152 #ifdef DEBUG_AUDIO_JACK_TARGET
153 std::cout << "AudioJACKTarget::process(" << nframes << "): have a source" << std::endl;
154 #endif
155
156 #ifdef DEBUG_AUDIO_JACK_TARGET
157 if (m_bufferSize != nframes) {
158 std::cerr << "WARNING: m_bufferSize != nframes (" << m_bufferSize << " != " << nframes << ")" << std::endl;
159 }
160 #endif
161
162 float **buffers = (float **)alloca(m_outputs.size() * sizeof(float *));
163
164 for (size_t ch = 0; ch < m_outputs.size(); ++ch) {
165 buffers[ch] = (float *)jack_port_get_buffer(m_outputs[ch], nframes);
166 }
167
168 if (m_source) {
169 m_source->getSourceSamples(nframes, buffers);
170 } else {
171 for (size_t ch = 0; ch < m_outputs.size(); ++ch) {
172 for (size_t i = 0; i < nframes; ++i) {
173 buffers[ch][i] = 0.0;
174 }
175 }
176 }
177
178 float peakLeft = 0.0, peakRight = 0.0;
179
180 for (size_t ch = 0; ch < m_outputs.size(); ++ch) {
181
182 float peak = 0.0;
183
184 for (size_t i = 0; i < nframes; ++i) {
185 buffers[ch][i] *= m_outputGain;
186 float sample = fabsf(buffers[ch][i]);
187 if (sample > peak) peak = sample;
188 }
189
190 if (ch == 0) peakLeft = peak;
191 if (ch > 0 || m_outputs.size() == 1) peakRight = peak;
192 }
193
194 if (m_source) {
195 m_source->setOutputLevels(peakLeft, peakRight);
196 }
197
198 m_mutex.unlock();
199 return 0;
200 }
201
202
203 #ifdef INCLUDE_MOCFILES
204 #include "AudioJACKTarget.moc.cpp"
205 #endif
206
207 #endif /* HAVE_JACK */
208