When I try to swap between AudioKit players, I have different types of problems. I'll add the code, but I'll try to simplify it.
Let's say, I have five players and one recorder for those players, I'm recording player1 once and player2 once, if I'm trying to swap between them, the swap succeeds. If I'm recording player1 twice and player2 twice, the swap succeeds, but if I'm recording player1 twice and player2 once, during the swap it says that player1 doesn't exist(nil) - Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value.
Another problem: I've recorded player1 twice, player2 twice and player3 and player4 once, I'm trying to swap between player3 and player4 but it says that player3 or player4 doesn't exist(nil) - Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value. Only if player1 and player2 recorded once, or player3 and player4 recorded twice, it succeeds.
Last problem: I've recorded player1 once and player2 once, I want to swap player1 with empty player3, it succeeds. When I try to swap between player2 and player1(that is now supposed to be empty), it says player1 doesn't exist(nil) - Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value, When player1 now is supposed to be swapped with the recording on player2.
Help me figure out why it's so frustrating. here's the code:
@objc func startStopClipRecording1(button: UIButton, event: UIEvent) {
switch self.state {
case .readyToRecord :
if self.recorded1 == true{
while multiPlayers.contains(player1) {
if let itemToRemoveIndex = multiPlayers.firstIndex(of: player1) {
multiPlayers.remove(at: itemToRemoveIndex)
}
}
}
self.plot?.node = self.mic
self.state = .recording
_ = AVAudioTime(hostTime: UInt64(event.timestamp * secondsToTicks))
guard let lastRenderHostTime = mainMixer.avAudioNode.lastRenderTime?.hostTime else { fatalError("Engine not running!") }
let audioSession = AKSettings.session
let bufferDurationTicks = UInt64(audioSession.ioBufferDuration * secondsToTicks)
let outputLatencyTicks = UInt64(audioSession.outputLatency * secondsToTicks)
let inputLatencyTicks = UInt64(audioSession.inputLatency * secondsToTicks)
let nextRenderHostTime = lastRenderHostTime + bufferDurationTicks
let renderAfterNextHostTime = nextRenderHostTime + bufferDurationTicks
let startTimeHost = renderAfterNextHostTime + outputLatencyTicks
let playbackStartTime = AVAudioTime(hostTime: startTimeHost - outputLatencyTicks)
let recordingStartTime = AVAudioTime(hostTime: startTimeHost + inputLatencyTicks)
metronome.beatTime = 0
directRecorder?.currentTime = 0
var bars = 30 / (4 * (60 / metronome.tempo))
bars.round(.towardZero)
let durationClipRec = bars * (4 * (60 / metronome.tempo))
try? directRecorder?.recordClip(time: 0, duration: durationClipRec, tap: nil) { result in
switch result {
case .error(let error):
AKLog(error)
return
case .clip(let clip):
AKLog("direct.duration \(clip.duration)")
AKLog("direct.StartTime \(clip.startTime)")
do {
let urlInDocs = FileManager.docs.appendingPathComponent(self.filename1).appendingPathExtension(clip.url.pathExtension)
if FileManager.default.fileExists(atPath: urlInDocs.path){
FileManager.emtpyDocumentsDirectory()
}
try FileManager.default.moveItem(at: clip.url, to: urlInDocs)
self.url1 = urlInDocs
self.clip1 = clip
AKLog("Direct saved at " + urlInDocs.path)
} catch {
AKLog(error)
}
}
}
let todoDelay = 0.001
if self.recordedButNot1 == true{
multiPlayers.forEach { player in
player.play(at: playbackStartTime) }
metronome.play(at: recordingStartTime + todoDelay)
directRecorder?.start(at: recordingStartTime)
recTimer1 = Timer.scheduledTimer(timeInterval: 30.2, target:self, selector:#selector(recAction1), userInfo:nil, repeats:false)
}else{
metronome.play(at: recordingStartTime + todoDelay)
directRecorder?.start(at: recordingStartTime)
recTimer1 = Timer.scheduledTimer(timeInterval: 30.2, target:self, selector:#selector(recAction1), userInfo:nil, repeats:false)
}
case .recording :
directRecorder?.stopRecording()
directRecorder?.stop()
recordAction1()
}
}
@objc func recAction1(){
recordAction1()
}
func recordAction1(){
self.addPlayer1(withFileURL: url1)
self.instButton1.isHidden = false
swapMButton.isUserInteractionEnabled = true
self.plot?.node = nil
self.recorded1 = true
self.firstRecordDuration = true
self.recordedButNot2 = true
self.recordedButNot3 = true
self.recordedButNot4 = true
self.recordedButNot5 = true
self.metronome.stop()
self.setupUIForPlaying()
self.setupUIForRecording1()
recTimer1.invalidate()
}
private func addPlayer1(withFileURL url: URL) {
player1 = AKPlayer(url: url)
player1.buffering = .always
player1.prepare()
player1.pan = 0
self.multiPlayers.append(self.player1)
self.mainMixer.connect(input: self.player1)
}
func swap(_ str1: inout URL, _ str2: inout URL) {
(str1, str2) = (str2, str1)
}
func swapPlayers(AKplayer: AKPlayer, urlString: URL, timeLabel1: UITextField, timeLabel2: UITextField,
textField1: UITextField, textField2: UITextField, playerName1: String, playerName2: String,
instrument1: InstrumentButton, instrument2: InstrumentButton, isPlayer2Recorded: Bool, button1:
UIImageView, button2: UIImageView, maskLayer: CAShapeLayer, view: UIView){
while self.multiPlayers.contains(AKplayer) {
if let itemToRemoveIndex = self.multiPlayers.firstIndex(of: AKplayer) {
self.multiPlayers.remove(at: itemToRemoveIndex)
}
}
if playerName1 == self.recordingName1{
fileName = filename1
clip6 = clip1
}
if playerName1 == self.recordingName2{
fileName = filename2
clip6 = clip2
}
if playerName1 == self.recordingName3{
fileName = filename3
clip6 = clip3
}
if playerName1 == self.recordingName4{
fileName = filename4
clip6 = clip4
}
if playerName1 == self.recordingName5{
fileName = filename5
clip6 = clip5
}
let myLayer = plot!.waveformLayer!
myLayer.path = maskLayer.path
view.layer.addSublayer(myLayer)
self.plot?.clear()
instTextField6.text = textField1.text
recordingTimeLabel6.text = timeLabel1.text
if isPlayer2Recorded == true{
if playerName2 == self.recordingName1{
AKplayer2 = player1
}
if playerName2 == self.recordingName2{
AKplayer2 = player2
}
if playerName2 == self.recordingName3{
AKplayer2 = player3
}
if playerName2 == self.recordingName4{
AKplayer2 = player4
}
if playerName2 == self.recordingName5{
AKplayer2 = player5
}
textField1.text = textField2.text
textField2.text = instTextField6.text
selectedInstrumentToImage(button: instrument1, textField: textField1)
selectedInstrumentToImage(button: instrument2, textField: textField2)
timeLabel1.text = timeLabel2.text
timeLabel2.text = recordingTimeLabel6.text
while self.multiPlayers.contains(AKplayer2) {
if let itemToRemoveIndex = self.multiPlayers.firstIndex(of: AKplayer2) {
self.multiPlayers.remove(at: itemToRemoveIndex)
}
}
if playerName1 == self.recordingName1{
if playerName2 == self.recordingName2{
print(url1!)
print(url2!)
swap(&url1, &url2)
print(url1!)
print(url2!)
addPlayer1(withFileURL: url1)
addPlayer2(withFileURL: url2)
}
if playerName2 == self.recordingName3{
self.url1 = self.url3
self.url3 = self.url6
addPlayer1(withFileURL: url1)
addPlayer3(withFileURL: url3)
}
if playerName2 == self.recordingName4{
self.url1 = self.url4
self.url4 = self.url6
addPlayer1(withFileURL: url1)
addPlayer4(withFileURL: url4)
}
if playerName2 == self.recordingName5{
self.url1 = self.url5
self.url5 = self.url6
addPlayer1(withFileURL: url1)
addPlayer5(withFileURL: url5)
}
}
if playerName1 == self.recordingName2{
if playerName2 == self.recordingName1{
self.url2 = self.url1
self.url1 = self.url6
addPlayer2(withFileURL: url2)
addPlayer1(withFileURL: url1)
}
if playerName2 == self.recordingName3{
self.url2 = self.url3
self.url3 = self.url6
addPlayer2(withFileURL: url2)
addPlayer3(withFileURL: url3)
}
if playerName2 == self.recordingName4{
self.url2 = self.url4
self.url4 = self.url6
addPlayer2(withFileURL: url2)
addPlayer4(withFileURL: url4)
}
if playerName2 == self.recordingName5{
self.url2 = self.url5
self.url5 = self.url6
addPlayer2(withFileURL: url2)
addPlayer5(withFileURL: url5)
}
}
if playerName1 == self.recordingName3{
if playerName2 == self.recordingName1{
self.url3 = self.url1
self.url1 = self.url6
addPlayer3(withFileURL: url3)
addPlayer1(withFileURL: url1)
}
if playerName2 == self.recordingName2{
self.url3 = self.url2
self.url2 = self.url6
addPlayer3(withFileURL: url3)
addPlayer2(withFileURL: url2)
}
if playerName2 == self.recordingName4{
self.url3 = self.url4
self.url4 = self.url6
addPlayer3(withFileURL: url3)
addPlayer4(withFileURL: url4)
}
if playerName2 == self.recordingName5{
self.url3 = self.url5
self.url5 = self.url6
addPlayer3(withFileURL: url3)
addPlayer5(withFileURL: url5)
}
}
if playerName1 == self.recordingName4{
if playerName2 == self.recordingName1{
self.url4 = self.url1
self.url1 = self.url6
addPlayer4(withFileURL: url4)
addPlayer1(withFileURL: url1)
}
if playerName2 == self.recordingName2{
self.url4 = self.url2
self.url2 = self.url6
addPlayer4(withFileURL: url4)
addPlayer2(withFileURL: url2)
}
if playerName2 == self.recordingName3{
self.url4 = self.url3
self.url3 = self.url6
addPlayer4(withFileURL: url4)
addPlayer3(withFileURL: url3)
}
if playerName2 == self.recordingName5{
self.url4 = self.url5
self.url5 = self.url6
addPlayer4(withFileURL: url4)
addPlayer5(withFileURL: url5)
}
}
if playerName1 == self.recordingName5{
if playerName2 == self.recordingName1{
self.url5 = self.url1
self.url1 = self.url6
addPlayer5(withFileURL: url5)
addPlayer1(withFileURL: url1)
}
if playerName2 == self.recordingName2{
self.url5 = self.url2
self.url2 = self.url6
addPlayer5(withFileURL: url5)
addPlayer2(withFileURL: url2)
}
if playerName2 == self.recordingName3{
self.url5 = self.url3
self.url3 = self.url6
addPlayer5(withFileURL: url5)
addPlayer3(withFileURL: url3)
}
if playerName2 == self.recordingName4{
self.url5 = self.url4
self.url4 = self.url6
addPlayer5(withFileURL: url5)
addPlayer4(withFileURL: url4)
}
}
}else{
button1.isUserInteractionEnabled = false
button2.isUserInteractionEnabled = true
textField1.text = ""
textField2.text = instTextField6.text
selectedInstrumentToImage(button: instrument1, textField: textField1)
selectedInstrumentToImage(button: instrument2, textField: textField2)
timeLabel1.text = timeLabel2.text
timeLabel2.text = recordingTimeLabel6.text
if playerName1 == self.recordingName1{
recorded1 = false
reverb1.outputNode.removeTap(onBus: 0)
delay1.outputNode.removeTap(onBus: 0)
player1.outputNode.removeTap(onBus: 0)
player1 = nil
delaySlider1.isEnabled = false
reverbSlider1.isEnabled = false
volumeSlider1.isEnabled = false
soloButton1.isEnabled = false
muteButton1.isEnabled = false
if playerName2 == self.recordingName2{
self.url1 = nil
self.clip1 = nil
self.url2 = self.url6
addPlayer2(withFileURL: url2)
recorded2 = true
}
if playerName2 == self.recordingName3{
self.url1 = nil
self.clip1 = nil
self.url3 = self.url6
addPlayer3(withFileURL: url3)
recorded3 = true
}
if playerName2 == self.recordingName4{
self.url1 = nil
self.clip1 = nil
self.url4 = self.url6
addPlayer4(withFileURL: url4)
recorded4 = true
}
if playerName2 == self.recordingName5{
self.url1 = nil
self.clip1 = nil
self.url5 = self.url6
addPlayer5(withFileURL: url5)
recorded5 = true
}
}
if playerName1 == self.recordingName2{
recorded2 = false
reverb2.outputNode.removeTap(onBus: 0)
delay2.outputNode.removeTap(onBus: 0)
player2.outputNode.removeTap(onBus: 0)
player2 = nil
delaySlider2.isEnabled = false
reverbSlider2.isEnabled = false
volumeSlider2.isEnabled = false
soloButton2.isEnabled = false
muteButton2.isEnabled = false
if playerName2 == self.recordingName1{
self.url2 = nil
self.clip2 = nil
self.url1 = self.url6
addPlayer1(withFileURL: url1)
recorded1 = true
}
if playerName2 == self.recordingName3{
self.url2 = nil
self.clip2 = nil
self.url3 = self.url6
addPlayer3(withFileURL: url3)
recorded3 = true
}
if playerName2 == self.recordingName4{
self.url2 = nil
self.clip2 = nil
self.url4 = self.url6
addPlayer4(withFileURL: url4)
recorded4 = true
}
if playerName2 == self.recordingName5{
self.url2 = nil
self.clip2 = nil
self.url5 = self.url6
addPlayer5(withFileURL: url5)
recorded5 = true
}
}
if playerName1 == self.recordingName3{
recorded3 = false
reverb3.outputNode.removeTap(onBus: 0)
delay3.outputNode.removeTap(onBus: 0)
player3.outputNode.removeTap(onBus: 0)
player3 = nil
delaySlider3.isEnabled = false
reverbSlider3.isEnabled = false
volumeSlider3.isEnabled = false
soloButton3.isEnabled = false
muteButton3.isEnabled = false
if playerName2 == self.recordingName1{
self.url3 = nil
self.clip3 = nil
self.url1 = self.url6
addPlayer1(withFileURL: url1)
recorded1 = true
}
if playerName2 == self.recordingName2{
self.url3 = nil
self.clip3 = nil
self.url2 = self.url6
addPlayer2(withFileURL: url2)
recorded2 = true
}
if playerName2 == self.recordingName4{
self.url3 = nil
self.clip3 = nil
self.url4 = self.url6
addPlayer4(withFileURL: url4)
recorded4 = true
}
if playerName2 == self.recordingName5{
self.url3 = nil
self.clip3 = nil
self.url5 = self.url6
addPlayer5(withFileURL: url5)
recorded5 = true
}
}
if playerName1 == self.recordingName4{
recorded4 = false
reverb4.outputNode.removeTap(onBus: 0)
delay4.outputNode.removeTap(onBus: 0)
player4.outputNode.removeTap(onBus: 0)
player4 = nil
delaySlider4.isEnabled = false
reverbSlider4.isEnabled = false
volumeSlider4.isEnabled = false
soloButton4.isEnabled = false
muteButton4.isEnabled = false
if playerName2 == self.recordingName1{
self.url4 = nil
self.clip4 = nil
self.url1 = self.url6
addPlayer1(withFileURL: url1)
recorded1 = true
}
if playerName2 == self.recordingName2{
self.url4 = nil
self.clip4 = nil
self.url2 = self.url6
addPlayer2(withFileURL: url2)
recorded2 = true
}
if playerName2 == self.recordingName3{
self.url4 = nil
self.clip4 = nil
self.url3 = self.url6
addPlayer3(withFileURL: url3)
recorded3 = true
}
if playerName2 == self.recordingName5{
self.url4 = nil
self.clip4 = nil
self.url5 = self.url6
addPlayer5(withFileURL: url5)
recorded5 = true
}
}
if playerName1 == self.recordingName5{
recorded5 = false
reverb5.outputNode.removeTap(onBus: 0)
delay5.outputNode.removeTap(onBus: 0)
player5.outputNode.removeTap(onBus: 0)
player5 = nil
delaySlider5.isEnabled = false
reverbSlider5.isEnabled = false
volumeSlider5.isEnabled = false
soloButton5.isEnabled = false
muteButton5.isEnabled = false
if playerName2 == self.recordingName1{
self.url5 = nil
self.clip5 = nil
self.url1 = self.url6
addPlayer1(withFileURL: url1)
recorded1 = true
}
if playerName2 == self.recordingName2{
self.url5 = nil
self.clip5 = nil
self.url2 = self.url6
addPlayer2(withFileURL: url2)
recorded2 = true
}
if playerName2 == self.recordingName3{
self.url5 = nil
self.clip5 = nil
self.url3 = self.url6
addPlayer3(withFileURL: url3)
recorded3 = true
}
if playerName2 == self.recordingName4{
self.url5 = nil
self.clip5 = nil
self.url4 = self.url6
addPlayer4(withFileURL: url4)
recorded4 = true
}
}
let urlInDocs = FileManager.docs.appendingPathComponent(self.fileName!).appendingPathExtension(clip6!.url.pathExtension)
if FileManager.default.fileExists(atPath: urlInDocs.path){
FileManager.emtpyDocumentsDirectory()
}
}
}