annotate data/model/WritableWaveFileModel.h @ 1520:954d0cf29ca7 import-audio-data

Switch the normalisation option in WritableWaveFileModel from normalising on read to normalising on write, so that the saved file is already normalised and therefore can be read again without having to remember to normalise it
author Chris Cannam
date Wed, 12 Sep 2018 13:56:56 +0100
parents 925d205c39b4
children c01cbe41aeb5
rev   line source
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@175 141 bool isOK() const;
Chris@175 142 bool isReady(int *) const;
Chris@1133 143
Chris@1133 144 /**
Chris@1133 145 * Return the generation completion percentage of this model. This
Chris@1133 146 * is always 100, because the model is always in a complete state
Chris@1133 147 * -- it just contains varying amounts of data depending on how
Chris@1133 148 * much has been written.
Chris@1133 149 */
Chris@1133 150 virtual int getCompletion() const { return 100; }
Chris@188 151
Chris@179 152 const ZoomConstraint *getZoomConstraint() const {
Chris@179 153 static PowerOfSqrtTwoZoomConstraint zc;
Chris@179 154 return &zc;
Chris@179 155 }
Chris@179 156
Chris@1038 157 sv_frame_t getFrameCount() const;
Chris@929 158 int getChannelCount() const { return m_channels; }
Chris@1040 159 sv_samplerate_t getSampleRate() const { return m_sampleRate; }
Chris@1122 160 sv_samplerate_t getNativeRate() const { return m_sampleRate; }
Chris@1122 161
Chris@1122 162 QString getTitle() const {
Chris@1122 163 if (m_model) return m_model->getTitle();
Chris@1122 164 else return "";
Chris@1122 165 }
Chris@1122 166 QString getMaker() const {
Chris@1122 167 if (m_model) return m_model->getMaker();
Chris@1122 168 else return "";
Chris@1122 169 }
Chris@1122 170 QString getLocation() const {
Chris@1122 171 if (m_model) return m_model->getLocation();
Chris@1122 172 else return "";
Chris@1122 173 }
Chris@175 174
Chris@175 175 float getValueMinimum() const { return -1.0f; }
Chris@175 176 float getValueMaximum() const { return 1.0f; }
Chris@175 177
Chris@1038 178 virtual sv_frame_t getStartFrame() const { return m_startFrame; }
Chris@1038 179 virtual sv_frame_t getEndFrame() const { return m_startFrame + getFrameCount(); }
Chris@175 180
Chris@1038 181 void setStartFrame(sv_frame_t startFrame);
Chris@175 182
Chris@1326 183 virtual floatvec_t getData(int channel, sv_frame_t start, sv_frame_t count) const;
Chris@175 184
Chris@1326 185 virtual std::vector<floatvec_t> getMultiChannelData(int fromchannel, int tochannel, sv_frame_t start, sv_frame_t count) const;
Chris@363 186
Chris@929 187 virtual int getSummaryBlockSize(int desired) const;
Chris@377 188
Chris@1038 189 virtual void getSummaries(int channel, sv_frame_t start, sv_frame_t count,
Chris@929 190 RangeBlock &ranges, int &blockSize) const;
Chris@300 191
Chris@1038 192 virtual Range getSummary(int channel, sv_frame_t start, sv_frame_t count) const;
Chris@175 193
Chris@345 194 QString getTypeName() const { return tr("Writable Wave File"); }
Chris@345 195
Chris@175 196 virtual void toXml(QTextStream &out,
Chris@175 197 QString indent = "",
Chris@175 198 QString extraAttributes = "") const;
Chris@175 199
Chris@175 200 protected:
Chris@1122 201 ReadOnlyWaveFileModel *m_model;
Chris@1520 202
Chris@1520 203 /** When normalising, this writer is used to write verbatim
Chris@1520 204 * samples to the temporary file prior to
Chris@1520 205 * normalisation. Otherwise it's null
Chris@1520 206 */
Chris@1520 207 WavFileWriter *m_temporaryWriter;
Chris@1520 208 QString m_temporaryPath;
Chris@1520 209
Chris@1520 210 /** When not normalising, this writer is used to write verbatim
Chris@1520 211 * samples direct to the target file. When normalising, it is
Chris@1520 212 * used to write normalised samples to the target after the
Chris@1520 213 * temporary file has been completed. But it is still created on
Chris@1520 214 * initialisation, so that there is a file header ready for the
Chris@1520 215 * reader to address.
Chris@1520 216 */
Chris@1520 217 WavFileWriter *m_targetWriter;
Chris@1520 218 QString m_targetPath;
Chris@1520 219
Chris@175 220 WavFileReader *m_reader;
Chris@1520 221 Normalisation m_normalisation;
Chris@1040 222 sv_samplerate_t m_sampleRate;
Chris@929 223 int m_channels;
Chris@1038 224 sv_frame_t m_frameCount;
Chris@1038 225 sv_frame_t m_startFrame;
Chris@1133 226 int m_proportion;
Chris@1520 227
Chris@1520 228 private:
Chris@1520 229 void init(QString path = "");
Chris@1520 230 void normaliseToTarget();
Chris@175 231 };
Chris@175 232
Chris@175 233 #endif
Chris@175 234