2016年10月24日

FM音源をArduboyで動かしてみた


先々週、PWMを使ったシンセサイザをArduboyに移植しましたが、その記事の中でも触れたpcm1723さんの「FMMelody」をArduboyで動かしてみました。

基本的にはタイマー周りの設定をしてあげるだけで動作しました。
鳴らしてみると、圧電スピーカーでもはっきりと音色の違いが表れます。
FM音源は倍音成分が多いので、圧電スピーカー向きの音質なのかもしれません。

パラメータをいろいろいじって遊びたくなったので、パラメータ設定のGUIと、曲が一応変更可能なステップシーケンサーをArduboyで実装しました。
始めてみると、狭い画面にいかに詰め込むかに熱中してしまい、週末をつぶして一気に作成しました。
コードはこちらに置いてあります。

boochow/abSynth-FM: FM Synthesizer with step sequencer for Arduboy

動作させるには、「Arduboy2」ライブラリが必要です。
今回は、ユーザーインタフェースを作りながらコーディングしていったこともあり、コードはあまり綺麗ではありません。
機会があったら見直したいところです。

GUIは例によってpaint.netでお絵かきしながら考えました。
VSTiベースのソフトウェアシンセでよくあるような、見栄え重視のコントローラをイメージしました。

それを先日作ったツールでデータ化しています。
その静止画の上に線や小さなビットマップを上書きすることでGUIを作っています。
paint.netのようなお絵かきツールは、画像の中の座標が簡単に調べられるので、こういうコーディングをするときに便利です。

loopの中は一般的なArduboyのアプリケーションと若干違っていて、画面の書き換えが最小限になるようにしています。
画面周りの処理を重くすると音のほうがとぎれがちになるためです。

Arduboy、シーケンサー付きのシンセサイザーとしてはTeenage EngineeringのPOシリーズよりも小型軽量かもしれませんね。
オーディオアウトがあればチップチューン用に使えたかもしれません。
まあ、分解して線を引き出せば良いのですが。
下のビデオの方はたぶんそれをやっていると思います。


ちなみに分解写真が以下のスレッドにありますが、圧電ブザーの線を引き出すだけなら簡単にできそうです。

Kickstarter Edition numbering - General - Community
タグ:Arduboy
posted by boochow at 01:50| Comment(0) | Arduino | このブログの読者になる | 更新情報をチェックする

2016年10月20日

Make: Japanでご紹介いただきました

今日のMake: Japanで、このブログの最近のArduboy関連記事(画像作成ツール、シェル、PWMサウンド)をご紹介いただきました。

Make: Japan | Arduboyプログラミングに役立つツールとノウハウ

ありがとうございます。
掲載に至るには、お世話になった数々のOSS/フリーソフトに加えてYouTubeとGitHubとミクさんが重要な役割を果たしたと思われます。
こちらにも感謝です。
タグ:Arduboy
posted by boochow at 23:28| Comment(0) | 日記 | このブログの読者になる | 更新情報をチェックする

2016年10月16日

Arduboy用画像作成ツール 解説

前回紹介したツールは基本的には単純なのですが、ウインドウ上に画像を表示する際の処理が若干分かりにくいかもしれません。

自分自身の備忘も兼ねて、解説を書いておきます。

下が表示部分の演算です。
ofRectangle bounds = ofRectangle(0, 0, img.getWidth(), img.getHeight());
ofRectangle sub = ofRectangle(0, 0, 512, 600);
sub.translate(offset);
sub = sub.getIntersection(bounds);

ofSetColor(255,255,255);
img.drawSubsection(sub.x - offset.x, sub.y - offset.y, sub.getWidth(), sub.getHeight(), sub.x, sub.y);

abimager01.png

imgが表示しようとしている画像で、スケーリングなどの処理は済んでいます。
スクリーン上での表示領域は左上が(0,0)、右下が(512, 600)で、これは固定値としています。

imgを実際に表示させるのが最後の行の命令drawSubsectionです。
これは、画像の一部を画面に描画する命令です。
パラメータは最初の2つが画面上の描画領域の左上の点(図のA)です。
次の2つが描画する画像(グレーの領域)の幅と高さです。
その次の二つが描画したい部分(グレーの領域)の左上の「画像データ上での」座標(図のB)です。
上のプログラムは、これら3組のパラメータを求める処理をしています。

