Zum Inhalt

apple/PhysarumApp/Tests/AudioTransientTests.swift

import XCTest
@testable import Physarum

final class AudioTransientTests: XCTestCase {
    private func tone(freq: Double, amp: Float, sr: Double, n: Int) -> [Float] {
        (0..<n).map { amp * Float(sin(2.0 * Double.pi * freq * Double($0) / sr)) }
    }
    /// The transient path is independent of the balance adaptation; keeping it off here
    /// means these tests observe the onset detector alone.
    private func rawTuning() -> AudioTuning {
        var t = AudioTuning()
        t.adaptiveBalance = false
        return t
    }
    func testSteadyToneTransientStaysLow_OnsetSpikes() {
        let sr = 48000.0, n = 1024
        let a = AudioAnalyzer(fftSize: n, smoothing: 0)
        var last = AudioBands.zero
        for _ in 0..<60 { last = a.analyze(samples: tone(freq: 120, amp: 0.5, sr: sr, n: n), sampleRate: sr, tuning: rawTuning()) }
        XCTAssertLessThan(last.transientBass, 0.15, "steady tone should idle low")
        let onset = a.analyze(samples: tone(freq: 120, amp: 1.0, sr: sr, n: n), sampleRate: sr, tuning: rawTuning())
        XCTAssertGreaterThan(onset.transientBass, last.transientBass + 0.2, "onset should spike transient")
    }
    func testSilenceTransientIsZero() {
        let sr = 48000.0, n = 1024
        let a = AudioAnalyzer(fftSize: n, smoothing: 0)
        var b = AudioBands.zero
        for _ in 0..<10 { b = a.analyze(samples: [Float](repeating: 0, count: n), sampleRate: sr, tuning: rawTuning()) }
        XCTAssertLessThan(b.transientBass, 0.05)
        XCTAssertLessThan(b.transientMid, 0.05)
        XCTAssertLessThan(b.transientHigh, 0.05)
    }
}