gpt4 book ai didi

ios - AudioKit iOS - 接收 MIDINoteOn 函数

转载 作者:可可西里 更新时间:2023-11-01 00:20:40 24 4
gpt4 key购买 nike

我正在尝试使用 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 :

  1. 点击无方案
  2. 点击管理方案
  3. 立即点击自动创建方案

关于ios - AudioKit iOS - 接收 MIDINoteOn 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48302292/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com