Chris@175
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@175
|
2
|
Chris@175
|
3 /*
|
Chris@175
|
4 Sonic Visualiser
|
Chris@175
|
5 An audio file viewer and annotation editor.
|
Chris@175
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@202
|
7 This file copyright 2006 QMUL.
|
Chris@175
|
8
|
Chris@175
|
9 This program is free software; you can redistribute it and/or
|
Chris@175
|
10 modify it under the terms of the GNU General Public License as
|
Chris@175
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@175
|
12 License, or (at your option) any later version. See the file
|
Chris@175
|
13 COPYING included with this distribution for more information.
|
Chris@175
|
14 */
|
Chris@175
|
15
|
Chris@1122
|
16 #ifndef WRITABLE_WAVE_FILE_MODEL_H
|
Chris@1122
|
17 #define WRITABLE_WAVE_FILE_MODEL_H
|
Chris@175
|
18
|
Chris@175
|
19 #include "WaveFileModel.h"
|
Chris@1122
|
20 #include "ReadOnlyWaveFileModel.h"
|
Chris@1122
|
21 #include "PowerOfSqrtTwoZoomConstraint.h"
|
Chris@175
|
22
|
Chris@175
|
23 class WavFileWriter;
|
Chris@175
|
24 class WavFileReader;
|
Chris@175
|
25
|
Chris@1122
|
26 class WritableWaveFileModel : public WaveFileModel
|
Chris@175
|
27 {
|
Chris@175
|
28 Q_OBJECT
|
Chris@175
|
29
|
Chris@175
|
30 public:
|
Chris@1520
|
31 enum class Normalisation { None, Peak };
|
Chris@1520
|
32
|
Chris@1520
|
33 /**
|
Chris@1520
|
34 * Create a WritableWaveFileModel of the given sample rate and
|
Chris@1520
|
35 * channel count, storing data in a new float-type extended WAV
|
Chris@1520
|
36 * file with the given path. If path is the empty string, the data
|
Chris@1520
|
37 * will be stored in a newly-created temporary file.
|
Chris@1520
|
38 *
|
Chris@1520
|
39 * If normalisation == None, sample values will be written
|
Chris@1520
|
40 * verbatim, and will be ready to read as soon as they have been
|
Chris@1520
|
41 * written. Otherwise samples will be normalised on writing; this
|
Chris@1520
|
42 * will require an additional pass and temporary file, and no
|
Chris@1520
|
43 * samples will be available to read until after writeComplete()
|
Chris@1520
|
44 * has returned.
|
Chris@1520
|
45 */
|
Chris@1520
|
46 WritableWaveFileModel(QString path,
|
Chris@1520
|
47 sv_samplerate_t sampleRate,
|
Chris@1520
|
48 int channels,
|
Chris@1520
|
49 Normalisation normalisation);
|
Chris@1520
|
50
|
Chris@1520
|
51 /**
|
Chris@1520
|
52 * Create a WritableWaveFileModel of the given sample rate and
|
Chris@1520
|
53 * channel count, storing data in a new float-type extended WAV
|
Chris@1520
|
54 * file in a temporary location. This is equivalent to passing an
|
Chris@1520
|
55 * empty path to the constructor above.
|
Chris@1520
|
56 *
|
Chris@1520
|
57 * If normalisation == None, sample values will be written
|
Chris@1520
|
58 * verbatim, and will be ready to read as soon as they have been
|
Chris@1520
|
59 * written. Otherwise samples will be normalised on writing; this
|
Chris@1520
|
60 * will require an additional pass and temporary file, and no
|
Chris@1520
|
61 * samples will be available to read until after writeComplete()
|
Chris@1520
|
62 * has returned.
|
Chris@1520
|
63 */
|
Chris@1517
|
64 WritableWaveFileModel(sv_samplerate_t sampleRate,
|
Chris@1517
|
65 int channels,
|
Chris@1520
|
66 Normalisation normalisation);
|
Chris@1520
|
67
|
Chris@1520
|
68 /**
|
Chris@1520
|
69 * Create a WritableWaveFileModel of the given sample rate and
|
Chris@1520
|
70 * channel count, storing data in a new float-type extended WAV
|
Chris@1520
|
71 * file in a temporary location, and applying no normalisation.
|
Chris@1520
|
72 *
|
Chris@1520
|
73 * This is equivalent to passing an empty path and
|
Chris@1520
|
74 * Normalisation::None to the first constructor above.
|
Chris@1520
|
75 */
|
Chris@1520
|
76 WritableWaveFileModel(sv_samplerate_t sampleRate,
|
Chris@1520
|
77 int channels);
|
Chris@1520
|
78
|
Chris@175
|
79 ~WritableWaveFileModel();
|
Chris@175
|
80
|
Chris@188
|
81 /**
|
Chris@188
|
82 * Call addSamples to append a block of samples to the end of the
|
Chris@1337
|
83 * file.
|
Chris@1337
|
84 *
|
Chris@1337
|
85 * This function only appends the samples to the file being
|
Chris@1337
|
86 * written; it does not update the model's view of the samples in
|
Chris@1337
|
87 * that file. That is, it updates the file on disc but the model
|
Chris@1337
|
88 * itself does not change its content. This is because re-reading
|
Chris@1337
|
89 * the file to update the model may be more expensive than adding
|
Chris@1337
|
90 * the samples in the first place. If you are writing small
|
Chris@1337
|
91 * numbers of samples repeatedly, you probably only want the model
|
Chris@1337
|
92 * to update periodically rather than after every write.
|
Chris@1337
|
93 *
|
Chris@1337
|
94 * Call updateModel() periodically to tell the model to update its
|
Chris@1337
|
95 * own view of the samples in the file being written.
|
Chris@1337
|
96 *
|
Chris@1337
|
97 * Call setWriteProportion() periodically if the file being
|
Chris@1337
|
98 * written has known duration and you want the model to be able to
|
Chris@1337
|
99 * report the write progress as a percentage.
|
Chris@1337
|
100 *
|
Chris@1337
|
101 * Call writeComplete() when the file has been completely written.
|
Chris@188
|
102 */
|
Chris@1325
|
103 virtual bool addSamples(const float *const *samples, sv_frame_t count);
|
Chris@1133
|
104
|
Chris@1133
|
105 /**
|
Chris@1337
|
106 * Tell the model to update its own (read) view of the (written)
|
Chris@1337
|
107 * file. May cause modelChanged() and modelChangedWithin() to be
|
Chris@1337
|
108 * emitted. See the comment to addSamples above for rationale.
|
Chris@1337
|
109 */
|
Chris@1337
|
110 void updateModel();
|
Chris@1337
|
111
|
Chris@1337
|
112 /**
|
Chris@1133
|
113 * Set the proportion of the file which has been written so far,
|
Chris@1133
|
114 * as a percentage. This may be used to indicate progress.
|
Chris@1133
|
115 *
|
Chris@1133
|
116 * Note that this differs from the "completion" percentage
|
Chris@1133
|
117 * reported through isReady()/getCompletion(). That percentage is
|
Chris@1133
|
118 * updated when "internal processing has advanced... but the model
|
Chris@1133
|
119 * has not changed externally", i.e. it reports progress in
|
Chris@1133
|
120 * calculating the initial state of a model. In contrast, an
|
Chris@1133
|
121 * update to setWriteProportion corresponds to a change in the
|
Chris@1133
|
122 * externally visible state of the model (i.e. it contains more
|
Chris@1133
|
123 * data than before).
|
Chris@1133
|
124 */
|
Chris@1133
|
125 void setWriteProportion(int proportion);
|
Chris@1133
|
126
|
Chris@1133
|
127 /**
|
Chris@1133
|
128 * Indicate that writing is complete. You should call this even if
|
Chris@1337
|
129 * you have never called setWriteProportion() or updateModel().
|
Chris@1133
|
130 */
|
Chris@1133
|
131 void writeComplete();
|
Chris@1133
|
132
|
Chris@1133
|
133 static const int PROPORTION_UNKNOWN;
|
Chris@1133
|
134
|
Chris@1133
|
135 /**
|
Chris@1133
|
136 * Get the proportion of the file which has been written so far,
|
Chris@1133
|
137 * as a percentage. Return PROPORTION_UNKNOWN if unknown.
|
Chris@1133
|
138 */
|
Chris@1133
|
139 int getWriteProportion() const;
|
Chris@175
|
140
|
Chris@1580
|
141 bool isOK() const override;
|
Chris@1133
|
142
|
Chris@1133
|
143 /**
|
Chris@1133
|
144 * Return the generation completion percentage of this model. This
|
Chris@1133
|
145 * is always 100, because the model is always in a complete state
|
Chris@1133
|
146 * -- it just contains varying amounts of data depending on how
|
Chris@1133
|
147 * much has been written.
|
Chris@1133
|
148 */
|
Chris@1671
|
149 int getCompletion() const override { return 100; }
|
Chris@188
|
150
|
Chris@1580
|
151 const ZoomConstraint *getZoomConstraint() const override {
|
Chris@179
|
152 static PowerOfSqrtTwoZoomConstraint zc;
|
Chris@179
|
153 return &zc;
|
Chris@179
|
154 }
|
Chris@179
|
155
|
Chris@1580
|
156 sv_frame_t getFrameCount() const override;
|
Chris@1580
|
157 int getChannelCount() const override { return m_channels; }
|
Chris@1580
|
158 sv_samplerate_t getSampleRate() const override { return m_sampleRate; }
|
Chris@1580
|
159 sv_samplerate_t getNativeRate() const override { return m_sampleRate; }
|
Chris@1122
|
160
|
Chris@1580
|
161 QString getTitle() const override {
|
Chris@1122
|
162 if (m_model) return m_model->getTitle();
|
Chris@1122
|
163 else return "";
|
Chris@1122
|
164 }
|
Chris@1580
|
165 QString getMaker() const override {
|
Chris@1122
|
166 if (m_model) return m_model->getMaker();
|
Chris@1122
|
167 else return "";
|
Chris@1122
|
168 }
|
Chris@1580
|
169 QString getLocation() const override {
|
Chris@1122
|
170 if (m_model) return m_model->getLocation();
|
Chris@1122
|
171 else return "";
|
Chris@1122
|
172 }
|
Chris@175
|
173
|
Chris@1580
|
174 float getValueMinimum() const override { return -1.0f; }
|
Chris@1580
|
175 float getValueMaximum() const override { return 1.0f; }
|
Chris@175
|
176
|
Chris@1580
|
177 sv_frame_t getStartFrame() const override { return m_startFrame; }
|
Chris@1725
|
178 sv_frame_t getTrueEndFrame() const override { return m_startFrame + getFrameCount(); }
|
Chris@175
|
179
|
Chris@1580
|
180 void setStartFrame(sv_frame_t startFrame) override;
|
Chris@175
|
181
|
Chris@1580
|
182 floatvec_t getData(int channel, sv_frame_t start, sv_frame_t count) const override;
|
Chris@175
|
183
|
Chris@1580
|
184 std::vector<floatvec_t> getMultiChannelData(int fromchannel, int tochannel, sv_frame_t start, sv_frame_t count) const override;
|
Chris@363
|
185
|
Chris@1580
|
186 int getSummaryBlockSize(int desired) const override;
|
Chris@377
|
187
|
Chris@1580
|
188 void getSummaries(int channel, sv_frame_t start, sv_frame_t count,
|
Chris@1580
|
189 RangeBlock &ranges, int &blockSize) const override;
|
Chris@300
|
190
|
Chris@1580
|
191 Range getSummary(int channel, sv_frame_t start, sv_frame_t count) const override;
|
Chris@175
|
192
|
Chris@1580
|
193 QString getTypeName() const override { return tr("Writable Wave File"); }
|
Chris@345
|
194
|
Chris@1580
|
195 void toXml(QTextStream &out,
|
Chris@175
|
196 QString indent = "",
|
Chris@1580
|
197 QString extraAttributes = "") const override;
|
Chris@175
|
198
|
Chris@1723
|
199 signals:
|
Chris@1752
|
200 void writeCompleted(ModelId);
|
Chris@1770
|
201
|
Chris@1770
|
202 protected slots:
|
Chris@1770
|
203 void componentModelChanged(ModelId);
|
Chris@1770
|
204 void componentModelChangedWithin(ModelId, sv_frame_t, sv_frame_t);
|
Chris@1723
|
205
|
Chris@175
|
206 protected:
|
Chris@1122
|
207 ReadOnlyWaveFileModel *m_model;
|
Chris@1520
|
208
|
Chris@1520
|
209 /** When normalising, this writer is used to write verbatim
|
Chris@1520
|
210 * samples to the temporary file prior to
|
Chris@1520
|
211 * normalisation. Otherwise it's null
|
Chris@1520
|
212 */
|
Chris@1520
|
213 WavFileWriter *m_temporaryWriter;
|
Chris@1520
|
214 QString m_temporaryPath;
|
Chris@1520
|
215
|
Chris@1520
|
216 /** When not normalising, this writer is used to write verbatim
|
Chris@1520
|
217 * samples direct to the target file. When normalising, it is
|
Chris@1520
|
218 * used to write normalised samples to the target after the
|
Chris@1520
|
219 * temporary file has been completed. But it is still created on
|
Chris@1520
|
220 * initialisation, so that there is a file header ready for the
|
Chris@1520
|
221 * reader to address.
|
Chris@1520
|
222 */
|
Chris@1520
|
223 WavFileWriter *m_targetWriter;
|
Chris@1520
|
224 QString m_targetPath;
|
Chris@1520
|
225
|
Chris@175
|
226 WavFileReader *m_reader;
|
Chris@1520
|
227 Normalisation m_normalisation;
|
Chris@1040
|
228 sv_samplerate_t m_sampleRate;
|
Chris@929
|
229 int m_channels;
|
Chris@1038
|
230 sv_frame_t m_frameCount;
|
Chris@1038
|
231 sv_frame_t m_startFrame;
|
Chris@1133
|
232 int m_proportion;
|
Chris@1520
|
233
|
Chris@1520
|
234 private:
|
Chris@1520
|
235 void init(QString path = "");
|
Chris@1520
|
236 void normaliseToTarget();
|
Chris@175
|
237 };
|
Chris@175
|
238
|
Chris@175
|
239 #endif
|
Chris@175
|
240
|