有名おもしろIC

8色バトルサウンドキットという言葉に聞き覚えはあるでしょうか。無くても、こんな音に聞き覚えはありますか。
※音量注意!

バトルサウンド #6

今から30年以上前だと思います。こんな音が 8種類入った、ただボタンを押して音が鳴るだけの玩具が流行したのです。そして、時期は定かではありませんが秋月電子でもこの音が出るキットを販売していたのです。それが8色バトルサウンドキットです。

キットとしては非常にやさしく、何せ IC が全ての機能を内蔵していますからボタンとスピーカーとあと少々を付けるだけで動いてしまうのです。この IC が GSE3568 というメロディIC です。扱いの簡単さと派手な電子音が鳴る楽しさから、いつも部品箱の中に置いておきたいような、そんな IC です。型番違いですが、私の部品箱には同じ機能の M09 という IC があります。

GSE3568同等品 M09

キットではありませんが、セリアで売ってたケースにこの IC を組み込んでみた様子がこんな感じです。

作品例 中身
作品例 外観

M09 と GSE3568 の関係はよく知りませんが、少なくとも全く同じと言っていい使い勝手です。秋月電子から GSE3568 が消え、別の通販で見つけた M09 を確保しておいたのですが、それも品切れになって久しいです。両者共に今は非常に入手困難、IC 単体としてはもう流通していないんじゃないかと思える程で、まさに絶滅危惧種なのです。これは由々しき事態です。そうこうしているうちに部品箱の M09 ももう尽きそうです!早くなんとかしなければなりません!ATtiny10 ならたくさんあるのに!ATtiny10 なら!!

ATtiny10?

中央 ATtiny10

正体を捕らえる

ぶっちゃけ GSE3568 であろうと M09 であろうと、ただ音が鳴るだけのおもしろIC に過ぎません。サウンド出力は 1bit ですので、所詮は出力ピンを ON/OFF してるだけです。Lチカみたいなもんです。だったら ATtiny10 でそっくり同じように ON/OFF すれば代わりは務まるということです。というわけで、このおもしろICの正体を探ります。

ちなみに8種類の音を出し分けるには入力となるボタンが 8個欲しいですが、電源ピン込みで 6ピンしか無い ATtiny10 でも心配いりません。多ボタン入力は以下のシリーズで扱っていて、今回もこの方法を使いますので興味があればぜひ。

ATtiny10 で多ボタンを扱う方法

M09 データシート

さてこのメロディIC ですが、手元にある M09 のデータシートはこんな感じです。

中国語がさっぱりでもシンプルな IC ですので見当は付きます。内部発振器は 128kHz、BZ が音声出力ピン、X,Y がオシレータ用の抵抗 150kΩ 接続端子、あとは電源ピンと K1~K8 の 8つのボタンです。K9 もボタンですが、これは内蔵された全種類の音を一気に再生するボタンで、テスト用みたいなものです。LO という LED出力もあるみたいですね。音に合わせてピカピカするんですかね。とりあえずサウンドにしか興味が無いので、LED は気にしません。

クロック単位のサンプリング

この M09 のサウンドの構成を知るために、まずはそのサウンドを録音してみようと思うでしょう。もちろん私の最初のアプローチもそうでしたが、バッサリ省略して恐縮ですが普通に録音するのはやめました。M09 のクロックに同期して正確にサンプリングすることにします。というのは、内蔵 CR発振器では発振周波数に幅があったり揺れたりしますので、そんな状態で録音しても結局サウンドの正しい周波数やタイミングが分からないからです。どうせ調べ上げるなら正確にやりたいところですしね。

クロック単位のサンプリングのためには、M09 が発振するクロックに合わせてサンプリングする方法と、外部から都合のよいクロックを与えながらサンプリングする方法があります。実現できるならどちらでもよいのですが、今回は後者で行きます。相手にタイミングを合わせるより、こちらの都合の良いタイミングを与える方が簡単だからです。というわけで、外部からクロックを与える方法を確認します。

