Вызов случайных AKPlayers в AKSequencer с повторяющимися случайными результатами - PullRequest
0 голосов
/ 14 сентября 2018

Это проект воспроизведения нескольких аудиофайлов, над которым я сейчас работаю, где несколько AKPlayers воспроизводятся в произвольном порядке через AKSequencer.

Во-первых, у меня есть массив имен файлов:

Let filenames = [“1.mp3”, “2.mp3, “3.mp3”, … “10.mp3”]

Это загружается в AKPlayer индивидуально, чтобы потом вызывать его в случайном порядке:

Let players: [AKPlayer] = {
    Do {
        Let filenames = [“1.mp3”, “2.mp3, “3.mp3”, … “10.mp3”]
        Return try filenames.map { AKPlayer(audioFile: try AKAudioFile(readRileName: $0)) }
    } catch {
        fatalError()
    }
}()

Затем я вызвал AKPlayer через AKsequencer, запустив его через функцию 'playRandom':

Let sequencer = AKSequencer()
Let callbackInst = AKCallbackInstrument()

func playRandom() {
    let playerIndex = Int(arc4random_uniform(UInt32(players.count)))
    players[playerIndex].play()
}

func addTracks() {
    let track = sequencer.newTrack()!
    track.add(noteNumber: 48, velocity: 127, position: AKDuration(beats: 0), duration: AKDuration(beats: 16), channel: 0)
    track.setMIDIOutput(callbackInst.midiIn)
    callbackInst.callback = { status, note, vel in
        guard status == .noteOn else { return }
        self.playRandom()
        }
    }

Наконец, я установил AKPlayer как AudioKit.output и запустил секвенсор.Пока это было успешно!Секвенсор играет AKPlayer без проблем, в случайном порядке.

Но я хотел попробовать другой тип случайности: повторять случайно выбранного игрока 2 или 3 раза .(например, 2, 2, 3, 3, 3, 1, 1, 5, 5, 5, 9, 9,…). Сейчас «playRandom» просто выбирает разные AKPlayer для каждого повтора.

В качестве одного решения, благодаря мастерам StackOverFlow, я попробовал что-то вроде:

class RandomWithRepeats {
var range: ClosedRange<Int>
var repeatRange: ClosedRange<Int>
var repeatCount = 0
var value = 0

init(range: ClosedRange<Int>, repeatRange: ClosedRange<Int>) {
    self.range = range
    self.repeatRange = repeatRange
}

// generate a random number in a range
// Just use Int.random(in:) with Swift 4.2 and later
func random(in range: ClosedRange<Int>) -> Int {
    return Int(arc4random_uniform(UInt32(range.upperBound - range.lowerBound + 1))) + range.lowerBound
}

func nextValue() -> Int {
    // if repeatCount is 0, its time to generate a new value and
    // a new repeatCount
    if repeatCount == 0 {
        // For Swift 4.2, just use Int.random(in:) instead
        value = self.random(in: range)
        repeatCount = self.random(in: repeatRange)
    }

    repeatCount -= 1
    return value
}
}

А потом я изменил playRandom функцию, например:

func playRandom() {
    Let rand = randomWithRepeats(range: 1…players.count, repeatRange: 2…3)
    Do { players[rand.nextValue()].play() }
}

Оказывается, это точно так жерезультат, потому что сама функция playRandom запускает (AKSequencer) каждый повтор, так что она фактически не «повторяет» случайный AKPlayer 2 или 3 раза.Могу ли я решить эту проблему по-другому?Очень признателен.<3 </p>

1 Ответ

0 голосов
/ 14 сентября 2018

Задача класса RandomWithRepeats состоит в том, чтобы отслеживать, когда доставить вам другой экземпляр AKPlayer, но вы создаете новый экземпляр RandomWithRepeats каждый раз, когда вызываете playRandom(), чтобы он мог ' не отследить ничего.

Создайте отдельный экземпляр RandomWithRepeats при создании массива игроков и используйте этот экземпляр в методе playRandom().

let rand = RandomWithRepeats(range: 0 ... players.count, repeatRange: 2 ... 3)

func playRandom() {
     try? players[rand.nextValue()].play() 
}

Для более чистого решения вы можете инкапсулировать логику RandomWithRepeats вместе с массивом AKPlayer в один класс, такой как класс RandomlyRepeatingPlayer.

...