Chris@297
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@297
|
2
|
Chris@297
|
3 /*
|
Chris@297
|
4 Sonic Visualiser
|
Chris@297
|
5 An audio file viewer and annotation editor.
|
Chris@297
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@297
|
7 This file copyright 2007 QMUL.
|
Chris@297
|
8
|
Chris@297
|
9 This program is free software; you can redistribute it and/or
|
Chris@297
|
10 modify it under the terms of the GNU General Public License as
|
Chris@297
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@297
|
12 License, or (at your option) any later version. See the file
|
Chris@297
|
13 COPYING included with this distribution for more information.
|
Chris@297
|
14 */
|
Chris@297
|
15
|
Chris@297
|
16 #include "AggregateWaveModel.h"
|
Chris@297
|
17
|
Chris@297
|
18 #include <iostream>
|
Chris@297
|
19
|
Chris@314
|
20 #include <QTextStream>
|
Chris@314
|
21
|
Chris@1096
|
22 using namespace std;
|
Chris@1096
|
23
|
Chris@1556
|
24 //#define DEBUG_AGGREGATE_WAVE_FILE_MODEL 1
|
Chris@1556
|
25
|
Chris@297
|
26 PowerOfSqrtTwoZoomConstraint
|
Chris@297
|
27 AggregateWaveModel::m_zoomConstraint;
|
Chris@297
|
28
|
Chris@297
|
29 AggregateWaveModel::AggregateWaveModel(ChannelSpecList channelSpecs) :
|
Chris@1732
|
30 m_components(channelSpecs)
|
Chris@297
|
31 {
|
Chris@1732
|
32 sv_samplerate_t overallRate = 0;
|
Chris@1389
|
33
|
Chris@1732
|
34 for (int channel = 0; in_range_for(m_components, channel); ++channel) {
|
Chris@1732
|
35
|
Chris@1732
|
36 auto model = ModelById::getAs<RangeSummarisableTimeValueModel>
|
Chris@1732
|
37 (m_components[channel].model);
|
Chris@1732
|
38
|
Chris@1732
|
39 if (!model) {
|
Chris@1732
|
40 SVCERR << "AggregateWaveModel: WARNING: component for channel "
|
Chris@1732
|
41 << channel << " is not found or is of wrong model type"
|
Chris@1732
|
42 << endl;
|
Chris@1732
|
43 continue;
|
Chris@1732
|
44 }
|
Chris@1732
|
45
|
Chris@1732
|
46 sv_samplerate_t rate = model->getSampleRate();
|
Chris@1732
|
47
|
Chris@1732
|
48 if (!rate) {
|
Chris@1732
|
49 SVCERR << "AggregateWaveModel: WARNING: component for channel "
|
Chris@1732
|
50 << channel << " reports zero sample rate" << endl;
|
Chris@1732
|
51
|
Chris@1732
|
52 } else if (!overallRate) {
|
Chris@1732
|
53
|
Chris@1732
|
54 overallRate = rate;
|
Chris@1732
|
55
|
Chris@1732
|
56 } else if (rate != overallRate) {
|
Chris@1732
|
57 SVCERR << "AggregateWaveModel: WARNING: component for channel "
|
Chris@1732
|
58 << channel << " has different sample rate from earlier "
|
Chris@1732
|
59 << "channels (has " << rate << ", expected " << overallRate
|
Chris@1732
|
60 << ")" << endl;
|
Chris@297
|
61 }
|
Chris@1770
|
62
|
Chris@1770
|
63 connect(model.get(), SIGNAL(modelChanged(ModelId)),
|
Chris@1770
|
64 this, SLOT(componentModelChanged(ModelId)));
|
Chris@1770
|
65 connect(model.get(), SIGNAL(modelChangedWithin(ModelId, sv_frame_t, sv_frame_t)),
|
Chris@1770
|
66 this, SLOT(componentModelChangedWithin(ModelId, sv_frame_t, sv_frame_t)));
|
Chris@1770
|
67 connect(model.get(), SIGNAL(completionChanged(ModelId)),
|
Chris@1770
|
68 this, SLOT(componentModelCompletionChanged(ModelId)));
|
Chris@297
|
69 }
|
Chris@297
|
70 }
|
Chris@297
|
71
|
Chris@297
|
72 AggregateWaveModel::~AggregateWaveModel()
|
Chris@297
|
73 {
|
Chris@1688
|
74 SVDEBUG << "AggregateWaveModel::~AggregateWaveModel" << endl;
|
Chris@297
|
75 }
|
Chris@297
|
76
|
Chris@297
|
77 bool
|
Chris@297
|
78 AggregateWaveModel::isOK() const
|
Chris@297
|
79 {
|
Chris@1732
|
80 if (m_components.empty()) {
|
Chris@1389
|
81 return false;
|
Chris@1389
|
82 }
|
Chris@1732
|
83 for (const auto &c: m_components) {
|
Chris@1732
|
84 auto model = ModelById::get(c.model);
|
Chris@1732
|
85 if (!model || !model->isOK()) {
|
Chris@1389
|
86 return false;
|
Chris@1389
|
87 }
|
Chris@297
|
88 }
|
Chris@297
|
89 return true;
|
Chris@297
|
90 }
|
Chris@297
|
91
|
Chris@297
|
92 bool
|
Chris@297
|
93 AggregateWaveModel::isReady(int *completion) const
|
Chris@297
|
94 {
|
Chris@297
|
95 if (completion) *completion = 100;
|
Chris@1389
|
96
|
Chris@297
|
97 bool ready = true;
|
Chris@1732
|
98 for (auto c: m_components) {
|
Chris@297
|
99 int completionHere = 100;
|
Chris@1732
|
100 auto model = ModelById::get(c.model);
|
Chris@1732
|
101 if (!model) continue;
|
Chris@1732
|
102 if (!model->isReady(&completionHere)) {
|
Chris@1556
|
103 ready = false;
|
Chris@1556
|
104 }
|
Chris@297
|
105 if (completion && completionHere < *completion) {
|
Chris@297
|
106 *completion = completionHere;
|
Chris@297
|
107 }
|
Chris@297
|
108 }
|
Chris@1556
|
109
|
Chris@1556
|
110 #ifdef DEBUG_AGGREGATE_WAVE_FILE_MODEL
|
Chris@1556
|
111 SVDEBUG << "AggregateWaveModel(" << objectName()
|
Chris@1556
|
112 << ")::isReady: returning " << ready << endl;
|
Chris@1556
|
113 #endif
|
Chris@1556
|
114
|
Chris@297
|
115 return ready;
|
Chris@297
|
116 }
|
Chris@297
|
117
|
Chris@1038
|
118 sv_frame_t
|
Chris@297
|
119 AggregateWaveModel::getFrameCount() const
|
Chris@297
|
120 {
|
Chris@1038
|
121 sv_frame_t count = 0;
|
Chris@1732
|
122 for (auto c: m_components) {
|
Chris@1732
|
123 auto model = ModelById::get(c.model);
|
Chris@1732
|
124 if (!model) continue;
|
Chris@1732
|
125 sv_frame_t thisCount = model->getEndFrame() - model->getStartFrame();
|
Chris@297
|
126 if (thisCount > count) count = thisCount;
|
Chris@297
|
127 }
|
Chris@297
|
128 return count;
|
Chris@297
|
129 }
|
Chris@297
|
130
|
Chris@929
|
131 int
|
Chris@297
|
132 AggregateWaveModel::getChannelCount() const
|
Chris@297
|
133 {
|
Chris@1038
|
134 return int(m_components.size());
|
Chris@297
|
135 }
|
Chris@297
|
136
|
Chris@1040
|
137 sv_samplerate_t
|
Chris@297
|
138 AggregateWaveModel::getSampleRate() const
|
Chris@297
|
139 {
|
Chris@1732
|
140 if (m_components.empty()) return 0;
|
Chris@1732
|
141 auto model = ModelById::get(m_components.begin()->model);
|
Chris@1732
|
142 if (!model) return 0;
|
Chris@1732
|
143 return model->getSampleRate();
|
Chris@297
|
144 }
|
Chris@297
|
145
|
Chris@1326
|
146 floatvec_t
|
Chris@1096
|
147 AggregateWaveModel::getData(int channel, sv_frame_t start, sv_frame_t count) const
|
Chris@297
|
148 {
|
Chris@1732
|
149 if (m_components.empty()) return {};
|
Chris@1732
|
150
|
Chris@297
|
151 int ch0 = channel, ch1 = channel;
|
Chris@297
|
152 if (channel == -1) {
|
Chris@297
|
153 ch0 = 0;
|
Chris@297
|
154 ch1 = getChannelCount()-1;
|
Chris@1732
|
155 } else if (!in_range_for(m_components, channel)) {
|
Chris@1732
|
156 return {};
|
Chris@297
|
157 }
|
Chris@297
|
158
|
Chris@1326
|
159 floatvec_t result(count, 0.f);
|
Chris@1038
|
160 sv_frame_t longest = 0;
|
Chris@1008
|
161
|
Chris@297
|
162 for (int c = ch0; c <= ch1; ++c) {
|
Chris@1096
|
163
|
Chris@1732
|
164 auto model = ModelById::getAs<RangeSummarisableTimeValueModel>
|
Chris@1732
|
165 (m_components[c].model);
|
Chris@1732
|
166 if (!model) continue;
|
Chris@1732
|
167
|
Chris@1732
|
168 auto here = model->getData(m_components[c].channel, start, count);
|
Chris@1100
|
169 if (sv_frame_t(here.size()) > longest) {
|
Chris@1100
|
170 longest = sv_frame_t(here.size());
|
Chris@1008
|
171 }
|
Chris@1096
|
172 for (sv_frame_t i = 0; in_range_for(here, i); ++i) {
|
Chris@1096
|
173 result[i] += here[i];
|
Chris@297
|
174 }
|
Chris@297
|
175 }
|
Chris@297
|
176
|
Chris@1096
|
177 result.resize(longest);
|
Chris@1096
|
178 return result;
|
Chris@297
|
179 }
|
Chris@363
|
180
|
Chris@1326
|
181 vector<floatvec_t>
|
Chris@1086
|
182 AggregateWaveModel::getMultiChannelData(int fromchannel, int tochannel,
|
Chris@1096
|
183 sv_frame_t start, sv_frame_t count) const
|
Chris@363
|
184 {
|
Chris@1038
|
185 sv_frame_t min = count;
|
Chris@363
|
186
|
Chris@1326
|
187 vector<floatvec_t> result;
|
Chris@1096
|
188
|
Chris@929
|
189 for (int c = fromchannel; c <= tochannel; ++c) {
|
Chris@1096
|
190 auto here = getData(c, start, count);
|
Chris@1100
|
191 if (sv_frame_t(here.size()) < min) {
|
Chris@1100
|
192 min = sv_frame_t(here.size());
|
Chris@1100
|
193 }
|
Chris@1096
|
194 result.push_back(here);
|
Chris@1096
|
195 }
|
Chris@1096
|
196
|
Chris@1096
|
197 if (min < count) {
|
Chris@1096
|
198 for (auto &v : result) v.resize(min);
|
Chris@363
|
199 }
|
Chris@363
|
200
|
Chris@1096
|
201 return result;
|
Chris@363
|
202 }
|
Chris@377
|
203
|
Chris@929
|
204 int
|
Chris@929
|
205 AggregateWaveModel::getSummaryBlockSize(int desired) const
|
Chris@377
|
206 {
|
Chris@377
|
207 //!!! complete
|
Chris@377
|
208 return desired;
|
Chris@377
|
209 }
|
Chris@297
|
210
|
Chris@297
|
211 void
|
Chris@1038
|
212 AggregateWaveModel::getSummaries(int, sv_frame_t, sv_frame_t,
|
Chris@929
|
213 RangeBlock &, int &) const
|
Chris@297
|
214 {
|
Chris@297
|
215 //!!! complete
|
Chris@297
|
216 }
|
Chris@297
|
217
|
Chris@297
|
218 AggregateWaveModel::Range
|
Chris@1038
|
219 AggregateWaveModel::getSummary(int, sv_frame_t, sv_frame_t) const
|
Chris@297
|
220 {
|
Chris@297
|
221 //!!! complete
|
Chris@297
|
222 return Range();
|
Chris@297
|
223 }
|
Chris@297
|
224
|
Chris@929
|
225 int
|
Chris@297
|
226 AggregateWaveModel::getComponentCount() const
|
Chris@297
|
227 {
|
Chris@1038
|
228 return int(m_components.size());
|
Chris@297
|
229 }
|
Chris@297
|
230
|
Chris@297
|
231 AggregateWaveModel::ModelChannelSpec
|
Chris@929
|
232 AggregateWaveModel::getComponent(int c) const
|
Chris@297
|
233 {
|
Chris@297
|
234 return m_components[c];
|
Chris@297
|
235 }
|
Chris@297
|
236
|
Chris@297
|
237 void
|
Chris@1770
|
238 AggregateWaveModel::componentModelChanged(ModelId)
|
Chris@297
|
239 {
|
Chris@1770
|
240 emit modelChanged(getId());
|
Chris@297
|
241 }
|
Chris@297
|
242
|
Chris@297
|
243 void
|
Chris@1770
|
244 AggregateWaveModel::componentModelChangedWithin(ModelId, sv_frame_t start, sv_frame_t end)
|
Chris@297
|
245 {
|
Chris@1770
|
246 emit modelChangedWithin(getId(), start, end);
|
Chris@297
|
247 }
|
Chris@297
|
248
|
Chris@297
|
249 void
|
Chris@1770
|
250 AggregateWaveModel::componentModelCompletionChanged(ModelId)
|
Chris@297
|
251 {
|
Chris@1770
|
252 emit completionChanged(getId());
|
Chris@297
|
253 }
|
Chris@297
|
254
|
Chris@297
|
255 void
|
Chris@1391
|
256 AggregateWaveModel::toXml(QTextStream &out,
|
Chris@1391
|
257 QString indent,
|
Chris@1391
|
258 QString extraAttributes) const
|
Chris@297
|
259 {
|
Chris@1391
|
260 QStringList componentStrings;
|
Chris@1391
|
261 for (const auto &c: m_components) {
|
Chris@1732
|
262 auto model = ModelById::get(c.model);
|
Chris@1732
|
263 if (!model) continue;
|
Chris@1732
|
264 componentStrings.push_back(QString("%1").arg(model->getExportId()));
|
Chris@1391
|
265 }
|
Chris@1391
|
266 Model::toXml(out, indent,
|
Chris@1391
|
267 QString("type=\"aggregatewave\" components=\"%1\" %2")
|
Chris@1391
|
268 .arg(componentStrings.join(","))
|
Chris@1391
|
269 .arg(extraAttributes));
|
Chris@297
|
270 }
|
Chris@297
|
271
|