この手の IC の CR発振器は大体こんな感じの回路になってるかと思います。

CR発振回路

簡単に説明しますと、COSC に電荷が少ない状態では C点と A点がいわばショート状態ですから、A点の論理値は C点の論理値と同じになります。そして A点から見てインバータ(NOT回路) 2つ目の出力は非反転ですから、A点の論理値と同じになります、つまり COSC によってC点の論理値が A点を通って素通しで C点に出力され、その論理値が維持されます。
一方で B点は C点と反対の論理値ですから、ROSC を通じて COSC に電荷がチャージされていくと、いずれ A点は C点の論理値から B点の論理値に移ります。そうすると C点の出力は反転します。C点が反転すると COSC が放電され、また電荷の無い状態から繰り返し、発振することになります。

このような発振器であれば、M09 は発振のために外付けの抵抗を付けるようになっているので、上図 A点と B点がデータシートで示されるオシレータ端子 X, Y のどちらかに対応することになります。それを確認するためにオシロを使って観測します。

X Y 端子の様子

黄色の Ch1 が X、青色の Ch2 が Y です。Ch1 はデジタルな出力ですからインバータの出力っぽいですし、Ch2 はコンデンサのチャージ電圧っぽい波形なのでインバータの入力っぽいですね。なので X は B点、Y は A点ということになります。
これが分かると、外部クロックはインバータの入力である A点 = Y に入力すればよいということが分かります。もちろんその時 ROSC は外しておきます。COSC の悪影響もありますが、小さな容量でしょうから無視します。

外部クロック入力方法が判明したところで、次のように接続します。お手軽に GPIO を使える Raspberry Pi 登場です。ちなみにうちのは初代です。

M09 と RaspberryPi 結線図
M09 と RaspberryPi 接続

RaspberryPi の GPIO の番号がバラバラですが、コネクタの並びに従っただけで特に意味はありません。とにかく繋がればいいです。そして RaspberryPi では、M09 の Y に繋がる GPIO17 を ON/OFF しながら M09 のサウンド出力 を GPIO27 から、ついでに LED出力も GPIO22 から読み取っていきます。
PHP でこんなコードを書いてみました。

rdM09.php
<?php

define('GPIO_CLKOUT', 17);
define('GPIO_SOUNDIN', 27);
define('GPIO_LEDIN', 22);

$clk = new GPIO(GPIO_CLKOUT, true);
$snd = new GPIO(GPIO_SOUNDIN, false);
$led = new GPIO(GPIO_LEDIN, false);


$fp = fopen('m09.log', 'w');
$c = 0;
for(;;) {
    $buf = '';
    for($i = 0; $i < 64; $i++) {
        $clk->wr($c);
        $s = $snd->rd();
        $l = $led->rd();

        $buf .= $c | ($s << 1) | ($l << 2);
        $c = 1 - $c;
    }
    $buf .= "\n";
    echo $buf;
    fwrite($fp, $buf);
}
fclose($fp);


class GPIO {
    private $pin;
    private $path;

    function __construct($pin, $isout = null)
    {
        $this->pin = $pin;
        $this->path = '/sys/class/gpio/gpio' . $pin . '/';
        file_put_contents('/sys/class/gpio/export', $pin);
        if ($isout !== null) $this->mode($isout);
    }

    function __destruct()
    {
        file_put_contents('/sys/class/gpio/unexport', $this->pin);
    }

    function mode($isout)
    {
        file_put_contents($this->path . 'direction', $isout ? 'out' : 'in');
    }

    function rd()
    {
        return (int)file_get_contents($this->path . 'value');
    }

    function wr($b)
    {
        file_put_contents($this->path . 'value', $b ? 1 : 0);
    }
}

