Mercurial > hg > svcore
comparison data/fileio/WavFileReader.cpp @ 1527:710e6250a401 zoom
Merge from default branch
author | Chris Cannam |
---|---|
date | Mon, 17 Sep 2018 13:51:14 +0100 |
parents | 954d0cf29ca7 |
children | 70e172e6cc59 f8e3dcbafb4d |
comparison
equal
deleted
inserted
replaced
1324:d4a28d1479a8 | 1527:710e6250a401 |
---|---|
23 #include <QMutexLocker> | 23 #include <QMutexLocker> |
24 #include <QFileInfo> | 24 #include <QFileInfo> |
25 | 25 |
26 using namespace std; | 26 using namespace std; |
27 | 27 |
28 WavFileReader::WavFileReader(FileSource source, bool fileUpdating) : | 28 WavFileReader::WavFileReader(FileSource source, |
29 bool fileUpdating, | |
30 Normalisation normalisation) : | |
29 m_file(0), | 31 m_file(0), |
30 m_source(source), | 32 m_source(source), |
31 m_path(source.getLocalFilename()), | 33 m_path(source.getLocalFilename()), |
32 m_seekable(false), | 34 m_seekable(false), |
33 m_lastStart(0), | 35 m_lastStart(0), |
34 m_lastCount(0), | 36 m_lastCount(0), |
37 m_normalisation(normalisation), | |
38 m_max(0.f), | |
35 m_updating(fileUpdating) | 39 m_updating(fileUpdating) |
36 { | 40 { |
37 m_frameCount = 0; | 41 m_frameCount = 0; |
38 m_channelCount = 0; | 42 m_channelCount = 0; |
39 m_sampleRate = 0; | 43 m_sampleRate = 0; |
40 | 44 |
41 m_fileInfo.format = 0; | 45 m_fileInfo.format = 0; |
42 m_fileInfo.frames = 0; | 46 m_fileInfo.frames = 0; |
47 | |
48 #ifdef Q_OS_WIN | |
49 m_file = sf_wchar_open((LPCWSTR)m_path.utf16(), SFM_READ, &m_fileInfo); | |
50 #else | |
43 m_file = sf_open(m_path.toLocal8Bit(), SFM_READ, &m_fileInfo); | 51 m_file = sf_open(m_path.toLocal8Bit(), SFM_READ, &m_fileInfo); |
52 #endif | |
44 | 53 |
45 if (!m_file || (!fileUpdating && m_fileInfo.channels <= 0)) { | 54 if (!m_file || (!fileUpdating && m_fileInfo.channels <= 0)) { |
46 SVDEBUG << "WavFileReader::initialize: Failed to open file at \"" | 55 SVDEBUG << "WavFileReader::initialize: Failed to open file at \"" |
47 << m_path << "\" (" | 56 << m_path << "\" (" |
48 << sf_strerror(m_file) << ")" << endl; | 57 << sf_strerror(m_file) << ")" << endl; |
49 | 58 |
50 if (m_file) { | 59 if (m_file) { |
51 m_error = QString("Couldn't load audio file '%1':\n%2") | 60 m_error = QString("Couldn't load audio file '%1':\n%2") |
52 .arg(m_path).arg(sf_strerror(m_file)); | 61 .arg(m_path).arg(sf_strerror(m_file)); |
53 } else { | 62 } else { |
54 m_error = QString("Failed to open audio file '%1'") | 63 m_error = QString("Failed to open audio file '%1'") |
55 .arg(m_path); | 64 .arg(m_path); |
56 } | 65 } |
57 return; | 66 return; |
58 } | 67 } |
59 | 68 |
60 if (m_fileInfo.channels > 0) { | 69 if (m_fileInfo.channels > 0) { |
61 | 70 |
62 m_frameCount = m_fileInfo.frames; | 71 m_frameCount = m_fileInfo.frames; |
80 // non-seekable. We know that certain common file types | 89 // non-seekable. We know that certain common file types |
81 // are definitely seekable so, again cautiously, identify | 90 // are definitely seekable so, again cautiously, identify |
82 // and mark those (basically only non-adaptive WAVs). | 91 // and mark those (basically only non-adaptive WAVs). |
83 m_seekable = true; | 92 m_seekable = true; |
84 } | 93 } |
85 } | 94 |
86 | 95 if (m_normalisation != Normalisation::None && !m_updating) { |
87 SVDEBUG << "WavFileReader: Filename " << m_path << ", frame count " << m_frameCount << ", channel count " << m_channelCount << ", sample rate " << m_sampleRate << ", format " << m_fileInfo.format << ", seekable " << m_fileInfo.seekable << " adjusted to " << m_seekable << endl; | 96 m_max = getMax(); |
97 } | |
98 } | |
99 | |
100 SVDEBUG << "WavFileReader: Filename " << m_path << ", frame count " << m_frameCount << ", channel count " << m_channelCount << ", sample rate " << m_sampleRate << ", format " << m_fileInfo.format << ", seekable " << m_fileInfo.seekable << " adjusted to " << m_seekable << ", normalisation " << int(m_normalisation) << endl; | |
88 } | 101 } |
89 | 102 |
90 WavFileReader::~WavFileReader() | 103 WavFileReader::~WavFileReader() |
91 { | 104 { |
92 if (m_file) sf_close(m_file); | 105 if (m_file) sf_close(m_file); |
99 | 112 |
100 sv_frame_t prevCount = m_fileInfo.frames; | 113 sv_frame_t prevCount = m_fileInfo.frames; |
101 | 114 |
102 if (m_file) { | 115 if (m_file) { |
103 sf_close(m_file); | 116 sf_close(m_file); |
117 #ifdef Q_OS_WIN | |
118 m_file = sf_wchar_open((LPCWSTR)m_path.utf16(), SFM_READ, &m_fileInfo); | |
119 #else | |
104 m_file = sf_open(m_path.toLocal8Bit(), SFM_READ, &m_fileInfo); | 120 m_file = sf_open(m_path.toLocal8Bit(), SFM_READ, &m_fileInfo); |
121 #endif | |
105 if (!m_file || m_fileInfo.channels <= 0) { | 122 if (!m_file || m_fileInfo.channels <= 0) { |
106 SVDEBUG << "WavFileReader::updateFrameCount: Failed to open file at \"" << m_path << "\" (" | 123 SVDEBUG << "WavFileReader::updateFrameCount: Failed to open file at \"" << m_path << "\" (" |
107 << sf_strerror(m_file) << ")" << endl; | 124 << sf_strerror(m_file) << ")" << endl; |
108 } | 125 } |
109 } | 126 } |
125 void | 142 void |
126 WavFileReader::updateDone() | 143 WavFileReader::updateDone() |
127 { | 144 { |
128 updateFrameCount(); | 145 updateFrameCount(); |
129 m_updating = false; | 146 m_updating = false; |
130 } | 147 if (m_normalisation != Normalisation::None) { |
131 | 148 m_max = getMax(); |
132 vector<float> | 149 } |
150 } | |
151 | |
152 floatvec_t | |
133 WavFileReader::getInterleavedFrames(sv_frame_t start, sv_frame_t count) const | 153 WavFileReader::getInterleavedFrames(sv_frame_t start, sv_frame_t count) const |
154 { | |
155 floatvec_t frames = getInterleavedFramesUnnormalised(start, count); | |
156 | |
157 if (m_normalisation == Normalisation::None || m_max == 0.f) { | |
158 return frames; | |
159 } | |
160 | |
161 for (int i = 0; in_range_for(frames, i); ++i) { | |
162 frames[i] /= m_max; | |
163 } | |
164 | |
165 return frames; | |
166 } | |
167 | |
168 floatvec_t | |
169 WavFileReader::getInterleavedFramesUnnormalised(sv_frame_t start, | |
170 sv_frame_t count) const | |
134 { | 171 { |
135 static HitCount lastRead("WavFileReader: last read"); | 172 static HitCount lastRead("WavFileReader: last read"); |
136 | 173 |
137 if (count == 0) return {}; | 174 if (count == 0) return {}; |
138 | 175 |
145 } | 182 } |
146 | 183 |
147 if (start >= m_fileInfo.frames) { | 184 if (start >= m_fileInfo.frames) { |
148 // SVDEBUG << "WavFileReader::getInterleavedFrames: " << start | 185 // SVDEBUG << "WavFileReader::getInterleavedFrames: " << start |
149 // << " > " << m_fileInfo.frames << endl; | 186 // << " > " << m_fileInfo.frames << endl; |
150 return {}; | 187 return {}; |
151 } | 188 } |
152 | 189 |
153 if (start + count > m_fileInfo.frames) { | 190 if (start + count > m_fileInfo.frames) { |
154 count = m_fileInfo.frames - start; | 191 count = m_fileInfo.frames - start; |
155 } | 192 } |
156 | 193 |
157 // Because WaveFileModel::getSummaries() is called separately for | 194 // Because WaveFileModel::getSummaries() is called separately for |
158 // individual channels, it's quite common for us to be called | 195 // individual channels, it's quite common for us to be called |
159 // repeatedly for the same data. So this is worth cacheing. | 196 // repeatedly for the same data. So this is worth cacheing. |
173 | 210 |
174 if (sf_seek(m_file, start, SEEK_SET) < 0) { | 211 if (sf_seek(m_file, start, SEEK_SET) < 0) { |
175 return {}; | 212 return {}; |
176 } | 213 } |
177 | 214 |
178 vector<float> data; | 215 floatvec_t data; |
179 sv_frame_t n = count * m_fileInfo.channels; | 216 sv_frame_t n = count * m_fileInfo.channels; |
180 data.resize(n); | 217 data.resize(n); |
181 | 218 |
182 m_lastStart = start; | 219 m_lastStart = start; |
183 m_lastCount = count; | 220 m_lastCount = count; |
187 return {}; | 224 return {}; |
188 } | 225 } |
189 | 226 |
190 m_buffer = data; | 227 m_buffer = data; |
191 return data; | 228 return data; |
229 } | |
230 | |
231 float | |
232 WavFileReader::getMax() const | |
233 { | |
234 if (!m_file || !m_channelCount) { | |
235 return 0.f; | |
236 } | |
237 | |
238 // First try for a PEAK chunk | |
239 | |
240 double sfpeak = 0.0; | |
241 if (sf_command(m_file, SFC_GET_SIGNAL_MAX, &sfpeak, sizeof(sfpeak)) | |
242 == SF_TRUE) { | |
243 SVDEBUG << "File has a PEAK chunk reporting max level " << sfpeak | |
244 << endl; | |
245 return float(fabs(sfpeak)); | |
246 } | |
247 | |
248 // Failing that, read all the samples | |
249 | |
250 float peak = 0.f; | |
251 sv_frame_t ix = 0, chunk = 65536; | |
252 | |
253 while (ix < m_frameCount) { | |
254 auto frames = getInterleavedFrames(ix, chunk); | |
255 for (float x: frames) { | |
256 float level = fabsf(x); | |
257 if (level > peak) { | |
258 peak = level; | |
259 } | |
260 } | |
261 ix += chunk; | |
262 } | |
263 | |
264 SVDEBUG << "Measured file peak max level as " << peak << endl; | |
265 return peak; | |
192 } | 266 } |
193 | 267 |
194 void | 268 void |
195 WavFileReader::getSupportedExtensions(set<QString> &extensions) | 269 WavFileReader::getSupportedExtensions(set<QString> &extensions) |
196 { | 270 { |