Merge pull request #532 from jpcima/restore-sfz-path
VST state file search
This commit is contained in:
commit
0cff698361
12 changed files with 640 additions and 2 deletions
|
|
@ -17,15 +17,32 @@ set(VSTPLUGIN_SOURCES
|
||||||
SfizzVstController.cpp
|
SfizzVstController.cpp
|
||||||
SfizzVstEditor.cpp
|
SfizzVstEditor.cpp
|
||||||
SfizzVstState.cpp
|
SfizzVstState.cpp
|
||||||
|
SfizzFileScan.cpp
|
||||||
|
SfizzForeignPaths.cpp
|
||||||
VstPluginFactory.cpp
|
VstPluginFactory.cpp
|
||||||
X11RunLoop.cpp)
|
X11RunLoop.cpp
|
||||||
|
NativeHelpers.cpp
|
||||||
|
FileTrie.cpp)
|
||||||
|
|
||||||
set(VSTPLUGIN_HEADERS
|
set(VSTPLUGIN_HEADERS
|
||||||
SfizzVstProcessor.h
|
SfizzVstProcessor.h
|
||||||
SfizzVstController.h
|
SfizzVstController.h
|
||||||
SfizzVstEditor.h
|
SfizzVstEditor.h
|
||||||
SfizzVstState.h
|
SfizzVstState.h
|
||||||
X11RunLoop.h)
|
SfizzFileScan.h
|
||||||
|
SfizzForeignPaths.h
|
||||||
|
X11RunLoop.h
|
||||||
|
NativeHelpers.h
|
||||||
|
FileTrie.h)
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
set(VSTPLUGIN_MAC_SOURCES
|
||||||
|
SfizzForeignPaths.mm
|
||||||
|
NativeHelpers.mm)
|
||||||
|
list(APPEND VSTPLUGIN_SOURCES ${VSTPLUGIN_MAC_SOURCES})
|
||||||
|
set_property(SOURCE ${VSTPLUGIN_MAC_SOURCES} APPEND_STRING
|
||||||
|
PROPERTY COMPILE_FLAGS " -fobjc-arc")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(${VSTPLUGIN_PRJ_NAME} MODULE
|
add_library(${VSTPLUGIN_PRJ_NAME} MODULE
|
||||||
${VSTPLUGIN_HEADERS}
|
${VSTPLUGIN_HEADERS}
|
||||||
|
|
@ -65,6 +82,16 @@ if (MINGW)
|
||||||
set_target_properties (${VSTPLUGIN_PRJ_NAME} PROPERTIES LINK_FLAGS "-static")
|
set_target_properties (${VSTPLUGIN_PRJ_NAME} PROPERTIES LINK_FLAGS "-static")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Link system dependencies
|
||||||
|
if(WIN32)
|
||||||
|
elseif(APPLE)
|
||||||
|
target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE ${APPLE_FOUNDATION_LIBRARY})
|
||||||
|
else()
|
||||||
|
pkg_check_modules(GLIB REQUIRED glib-2.0)
|
||||||
|
target_include_directories(${VSTPLUGIN_PRJ_NAME} PRIVATE ${GLIB_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE ${GLIB_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
# Create the bundle (see "VST 3 Locations / Format")
|
# Create the bundle (see "VST 3 Locations / Format")
|
||||||
execute_process (
|
execute_process (
|
||||||
COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources")
|
COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources")
|
||||||
|
|
|
||||||
108
vst/FileTrie.cpp
Normal file
108
vst/FileTrie.cpp
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#include "FileTrie.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
constexpr size_t FileTrie::npos;
|
||||||
|
|
||||||
|
fs::path FileTrie::at(size_t index) const
|
||||||
|
{
|
||||||
|
if (index >= entries_.size())
|
||||||
|
throw std::out_of_range("FileTrie::at");
|
||||||
|
return pathFromEntry(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::path FileTrie::operator[](size_t index) const
|
||||||
|
{
|
||||||
|
assert(index < entries_.size());
|
||||||
|
return pathFromEntry(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::path FileTrie::pathFromEntry(size_t index) const
|
||||||
|
{
|
||||||
|
const Entry* currentEntry = &entries_[index];
|
||||||
|
fs::path path = fs::u8path(currentEntry->name);
|
||||||
|
|
||||||
|
size_t currentIndex;
|
||||||
|
while ((currentIndex = currentEntry->parent) != npos) {
|
||||||
|
currentEntry = &entries_[currentIndex];
|
||||||
|
path = fs::u8path(currentEntry->name) / path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const FileTrie& trie)
|
||||||
|
{
|
||||||
|
os << '{' << '\n';
|
||||||
|
for (size_t i = 0, n = trie.size(); i < n; ++i)
|
||||||
|
os << '\t' << i << ':' << ' ' << trie[i] << ',' << '\n';
|
||||||
|
os << '}';
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
FileTrieBuilder::FileTrieBuilder(size_t initialCapacity)
|
||||||
|
{
|
||||||
|
FileTrie& trie = trie_;
|
||||||
|
trie.entries_.reserve(initialCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileTrie&& FileTrieBuilder::build()
|
||||||
|
{
|
||||||
|
FileTrie& trie = trie_;
|
||||||
|
trie.entries_.shrink_to_fit();
|
||||||
|
return std::move(trie);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FileTrieBuilder::addFile(const fs::path& path)
|
||||||
|
{
|
||||||
|
if (path.empty())
|
||||||
|
return FileTrie::npos;
|
||||||
|
|
||||||
|
size_t dirIndex = ensureDirectory(path.parent_path());
|
||||||
|
|
||||||
|
FileTrie& trie = trie_;
|
||||||
|
FileTrie::Entry ent;
|
||||||
|
ent.parent = dirIndex;
|
||||||
|
ent.name = (--path.end())->u8string();
|
||||||
|
|
||||||
|
size_t fileIndex = trie.entries_.size();
|
||||||
|
trie.entries_.push_back(std::move(ent));
|
||||||
|
|
||||||
|
return fileIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FileTrieBuilder::ensureDirectory(const fs::path& dirPath)
|
||||||
|
{
|
||||||
|
if (dirPath.empty())
|
||||||
|
return FileTrie::npos;
|
||||||
|
|
||||||
|
const fs::path::string_type& dirNat = dirPath.native();
|
||||||
|
auto it = directories_.find(dirNat);
|
||||||
|
if (it != directories_.end())
|
||||||
|
return it->second;
|
||||||
|
|
||||||
|
FileTrie& trie = trie_;
|
||||||
|
FileTrie::Entry ent;
|
||||||
|
ent.parent = FileTrie::npos;
|
||||||
|
ent.name = (--dirPath.end())->u8string();
|
||||||
|
if (dirPath.has_parent_path()) {
|
||||||
|
fs::path parentPath = dirPath.parent_path();
|
||||||
|
if (parentPath != dirPath)
|
||||||
|
ent.parent = ensureDirectory(parentPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t dirIndex = trie.entries_.size();
|
||||||
|
trie.entries_.push_back(std::move(ent));
|
||||||
|
|
||||||
|
directories_[dirNat] = dirIndex;
|
||||||
|
|
||||||
|
return dirIndex;
|
||||||
|
}
|
||||||
52
vst/FileTrie.h
Normal file
52
vst/FileTrie.h
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <ghc/fs_std.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
class FileTrie {
|
||||||
|
public:
|
||||||
|
static constexpr size_t npos = ~size_t(0);
|
||||||
|
|
||||||
|
size_t size() const noexcept { return entries_.size(); }
|
||||||
|
fs::path at(size_t index) const;
|
||||||
|
fs::path operator[](size_t index) const;
|
||||||
|
void clear() noexcept { entries_.clear(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
fs::path pathFromEntry(size_t index) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Entry {
|
||||||
|
size_t parent = npos;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
std::vector<Entry> entries_;
|
||||||
|
|
||||||
|
friend class FileTrieBuilder;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const FileTrie& trie);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
class FileTrieBuilder {
|
||||||
|
public:
|
||||||
|
explicit FileTrieBuilder(size_t initialCapacity = 8192);
|
||||||
|
FileTrie&& build();
|
||||||
|
size_t addFile(const fs::path& path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t ensureDirectory(const fs::path& dirPath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FileTrie trie_;
|
||||||
|
std::unordered_map<fs::path::string_type, size_t> directories_;
|
||||||
|
};
|
||||||
39
vst/NativeHelpers.cpp
Normal file
39
vst/NativeHelpers.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#include "NativeHelpers.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
|
||||||
|
const fs::path& getUserDocumentsDirectory()
|
||||||
|
{
|
||||||
|
static const fs::path directory = []() -> fs::path {
|
||||||
|
std::unique_ptr<WCHAR[]> path(new WCHAR[32768]);
|
||||||
|
if (SHGetFolderPathW(nullptr, CSIDL_PERSONAL|CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, path.get()) != S_OK)
|
||||||
|
throw std::runtime_error("Cannot get the document directory.");
|
||||||
|
return fs::path(path.get());
|
||||||
|
}();
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
// implemented in NativeHelpers.mm
|
||||||
|
#else
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
const fs::path& getUserDocumentsDirectory()
|
||||||
|
{
|
||||||
|
static const fs::path directory = []() -> fs::path {
|
||||||
|
const gchar* path = g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS);
|
||||||
|
if (!path)
|
||||||
|
throw std::runtime_error("Cannot get the document directory.");
|
||||||
|
return fs::path(path);
|
||||||
|
}();
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
10
vst/NativeHelpers.h
Normal file
10
vst/NativeHelpers.h
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <ghc/fs_std.hpp>
|
||||||
|
|
||||||
|
const fs::path& getUserDocumentsDirectory();
|
||||||
27
vst/NativeHelpers.mm
Normal file
27
vst/NativeHelpers.mm
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#include "NativeHelpers.h"
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#if !__has_feature(objc_arc)
|
||||||
|
#error This source file requires ARC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const fs::path& getUserDocumentsDirectory()
|
||||||
|
{
|
||||||
|
static const fs::path directory = []() -> fs::path {
|
||||||
|
NSFileManager* fm = [NSFileManager defaultManager];
|
||||||
|
NSArray<NSURL*>* urls = [fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
|
||||||
|
for (NSUInteger i = 0, n = [urls count]; i < n; ++i) {
|
||||||
|
NSURL *url = [urls objectAtIndex:i];
|
||||||
|
if ([url isFileURL])
|
||||||
|
return fs::path([url path].UTF8String);
|
||||||
|
}
|
||||||
|
throw std::runtime_error("Cannot get the document directory.");
|
||||||
|
}();
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
218
vst/SfizzFileScan.cpp
Normal file
218
vst/SfizzFileScan.cpp
Normal file
|
|
@ -0,0 +1,218 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#include "SfizzFileScan.h"
|
||||||
|
#include "SfizzForeignPaths.h"
|
||||||
|
#include "NativeHelpers.h"
|
||||||
|
#include <absl/strings/ascii.h>
|
||||||
|
#include <absl/algorithm/container.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
// wait at least this much before refreshing the file rescan
|
||||||
|
// it permits to not repeat the operation many times if many searches are
|
||||||
|
// requested at once, eg. on session loading with multiple plugin instances
|
||||||
|
static const std::chrono::seconds expiration_time { 10 };
|
||||||
|
|
||||||
|
SfzFileScan& SfzFileScan::getInstance()
|
||||||
|
{
|
||||||
|
static SfzFileScan instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SfzFileScan::locateRealFile(const fs::path& pathOrig, fs::path& pathFound)
|
||||||
|
{
|
||||||
|
if (pathOrig.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock { mutex };
|
||||||
|
refreshScan();
|
||||||
|
|
||||||
|
auto it = file_index_.find(keyOf(pathOrig));
|
||||||
|
if (it == file_index_.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const std::list<size_t>& candidateIndices = it->second;
|
||||||
|
std::vector<fs::path> candidates;
|
||||||
|
candidates.reserve(candidateIndices.size());
|
||||||
|
for (const size_t index : candidateIndices)
|
||||||
|
candidates.push_back(file_trie_[index]);
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
pathFound = electBestMatch(pathOrig, candidates);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SfzFileScan::isExpired() const
|
||||||
|
{
|
||||||
|
return !completion_time_ ||
|
||||||
|
(clock::now() - *completion_time_) > expiration_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SfzFileScan::refreshScan(bool force)
|
||||||
|
{
|
||||||
|
if (!force && !isExpired())
|
||||||
|
return;
|
||||||
|
|
||||||
|
file_trie_.clear();
|
||||||
|
file_index_.clear();
|
||||||
|
|
||||||
|
FileTrieBuilder builder;
|
||||||
|
|
||||||
|
for (const fs::path& dirPath : SfizzPaths::sfzDefaultPaths()) {
|
||||||
|
std::error_code ec;
|
||||||
|
const fs::directory_options dirOpts =
|
||||||
|
fs::directory_options::skip_permission_denied;
|
||||||
|
|
||||||
|
for (fs::recursive_directory_iterator it(dirPath, dirOpts, ec);
|
||||||
|
!ec && it != fs::recursive_directory_iterator();
|
||||||
|
it.increment(ec))
|
||||||
|
{
|
||||||
|
const fs::directory_entry& ent = *it;
|
||||||
|
const fs::path& filePath = ent.path();
|
||||||
|
std::error_code ec;
|
||||||
|
if (ent.is_regular_file(ec) /*&& pathIsSfz(filePath)*/) {
|
||||||
|
size_t fileIndex = builder.addFile(filePath);
|
||||||
|
file_index_[keyOf(filePath.filename())].push_back(fileIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file_trie_ = builder.build();
|
||||||
|
completion_time_ = clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SfzFileScan::keyOf(const fs::path& path)
|
||||||
|
{
|
||||||
|
std::string key = path.u8string();
|
||||||
|
absl::AsciiStrToLower(&key);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace SfzFileScanImpl {
|
||||||
|
template <class T>
|
||||||
|
bool asciiCaseEqual(const std::basic_string<T>& a, const std::basic_string<T>& b)
|
||||||
|
{
|
||||||
|
const size_t n = a.size();
|
||||||
|
if (n != b.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto lower = [](T c) -> T {
|
||||||
|
return (c >= T('A') && c <= T('Z')) ? (c - T('A') + T('a')) : c;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i)
|
||||||
|
if (lower(a[i]) != lower(b[i]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace SfzFileScanImpl
|
||||||
|
|
||||||
|
bool SfzFileScan::pathIsSfz(const fs::path& path)
|
||||||
|
{
|
||||||
|
const fs::path::string_type& str = path.native();
|
||||||
|
using char_type = fs::path::value_type;
|
||||||
|
const size_t n = str.size();
|
||||||
|
return n > 4 &&
|
||||||
|
str[n - 4] == char_type('.') &&
|
||||||
|
(str[n - 3] == char_type('s') || str[n - 3] == char_type('S')) &&
|
||||||
|
(str[n - 2] == char_type('f') || str[n - 2] == char_type('F')) &&
|
||||||
|
(str[n - 1] == char_type('z') || str[n - 1] == char_type('Z'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const fs::path& SfzFileScan::electBestMatch(const fs::path& path, absl::Span<const fs::path> candidates)
|
||||||
|
{
|
||||||
|
if (candidates.empty())
|
||||||
|
return path;
|
||||||
|
|
||||||
|
if (candidates.size() == 1)
|
||||||
|
return candidates.front();
|
||||||
|
|
||||||
|
struct Score {
|
||||||
|
size_t components = 0;
|
||||||
|
size_t exact = 0;
|
||||||
|
bool operator<(const Score& other) const noexcept
|
||||||
|
{
|
||||||
|
return (components != other.components) ?
|
||||||
|
(components < other.components) : (exact < other.exact);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Score> scores;
|
||||||
|
scores.reserve(candidates.size());
|
||||||
|
|
||||||
|
for (size_t i = 0, n = candidates.size(); i < n; ++i) {
|
||||||
|
scores.emplace_back();
|
||||||
|
Score& score = scores.back();
|
||||||
|
|
||||||
|
const fs::path& p1 = path;
|
||||||
|
const fs::path& p2 = candidates[i];
|
||||||
|
auto it1 = p1.end();
|
||||||
|
auto it2 = p2.end();
|
||||||
|
|
||||||
|
bool matching = true;
|
||||||
|
while (matching && it1-- != p1.begin() && it2-- != p2.begin()) {
|
||||||
|
const fs::path& c1 = *it1;
|
||||||
|
const fs::path& c2 = *it2;
|
||||||
|
if (c1 == c2) {
|
||||||
|
score.components += 1;
|
||||||
|
score.exact += 1;
|
||||||
|
}
|
||||||
|
else if (SfzFileScanImpl::asciiCaseEqual(c1.native(), c2.native()))
|
||||||
|
score.components += 1;
|
||||||
|
else
|
||||||
|
matching = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t best = 0;
|
||||||
|
for (size_t i = 1, n = scores.size(); i < n; ++i) {
|
||||||
|
if (scores[best] < scores[i])
|
||||||
|
best = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidates[best];
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace SfizzPaths {
|
||||||
|
|
||||||
|
absl::Span<const fs::path> sfzDefaultPaths()
|
||||||
|
{
|
||||||
|
static const auto paths = []() -> std::vector<fs::path> {
|
||||||
|
std::vector<fs::path> paths;
|
||||||
|
paths.reserve(8);
|
||||||
|
auto addPath = [&paths](const fs::path& newPath) {
|
||||||
|
if (absl::c_find(paths, newPath) == paths.end())
|
||||||
|
paths.push_back(newPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
addPath(getUserDocumentsDirectory() / "SFZ instruments");
|
||||||
|
|
||||||
|
for (const fs::path& foreign : {
|
||||||
|
getAriaPathSetting("user_files_dir"),
|
||||||
|
getAriaPathSetting("Converted_path") })
|
||||||
|
if (!foreign.empty() && foreign.is_absolute())
|
||||||
|
addPath(foreign);
|
||||||
|
|
||||||
|
paths.shrink_to_fit();
|
||||||
|
return paths;
|
||||||
|
}();
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
void createSfzDefaultPaths()
|
||||||
|
{
|
||||||
|
for (const fs::path& path : sfzDefaultPaths()) {
|
||||||
|
std::error_code ec;
|
||||||
|
fs::create_directory(path, ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace SfizzPaths
|
||||||
40
vst/SfizzFileScan.h
Normal file
40
vst/SfizzFileScan.h
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "FileTrie.h"
|
||||||
|
#include <absl/types/span.h>
|
||||||
|
#include <absl/types/optional.h>
|
||||||
|
#include <ghc/fs_std.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <mutex>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
class SfzFileScan {
|
||||||
|
public:
|
||||||
|
static SfzFileScan& getInstance();
|
||||||
|
bool locateRealFile(const fs::path& pathOrig, fs::path& pathFound);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::chrono::steady_clock clock;
|
||||||
|
std::mutex mutex;
|
||||||
|
absl::optional<clock::time_point> completion_time_;
|
||||||
|
FileTrie file_trie_;
|
||||||
|
std::unordered_map<std::string, std::list<size_t>> file_index_;
|
||||||
|
|
||||||
|
bool isExpired() const;
|
||||||
|
void refreshScan(bool force = false);
|
||||||
|
static std::string keyOf(const fs::path& path);
|
||||||
|
static bool pathIsSfz(const fs::path& path);
|
||||||
|
static const fs::path& electBestMatch(const fs::path& path, absl::Span<const fs::path> candidates);
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace SfizzPaths {
|
||||||
|
absl::Span<const fs::path> sfzDefaultPaths();
|
||||||
|
void createSfzDefaultPaths();
|
||||||
|
} // namespace SfizzPaths
|
||||||
51
vst/SfizzForeignPaths.cpp
Normal file
51
vst/SfizzForeignPaths.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#include "SfizzForeignPaths.h"
|
||||||
|
|
||||||
|
namespace SfizzPaths {
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
fs::path getAriaPathSetting(const char* name)
|
||||||
|
{
|
||||||
|
fs::path path;
|
||||||
|
|
||||||
|
HKEY key = 0;
|
||||||
|
|
||||||
|
std::unique_ptr<WCHAR[]> nameW;
|
||||||
|
unsigned nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0);
|
||||||
|
if (nameSize == 0)
|
||||||
|
return {};
|
||||||
|
nameW.reset(new WCHAR[nameSize]);
|
||||||
|
if (MultiByteToWideChar(CP_UTF8, 0, name, -1, nameW.get(), nameSize) == 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const WCHAR ariaKeyPath[] = L"Software\\Plogue Art et Technologie, Inc\\Aria";
|
||||||
|
|
||||||
|
if (RegOpenKeyExW(HKEY_CURRENT_USER, ariaKeyPath, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
|
||||||
|
WCHAR valueBuffer[32768 + 1];
|
||||||
|
DWORD valueSize = sizeof(valueBuffer) - sizeof(WCHAR);
|
||||||
|
if (RegQueryValueExW(key, nameW.get(), nullptr, nullptr, reinterpret_cast<LPBYTE>(valueBuffer), &valueSize) == ERROR_SUCCESS) {
|
||||||
|
valueBuffer[32768] = L'\0';
|
||||||
|
path = fs::path(valueBuffer);
|
||||||
|
}
|
||||||
|
RegCloseKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
// implementation in SfizzForeignPaths.mm
|
||||||
|
#else
|
||||||
|
fs::path getAriaPathSetting(const char* name)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace SfizzPaths
|
||||||
12
vst/SfizzForeignPaths.h
Normal file
12
vst/SfizzForeignPaths.h
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <ghc/fs_std.hpp>
|
||||||
|
|
||||||
|
namespace SfizzPaths {
|
||||||
|
fs::path getAriaPathSetting(const char* name);
|
||||||
|
} // namespace SfizzPaths
|
||||||
27
vst/SfizzForeignPaths.mm
Normal file
27
vst/SfizzForeignPaths.mm
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#include "SfizzForeignPaths.h"
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#if !__has_feature(objc_arc)
|
||||||
|
#error This source file requires ARC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace SfizzPaths {
|
||||||
|
|
||||||
|
fs::path getAriaPathSetting(const char* name)
|
||||||
|
{
|
||||||
|
NSUserDefaults* ud = [[NSUserDefaults alloc] initWithSuiteName:@"com.plogue.aria"];
|
||||||
|
NSString* value = [ud stringForKey:[NSString stringWithUTF8String:name]];
|
||||||
|
if (!value)
|
||||||
|
return {};
|
||||||
|
return fs::path(value.UTF8String);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace SfizzPaths
|
||||||
|
#endif
|
||||||
|
|
@ -7,9 +7,11 @@
|
||||||
#include "SfizzVstProcessor.h"
|
#include "SfizzVstProcessor.h"
|
||||||
#include "SfizzVstController.h"
|
#include "SfizzVstController.h"
|
||||||
#include "SfizzVstState.h"
|
#include "SfizzVstState.h"
|
||||||
|
#include "SfizzFileScan.h"
|
||||||
#include "base/source/fstreamer.h"
|
#include "base/source/fstreamer.h"
|
||||||
#include "pluginterfaces/vst/ivstevents.h"
|
#include "pluginterfaces/vst/ivstevents.h"
|
||||||
#include "pluginterfaces/vst/ivstparameterchanges.h"
|
#include "pluginterfaces/vst/ivstparameterchanges.h"
|
||||||
|
#include <ghc/fs_std.hpp>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
|
|
@ -28,6 +30,8 @@ SfizzVstProcessor::SfizzVstProcessor()
|
||||||
: _fifoToWorker(64 * 1024), _fifoMidiFromUi(64 * 1024)
|
: _fifoToWorker(64 * 1024), _fifoMidiFromUi(64 * 1024)
|
||||||
{
|
{
|
||||||
setControllerClass(SfizzVstController::cid);
|
setControllerClass(SfizzVstController::cid);
|
||||||
|
|
||||||
|
SfizzPaths::createSfzDefaultPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
SfizzVstProcessor::~SfizzVstProcessor()
|
SfizzVstProcessor::~SfizzVstProcessor()
|
||||||
|
|
@ -83,6 +87,29 @@ tresult PLUGIN_API SfizzVstProcessor::setState(IBStream* stream)
|
||||||
if (r != kResultTrue)
|
if (r != kResultTrue)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
// check the files to really exist, otherwise search them
|
||||||
|
for (std::string* statePath : { &s.sfzFile, &s.scalaFile }) {
|
||||||
|
if (statePath->empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fs::path pathOrig = fs::u8path(*statePath);
|
||||||
|
std::error_code ec;
|
||||||
|
if (fs::is_regular_file(pathOrig, ec))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fprintf(stderr, "[Sfizz] searching for missing file: %s\n", pathOrig.filename().u8string().c_str());
|
||||||
|
|
||||||
|
SfzFileScan& fileScan = SfzFileScan::getInstance();
|
||||||
|
fs::path pathFound;
|
||||||
|
if (!fileScan.locateRealFile(pathOrig, pathFound))
|
||||||
|
fprintf(stderr, "[Sfizz] file not found: %s\n", pathOrig.filename().u8string().c_str());
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "[Sfizz] file found: %s\n", pathFound.filename().u8string().c_str());
|
||||||
|
*statePath = pathFound.u8string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
std::lock_guard<std::mutex> lock(_processMutex);
|
std::lock_guard<std::mutex> lock(_processMutex);
|
||||||
_state = s;
|
_state = s;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue