Edited at

iPod20台を通信/制御/連携してみた【Max × Swift × OSC】

More than 1 year has passed since last update.


はじめに

この記事は、Life is Tech ! アドベントカレンダー2016 23日目の記事です.

はじめまして岐阜のiPhoneメンターこと ぬっきーです.

普段は秘境岐阜県にある精神と時の部屋ことIAMASという学校でひっそりと息をしています.

そんな私が最近取り組んでいるのは大量のiPodを制御することです.大量にピカらせてます.

ipodjockeyPhotoISCA2.png

スクリーンショット 2016-12-23 14.37.14.png

VJやデコみたいに光らすことも

今回はMaxやswiftにおけるOSCの送受信をベースに大量の端末を制御するときの知見を共有できたらと思います.


本記事について

OSCまわりで横断的にまとめられている記事が少なかったのでこの際まとめてみました.

Maxの基本操作やSwiftの基礎についてはあまり触れません、ごめんなさい.


  • OSC通信

  • Max,swiftでの実装

  • 通信まわりとブロードキャスト

  • 実践例


OSC通信って

OSC(Open Sound Control)とは本来電子楽器同士を連携させるために開発された通信プロトコル.

複数端末間で信号が送受信可能、かつ超便利と簡単シンプルということから、

今では様々なソフトを架け橋するために利用されるようになりました.

詳しくは田所先生の記事がとても詳しく解説されています.


【基礎】MaxにおけるOSC送受信

Maxでは一般的には以下のようなパッチを組むと送受信することがいとも簡単にできてします.

OSC通信でデバッグや簡単な通信を試してみたいときは簡単に試すことができるのでオススメです.

買わずとも体験版では"保存する"以外使えるので触ったことない方は是非試してみてください.


実装


1つの値を送る場合

"udpsend"によりOSCメッセージを送ることが可能

IPアドレス : 192.168.1.255

port : 3333

スクリーンショット 2016-12-23 12.36.38.png


複数の値を送る場合

"sprintf"により値をまとめる

"%s %f"はそれぞれ"整数 小数"を意味する

スクリーンショット 2016-12-23 12.36.45.png


受信するやで

"udpreceive"によりOSCメッセージを受信することが可能(portを指定)

"route /OSCメッセージ"によりOSCメッセージの場合分け可能

"uppack"により複数の値を切り分けが可能

"0 0."はそれぞれ"整数 小数"の型を指定

スクリーンショット 2016-12-23 12.38.58.png


余談

外部ライブラリ"OSC-route"の使用で楽ちんだったりもしますよう.

スクリーンショット 2016-12-23 12.16.03.png


【基礎】swiftにおけるOSC送受信

iOSアプリでのOSCのやりとりは"buzzOSC"というライブラリを使用することで簡単に実装します


導入手順

1.buzzOSCファイル内の"F53OSC"を丸ごと自分のXcodeプロジェクトファイルの中にぶっ込みます

スクリーンショット 2016-04-22 23.30.42.png

2.ブリッジングヘーダーを作成して以下のように入力しましょう.

(詳しいbridgingheader導入の仕方はこちら)


(プロジェクト名)_Bridging_Header.h

#import "F53OSC.h"



実装


OSC送信すんで


OscSendViewConroller.swift

import UIKit

class OscSendViewController: UIViewController {

//osc送信のためのoscClientの初期化
let oscClient = F53OSCClient.init()

override func viewDidLoad() {
super.viewDidLoad()

//OSCを送りたい先のIPアドレスを指定
oscClient.host = "192.000.0.000"
//贈りたい先のport番号を指定
oscClient.port = 3333

}

@IBAction func sendOSC(){
//123というメッセージをOSCで送信
self.sendMessage(oscClient, addressPattern: "/value", arguments: [123])
//複数の値を送る場合はarguments:[123,231,312]
}

//osc送信のためのメソッド
func sendMessage(client: F53OSCClient, addressPattern: String, arguments: [AnyObject]) {
let message = F53OSCMessage(addressPattern: addressPattern, arguments: arguments)
client.sendPacket(message)
print("Sent '\(message)' to \(client.host):\(client.port)")
}
}



OSC受信するわ


OscRecieveViewController.swift

import UIKit

//デリゲートまわりでF53OSCPacketDestinationの追加
class OscRecieveViewController: UIViewController,F53OSCPacketDestination {

//osc受信のためのoscServerの初期化
let oscServer = F53OSCServer.init()

override func viewDidLoad() {
super.viewDidLoad()
//portの指定など
oscServer.port = 3333
oscServer.delegate = self
if oscServer.startListening() {
print("Listening for messages on port \(oscServer.port)")
} else {
print("Error: Server was unable to start listening on port \(oscServer.port)")
}
}

//OSC受信するためのメソッド
func takeMessage(message: F53OSCMessage!) {

print(message)

//OSCmessageによる比較
if message.addressPattern == "/value" {

//OSCargumentsによる比較
if message.arguments[0] as! Int == 123{
print("hello 123")
}else if message.arguments[0] as! Int == 321{
print("hello 321")
}
}
}

}


