From 9aa9adaba2f9fe7c2342c75acad285db2aaa6713 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 1 Jul 2026 05:56:51 +0000 Subject: [PATCH 1/3] Fix CI: pin Linux runner and repair AudioUnit registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two pre-existing CI failures on main, unrelated to each other: - Linux job died in swift-actions/setup-swift@v1 with "Version 24.04 of Ubuntu is not supported" because `ubuntu-latest` now resolves to Ubuntu 24.04, which that action version predates. Pin the job to ubuntu-22.04. - macOS job failed to compile PortaDSPNodeFactory: it calls PortaDSPAudioUnit.register() and .componentDescription, but the real AUAudioUnit subclass never declared those statics — they existed only on the Linux stub class. Add a static componentDescription and an idempotent register() (via AUAudioUnit.registerSubclass) to the Apple implementation, which also resolves the cascading 'AUAudioUnitError' scope error in instantiateSync(). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01CJTwEPDS71A9cFJFnpjB63 --- .github/workflows/ci.yml | 6 +++-- .../PortaDSPKit/PortaDSPAudioUnit.swift | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5deb66b..2d143a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,8 +7,10 @@ on: jobs: linux: - name: Linux (ubuntu-latest) - runs-on: ubuntu-latest + name: Linux (ubuntu-22.04) + # Pinned to 22.04: swift-actions/setup-swift@v1 does not support the + # Ubuntu 24.04 image that `ubuntu-latest` now resolves to. + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - name: Set up Swift diff --git a/Packages/PortaDSPKit/Sources/PortaDSPKit/PortaDSPAudioUnit.swift b/Packages/PortaDSPKit/Sources/PortaDSPKit/PortaDSPAudioUnit.swift index 0e638e0..702512e 100644 --- a/Packages/PortaDSPKit/Sources/PortaDSPKit/PortaDSPAudioUnit.swift +++ b/Packages/PortaDSPKit/Sources/PortaDSPKit/PortaDSPAudioUnit.swift @@ -576,6 +576,33 @@ public final class PortaDSPAudioUnit: AUAudioUnit { } return result } + + /// Audio component description identifying this unit to the component system + /// (effect type, subtype "P424", manufacturer "Jhnc"). + public static let componentDescription = AudioComponentDescription( + componentType: OSType(kAudioUnitType_Effect), + componentSubType: PortaDSPAudioUnit.makeFourCC("P424"), + componentManufacturer: PortaDSPAudioUnit.makeFourCC("Jhnc"), + componentFlags: 0, + componentFlagsMask: 0 + ) + + // Registers the subclass exactly once; lazy static initialization is + // thread-safe and runs its body a single time. + private static let registration: Void = { + AUAudioUnit.registerSubclass( + PortaDSPAudioUnit.self, + as: PortaDSPAudioUnit.componentDescription, + name: "Porta424: PortaDSP", + version: 0x0001_0000 + ) + }() + + /// Registers `PortaDSPAudioUnit` with the Audio Unit component system so it + /// can be instantiated via `AVAudioUnit.instantiate(with:)`. Idempotent. + public static func register() { + _ = registration + } } public enum PortaDSPNodeFactory { From 38ba997088a0d97e33e91948414edd8f3405c053 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 1 Jul 2026 06:03:16 +0000 Subject: [PATCH 2/3] Fix remaining macOS build errors and use Swift container on Linux Deeper CI diagnosis from the PR build surfaced more than the first log showed: Linux: pinning to ubuntu-22.04 got past the "24.04 not supported" error but swift-actions/setup-swift@v1 then failed at its GPG key-import step. The action is unmaintained; switch to the official `swift:5.9` container image, which ships the toolchain and needs no download/verify step. macOS: PortaDSPAudioUnit.swift (the canImport(AudioToolbox) branch) never imported the C bridge, so every porta_create/porta_destroy/porta_update_params/ porta_process_interleaved/porta_get_meters_dbfs call was out of scope. Import PortaDSPBridge (as PortaDSPWrapper.swift does) and drop the conflicting local porta_dsp_handle typealias so the handle type comes from the C module. Also replace two throws of the non-existent `AUAudioUnitError` type with NSError(domain: NSOSStatusErrorDomain, code:) using kAudioUnitErr_FormatNotSupported and kAudioUnitErr_FailedInitialization. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01CJTwEPDS71A9cFJFnpjB63 --- .github/workflows/ci.yml | 14 ++++++-------- .../Sources/PortaDSPKit/PortaDSPAudioUnit.swift | 13 +++++-------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d143a1..fb49aec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,16 +7,14 @@ on: jobs: linux: - name: Linux (ubuntu-22.04) - # Pinned to 22.04: swift-actions/setup-swift@v1 does not support the - # Ubuntu 24.04 image that `ubuntu-latest` now resolves to. - runs-on: ubuntu-22.04 + name: Linux (Swift 5.9) + runs-on: ubuntu-latest + # Use the official Swift toolchain image instead of swift-actions/setup-swift, + # which is unmaintained and now fails on current runners (no Ubuntu 24.04 + # support, and a broken GPG key-import step on 22.04). + container: swift:5.9 steps: - uses: actions/checkout@v4 - - name: Set up Swift - uses: swift-actions/setup-swift@v1 - with: - swift-version: "5.9" - name: Build run: swift build --build-tests - name: Test diff --git a/Packages/PortaDSPKit/Sources/PortaDSPKit/PortaDSPAudioUnit.swift b/Packages/PortaDSPKit/Sources/PortaDSPKit/PortaDSPAudioUnit.swift index 702512e..07a62b7 100644 --- a/Packages/PortaDSPKit/Sources/PortaDSPKit/PortaDSPAudioUnit.swift +++ b/Packages/PortaDSPKit/Sources/PortaDSPKit/PortaDSPAudioUnit.swift @@ -2,12 +2,9 @@ import AudioToolbox import AVFoundation import Foundation - -// Provide a local alias for the opaque DSP handle if not provided by the C headers -// This matches the typical pattern of an opaque C pointer handle. -#if !canImport(PortaDSPCHandleTypes) -public typealias porta_dsp_handle = OpaquePointer -#endif +// The C bridge target supplies the porta_* render functions and the +// `porta_dsp_handle` type, mirroring PortaDSPWrapper.swift. +import PortaDSPBridge public enum PortaDSPAudioUnitError: Error { case failedToCreateEngineNode @@ -415,7 +412,7 @@ public final class PortaDSPAudioUnit: AUAudioUnit { public override func allocateRenderResources() throws { try super.allocateRenderResources() guard inputBus.format.channelCount == outputBus.format.channelCount else { - throw AUAudioUnitError(.formatNotSupported) + throw NSError(domain: NSOSStatusErrorDomain, code: Int(kAudioUnitErr_FormatNotSupported)) } let channels = Int(outputBus.format.channelCount) let frames = Int(maximumFramesToRender) @@ -625,7 +622,7 @@ public enum PortaDSPNodeFactory { throw error } guard let resolvedUnit = unit else { - throw AUAudioUnitError(.failedInitialization) + throw NSError(domain: NSOSStatusErrorDomain, code: Int(kAudioUnitErr_FailedInitialization)) } return resolvedUnit } From f3d1fb41f92c3a874a3e883ff3261fd9410da6c2 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 1 Jul 2026 06:05:44 +0000 Subject: [PATCH 3/3] Fix AUAudioUnit init: set parameterTree after super.init With the earlier scope errors resolved, the compiler reached an init-order error: `self.parameterTree` (an AUAudioUnit superclass property) was assigned before `super.init`. Move the assignment to after super.init. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01CJTwEPDS71A9cFJFnpjB63 --- .../PortaDSPKit/Sources/PortaDSPKit/PortaDSPAudioUnit.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Packages/PortaDSPKit/Sources/PortaDSPKit/PortaDSPAudioUnit.swift b/Packages/PortaDSPKit/Sources/PortaDSPKit/PortaDSPAudioUnit.swift index 07a62b7..a088582 100644 --- a/Packages/PortaDSPKit/Sources/PortaDSPKit/PortaDSPAudioUnit.swift +++ b/Packages/PortaDSPKit/Sources/PortaDSPKit/PortaDSPAudioUnit.swift @@ -255,7 +255,6 @@ public final class PortaDSPAudioUnit: AUAudioUnit { parameterMap = map let orderedParameters = ParameterID.allCases.compactMap { map[$0] } parameterTreeImpl = AUParameterTree.createTree(withChildren: orderedParameters) - self.parameterTree = parameterTreeImpl let defaultFormat = AVAudioFormat( commonFormat: .pcmFormatFloat32, @@ -266,6 +265,9 @@ public final class PortaDSPAudioUnit: AUAudioUnit { inputBus = try AUAudioUnitBus(format: defaultFormat) outputBus = try AUAudioUnitBus(format: defaultFormat) try super.init(componentDescription: componentDescription, options: options) + // `parameterTree` is a superclass property, so it can only be assigned + // after super.init. + parameterTree = parameterTreeImpl maximumFramesToRender = 4096 inputBusArray = AUAudioUnitBusArray(audioUnit: self, busType: .input, busses: [inputBus]) outputBusArray = AUAudioUnitBusArray(audioUnit: self, busType: .output, busses: [outputBus])