Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multicam with individual Audio Role voice isolation breaks in FCPXML v1.11 #314

Open
randomeizer opened this issue Dec 29, 2023 · 6 comments

Comments

@randomeizer
Copy link

randomeizer commented Dec 29, 2023

Apple Feedback Assistant ID: FB13500575

DESCRIBE THE BUG:
When I have a timeline with a Multicam clip that has multiple audio roles, and I select an individual role to apply Voice Isolation + Volume adjustments, the exported FCPXML in v1.11 will be output in this order (volume then voiceIsolation):

<mc-source angleID="VxamD/tAS4iO44cSAPFyuw" srcEnable="audio">
    <audio-role-source role="dialogue.Foo"/>
    <audio-role-source role="dialogue.Bar">
        <adjust-volume amount="12dB"/>
        <adjust-voiceIsolation amount="50"/>
    </audio-role-source>
</mc-source>

However, it should be in this order (voiceIsolation, then volume):

<mc-source angleID="VxamD/tAS4iO44cSAPFyuw" srcEnable="audio">
    <audio-role-source role="dialogue.Foo"/>
    <audio-role-source role="dialogue.Bar">
        <adjust-voiceIsolation amount="50"/>
        <adjust-volume amount="12dB"/>
    </audio-role-source>
</mc-source>

This only occurs in FCPXML 1.11. FCPXML 1.10 outputs correctly.


TO REPRODUCE:

  1. Create a multicam clip with at least two different audio roles. Eg, make a Stereo track into Dual Mono, assign different roles to each.
  2. Select only one of the roles.
  3. Apply both volume and voice isolation adjustments to one of the roles.
  4. Export the XML in v1.11
  5. Try importing the same exported XML file back into Final Cut. Get this error message: Voice Isolation Import Error

EXPECTED BEHAVIOUR
Exporting would be in the correct order, and importing would work correctly.


SCREENSHOTS
Voice Isolation Bug - Inspector
Voice Isolation Import Error


SPECS

  • 2022 16-inch MacBook Pro (M2 Max, 32GB RAM, 1TB SSD)
  • macOS Ventura 13.6.3 (22G436)
  • Final Cut Pro 10.7.1

ADDITIONAL COMMENTS
Workaround: Export in FCPXML v1.10.

@randomeizer
Copy link
Author

I've reported this to Apple but didn't get a feedback ID.

@latenitefilms
Copy link
Contributor

latenitefilms commented Jan 1, 2024

Another example:

invalid-fcpxml
<sync-source sourceID="connected">
    <audio-role-source role="dialogue.ALICE" enabled="0"/>
    <audio-role-source role="dialogue.BOOM"/>
    <audio-role-source role="dialogue.DR ANASTASIA" enabled="0"/>
    <audio-role-source role="dialogue.DR HELENA" enabled="0"/>
    <audio-role-source role="dialogue.DR MARTINEZ" enabled="0"/>
    <audio-role-source role="dialogue.MIX BOOM"/>
    <audio-role-source role="dialogue.MIX LAV"/>
    <audio-role-source role="dialogue.TANAKA">
        <adjust-loudness amount="40" uniformity="3"/>
        <adjust-volume>
            <param name="amount">
                <keyframeAnimation>
                    <keyframe time="1167367663200/23040000s" value="-96dB"/>
                    <keyframe time="1167387650400/23040000s" value="-96dB"/>
                    <keyframe time="1167442571008/23040000s" value="-96dB"/>
                    <keyframe time="1167449233152/23040000s" value="0dB"/>
                    <keyframe time="1167478380032/23040000s" value="0dB"/>
                    <keyframe time="1167489206016/23040000s" value="-96dB"/>
                    <keyframe time="1167584141568/23040000s" value="-96dB"/>
                    <keyframe time="1167592469248/23040000s" value="0dB"/>
                    <keyframe time="1167654094080/23040000s" value="0dB"/>
                    <keyframe time="1167663254528/23040000s" value="-96dB"/>
                </keyframeAnimation>
            </param>
        </adjust-volume>
        <filter-audio ref="r265" name="Channel EQ">
            <data key="effectState">YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVtlZmZlY3RTdGF0ZYABrxAPCwwfICEiIyQlJicoKSorVSRudWxs0w0ODxAXHldOUy5rZXlzWk5TLm9iamVjdHNWJGNsYXNzphESExQVFoACgAOABIAFgAaAB6YYGRobHB2ACIAJgAqAC4AMgA2ADld2ZXJzaW9uXG1hbnVmYWN0dXJlclRkYXRhVG5hbWVUdHlwZVdzdWJ0eXBlEAASRU1BR08Q7OwAAAABAAAAMwAAAEdBTUVUU1BQ7AAAAAAAAAAAAAAAAACgQQAAgECPwjU/AACAPwAAlkIAAAAAAACAPwAAgD8AAMhCAAAAAJmZGT8AAIA/AAB6QwAAAACZmRk/AACAPwCAO0QAAAAAmZkZPwAAgD8AQBxFAAAAAJmZGT8AAIA/AGDqRQAAAAAAAIA/AACAPwBA00QAAABAHoUrPwAAAAAAAAAAMzNDQQAAAAAAAAAAAAAAAAAAAEAAAAAAAAAgQQAAgD8AAIA/AAAAAAAAgD8AAAAAAACAPwAAcEIAAAAAAABwQng4UEwIAAAAWFVudGl0bGVkEmF1ZngQ7NIsLS4vWiRjbGFzc25hbWVYJGNsYXNzZXNcTlNEaWN0aW9uYXJ5oi4wWE5TT2JqZWN0AAgAEQAaACQAKQAyADcASQBMAFgAWgBsAHIAeQCBAIwAkwCaAJwAngCgAKIApACmAK0ArwCxALMAtQC3ALkAuwDDANAA1QDaAN8A5wDpAO4B3QHmAesB7QHyAf0CBgITAhYAAAAAAAACAQAAAAAAAAAxAAAAAAAAAAAAAAAAAAACHw==</data>
            <param name="High Cut On/Off" key="29" value="1"/>
            <param name="High Cut Frequency [Hz]" key="30" value="1690" auxValue="669"/>
            <param name="High Cut Q-Factor" key="32" value="0.67" auxValue="35"/>
        </filter-audio>
        <adjust-voiceIsolation amount="50"/>
    </audio-role-source>
