removed unwanted bar now with waveforms, major updates and enhancements

This commit is contained in:
Mark Gregory
2026-11-06 14:17:31 +00:00
parent a33ebdc1d3
commit f9655503df
3 changed files with 69 additions and 30 deletions
+47 -3
View File
@@ -3053,7 +3053,7 @@ extension KJamsCloneTests {
for song in dj.songs { XCTAssertNotNil(try WaveformCache.load(audio:URL(fileURLWithPath:song.audio),directory:dj.waveformDirectory)) }
}
@MainActor func testAddingLoopToPlayingTrackDoesNotRestartAudioNode() async throws {
@MainActor func testAddingLoopReplacesFileCommandsOnceAndKeepsRepeating() async throws {
let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
defer { try? FileManager.default.removeItem(at:root) }
let fixture = try XCTUnwrap(Bundle(for:Self.self).resourceURL?.appendingPathComponent("Fixtures/Demo.wav"))
@@ -3066,11 +3066,11 @@ extension KJamsCloneTests {
player.defineLoop(start:start,end:start+0.3)
for _ in 0..<100 where !player.nativeLoopActive { try await Task.sleep(nanoseconds:10_000_000) }
XCTAssertTrue(player.nativeLoopActive);XCTAssertTrue(player.audioPlaybackStarted)
XCTAssertEqual(player.audioScheduleRestartCount,restarts,"Adding a live loop must not stop the audio node")
XCTAssertEqual(player.audioScheduleRestartCount,restarts+1,"A live file command must be replaced once with the prepared loop")
try await Task.sleep(nanoseconds:400_000_000)
XCTAssertGreaterThanOrEqual(player.displayTime,start);XCTAssertLessThan(player.displayTime,start+0.301)
player.loopEnabled = false
XCTAssertEqual(player.audioScheduleRestartCount,restarts,"Cancelling the loop must also leave the audio node running")
XCTAssertEqual(player.audioScheduleRestartCount,restarts+1,"Repeating and cancelling must not replace the node commands again")
XCTAssertTrue(player.audioPlaybackStarted)
}
@@ -3099,4 +3099,48 @@ extension KJamsCloneTests {
XCTAssertTrue(finished);XCTAssertFalse(player.playing)
}
@MainActor func testLiveLoopRepeatsActualAudioRatherThanOnlyWrappingDisplay() async throws {
let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
defer { try? FileManager.default.removeItem(at:root) }
try FileManager.default.createDirectory(at:root,withIntermediateDirectories:true)
let format = try XCTUnwrap(AVAudioFormat(standardFormatWithSampleRate:44100,channels:2))
let buffer = try XCTUnwrap(AVAudioPCMBuffer(pcmFormat:format,frameCapacity:132300));buffer.frameLength = 132300
let data = try XCTUnwrap(buffer.floatChannelData)
for i in 0..<132300 {
let amplitude: Float = i < 30870 ? 0.1 : 0.7
let value = amplitude*Float(sin(Double(i)*2 * .pi*440/44100))
data[0][i] = value;data[1][i] = value
}
let url = root.appendingPathComponent("LoopSignal.wav")
do { let file = try AVAudioFile(forWriting:url,settings:format.settings);try file.write(from:buffer) }
let player = Player(waveformCacheDirectory:root.appendingPathComponent("Cache"),persistsMix:false)
defer { player.stop() }
player.autoFade = false;player.volume = 0.8
try player.load(Song(id:1,title:"Loop signal",audio:url.path,cdg:nil,rating:0,plays:0))
for _ in 0..<100 where player.displayTime < 0.1 { try await Task.sleep(nanoseconds:10_000_000) }
player.defineLoop(start:0.2,end:0.5)
for _ in 0..<100 where !player.nativeLoopActive { try await Task.sleep(nanoseconds:10_000_000) }
try await Task.sleep(nanoseconds:1_000_000_000)
for _ in 0..<10 {
XCTAssertGreaterThan(player.scrubOutputLevel,0.02,"Loop audio must remain audible")
XCTAssertLessThan(player.scrubOutputLevel,0.2,"The quiet loop must repeat; the loud audio after it must never render")
try await Task.sleep(nanoseconds:30_000_000)
}
let handoffs = player.audioScheduleRestartCount
player.defineLoop(start:0.2,end:1.1)
var extendedPeak: Float = 0
for _ in 0..<50 {
try await Task.sleep(nanoseconds:30_000_000)
extendedPeak = max(extendedPeak,player.scrubOutputLevel)
}
XCTAssertGreaterThan(extendedPeak,0.4,"Extending the loop must render its newly included loud section")
player.defineLoop(start:0.2,end:0.5)
try await Task.sleep(nanoseconds:1_200_000_000)
XCTAssertLessThan(player.scrubOutputLevel,0.2,"Shortening must return to the quiet loop audio")
player.loopEnabled = false
try await Task.sleep(nanoseconds:800_000_000)
XCTAssertGreaterThan(player.scrubOutputLevel,0.4,"Loop Off must resume the actual file beyond the loop")
XCTAssertEqual(player.audioScheduleRestartCount,handoffs,"Resizing and cancellation must keep the node running")
}
}