- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在尝试使用 receivedMIDINoteOn 函数在音序器播放音符时闪烁 UILabel。我尝试使用 AKMIDIListener 协议(protocol)但没有成功。我还制作了 AKMIDISampler 的子类,并从音序器向它发送 midi。它播放 midi 但未调用 receivedMIDINoteOn。
这是我在 conductor 的 init() 中的内容:
init() {
[ahSampler, beeSampler, gooSampler,flasher] >>> samplerMixer
AudioKit.output = samplerMixer
AudioKit.start()
let midi = AKMIDI()
midi.createVirtualPorts()
midi.openInput("Session 1")
midi.addListener(self)
}
指挥遵循 AKMIDIListener 协议(protocol)
这是函数:它永远不会被调用
func receivedMIDINoteOn(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel)
{
print("got it")
}
这是 AKMIDISampler 的子类,它获取 midi 并播放正弦合成器,但从未调用 receivedMIDINoteOn。
class Flasher: AKMIDISampler
{
override func receivedMIDINoteOn(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel)
{
print("Flasher got it!")
}
}
编辑:我应该一直使用 AKCallbackInstrument 类,并覆盖它的 start() 函数。
最佳答案
本,
在没有看到您的整个项目的情况下,我猜想如果您的项目能够接收和触发 MIDI 音符,那么仅将其输出发送到 UILabel 就是一个问题。我建议在 Conductor
类中收到 MIDI 事件时使用 NotificationCenter 通知 ViewController。请务必添加 DispatchQueue.main.async
代码,否则文本不会按预期更新。这已在 AudioKit Google Group 中注明 here .
示例:
DispatchQueue.main.async(execute: {
nc.post(name: NSNotification.Name(rawValue: "outputMessage"),
object: nil,
userInfo: [
"message": self.outputMIDIMessage,
"midiSignalReceived": self.midiSignalReceived,
"midiTypeReceived": self.midiTypeReceived
])
})
我还推荐以下内容:
将 let midi = AKMIDI()
移动到 Conductor 类顶部的 init()
之外的实例变量中,而不是在它的内部。看起来您正试图在 AudioKit.start()
之后创建它。
我发布了一个示例项目,演示了如何在通过 AudioKit 收到 MIDI 音符编号时更改 UILabel 的颜色:
https://github.com/markjeschke/AKMidiReceiver
导体类:
import AudioKit
enum MidiEventType: String {
case
noteNumber = "Note Number",
continuousControl = "Continuous Control",
programChange = "Program Change"
}
class Conductor: AKMIDIListener {
// Globally accessible
static let sharedInstance = Conductor()
// Set the instance variables outside of the init()
let midi = AKMIDI()
var demoSampler = SamplerAudioFileLoader()
var samplerMixer = AKMixer()
var outputMIDIMessage = ""
var midiSignalReceived = false
var midiTypeReceived: MidiEventType = .noteNumber
init() {
// Session settings
AKSettings.bufferLength = .medium
AKSettings.defaultToSpeaker = true
// Allow audio to play while the iOS device is muted.
AKSettings.playbackWhileMuted = true
do {
try AKSettings.setSession(category: .playAndRecord, with: [.defaultToSpeaker, .allowBluetooth, .mixWithOthers])
} catch {
AKLog("Could not set session category.")
}
// File path options are:
// "TX Brass"
// "TX LoTine81z"
// "TX Metalimba"
// "TX Pluck Bass"
demoSampler.loadEXS24Sample(filePath: "TX Brass")
// If you wish to load a wav file, comment the `loadEXS24` method and uncomment this one:
// demoSampler.loadWavSample(filePath: "Kick") // Load Kick wav file
[demoSampler] >>> samplerMixer
AudioKit.output = samplerMixer
AudioKit.start()
// MIDI Configure
midi.createVirtualInputPort(98909, name: "AKMidiReceiver")
midi.createVirtualOutputPort(97789, name: "AKMidiReceiver")
midi.openInput()
midi.openOutput()
midi.addListener(self)
}
// Capture the MIDI Text within a DispatchQueue, so that it's on the main thread.
// Otherwise, it won't display.
func captureMIDIText() {
let nc = NotificationCenter.default
DispatchQueue.main.async(execute: {
nc.post(name: NSNotification.Name(rawValue: "outputMessage"),
object: nil,
userInfo: [
"message": self.outputMIDIMessage,
"midiSignalReceived": self.midiSignalReceived,
"midiTypeReceived": self.midiTypeReceived
])
})
}
// MARK: MIDI received
// Note On Number + Velocity + MIDI Channel
func receivedMIDINoteOn(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel) {
midiTypeReceived = .noteNumber
outputMIDIMessage = "\(midiTypeReceived.rawValue)\nChannel: \(channel+1) noteOn: \(noteNumber) velocity: \(velocity)"
print(outputMIDIMessage)
midiSignalReceived = true
captureMIDIText()
playNote(note: noteNumber, velocity: velocity, channel: channel)
}
// Note Off Number + Velocity + MIDI Channel
func receivedMIDINoteOff(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel) {
midiTypeReceived = .noteNumber
outputMIDIMessage = "\(midiTypeReceived.rawValue)\nChannel: \(channel+1) noteOff: \(noteNumber) velocity: \(velocity)"
print(outputMIDIMessage)
midiSignalReceived = false
captureMIDIText()
stopNote(note: noteNumber, channel: channel)
}
// Controller Number + Value + MIDI Channel
func receivedMIDIController(_ controller: MIDIByte, value: MIDIByte, channel: MIDIChannel) {
// If the controller value reaches 127 or above, then trigger the `demoSampler` note.
// If the controller value is less, then stop the note.
// This creates an on/off type of "momentary" MIDI messaging.
if value >= 127 {
playNote(note: 30 + controller, velocity: 80, channel: channel)
} else {
stopNote(note: 30 + controller, channel: channel)
}
midiTypeReceived = .continuousControl
outputMIDIMessage = "\(midiTypeReceived.rawValue)\nChannel: \(channel+1) controller: \(controller) value: \(value)"
midiSignalReceived = true
captureMIDIText()
}
// Program Change Number + MIDI Channel
func receivedMIDIProgramChange(_ program: MIDIByte, channel: MIDIChannel) {
// Trigger the `demoSampler` note and release it after half a second (0.5), since program changes don't have a note off release.
triggerSamplerNote(program, channel: channel)
midiTypeReceived = .programChange
outputMIDIMessage = "\(midiTypeReceived.rawValue)\nChannel: \(channel+1) programChange: \(program)"
midiSignalReceived = true
captureMIDIText()
}
func receivedMIDISetupChange() {
print("midi setup change")
print("midi.inputNames: \(midi.inputNames)")
let listInputNames = midi.inputNames
for inputNames in listInputNames {
print("inputNames: \(inputNames)")
midi.openInput(inputNames)
}
}
func playNote(note: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel) {
demoSampler.play(noteNumber: note, velocity: velocity, channel: channel)
}
func stopNote(note: MIDINoteNumber, channel: MIDIChannel) {
demoSampler.stop(noteNumber: note, channel: channel)
}
func triggerSamplerNote(_ program: MIDIByte, channel: MIDIChannel) {
playNote(note: 60 + program, velocity: 80, channel: channel)
let releaseNoteDelay = DispatchTime.now() + 0.5 // Change 0.5 to desired number of seconds
DispatchQueue.main.asyncAfter(deadline: releaseNoteDelay) {
self.stopNote(note: 60 + program, channel: channel)
self.midiSignalReceived = false
}
}
}
带有 UILabel 的 ViewController:
import UIKit
import AudioKit
class ViewController: UIViewController {
@IBOutlet weak var outputTextLabel: UILabel!
var conductor = Conductor.sharedInstance
var midiSignalReceived = false
var midiTypeReceived: MidiEventType = .noteNumber
override func viewDidLoad() {
super.viewDidLoad()
let nc = NotificationCenter.default
nc.addObserver(forName:NSNotification.Name(rawValue: "outputMessage"), object:nil, queue:nil, using:catchNotification)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
flashBackgroundColor()
midiSignalReceived = false
self.outputTextLabel.text = "Listening for MIDI events..."
}
@objc func catchNotification(notification:Notification) -> Void {
guard
let userInfo = notification.userInfo,
let message = userInfo["message"] as? String,
let midiSignalReceived = userInfo["midiSignalReceived"] as? Bool,
let midiTypeReceived = userInfo["midiTypeReceived"] as? MidiEventType else {
print("No userInfo found in notification")
return
}
DispatchQueue.main.async(execute: {
self.outputTextLabel.text = message
self.midiSignalReceived = midiSignalReceived
self.midiTypeReceived = midiTypeReceived
self.flashBackgroundColor()
})
}
@objc func flashBackgroundColor() {
if midiSignalReceived {
self.outputTextLabel.backgroundColor = UIColor.green
self.view.backgroundColor = UIColor.lightGray
if midiTypeReceived != .noteNumber {
self.perform(#selector(dismissFlashBackgroundColor), with: nil, afterDelay: 0.5)
}
} else {
dismissFlashBackgroundColor()
}
}
@objc func dismissFlashBackgroundColor() {
UIView.animate(withDuration: 0.5) {
self.outputTextLabel.backgroundColor = UIColor.clear
self.view.backgroundColor = UIColor.white
self.midiSignalReceived = false
self.conductor.midiSignalReceived = false
}
}
deinit {
NotificationCenter.default.removeObserver(self,
name: NSNotification.Name(rawValue: "outputMessage"),
object: nil)
}
}
SamplerAudioFileLoader.swift:
import AudioKit
class SamplerAudioFileLoader: AKMIDISampler {
internal func loadWavSample(filePath: String) {
do {
try self.loadWav("Sounds/\(filePath)")
} catch {
print("Could not locate the Wav file.")
}
}
internal func loadEXS24Sample(filePath: String) {
do {
try self.loadEXS24("Sounds/Sampler Instruments/\(filePath)")
} catch {
print("Could not locate the EXS24 file.")
}
}
}
希望对您有所帮助。如果您对此有任何疑问,请告诉我。
保重,
标记
附言如果你克隆这个 AKMidiReceiver example ,打开Workspace,Xcode工程中没有出现scheme,请按照找到的步骤进行here :
关于ios - AudioKit iOS - 接收 MIDINoteOn 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48302292/
我正在尝试使用 receivedMIDINoteOn 函数在音序器播放音符时闪烁 UILabel。我尝试使用 AKMIDIListener 协议(protocol)但没有成功。我还制作了 AKMIDI
我是一名优秀的程序员,十分优秀!