mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-06-20 19:03:56 +02:00
[yabridgectl] Convert VST 3.7.5 moduleinfo files
This commit is contained in:
@@ -96,6 +96,8 @@ Versioning](https://semver.org/spec/v2.0.0.html).
|
|||||||
once after updating to yabridge 4.0, yabridge can now be updated without
|
once after updating to yabridge 4.0, yabridge can now be updated without
|
||||||
needing to rerun `yabridgectl sync`. This is particularly useful when using a
|
needing to rerun `yabridgectl sync`. This is particularly useful when using a
|
||||||
distro packaged version of yabridge.
|
distro packaged version of yabridge.
|
||||||
|
- Added support for the new VST 3.7.5 `moduleinfo.json` format to allow
|
||||||
|
VST3 plugins to replace other VST3 and VST2 plugins with different class IDs.
|
||||||
- `yabridgectl status` now shows the locations where bridged VST2 and VST3
|
- `yabridgectl status` now shows the locations where bridged VST2 and VST3
|
||||||
plugins will be set up.
|
plugins will be set up.
|
||||||
- `yabridgectl sync --prune` now also considers broken symlinks.
|
- `yabridgectl sync --prune` now also considers broken symlinks.
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ use crate::config::{
|
|||||||
use crate::files::{self, NativeFile, Plugin, Vst2Plugin};
|
use crate::files::{self, NativeFile, Plugin, Vst2Plugin};
|
||||||
use crate::utils::{self, get_file_type};
|
use crate::utils::{self, get_file_type};
|
||||||
use crate::utils::{verify_path_setup, verify_wine_setup};
|
use crate::utils::{verify_path_setup, verify_wine_setup};
|
||||||
|
use crate::vst3_moduleinfo::ModuleInfo;
|
||||||
|
|
||||||
pub mod blacklist;
|
pub mod blacklist;
|
||||||
|
|
||||||
@@ -471,6 +472,37 @@ pub fn do_sync(config: &mut Config, options: &SyncOptions) -> Result<()> {
|
|||||||
managed_vst3_bundle_files.insert(target_resources_dir);
|
managed_vst3_bundle_files.insert(target_resources_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the plugin has a VST 3.7.10 moduleinfo file, then we'll rewrite the byte
|
||||||
|
// orders of the class IDs stored within the file and then write it to the
|
||||||
|
// bridged VST3 bundle.
|
||||||
|
// https://steinbergmedia.github.io/vst3_dev_portal/pages/Technical+Documentation/VST+Module+Architecture/ModuleInfo-JSON.html
|
||||||
|
if let Some(original_moduleinfo_path) = module.original_moduleinfo_path() {
|
||||||
|
let target_moduleinfo_path = module.target_moduleinfo_path();
|
||||||
|
|
||||||
|
let result = utils::read_to_string(&original_moduleinfo_path)
|
||||||
|
.and_then(|module_info_json| {
|
||||||
|
serde_jsonrc::from_str(&module_info_json)
|
||||||
|
.context("Could not parse JSON file")
|
||||||
|
})
|
||||||
|
.and_then(|mut module_info: ModuleInfo| {
|
||||||
|
module_info.rewrite_uid_byte_orders()?;
|
||||||
|
Ok(module_info)
|
||||||
|
})
|
||||||
|
.and_then(|converted_module_info| {
|
||||||
|
let converted_json =
|
||||||
|
serde_jsonrc::to_string_pretty(&converted_module_info)
|
||||||
|
.context("Could not format JSON file")?;
|
||||||
|
utils::write(target_moduleinfo_path, converted_json)
|
||||||
|
});
|
||||||
|
if let Err(error) = result {
|
||||||
|
eprintln!(
|
||||||
|
"Error converting '{}', skipping...\n{}",
|
||||||
|
original_moduleinfo_path.display(),
|
||||||
|
error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.original_path().to_path_buf()
|
module.original_path().to_path_buf()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -217,6 +217,24 @@ impl Vst3Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the path to the Windows plugin's `moduleinfo.json` file if this is a bundle-style
|
||||||
|
/// plugin and the plugin has one. This file would need to be rewritten using
|
||||||
|
/// `ModuleInfo::rewrite_uid_byte_orders()` first.
|
||||||
|
pub fn original_moduleinfo_path(&self) -> Option<PathBuf> {
|
||||||
|
match &self.module {
|
||||||
|
Vst3ModuleType::Bundle(bundle_home) => {
|
||||||
|
let mut path = bundle_home.join("Contents");
|
||||||
|
path.push("moduleinfo.json");
|
||||||
|
if path.exists() {
|
||||||
|
Some(path)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Vst3ModuleType::Legacy(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the path to the bundle in `~/.vst3` corresponding to the bridged version of this module.
|
/// Get the path to the bundle in `~/.vst3` corresponding to the bridged version of this module.
|
||||||
/// We will try to recreate the original subdirectory structure so plugins are still grouped by
|
/// We will try to recreate the original subdirectory structure so plugins are still grouped by
|
||||||
/// manufacturer.
|
/// manufacturer.
|
||||||
@@ -283,6 +301,15 @@ impl Vst3Module {
|
|||||||
path
|
path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If the Windows VST3 plugin had a `moduleinfo.json` file, then it should be translated using
|
||||||
|
/// `ModuleInfo::rewrite_uid_byte_orders()` and then written to this path.
|
||||||
|
pub fn target_moduleinfo_path(&self) -> PathBuf {
|
||||||
|
let mut path = self.target_bundle_home();
|
||||||
|
path.push("Contents");
|
||||||
|
path.push("moduleinfo.json");
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a textual representation of the module type. Used in `yabridgectl status`.
|
/// Get a textual representation of the module type. Used in `yabridgectl status`.
|
||||||
pub fn type_str(&self) -> &str {
|
pub fn type_str(&self) -> &str {
|
||||||
match &self.module {
|
match &self.module {
|
||||||
|
|||||||
@@ -61,6 +61,13 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> Result<()> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wrapper around [`std::fs::read_to_string()`](std::fs::read_to_string) with a human readable
|
||||||
|
/// error message.
|
||||||
|
pub fn read_to_string<P: AsRef<Path>>(path: P) -> Result<String> {
|
||||||
|
fs::read_to_string(&path)
|
||||||
|
.with_context(|| format!("Could not read file '{}'", path.as_ref().display()))
|
||||||
|
}
|
||||||
|
|
||||||
/// Wrapper around [`std::fs::remove_dir_all()`](std::fs::remove_dir_all) with a human readable
|
/// Wrapper around [`std::fs::remove_dir_all()`](std::fs::remove_dir_all) with a human readable
|
||||||
/// error message.
|
/// error message.
|
||||||
pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> Result<()> {
|
pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> Result<()> {
|
||||||
@@ -87,6 +94,12 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Result<()> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wrapper around [`std::fs::write()`](std::fs::write) with a human readable error message.
|
||||||
|
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {
|
||||||
|
fs::write(&path, contents)
|
||||||
|
.with_context(|| format!("Could write to '{}'", path.as_ref().display()))
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the architecture of the ELF file at `path`. This detection is a bit naive, but we'd rather
|
/// Get the architecture of the ELF file at `path`. This detection is a bit naive, but we'd rather
|
||||||
/// not depend on `libmagic` or `libreadelf` just for this, since encountering a 32-bit yabridge
|
/// not depend on `libmagic` or `libreadelf` just for this, since encountering a 32-bit yabridge
|
||||||
/// library is going to be incredibly rare.
|
/// library is going to be incredibly rare.
|
||||||
|
|||||||
Reference in New Issue
Block a user