Polyphonic STK + MIDIKit
이 코드는 AudioKit과 MIDIKit을 함께 사용하여,
가상 또는 외부 MIDI 장치로부터 들어오는 MIDI 이벤트를 수신하고,
RhodesPianoKey(SoundpipeAudioKit) 기반으로 폴리포닉 연주를 가능하게 하는 구조입니다.
MIDIKit 관련 설명
MIDIManager 생성
1
2
3
4
5
| let midiManager = MIDIManager(
clientName: "CookbookAppMIDIManager",
model: "CookbookApp",
manufacturer: "BGSMM"
)
|
- MIDIKit의 핵심 객체
- CoreMIDI 클라이언트를 만들고, 포트와 연결을 관리함
- iOS/macOS의 MIDI 시스템과 연동됨
MIDI 연결 설정: MIDIConnect()
1. MIDI 서비스 시작
1
| try midiManager.start()
|
- MIDI 시스템 접근을 시작하며, 장치 탐색 및 연결 가능 상태로 전환
2. 입력 연결 설정
1
2
3
4
5
6
| try midiManager.addInputConnection(
to: .allOutputs,
tag: "Listener",
filter: .owned(),
receiver: .events { ... }
)
|
.allOutputs: 연결 가능한 모든 외부 출력 포트를 수신 대상으로 설정
filter: .owned(): 본 앱이 만든 가상 포트는 수신 대상에서 제외
receiver: .events: 이벤트 수신 핸들러
이벤트 수신 핸들러
1
2
3
4
5
6
7
| receiver: .events { [weak self] events, timeStamp, source in
Task { @MainActor in
for event in events {
self?.received(midiEvent: event)
}
}
}
|
- 비동기 클로저이며 백그라운드 스레드에서 호출됨
Task { @MainActor in ... }으로 UI 안전하게 업데이트
self는 weak으로 캡처하여 메모리 누수 방지
@Sendable 제한을 피하기 위해 DispatchQueue.main.async 대신 Task { @MainActor } 사용
수신된 MIDI 이벤트 처리
1
| private func received(midiEvent: MIDIEvent) { ... }
|
| 타입 |
처리 내용 |
.noteOn |
음을 재생 + NotificationCenter로 노트 정보 전달 |
.noteOff |
해당 음을 멈춤 + NotificationCenter로 노트 정보 전달 |
.cc |
콘트롤 체인지 정보 콘솔 출력 |
.programChange |
프로그램 체인지 이벤트 출력 |
| 기타 |
무시 |
NotificationCenter.default.post(...)는 외부 UI에 키보드 상태 전파에 사용됨
AudioKit 관련 (간단 요약)
RhodesPianoKey → 기본 오실레이터
AmplitudeEnvelope으로 각각 음의 게이트 제어
- 최대 11음까지 동시에 연주 가능
.noteOn, .noteOff로 envs[i].openGate() / closeGate() 처리
- 출력은
Mixer(envs) → engine.output
🧪 동작 요약
- 앱 실행 → MIDIManager 시작
- 가상포트 혹은 실제 MIDI 키보드에서 노트를 누름
.noteOn 수신 → noteOn(pitch:) 호출
- RhodesPianoKey 연주 시작
.noteOff 수신 → noteOff(pitch:) → 게이트 닫힘
사용 예
- 외부 MIDI 장치, 가상 MIDI 장치, DAW 등에서 이 앱으로 노트 전송 가능
- SwiftUI UI에서
MIDIKItKeyboard로 직접 연주도 가능
- 모든 이벤트는 콘솔과 UI에 실시간 반영됨