broken changes

This commit is contained in:
Mark Gregory
2026-11-05 16:35:24 +00:00
parent 7bf251c5e6
commit 1b5e48dfa1
7 changed files with 225 additions and 44 deletions
+12 -3
View File
@@ -27,14 +27,17 @@ struct DJXMLProfile: Codable, Identifiable {
var bindings: [DJXMLBinding]
var issues: [String]
var total: Int
var aliases: [String]?
var adapter: String?
var report: String {
"\(name)\n\(bindings.count) supported bindings of \(total) control entries.\n\n" +
(adapter == "Mixtrack Go" ? "Uses the dedicated Mixtrack Go adapter for 14-bit tempo, relative jog, pad modes and transport/mode feedback.\n\n" : "") +
"BPM sync, seek-based jog and headphones use KJMix Pro behaviour. Relative encoders use signed or offset MIDI values; djay acceleration curves are not reproduced. Hardware has not been certified. Audio routing is configured separately.\n\n" + issues.joined(separator:"\n")
}
static func parse(_ data: Data,filename: String) throws -> DJXMLProfile {
guard data.count <= 8_000_000 else { throw failure("Mapping file exceeds 8 MB.") }
guard let root = try PropertyListSerialization.propertyList(from:data,options:[],format:nil) as? [String:Any],
root["schemeVersion"] as? Int == 1 else { throw failure("Expected a djay mapping XML property list with schemeVersion 1.") }
(root["schemeVersion"] as? Int == 1 || root["schemeVersion"] as? String == "1") else { throw failure("Expected a djay mapping XML property list with schemeVersion 1.") }
let controls = root["controls"] as? [[String:Any]] ?? []
guard controls.count <= 20000 else { throw failure("Mapping contains too many controls.") }
var bindings = [DJXMLBinding](),issues = Set<String>(),blocked = Set<String>()
@@ -70,14 +73,20 @@ struct DJXMLProfile: Codable, Identifiable {
if !blocked.isEmpty { issues.insert("All bindings sharing an unsupported/conditional address are disabled to prevent accidental actions.") }
if root["customClassName"] != nil { issues.insert("Device-specific djay custom processor is unavailable; only independent standard MIDI bindings are enabled.") }
if root["outputs"] != nil { issues.insert("Device output/display definitions are not executed.") }
return .init(id:root["uuid"] as? String ?? filename,name:filename,endpoint:root["endpointName"] as? String ?? filename,bindings:bindings,issues:issues.sorted(),total:controls.filter{$0["headingTitle"] == nil}.count)
let aliases = root["endpointName"] as? [String] ?? [root["endpointName"] as? String ?? filename]
let adapter = root["customClassName"] as? String == "NumarkMixtrackGo" ? "Mixtrack Go" : nil
if adapter != nil {
bindings = MixtrackGoProtocol.mappings(source:0).map { .init(status:$0.status,number:$0.number,action:$0.action,mode:$0.mode,flipped:false,pickup:false) }
issues.insert("Mixtrack Go uses KJMix Pro’s dedicated protocol adapter, including its pad-mode state. Stems, sampler and FX modes remain unavailable.")
}
return .init(id:root["uuid"] as? String ?? filename,name:filename,endpoint:aliases.first ?? filename,bindings:bindings,issues:issues.sorted(),total:controls.filter{$0["headingTitle"] == nil}.count,aliases:aliases,adapter:adapter)
}
static func failure(_ message: String) -> NSError { NSError(domain:"DJ XML Mapping",code:1,userInfo:[NSLocalizedDescriptionKey:message]) }
static func normalized(_ name: String) -> String {
name.lowercased().split(whereSeparator:{$0.isWhitespace}).joined(separator:" ")
}
static func match(_ endpoint: String,in profiles: [DJXMLProfile]) -> DJXMLProfile? {
let matches = profiles.filter { !$0.bindings.isEmpty && normalized($0.endpoint) == normalized(endpoint) }
let matches = profiles.filter { !$0.bindings.isEmpty && ($0.aliases ?? [$0.endpoint]).contains { normalized($0) == normalized(endpoint) } }
return matches.count == 1 ? matches.first : nil
}
static func action(_ path: String) -> String? {