mirror of
https://github.com/audacity/mod-openvino-macos.git
synced 2025-12-11 14:05:24 -06:00
Enable ARM build
This commit is contained in:
parent
13f5e0a8bf
commit
533ea2d3ed
50
.github/workflows/build.yml
vendored
Normal file
50
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
name: build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
ARTIFACT_PATH: ${{ github.workspace }}/artifact
|
||||||
|
BUILD_PATH: ${{ github.workspace }}/build
|
||||||
|
PACKAGE_PATH: ${{ github.workspace }}/package
|
||||||
|
SOURCE_PATH: ${{ github.workspace }}/sources
|
||||||
|
STAGING_PATH: ${{ github.workspace }}/staging
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-openvino-plugins-arm64:
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: ${{ github.workspace }}
|
||||||
|
|
||||||
|
- name: Install Apple codesigning certificates
|
||||||
|
uses: apple-actions/import-codesign-certs@v2
|
||||||
|
env:
|
||||||
|
P12_FILE_BASE64: ${{ secrets.APPLE_CERTIFICATE }}
|
||||||
|
P12_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||||
|
if: ${{ env.P12_FILE_BASE64 != '' && env.P12_PASSWORD != '' }}
|
||||||
|
with:
|
||||||
|
p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }}
|
||||||
|
p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Build audacity for arm64
|
||||||
|
run: |
|
||||||
|
scripts/prepare-build.sh
|
||||||
|
scripts/build-arm64.sh
|
||||||
|
env:
|
||||||
|
APPLE_CODESIGN_IDENTITY: ${{ secrets.APPLE_CODESIGN_IDENTITY }}
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: mod-openvino-arm64
|
||||||
|
path: ${{ env.STAGING_PATH }}/Audacity-OpenVINO.pkg
|
||||||
|
|
||||||
14
.gitignore
vendored
14
.gitignore
vendored
@ -1,5 +1,19 @@
|
|||||||
build/*
|
build/*
|
||||||
sources/*
|
sources/*
|
||||||
staging/*
|
staging/*
|
||||||
|
packages/*
|
||||||
|
|
||||||
*.pkg
|
*.pkg
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
### Xcode ###
|
||||||
|
xcuserdata/
|
||||||
|
*.xcscmblueprint
|
||||||
|
*.xccheckout
|
||||||
|
*.xcodeproj/*
|
||||||
|
!*.xcodeproj/project.pbxproj
|
||||||
|
!*.xcodeproj/xcshareddata/
|
||||||
|
!*.xcodeproj/project.xcworkspace/
|
||||||
|
!*.xcworkspace/contents.xcworkspacedata
|
||||||
|
/*.gcno
|
||||||
|
**/xcshareddata/WorkspaceSettings.xcsettings
|
||||||
31
installer/Resources/Conclusion.html
Normal file
31
installer/Resources/Conclusion.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head><meta charset="UTF-8"><title>Installation Complete</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
padding: 40px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
p, li {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Installation Complete</h1>
|
||||||
|
<p>The Audacity OpenVINO Plugin has been successfully installed.</p>
|
||||||
|
<p>Launch Audacity to start using the new features!</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
31
installer/Resources/License.html
Normal file
31
installer/Resources/License.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head><meta charset="UTF-8"><title>License Agreement</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
padding: 40px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
p, li {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>License Agreement</h1>
|
||||||
|
<p>This software is provided under the GNU General Public License v3 (GPLv3).</p>
|
||||||
|
<p>Please review the full license terms before proceeding.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
35
installer/Resources/ReadMe.html
Normal file
35
installer/Resources/ReadMe.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head><meta charset="UTF-8"><title>Important</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
padding: 40px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
p, li {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Please read</h1>
|
||||||
|
<ul>
|
||||||
|
<li>OpenVINO toolkit runs AI models locally and requires AI models to be downloaded.</li>
|
||||||
|
<li>Models will be downloaded during installation based on your configuration.</li>
|
||||||
|
<li><strong>No progress bar will be shown.</strong> The installer will simply appear to pause for a log period of time.</li>
|
||||||
|
<li>Disk space requirements vary depending on model selection. Some models are few GB each.</li>
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
33
installer/Resources/Welcome.html
Normal file
33
installer/Resources/Welcome.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head><meta charset="UTF-8"><title>Welcome to Audacity OpenVINO Plugin</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
padding: 40px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
p, li {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Audacity OpenVINO Plugin</h1>
|
||||||
|
<p>This plugin adds AI-based features to Audacity using Intel's OpenVINO toolkit.</p>
|
||||||
|
<p><strong>Note:</strong> During installation, the plugin will download additional AI models.</p>
|
||||||
|
<p>These downloads can be large and may take a significant amount of time depending on your internet speed and model selection.</p>
|
||||||
|
<p>The installer will appear to "hang" on "Running package scripts" during this process — this is expected.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
74
installer/Scripts/postinstall
Executable file
74
installer/Scripts/postinstall
Executable file
@ -0,0 +1,74 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# This script runs after the installation
|
||||||
|
# It updates the Audacity configuration file to enable the OpenVINO module
|
||||||
|
|
||||||
|
MODULE_NAME="mod-openvino"
|
||||||
|
MODULE_PATH="/Library/Application Support/audacity/modules/${MODULE_NAME}.so"
|
||||||
|
MODULE_DATETIME=$(stat -f "%m" "$MODULE_PATH" | xargs -I{} date -r {} +"%Y-%m-%dT%H:%M:%S")
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(dirname "$0")"
|
||||||
|
APP_PATH="$SCRIPT_DIR/ResourceDownloader.app"
|
||||||
|
LOGGED_IN_USER=$(stat -f "%Su" /dev/console)
|
||||||
|
|
||||||
|
# Block until the app quits
|
||||||
|
sudo -u "$LOGGED_IN_USER" open -W "$APP_PATH"
|
||||||
|
|
||||||
|
update_config_section() {
|
||||||
|
|
||||||
|
local cfg_file="$1"
|
||||||
|
local section="$2"
|
||||||
|
local key="$3"
|
||||||
|
local value="$4"
|
||||||
|
local tmp_file="${cfg_file}.tmp"
|
||||||
|
original_owner=$(stat -f "%u" "$cfg_file")
|
||||||
|
original_group=$(stat -f "%g" "$cfg_file")
|
||||||
|
|
||||||
|
awk -v section="$section" -v key="$key" -v value="$value" '
|
||||||
|
BEGIN {
|
||||||
|
found_section = 0
|
||||||
|
found_key = 0
|
||||||
|
}
|
||||||
|
$0 == "[" section "]" {
|
||||||
|
found_section = 1
|
||||||
|
print
|
||||||
|
next
|
||||||
|
}
|
||||||
|
found_section && $0 ~ "^" key{
|
||||||
|
print key "=" value
|
||||||
|
found_key = 1
|
||||||
|
found_section = 0
|
||||||
|
next
|
||||||
|
}
|
||||||
|
found_section && !found_key && /^\[.*\]/ {
|
||||||
|
print key "=" value
|
||||||
|
found_key = 1
|
||||||
|
found_section = 0
|
||||||
|
}
|
||||||
|
{ print }
|
||||||
|
END { }
|
||||||
|
' "$cfg_file" > "$tmp_file" && mv "$tmp_file" "$cfg_file"
|
||||||
|
chown "$original_owner":"$original_group" "$cfg_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Loop through all user home directories in /Users (excluding system users)
|
||||||
|
for USER_HOME in /Users/*; do
|
||||||
|
# Only act on real user dirs
|
||||||
|
[ -d "$USER_HOME" ] || continue
|
||||||
|
[ -f "$USER_HOME/.zshrc" ] || [ -f "$USER_HOME/.bash_profile" ] || continue
|
||||||
|
|
||||||
|
CFG_PATH="$USER_HOME/Library/Application Support/audacity/audacity.cfg"
|
||||||
|
CFG_PATH1="$USER_HOME/Library/Application Support/audacity/_audacity.cfg"
|
||||||
|
|
||||||
|
# Skip if the config doesn't exist
|
||||||
|
[ -f "$CFG_PATH" ] || continue
|
||||||
|
|
||||||
|
echo "Updating $CFG_PATH"
|
||||||
|
|
||||||
|
update_config_section "$CFG_PATH" "Module" "mod-openvino" "1"
|
||||||
|
update_config_section "$CFG_PATH" "ModuleDateTime" "mod-openvino" "$MODULE_DATETIME"
|
||||||
|
update_config_section "$CFG_PATH" "ModulePath" "mod-openvino" "$MODULE_PATH"
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
27
installer/distribution.xml
Normal file
27
installer/distribution.xml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<installer-gui-script minSpecVersion="1">
|
||||||
|
<title>Audacity OpenVINO module</title>
|
||||||
|
|
||||||
|
<welcome file="Welcome.html"/>
|
||||||
|
<license file="License.html"/>
|
||||||
|
<readme file="ReadMe.html"/>
|
||||||
|
<conclusion file="Conclusion.html"/>
|
||||||
|
|
||||||
|
<options customize="never" require-scripts="false" rootVolumeOnly="true" hostArchitectures="arm64,x86_64"/>
|
||||||
|
|
||||||
|
<choices-outline>
|
||||||
|
<line choice="module"/>
|
||||||
|
</choices-outline>
|
||||||
|
|
||||||
|
<choice id="module" title="Module">
|
||||||
|
<pkg-ref id="org.audacity.openvino-module"/>
|
||||||
|
</choice>
|
||||||
|
|
||||||
|
<pkg-ref id="org.audacity.openvino-module">
|
||||||
|
#openvino-module.pkg
|
||||||
|
<must-close>
|
||||||
|
<app id="org.audacityteam.audacity"/>
|
||||||
|
</must-close>
|
||||||
|
</pkg-ref>
|
||||||
|
|
||||||
|
</installer-gui-script>
|
||||||
10
patches/audacity/modules.patch
Normal file
10
patches/audacity/modules.patch
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
--- modules/CMakeLists.txt.orig 2025-04-24 14:23:00.161466283 +0300
|
||||||
|
+++ modules/CMakeLists.txt 2025-04-24 14:23:19.002006483 +0300
|
||||||
|
@@ -9,6 +9,7 @@
|
||||||
|
# The list of module sub-folders is ordered so that each folder occurs after any
|
||||||
|
# others that it depends on
|
||||||
|
set( FOLDERS
|
||||||
|
+ mod-openvino
|
||||||
|
etc
|
||||||
|
import-export
|
||||||
|
track-ui
|
||||||
28
patches/openvino-plugins-ai-audacity/htdemux.h.patch
Normal file
28
patches/openvino-plugins-ai-audacity/htdemux.h.patch
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
--- mod-openvino/htdemucs.h.orig 2024-12-20 16:59:14.000000000 +0300
|
||||||
|
+++ mod-openvino/htdemucs.h 2025-04-24 14:58:08.662787586 +0300
|
||||||
|
@@ -4,7 +4,7 @@
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
-namespace torch
|
||||||
|
+namespace at
|
||||||
|
{
|
||||||
|
class Tensor;
|
||||||
|
}
|
||||||
|
@@ -41,11 +41,11 @@
|
||||||
|
std::shared_ptr< HTDemucs_impl > _impl;
|
||||||
|
#endif
|
||||||
|
std::shared_ptr< HTDemucs_openvino_impl > _impl_ov;
|
||||||
|
- bool _apply_model_0(torch::Tensor& mix, torch::Tensor& out, int64_t shifts = 1, bool split = true, double overlap = 0.25, double transition_power = 1., int64_t static_shifts = 1);
|
||||||
|
- bool _apply_model_1(torch::Tensor& mix, torch::Tensor& out, int64_t shifts = 1, bool split = true, double overlap = 0.25, double transition_power = 1., int64_t static_shifts = 1);
|
||||||
|
- bool _apply_model_2(TensorChunk& mix, torch::Tensor& out, bool split = true, double overlap = 0.25, double transition_power = 1., int64_t static_shifts = 1);
|
||||||
|
- bool _apply_model_3(TensorChunk& mix, torch::Tensor& out);
|
||||||
|
- bool _actually_run_model(torch::Tensor& mix_tensor, torch::Tensor& x);
|
||||||
|
+ bool _apply_model_0(at::Tensor& mix, at::Tensor& out, int64_t shifts = 1, bool split = true, double overlap = 0.25, double transition_power = 1., int64_t static_shifts = 1);
|
||||||
|
+ bool _apply_model_1(at::Tensor& mix, at::Tensor& out, int64_t shifts = 1, bool split = true, double overlap = 0.25, double transition_power = 1., int64_t static_shifts = 1);
|
||||||
|
+ bool _apply_model_2(TensorChunk& mix, at::Tensor& out, bool split = true, double overlap = 0.25, double transition_power = 1., int64_t static_shifts = 1);
|
||||||
|
+ bool _apply_model_3(TensorChunk& mix, at::Tensor& out);
|
||||||
|
+ bool _actually_run_model(at::Tensor& mix_tensor, at::Tensor& x);
|
||||||
|
|
||||||
|
int64_t _shifts = 0;
|
||||||
|
int64_t _offsets = 0;
|
||||||
11
patches/openvino-plugins-ai-audacity/musicgen.patch
Normal file
11
patches/openvino-plugins-ai-audacity/musicgen.patch
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
--- mod-openvino/musicgen/music_gen_decoder_cl.cpp.orig 2025-04-24 14:58:41.839354735 +0300
|
||||||
|
+++ mod-openvino/musicgen/music_gen_decoder_cl.cpp 2025-04-24 15:00:48.024587074 +0300
|
||||||
|
@@ -521,7 +521,7 @@
|
||||||
|
{
|
||||||
|
//slice the new key values into the existing past_key_vals buffer using OpenCL.
|
||||||
|
std::array<size_t, 3> srcOrigin = { 0, 0, 0 }; // Start at the beginning of the source buffer
|
||||||
|
- std::array<size_t, 3> dstOrigin = { 0, _past_length, 0 };
|
||||||
|
+ std::array<size_t, 3> dstOrigin = { 0, (unsigned long) _past_length, 0 };
|
||||||
|
|
||||||
|
// Size of one element
|
||||||
|
std::array<size_t, 3> region = { sizeof(ov::float16) * past_key_values_shape[3], 1, past_key_values_shape[0] * past_key_values_shape[1] };
|
||||||
105
patches/openvino-plugins-ai-audacity/paths.patch
Normal file
105
patches/openvino-plugins-ai-audacity/paths.patch
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
diff --color -ruN mod-openvino.orig/OVAudioSR.cpp mod-openvino/OVAudioSR.cpp
|
||||||
|
--- mod-openvino.orig/OVAudioSR.cpp 2025-04-26 15:56:46.861144303 +0300
|
||||||
|
+++ mod-openvino/OVAudioSR.cpp 2025-04-26 16:00:47.323405438 +0300
|
||||||
|
@@ -52,7 +52,7 @@
|
||||||
|
{
|
||||||
|
std::vector<std::string> available_models;
|
||||||
|
|
||||||
|
- auto model_folder = wxFileName(FileNames::BaseDir(), wxT("openvino-models")).GetFullPath();
|
||||||
|
+ auto model_folder = wxFileName(FileNames::DataDir(), wxT("openvino-models")).GetFullPath();
|
||||||
|
model_folder = wxFileName(model_folder, wxT("audiosr")).GetFullPath();
|
||||||
|
|
||||||
|
//make sure that all of the 'base' models are present
|
||||||
|
@@ -607,7 +607,7 @@
|
||||||
|
//todo: Right now we're looking for the model in the 'BaseDir' (which is top-level folder of Audacity install)
|
||||||
|
// This might be okay, but some users may not have permissions to place models there. So, also look in
|
||||||
|
// DataDir(), which is the path to C:\Users\<user>\AppData\Roaming\audacity.
|
||||||
|
- auto model_folder_wx = wxFileName(FileNames::BaseDir(), wxT("openvino-models")).GetFullPath();
|
||||||
|
+ auto model_folder_wx = wxFileName(FileNames::DataDir(), wxT("openvino-models")).GetFullPath();
|
||||||
|
auto model_folder = audacity::ToUTF8(wxFileName(model_folder_wx, wxT("audiosr")).GetFullPath());
|
||||||
|
|
||||||
|
FilePath cache_folder = FileNames::MkDir(wxFileName(FileNames::DataDir(), wxT("openvino-model-cache")).GetFullPath());
|
||||||
|
diff --color -ruN mod-openvino.orig/OVMusicGenerationLLM.cpp mod-openvino/OVMusicGenerationLLM.cpp
|
||||||
|
--- mod-openvino.orig/OVMusicGenerationLLM.cpp 2025-04-26 15:56:46.862479864 +0300
|
||||||
|
+++ mod-openvino/OVMusicGenerationLLM.cpp 2025-04-26 16:00:47.329323234 +0300
|
||||||
|
@@ -70,7 +70,7 @@
|
||||||
|
{
|
||||||
|
std::vector<std::string> available_models;
|
||||||
|
|
||||||
|
- auto model_folder = wxFileName(FileNames::BaseDir(), wxT("openvino-models")).GetFullPath();
|
||||||
|
+ auto model_folder = wxFileName(FileNames::DataDir(), wxT("openvino-models")).GetFullPath();
|
||||||
|
model_folder = wxFileName(model_folder, wxT("musicgen")).GetFullPath();
|
||||||
|
|
||||||
|
//make sure that a couple of the 'base' models, like EnCodec, tokenizer are present.
|
||||||
|
@@ -301,7 +301,7 @@
|
||||||
|
bool bGoodResult = true;
|
||||||
|
|
||||||
|
{
|
||||||
|
- FilePath model_folder = FileNames::MkDir(wxFileName(FileNames::BaseDir(), wxT("openvino-models")).GetFullPath());
|
||||||
|
+ FilePath model_folder = FileNames::MkDir(wxFileName(FileNames::DataDir(), wxT("openvino-models")).GetFullPath());
|
||||||
|
std::string musicgen_model_folder = audacity::ToUTF8(wxFileName(model_folder, wxString("musicgen"))
|
||||||
|
.GetFullPath());
|
||||||
|
|
||||||
|
diff --color -ruN mod-openvino.orig/OVMusicSeparation.cpp mod-openvino/OVMusicSeparation.cpp
|
||||||
|
--- mod-openvino.orig/OVMusicSeparation.cpp 2025-04-26 15:56:46.863791883 +0300
|
||||||
|
+++ mod-openvino/OVMusicSeparation.cpp 2025-04-26 16:00:47.323431730 +0300
|
||||||
|
@@ -254,7 +254,7 @@
|
||||||
|
//todo: Right now we're looking for the model in the 'BaseDir' (which is top-level folder of Audacity install)
|
||||||
|
// This might be okay, but some users may not have permissions to place models there. So, also look in
|
||||||
|
// DataDir(), which is the path to C:\Users\<user>\AppData\Roaming\audacity.
|
||||||
|
- FilePath model_folder = FileNames::MkDir(wxFileName(FileNames::BaseDir(), wxT("openvino-models")).GetFullPath());
|
||||||
|
+ FilePath model_folder = FileNames::MkDir(wxFileName(FileNames::DataDir(), wxT("openvino-models")).GetFullPath());
|
||||||
|
std::string demucs_v4_path = audacity::ToUTF8(wxFileName(model_folder, wxT("htdemucs_v4.xml"))
|
||||||
|
.GetFullPath());
|
||||||
|
|
||||||
|
diff --color -ruN mod-openvino.orig/OVNoiseSuppression.cpp mod-openvino/OVNoiseSuppression.cpp
|
||||||
|
--- mod-openvino.orig/OVNoiseSuppression.cpp 2025-04-26 15:56:46.865271447 +0300
|
||||||
|
+++ mod-openvino/OVNoiseSuppression.cpp 2025-04-26 16:00:47.329279025 +0300
|
||||||
|
@@ -50,7 +50,7 @@
|
||||||
|
|
||||||
|
static bool is_deepfilter_model_present(std::string deepfilter_basename)
|
||||||
|
{
|
||||||
|
- auto model_folder = wxFileName(FileNames::BaseDir(), wxT("openvino-models")).GetFullPath();
|
||||||
|
+ auto model_folder = wxFileName(FileNames::DataDir(), wxT("openvino-models")).GetFullPath();
|
||||||
|
model_folder = wxFileName(model_folder, wxString(deepfilter_basename)).GetFullPath();
|
||||||
|
|
||||||
|
std::vector< std::string > model_basenames = { "enc", "erb_dec", "df_dec" };
|
||||||
|
@@ -77,7 +77,7 @@
|
||||||
|
|
||||||
|
static bool is_omz_model_present(std::string omz_model_basename)
|
||||||
|
{
|
||||||
|
- auto model_folder = wxFileName(FileNames::BaseDir(), wxT("openvino-models")).GetFullPath();
|
||||||
|
+ auto model_folder = wxFileName(FileNames::DataDir(), wxT("openvino-models")).GetFullPath();
|
||||||
|
|
||||||
|
auto binmodelpath = wxFileName(model_folder, wxString(omz_model_basename + ".bin"));
|
||||||
|
auto xmlmodelpath = wxFileName(model_folder, wxString(omz_model_basename + ".xml"));
|
||||||
|
@@ -384,7 +384,7 @@
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//CompileNoiseSuppression(compiledModel);
|
||||||
|
- FilePath model_folder = FileNames::MkDir(wxFileName(FileNames::BaseDir(), wxT("openvino-models")).GetFullPath());
|
||||||
|
+ FilePath model_folder = FileNames::MkDir(wxFileName(FileNames::DataDir(), wxT("openvino-models")).GetFullPath());
|
||||||
|
FilePath cache_folder = FileNames::MkDir(wxFileName(FileNames::DataDir(), wxT("openvino-model-cache")).GetFullPath());
|
||||||
|
std::string cache_path = wstring_to_string(wxFileName(cache_folder).GetFullPath().ToStdWstring());
|
||||||
|
|
||||||
|
diff --color -ruN mod-openvino.orig/OVWhisperTranscription.cpp mod-openvino/OVWhisperTranscription.cpp
|
||||||
|
--- mod-openvino.orig/OVWhisperTranscription.cpp 2025-04-26 15:56:46.867815026 +0300
|
||||||
|
+++ mod-openvino/OVWhisperTranscription.cpp 2025-04-26 16:00:47.323457689 +0300
|
||||||
|
@@ -292,7 +292,7 @@
|
||||||
|
static bool is_whisper_model_present(std::string whisper_basename)
|
||||||
|
{
|
||||||
|
std::cout << "is_whisper_model_present(" << whisper_basename << ")" << std::endl;
|
||||||
|
- auto model_folder = wxFileName(FileNames::BaseDir(), wxT("openvino-models")).GetFullPath();
|
||||||
|
+ auto model_folder = wxFileName(FileNames::DataDir(), wxT("openvino-models")).GetFullPath();
|
||||||
|
|
||||||
|
{
|
||||||
|
std::string ggml_binname = std::string("ggml-") + whisper_basename + std::string(".bin");
|
||||||
|
@@ -877,7 +877,7 @@
|
||||||
|
params.prompt = mInitialPrompt;
|
||||||
|
|
||||||
|
//whisper init
|
||||||
|
- FilePath model_folder = FileNames::MkDir(wxFileName(FileNames::BaseDir(), wxT("openvino-models")).GetFullPath());
|
||||||
|
+ FilePath model_folder = FileNames::MkDir(wxFileName(FileNames::DataDir(), wxT("openvino-models")).GetFullPath());
|
||||||
|
std::string whisper_variant = mSupportedModels[m_modelSelectionChoice];
|
||||||
|
std::string ggml_binname = std::string("ggml-") + whisper_variant + std::string(".bin");
|
||||||
|
std::string whisper_model_path = audacity::ToUTF8(wxFileName(model_folder, wxString(ggml_binname))
|
||||||
179
scripts/build-arm64.sh
Executable file
179
scripts/build-arm64.sh
Executable file
@ -0,0 +1,179 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
brew install opencl-clhpp-headers
|
||||||
|
brew install libomp
|
||||||
|
|
||||||
|
MODULE_VERSION="3.7.1-R4.2"
|
||||||
|
ROOT_DIR=$(pwd)
|
||||||
|
SOURCE_PATH=$(pwd)/sources
|
||||||
|
PACKAGE_PATH=$(pwd)/packages
|
||||||
|
BUILD_PATH=$(pwd)/build
|
||||||
|
STAGING_PATH=$(pwd)/staging
|
||||||
|
|
||||||
|
echo "Applying patches..."
|
||||||
|
|
||||||
|
for repo in $(ls $SOURCE_PATH); do
|
||||||
|
patch_dir=${ROOT_DIR}/patches/$repo
|
||||||
|
if [ -d "$patch_dir" ]; then
|
||||||
|
echo "Applying patches to $repo"
|
||||||
|
for patch in $patch_dir/*.patch; do
|
||||||
|
if [ -f "$patch" ]; then
|
||||||
|
echo "Applying patch $patch"
|
||||||
|
patch -d $SOURCE_PATH/$repo < $patch
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "No patches found for $repo"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
cp -r $SOURCE_PATH/openvino-plugins-ai-audacity/mod-openvino $SOURCE_PATH/audacity/modules
|
||||||
|
|
||||||
|
cd $PACKAGE_PATH
|
||||||
|
wget https://storage.openvinotoolkit.org/repositories/openvino/packages/2024.0/macos/m_openvino_toolkit_macos_11_0_2024.0.0.14509.34caeefd078_arm64.tgz
|
||||||
|
tar xvf m_openvino_toolkit_macos_11_0_2024.0.0.14509.34caeefd078_arm64.tgz
|
||||||
|
source m_openvino_toolkit_macos_11_0_2024.0.0.14509.34caeefd078_arm64/setupvars.sh
|
||||||
|
|
||||||
|
wget https://download.pytorch.org/libtorch/cpu/libtorch-macos-arm64-2.2.2.zip
|
||||||
|
unzip libtorch-macos-arm64-2.2.2.zip
|
||||||
|
export LIBTORCH_ROOTDIR=$PACKAGE_PATH/libtorch
|
||||||
|
|
||||||
|
mkdir -p $BUILD_PATH/whisper
|
||||||
|
cd $BUILD_PATH/whisper
|
||||||
|
cmake $SOURCE_PATH/whisper.cpp -DWHISPER_OPENVINO=ON -DMACOS_ARCHITECTURE=arm64 -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 -DWHISPER_NO_ACCELERATE=ON
|
||||||
|
make -j`sysctl -n hw.ncpu`
|
||||||
|
|
||||||
|
cmake --install . --config Release --prefix $PACKAGE_PATH/whisper
|
||||||
|
export WHISPERCPP_ROOTDIR=$PACKAGE_PATH/whisper
|
||||||
|
export LD_LIBRARY_PATH=${WHISPERCPP_ROOTDIR}/lib:$LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
mkdir -p $BUILD_PATH/openvino_tokenizers
|
||||||
|
cd $BUILD_PATH/openvino_tokenizers
|
||||||
|
cmake $SOURCE_PATH/openvino_tokenizers -DMACOS_ARCHITECTURE=arm64 -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0
|
||||||
|
make -j`sysctl -n hw.ncpu`
|
||||||
|
|
||||||
|
cmake --install . --config Release --prefix $PACKAGE_PATH/openvino_tokenizers
|
||||||
|
|
||||||
|
mkdir -p $BUILD_PATH/audacity
|
||||||
|
cd $BUILD_PATH/audacity
|
||||||
|
|
||||||
|
cmake -G "Unix Makefiles" \
|
||||||
|
-D CMAKE_CXX_FLAGS="-I/opt/homebrew/opt/opencl-clhpp-headers/include" \
|
||||||
|
-DMACOS_ARCHITECTURE=arm64 -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0\
|
||||||
|
$SOURCE_PATH/audacity -DCMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
|
make -j`sysctl -n hw.ncpu`
|
||||||
|
|
||||||
|
mkdir -p $STAGING_PATH
|
||||||
|
cd $STAGING_PATH
|
||||||
|
MODULE_PATH="$STAGING_PATH/dist/Library/Application Support/audacity/modules"
|
||||||
|
|
||||||
|
mkdir -p "$MODULE_PATH/libs"
|
||||||
|
|
||||||
|
cp -p $BUILD_PATH/audacity/Release/Audacity.app/Contents/modules/mod-openvino.so \
|
||||||
|
"$MODULE_PATH"
|
||||||
|
|
||||||
|
cp -p $PACKAGE_PATH/m_openvino_toolkit_macos_11_0_2024.0.0.14509.34caeefd078_arm64/runtime/lib/arm64/Release/*.so \
|
||||||
|
"$MODULE_PATH/libs"
|
||||||
|
cp -p $PACKAGE_PATH/m_openvino_toolkit_macos_11_0_2024.0.0.14509.34caeefd078_arm64/runtime/lib/arm64/Release/*.dylib \
|
||||||
|
"$MODULE_PATH/libs"
|
||||||
|
cp -p $PACKAGE_PATH/m_openvino_toolkit_macos_11_0_2024.0.0.14509.34caeefd078_arm64/runtime/3rdparty/tbb/lib/*.dylib \
|
||||||
|
"$MODULE_PATH/libs"
|
||||||
|
|
||||||
|
cp -p $PACKAGE_PATH/libtorch/lib/libc10.dylib \
|
||||||
|
"$MODULE_PATH/libs"
|
||||||
|
cp -p $PACKAGE_PATH/libtorch/lib/libtorch.dylib \
|
||||||
|
"$MODULE_PATH/libs"
|
||||||
|
cp -p $PACKAGE_PATH/libtorch/lib/libtorch_cpu.dylib \
|
||||||
|
"$MODULE_PATH/libs"
|
||||||
|
|
||||||
|
cp -P $PACKAGE_PATH/whisper/lib/*.dylib \
|
||||||
|
"$MODULE_PATH/libs"
|
||||||
|
|
||||||
|
cp -P $PACKAGE_PATH/openvino_tokenizers/lib/*.dylib \
|
||||||
|
"$MODULE_PATH/libs/"
|
||||||
|
|
||||||
|
cp /opt/homebrew/opt/libomp/lib/libomp.dylib \
|
||||||
|
"$MODULE_PATH/libs/"
|
||||||
|
|
||||||
|
chmod -R ug+w "$MODULE_PATH"
|
||||||
|
|
||||||
|
xattr -cr "$MODULE_PATH"
|
||||||
|
|
||||||
|
# Fix loading paths
|
||||||
|
cd "$MODULE_PATH"
|
||||||
|
for lib in *.so *.dylib; do
|
||||||
|
[ -e "$lib" ] || continue
|
||||||
|
|
||||||
|
echo "Processing $lib..."
|
||||||
|
|
||||||
|
deps=$(otool -L "$lib" | awk 'NR>1 {print $1}' | grep '@loader_path/../Frameworks/')
|
||||||
|
|
||||||
|
for dep in $deps; do
|
||||||
|
|
||||||
|
dep_filename=$(basename "$dep")
|
||||||
|
|
||||||
|
# If we have this file in the libs directory, use it
|
||||||
|
if [[ -f "./libs/$dep_filename" ]]; then
|
||||||
|
new_dep="@rpath/$dep_filename"
|
||||||
|
echo " Updating dependency: $dep → $new_dep"
|
||||||
|
install_name_tool -change "$dep" "$new_dep" "$lib"
|
||||||
|
else
|
||||||
|
# If the file does not exist load it from the Audacity/Frameworks directory
|
||||||
|
new_dep="@executable_path/../Frameworks/$dep_filename"
|
||||||
|
echo " Updating dependency: $dep → $new_dep"
|
||||||
|
install_name_tool -change "$dep" "$new_dep" "$lib"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
install_name_tool -add_rpath @loader_path/libs "$lib"
|
||||||
|
done
|
||||||
|
|
||||||
|
cd $ROOT_DIR
|
||||||
|
cp -r installer/* "$STAGING_PATH"
|
||||||
|
|
||||||
|
sudo xcode-select -s /Applications/Xcode_16.2.app
|
||||||
|
|
||||||
|
PROJECT="tools/ResourceDownloader/ResourceDownloader.xcodeproj"
|
||||||
|
SCHEME="ResourceDownloader"
|
||||||
|
CONFIG="Release"
|
||||||
|
BUILD_DIR="build"
|
||||||
|
|
||||||
|
xcodebuild \
|
||||||
|
-project "$PROJECT" \
|
||||||
|
-scheme "$SCHEME" \
|
||||||
|
-configuration "$CONFIG" \
|
||||||
|
-derivedDataPath "$BUILD_DIR" \
|
||||||
|
clean build
|
||||||
|
|
||||||
|
APP_PATH="$BUILD_DIR/Build/Products/$CONFIG/$SCHEME.app"
|
||||||
|
|
||||||
|
# codesign --verbose --timestamp --identifier "org.audacityteam.resourcedownloader" --sign "${APPLE_CODESIGN_IDENTITY}" "$APP_PATH"
|
||||||
|
|
||||||
|
cp -R "$APP_PATH" "$STAGING_PATH/Scripts"
|
||||||
|
|
||||||
|
cd "$STAGING_PATH"
|
||||||
|
mkdir -p packages
|
||||||
|
|
||||||
|
pkgbuild \
|
||||||
|
--root dist \
|
||||||
|
--scripts Scripts \
|
||||||
|
--install-location / \
|
||||||
|
--identifier org.audacityteam.audacity \
|
||||||
|
--version "$MODULE_VERSION" \
|
||||||
|
packages/openvino-module.pkg
|
||||||
|
|
||||||
|
# productsign --sign "${APPLE_CODESIGN_IDENTITY}" packages/openvino-module.pkg packages/openvino-module.pkg
|
||||||
|
|
||||||
|
productbuild --distribution distribution.xml \
|
||||||
|
--resources Resources \
|
||||||
|
--package-path ./packages \
|
||||||
|
./Audacity-OpenVINO.pkg
|
||||||
|
|
||||||
|
# productsign --sign "${APPLE_CODESIGN_IDENTITY}" final.pkg final.pkg
|
||||||
|
|
||||||
|
echo "Done."
|
||||||
67
scripts/postinstall
Executable file
67
scripts/postinstall
Executable file
@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# This script runs after the installation
|
||||||
|
# It updates the Audacity configuration file to enable the OpenVINO module
|
||||||
|
|
||||||
|
MODULE_NAME="mod-openvino"
|
||||||
|
MODULE_PATH="/Library/Application Support/audacity/modules/${MODULE_NAME}.so"
|
||||||
|
MODULE_DATETIME=$(stat -f "%m" "$MODULE_PATH" | xargs -I{} date -r {} +"%Y-%m-%dT%H:%M:%S")
|
||||||
|
|
||||||
|
update_config_section() {
|
||||||
|
|
||||||
|
local cfg_file="$1"
|
||||||
|
local section="$2"
|
||||||
|
local key="$3"
|
||||||
|
local value="$4"
|
||||||
|
local tmp_file="${cfg_file}.tmp"
|
||||||
|
original_owner=$(stat -f "%u" "$cfg_file")
|
||||||
|
original_group=$(stat -f "%g" "$cfg_file")
|
||||||
|
|
||||||
|
awk -v section="$section" -v key="$key" -v value="$value" '
|
||||||
|
BEGIN {
|
||||||
|
found_section = 0
|
||||||
|
found_key = 0
|
||||||
|
}
|
||||||
|
$0 == "[" section "]" {
|
||||||
|
found_section = 1
|
||||||
|
print
|
||||||
|
next
|
||||||
|
}
|
||||||
|
found_section && $0 ~ "^" key{
|
||||||
|
print key "=" value
|
||||||
|
found_key = 1
|
||||||
|
found_section = 0
|
||||||
|
next
|
||||||
|
}
|
||||||
|
found_section && !found_key && /^\[.*\]/ {
|
||||||
|
print key "=" value
|
||||||
|
found_key = 1
|
||||||
|
found_section = 0
|
||||||
|
}
|
||||||
|
{ print }
|
||||||
|
END { }
|
||||||
|
' "$cfg_file" > "$tmp_file" && mv "$tmp_file" "$cfg_file"
|
||||||
|
chown "$original_owner":"$original_group" "$cfg_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Loop through all user home directories in /Users (excluding system users)
|
||||||
|
for USER_HOME in /Users/*; do
|
||||||
|
# Only act on real user dirs
|
||||||
|
[ -d "$USER_HOME" ] || continue
|
||||||
|
[ -f "$USER_HOME/.zshrc" ] || [ -f "$USER_HOME/.bash_profile" ] || continue
|
||||||
|
|
||||||
|
CFG_PATH="$USER_HOME/Library/Application Support/audacity/audacity.cfg"
|
||||||
|
CFG_PATH1="$USER_HOME/Library/Application Support/audacity/_audacity.cfg"
|
||||||
|
|
||||||
|
# Skip if the config doesn't exist
|
||||||
|
[ -f "$CFG_PATH" ] || continue
|
||||||
|
|
||||||
|
echo "Updating $CFG_PATH"
|
||||||
|
|
||||||
|
update_config_section "$CFG_PATH" "Module" "mod-openvino" "1"
|
||||||
|
update_config_section "$CFG_PATH" "ModuleDateTime" "mod-openvino" "$MODULE_DATETIME"
|
||||||
|
update_config_section "$CFG_PATH" "ModulePath" "mod-openvino" "$MODULE_PATH"
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
58
scripts/prepare-build.sh
Executable file
58
scripts/prepare-build.sh
Executable file
@ -0,0 +1,58 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
ROOT_DIR=$(pwd)
|
||||||
|
SOURCE_PATH=$(pwd)/sources
|
||||||
|
PACKAGE_PATH=$(pwd)/packages
|
||||||
|
BUILD_PATH=$(pwd)/build
|
||||||
|
|
||||||
|
function download_release {
|
||||||
|
cd $SOURCE_PATH
|
||||||
|
local repo=$1
|
||||||
|
local release=${2:+tags/$2}
|
||||||
|
release=${release:-latest}
|
||||||
|
local target_dir=$(basename $repo)
|
||||||
|
echo Downloading ${release} release of $repo into $target_dir
|
||||||
|
mkdir -p $target_dir
|
||||||
|
curl -sL https://api.github.com/repos/${repo}/releases/${release}
|
||||||
|
wget -O ${target_dir}/archive.tar.gz $(wget -q -O - https://api.github.com/repos/${repo}/releases/${release} | jq -r '.tarball_url')
|
||||||
|
tar --strip-components=1 -xzf ${target_dir}/archive.tar.gz -C $target_dir
|
||||||
|
rm -f ${target_dir}/archive.tar.gz
|
||||||
|
cd $ROOT_DIR
|
||||||
|
}
|
||||||
|
|
||||||
|
function download_tarball {
|
||||||
|
cd "$SOURCE_PATH" || exit 1
|
||||||
|
local repo=$1
|
||||||
|
local url=$2
|
||||||
|
local target_dir=$(basename "$repo")
|
||||||
|
echo "Downloading from $url into $target_dir"
|
||||||
|
mkdir -p "$target_dir"
|
||||||
|
|
||||||
|
wget -O "${target_dir}/archive.tar.gz" "$url"
|
||||||
|
tar --strip-components=1 -xzf "${target_dir}/archive.tar.gz" -C "$target_dir"
|
||||||
|
rm -f "${target_dir}/archive.tar.gz"
|
||||||
|
cd "$ROOT_DIR" || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Cleaning build directory..."
|
||||||
|
rm -rf $PACKAGE_PATH
|
||||||
|
rm -rf $BUILD_PATH
|
||||||
|
rm -rf $SOURCE_PATH
|
||||||
|
|
||||||
|
mkdir -p $PACKAGE_PATH
|
||||||
|
mkdir -p $BUILD_PATH
|
||||||
|
mkdir -p $SOURCE_PATH
|
||||||
|
|
||||||
|
# download dependencies
|
||||||
|
# download_release "audacity/audacity"
|
||||||
|
# download_release "intel/openvino-plugins-ai-audacity"
|
||||||
|
# download_release "ggerganov/whisper.cpp" "v1.6.0"
|
||||||
|
# download_release "openvinotoolkit/openvino_tokenizers" "2024.0.0.0"
|
||||||
|
|
||||||
|
download_tarball "audacity/audacity" "https://github.com/audacity/audacity/archive/refs/tags/Audacity-3.7.3.tar.gz"
|
||||||
|
download_tarball "intel/openvino-plugins-ai-audacity" "https://github.com/intel/openvino-plugins-ai-audacity/archive/refs/tags/v3.7.1-R4.2.tar.gz"
|
||||||
|
download_tarball "ggerganov/whisper.cpp" "https://github.com/ggml-org/whisper.cpp/archive/refs/tags/v1.6.0.tar.gz"
|
||||||
|
download_tarball "openvinotoolkit/openvino_tokenizers" "https://github.com/openvinotoolkit/openvino_tokenizers/archive/refs/tags/2024.0.0.0.tar.gz"
|
||||||
@ -0,0 +1,538 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 56;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
0A2E72612DBFC63900F87746 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 0A2E724A2DBFC63800F87746 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 0A2E72512DBFC63800F87746;
|
||||||
|
remoteInfo = ResourceDownloader;
|
||||||
|
};
|
||||||
|
0A2E726B2DBFC63900F87746 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 0A2E724A2DBFC63800F87746 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 0A2E72512DBFC63800F87746;
|
||||||
|
remoteInfo = ResourceDownloader;
|
||||||
|
};
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
0A2E72522DBFC63800F87746 /* ResourceDownloader.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ResourceDownloader.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
0A2E72602DBFC63900F87746 /* ResourceDownloaderTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ResourceDownloaderTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
0A2E726A2DBFC63900F87746 /* ResourceDownloaderUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ResourceDownloaderUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
0A2E72542DBFC63800F87746 /* ResourceDownloader */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = ResourceDownloader; sourceTree = "<group>"; };
|
||||||
|
0A2E72632DBFC63900F87746 /* ResourceDownloaderTests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = ResourceDownloaderTests; sourceTree = "<group>"; };
|
||||||
|
0A2E726D2DBFC63900F87746 /* ResourceDownloaderUITests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = ResourceDownloaderUITests; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
0A2E724F2DBFC63800F87746 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
0A2E725D2DBFC63900F87746 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
0A2E72672DBFC63900F87746 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
0A2E72492DBFC63800F87746 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0A2E72542DBFC63800F87746 /* ResourceDownloader */,
|
||||||
|
0A2E72632DBFC63900F87746 /* ResourceDownloaderTests */,
|
||||||
|
0A2E726D2DBFC63900F87746 /* ResourceDownloaderUITests */,
|
||||||
|
0A2E72532DBFC63800F87746 /* Products */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
0A2E72532DBFC63800F87746 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0A2E72522DBFC63800F87746 /* ResourceDownloader.app */,
|
||||||
|
0A2E72602DBFC63900F87746 /* ResourceDownloaderTests.xctest */,
|
||||||
|
0A2E726A2DBFC63900F87746 /* ResourceDownloaderUITests.xctest */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
0A2E72512DBFC63800F87746 /* ResourceDownloader */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 0A2E72742DBFC63900F87746 /* Build configuration list for PBXNativeTarget "ResourceDownloader" */;
|
||||||
|
buildPhases = (
|
||||||
|
0A2E724E2DBFC63800F87746 /* Sources */,
|
||||||
|
0A2E724F2DBFC63800F87746 /* Frameworks */,
|
||||||
|
0A2E72502DBFC63800F87746 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
fileSystemSynchronizedGroups = (
|
||||||
|
0A2E72542DBFC63800F87746 /* ResourceDownloader */,
|
||||||
|
);
|
||||||
|
name = ResourceDownloader;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = ResourceDownloader;
|
||||||
|
productReference = 0A2E72522DBFC63800F87746 /* ResourceDownloader.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
0A2E725F2DBFC63900F87746 /* ResourceDownloaderTests */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 0A2E72772DBFC63900F87746 /* Build configuration list for PBXNativeTarget "ResourceDownloaderTests" */;
|
||||||
|
buildPhases = (
|
||||||
|
0A2E725C2DBFC63900F87746 /* Sources */,
|
||||||
|
0A2E725D2DBFC63900F87746 /* Frameworks */,
|
||||||
|
0A2E725E2DBFC63900F87746 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
0A2E72622DBFC63900F87746 /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
fileSystemSynchronizedGroups = (
|
||||||
|
0A2E72632DBFC63900F87746 /* ResourceDownloaderTests */,
|
||||||
|
);
|
||||||
|
name = ResourceDownloaderTests;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = ResourceDownloaderTests;
|
||||||
|
productReference = 0A2E72602DBFC63900F87746 /* ResourceDownloaderTests.xctest */;
|
||||||
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
|
};
|
||||||
|
0A2E72692DBFC63900F87746 /* ResourceDownloaderUITests */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 0A2E727A2DBFC63900F87746 /* Build configuration list for PBXNativeTarget "ResourceDownloaderUITests" */;
|
||||||
|
buildPhases = (
|
||||||
|
0A2E72662DBFC63900F87746 /* Sources */,
|
||||||
|
0A2E72672DBFC63900F87746 /* Frameworks */,
|
||||||
|
0A2E72682DBFC63900F87746 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
0A2E726C2DBFC63900F87746 /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
fileSystemSynchronizedGroups = (
|
||||||
|
0A2E726D2DBFC63900F87746 /* ResourceDownloaderUITests */,
|
||||||
|
);
|
||||||
|
name = ResourceDownloaderUITests;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = ResourceDownloaderUITests;
|
||||||
|
productReference = 0A2E726A2DBFC63900F87746 /* ResourceDownloaderUITests.xctest */;
|
||||||
|
productType = "com.apple.product-type.bundle.ui-testing";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
0A2E724A2DBFC63800F87746 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
BuildIndependentTargetsInParallel = 1;
|
||||||
|
LastSwiftUpdateCheck = 1630;
|
||||||
|
LastUpgradeCheck = 1630;
|
||||||
|
TargetAttributes = {
|
||||||
|
0A2E72512DBFC63800F87746 = {
|
||||||
|
CreatedOnToolsVersion = 16.3;
|
||||||
|
};
|
||||||
|
0A2E725F2DBFC63900F87746 = {
|
||||||
|
CreatedOnToolsVersion = 16.3;
|
||||||
|
TestTargetID = 0A2E72512DBFC63800F87746;
|
||||||
|
};
|
||||||
|
0A2E72692DBFC63900F87746 = {
|
||||||
|
CreatedOnToolsVersion = 16.3;
|
||||||
|
TestTargetID = 0A2E72512DBFC63800F87746;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 0A2E724D2DBFC63800F87746 /* Build configuration list for PBXProject "ResourceDownloader" */;
|
||||||
|
compatibilityVersion = "Xcode 12.0";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 0A2E72492DBFC63800F87746;
|
||||||
|
minimizedProjectReferenceProxies = 1;
|
||||||
|
productRefGroup = 0A2E72532DBFC63800F87746 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
0A2E72512DBFC63800F87746 /* ResourceDownloader */,
|
||||||
|
0A2E725F2DBFC63900F87746 /* ResourceDownloaderTests */,
|
||||||
|
0A2E72692DBFC63900F87746 /* ResourceDownloaderUITests */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
0A2E72502DBFC63800F87746 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
0A2E725E2DBFC63900F87746 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
0A2E72682DBFC63900F87746 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
0A2E724E2DBFC63800F87746 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
0A2E725C2DBFC63900F87746 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
0A2E72662DBFC63900F87746 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
0A2E72622DBFC63900F87746 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 0A2E72512DBFC63800F87746 /* ResourceDownloader */;
|
||||||
|
targetProxy = 0A2E72612DBFC63900F87746 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
0A2E726C2DBFC63900F87746 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 0A2E72512DBFC63800F87746 /* ResourceDownloader */;
|
||||||
|
targetProxy = 0A2E726B2DBFC63900F87746 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
0A2E72722DBFC63900F87746 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 15.2;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
0A2E72732DBFC63900F87746 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 15.2;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
0A2E72752DBFC63900F87746 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = ResourceDownloader/ResourceDownloader.entitlements;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
ENABLE_PREVIEWS = YES;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/../Frameworks",
|
||||||
|
);
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.audacity.ResourceDownloader;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
REGISTER_APP_GROUPS = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
0A2E72762DBFC63900F87746 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = ResourceDownloader/ResourceDownloader.entitlements;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
ENABLE_PREVIEWS = YES;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/../Frameworks",
|
||||||
|
);
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.audacity.ResourceDownloader;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
REGISTER_APP_GROUPS = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
0A2E72782DBFC63900F87746 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 15.2;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.audacity.ResourceDownloaderTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ResourceDownloader.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/ResourceDownloader";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
0A2E72792DBFC63900F87746 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 15.2;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.audacity.ResourceDownloaderTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ResourceDownloader.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/ResourceDownloader";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
0A2E727B2DBFC63900F87746 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.audacity.ResourceDownloaderUITests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_TARGET_NAME = ResourceDownloader;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
0A2E727C2DBFC63900F87746 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.audacity.ResourceDownloaderUITests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_TARGET_NAME = ResourceDownloader;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
0A2E724D2DBFC63800F87746 /* Build configuration list for PBXProject "ResourceDownloader" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
0A2E72722DBFC63900F87746 /* Debug */,
|
||||||
|
0A2E72732DBFC63900F87746 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
0A2E72742DBFC63900F87746 /* Build configuration list for PBXNativeTarget "ResourceDownloader" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
0A2E72752DBFC63900F87746 /* Debug */,
|
||||||
|
0A2E72762DBFC63900F87746 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
0A2E72772DBFC63900F87746 /* Build configuration list for PBXNativeTarget "ResourceDownloaderTests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
0A2E72782DBFC63900F87746 /* Debug */,
|
||||||
|
0A2E72792DBFC63900F87746 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
0A2E727A2DBFC63900F87746 /* Build configuration list for PBXNativeTarget "ResourceDownloaderUITests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
0A2E727B2DBFC63900F87746 /* Debug */,
|
||||||
|
0A2E727C2DBFC63900F87746 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 0A2E724A2DBFC63800F87746 /* Project object */;
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "512x512"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "512x512"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.app-sandbox</key>
|
||||||
|
<false/>
|
||||||
|
<key>com.apple.security.files.user-selected.read-only</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.network.client</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@ -0,0 +1,591 @@
|
|||||||
|
import SwiftUI
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
struct Resource: Identifiable {
|
||||||
|
var id: UUID = UUID()
|
||||||
|
var name: String
|
||||||
|
var urls: [String] = []
|
||||||
|
}
|
||||||
|
|
||||||
|
class ModelStore: ObservableObject {
|
||||||
|
@Published var nodes: [Node] = []
|
||||||
|
|
||||||
|
var selectedItems: [Node] {
|
||||||
|
nodes.flatMap { $0.selectedItems }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct TreeTableApp: App {
|
||||||
|
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
||||||
|
@StateObject private var modelStore = ModelStore()
|
||||||
|
@State private var currentView = CurrentScreen.welcome
|
||||||
|
var body: some Scene {
|
||||||
|
WindowGroup {
|
||||||
|
switch currentView {
|
||||||
|
case .welcome:
|
||||||
|
WelcomeView(onContinue: {
|
||||||
|
modelStore.nodes = loadNodesFromJSON(named: "models")
|
||||||
|
currentView = .selection
|
||||||
|
})
|
||||||
|
case .selection:
|
||||||
|
ContentView(
|
||||||
|
modelStore: modelStore,
|
||||||
|
onBack: {
|
||||||
|
currentView = .welcome
|
||||||
|
},
|
||||||
|
onContinue: {
|
||||||
|
currentView = .download
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.frame(width: 500, height: 400)
|
||||||
|
.onAppear() {
|
||||||
|
if let window = NSApplication.shared.windows.first {
|
||||||
|
window.center()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .download:
|
||||||
|
DownloadView(currentView: $currentView, items: modelStore.selectedItems)
|
||||||
|
.frame(width: 500, height: 400)
|
||||||
|
case .conclusion:
|
||||||
|
CompletionView()
|
||||||
|
.frame(width: 500, height: 400)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
|
||||||
|
func applicationDidFinishLaunching(_ notification: Notification) {
|
||||||
|
if let window = NSApplication.shared.windows.first {
|
||||||
|
window.delegate = self
|
||||||
|
window.setContentSize(NSSize(width: 500, height: 400))
|
||||||
|
window.center()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func windowWillClose(_ notification: Notification) {
|
||||||
|
NSApp.terminate(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CurrentScreen {
|
||||||
|
case welcome
|
||||||
|
case selection
|
||||||
|
case download
|
||||||
|
case conclusion
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WelcomeView: View {
|
||||||
|
var onContinue: () -> Void
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(spacing: 20) {
|
||||||
|
Image(systemName: "sparkles")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 80, height: 80)
|
||||||
|
.foregroundColor(.accentColor)
|
||||||
|
|
||||||
|
Text("Welcome to the Setup Wizard")
|
||||||
|
.font(.title)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
|
||||||
|
Text("This wizard will help you configure and launch OpenVINO in Audacity.")
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
.padding()
|
||||||
|
|
||||||
|
Button("Continue") {
|
||||||
|
onContinue()
|
||||||
|
}
|
||||||
|
.buttonStyle(.borderedProminent)
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
.frame(width: 400, height: 300)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CheckState {
|
||||||
|
case checked
|
||||||
|
case unchecked
|
||||||
|
case mixed
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FileInfo: Codable {
|
||||||
|
let url: String
|
||||||
|
let sha256: String
|
||||||
|
let dsize: Int
|
||||||
|
let esize: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class Node: Identifiable, ObservableObject, Decodable {
|
||||||
|
let id = UUID()
|
||||||
|
let name: String
|
||||||
|
let description: String
|
||||||
|
let dir: String
|
||||||
|
let files: [FileInfo]
|
||||||
|
|
||||||
|
@Published var state: CheckState = .unchecked
|
||||||
|
@Published var children: [Node]?
|
||||||
|
weak var parent: Node?
|
||||||
|
|
||||||
|
var downloadSizeRecursive: Int {
|
||||||
|
let ownSize = files.map { $0.dsize }.reduce(0, +)
|
||||||
|
let childSize = (children ?? [])
|
||||||
|
.filter { $0.state == .checked }
|
||||||
|
.map { $0.downloadSize }
|
||||||
|
.reduce(0, +)
|
||||||
|
return ownSize + childSize
|
||||||
|
}
|
||||||
|
|
||||||
|
var extractedSizeRecursive: Int {
|
||||||
|
let ownSize = files.map { $0.esize }.reduce(0, +)
|
||||||
|
let childSize = (children ?? [])
|
||||||
|
.filter { $0.state == .checked }
|
||||||
|
.map { $0.extractedSize }
|
||||||
|
.reduce(0, +)
|
||||||
|
return ownSize + childSize
|
||||||
|
}
|
||||||
|
|
||||||
|
var downloadSize: Int {
|
||||||
|
return files.map { $0.dsize }.reduce(0, +)
|
||||||
|
}
|
||||||
|
|
||||||
|
var extractedSize: Int {
|
||||||
|
return files.map { $0.esize }.reduce(0, +)
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedItems: [Node] {
|
||||||
|
var results: [Node] = []
|
||||||
|
|
||||||
|
if state != .unchecked {
|
||||||
|
results.append(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
for child in children ?? [] {
|
||||||
|
results.append(contentsOf: child.selectedItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CodingKeys: CodingKey {
|
||||||
|
case name, description, dir, files, children
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
self.name = try container.decode(String.self, forKey: .name)
|
||||||
|
self.description = try container.decode(String.self, forKey: .description)
|
||||||
|
self.dir = try container.decode(String.self, forKey: .dir)
|
||||||
|
self.files = try container.decodeIfPresent([FileInfo].self, forKey: .files) ?? []
|
||||||
|
self.children = try container.decodeIfPresent([Node].self, forKey: .children)
|
||||||
|
|
||||||
|
self.children?.forEach { $0.parent = self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ContentView: View {
|
||||||
|
@ObservedObject var modelStore: ModelStore
|
||||||
|
@StateObject var viewModel = TreeViewModel()
|
||||||
|
|
||||||
|
var onBack: () -> Void
|
||||||
|
var onContinue: () -> Void
|
||||||
|
|
||||||
|
init(modelStore: ModelStore, onBack: @escaping () -> Void, onContinue: @escaping () -> Void) {
|
||||||
|
self.modelStore = modelStore
|
||||||
|
self.onBack = onBack
|
||||||
|
self.onContinue = onContinue
|
||||||
|
_viewModel = StateObject(wrappedValue: TreeViewModel(nodes: modelStore.nodes))
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(spacing: 0) {
|
||||||
|
List {
|
||||||
|
OutlineGroup(viewModel.nodes, id: \.id, children: \.children) { node in
|
||||||
|
CheckboxView(node: node)
|
||||||
|
.onTapGesture { viewModel.toggle(node: node) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.listStyle(.bordered(alternatesRowBackgrounds: false))
|
||||||
|
|
||||||
|
Divider()
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
SizeInfoView(
|
||||||
|
label: "Total Download Size:",
|
||||||
|
size: viewModel.totalDownloadSize
|
||||||
|
)
|
||||||
|
SizeInfoView(
|
||||||
|
label: "Total Extracted Size:",
|
||||||
|
size: viewModel.totalExtractedSize
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
Button("Download selected", systemImage: "arrow.down.to.line") {
|
||||||
|
onContinue()
|
||||||
|
}
|
||||||
|
.buttonStyle(.borderedProminent)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
.navigationTitle("Download Wizard")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CheckboxView: View {
|
||||||
|
@ObservedObject var node: Node
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: systemImageName)
|
||||||
|
.foregroundColor(node.state == .checked ? .blue : .primary)
|
||||||
|
Text(node.name)
|
||||||
|
.font(.body)
|
||||||
|
}
|
||||||
|
HStack(spacing: 16) {
|
||||||
|
Text("Download: \(node.downloadSizeRecursive.formatted(.byteCount(style: .file)))")
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
Text("Extracted: \(node.extractedSizeRecursive.formatted(.byteCount(style: .file)))")
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
.font(.caption)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.leading, node.children != nil ? 0 : 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var systemImageName: String {
|
||||||
|
switch node.state {
|
||||||
|
case .checked: return "checkmark.square.fill"
|
||||||
|
case .unchecked: return "square"
|
||||||
|
case .mixed: return "minus.square.fill"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SizeInfoView: View {
|
||||||
|
let label: String
|
||||||
|
let size: Int
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text(label)
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
Text(size.formatted(.byteCount(style: .file)))
|
||||||
|
.font(.system(.body, design: .monospaced))
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.padding(8)
|
||||||
|
.background(RoundedRectangle(cornerRadius: 8).fill(Color(nsColor: .controlBackgroundColor)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TreeViewModel: ObservableObject {
|
||||||
|
|
||||||
|
@Published var nodes: [Node]
|
||||||
|
|
||||||
|
@Published var totalDownloadSize = 0
|
||||||
|
@Published var totalExtractedSize = 0
|
||||||
|
|
||||||
|
init(nodes: [Node] = []) {
|
||||||
|
self.nodes = nodes
|
||||||
|
self.totalDownloadSize = totalDownloadSize
|
||||||
|
self.totalExtractedSize = totalExtractedSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func toggle(node: Node) {
|
||||||
|
let newState: CheckState = node.state == .checked ? .unchecked : .checked
|
||||||
|
node.state = newState
|
||||||
|
updateChildren(node: node, state: newState)
|
||||||
|
updateParentState(node.parent)
|
||||||
|
calculateTotals()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func calculateTotals() {
|
||||||
|
totalDownloadSize = calculateTotal(for: \.downloadSizeRecursive)
|
||||||
|
totalExtractedSize = calculateTotal(for: \.extractedSizeRecursive)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateChildren(node: Node, state: CheckState) {
|
||||||
|
node.children?.forEach {
|
||||||
|
$0.state = state
|
||||||
|
updateChildren(node: $0, state: state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateParentState(_ parent: Node?) {
|
||||||
|
guard let parent = parent else { return }
|
||||||
|
|
||||||
|
let childrenStates = parent.children?.map { $0.state } ?? []
|
||||||
|
let allChecked = childrenStates.allSatisfy { $0 == .checked }
|
||||||
|
let allUnchecked = childrenStates.allSatisfy { $0 == .unchecked }
|
||||||
|
|
||||||
|
parent.state = allChecked ? .checked :
|
||||||
|
allUnchecked ? .unchecked : .mixed
|
||||||
|
|
||||||
|
updateParentState(parent.parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func calculateTotal(for keyPath: KeyPath<Node, Int>) -> Int {
|
||||||
|
var total = 0
|
||||||
|
for node in nodes {
|
||||||
|
if node.state != .unchecked {
|
||||||
|
total += node[keyPath: keyPath]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func loadNodesFromJSON(named filename: String) -> [Node] {
|
||||||
|
guard let url = Bundle.main.url(forResource: filename, withExtension: "json") else {
|
||||||
|
fatalError("Unable to find \(filename).json in bundle.")
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
let data = try Data(contentsOf: url)
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
return try decoder.decode([Node].self, from: data)
|
||||||
|
} catch {
|
||||||
|
print("Tried to load from: \(url)")
|
||||||
|
print("Error: \(error)")
|
||||||
|
fatalError("Failed to load or decode \(filename).json: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DownloadItem: Identifiable {
|
||||||
|
let id = UUID()
|
||||||
|
let item: Node
|
||||||
|
var progress: Double = 0.0
|
||||||
|
var isDownloading = false
|
||||||
|
var isCompleted = false
|
||||||
|
}
|
||||||
|
|
||||||
|
class DownloadManager: ObservableObject {
|
||||||
|
@Published var items: [DownloadItem]
|
||||||
|
@Published var currentDownloadItem: DownloadItem?
|
||||||
|
@Published var completedItems = 0 {
|
||||||
|
didSet {
|
||||||
|
if completedItems == items.count {
|
||||||
|
isFinished = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Published var isFinished: Bool
|
||||||
|
|
||||||
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
init(items: [Node]) {
|
||||||
|
self.items = items.map { DownloadItem(item: $0) }
|
||||||
|
self.isFinished = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func startDownloads() {
|
||||||
|
processNextDownload()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func processNextDownload() {
|
||||||
|
guard let nextItem = items.first(where: { !$0.isCompleted && !$0.isDownloading }) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard !nextItem.item.files.isEmpty else {
|
||||||
|
if let index = items.firstIndex(where: { $0.id == nextItem.id }) {
|
||||||
|
items[index].isCompleted = true
|
||||||
|
}
|
||||||
|
processNextDownload()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentItem = nextItem
|
||||||
|
currentItem.isDownloading = true
|
||||||
|
if let index = items.firstIndex(where: { $0.id == currentItem.id }) {
|
||||||
|
items[index] = currentItem
|
||||||
|
}
|
||||||
|
currentDownloadItem = currentItem
|
||||||
|
|
||||||
|
for file in currentItem.item.files {
|
||||||
|
let url = URL(string: file.url)!
|
||||||
|
let request = URLRequest(url: url)
|
||||||
|
let session = URLSession.shared
|
||||||
|
let task = session.downloadTask(with: request) { [weak self] tempURL, response, error in
|
||||||
|
guard let self = self, let tempURL = tempURL else { return }
|
||||||
|
|
||||||
|
|
||||||
|
let homeDirectory = FileManager.default.homeDirectoryForCurrentUser
|
||||||
|
var destinationDir = homeDirectory.appendingPathComponent("Library/Application Support/audacity/openvino-models")
|
||||||
|
|
||||||
|
destinationDir = destinationDir.appendingPathComponent(currentItem.item.dir, isDirectory: true)
|
||||||
|
do {
|
||||||
|
// Create the directory if it doesn't exist
|
||||||
|
try FileManager.default.createDirectory(at: destinationDir, withIntermediateDirectories: true)
|
||||||
|
print("Directory created or already exists at: \(destinationDir.path)")
|
||||||
|
} catch {
|
||||||
|
print("Failed to create directory: \(error)")
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
try FileManager.default.createDirectory(at: destinationDir, withIntermediateDirectories: true)
|
||||||
|
|
||||||
|
let filename = url.lastPathComponent
|
||||||
|
let destinationPath = destinationDir.appendingPathComponent(filename)
|
||||||
|
|
||||||
|
// Move downloaded file to destination
|
||||||
|
try FileManager.default.moveItem(at: tempURL, to: destinationPath)
|
||||||
|
|
||||||
|
// Extract based on file extension
|
||||||
|
if filename.hasSuffix(".zip") {
|
||||||
|
let unzipTask = Process()
|
||||||
|
unzipTask.executableURL = URL(fileURLWithPath: "/usr/bin/unzip")
|
||||||
|
unzipTask.arguments = ["-o", destinationPath.path, "-d", destinationDir.path]
|
||||||
|
try unzipTask.run()
|
||||||
|
unzipTask.waitUntilExit()
|
||||||
|
try FileManager.default.removeItem(at: destinationPath)
|
||||||
|
} else if filename.hasSuffix(".tar.gz") {
|
||||||
|
let tarTask = Process()
|
||||||
|
tarTask.executableURL = URL(fileURLWithPath: "/usr/bin/tar")
|
||||||
|
tarTask.arguments = ["-xzf", destinationPath.path, "-C", destinationDir.path]
|
||||||
|
try tarTask.run()
|
||||||
|
tarTask.waitUntilExit()
|
||||||
|
try FileManager.default.removeItem(at: destinationPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
print("Error during file handling: \(error)")
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if let index = self.items.firstIndex(where: { $0.id == currentItem.id }) {
|
||||||
|
self.items[index].isDownloading = false
|
||||||
|
self.items[index].isCompleted = true
|
||||||
|
self.completedItems += 1
|
||||||
|
self.currentDownloadItem = nil
|
||||||
|
self.processNextDownload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let progressObserver = task.progress.observe(\.fractionCompleted) { [weak self] progress, _ in
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if let index = self?.items.firstIndex(where: { $0.id == currentItem.id }) {
|
||||||
|
self?.items[index].progress = progress.fractionCompleted
|
||||||
|
self?.currentDownloadItem = self?.items[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancellables.insert(AnyCancellable {
|
||||||
|
progressObserver.invalidate()
|
||||||
|
})
|
||||||
|
|
||||||
|
task.resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DownloadView: View {
|
||||||
|
@Binding var currentView: CurrentScreen
|
||||||
|
@StateObject private var downloadManager: DownloadManager
|
||||||
|
private let totalItems: Int
|
||||||
|
var buttonText: String {
|
||||||
|
downloadManager.completedItems == totalItems ? "Finish" : "Cancel"
|
||||||
|
}
|
||||||
|
|
||||||
|
init(currentView: Binding<CurrentScreen>, items: [Node]) {
|
||||||
|
_currentView = currentView
|
||||||
|
_downloadManager = StateObject(wrappedValue: DownloadManager(items: items))
|
||||||
|
totalItems = items.count
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(spacing: 20) {
|
||||||
|
// Overall progress
|
||||||
|
VStack {
|
||||||
|
Text("Total Progress")
|
||||||
|
.font(.headline)
|
||||||
|
ProgressView(value: Double(downloadManager.completedItems), total: Double(totalItems))
|
||||||
|
Text("\(downloadManager.completedItems)/\(totalItems) items downloaded")
|
||||||
|
.font(.caption)
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
|
||||||
|
// Current item progress
|
||||||
|
if let currentItem = downloadManager.currentDownloadItem {
|
||||||
|
VStack {
|
||||||
|
let itemName = currentItem.item
|
||||||
|
let label = itemName.parent != nil
|
||||||
|
? "Downloading: \(itemName.parent!.name): \(itemName.name)"
|
||||||
|
: "Downloading: \(itemName.name)"
|
||||||
|
|
||||||
|
Text(label)
|
||||||
|
.font(.headline)
|
||||||
|
ProgressView(value: currentItem.progress)
|
||||||
|
Text("\(Int(currentItem.progress * 100))% complete")
|
||||||
|
.font(.caption)
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
.transition(.opacity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
.onAppear {
|
||||||
|
downloadManager.startDownloads()
|
||||||
|
}
|
||||||
|
.onChange(of: downloadManager.isFinished) { finished in
|
||||||
|
if (finished) {
|
||||||
|
currentView = .conclusion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigationTitle("Download Wizard")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CompletionView: View {
|
||||||
|
var body: some View {
|
||||||
|
VStack(spacing: 20) {
|
||||||
|
Image(systemName: "checkmark.seal.fill")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 80, height: 80)
|
||||||
|
.foregroundColor(.green)
|
||||||
|
|
||||||
|
Text("All Done!")
|
||||||
|
.font(.title)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
|
||||||
|
Text("All components were installed successfully. To start using OpenVINO features in Audacity, please restart the application.")
|
||||||
|
.font(.body)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
.padding(.horizontal)
|
||||||
|
|
||||||
|
Text("Once restarted, you'll be able to access enhanced AI-powered effects and tools powered by OpenVINO.")
|
||||||
|
.font(.footnote)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.padding(.horizontal)
|
||||||
|
Spacer()
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
Button("Finish") {
|
||||||
|
closeWindow()
|
||||||
|
}
|
||||||
|
.buttonStyle(.borderedProminent)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
.navigationTitle("Download Wizard")
|
||||||
|
}
|
||||||
|
func closeWindow() {
|
||||||
|
NSApp.keyWindow?.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
256
tools/ResourceDownloader/ResourceDownloader/models.json
Normal file
256
tools/ResourceDownloader/ResourceDownloader/models.json
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Audio Super Resolution",
|
||||||
|
"description": "Versatile Audio Super Resolution",
|
||||||
|
"dir": "audiosr",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/versatile_audio_super_resolution_openvino/resolve/9a97d7f128b22aea72e92862a3eccc310f88ac26/versatile_audio_sr_base_openvino_models.zip?download=true",
|
||||||
|
"sha256": "e4058862616e8eaa157a6a69d75daff49b63f997c69e59887c77a04ce6840d86",
|
||||||
|
"dsize": 930565310,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "Basic",
|
||||||
|
"description": "Basic",
|
||||||
|
"dir": "audiosr",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/versatile_audio_super_resolution_openvino/resolve/9a97d7f128b22aea72e92862a3eccc310f88ac26/versatile_audio_sr_ddpm_basic_openvino_models.zip?download=true",
|
||||||
|
"sha256": "382e0693e35e4bbeae1a0f3223954250e13427108ae16c0fe8f786489bbe2767",
|
||||||
|
"dsize": 473639145,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Speech",
|
||||||
|
"description": "Speech",
|
||||||
|
"dir": "audiosr",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/versatile_audio_super_resolution_openvino/resolve/9a97d7f128b22aea72e92862a3eccc310f88ac26/versatile_audio_sr_ddpm_speech_openvino_models.zip?download=true",
|
||||||
|
"sha256": "f44ee433da9e1aa6dd948142d81523c7a58213acfa0699a4014e1f6d30e8a349",
|
||||||
|
"dsize": 473616589,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "MusicGen",
|
||||||
|
"description": "MusicGen",
|
||||||
|
"dir": "musicgen",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/musicgen-static-openvino/resolve/b2ad8083f3924ed704814b68c5df9cbbf2ad2aae/musicgen_small_enc_dec_tok_openvino_models.zip?download=true",
|
||||||
|
"sha256": "f5cdd695a52cf4c0619dd419c8bff4e71700ee805b547e86b7483423883d6f32",
|
||||||
|
"dsize": 279450559,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"name": "Small (mono)",
|
||||||
|
"description": "Mono",
|
||||||
|
"dir": "musicgen",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/musicgen-static-openvino/resolve/b2ad8083f3924ed704814b68c5df9cbbf2ad2aae/musicgen_small_stereo_openvino_models.zip?download=true",
|
||||||
|
"sha256": "1c6496267b22175ecdd2518b9ed8c9870454674fc08fac1c864ca62e3d87e8e7",
|
||||||
|
"dsize": 1154648066,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Small (stereo)",
|
||||||
|
"description": "Stereo",
|
||||||
|
"dir": "musicgen",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/musicgen-static-openvino/resolve/b2ad8083f3924ed704814b68c5df9cbbf2ad2aae/musicgen_small_mono_openvino_models.zip?download=true",
|
||||||
|
"sha256": "b1e47df3ec60d0c5f70ba664fea636df9bc94710269ee72357a3353fd579afd9",
|
||||||
|
"dsize": 1098243900,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Whisper",
|
||||||
|
"description": "Whisper Base",
|
||||||
|
"dir": ".",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/whisper.cpp-openvino-models/resolve/194efafbee09390bbf33f33d02d9856dacfdd162/ggml-base-models.zip?download=true",
|
||||||
|
"sha256": "18f6e87146bfe9986fa764657cca26695bcb7fa3ba5d77d6d6af1d38de720e4c",
|
||||||
|
"dsize": 171306938,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"name": "Small",
|
||||||
|
"description": "Small",
|
||||||
|
"dir": ".",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/whisper.cpp-openvino-models/resolve/194efafbee09390bbf33f33d02d9856dacfdd162/ggml-small-models.zip?download=true",
|
||||||
|
"sha256": "7efabdcb08ec09ee24b615db9fe86425114a46d87a25d1e3d14ecd7195dd4e9f",
|
||||||
|
"dsize": 610456149,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Small (English only)",
|
||||||
|
"description": "Small English",
|
||||||
|
"dir": ".",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/whisper.cpp-openvino-models/resolve/194efafbee09390bbf33f33d02d9856dacfdd162/ggml-small.en-tdrz-models.zip?download=true",
|
||||||
|
"sha256": "ea825cb105e48aa0796e332c93827339dd60aa1a61633df14bb6611bcef26b95",
|
||||||
|
"dsize": 609030010,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Medium",
|
||||||
|
"description": "Medium",
|
||||||
|
"dir": ".",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/whisper.cpp-openvino-models/resolve/5c2f20da06aa17198dbd778d4190383557c23b1b/ggml-medium-models.zip?download=true",
|
||||||
|
"sha256": "afd961c0bac5830dbcbd15826f49553a5d5fb8a09c7a24eb634304fa068fe59f",
|
||||||
|
"dsize": 2110515739,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Large v1",
|
||||||
|
"description": "Large V1",
|
||||||
|
"dir": ".",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/whisper.cpp-openvino-models/resolve/9731937f2b9ca0aff8b8acd031ed77a1a378cc72/ggml-large-v1-models.zip?download=true",
|
||||||
|
"sha256": "fa187861eb46b701f242d63fc0067878de6345a71714d926c4b0eecf1ec0fffa",
|
||||||
|
"dsize": 4301056953,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Large v2",
|
||||||
|
"description": "Large V2",
|
||||||
|
"dir": ".",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/whisper.cpp-openvino-models/resolve/dc08ae819b895594cae08b0210bee051462aba75/ggml-large-v2-models.zip?download=true",
|
||||||
|
"sha256": "ab306b0a0a93a731e56efbfa4e80448206bd9b5b863d5a99e40a3532d64ec754",
|
||||||
|
"dsize": 4285702502,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Large v3",
|
||||||
|
"description": "Large V3",
|
||||||
|
"dir": ".",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/whisper.cpp-openvino-models/resolve/d0c3075c40e4938fb2a4cccfc91704106d3e7d12/ggml-large-v3-models.zip?download=true",
|
||||||
|
"sha256": "d61160dc5b1c1abc1dbdd6ae571fe4da87079fa3170156408f8775b493c15cdd",
|
||||||
|
"dsize": 4277163902,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Noise Suppression",
|
||||||
|
"description": "Noise Suppression",
|
||||||
|
"dir": ".",
|
||||||
|
"files": [],
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"name": "Deep Filter Net 2",
|
||||||
|
"description": "Deep Filter Net 2",
|
||||||
|
"dir": ".",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/deepfilternet-openvino/resolve/995706bda3da69da0825074ba7dbc8a78067e980/deepfilternet2.zip?download=true",
|
||||||
|
"sha256": "9d10c9c77a64121587e7d94a3d4d5cfeb67e9bfd2e416d48d1f74ac725c4f66e",
|
||||||
|
"dsize": 8648697,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Deep Filter Net 3",
|
||||||
|
"description": "Deep Filter Net 3",
|
||||||
|
"dir": ".",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/deepfilternet-openvino/resolve/995706bda3da69da0825074ba7dbc8a78067e980/deepfilternet3.zip?download=true",
|
||||||
|
"sha256": "fdc74e11439ca09a106f5bd77ed24002ef4d0e02114238a271c069d06172f341",
|
||||||
|
"dsize": 8004431,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dense UNet",
|
||||||
|
"description": "Dense UNet",
|
||||||
|
"dir": ".",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://storage.openvinotoolkit.org/repositories/open_model_zoo/2023.0/models_bin/1/noise-suppression-denseunet-ll-0001/FP16/noise-suppression-denseunet-ll-0001.bin",
|
||||||
|
"sha256": "da59b41a656b2948a4b45580b4870614d2dfa071a7566555aea4547423888e08",
|
||||||
|
"dsize": 8625568,
|
||||||
|
"esize": 234
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://storage.openvinotoolkit.org/repositories/open_model_zoo/2023.0/models_bin/1/noise-suppression-denseunet-ll-0001/FP16/noise-suppression-denseunet-ll-0001.xml",
|
||||||
|
"sha256": "89116a01cc59f7ac3f1f1365c851e47c9089fd33ca86712c30dc1f0ee7d14803",
|
||||||
|
"dsize": 689820,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Music Separation",
|
||||||
|
"description": "Music Separation",
|
||||||
|
"dir": ".",
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"name": "Basic",
|
||||||
|
"description": "Basic",
|
||||||
|
"dir": ".",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/demucs-openvino/resolve/97fc578fb57650045d40b00bc84c7d156be77547/htdemucs_v4.bin?download=true",
|
||||||
|
"sha256": "7aa84fa1f2b534bd6865a5609b8b5b028802fe761d6a09b1d30a1564f8fac6f8",
|
||||||
|
"dsize": 101167138,
|
||||||
|
"esize": 234
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://huggingface.co/Intel/demucs-openvino/resolve/97fc578fb57650045d40b00bc84c7d156be77547/htdemucs_v4.xml?download=true",
|
||||||
|
"sha256": "304e24325756089d6bb6583171dd1bea2327505e87c6cb6e010afea7463d9f0a",
|
||||||
|
"dsize": 1875040,
|
||||||
|
"esize": 234
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import Testing
|
||||||
|
@testable import ResourceDownloader
|
||||||
|
|
||||||
|
struct ResourceDownloaderTests {
|
||||||
|
|
||||||
|
@Test func example() async throws {
|
||||||
|
// Write your test here and use APIs like `#expect(...)` to check expected conditions.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
import XCTest
|
||||||
|
|
||||||
|
final class ResourceDownloaderUITests: XCTestCase {
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
|
|
||||||
|
// In UI tests it is usually best to stop immediately when a failure occurs.
|
||||||
|
continueAfterFailure = false
|
||||||
|
|
||||||
|
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tearDownWithError() throws {
|
||||||
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
func testExample() throws {
|
||||||
|
// UI tests must launch the application that they test.
|
||||||
|
let app = XCUIApplication()
|
||||||
|
app.launch()
|
||||||
|
|
||||||
|
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
func testLaunchPerformance() throws {
|
||||||
|
// This measures how long it takes to launch your application.
|
||||||
|
measure(metrics: [XCTApplicationLaunchMetric()]) {
|
||||||
|
XCUIApplication().launch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
import XCTest
|
||||||
|
|
||||||
|
final class ResourceDownloaderUITestsLaunchTests: XCTestCase {
|
||||||
|
|
||||||
|
override class var runsForEachTargetApplicationUIConfiguration: Bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
continueAfterFailure = false
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
func testLaunch() throws {
|
||||||
|
let app = XCUIApplication()
|
||||||
|
app.launch()
|
||||||
|
|
||||||
|
// Insert steps here to perform after app launch but before taking a screenshot,
|
||||||
|
// such as logging into a test account or navigating somewhere in the app
|
||||||
|
|
||||||
|
let attachment = XCTAttachment(screenshot: app.screenshot())
|
||||||
|
attachment.name = "Launch Screen"
|
||||||
|
attachment.lifetime = .keepAlways
|
||||||
|
add(attachment)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user