如何在AudioKit Keyboard上显示MIDI键盘按下的按键?
解决AudioKit Keyboard同步MIDI键盘按键显示问题
问题说明
已实现MIDI键盘输入的监听,也能展示AudioKit的Keyboard组件,但无法将MIDI键盘按下的按键状态同步到AudioKit Keyboard上,希望实现MIDI按键时,对应的Keyboard琴键同步高亮显示。
解决方案
AudioKit的Keyboard组件支持通过pressedPitches参数绑定已按下的音高集合,只需在MIDI监听逻辑中维护这个集合,就能实现同步显示。具体修改如下:
1. 更新MIDI监听类,维护已按下音高集合
在MIDIMonitorConductor中添加一个@Published修饰的Set<Pitch>,用于存储当前按下的音高:
class MIDIMonitorConductor: ObservableObject, MIDIListener { let midi = MIDI() @Published var data = MIDIMonitorData() @Published var midiEventType: MIDIEventType = .none // 添加已按下音高集合 @Published var pressedPitches: Set<Pitch> = [] // ... 其他原有代码 ... func receivedMIDINoteOn(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel, portID _: MIDIUniqueID?, timeStamp _: MIDITimeStamp?) { DispatchQueue.main.async { self.midiEventType = .noteOn self.data.noteOn = Int(noteNumber) self.data.velocity = Int(velocity) self.data.channel = Int(channel) // 将MIDI音符转换为Pitch并加入集合 if let pitch = Pitch(midiNoteNumber: noteNumber) { self.pressedPitches.insert(pitch) } print(Int(noteNumber)) } } func receivedMIDINoteOff(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel, portID _: MIDIUniqueID?, timeStamp _: MIDITimeStamp?) { DispatchQueue.main.async { self.midiEventType = .noteOff self.data.noteOff = Int(noteNumber) self.data.velocity = Int(velocity) self.data.channel = Int(channel) // 将对应的Pitch从集合中移除 if let pitch = Pitch(midiNoteNumber: noteNumber) { self.pressedPitches.remove(pitch) } } } // ... 其他原有代码 ... }
2. 在ContentView中绑定Keyboard的pressedPitches参数
修改Keyboard的初始化代码,将pressedPitches绑定到conductor的对应属性:
struct ContentView: View { @StateObject private var conductor = MIDIMonitorConductor() var body: some View { HStack { VStack { Keyboard( layout: .verticalPiano(pitchRange: Pitch(intValue: 21) ... Pitch(intValue: 108)), // 绑定已按下音高集合 pressedPitches: $conductor.pressedPitches ).frame(width: 150) } } .onAppear { conductor.start() } .onDisappear { conductor.stop() } } }
原理说明
AudioKit的Keyboard组件内部会监听pressedPitches的变化,当集合中的音高更新时,自动对应高亮或取消高亮相应的琴键。通过在MIDI的NoteOn/NoteOff事件中更新这个集合,就能实现MIDI键盘与UI键盘的状态同步。
内容的提问来源于stack exchange,提问作者sidneivl
相关产品推荐
相关产品推荐