img全体の領域(黒枠)を表す矩形がboundsです。

画像の中でスクリーンに表示したい領域(図の赤枠の領域)はスクロールで移動します。
画像の左上を(0,0)とすると、赤枠領域の左上の座標は、スクロールによってoffsetだけずれています。
赤枠の領域の大きさは、スクリーン上での表示領域の大きさ(512×600)と同じです。

赤枠と画像が重なっている領域が実際に描画すべき領域で、図ではグレーで表しています。
この領域は矩形同士の重なり部分を算出する演算getIntersectionで求めています。
その結果をsubに代入していますので、最終的にはsubはグレーの領域を表す矩形となります。

subの左上の点は図のBの座標に相当し、これを-offsetだけ移動することによって、スクリーン上での位置であるAの座標が得られます。
タグ:Arduboy
posted by boochow at 21:33| Comment(0) | Windows | このブログの読者になる | 更新情報をチェックする

openFrameworksでArduboy用画像作成ツール

abimager.png

Arduboy用の画像変換ツールについては以前もちらっと書きましたが、一応動作するようになりました。
いつものことながら、コードはGitHubに上げてあります。

boochow/ArduboyImager

コンパイル済みのバイナリも一応こちらに置いておきます。
[2016/11/12追記]Mac版はこちらです。

説明ビデオも作りました。


ファイルを開いて、マウスの左クリックで切り取り、右下の「a C array」をクリックすればC言語用の配列定数が、「AbShell commands」をクリックすればabshell用のコマンド列が、クリップボードにコピーされます。

C arrayの例:
{
//width = 16, height = 16
0x09, 0xb0, 0x06, 0x49, 0x09, 0x36, 0x46, 0x48, 0x19, 0x07, 0x32, 0x08, 0x05, 0x13, 0x4e, 0x2d,
0x00, 0x00, 0x40, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x60, 0xc8, 0x90,
};


AbShell commandsの例:
clear
bitmap 0 0 16 16
.x 09b00649093646481907320805134e2d0000400008000000000040000060c890


カラー画像を白黒へ変換するディザリングの処理は、下記で公開されていたライブラリを使わせていただきました。(古いためか、そのままだと動作しなかったので、若干修正しています。)

ofxDither | julapy

今回使ったのはopenFrameworksという以前も紹介したツールキットです。
画像処理に関しては、かなり機能が充実していますし、Javaではなくネイティブで動作するので高速です。

今回作ったアプリケーションは、画像処理はopenFrameworksとofxDitherですべて行っていますので、実質的には200行程度のものです。
その内、かなりの部分をGUIのハンドリングが占めており、開発の所要時間も、GUIライブラリの学習とユーザーインタフェースのデザインが半分以上だと思います。

使用したGUIライブラリは、標準的に用意されているofxGuiです。
ドキュメントはあまり整備されていないのですが、openFrameworksの付属のサンプルを見れば何とかなります。
提供されるGUI部品は、CGを生成するアプリを作るために必要な本当の最低限という感じで、ボタンもチェックボックスも見かけは同じですし、扱えるのは数値と論理値だけで、テキストを入出力する部品もありません。

典型的な、数値をスライダーで設定する場合、画像のスケーリングを例にとると、GUIに関するコードは以下のようになります。(抜粋です。)

ofApp.h :
		ofxPanel imageGui;
ofParameter<float> scale;
void scaleChanged(float & v);


ofApp.c :
void ofApp::setup() {
imageGui.setup("Image","settings-image.xml");
scale.addListener(this, &ofApp::scaleChanged);
imageGui.add(scale.set("Scale", 1.0, 0.125, 2));
}

void ofApp::scaleChanged(float &v) {
updateImages();
}

void ofApp::draw(){
imageGui.draw();
}


上記のコードでは、変数scaleはそれ単体でfloat型の変数として動作しますが、Listenerが設定されていて、値が変化するとofApp::scaleChangedが自動で呼ばれます。
(自動で呼びたくない場合は、値の変更にsetWithoutEventNotificationsを用います。)

ofxPanelは複数のGUIコンポーネントをまとめるオブジェクトで、scaleの値を変更するスライダーがofxPanelのインスタンスであるimageGuiへaddによって追加されています。


マウス操作のユーザーインタフェースデザインをどうするかは、一週間ばかり悩みました。

