summarylogtreecommitdiffstats
path: root/PKGBUILD
blob: a37887d44e8f9d684a9cbc91cebc8f14e56a23eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# Maintainer: Selene Bray-Hernandez <selebray1998@gmail.com>
# Previous Maintainer: Felipe Facundes
# Changelog: CHANGELOG

pkgname=audacity-openvino
pkgver=3.7.7
pkgrel=10

# Auto-track latest 3.7.x release tag; override with explicit pkgver if needed
_audacity_tag_prefix=Audacity-3.7
pkgdesc="Audacity - Digital audio editor with AI support via openvino (mod-openvino)"
arch=(x86_64)
url="https://audacityteam.org"
license=(GPL-3.0-or-later)
install=audacity-openvino.install
depends=(
  libtorch whisper.cpp-openvino
  glibc
  libid3tag libmad libsndfile libsoxr
  lilv opusfile portaudio portmidi portsmf
  soundtouch sqlite openvino-models wxwidgets-gtk3
  vamp-plugin-sdk wavpack suil twolame
)
optdepends=(
  intel-compute-runtime
  level-zero-loader
  libtorch-cuda
  libtorch-rocm
  cuda
)
conflicts=(audacity)
provides=(
  ladspa-host
  lv2-host
  vamp-host
  vst-host
  vst3-host
  audacity
)
makedepends=(
  git cmake chrpath ffmpeg rapidjson vst3sdk opencl-clhpp
)
source=(
   "git+https://github.com/audacity/audacity.git"
   "git+https://github.com/intel/openvino-plugins-ai-audacity.git#tag=v3.7.1-R4.2"
   "audacity-openvino"
   "audacity-openvino.desktop"
   "audacity-openvino.install"
   "audacity-openvino-elf-fix.hook"
   "CHANGELOG"
   "elf_fix.py"
)
sha256sums=(
	'SKIP'
	'SKIP'
	'SKIP'
	'SKIP'
	'SKIP'
	'SKIP'
	'SKIP'
	'SKIP'
) # Yes I know this looks suspicious. I'm not trying to be - because I'm modifying code on the fly I can't do a checksum as far as I know. Please feel free to leave a comment on the package if you have a solution!

pkgver() {
  cd "${srcdir}/audacity"
  local tag
  tag=$(git tag -l "${_audacity_tag_prefix}.*" --sort=-v:refname | head -1)
  if [ -n "$tag" ]; then
    echo "${tag#Audacity-}"
  else
    echo "${pkgver}"
  fi
}

prepare() {
  cd "${srcdir}/audacity"

  # Checkout the latest matching tag
  local latest_tag
  latest_tag=$(git tag -l "${_audacity_tag_prefix}.*" --sort=-v:refname | head -1 || true)
  if [ -n "$latest_tag" ]; then
    git -c advice.detachedHead=false checkout "$latest_tag"
  else
    echo "==> WARNING: no tag matching ${_audacity_tag_prefix}.* found, using HEAD"
  fi

  rm -rf modules/openvino-plugins-ai-audacity
  cp -r "${srcdir}/openvino-plugins-ai-audacity" modules/openvino-plugins-ai-audacity

  cat > modules/openvino-plugins-ai-audacity/CMakeLists.txt <<'EOF'
#[[
A directory of module targets
]]

# Include the modules that we'll build

# The list of modules is ordered so that each module occurs after any others
# that it depends on
set( MODULES
   mod-openvino
)

audacity_module_subdirectory("${MODULES}")
EOF

  if ! grep -q "openvino-plugins-ai-audacity" modules/CMakeLists.txt; then
    sed -i '/foreach( FOLDER ${FOLDERS} )/i add_subdirectory("openvino-plugins-ai-audacity")' modules/CMakeLists.txt
  fi

  # whisper.cpp 1.8.3 removed speed_up from whisper_full_params
  sed -i '/wparams\.speed_up = params\.speed_up;/d' modules/openvino-plugins-ai-audacity/mod-openvino/OVWhisperTranscription.cpp
  sed -i '/bool speed_up = false;/d' modules/openvino-plugins-ai-audacity/mod-openvino/OVWhisperTranscription.cpp

  # Newer OpenVINO API: data<T>() returns const T* for const tensors
  sed -i 's/float\* pXTensor = x_tensor\.data<float>()/const float* pXTensor = x_tensor.data<float>()/g' modules/openvino-plugins-ai-audacity/mod-openvino/htdemucs.cpp
  sed -i 's/float\* pXTTensor = xt_tensor\.data<float>()/const float* pXTTensor = xt_tensor.data<float>()/g' modules/openvino-plugins-ai-audacity/mod-openvino/htdemucs.cpp
  sed -i 's/float\* pXTensor_Out = x_out_tensor\.data<float>()/const float* pXTensor_Out = x_out_tensor.data<float>()/g' modules/openvino-plugins-ai-audacity/mod-openvino/htdemucs.cpp
  sed -i 's/float\* pXTTensor_Out = xt_out_tensor\.data<float>()/const float* pXTTensor_Out = xt_out_tensor.data<float>()/g' modules/openvino-plugins-ai-audacity/mod-openvino/htdemucs.cpp
  # std::memcpy destination needs non-const void*; data_ptr() returns void* for writes
  sed -i 's/std::memcpy(pXTensor, x\.data_ptr()/std::memcpy(const_cast<float*>(pXTensor), x.data_ptr()/g' modules/openvino-plugins-ai-audacity/mod-openvino/htdemucs.cpp
  sed -i 's/std::memcpy(pXTTensor, xt\.data_ptr()/std::memcpy(const_cast<float*>(pXTTensor), xt.data_ptr()/g' modules/openvino-plugins-ai-audacity/mod-openvino/htdemucs.cpp
  # torch::from_blob takes void*, not const void*
  sed -i 's/torch::from_blob(pXTensor_Out,/torch::from_blob(const_cast<float*>(pXTensor_Out),/g' modules/openvino-plugins-ai-audacity/mod-openvino/htdemucs.cpp
  sed -i 's/torch::from_blob(pXTTensor_Out,/torch::from_blob(const_cast<float*>(pXTTensor_Out),/g' modules/openvino-plugins-ai-audacity/mod-openvino/htdemucs.cpp

  # std::not1 was removed in C++20; replace with std::not_fn
  sed -i 's/std::not1( std::mem_fn( pmf ) )/std::not_fn( std::mem_fn( pmf ) )/g' libraries/lib-track/Track.h
}

