Audiokit AKSampler 在单独的 class 中作为 AKNode/AKPolyphonicNode
Audiokit AKSampler as a AKNode/AKPolyphonicNode in a separate class
如何将 AKSampler 分离成 class?
例如:
SoundEngine.swift
import AudioKit
import MySampler
final class SoundEngine : ObservableObject {
static let shared = SoundEngine()
let mySampler = MySampler()
init() {
mySampler.loadSamples('samples1')
AudioKit.output = AKMixer(noise1, noise2, mySampler)
try AudioKit.start()
mySampler.play(note: 60, vel: 127)
}
MySampler.swift
import Foundation
import AudioKit
class MySampler : AKPolyphonicNode {
var mySampler1 = AKSampler()
func play(note: MIDINoteNumber, vel: MIDIVelocity) {
mySampler1.play(noteNumber: note, velocity: velocity)
}
}
不幸的是,它不适用于 AKNode
或 AKPolyphonicNode
,如上例所示:Terminating app due to uncaught exception ‘com.apple.coreaudio.avfaudio’, reason: ‘required condition is false: node != nil’
我做错了什么?
对您 "What am I doing wrong?" 的简单回答是,您启动了第二个采样器,它是正在播放的 MySampler class 的一部分,但未连接到信号链。当然,它的父项在 AKMixer 中,但这并不意味着其中的一些随机 属性。也许其他一些好人会 post 一个 GitHub 项目的更好的设置示例。
对于SoundEngine.swift:
import AudioKit
final class SoundEngine {
static let shared = SoundEngine()
// Create instance variables of the MySampler objects.
// I renamed them from noise1, noise2, and mySampler1, so that they are descriptive and clear about the intended sounds from each MySampler object.
var kick: MySampler
var snare: MySampler
var hiHat: MySampler
var drumMixer: AKMixer
init() {
// Instantiate MySampler objects
kick = MySampler()
snare = MySampler()
hiHat = MySampler()
// These drum samples are royalty-free from Music Radar: https://www.musicradar.com/news/drums/1000-free-drum-samples
kick.loadSample(filePath: "CYCdh_K2room_Kick-08")
snare.loadSample(filePath: "CYCdh_K2room_Snr-05")
hiHat.loadSample(filePath: "CYCdh_K2room_ClHat-06")
// Initialize the AudioKit engine settings.
AKSettings.bufferLength = .medium
AKSettings.enableRouteChangeHandling = true
AKSettings.playbackWhileMuted = true
do {
try AKSettings.setSession(category: .playAndRecord, with: [.defaultToSpeaker, .allowBluetooth, .mixWithOthers])
} catch {
AKLog("Could not set session category.")
}
// Combine the samples into a mixer, so that they can be played together in a single output.
drumMixer = AKMixer(snare, kick, hiHat)
AudioKit.output = drumMixer
// Start the audio engine
try! AudioKit.start()
}
// MARK: Sample Playback Triggers
// The following functions can be triggered via the button actions from the ViewController.
internal func playKick() {
try! kick.play(noteNumber: 60, velocity: 127, channel: 0)
}
internal func playSmare() {
try! snare.play(noteNumber: 60, velocity: 127, channel: 0)
}
internal func playHiHat() {
try! hiHat.play(noteNumber: 60, velocity: 127, channel: 0)
}
}
对于MySampler.swift:
import AudioKit
class MySampler: AKMIDISampler {
internal func loadSample(filePath: String) {
do {
try self.loadWav(Constants.sampleDirectoryPath + filePath)
// This will interpolate a string variable path like this: "Sounds/CYCdh_K2room_Kick-08"
} catch {
print("Could not locate the wav file.")
}
}
}
我还添加了一个常量,这样你就可以只提供音频文件名,而不必包含目录路径。
Constants.swift:
struct Constants {
static let sampleDirectoryPath = "Sounds/"
}
我创建了一个GitHub项目供您参考:
如何将 AKSampler 分离成 class? 例如:
SoundEngine.swift
import AudioKit
import MySampler
final class SoundEngine : ObservableObject {
static let shared = SoundEngine()
let mySampler = MySampler()
init() {
mySampler.loadSamples('samples1')
AudioKit.output = AKMixer(noise1, noise2, mySampler)
try AudioKit.start()
mySampler.play(note: 60, vel: 127)
}
MySampler.swift
import Foundation
import AudioKit
class MySampler : AKPolyphonicNode {
var mySampler1 = AKSampler()
func play(note: MIDINoteNumber, vel: MIDIVelocity) {
mySampler1.play(noteNumber: note, velocity: velocity)
}
}
不幸的是,它不适用于 AKNode
或 AKPolyphonicNode
,如上例所示:Terminating app due to uncaught exception ‘com.apple.coreaudio.avfaudio’, reason: ‘required condition is false: node != nil’
我做错了什么?
对您 "What am I doing wrong?" 的简单回答是,您启动了第二个采样器,它是正在播放的 MySampler class 的一部分,但未连接到信号链。当然,它的父项在 AKMixer 中,但这并不意味着其中的一些随机 属性。也许其他一些好人会 post 一个 GitHub 项目的更好的设置示例。
对于SoundEngine.swift:
import AudioKit
final class SoundEngine {
static let shared = SoundEngine()
// Create instance variables of the MySampler objects.
// I renamed them from noise1, noise2, and mySampler1, so that they are descriptive and clear about the intended sounds from each MySampler object.
var kick: MySampler
var snare: MySampler
var hiHat: MySampler
var drumMixer: AKMixer
init() {
// Instantiate MySampler objects
kick = MySampler()
snare = MySampler()
hiHat = MySampler()
// These drum samples are royalty-free from Music Radar: https://www.musicradar.com/news/drums/1000-free-drum-samples
kick.loadSample(filePath: "CYCdh_K2room_Kick-08")
snare.loadSample(filePath: "CYCdh_K2room_Snr-05")
hiHat.loadSample(filePath: "CYCdh_K2room_ClHat-06")
// Initialize the AudioKit engine settings.
AKSettings.bufferLength = .medium
AKSettings.enableRouteChangeHandling = true
AKSettings.playbackWhileMuted = true
do {
try AKSettings.setSession(category: .playAndRecord, with: [.defaultToSpeaker, .allowBluetooth, .mixWithOthers])
} catch {
AKLog("Could not set session category.")
}
// Combine the samples into a mixer, so that they can be played together in a single output.
drumMixer = AKMixer(snare, kick, hiHat)
AudioKit.output = drumMixer
// Start the audio engine
try! AudioKit.start()
}
// MARK: Sample Playback Triggers
// The following functions can be triggered via the button actions from the ViewController.
internal func playKick() {
try! kick.play(noteNumber: 60, velocity: 127, channel: 0)
}
internal func playSmare() {
try! snare.play(noteNumber: 60, velocity: 127, channel: 0)
}
internal func playHiHat() {
try! hiHat.play(noteNumber: 60, velocity: 127, channel: 0)
}
}
对于MySampler.swift:
import AudioKit
class MySampler: AKMIDISampler {
internal func loadSample(filePath: String) {
do {
try self.loadWav(Constants.sampleDirectoryPath + filePath)
// This will interpolate a string variable path like this: "Sounds/CYCdh_K2room_Kick-08"
} catch {
print("Could not locate the wav file.")
}
}
}
我还添加了一个常量,这样你就可以只提供音频文件名,而不必包含目录路径。
Constants.swift:
struct Constants {
static let sampleDirectoryPath = "Sounds/"
}
我创建了一个GitHub项目供您参考: