oF、Max/MSP、QCから外部コマンドを実行する方法

# TL;DR
[クリエイティブコーディング Advent Calendar 2016](http://qiita.com/advent-calendar/2016/creative-coding)へ3本目の投稿です。

MacOSがBSD系UNIXであることを最大限活かすと、クリエィティブコーディングが少し楽になりますよ。
「oFでディレクトリ作るときは[`ofDirectory::createDirectory(const string &dirPath, bool bRelativeToData=true, bool recursive=false)`](http://openframeworks.cc/documentation/utils/ofDirectory/#show_createDirectory)…?」なんてやらなくて良いんです。
そう、いつもと同じように`mkdir`で良いんです。

## たとえば…
* 日別にログファイルを整理したい → [mv](https://ja.wikipedia.org/wiki/Mv_(UNIX)), [date](https://ja.wikipedia.org/wiki/Date_(UNIX))
* 書き出したファイルを圧縮したい → [zip](https://ja.wikipedia.org/wiki/ZIP_(ファイルフォーマット)), [tar](https://ja.wikipedia.org/wiki/Tar)
* 処理が終わったら通知を出したい → [terminal-notifier](https://github.com/julienXX/terminal-notifier), [osascript](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/osascript.1.html)
* 喋らせたい → [say](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/say.1.html)
* Web APIを叩いた結果が欲しい → [curl](https://ja.wikipedia.org/wiki/CURL), [wget](https://ja.wikipedia.org/wiki/GNU_Wget), [jq](https://stedolan.github.io/jq/)
* 適当なアプリで開きたい → [open](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/open.1.html)

正直、`osascript`でAppleScriptが叩ければ、すなわちMacOSのほとんどが制御できることになるので、
クリップボードを共有するなり、カーソルを動かすなり、音量を最大にするなり、他のアプリを前面に持ってくるなり、なんでもござれ。
こういったコマンドを駆使できるからクリエィティブコーディングは極力MacOSでやりたいと思っています。

参考までに、openFrameworksとMax/MSP、QuartzComposerからシェルを叩く方法をご紹介します。

# w/ openFrameworks
## ofSystem()を使う
もっとも簡単なのは[`ofSystem`](http://openframeworks.cc/documentation/utils/ofUtils/#show_ofSystem)を使う方法。

```cpp
ofSystem("say -v Kyoko こんにちは");
```

## ちゃんとPIPEする
`ofSystem()`では途中出力を受け取れないし、処理が終わるまでスレッドがブロックされるので、
Brettさんが[Gist](https://gist.github.com/robotconscience/2554110)に上げていた実装が参考になります。

```cpp:SysCommand.h
//
//  SysCommand.h
//
//  Created by Brett Renfer on 2/22/12.
//

#pragma once
#include "ofThread.h"

class SysCommand : private ofThread
{
public:
    ofEvent<string> commandComplete;
    
    void callCommand( string command ){
        cmd = command;
        stopThread();
        startThread();
    }
    
    // CALL THIS DIRECTLY FOR BLOCKING COMMAND
    // thanks to: http://stackoverflow.com/questions/478898/how-to-execute-a-command-and-get-output-of-command-within-c
    std::string exec(char* cmd) {
        FILE* pipe = popen(cmd, "r");
        if (!pipe) return "ERROR";
        char buffer[128];
        std::string result = "";
        while(!feof(pipe)) {
            if(fgets(buffer, 128, pipe) != NULL)
                result += buffer;
        }
        pclose(pipe);
        return result;
    }
    
private:
    void threadedFunction(){
        ofLog( OF_LOG_VERBOSE, "call "+cmd );
        string result = exec( (char *) cmd.c_str() );
        ofLog( OF_LOG_VERBOSE, "RESULT "+result );
        stopThread();
        ofNotifyEvent( commandComplete, result, this );
    }
    string cmd;
};
```

# w/ Max/MSP
## Bill氏の"shell"オブジェクトを使う
<img width="520" alt="Screen Shot 2016-12-08 at 22.12.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/13971/1675a8df-5961-cd78-fde1-8dda18033c5c.png">

[公式のフォーラム](https://cycling74.com/toolbox/bernstein-shell/#.WElTtndh3ag)からダウンロードできます。
中身を見るとCからpthreadしてますね。

## 赤松先生の"aka.shell"を使う
<img width="662" alt="Screen Shot 2016-12-08 at 22.14.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/13971/12a03080-ed07-8f29-220d-5a142676ba30.png">

[赤松先生のWeb](http://www.iamas.ac.jp/~aka/max/#aka_shell)よりダウンロードできます。
こちらはpopenでの実装ですが、よりメジャーなので参考になる記事がたくさん見つかります。
Qiitaに詳しい記事もありました。 → [UnixコマンドをインタフェースとしたMax-外部アプリ間の連携方法](http://qiita.com/tgck/items/f3d6a98fc1fa76a139f3)

# w/ Quartz Composer
## CommandLineTool
[デペロッパーライブラリ](https://developer.apple.com/library/content/samplecode/CommandLineTool/Introduction/Intro.html)から謹製のサンプルコードが手に入ります。
古いので、Xcodeで読み込んでから微修正が必要です。
日本語で書かれた参考記事がありました。 → [UNIX Command – execute in Quartz Composer](https://dasaq.wordpress.com/2009/05/21/command/)
## ShellCommandパッチを使う
![shell-command-patch.png](https://qiita-image-store.s3.amazonaws.com/0/13971/7d52e5b3-ef9c-0607-7f50-de753767eac5.png)
[Kosada inc.](http://kosada.com/SoftwareDevelopment/QuartzComposer/Kineme/ShellCommandPatch)が公開しているShellCommandパッチを使う方法もあります。
[Kinema](http://kineme.net/ShellCommand)からダウンロードできます。

# まとめ
どのツール/フレームワークも外部コマンドを実行できる仕組みが複数あります。
それぐらい強力な連携なのですが、いずれも「とんでもない引数を渡してた！」「コマンドを絶対パスにしないと動かない！」といったリスク&あるあるがあったりしますので、心してお使いくださいませ。