・マウスポインタの直下のエリアが自動で白黒化されるインタフェースが気に入ったので、これを活かしたい
・クリックすると、そのとき白黒になっている部分が取り込まれてデータを出力するのも自然で良い
・白黒化された状態の画像をウインドウ右側で常に確認できる機能も捨てがたい
・クリック&ドラッグで画像をスクロールさせたい

を全部実現するにはどうするか。
最終版では、白黒化された画像の領域を3つ(マウスポインタ直下、その画像を定位置で表示して確認、クリックして取り込んだ画像の確認)用意することで落ち着きました。
これによって、取り込んだ画像と現在の画像の比較をすることもできるようになりました。
posted by boochow at 17:22| Comment(0) | Windows | このブログの読者になる | 更新情報をチェックする

2016年10月10日

ArduboyでのPWMサウンド出力

Arduinoのライブラリには標準でtone命令が用意されていますが、一定音量の矩形波しか出せません。
PWM(パルス幅変調)を使うと、アナログ波形を出力することができるので、より多彩な音を出すことができます。
I/Oピンからは1か0の信号しか出せないのですが、PWMは1と0を高速に出力して、その時間平均を取ることにより中間の値を表現します。

直感的には「白」と「黒」を交互に切り替える操作を高速に行うと、「灰色」に感じられる、というようなものです。時間軸に沿って「白」と「黒」を見せる割合を変化させると、「灰色」の濃さも変化させることができるわけです。

Arduboy内蔵のスピーカーでも、この機能は使えます。
圧電スピーカーなので再生能力は限定されますが・・・。


ということで、ちょっと関連の情報を調べてみたので整理しておきます。


まず、Arduino UNOではPWMを使った音声出力の実験がいろいろ行われています。

・FM音源
Arduino スケッチ 「FMmelody」
Pakurino (1) - シンセ・アンプラグド

・ポリフォニックサウンドジェネレータ
PWMDAC_Synthライブラリ | CAmiDion blog
PWMDAC_Synthライブラリ Wiki - OSDN

・解説記事ほか
[WIP] Arduinoで音を出したい(メモ) - Qiita
Audio via Arduino 16-bit PWM | Sand, software and sound
Secrets of Arduino PWM
TimerのPWMモードで Sin波形を発生
シグマデルタ変調 PWM (1) - シンセ・アンプラグド

これらの記事では実際に動作するスケッチやライブラリが紹介されています。
ただし、そのほとんどはArduino UNO用で、Arduboyにはそのままでは使えません。
ArduboyはArduino Leonardoベースであり、UNOのCPU(ATmega328)とは異なるCPU(ATmega32u4)が使われており、利用できるハードウェアタイマーが異なるためです。
以下に解説があります。

R6500: Fast PWM on Arduino Leonardo
Arduino Timer | TONYLABS

Arduino UNOおよびArduino Leonardoのピンアサイン図は以下にあります。

Arduino Pinout Diagrams – marcusjenkins.com

Arduino UNOでPWM出力できるピンは3, 5, 6, 9, 10, 11です。
ただし、上述のPWMDAC_Synthライブラリの作者さんによると、5と6が連動するTIMER0はArduino の millis() などのために使われているため、利用できないようです。

Arduino LeonardoPWM出力できるピンは3, 5, 6, 9, 10, 11, 12, 13となっています。
また、32u4はタイマー2が無く、タイマー3と4があります。

PWMで利用する、値比較(Output Compare)用のレジスタと出力ピンの関係について、UNOとLeonardoで対比すると以下のようになっています。

Timer 0 (8 bit)
・OC0A → UNO(6)、Leonardo(11)
・OC0B → UNO(5)、Leonardo(3, 18)
Timer 1 (16 bit)
・OC1A → UNO(9)、Leonardo(9)
・OC1B → UNO(10)、Leonardo(10)
・OC1C → UNO(-)、Leonardo(11)
Timer 2 (8 bit)
・OC2A → UNO(11)、Leonardo(-)
・OC2B → UNO(3)、Leonardo(-)
Timer 3 (16 bit)
・OC3A → UNO(-)、Leonardo(5)
Timer 4 (10 bit)
・OC4A → UNO(-)、Leonardo(13)
・OC4B → UNO(-)、Leonardo(10)
・OC4D → UNO(-)、Leonardo(6)
・#OC4A → UNO(-)、Leonardo(5)
・#OC4B → UNO(-)、Leonardo(9)
・#OC4D → UNO(-)、Leonardo(12)

