S98Player Ver. 0.2を作った

4年ほど前にFM音源のサウンドログを再生するアプリを作ったのですが,最近FM音源づいていてちょっとだけコードを修正したので公開します.機能は全く変わっておらず,使い勝手も悪いままですが.

…そして誰も使わないとは思いますが.

修正点は以下の通り.

  • サンプリング周波数を44100Hzから55466Hzに変更.原音に近くなりました.
  • S98v3のヘッダをもう少しきちんと読むように.UTF8,SJIS両方読めます.
  • しかし基本的にOPNAのみの対応….
  • 10.5SDK上でコンパイルしたので10.5以降でしか動かないかも.

OPNへの対応は,サウンドログファイルをもってないのでチェックできないんですよね.ま,基本的に自分用アプリなので問題ないんですけどね(無駄にiPhone向けに移植して一人楽しんでます).

続・FM音源の仕組みを視覚的に理解する

前回のエントリで簡単なFM音源もどきを作ったわけですが、どうも物足りなく感じたため(というか、なんとなく達成感がないというか…)、並列接続も可能な4オペレータ版を作成しました。

そして、オペレータ接続アルゴリズムも8種類から選べるようにしました。

単音しかなりませんが、機能的には、往年のYM-2203音源などと同じ程度のパラメータをいじれます(多少少ないんですが)。

FM音源って?

という方は、是非前エントリをご一読ください。

ダウンロード

となります。

使い方

まぁ、大したことができないのは相変わらずですが…。

右下のプルダウンメニューでアルゴリズムが選べますので、それを選ぶと各オペレータの接続アルゴリズムが変わります。用意した接続アルゴリズムは8種類で、これはYAMAHAのOPN系音源に準じています。

接続アルゴリズムを選ぶと、プルダウンメニューの下に接続の模式図が現れますので、雰囲気はつかめるはずです。

感想

単純な直列だけだと「ふーん」ってな感じでしたが、並列もできるようになるとかなり音が「それっぽい」感じになりました。

最終の出力の手前部分が並列になっているもの(Algorithm 4など)は特に、直列では聞けなかった音が合成されますので、楽しいです。

まとめ

相変わらず実用性皆無のアプリではありますが、往年のYAMAHA製FM音源であるOPN系音源における音色作成くらいは追体験できるのではないかと思います。

気に入った方がいたら、是非アフィリエイトサイトで本でも買ってやってください(笑)

FM音源の仕組みを視覚的に理解する

FM音源って知ってますか? 今じゃ表立って耳にする機会も少ないですが、つい最近まで携帯電話の着メロなんかはこのFM音源を使ってました。

「機械っぽい音」なんていわれるとまぁその通りではあるんですが、往年のNEC製PCなどで使われていたこともあり、独特な音にファンも少なからずいたりします。

このFM音源、「FM (Frequency Modulation)」と名のつく通り「周波数変調」を利用して音を作っているのですが、これがイマイチよく分かりません。いや、Wikipediaの当該ページを見ると波形を導き出す式も載っていますし、それはそれで分かるんですが、その式をいくら見たところで「どんな音がするか」がよく分からない…。

様々なサイトで「周波数変調は、扇風機の前で声を出すとあ”あ”あ”あ”あ”〜〜〜と音が変わるのと同じ原理です」なんて説明されていたりするのですが、この説明は周波数変調がわかっている人にしか理解できないものだと思うのです。

…というわけで、式を見ても分からないなら手を動かせ、ということで、単純なFM音源を鳴らすプログラムを組んでみました。 各オペレータの波形をリアルタイムに表示させて、パラメータをいじるとどのように波形が変わるのかが分かるようにしてみました。

とりあえずお披露目

Cocoaアプリを作りました。何も考えずに作ったのですが、もしかしたらSnow Leopardでしか動かないかもしれません。 ソースも置いておきます。他人に見せるために書いてないので汚くてコメントないですが…。

ま、適当にいじってみてください。大したことはできませんが…。 頭では原理がわかっていても、パラメータをいじると実際に波形が変わるので、見てるだけで(個人的には)楽しいです。 また、パラメータだけだと想像つかなかった音色も、波形を見ればだいぶ想像しやすくなる気がします。

FM音源のキホン

Wikipediaの説明を読むと、FM音源の基本は周波数を変調することだそうですが、どう変調するか、そこがキモのようです。 昔の数学やら物理やらの授業の記憶を掘り返し、頑張って正弦波(sin波)の基本公式を思い出してください(笑)

y = A sin (2 π f t + φ)

ってやつですね(Aは振幅、fが周波数、φが初期位相、tが時間)。