build() {
  cd "${srcdir}/audacity"
  # Use CUDA libtorch if available, then ROCm, then system libtorch, fall back to CPU
  if [ -d "/opt/libtorch-cuda" ] && command -v nvcc &> /dev/null; then
    export LIBTORCH_ROOTDIR="/opt/libtorch-cuda"
    export CMAKE_CUDA_COMPILER=$(command -v nvcc)
  elif [ -d "/opt/libtorch-rocm" ]; then
    export LIBTORCH_ROOTDIR="/opt/libtorch-rocm"
  elif [ -d "/opt/libtorch" ]; then
    export LIBTORCH_ROOTDIR="/opt/libtorch"
  else
    export LIBTORCH_ROOTDIR="/opt/libtorch-cpu"
  fi

  # Fix ELF load command alignment in libtorch_cpu.so at the selected path.
  # Pre-built ROCm binaries sometimes ship zero-length LOAD segments with
  # misaligned p_offset, glibc rejects with "not page-aligned" (bug #2).
  if [ -f "${LIBTORCH_ROOTDIR}/lib/libtorch_cpu.so" ] && [ -w "${LIBTORCH_ROOTDIR}/lib/libtorch_cpu.so" ]; then
  python3 -c "
import struct
with open('${LIBTORCH_ROOTDIR}/lib/libtorch_cpu.so', 'r+b') as f:
  f.seek(32); e_phoff = struct.unpack('<Q', f.read(8))[0]
  f.seek(56); e_phnum = struct.unpack('<H', f.read(2))[0]
  fixed = 0
  for i in range(e_phnum):
    entry_off = e_phoff + i * 56; f.seek(entry_off)
    p_type, p_flags, p_offset, p_vaddr, p_paddr, p_filesz, p_memsz, p_align = struct.unpack('<IIQQQQQQ', f.read(56))
    if p_type != 1 or p_filesz or p_memsz: continue
    if (p_vaddr - p_offset) & (p_align - 1) == 0: continue
    f.seek(entry_off + 8); f.write(struct.pack('<Q', p_vaddr))
    print(f'Fixed segment {i}: p_offset 0x{p_offset:x} -> 0x{p_vaddr:x}'); fixed += 1
  if fixed: print(f'Fixed {fixed} ELF segment(s) in libtorch_cpu.so')
  else: print('No ELF alignment issues in libtorch_cpu.so')
"
  elif [ -f "${LIBTORCH_ROOTDIR}/lib/libtorch_cpu.so" ]; then
    echo "WARNING: Skipping ELF alignment fix for libtorch_cpu.so due to insufficient permissions. You may need to fix this manually if encountering 'not page-aligned' errors."
  fi

  local cmake_options=(
    -B build
    -S .
    -D CMAKE_BUILD_TYPE=Release
    -D CMAKE_INSTALL_PREFIX=/usr
    -D audacity_use_openvino=ON
    -D audacity_conan_enabled=OFF
    -D audacity_has_tests=OFF
    -D audacity_lib_preference=system
    -D audacity_obey_system_dependencies=ON
    -W no-dev
    -D CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations"
    -D CMAKE_RULE_MESSAGES=OFF
    --log-level=ERROR
  )

  export CFLAGS+=" -DNDEBUG -std=gnu11"
  export CXXFLAGS+=" -DNDEBUG"
  export VST3SDK="/usr/src/vst3sdk"

  cmake "${cmake_options[@]}"
  cmake --build build -- -j$(nproc)
}

package() {
  shortcut="${pkgdir}/usr/share/applications/audacity.desktop"

  cd "${srcdir}/audacity"
  DESTDIR="${pkgdir}" cmake --install build

  # Install script wrapper
  install -Dm755 "$srcdir/audacity-openvino" "${pkgdir}/usr/bin/audacity-openvino"
  # Replace native .desktop
  if [ -f "$shortcut" ]; then
  	rm -f "$shortcut"
  fi
  install -Dm644 "$srcdir/audacity-openvino.desktop" "$shortcut"
  # Install changelog
  install -Dm644 "$srcdir/CHANGELOG" "${pkgdir}/usr/share/doc/${pkgname}/CHANGELOG"

  # Install ELF alignment fix script and pacman hook
  install -Dm755 "$srcdir/elf_fix.py" "${pkgdir}/usr/share/audacity-openvino/elf_fix.py"
  install -Dm644 "$srcdir/audacity-openvino-elf-fix.hook" "${pkgdir}/usr/share/libalpm/hooks/audacity-openvino-elf-fix.hook"

  # Create user models directory (world-writable for Audacity)
  mkdir -p "${pkgdir}/usr/share/audacity/openvino-models/user-models"
  chmod a+w "${pkgdir}/usr/share/audacity/openvino-models/user-models"

}