Group Group Group Group Group Group Group Group Group

Unable to spot why a particular method isn't working

I’m unable to spot where I’ve gone wrong in writing the code below, except that it’s probably somewhere in the insertCheckboxArguments method.

What this should do is define the ffmpegArguments array based on the conversionSelection method, then insert additional arguments into the array based on whether one or both of two checkboxes is checked, and then pass the (maybe altered, maybe not) array into the ffmpegConvert process to be used as the convertTask.arguments.

The conversionSelection method works fine. The ffmpegConvert process works fine when used with the ffmpegArguments array created by the conversionSelection method. The print statements confirm that the getAudiobookDuration method is working as it should be…

…but when I run these methods all together with the ‘insertCheckboxArguments’ method, the ffmpeg process runs, but it produces a file that is 0.0 seconds long. Basically, it’s just the audiobook cover and metadata without the audio.

Because I’m so new at this, I’m still…fuzzy…on when it’s appropriate to use function parameters and returns, so that may be what I’m missing to pull this all together. But every time I go back to the tutorials and documentation to read up on that again, it seems to make sense to me in the context of the tutorial, but I fail to make the leap to applying it to my own situation here.

I suppose I could add additional switches into the conversionSelection method in order to combine it with the insertCheckboxArguments argument, but that feels like cheating. And it would definitely get sloppy and repetitive. Surely there’s a cleaner way.

// select a conversion preset
func conversionSelection() {
	if inputFileUrl != nil {
		let conversionChoice = conversionOptionsPopup.indexOfSelectedItem
		switch conversionChoice {
			case 1 :
				outputExtension = ".mp3"
				ffmpegArguments = [
					"-hide_banner",
					"-i", "\(inputFilePath)",
					"-c:a", "libmp3lame",
					"\(outputTextDisplay.stringValue)"
			]
			case 2:
				outputExtension = ".flac"
				ffmpegArguments = [
					"-hide_banner",
					"-i", "\(inputFilePath)",
					"-c:a", "flac",
					"\(outputTextDisplay.stringValue)"
			]
			default :
				outputExtension = ".m4b"
				ffmpegArguments = [
					"-hide_banner",
					"-i", "\(inputFilePath)",
					"-c", "copy",
					"\(outputTextDisplay.stringValue)"
			]
		}
	}
}

// get audiobook length in order to trim from the end
	func getAudiobookDuration() {
		let audioAsset = AVURLAsset.init(url: inputFileUrl!, options: nil)
		audioAsset.loadValuesAsynchronously(forKeys: ["duration"]) {
			var error: NSError? = nil
			let status = audioAsset.statusOfValue(forKey: "duration", error: &error)
			switch status {
				case .loaded: // Sucessfully loaded. Continue processing.
					let duration = audioAsset.duration
					self.fileDuration = CMTimeGetSeconds(duration)
					self.trimmedAudio = self.fileDuration - 4.2
					print("Audio Duration is: \(self.fileDuration)")
					print("TrimmedAudioDuration is: \(self.trimmedAudio)")
					break
				case .failed: break // Handle error
				case .cancelled: break // Terminate processing
				default: break // Handle all other cases
		}
	}
}

// check if verbosity checkbox is marked, if so, add verbosity argument
// check if trimming checkbox is marked, if so, add trimming argument
// if both are marked, add both
func insertCheckboxArguments() {
	conversionSelection()
	getAudiobookDuration()
	let verbositySelector = ffmpegVerboseLogCheckbox.state
	let trimEndSelector = trimInOutClipsCheckbox.state
	switch verbositySelector {
		case .on :
			switch trimEndSelector {
				case .off :
					ffmpegArguments.insert(contentsOf: ["-v", "verbose"], at: 1) // verbosity on, end trim off
				default :
					ffmpegArguments.insert(contentsOf: ["-v", "verbose"], at: 1) // both on
					ffmpegArguments.insert(contentsOf: ["-ss", "00:00:02.000", "-t", "\(trimmedAudio)"], at: 3)
		}
		default :
			switch trimEndSelector {
				case .off : // neither on
					break
				default : // end trim on
					ffmpegArguments.insert(contentsOf: ["-ss", "00:00:02.000", "-t", "\(trimmedAudio)"], at: 1)
		}
	}
}

// MARK: ffmpeg code
func ffmpegConvert() {
	insertCheckboxArguments()
	guard let launchPath = Bundle.main.path(forResource: "ffmpeg", ofType: "") else { return }
	do {
		let convertTask: Process = Process()
		convertTask.launchPath = launchPath
		convertTask.arguments = ffmpegArguments
		convertTask.standardInput = FileHandle.nullDevice
		convertTask.launch()
		convertTask.waitUntilExit()
	}
}

@ncrusher Do you still have issues with this?

I did eventually get it running, though it’s evolved so many times since that I can’t remember precisely what I did to get it to work. What I have now is:

func conversionSelection() -> String {
    var outputExtension: String = ""
    if inputPathDisplay != nil {
        let conversionChoice = conversionOptionsPopup.indexOfSelectedItem
        switch conversionChoice {
        case 1 :
            outputExtension = ".mp3"
        case 2:
            outputExtension = ".flac"
        default :
            outputExtension = ".m4b"
        }
    }
    return outputExtension
}

// create default argument template
func buildConversionArgs() -> [String] {
    var ffmpegArguments = [String]()
    let activationBytes = UserDefaults.standard.string(forKey:"ActivationBytes")!
    let input = inputPathDisplay.stringValue
    let output = outputPathDisplay.stringValue
    ffmpegArguments = [
        "-y", "-hide_banner",
        "-activation_bytes", activationBytes,
        "-i", input,
        output
    ]
    return ffmpegArguments
}

// insert specific argument for file conversion type
func getConversionMethod() -> [String] {
    var ffmpegArguments = buildConversionArgs()
    let fileExtension = conversionSelection()
    switch fileExtension {
    case ".mp3" :
        ffmpegArguments.insert(contentsOf: ["-c:a", "libmp3lame"], at: 6)
    case ".flac" :
        ffmpegArguments.insert(contentsOf: ["-c:a", "flac"], at: 6)
    default :
        ffmpegArguments.insert(contentsOf: ["-c", "copy"], at: 6)
    }
    return ffmpegArguments
}

// insert specific argument for audio duration and output type
func insertCheckboxArgs(audioFile: AudioFile) -> [String] {
    var ffmpegArguments = getConversionMethod()
    var trimmedAudio: Double = 0.000
        do {
            trimmedAudio = try audioFile.trimDuration()
        } catch {}
    let verbositySelector = verboseOutputCheckbox.state
    let trimEndsSelector = trimEndsCheckbox.state
    switch verbositySelector {
    case .on :
        switch trimEndsSelector {
        case .off :
            ffmpegArguments.insert(contentsOf: ["-v", "verbose"], at: 2)
        default :
            ffmpegArguments.insert(contentsOf: ["-v", "verbose"], at: 2)
            ffmpegArguments.insert(contentsOf: ["-ss", "00:00:02.000", "-t", "\(trimmedAudio)"], at: 6)
        }
    default :
        switch trimEndsSelector {
        case .off :
            break
        default :
            ffmpegArguments.insert(contentsOf: ["-ss", "00:00:02.000", "-t", "\(trimmedAudio)"], at: 4)
        }
    }
    return ffmpegArguments
}

And then the conversion task has become a whole different thing.

Thank you!