问题
I run several AKPlayer with different files and the same length - the first one starts from the beginning, the others start by the button relative to the time of the first. Files are seamless, worth buffering type = .always, loop = true. If AKPlayer did not start from the beginning, then only that part of the track from which the track began to play to the end, and when the loop occurs, starts StartTime is not a zero value. It is necessary that when a loop is played all the tracks from the beginning. With AKWaveTable, everything works adequately, but there are no pan and pitch settings in the player.
Here is a sample code. In the original, I use an array of players and in a loop I upload all the files to my players. I’m doing something like drummachine - several audio files are playing, and I can turn on / off other files in parallel with respect to the time the player was first started. Each file is the same in duration. When I do the same in AKWaveTable, then everything works correctly, but in the future it does not suit me. In this example, I run the playPlayer1 method first and after a while I run playPlayer2. When Player1 starts the loop from the beginning, then Player2 starts the loop from the previous currentTime (for example, from the middle of the file) and its length becomes equal forever (endTime - currentTime)
var player1: AKPlayer!
var player2: AKPlayer!
var playersMixer: AKMixer!
init() {
do {
let file1 = try AKAudioFile(readFileName: "Audio/file1.m4a")
let file2 = try AKAudioFile(readFileName: "Audio/file2.m4a")
player1.load(audioFile: file1)
player2.load(audioFile: file2)
} catch {
print(error.localizedDescription)
}
player1.buffering = .always
player1.isLooping = true
player2.buffering = .always
player2.isLooping = true
playersMixer = AKMixer (player1,player2)
AudioKit.output = playersMixer
do {
try AudioKit.start()
} catch {
print(error.localizedDescription)
}
}
func playPlayer1() {
player1.play()
}
func playPlayer2() {
player2.play(from: currentTime)
}
var currentTime: Double {
get {
if player1.isPlaying {
return player1.currentTime
}
return 0
}
}
回答1:
I think that's a missing feature in AudioKit or a bug. Meanwhile, the current version does use the startTime
for the loop points as we can see in the source code (https://github.com/AudioKit/AudioKit/blob/master/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift)
Meanwhile, there's a solution I found and hope it's useful for other readers:
player.isLooping = false
player.buffering = .dynamic
player.completionHandler = {
player.isLooping = true
player.buffering = .always
player.play(from: 0, to: player.duration)
}
player.play(from: masterPlayer.currentTime)
What I'm doing is to create a player and set .isLooping
and .buffering
falsely and call .play
to run it as a one-time, or a single shot play! A .completionHandler
callback is called on complete, where I set .isLooping
and .buffering
positively. Finally, call .play
setting the desired loop points using the properties from
and to
from self
. The masterPlayer
refers to a separate player
that is used as a reference to get the current play position, I know it's easy to understand but just to avoid assumptions.
EDIT:
After going throw tests, I found an issue that I've reported and deleted before (Is synchronised looping supported for AKPlayers that are multiples in their duration?) and had to reopen, so hopefully, I get an answer and will help understand if it's supposed to work or not.
Also forced player
to detach
and created a new one:
player.completionHandler = {
player.detach()
let player = self.createPlayer(audioFile: audioFile)
self.connectPlayerToMixer(player)
player.isLooping = true
player.buffering = .always
player.startTime = 0
player.endTime = audioFile.duration
player.play(at: AVAudioTime.now())
}
I've now tested AKWaveTable
and hopefully, I did it correctly but it also fails just after the recording that is twice the size of previews recording, for example:
- Loop1 > 1 2 3 4
- Loop2 > 1 2 3 4
- Loop3 > 1 2 3 4 5 6 7 8
- Loop4 > 1 2 3 4
- Loop5 > 5 6 7 8 (recorded as 1 2 3 4 5 6 7 8, but plays back as 5 6 7 8)
I'll have to go back and test the original AKNodeRecorder
to see if the behaviour is similar, but for the moment I'll try another tests with AKWaveTable
.
- After some time testing * *
Here's the audio recording describing the issue above:
https://drive.google.com/open?id=1zxIJgFFvTwGsve11RFpc-_Z94gEEzql7
After looking at the problem for some time, and all the research I found what seems to be a solution. By shifting the procedure that is used! Instead of setting the player to start along the current time, should instead schedule it to start from the start time. This because the start time is what is used for the loop start and endpoints! To learn a bit more follow the link to another StackOverflow post I've posted before (Solution is presented here (Is synchronised looping supported for AKPlayers that are multiples in their duration?), thanks!
来源:https://stackoverflow.com/questions/57764856/how-to-use-the-loop-if-the-track-was-not-started-from-the-beginning-with-buffer