この中でA, f, φが一定であれば普通の正弦波になるわけですが(tだけ時間に合わせて値が変わる)、FM音源は、ここのφの部分も時間に応じて変化させて複雑な音を作り出します。

φをどうやって時間変化させるか

基本的なFM音源の場合、φを、さらに別の正弦波を使って時間変化させます。 これが、キャリアとモジュレータの関係みたいですね。キャリアがメインとなる正弦波を作るオシレータ、モジュレータがキャリアのφを時間変化させるオシレータです。

キャリアとモジュレータの周波数は同じでなくても構いません。 ただ、モジュレータの周波数がキャリアの周波数の整数倍でないと、音がキャリア周波数の高さに聴こえません。 これは、整数倍でないときに

y = A sin (2 π f t + φ)

のsinの中身が、キャリアの1周期ごとに0にならなくなってしまうからです(ちょっと計算してみるとわかります)。

エンベロープジェネレータを使ってさらに変化させる

エンベロープジェネレータの説明はWikipediaなどを読んでいただくとして。 楽器から音が出始めてから終わるまで、音量は一定ではありません。オルガンなどは鍵盤を押した瞬間に最大音量となり、離すと音がプツリと消えますが、ピアノであれば鍵盤を話しても弦が揺れて少しのあいだ音が鳴り続けますし、バイオリンなどは音の出始めがゆっくりです。

FM音源の場合、キャリアに対してエンベロープ変化をつけると、上記のように「オルガンっぽい音の出だし」から「バイオリンっぽい音の出だし」といったように音量を変化させることができます。

しかしさらに複雑なことに、モジュレータの出力に対してもエンベロープジェネレータを使って変化させることができます。 これによって、キャリアから出力される波形が最初は普通の正弦波なんだけどだんだんφが大きくなって違う音になります。つまり、エンベロープジェネレータをモジュレータの出力にかけることによって、音量だけでなく音色まで変化させることができるようになるわけです。

どうやってコーディングしてるか

FM音源のオペレータは、構造体で以下のように定義されています。

struct _FMInfo{
    double isFB;
    int isEnabled;

    double carrierFreq;
    double freqIndex;
    double modIndex;

    double attack;
    double decay;
    double sustain;
    double release;

    int numOfParents;
    FMInfo** parents;
};

