mirror of
https://github.com/audacity/mod-openvino-macos.git
synced 2025-12-10 03:56:51 -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/*
|
||||
sources/*
|
||||
staging/*
|
||||
packages/*
|
||||
|
||||
*.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