Mercurial > hg > svcore
changeset 1100:5cbf71022679 simple-fft-model
Smooth signal flow through from file to fft model
author | Chris Cannam |
---|---|
date | Mon, 15 Jun 2015 16:02:58 +0100 |
parents | 0c351e061945 |
children | cd156ede1395 |
files | data/fileio/CodedAudioFileReader.cpp data/fileio/CodedAudioFileReader.h data/model/AggregateWaveModel.cpp data/model/FFTModel.cpp data/model/FFTModel.h data/model/WaveFileModel.cpp |
diffstat | 6 files changed, 70 insertions(+), 46 deletions(-) [+] |
line wrap: on
line diff
--- a/data/fileio/CodedAudioFileReader.cpp Mon Jun 15 15:35:57 2015 +0100 +++ b/data/fileio/CodedAudioFileReader.cpp Mon Jun 15 16:02:58 2015 +0100 @@ -367,7 +367,7 @@ break; case CacheInMemory: - m_dataLock.lockForWrite(); + m_dataLock.lock(); m_data.insert(m_data.end(), buffer, buffer + count); m_dataLock.unlock(); break; @@ -449,26 +449,25 @@ if (!isOK()) return {}; if (count == 0) return {}; - sv_frame_t idx = start * m_channelCount; - sv_frame_t i = 0; - sv_frame_t n = count * m_channelCount; + sv_frame_t ix0 = start * m_channelCount; + sv_frame_t ix1 = ix0 + (count * m_channelCount); - frames.resize(n); - - m_dataLock.lockForRead(); - while (i < n && in_range_for(m_data, idx)) { - frames[i++] = m_data[idx++]; - } + // This lock used to be a QReadWriteLock, but it appears that + // its lock mechanism is significantly slower than QMutex so + // it's not a good idea in cases like this where we don't + // really have threads taking a long time to read concurrently + m_dataLock.lock(); + sv_frame_t n = sv_frame_t(m_data.size()); + if (ix1 > n) ix1 = n; + frames = vector<float>(m_data.begin() + ix0, m_data.begin() + ix1); m_dataLock.unlock(); - - frames.resize(i); } } if (m_normalised) { for (auto &f: frames) f *= m_gain; } - + return frames; }
--- a/data/fileio/CodedAudioFileReader.h Mon Jun 15 15:35:57 2015 +0100 +++ b/data/fileio/CodedAudioFileReader.h Mon Jun 15 16:02:58 2015 +0100 @@ -84,7 +84,7 @@ QMutex m_cacheMutex; CacheMode m_cacheMode; std::vector<float> m_data; - mutable QReadWriteLock m_dataLock; + mutable QMutex m_dataLock; bool m_initialised; Serialiser *m_serialiser; sv_samplerate_t m_fileRate;
--- a/data/model/AggregateWaveModel.cpp Mon Jun 15 15:35:57 2015 +0100 +++ b/data/model/AggregateWaveModel.cpp Mon Jun 15 16:02:58 2015 +0100 @@ -111,8 +111,8 @@ auto here = m_components[c].model->getData(m_components[c].channel, start, count); - if (here.size() > longest) { - longest = here.size(); + if (sv_frame_t(here.size()) > longest) { + longest = sv_frame_t(here.size()); } for (sv_frame_t i = 0; in_range_for(here, i); ++i) { result[i] += here[i]; @@ -133,7 +133,9 @@ for (int c = fromchannel; c <= tochannel; ++c) { auto here = getData(c, start, count); - if (here.size() < min) min = here.size(); + if (sv_frame_t(here.size()) < min) { + min = sv_frame_t(here.size()); + } result.push_back(here); }
--- a/data/model/FFTModel.cpp Mon Jun 15 15:35:57 2015 +0100 +++ b/data/model/FFTModel.cpp Mon Jun 15 16:02:58 2015 +0100 @@ -225,23 +225,24 @@ // << "): saved range is (" << m_savedData.range.first // << "," << m_savedData.range.second << ")" << endl; - if (m_savedData.range == range) return m_savedData.data; + if (m_savedData.range == range) { + return m_savedData.data; + } if (range.first < m_savedData.range.second && range.first >= m_savedData.range.first && range.second > m_savedData.range.second) { - //!!! Need FFTModel overlap tests to exercise this - - sv_frame_t off = range.first - m_savedData.range.first; - - vector<float> acc(m_savedData.data.begin() + off, m_savedData.data.end()); + sv_frame_t discard = range.first - m_savedData.range.first; + + vector<float> acc(m_savedData.data.begin() + discard, + m_savedData.data.end()); vector<float> rest = getSourceDataUncached({ m_savedData.range.second, range.second }); + + acc.insert(acc.end(), rest.begin(), rest.end()); - acc.insert(acc.end(), rest.begin(), rest.end()); - m_savedData = { range, acc }; return acc; @@ -279,6 +280,7 @@ if (channels > 1) { int n = int(data.size()); float factor = 1.f / float(channels); + // use mean instead of sum for fft model input for (int i = 0; i < n; ++i) { data[i] *= factor; } @@ -298,7 +300,7 @@ } auto samples = getSourceSamples(n); - m_windower.cut(&samples[0]); + m_windower.cut(samples.data()); auto col = m_fft.process(samples); SavedColumn sc { n, col };
--- a/data/model/FFTModel.h Mon Jun 15 15:35:57 2015 +0100 +++ b/data/model/FFTModel.h Mon Jun 15 16:02:58 2015 +0100 @@ -183,8 +183,6 @@ }; mutable std::deque<SavedColumn> m_cached; size_t m_cacheSize; - - //!!! also optionally cache polar? }; #endif
--- a/data/model/WaveFileModel.cpp Mon Jun 15 15:35:57 2015 +0100 +++ b/data/model/WaveFileModel.cpp Mon Jun 15 16:02:58 2015 +0100 @@ -189,35 +189,55 @@ vector<float> WaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count) const { - // Always read these directly from the file. - // This is used for e.g. audio playback or input to transforms. + // Read directly from the file. This is used for e.g. audio + // playback or input to transforms. #ifdef DEBUG_WAVE_FILE_MODEL cout << "WaveFileModel::getData[" << this << "]: " << channel << ", " << start << ", " << count << ", " << buffer << endl; #endif + int channels = getChannelCount(); + + if (channel >= channels) { + cerr << "ERROR: WaveFileModel::getData: channel (" + << channel << ") >= channel count (" << channels << ")" + << endl; + return {}; + } + if (!m_reader || !m_reader->isOK() || count == 0) { return {}; } + if (start >= m_startFrame) { + start -= m_startFrame; + } else { + if (count <= m_startFrame - start) { + return {}; + } else { + count -= (m_startFrame - start); + start = 0; + } + } + + vector<float> interleaved = m_reader->getInterleavedFrames(start, count); + if (channels == 1) return interleaved; + + sv_frame_t obtained = interleaved.size() / channels; + + vector<float> result(obtained, 0.f); + if (channel != -1) { // get a single channel - auto data = getMultiChannelData(channel, channel, start, count); - if (data.empty()) return {}; - else return data[0]; - } - - // channel == -1, mix down all channels - - auto all = getMultiChannelData(0, getChannelCount()-1, start, count); - if (all.empty()) return {}; - - sv_frame_t n = all[0].size(); - vector<float> result(n, 0.f); - - for (int c = 0; in_range_for(all, c); ++c) { - for (sv_frame_t i = 0; i < n; ++i) { - result[i] += all[c][i]; + for (int i = 0; i < obtained; ++i) { + result[i] = interleaved[i * channels + channel]; + } + } else { + // channel == -1, mix down all channels + for (int c = 0; c < channels; ++c) { + for (int i = 0; i < obtained; ++i) { + result[i] += interleaved[i * channels + c]; + } } } @@ -228,6 +248,9 @@ WaveFileModel::getMultiChannelData(int fromchannel, int tochannel, sv_frame_t start, sv_frame_t count) const { + // Read directly from the file. This is used for e.g. audio + // playback or input to transforms. + #ifdef DEBUG_WAVE_FILE_MODEL cout << "WaveFileModel::getData[" << this << "]: " << fromchannel << "," << tochannel << ", " << start << ", " << count << ", " << buffer << endl; #endif