如何用AudioKit Sequencer在指定位置播放本地音频文件?
Alright, let's get this sorted! The key here is to swap out the default AKSynthSnare with AKPlayer instances (one for your high-frequency audio, one for low) and map each character in your binary string to a timed event in the AudioKit Sequencer. Here's how to do it step by step:
Step 1: Prepare Your Audio Players
First, we'll create two AKPlayer objects to handle your local high and low frequency audio files. These players will be triggered by the sequencer at the correct positions.
import AudioKit class AudioSequencePlayer { // Core audio setup let engine = AudioEngine() let mixer = Mixer() // Players for high/low frequency sounds var highFreqPlayer: AKPlayer! var lowFreqPlayer: AKPlayer! // Sequencer and track to handle timing var sequencer: Sequencer! var track: Track! init() { // Load local audio files - replace with your actual file names/extensions guard let highFreqURL = Bundle.main.url(forResource: "high_tone", withExtension: "wav"), let lowFreqURL = Bundle.main.url(forResource: "low_tone", withExtension: "wav") else { fatalError("Couldn't locate audio files in the app bundle!") } // Initialize players and configure for single-shot playback highFreqPlayer = AKPlayer(url: highFreqURL) lowFreqPlayer = AKPlayer(url: lowFreqURL) highFreqPlayer.isLooping = false lowFreqPlayer.isLooping = false // Route audio flow: players → mixer → engine output highFreqPlayer >>> mixer lowFreqPlayer >>> mixer engine.output = mixer } }
Step 2: Map Binary String to Sequencer Timed Events
Next, we'll add a method to parse your binary string, iterate over each character, and place trigger events at the exact beat positions using AKDuration(beats:).
Add this method inside the AudioSequencePlayer class:
func setupSequence(with binaryString: String) { // Reset sequencer and track sequencer = Sequencer() track = sequencer.addTrack() track.clear() // Loop through each character in the binary input for (index, char) in binaryString.enumerated() { // Calculate position: each character corresponds to 1 beat let eventPosition = AKDuration(beats: Double(index)) // Assign unique MIDI note numbers to distinguish high/low triggers let triggerNote: MIDINoteNumber = char == "1" ? 60 : 40 // Add the note event to the track (short duration to avoid hanging notes) track.add(triggerNote, velocity: 127, position: eventPosition, duration: AKDuration(beats: 0.4)) } // Attach a listener to catch MIDI events and trigger the right player sequencer.addMIDIListener(self) }
Step 3: Trigger Players via MIDI Events
We need to conform to AKMIDIListener to respond to the sequencer's note events and play the corresponding audio file. Add this extension:
extension AudioSequencePlayer: AKMIDIListener { func receivedMIDINoteOn(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel) { // Trigger the correct player based on our assigned note numbers if noteNumber == 60 { // Reset and play high frequency sound (ensures it starts from the top) highFreqPlayer.stop() highFreqPlayer.play() } else if noteNumber == 40 { lowFreqPlayer.stop() lowFreqPlayer.play() } } }
Step 4: Control Sequence Playback
Add these helper methods to start/stop the sequence and manage the audio engine:
func startSequence() { do { try engine.start() sequencer.play() } catch { print("Failed to start audio engine: \(error.localizedDescription)") } } func stopSequence() { sequencer.stop() engine.stop() highFreqPlayer.stop() lowFreqPlayer.stop() }
How to Use the Class
Initialize and trigger your sequence with a binary string like this:
let audioPlayer = AudioSequencePlayer() audioPlayer.setupSequence(with: "1100011010") audioPlayer.startSequence() // To stop playback later: // audioPlayer.stopSequence()
Quick Tips
- Replace
"high_tone.wav"and"low_tone.wav"with your actual local audio file names and extensions (supports most common formats like MP3, WAV). - Adjust the
durationparameter intrack.add()if you need longer/shorter playback of each sound. - The
stop()call beforeplay()ensures the audio file restarts from the beginning every time it's triggered, even if it was already playing.
内容的提问来源于stack exchange,提问作者Jonas0000