以上がswiftによるOSC送受信の基礎的な解説でした.


通信方法とブロードキャスト

OSC通信ではメッセージを贈りたい相手のIPアドレスを指定してメッセージを送っていましたが30台のiPodのIPアドレスなんて…となりますよね 


1.各々のIPアドレスを吐き出してもらう

iOSアプリ側でアプリ起動したときに自分のIPアドレスをMacPCのIPドレス宛に送ってもらう案


ブリッジングヘーダー(.h)内に追加するコード


(プロジェクト名)_Bridging_Header.h

#include <ifaddrs.h> 



自身のIPアドレス取得メソッド


ViewController.swift

 func getIFAddresses() -> [String] {

var addresses = [String]()
var ifaddr : UnsafeMutablePointer<ifaddrs> = nil

if getifaddrs(&ifaddr) == 0 {
for (var ptr = ifaddr; ptr != nil; ptr = ptr.memory.ifa_next) {
let flags = Int32(ptr.memory.ifa_flags)
var addr = ptr.memory.ifa_addr.memory

if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)

if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
if let address = String.fromCString(hostname) {
addresses.append(address)
}
}
}
}
}
freeifaddrs(ifaddr)
}
print(addresses)
return addresses

}



メソッドの使い方


ViewController.swift

let  myIPaddress = getIFAddresses()[0]


あとは制御しているMacPC宛てに端末IPアドレスを送りつけて、oFアプリであれば受信したIPアドレスを配列にまとめて、一括管理可能なんてことが可能ですね.

でもめんどうという方は次のやり方!!


2.ブロードキャストアドレス

ブロードキャストアドレスとは

同じネットワークに繋がっている全ての端末にメッセージを送りたいときに使う特殊なアドレス

宛先IPアドレスを "XXX.XXX.1.255" にすることでブロードキャストが実現可能です.(他にもやり方はあったり…)

(XXX.XXXは端末のIPアドレス上2つ数字を入力しください.例としは"192.168.1.255","10.10.1.255" となるはずです)

※ただし注意することとしては大学のLANとかでブロードキャストアドレスにメッセージを送るのはやめましょう.

他人がキャッチしてしまったり迷惑極まりないので気を付けましょう(めっちゃ飛ばして怒られました)


20台繋げるときに気をつけること


ad-hoc接続では限界がある

OSC通信は通常同じネットワークに繋がっていないと通信がうまくいきません.

そのためさまざまな現場に行ったときは自分のPCをルーター代わりにad-hoc通信をすることがよくあります.

いわゆるモバイルアドホックネットワークなこと.

少し詳しく言うと以下のようにネットワークをMacで作成することですね.

スクリーンショット 2016-12-23 14.00.29.png

スクリーンショット 2016-12-23 18.10.39.png

ですがad-hoc接続では通信量に限界があり、多くて13〜15台の接続で 遅延や

メッセージが届かないアクシデント(パケットロス)
が多発してしまいます.


AirMacExtremeとかを使うと余裕マン

それを解決するために使用したのが通信容量の大きいApple純正無線LANルーター "Air Mac Extreme"

AirMacExtreme_image-1.jpg

こちらに全てのiPodと制御用PCを繋げることで全台目立つ遅延なく通信ができました.

Appleさん曰くは 50台まで接続が可能ということで、20台以上でもきっと ヌルサクに通信をすることが可能でしょう.

またad-hoc接続しているとネットワークを普通に繋げられないので毎回wifiを切り替えてはセットアップが必要という手間が省けるので素敵です.


実践例

できることは未知数っていうのが正直な所

また個別のデバイスごとに 個別IDをもたせると集合体のような動きが実現可能(制作途中の汚い写真でごめんなさい)

ipjID.png

下のように徐々に信号が伝わっていく光らせ方が可能となります


最後に

さいごまで読んでいただきありがとうございます、

20台もiPodなんてねーよって方がたくさんだと思いますが、友達同士でMacに同じプロジェクトを配って

同じwifiに繋げて同じアプリ立ち上げれば似たようなことができます.忘年会とかでも使えるかもですね.

この記事が少しでも誰かの手助けorインスピレーションにつながれば幸いです.

ありがとうございました!コメントいいねストックお待ちしていおります!

さて明日は"東工大のハッカソン荒らし"またの名を"oF王子"こと"ぬま"です、お楽しみにー!