そして、ある時間の波形の高さは、以下の関数で計算しています。ほんとに、上記の公式を愚直に計算してます(笑

double fmGetValue(FMInfo* fm, double sec){

    double parentPhase = 0.0;

    for (int i = 0; i < fm->numOfParents; i++){
        parentPhase += fmGetValue(fm->parents[i], sec);
    }

    if (fm->isFB > 0){
        double value = 0.0;
        double beta = M_PI * fm->isFB / 8.0;

        for (int i = 0; i < 20; i++){
            value = sin(2.0 * M_PI * (fm->carrierFreq * fm->freqIndex) * sec + beta * value);
        }

        return fm->modIndex * value * fmGetPower(fm, sec);

    }

    return fm->modIndex * sin(2 * M_PI * (fm->carrierFreq * fm->freqIndex) * sec + parentPhase) * fmGetPower(fm, sec);
}

fmGetPowerという関数はエンベロープジェネレータでの高さを計算する部分です。 今回は、「鍵盤を離した」部分は「音が鳴り始めたら4秒」と決め打ちにしているので、以下のようなコードになっています。

double fmGetPower(FMInfo* fm, double sec){

    double power = 1.0;

    if (sec < fm->attack){
        power = sec / fm->attack;
    }else if (sec < fm->decay + fm->attack) {
        double t = sec - fm->attack;
        double w = (1.0 - fm->sustain) * t / fm->decay;

        power = 1.0 - w;
    }else if( sec < 4){
        power = fm->sustain;
    }else if (sec > 4 && sec < (4 + fm->release)) {
        double t = sec - 4.0;
        power = fm->sustain * (1.0 - t / fm->release);

    }else if (sec >  + fm->release){
        power = 0;
    }

    return power;
}

興味のある方はソース中にあるOperator.hおよびOperator.cをご覧下さい。綺麗ではありませんが、どうなっているかは理解できるのではないかと思います。

オペレータの並列接続

今回のアプリは、キャリアとモジュレータ2つの3オペレータを直列につないだものしか音が出せないのですが、実際には並列接続のものもあります。 並列接続は、いわゆる波形の合成です。周波数をいじるのではなくて、単純に足し算ですね。

上記のコードを読んだ方はお気づきかもしれませんが、コード内では既に並列接続の計算もできるようになっています。ただアプリのUIが複雑になるため、今回はパスしました。暇があったら作るかもしれません。…作らないかもしれません。

まとめ

FM音源の原理はわかっていてもイマイチどういう音が出てくるのか想像できなかったため、簡単なFM音源もどきを実際に作りました。 パラメータをいじって音色を確かめられるだけではなく、波形がリアルタイムに変わることで、パラメータを意図して変化させることも容易になるかもしれません。

今回のアプリではオペレータの並列接続はサポートしていませんが、いつか暇ができたら(そして興味がつづいていたら)実装するかもしれません。 AudioUnitで動く音源を作るのも面白そうですが、そこまでできるかなー。

蛇足

エントリと直接関係ありませんが、右にある本はiPhoneでCoreAudioをいじくるにはとても良い本です。少々値段が高いのですが、iPhone / iPad / iPod touchで音楽をいじるにはこの本は必須だと思います。どうもCoreAudio系はAppleの技術文書が少ないイメージがあり、このように系統だって(それも日本語で!)まとめられた本があるのは助かります。

実はこの本の中にシンプルなFM音源ドラムマシンの実装があり、最初はこれを参考にiPadアプリを作ろうとしていました(オペレータ間の接続をタッチで行ったりできると楽しいなぁ、と)。

ただiPadよりもまずは慣れたMacでやろうということで、ひとまず上記のアプリになりました。また、波形生成のアルゴリズム部分に関しても、オペレータの並列・直列やフィードバックなどを盛り込んだため、異なった実装になっています。

補足

次のエントリに4オペレータ版で並列配置も可能なものを公開しました。よろしければご覧になってください。

On-vehicle movie overlaying vehicle information using CANUSB

I overlaid various vehicle information (i.e. speed, rpm, and so on) extracted by CANUSB on my on-vehicle movie.

HS-CAN Data

At first, I tried to use information posted by Madox.NET, but unfortunately HS-CAN Data extracted by my RX-8 look totally different from Madox’s one.

I’m not sure why there are big differences. But one possible reason is that Madox’s RX-8 is AT. My RX-8 is 2007 5MT model.

  • RPM: ID 0x201, (data[0] * 256 + data[1]) / 4
  • Vehicle Speed(km/h): ID 0x201, (data[4] * 256 + data[5] – 10000) / 100
  • Accel Throttle Position(0 – 255): ID 0x201, data[6]
  • Hand Brake(on/off): ID 0x212, (data[4] & 0x40)
  • Foot Brake(on/off): ID 0x212, (data[5] & 0x08)
  • Declutching(on/off): ID 0x231, (data[0] & 0xf0)
  • Engine Coolant Temp(degree celsius): ID 0x240, data[3] – 40
  • Intake Air Temp(degree celsius): ID 0x250, data[3] – 40

Here is what I analyzed.

I want to extract some more information such as steering column angle, but I haven’t yet.

Overlaying

I used Apple’s Quartz Composer for overlaying information.

CAN + Quartz Composer + 車載動画 = PS4動画?

CANデータを使った動画、もう少し派手めに…ということで、作ってみました。 といっても、CANのデータからいちいち速度などの情報を手で入力していては日がくれてしまうので、それらを自動でレンダリングする術を考えなければなりません。

今回は、Quartz Composerのカスタムパッチを作ることでCANログをQuartz Composerに取り込むことにしました。

Quartz Composer?

Quartz Composerは、いわゆるビジュアルプログラミング環境です。Mac OS Xの開発環境(無料)に同梱されています。

これを使うと簡単にモーショングラフィクスを作成できるのですが、当然のことながらCANデータログを読み込んでくれるようなパッチはありませんので、それを自作することにしました。

昔はカスタムパッチの作成手順は公開されていなかったので面倒でしたが、今はオフィシャルの情報をたどると簡単に作ることができます。 Objective-C 2.0のプロパティなどを使うことで、パッチのポートの宣言なども煩雑にならずにできるようになりました。

Quartz Composerのオフラインレンダリング

QuickTime 7の時代には、QuickTime PlayerをPro版にするとQuartz Composerのパッチを動画として書きだすことができました。 Mac OS X 10.6になってQuickTimeはQuickTime Xに刷新されましたが、一応オプションでQuickTime 7をインストールすることができます。

最初はこれでなんとかなるかと思っていたのですが、どうやらカスタムパッチを含むコンポジションの場合は、セキュリティなどの問題でQuartz Composer以外では無効にされてしまうようです。

Appleのデベロッパ向けのサイトにQuartz Composer Offline Renderingというサンプルコード(最初の10フレームを書き出す)があるのですが、どうもコードが古いせいか、きちんと静止画を書きだすことができませんでした。色味などがおかしい…。

しかし、Leopard時代から書き出し関係で新しいメソッドが用意されており、そちらに書き換えるとうまく静止画を書き出すことができました。それらを30fpsで全フレームをレンダリングし、最後にフレームをまとめて動画にする、というようにプログラムを書き換えました。

このOffline Renderingに関してはそこそこ需要があるような気がするので(そもそもQuickTime 7を入れたくないですし、Proにするのが無料じゃないですし)、次のエントリでまとめて説明、配布しようと思います。

まとめ

CANデータを車載動画にかぶせるようなものを作るため、Quartz Composerのカスタムパッチを作成してレンダリングしてみました。

今回の動画は、ビデオカメラで撮影した動画を運転終了後にCANのログと重ねあわせましたが、USB接続のWebカメラなどを使えばリアルタイムレンダリングも可能だと思います。

これで生放送とかしても面白そうですね。

iPhoneのSafariを使って走行中の道路名をtweetしてみた

というわけで、サーバに展開した国交省のデータを使って、実際にTwitterでつぶやくようなアプリを作ってみました。

といっても、専用アプリを書くのは面倒なので、ひとまずはiPhoneのSafariからGPS情報をサーバに送りつぶやくようにしてみました。

仕組み

iPhoneのSafariは、JavaScriptを利用して現在位置を取得するGeolocation APIに準拠しています。そこで、定期的にiPhoneから現在位置をサーバに投げてやり、サーバ側で道路名を解析してTwitterにツイートさせてやるような仕組みを作りました。 iPhoneのSafariでGPS情報を扱う方法は、Ascii.jpのiPhoneのGPSをJavaScriptで操ろうという記事が参考になります。

…というか、今回やったことはこの6ページ目にあるサンプル03をちょいといじっただけです。

ここのソースコードにupdate関数があり、位置情報が更新された際に呼び出されます。結構これは頻繁に呼び出されるので、たとえば10分おきにサーバに情報を伝えたい、なんてときには、update関数の最後あたりに

var now = new Date();
if ((now.getTime() - before.getTime() ) > (1000 * 60 * 10)){
    before = new Date();
    updateStatus();
}

こんなのを埋め込んで、10分おきにupdateStatus関数が呼ばれるようにすれば良いです。

そして、updateStatus関数内では、lat変数とlng変数を利用してサーバ側にデータを渡してやります。ここではXMLHttpRequestを使います。たとえばこんな感じに。

var url = "http://your_site.com/rest.jsp?lat=" + lat + "&lng=" + lng;
var myRequest = new XMLHttpRequest();
myRequest.open("GET", url);
myRequest.onreadystatechange = function(){ 
    //readyState値は4で受信完了
    if (httpoj.readyState==4){ 
        getServerResponse(httpoj)
    }
}
myRequest.send(null);

そしてまぁ、urlからの返答如何によっては再送したりなんなりをgetServerResponse内で実装してやれば良いです。

サーバ側では、前回までに作ったDBでHibernateを利用しつつ道路名を割り出し、Twitter4Jを使ってツイートをしています。

できばえ

まず大学まで、いつもとは全然違う道をとおって走ってみましたが、うまくいきませんでした。これは単純に道路名割り出しルーチン内で、しきい値がやたらシビアだったためでした。

そのため大学でちょっとプログラムを書き直し、またいつもとは全然違う道を走って動作確認をしたところ、そこそこうまくいっているようです(それが上の図)。 ただまぁ、例によって15年前のデータなので「浦和東村山線」なんて道路名が出てきたりしてますが、現在は「さいたま東村山線」だったりするようです。

最新のデータについては、先日国交省にもらえないのかメールしてみました。担当者に確認の後返事を頂けるようですが、どうも「公開していない理由」を担当者に確認するみたいな雰囲気なので、あまり期待せずに待っています^^;

まとめ

常にツイートし続けるのはどうかと思いますが、どっか遠出するときとかはおもしろいかもしれません。そこそこうまくツイートできてるっぽいですし。 今は一定間隔でツイートしてますが、道路が変わったらツイートする、なんてのも面白いかもしれませんね。

DarwiinRemote 0.5をリリースしました

ごぶさたしております、Hiroakiでございます。

やっとこさVersion 0.5のご案内です。
今回のバージョンでは、クラシックコントローラのサポートおよび、これまで懸案の一つであったPPCマシンでの不具合の修正が行われています。
ダウンロードはこちらよりどうぞ。


そういえば、先月末に発売されたMac People 2007年4月号にWii関連の特集が組まれてDarwiinRemoteも紹介されました。
DarwiinRemoteの動作に関する質問や、ゲラ刷り原稿が編集の方からPDFで送られていてチェックを頼まれたりしたので、てっきり献本等のお話があるかと思いきや…。結局特に何もなく。
こちらから何か言うのもなんなので、自分では結局買わないままです。読みはしましたけど、ね。

記事自体はとても簡潔に操作法などが纏められているので、DarwiinRemoteの使い方が分からないなどの場合にはご参考になさってください。分かりやすいと思います。

DarwiinRemote and WiiRemoteFramework 0.5 have been released!

Hi all,

I’m very sorry that I was far away from developing DarwiinRemote…
anyway, I’ve released new version of DarwiinRemote and WiiRemoteFramework.


The latest DarwiinRemote supports classic controller, and some critical bugs including PPC issue were fixed. Please download the software from here. Enjoy!


In this version, especially Jasen made great efforts to improve the framework 😉

DarwiinRemote 0.4をリリースしました

なんか、Nobiさんに「なお、現行のバージョンは、やや技術スキルがある人を対象にしたものなので注意が必要だ。」と書かれてしまって、まぁ、確かに英語だけしかなければ普通の人は使うのを躊躇するかなぁ、なんて思ってしまった最近です。
というわけで、日本語でもリリースを書くことにします。日本語はFAQ以来なので少々詳しく書きます(あと、「日本語だから」ってのもありますけど^^;)。

DarwiinRemoteはご存じの通り任天堂のWiiについてくるWiiリモコン(単品でも買えます)をMacで使うようにするためのソフトウェアです。
今回のバージョン0.4では、以下のことが出来るようになりました。

  1. 拡張コントローラの一つであるヌンチャクに対応しました。
  2. 今までは自分でセンサの値をキャリブレーションする必要がありましたが、Wiiリモコン内部の値も使うことが出来るようになりました。
  3. Wiiリモコンのボタンを押した際に起こるイベントをカスタマイズできるようになりました。カスタマイズデータを保存することも出来るので、場面場面で切り替えることが出来ます。DarwiinRemoteメニューから、Preferences…を選んでください。
  4. マウスの移動速度を調整できるようになりました。

ダウンロードはこちらからどうぞ。この中にある、DarwiinRemote0.4.dmgというのがそれです。クリックすると、どこからダウンロードするか選べるはずですので、リストの中からどれかを選んで「Download」をクリックしてください。


クラシックコントローラへの対応とか、ヌンチャクのジョイスティックの対応とかやることはたくさんあったのですが、あまり間を開けるのもどうかなと思い、実用性があがって一段落ついたものをリリースしました。
ちなみに一般の方にはどうでも良いことですが、キーのカスタマイズはCoreDataとCocoa Bindingという比較的新しい技術を使って実装しました。初めて使いましたが、なかなか便利で良いですね。ただ逆に、10.3では確実に動かなくなってしまいました(今までのやつは、おそらくちょっとファイルを変えれば動いたはず)。まぁ来月には10.5も発表されるので大目に見てください。


P.S.
これまで微妙にamazonへのアフィリエイトリンクを貼っていましたが、このエントリだけはずいぶん貼ってあります(笑
もしまだWiiリモコンを持ってないという方は、よろしければこちらのエントリのリンクから飛んでamazonで購入してもらえると嬉しいです。いくばくかのお金(売り上げの3%くらい)がHiroakiのもとへ入ってきます。
ただまぁ、そんなことをいっても実際のところあまり期待はしていないのです。というのも、これまでのエントリで得られた紹介料は130円ですから(笑


次のバージョンではクラシックコントローラへの対応をやりたいです。
しかし、DarwiinRemoteで使うとなると「ジョイスティック」は何に使えばいいんでしょうね。もう一方のWiiRemoteFrameworkではいろいろ遊べそうですけれど。

DarwiinRemote and WiiRemoteFramework 0.4 have been released!

Hi all,
We’ve just released DarwiinRemote 0.4 and WiiRemoteFramework 0.4.

New features of DarwiinRemote are…

  • supports Nunchuk (sorry still not Classic Controller, but will support soon)
  • supports custom key mappings; you can customize mappings, save and load it.
  • supports mouse sensitivity
  • supports motion sensor auto calibration

New features of WiiRemoteFramework are…

  • supports communicating with Exspansion devices (now Nunchuk only)
  • posts notification when Expansion port is plugged and unplugged
  • post notification when battery is low
  • can retrieve calibration data

Enjoy them and please let me know what you notice about these software.

Download from here!