Mercurial > hg > sonic-visualiser
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 |