comparison audioio/AudioJACKTarget.cpp @ 0:cd5d7ff8ef38

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