iOSのBLE通信によるMIDI I/Fを使って実際に音源を鳴らすテストをしてみました。
BLEはこれまでもいろいろなデバイスでテストをしてきましたが、PGMIDIというライブラリとその実装が下記サイトにあり、とてもわかりやすかったため参考にさせていただきました。
参考) https://github.com/JunichiMinamino/BleMidiTest
https://github.com/JunichiMinamino/BleMidiTest/blob/main/BleMidiTest/ViewController.m
上記ViewControllerでは、UIをコードで書いているところをInterfaceBuilderに置き換えて、私がテストしたい必要最低限のところのみ実装しました。
Delegate以下はそのまま使わせていただきました。
実は手持ちのドラム音源Roland TD-17に直接接続したかったのですが、BLEでは接続できないようなので、YAMAHA UD-BT01にUSB-MIDIを接続してテストしました。
やりたいことは、TD-17のSD,BDの音をiPhoneから鳴らすことと、パッドを叩くとそのノート情報を受信することです。
メイン画面をナビゲータ画面の一つとしておくと、CABTMIDICentralViewControllerを呼び出すだけで、BLE接続に関する処理を全てやってくれます。(とても便利!)
ここでは、セントラルによる接続のみにしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
#import <CoreAudioKit/CoreAudioKit.h> #import "MidiViewController.h" #import "PGMidi.h" @interface MidiViewController () <PGMidiDelegate, PGMidiSourceDelegate> { PGMidi *_midi; __weak IBOutlet UILabel *_labelCount; __weak IBOutlet UILabel *_labelReceive; } @end @implementation MidiViewController - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) { self.title = @"MidiView"; } return self; } - (void)viewDidLoad { [super viewDidLoad]; _midi = [[PGMidi alloc] init]; _midi.networkEnabled = YES; _midi.delegate = self; for (PGMidiSource *source in _midi.sources) { [source addDelegate:self]; } _midi.virtualDestinationEnabled = YES; _midi.virtualSourceEnabled = YES; } - (IBAction)btnConnect:(UIButton *)sender { CABTMIDICentralViewController *pCentralVC = [[CABTMIDICentralViewController alloc] init]; [self.navigationController pushViewController:pCentralVC animated:YES]; } - (IBAction)btnDownSD:(UIButton *)sender { const UInt8 noteOn[] = {0x99, 38, 127}; [_midi sendBytes:noteOn size:sizeof(noteOn)]; } - (IBAction)btnUpSD:(UIButton *)sender { const UInt8 noteOff[] = {0x89, 38, 0}; [_midi sendBytes:noteOff size:sizeof(noteOff)]; } - (IBAction)btnDownBD:(UIButton *)sender { const UInt8 noteOn[] = {0x99, 36, 127}; [_midi sendBytes:noteOn size:sizeof(noteOn)]; } - (IBAction)btnUpBD:(UIButton *)sender { const UInt8 noteOff[] = {0x89, 36, 0}; [_midi sendBytes:noteOff size:sizeof(noteOff)]; } #pragma mark - PGMidiDelegate - (void)midi:(PGMidi *)midi sourceAdded:(PGMidiSource *)source { [source addDelegate:self]; [self updateCountLabel]; [self updateReceiveLabel:[NSString stringWithFormat:@"Source added: %@", ToString(source)]]; } - (void)midi:(PGMidi *)midi sourceRemoved:(PGMidiSource *)source { [self updateCountLabel]; [self updateReceiveLabel:[NSString stringWithFormat:@"Source removed: %@", ToString(source)]]; } // Connect USB keyboard - (void)midi:(PGMidi *)midi destinationAdded:(PGMidiDestination *)destination { [self updateCountLabel]; [self updateReceiveLabel:[NSString stringWithFormat:@"Desintation added: %@", ToString(destination)]]; } - (void)midi:(PGMidi *)midi destinationRemoved:(PGMidiDestination *)destination { [self updateCountLabel]; [self updateReceiveLabel:[NSString stringWithFormat:@"Desintation removed: %@", ToString(destination)]]; } - (void)updateReceiveLabel:(NSString *)string { _labelReceive.text = string; NSLog(@"%@", string); } - (void)updateCountLabel { NSString *strCount = [NSString stringWithFormat:@"sources=%u destinations=%u", (unsigned)_midi.sources.count, (unsigned)_midi.destinations.count]; _labelCount.text = strCount; NSLog(@"%@", strCount); } const char *isToString(BOOL b) { return b ? "yes":"no"; } NSString *ToString(PGMidiConnection *connection) { return [NSString stringWithFormat:@"< PGMidiConnection: name=%@ isNetwork=%s >", connection.name, isToString(connection.isNetworkSession)]; } #pragma mark - PGMidiSourceDelegate - (void)callMIDIPacket:(NSInteger)iIndex packet:(const MIDIPacket *)packet { Byte bNoteOn = 0x9; Byte bNoteOff = 0x8; if (packet->data[0] >> 4 == bNoteOn) { [self updateReceiveLabel:[NSString stringWithFormat:@"NoteOn: %d %d %d", packet->data[0], packet->data[1], packet->data[2]]]; } else if (packet->data[0] >> 4 == bNoteOff) { [self updateReceiveLabel:[NSString stringWithFormat:@"NoteOff: %d %d %d", packet->data[0], packet->data[1], packet->data[2]]]; } } - (void)midiSource:(PGMidiSource *)midi midiReceived:(const MIDIPacketList *)packetList { const MIDIPacket *packet = &packetList->packet[0]; for (int i = 0; i < packetList->numPackets; ++i) { dispatch_async(dispatch_get_main_queue(), ^{ [self callMIDIPacket:i packet:packet]; }); packet = MIDIPacketNext(packet); } } @end |
環境) iPhone6 / Build Target iOS 9.2 / Xcode 13.2.1 / macOS Big Sur 11.6.2
BLE-MIDIはデバイスによって(Linux,Windows,Macとか、BluetoohのバージョンにもよるのでそのPCの年代にもよる。また今回のようにUSB-MIDIを使うときはホスト側かデバイス側か、とかも考慮)接続ができなかったりすることが多く、実際に使いたい組み合わせで動作するときは、それをメモっておきたくなります。(In/Out両方同時に使えない楽器もあった)
今回のテストも、その一つでした。