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
|
||||
}
|
||||
|
||||
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 };
|
||||
|
||||
if (!fs::exists(file))
|
||||
return {};
|
||||
|
||||
SndfileHandle sndFile(file.string().c_str());
|
||||
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 {};
|
||||
}
|
||||
|
||||
|
|
@ -198,13 +201,11 @@ absl::optional<sfz::FilePool::FileInformation> sfz::FilePool::getFileInformation
|
|||
bool sfz::FilePool::preloadFile(const std::string& filename, uint32_t maxOffset) noexcept
|
||||
{
|
||||
fs::path file { rootDirectory / filename };
|
||||
|
||||
if (!fs::exists(file))
|
||||
auto fileInformation = getFileInformation(filename);
|
||||
if (!fileInformation)
|
||||
return false;
|
||||
|
||||
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
|
||||
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);
|
||||
}();
|
||||
|
||||
if (preloadedFiles.contains(filename)) {
|
||||
if (framesToLoad > preloadedFiles[filename].preloadedData->getNumFrames()) {
|
||||
const auto existingFile = preloadedFiles.find(filename);
|
||||
if (existingFile != preloadedFiles.end()) {
|
||||
if (framesToLoad > existingFile->second.preloadedData->getNumFrames()) {
|
||||
preloadedFiles[filename].preloadedData = readFromFile<float>(sndFile, framesToLoad, oversamplingFactor);
|
||||
}
|
||||
} else {
|
||||
const float sourceSampleRate { static_cast<float>(oversamplingFactor) * static_cast<float>(sndFile.samplerate()) };
|
||||
PreloadedFileHandle handle { readFromFile<float>(sndFile, framesToLoad, oversamplingFactor), sourceSampleRate };
|
||||
fileInformation->sampleRate = static_cast<float>(oversamplingFactor) * static_cast<float>(sndFile.samplerate());
|
||||
FileDataHandle handle {
|
||||
readFromFile<float>(sndFile, framesToLoad, oversamplingFactor),
|
||||
*fileInformation
|
||||
};
|
||||
preloadedFiles.insert_or_assign(filename, handle);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (emptyPromises.empty()) {
|
||||
|
|
@ -244,7 +273,7 @@ sfz::FilePromisePtr sfz::FilePool::getFilePromise(const std::string& filename) n
|
|||
auto promise = emptyPromises.back();
|
||||
promise->filename = preloaded->first;
|
||||
promise->preloadedData = preloaded->second.preloadedData;
|
||||
promise->sampleRate = preloaded->second.sampleRate;
|
||||
promise->sampleRate = preloaded->second.information.sampleRate;
|
||||
promise->oversamplingFactor = oversamplingFactor;
|
||||
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) };
|
||||
SndfileHandle sndFile(file.string().c_str());
|
||||
preloadedFile.second.preloadedData = readFromFile<float>(sndFile, preloadSize + maxOffset, factor);
|
||||
preloadedFile.second.sampleRate *= samplerateChange;
|
||||
preloadedFile.second.information.sampleRate *= samplerateChange;
|
||||
}
|
||||
|
||||
this->oversamplingFactor = factor;
|
||||
|
|
|
|||
|
|
@ -43,11 +43,19 @@ namespace sfz {
|
|||
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...
|
||||
struct PreloadedFileHandle
|
||||
struct FileDataHandle
|
||||
{
|
||||
std::shared_ptr<AudioBuffer<float>> preloadedData;
|
||||
float sampleRate;
|
||||
FileInformation information;
|
||||
};
|
||||
|
||||
struct FilePromise
|
||||
|
|
@ -142,14 +150,6 @@ public:
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
|
@ -159,7 +159,7 @@ public:
|
|||
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 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;
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
|
|
@ -258,7 +267,9 @@ private:
|
|||
std::atomic<bool> addingPromisesToClear { false };
|
||||
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 { };
|
||||
LEAK_DETECTOR(FilePool);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue