broken changes
This commit is contained in:
@@ -1767,7 +1767,7 @@ extension KJamsCloneTests {
|
||||
XCTAssertEqual(MIDISourceCreate(client,"KJMix virtual test controller" as CFString,&source),noErr)
|
||||
let suite = "KJMix.VirtualMIDI.\(UUID().uuidString)",defaults = try XCTUnwrap(UserDefaults(suiteName:suite))
|
||||
defer { defaults.removePersistentDomain(forName:suite) }
|
||||
let midi = DJMIDI(defaults:defaults);midi.refreshSources()
|
||||
let midi = DJMIDI(defaults:defaults,catalog:[]);midi.refreshSources()
|
||||
let input = try XCTUnwrap(midi.sources.first{$0.endpoint == source});midi.select(input.id)
|
||||
XCTAssertEqual(midi.sourceID,input.id)
|
||||
XCTAssertEqual(defaults.integer(forKey:"DJ.MIDISource.v1"),Int(input.id))
|
||||
@@ -2075,6 +2075,82 @@ extension KJamsCloneTests {
|
||||
let data = try PropertyListSerialization.data(fromPropertyList:["schemeVersion":1,"uuid":"xml-test","endpointName":endpoint,"controls":controls],format:.xml,options:0)
|
||||
return try DJXMLProfile.parse(data,filename:endpoint)
|
||||
}
|
||||
func testStereoRoutingMapsAndRejectsPublicCueOverlap() throws {
|
||||
XCTAssertEqual(try DJAudioRouting.channelMap(channels:4,first:2),[-1,-1,0,1])
|
||||
XCTAssertEqual(try DJAudioRouting.channelMap(channels:4,first:0),[0,1,-1,-1])
|
||||
XCTAssertThrowsError(try DJAudioRouting.channelMap(channels:2,first:2))
|
||||
let device = DJAudioDevice(id:1,uid:"controller",name:"Controller",outputChannels:4)
|
||||
var routing = DJAudioRouting();routing.main.uid = device.uid;routing.cue = .init(uid:device.uid,firstChannel:2)
|
||||
XCTAssertNoThrow(try routing.validate(devices:[device],defaultID:1))
|
||||
routing.cue.firstChannel = 0;XCTAssertThrowsError(try routing.validate(devices:[device],defaultID:1))
|
||||
routing.cue.uid = "";routing.mode = "External";routing.deckA.uid = device.uid;routing.deckB = .init(uid:device.uid,firstChannel:2)
|
||||
XCTAssertNoThrow(try routing.validate(devices:[device],defaultID:1))
|
||||
routing.deckB.firstChannel = 0;XCTAssertThrowsError(try routing.validate(devices:[device],defaultID:1))
|
||||
}
|
||||
@MainActor func testAudioOutputsAndActualFourChannelRoutingWhenInterfaceAttached() async throws {
|
||||
let outputs = DJAudioDevice.outputs()
|
||||
XCTAssertFalse(outputs.isEmpty,"CoreAudio should expose available Mac and USB outputs")
|
||||
guard let controller = outputs.first(where:{$0.name.localizedCaseInsensitiveContains("MixTrack Go") && $0.outputChannels >= 4}) else { throw XCTSkip("Four-channel Mixtrack Go is not attached") }
|
||||
let player = Player(persistsMix:false)
|
||||
try player.routeOutput(controller.id,firstChannel:2)
|
||||
XCTAssertEqual(player.outputChannelMap(),[-1,-1,0,1])
|
||||
try player.routeOutput(controller.id,firstChannel:0)
|
||||
XCTAssertEqual(player.outputChannelMap(),[0,1,-1,-1])
|
||||
let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
|
||||
defer { try? FileManager.default.removeItem(at:root) }
|
||||
let model = AppModel(storageURL:root)
|
||||
var routing = DJAudioRouting();routing.main.uid = controller.uid;routing.cue = .init(uid:controller.uid,firstChannel:2)
|
||||
model.dj.applyRouting(routing);XCTAssertNil(model.dj.error);XCTAssertEqual(model.dj.routing,routing)
|
||||
XCTAssertEqual(DJSystem(storageURL:model.dj.root).routing,routing)
|
||||
let host = NSHostingView(rootView:StudioSettingsDialog(model:model,scope:"DJ",category:"Devices").preferredColorScheme(.dark))
|
||||
host.frame = NSRect(x:0,y:0,width:850,height:700)
|
||||
let window = NSWindow(contentRect:host.frame,styleMask:[.borderless],backing:.buffered,defer:false)
|
||||
window.contentView = host;window.setFrameOrigin(NSPoint(x:-10000,y:-10000));window.orderFront(nil)
|
||||
defer { window.orderOut(nil);window.contentView = nil }
|
||||
try await Task.sleep(nanoseconds:150_000_000);host.layoutSubtreeIfNeeded()
|
||||
if let rep = host.bitmapImageRepForCachingDisplay(in:host.bounds) { host.cacheDisplay(in:host.bounds,to:rep);try XCTUnwrap(rep.representation(using:.png,properties:[:])).write(to:URL(fileURLWithPath:"/private/tmp/kjmix-xml-mappings/audio-routing.png")) }
|
||||
}
|
||||
func testXMLStandardLEDOutputHonoursOverridesAndInversion() throws {
|
||||
let profile = try xmlMapping([["keyPath":"turntable1.playPause","midiMessageType":1,"midiChannel":0,"midiData":4,"output":["midiChannel":2,"midiData":9,"midiMessageType":3,"midiMinValue":1,"midiMaxValue":100,"flipped":true]]])
|
||||
let output = try XCTUnwrap(profile.outputs?.first)
|
||||
XCTAssertEqual(output.packet(active:true),[0xB2,9,1])
|
||||
XCTAssertEqual(output.packet(active:false),[0xB2,9,100])
|
||||
}
|
||||
@MainActor func testMixtrackXMLUsesNativeAdapterAndSendsActualLEDOutput() async throws {
|
||||
let profile = try XCTUnwrap(DJXMLProfile.bundled.first{$0.name == "Numark Mixtrack GO"})
|
||||
XCTAssertEqual(profile.adapter,"Mixtrack Go")
|
||||
XCTAssertNotNil(DJXMLProfile.match("Numark MixTrack Go Bluetooth",in:[profile]))
|
||||
var client = MIDIClientRef(0),source = MIDIEndpointRef(0),destination = MIDIEndpointRef(0)
|
||||
XCTAssertEqual(MIDIClientCreateWithBlock("KJMix LED test" as CFString,&client,nil),noErr)
|
||||
defer { if source != 0 { MIDIEndpointDispose(source) };if destination != 0 { MIDIEndpointDispose(destination) };MIDIClientDispose(client) }
|
||||
let name = "KJMix LED \(UUID())"
|
||||
var received = [UInt8]()
|
||||
XCTAssertEqual(MIDIDestinationCreateWithBlock(client,name as CFString,&destination) { packets,_ in
|
||||
var bytes = [UInt8]()
|
||||
var packet = UnsafeRawPointer(packets).advanced(by:MemoryLayout<MIDIPacketList>.offset(of:\.packet)!).assumingMemoryBound(to:MIDIPacket.self)
|
||||
for _ in 0..<packets.pointee.numPackets {
|
||||
let data = UnsafeRawPointer(packet).advanced(by:MemoryLayout<MIDIPacket>.offset(of:\.data)!)
|
||||
bytes.append(contentsOf:UnsafeRawBufferPointer(start:data,count:Int(packet.pointee.length)));packet = UnsafePointer(MIDIPacketNext(packet))
|
||||
}
|
||||
let captured = bytes;Task { @MainActor in received += captured }
|
||||
},noErr)
|
||||
XCTAssertEqual(MIDISourceCreate(client,name as CFString,&source),noErr)
|
||||
let suite = "KJMix.LED.\(UUID())",defaults = try XCTUnwrap(UserDefaults(suiteName:suite))
|
||||
defer { defaults.removePersistentDomain(forName:suite) }
|
||||
let midi = DJMIDI(defaults:defaults,catalog:[]);midi.refreshSources()
|
||||
let input = try XCTUnwrap(midi.sources.first{$0.endpoint == source});midi.select(input.id);midi.applyXML(profile)
|
||||
XCTAssertTrue(midi.mixtrackEnabled)
|
||||
var actions = [String]();midi.onAction = { action,_,_ in actions.append(action) }
|
||||
midi.receive([0x95,0,127,0x95,0x17,127]);XCTAssertTrue(actions.contains("B Loop 8"))
|
||||
midi.updateFeedback(aPlaying:true,bPlaying:false,sync:true,aLoaded:true,bLoaded:true,cue:"B",aCues:[true,false,false,false])
|
||||
try await Task.sleep(nanoseconds:100_000_000)
|
||||
XCTAssertTrue((0..<max(0,received.count-2)).contains{Array(received[$0..<($0+3)]) == [0x90,0,127]})
|
||||
XCTAssertTrue((0..<max(0,received.count-2)).contains{Array(received[$0..<($0+3)]) == [0x94,0x14,127]})
|
||||
XCTAssertTrue((0..<max(0,received.count-6)).contains{Array(received[$0..<($0+7)]) == [0xF0,0,0x20,0x7F,3,1,0xF7]})
|
||||
let initial = received.count
|
||||
try await Task.sleep(nanoseconds:2_100_000_000)
|
||||
XCTAssertGreaterThan(received.count,initial,"LED state is resent after the startup light show ends")
|
||||
}
|
||||
func testDjayXMLLoadsAllSuppliedProfilesAndReportsUnsupportedActions() throws {
|
||||
XCTAssertEqual(DJXMLProfile.bundled.count,210)
|
||||
let dj2go = try XCTUnwrap(DJXMLProfile.bundled.first{$0.name == "Numark DJ2GO"})
|
||||
|
||||
Reference in New Issue
Block a user