We can use second timer for bass chords but it won't be sync with first. In any case I commented second timer and added bassToneOutput to the first timer to sync it.
Add new property to Pitch
Code Block func performance(owner: Assessable) { let toneOutput = ToneOutput() let bassToneOutput = ToneOutput() let qPitches:[Pitch] = [.e3, .e3, .f3, .g3, .g3, .f3, .e3, .d3, .c3, .c3, .d3, .e3, .e3, .d3] let hPitches:[Pitch] = [.d3] let notes: [Note] = qPitches.map{Note.quarter($0)} + hPitches.map{Note.half($0)} var pitches = [Pitch]() for note in notes { pitches.append(contentsOf: note.subdivide()) } var index = 0 let interval = TimeInterval(Note.shortestSupportedNoteLength * 0.5) Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { timer in guard index < pitches.count else { toneOutput.stopTones() bassToneOutput.stopTones() timer.invalidate() owner.endPerformance() return } toneOutput.play(tone: Tone(pitch: pitches[index].frequency, volume: 0.3)) bassToneOutput.play(tone: Tone(pitch: pitches[index].bassFrequency, volume: 0.3)) index += 1 } // Second timer but it won’t with the first timer. // Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { timer in // guard index < pitches.count else { // bassToneOutput.stopTones() // timer.invalidate() // owner.endPerformance() // return // } // // bassToneOutput.play(tone: Tone(pitch: pitches[index].bassFrequency, volume: 0.3)) // //index += 1 // } owner.endPerformance() }
Add new property to Pitch
Code Block language public var bassFrequency: Double { return self.rawValue/2.0 }