なお、#OCnxは、OCnxのNOTで、かつOCnxの立ち上がりより前・立下がりより後に変化させることができるようです。このへんは詳しいことは良く分かりません。データシートには詳しく書かれています。
また、以下のサイトに日本語訳があります。

AVR.jp

AVRのタイマーに関しては、以下の解説も詳しいです。

AVRでのタイマとPWMの使い方 | うしこlog


ではArduboyはどのようなハードウェア設計になっているかですが、Arduboyの開発過程でも、PWMによる音声出力を想定してスピーカー周辺の設計(主に、どの出力ピンとタイマーを割り当てるか)については、相当に議論が行われていたようです。

Music library brainstorm - Arduboy / Development - Community

その結果、圧電ブザーはPC6(Arduino的には5番ピン)とPC7(Arduino的には13番ピン)の間に接続することになりました。
(下の引用した回路図はPD6につながっていますが、その後の議論でPC7に変わりました。なお、最終的な完全な回路図はこちら
arduboy-schematic.png

Arduboy Kickstarter version design discussion - Arduboy / Development - Communityより引用)

従って、Arduboyの圧電ブザーを鳴らす信号はタイマー3で作ることもできるし、タイマー3とタイマー4を組み合わせて使うこともできるし、タイマー4だけで作ることもできるようになっています。

もっとも、「Pin 6とPin 12にしておけば圧電ブザーから入力することもできたのに!」という意見も書かれていました。スピーカーは電力を運動(音波)に変換しますが、逆に音波を電力に変換することもできるので、ADC入力として使えるPin6を割り当てれば、音を拾えたかもしれないということのようです。


実際にPWMを使ってサウンド再生をするプログラムもいくつか作られています。
もっとも単純なものは、上記のコミュニティ議論の中でノコギリ波を生成するサンプルとして提示されているもので、25番目の書き込みにあります。
似たコードが二つ提示されていますが、1つ目はタイマー4のみ、2つ目はタイマー3とタイマー4を使って信号を生成しています。
タイマー4のみのほうが音量が大きめです。
タイマー4のみを使う場合はスピーカーの2つの端子に逆相の信号を与えられますが、タイマー3と4を使う場合は2つの信号が打ち消しあっているかもしれない、と記事のコメントには書かれています。

Music library brainstorm - Arduboy / Development - Community

また、Arduboy用にさまざまなゲームを作っているTEAM a.r.g.さんが4和音のライブラリを開発中です。現在はまだ完成版ではないようですが、ArduboyBasedTrackerというサンプルが動作しています。

[WIP] 4 channel Music - Arduboy / Development - Community

ということで、私も試しに上述のPWMDAC_SynthライブラリをArduboyに移植してみました。
出力は、とりあえず5番ピン側でタイマー3を使うことにしました。
オリジナルはタイマー1またはタイマー2を使用するようになっていますので、その部分をタイマー3に書き換えます。

6和音だと処理能力の余力が小さそうなので、4和音にしました。
ファイルは以下のGitHubに置いてあります。
動作させるには「Arduboy2」ライブラリが必要です。(Arduboy2はサウンド関連が分離されているため、競合が起こりません。)

boochow/pwmtest: PWM sound synthesize test for Arduboy

一応音は出るようになりましたが、結構小さい音です。
下のビデオではICレコーダーと重ねて録音レベルを最大にして録っていますが、それでもこの程度です。
ゲームの効果音に使うには、ちょっと迫力に欠けるかもしれません。



録音した音声の波形です。音声に強弱が付いていることが分かります。

pwmwave.png


2016/10/11追記:
タイマー4を使うコードも追加しました。やはりタイマー4のみのほうが音は大きいです。

スケッチの中で
#define PWMDAC_OUTPUT_PIN 13
#define PWMDAC_OUTPUT_PIN2 5

とするとタイマー4を使います。タイマー3を使う場合は、
#define PWMDAC_OUTPUT_PIN 5
#define PWMDAC_OUTPUT_PIN2 13

として下さい。
タグ:Arduboy
posted by boochow at 01:48| Comment(0) | Arduino | このブログの読者になる | 更新情報をチェックする
人気記事