</sync-source>

@latenitefilms
Copy link
Contributor

@randomeizer - Strangely, I'm having trouble manually re-creating this bug. Are you able to share a demonstration library?

@latenitefilms
Copy link
Contributor

For any developers following along, here's my quick and dirty Swift-workaround:

import Foundation

//---------------------------------------------------------
// Correct FCPXML for a bug in Final Cut Pro 10.7.1 when
// using FCPXML v1.11.
//
// See: https://github.com/CommandPost/FCPCafe/issues/314
//---------------------------------------------------------
func correctFCPXML(xmlString: String) -> String {
    guard let xmlData = xmlString.data(using: .utf8) else {
        return xmlString
    }

    let parser = XMLParser(data: xmlData)
    let delegate = FCPXMLWorkaroundsParserDelegate()
    parser.delegate = delegate

    if parser.parse(), delegate.isVersionValid {
        NSLog("[Metaburner Pro Renderer] It's from Final Cut Pro v10.7.1 and FCPXML v1.11 so we'll 'fix it'.")
        return delegate.getCorrectedXML()
    } else {
        return xmlString
    }
}

//---------------------------------------------------------
// Parser Delegate:
//---------------------------------------------------------
class FCPXMLWorkaroundsParserDelegate: NSObject, XMLParserDelegate {
    private var correctedXML: String = ""
    private var currentElement: String = ""
    private var currentAudioRoleSource: String = ""
    var isVersionValid: Bool = false
    private var orderMap: [String: Int] = [
        "adjust-loudness":          1,
        "adjust-noiseReduction":    2,
        "adjust-humReduction":      3,
        "adjust-EQ":                4,
        "adjust-matchEQ":           5,
        "adjust-voiceIsolation":    6,
        "adjust-volume":            7,
        "adjust-panner":            8,
        "filter-audio":             9,
        "mute":                     10
    ]
    private var audioRoleSourceChildren: [String] = []

    func parser(_ parser: XMLParser, foundCharacters string: String) {
        switch currentElement {
            case "audio-role-source":
                currentAudioRoleSource += string
            default:
                correctedXML += string
        }
    }

    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
        currentElement = elementName
        if elementName == "fcpxml" {
            if let version = attributeDict["version"], version == "1.11" {
                isVersionValid = true
            }
            correctedXML += "<\(elementName)"
            attributeDict.forEach { correctedXML += " \($0.key)=\"\($0.value)\"" }
            correctedXML += ">"
        } else if elementName == "audio-role-source" {
            currentAudioRoleSource = "<\(elementName)"
            attributeDict.forEach { currentAudioRoleSource += " \($0.key)=\"\($0.value)\"" }
            currentAudioRoleSource += ">"
        } else if !audioRoleSourceChildren.contains(elementName) {
            correctedXML += "<\(elementName)"
            attributeDict.forEach { correctedXML += " \($0.key)=\"\($0.value)\"" }
            correctedXML += ">"
        }
    }

    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        if elementName == "audio-role-source" {
            reorderAudioRoleSourceChildren()
            correctedXML += currentAudioRoleSource
            correctedXML += "</\(elementName)>"
        } else if !audioRoleSourceChildren.contains(elementName) {
            correctedXML += "</\(elementName)>"
        }
    }

    private func reorderAudioRoleSourceChildren() {
        let sortedChildren = audioRoleSourceChildren.sorted { orderMap[$0]! < orderMap[$1]! }
        sortedChildren.forEach { currentAudioRoleSource += $0 }
        audioRoleSourceChildren.removeAll()
    }

    func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
        NSLog("[Metaburner Pro Renderer] FCPXMLWorkarounds - Parse error: \(parseError.localizedDescription)")
    }

    func getCorrectedXML() -> String {
        return correctedXML
    }
}

@randomeizer
Copy link
Author

Were you able to replicate? I didn't get time to export a library yesterday, sorry.

@randomeizer
Copy link
Author

Voice Isolation Bug.zip

Here is a library which contains a project which will export with the FCPXML bug in v1.11.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants