Change the FilePool to load files and not only preload
This commit is contained in:
parent
2add056a51
commit
62b68b2af3
2 changed files with 65 additions and 25 deletions
|
|
@ -170,13 +170,16 @@ bool sfz::FilePool::checkSample(std::string& filename) const noexcept
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::optional<sfz::FilePool::FileInformation> sfz::FilePool::getFileInformation(const std::string& filename) noexcept
|
absl::optional<sfz::FileInformation> sfz::FilePool::getFileInformation(const std::string& filename) noexcept
|
||||||
{
|
{
|
||||||
fs::path file { rootDirectory / filename };
|
fs::path file { rootDirectory / filename };
|
||||||
|
|
||||||
|
if (!fs::exists(file))
|
||||||
|
return {};
|
||||||
|
|
||||||
SndfileHandle sndFile(file.string().c_str());
|
SndfileHandle sndFile(file.string().c_str());
|
||||||
if (sndFile.channels() != 1 && sndFile.channels() != 2) {
|
if (sndFile.channels() != 1 && sndFile.channels() != 2) {
|
||||||
DBG("Missing logic for " << sndFile.channels() << " channels, discarding sample " << filename);
|
DBG("[sfizz] Missing logic for " << sndFile.channels() << " channels, discarding sample " << filename);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -198,13 +201,11 @@ absl::optional<sfz::FilePool::FileInformation> sfz::FilePool::getFileInformation
|
||||||
bool sfz::FilePool::preloadFile(const std::string& filename, uint32_t maxOffset) noexcept
|
bool sfz::FilePool::preloadFile(const std::string& filename, uint32_t maxOffset) noexcept
|
||||||
{
|
{
|
||||||
fs::path file { rootDirectory / filename };
|
fs::path file { rootDirectory / filename };
|
||||||
|
auto fileInformation = getFileInformation(filename);
|
||||||
if (!fs::exists(file))
|
if (!fileInformation)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SndfileHandle sndFile(file.string().c_str());
|
SndfileHandle sndFile(file.string().c_str());
|
||||||
if (sndFile.channels() != 1 && sndFile.channels() != 2)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// FIXME: Large offsets will require large preloading; is this OK in practice? Apparently sforzando does the same
|
// FIXME: Large offsets will require large preloading; is this OK in practice? Apparently sforzando does the same
|
||||||
const auto frames = static_cast<uint32_t>(sndFile.frames());
|
const auto frames = static_cast<uint32_t>(sndFile.frames());
|
||||||
|
|
@ -215,19 +216,47 @@ bool sfz::FilePool::preloadFile(const std::string& filename, uint32_t maxOffset)
|
||||||
return min(frames, maxOffset + preloadSize);
|
return min(frames, maxOffset + preloadSize);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
if (preloadedFiles.contains(filename)) {
|
const auto existingFile = preloadedFiles.find(filename);
|
||||||
if (framesToLoad > preloadedFiles[filename].preloadedData->getNumFrames()) {
|
if (existingFile != preloadedFiles.end()) {
|
||||||
|
if (framesToLoad > existingFile->second.preloadedData->getNumFrames()) {
|
||||||
preloadedFiles[filename].preloadedData = readFromFile<float>(sndFile, framesToLoad, oversamplingFactor);
|
preloadedFiles[filename].preloadedData = readFromFile<float>(sndFile, framesToLoad, oversamplingFactor);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const float sourceSampleRate { static_cast<float>(oversamplingFactor) * static_cast<float>(sndFile.samplerate()) };
|
fileInformation->sampleRate = static_cast<float>(oversamplingFactor) * static_cast<float>(sndFile.samplerate());
|
||||||
PreloadedFileHandle handle { readFromFile<float>(sndFile, framesToLoad, oversamplingFactor), sourceSampleRate };
|
FileDataHandle handle {
|
||||||
|
readFromFile<float>(sndFile, framesToLoad, oversamplingFactor),
|
||||||
|
*fileInformation
|
||||||
|
};
|
||||||
preloadedFiles.insert_or_assign(filename, handle);
|
preloadedFiles.insert_or_assign(filename, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
absl::optional<sfz::FileDataHandle> sfz::FilePool::loadFile(const std::string& filename) noexcept
|
||||||
|
{
|
||||||
|
fs::path file { rootDirectory / filename };
|
||||||
|
auto fileInformation = getFileInformation(filename);
|
||||||
|
if (!fileInformation)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
SndfileHandle sndFile(file.string().c_str());
|
||||||
|
|
||||||
|
// FIXME: Large offsets will require large preloading; is this OK in practice? Apparently sforzando does the same
|
||||||
|
const auto frames = static_cast<uint32_t>(sndFile.frames());
|
||||||
|
const auto existingFile = loadedFiles.find(filename);
|
||||||
|
if (existingFile != loadedFiles.end()) {
|
||||||
|
return existingFile->second;
|
||||||
|
} else {
|
||||||
|
fileInformation->sampleRate = static_cast<float>(oversamplingFactor) * static_cast<float>(sndFile.samplerate());
|
||||||
|
FileDataHandle handle {
|
||||||
|
readFromFile<float>(sndFile, frames, oversamplingFactor),
|
||||||
|
*fileInformation
|
||||||
|
};
|
||||||
|
loadedFiles.insert_or_assign(filename, handle);
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sfz::FilePromisePtr sfz::FilePool::getFilePromise(const std::string& filename) noexcept
|
sfz::FilePromisePtr sfz::FilePool::getFilePromise(const std::string& filename) noexcept
|
||||||
{
|
{
|
||||||
if (emptyPromises.empty()) {
|
if (emptyPromises.empty()) {
|
||||||
|
|
@ -244,7 +273,7 @@ sfz::FilePromisePtr sfz::FilePool::getFilePromise(const std::string& filename) n
|
||||||
auto promise = emptyPromises.back();
|
auto promise = emptyPromises.back();
|
||||||
promise->filename = preloaded->first;
|
promise->filename = preloaded->first;
|
||||||
promise->preloadedData = preloaded->second.preloadedData;
|
promise->preloadedData = preloaded->second.preloadedData;
|
||||||
promise->sampleRate = preloaded->second.sampleRate;
|
promise->sampleRate = preloaded->second.information.sampleRate;
|
||||||
promise->oversamplingFactor = oversamplingFactor;
|
promise->oversamplingFactor = oversamplingFactor;
|
||||||
promise->creationTime = std::chrono::high_resolution_clock::now();
|
promise->creationTime = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
|
@ -396,7 +425,7 @@ void sfz::FilePool::setOversamplingFactor(sfz::Oversampling factor) noexcept
|
||||||
fs::path file { rootDirectory / std::string(preloadedFile.first) };
|
fs::path file { rootDirectory / std::string(preloadedFile.first) };
|
||||||
SndfileHandle sndFile(file.string().c_str());
|
SndfileHandle sndFile(file.string().c_str());
|
||||||
preloadedFile.second.preloadedData = readFromFile<float>(sndFile, preloadSize + maxOffset, factor);
|
preloadedFile.second.preloadedData = readFromFile<float>(sndFile, preloadSize + maxOffset, factor);
|
||||||
preloadedFile.second.sampleRate *= samplerateChange;
|
preloadedFile.second.information.sampleRate *= samplerateChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->oversamplingFactor = factor;
|
this->oversamplingFactor = factor;
|
||||||
|
|
|
||||||
|
|
@ -43,11 +43,19 @@ namespace sfz {
|
||||||
using AudioBufferPtr = std::shared_ptr<AudioBuffer<float>>;
|
using AudioBufferPtr = std::shared_ptr<AudioBuffer<float>>;
|
||||||
|
|
||||||
|
|
||||||
|
struct FileInformation {
|
||||||
|
uint32_t end { Default::sampleEndRange.getEnd() };
|
||||||
|
uint32_t loopBegin { Default::loopRange.getStart() };
|
||||||
|
uint32_t loopEnd { Default::loopRange.getEnd() };
|
||||||
|
double sampleRate { config::defaultSampleRate };
|
||||||
|
int numChannels { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
// Strict C++11 disallows member initialization if aggregate initialization is to be used...
|
// Strict C++11 disallows member initialization if aggregate initialization is to be used...
|
||||||
struct PreloadedFileHandle
|
struct FileDataHandle
|
||||||
{
|
{
|
||||||
std::shared_ptr<AudioBuffer<float>> preloadedData;
|
std::shared_ptr<AudioBuffer<float>> preloadedData;
|
||||||
float sampleRate;
|
FileInformation information;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FilePromise
|
struct FilePromise
|
||||||
|
|
@ -142,14 +150,6 @@ public:
|
||||||
*/
|
*/
|
||||||
size_t getNumPreloadedSamples() const noexcept { return preloadedFiles.size(); }
|
size_t getNumPreloadedSamples() const noexcept { return preloadedFiles.size(); }
|
||||||
|
|
||||||
struct FileInformation {
|
|
||||||
uint32_t end { Default::sampleEndRange.getEnd() };
|
|
||||||
uint32_t loopBegin { Default::loopRange.getStart() };
|
|
||||||
uint32_t loopEnd { Default::loopRange.getEnd() };
|
|
||||||
double sampleRate { config::defaultSampleRate };
|
|
||||||
int numChannels { 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get metadata information about a file.
|
* @brief Get metadata information about a file.
|
||||||
*
|
*
|
||||||
|
|
@ -159,7 +159,7 @@ public:
|
||||||
absl::optional<FileInformation> getFileInformation(const std::string& filename) noexcept;
|
absl::optional<FileInformation> getFileInformation(const std::string& filename) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check that a file is preloaded with the proper offset bounds
|
* @brief Preload a file with the proper offset bounds
|
||||||
*
|
*
|
||||||
* @param filename
|
* @param filename
|
||||||
* @param offset the maximum offset to consider for preloading. The total preloaded
|
* @param offset the maximum offset to consider for preloading. The total preloaded
|
||||||
|
|
@ -169,6 +169,15 @@ public:
|
||||||
*/
|
*/
|
||||||
bool preloadFile(const std::string& filename, uint32_t maxOffset) noexcept;
|
bool preloadFile(const std::string& filename, uint32_t maxOffset) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load a file and return its information. The file pool will store this
|
||||||
|
* data for future requests so use this function responsibly.
|
||||||
|
*
|
||||||
|
* @param filename
|
||||||
|
* @return A handle on the file data
|
||||||
|
*/
|
||||||
|
absl::optional<sfz::FileDataHandle> loadFile(const std::string& filename) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check that the sample exists. If not, try to find it in a case insensitive way.
|
* @brief Check that the sample exists. If not, try to find it in a case insensitive way.
|
||||||
*
|
*
|
||||||
|
|
@ -258,7 +267,9 @@ private:
|
||||||
std::atomic<bool> addingPromisesToClear { false };
|
std::atomic<bool> addingPromisesToClear { false };
|
||||||
std::atomic<bool> canAddPromisesToClear { true };
|
std::atomic<bool> canAddPromisesToClear { true };
|
||||||
|
|
||||||
absl::flat_hash_map<absl::string_view, PreloadedFileHandle> preloadedFiles;
|
// Preloaded data
|
||||||
|
absl::flat_hash_map<absl::string_view, FileDataHandle> preloadedFiles;
|
||||||
|
absl::flat_hash_map<absl::string_view, FileDataHandle> loadedFiles;
|
||||||
std::vector<std::thread> threadPool { };
|
std::vector<std::thread> threadPool { };
|
||||||
LEAK_DETECTOR(FilePool);
|
LEAK_DETECTOR(FilePool);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue