たまりば

  パソコン・インターネット パソコン・インターネット  三鷹市 三鷹市

JavaScriptで生成した波形をHTML5のaudioで再生
2015年09月30日 00:02


タイトルの通り。
前々からやりたいと思っていたがやっとできた。
FirefoxとChromeで動作確認。IEはwavに非対応らしい。なんでじゃ。

//ArrayBufferを生成
var arrbuf = new ArrayBuffer(44100*2*5+44); //44.1kHz、2チャンネル、5秒、8bit +ヘッダ分
//ArrayBufferをUint8で扱う。せっかくなのでクランプ。
var uint8arr = new Uint8ClampedArray(arrbuf);
//wavヘッダ。各種データは決め打ち。
var head = [
    0x52, 0x49, 0x46, 0x46, 0xC8, 0xBA, 0x06, 0, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, 0x20,
    0x10, 0, 0, 0, 0x01, 0, 0x02, 0, 0x44, 0xAC, 0x00, 0x00, 0x88, 0x58, 0x01, 0x00,
    0x02, 0, 0x08, 0, 0x64, 0x61, 0x74, 0x61, 0xA8, 0xBA, 0x06, 0
    ];

var i=0;
for( ; i<head.length; i++)
{
    uint8arr[i] = head[i]; //ヘッダをArrayBufferに入れる
}
for( ; i<uint8arr.length; i++)
{
    uint8arr[i] = (i%256-128)/3+128; //波形データ生成。鋸歯波。3で割ってるのはボリューム100%だとうるさいから。
}

var blob = new Blob([arrbuf]); //ArrayBufferをBlobに

var bloburl = window.URL.createObjectURL( blob ); //BlobのURLを生成

document.getElementById("aud").src = bloburl; //URLをaudioのsrcに入れる
15/10/03 修正
(i%256)/3+128 → (i%256-128)/3+128
直流分出ちゃってました。


参考文献:
ArrayBufferとBlob
http://hakuhin.jp/js/array_buffer.html
http://hakuhin.jp/js/blob_url_scheme.html
WAV
http://www.web-sky.org/program/other/wave.php
  

  • 初代PIC解説
    2015年09月22日 05:27

    PICマイコンの歴史を追っていこうと思う。
    以前ベースラインPICの注意点としてベースラインからミッドレンジでの差異を書いたが、今回はそのさらに前、PIC1650について。

    PIC1650はまだMicrochipが分社化される前、GIにより作られたもので、「商業的に入手可能な最初のPIC」であるようだ。
    CP1600という16bitマイコンの周辺インターフェース制御のために作られたそうだ。
    そう、なんで8bitなのにPIC16なのかの謎がこれで解けた。

    ネットで探すとデータシートが見つかるので現在のPICと比較してみたところ、これが現在でいうベースラインPICとほとんど同じと言っていい作りであった。初代から現在まで連続的に拡張を繰り返しているわけだ。それはアーキテクチャも変態になろうというものだ。
    この頃はまだアーキテクチャが単純で整然としている。

    具体的に見ていこう。

    クロックは外部クロックと外部RCが使用でき、最大周波数は1MHz。
    現在のPICはほとんどがRC発振器内蔵・発振子用の発振回路内蔵だがそのようなものはない。

    コールスタックはベースラインと同じく2レベル。

    レジスタは今でいうSFRを含め32本のみ。ページングなし。
    今のようにアセンブラで指示するためのレジスタ名は付いていないようで、F0など数字で書かれている。
    F0 (名前なし)
    F1 Real Time Clock Counter Register
    F2 Program Counter (PC)
    F3 Status Word Register
    F4 File Select Register (FSR)
    F5 I/O Register A (RA)
    F6 I/O Register B (RB)
    F7 I/O Register C (RC)
    F8 I/O Register D (RD)
    これを見て分かるように、周辺機能と呼べるものはReal Time Clock Counterしか存在しない。

    現在のPICで最も近いと思われるPIC16F5xと比較してみよう。
    00 INDF
    01 TMR0
    02 PCL
    03 STATUS
    04 FSR
    05 PORTA
    06 PORTB
    07 PORTC (16F57,59のみ)
    08 PORTD (16F59のみ)
    09 PORTE (16F59のみ)
    普通にアクセスできるレジスタに関しては全く同じ構成であることが分かる。(後述するようにOPTION_REGとTRISxは無い)

    ただし機能は異なるものもある。順に比較しよう。
    ・F0
    今のINDFと同じ
    ・F1
    リアルタイムクロックなどと大層な名前が付いているが今のTMR0の外部入力モードと同じ。
    内部クロックのカウント機能は無い。ただしクロック出力ピン(現在のものと同じく1/4出力)はあるので外部でタイマー入力につなぐことで同じ動作が可能。
    プリスケーラや入力エッジ選択機能も無い。
    ・F2
    今のPCLと違い、書き込みのみで読み出し不可。
    つまり現在のような「ADDWF PCL」でのジャンプは出来ないことになる。定数テーブルの読み出しが面倒である。
    ・F3
    内容は、
    1 1 1 1 PC9 Z DC C
    PC9はPCの(0から数えた)9bit目、今でいうPA0相当。ただし将来のための予約bitで、PIC1650は512Wordしかないため未使用。
    スリープ・WDT関係のフラグが無く、PA0相当の位置が違うが、内容は現在のSTATUSとかなり近い。
    ただし今のSTATUSと違い、ビットセット/クリア命令でのみ書き込み可能。
    今のSTATUSは、「C,DC,Zのうちいずれかのフラグに影響する命令を使うと、この3つ全てのフラグへの書き込みが無視された上で、命令の影響でフラグがセットされる」という複雑な仕様である。
    ・F4
    今のFSRと同じ。未使用bitが「1」で読めるところも今と同じ。
    ・F5-F8
    今のPORTxに相当するが、TRISxレジスタは無い。
    しかしポートは入出力が可能ということになっている。説明を読むと、
    1を書き込むと、Highになる
    0を書き込むと、Lowになる
    読むと、現在のピンの状態が読める
    これだけ見るとただの出力ピンだが、このHighというのが出力電流100μAでしかない。そうか、この頃はCMOSじゃなかった。
    つまり、実質的に、1でプルアップ・0でLowということなので、1を書き込んだ状態でプルアップ付き入力として使えるわけである。
    説明を読むと、TTLデバイスの入力やオープンコレクタデバイスの出力につなげますよと書いてある。TTLの出力には繋げないのだろうか。

    命令を並べてみると、整然としている。
    000000 0 00000No OperationNOP
    000000 1 fffffMove W to fMOVWF
    000001 0 fffffClear WCLRW
    000001 1 fffffClear f CLRF
    000010 d fffffSubtract W from fSUBWF
    000011 d fffffDecrement fDECF
    000100 d fffffInclusive OR W and fIORWF
    000101 d fffffAND W and fANDWF
    000110 d fffffExclusive OR W and fXORWF
    000111 d fffffAdd W and fADDWF
    001000 d fffffMove fMOVF
    001001 d fffffComplement fCOMF
    001010 d fffffIncrement fINCF
    001011 d fffffDecrement f, Skip if ZeroDECFSZ
    001100 d fffffRotate Right fRRF
    001101 d fffffRotate Left fRLF
    001110 d fffffSwap halves fSWAPF
    001111 d fffffIncrement f, Skip if ZeroINCFSZ

    0100 bbb fffffBit Clear fBCF
    0101 bbb fffffBit Set fBSF
    0110 bbb fffffBit Test f, Skip if ClearBTFSC
    0111 bbb fffffBit Test f, Skip if SetBTFSS

    1000 kkkkkkkkReturnRET (ビットパターンは原文ママ; 後述)
    1000 kkkkkkkkReturn and place Literal in WRETLW
    1001 kkkkkkkkCall subroutineCALL
    101x kkkkkkkkGo To addressGOTO
    1100 kkkkkkkkMove Literal to WMOVLW
    1101 kkkkkkkkInclusive OR Literal and WIORLW
    1110 kkkkkkkkAND Literal and WANDLW
    1111 kkkkkkkkExclusive OR Literal and WXORLW
    現在のベースラインPICの33命令と比べ、無い命令がTRIS, OPTION, SLEEP, CLRWDTの4つ。
    TRISは先述。
    OPTIONは、設定するほどオプションが無い。
    NMOSなのでクロックを止めたところで電力は減らないのでスリープという概念が無い。(という理解でいいのかな…)
    ウォッチドッグタイマは無い。
    その他の命令はベースラインと同一である。
    GOTOの9bit目が「x」と表記されているが、説明を見るとページ切り替えということで、動作はベースラインと同じで表記が異なるだけのようだ。たぶんリテラルを8bitに合わせたかったのだろう。
    RET命令が表に載っているがなぜかビットパターンはRETLW命令と同じである。説明を見ると「0→W, RAR→PC」とあり(RAR = Return Address Register)、たぶん誤植で本来は「1000 00000000」と書きたかったのだろう。
    現在もベースラインでRETURN命令は「RETLW 0」のエイリアスとなっているのでそれと同じことである。

    なおベースラインでの追加4命令+隠し命令HALTのビットパターンを見ると、後から隙間に追加したことがよく分かる。
    0000 0000 0001 HALT
    0000 0000 0010 OPTION
    0000 0000 0011 SLEEP
    0000 0000 0100 CLRWDT
    0000 0000 0101 TRIS PORTA

    0000 0000 1001 TRIS PORTE
    ついでにEnhancedベースラインの追加命令も並べておこう。こちらは空き領域の上から攻めてきているようだ。
    0000 0001 1111 RETFIE
    0000 0001 1110 RETURN
    0000 0001 0kkk MOVLB