このスクリプトを開始してから、M09 の任意のキー入力を行います。そうして出力されるサウンドなどをサンプリングして画面とファイル m09.log に出力します。サウンド出力と言ってもこのスクリプトのクロック出力は相当遅いので、スピーカーを繋いでいてもチリチリとした音が聞こえるくらいですし、数秒であるはずのサウンドでもサンプリングには数十秒を要します。画面を見て出力の変化が止まった頃合いで CTRC-C して止めて、ログをリネームして、また実行して次の音をサンプリングします。
出力はこんな感じになります。

 :
4545454545454545454545454545454545454545454545454545454545454545
4545454545454545454545454545454545454545454545454545454545454545
4545454545454545454545454545454545454545454545454545454545454545
4545454545454545454545454547676767676767676767676767676767676767
6767676767676767676767676767676767676767676767676767676767676767
6767676767676767676545454545454545454545454545454545454545454545
4545454545454545454545454545454545454545454545454547676767676767
6767676767654545454545454545454545454545454545454545454545454545
4545454545454545454545454545454545454545454545454545454545454545
4547676767676767676767676767676767676767676767676767676767676767
6767676767654545454545454545454545476767676767676767676767654545
4545454545454545454545454545454545454545454545454545454545454545
4547676767676767676767676767676767676767676767676765454545454545
4545454545454545454545454545454545476767676767676767676767676767
6767676767676767676545454545454545454545454767676767676767676767
6767676767676767676767676767676767676767676767676767676767676767
 :

1文字 1サンプルで、クロックの変化も記録しています。ビット割り当ては以下の通りです。

bit0 (1)クロック出力ピン
bit1 (2)サウンド入力ピン
bit2 (4)LED入力ピン
サンプリングデータビット割り当て

冒頭は 4 と 5 の繰り返しですが、これは 音声出力 Low、LED 出力 High の状態でクロックが Low High を繰り返している状態です。サウンド出力中はクロック以外のビットも変化していくのも分かると思いますが、ともかく正確にサンプリングできました。これで解析準備は整いました。
ちなみにこれをオーディオファイル化したものが冒頭のものです。参考に一式を以下に並べておきます。

M09 #1 RIFLE
M09 #2 RIFLE(ECHO)
M09 #3 TV GAME
M09 #4 DUAL TONE
M09 #5 BOMB 1
M09 #6 BOMB 2
M09 #7 GUN 1
M09 #8 GUN 2

元のデータはカッチリした 1bit音声ですが、これらは mp3ファイル化してるので波形は崩れています。

再現方針

改めて言うまでも無いかもしれませんが、このサウンドを再現するのにサンプリングした音を再生しましょうってお話ではありません。サウンドの構成を分析して、どんな周波数のトーン(ピーとかプーとかの音程のある音)やノイズをいつどのくらいの長さ出せばよいかを突き止め、プログラムによってそのような出力を行います。トーンは周期(周波数)さえ分かれば ATtiny10 のタイマ/カウンタを利用して出力できそうです。ノイズの方は ATtiny10 のハードウェア的には生成することはできないので、ノイズ生成アルゴリズムを自前で実装する必要があります。このアルゴリズムを特定するか、特定しないまでも同じようなノイズパターンを出せるようになるために、特にノイズ部分のクロック単位のビットパターンが欲しかったのです。もしノイズが比較的短いパターンの繰り返しということが分かれば、ATtiny10 の小さなメモリでもサンプリングしたものを再生するという選択肢も出てくるかもしれませんし。どちらにせよそのような判断を行うためには、正確なビットパターンが必要なのです。

次回予告

ちょっと短いですが今回はここまでです。次回はサンプリングしたデータから、トーンの変化の仕方、ノイズの再現方法などを分析します。実はこの記事を書いている時点ではまだ ATtiny10 への実装には未着手なので、分析できたはいいものの実装できませんでした!なんて可能性がゼロじゃないのですが、のんびりやっていきます。クロックが 4MHz ないし 8MHz まで選べますからなんとかなるでしょう。

このシリーズ

この記事です

関連記事

多ボタン入力の実現についての記事
ATtiny10 の紹介