Mercurial > hg > svapp
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 |