パーツライブラリ - SerDAC


2021/6/19公開
2021/6/23更新

概要
ESP8266用UART-DACならびにそのobniz用パーツライブラリを開発しましたので公開します。
名前はSerialを使ったDACなのでSerDAC(汁ダク)としています。
ありがちなanalogWriteによるアナログ出力ではなく32倍オーバーサンプリングのΔΣ変調、すなわちDSD32(=DSD1.4MHz)変換によりそこそこ高音質な音が出ます。あくまでそこそこ。
拙作のSPIkerよりかはだいぶ良い感じです。
ただし出力サンプル間にわずかな謎の間があり連続音が綺麗に出ないので個人的に完成度はあともう一歩といったところではあります。
ESP8266用UART-DACプログラム(SerDAC.ino)とobniz用パーツライブラリ(SerDAC.js)と組み合わせて使います。

製作意図
まずobnizで高音質(=サンプリングレート44.1KHz)な音をなるべく低コストで出せるようにしたいという思いがあったのと、
obnizで音を出したい、となった場合には大抵DFPlayer mini辺りを使うかと思いますが、あれはあらかじめSDカードに書き込んだMP3を再生することしかできず柔軟性に欠けるという点も製作に至ったポイントです。
と、デカイ事を言ってますがソースを見てわかる通り超シンプルな処理です。
色々試行錯誤した結果、最終的にシンプルなコードが一番安定していたのでこのような形になりました。

Arduino環境構築とESP8266用プログラム書き込み
・下記サイトを参考にArduino IDEにESP8266の環境をインストールします。そこそこ手順がありますが頑張りましょう。
Arduino IDE に Stable ( Staging )版 ESP8266 ボードをインストールする方法

作者の環境ではボードはスイッチサイエンス製のESPr Developer(Rev.3)を使用し、下記画像のように設定しています。


・ESP8266Audioライブラリを使用しているので下記サイトを参考にインストールします。
"ESP8266Audioのインストール"の段落のみ実施します。
【SD不要】ESP32の内臓DACを使ってSPIFFS領域のMP3ファイルを再生する

・SerDAC.inoを開き、メニューから「スケッチ⇒マイコンボードに書き込む」を選択してESP8266に書き込みます。
初回コンパイルは10分強程度は時間がかかるのでお茶でも飲んでごゆるりとお待ちください。別にコーヒーでもいいですが。

obniz用パーツライブラリ説明
クラス名は"SerDAC"です。
再生可能なWAVファイルは"44,100Hz モノラル Unsigned 8bit(推奨) または Signed 16bit"ですので必要に応じてAudacityなどの波形編集ツールで変換してください。
WAVファイルの指定はURIによる方法とBASE64文字列による方法の2パターンあります。ローカルファイルは使用できません。
また、WAVファイルヘッダ削除&バイナリ配列生成ツール「Wavギロチン」を使って変換した再生用バイナリデータを使って再生することもできます。
(使用例)

obniz用パーツライブラリ仕様

wired("SerDAC" , { tx, rx, gnd } )


ESP8266と接続します。rxは使用しませんがobnizの仕様上必須のため適当なピンを指定してください。
<script src="https://unpkg.com/obniz@3.x/obniz.js"></script>
<script src="SerDAC.js"></script>

<script>
var obniz = new Obniz("OBNIZ_ID_HERE");

obniz.onconnect = async function () {
  // パーツライブラリの登録
  Obniz.PartsRegistrate(SerDAC);

  var dac = obniz.wired("SerDAC", { rx:9, tx:10, gnd:11 });
}
</script>
配線例は下記の通りです。
obniz ESP8266 スピーカー
Tx IO13 RXD Signal
Gnd GND GND Gnd

パッシブスピーカーを駆動するには少々信号が弱いため、アンプ付きのスピーカーを使うか回路図を参考にトランジスタ(2N3904)を間に挟んでください。
(信号の高周波域のノイズシェーピングがなされていないのでローパスフィルタも追加した方が本当はベターですが)
ブレッドボードを使う場合は3.5mmステレオミニジャックDIP化キットを使うと便利です。

[async] convertFromURI(uri)


引数で指定されたURIのWAVファイル(44,100Hz モノラル Unsigned 8bit(推奨) または Signed 16bit)を再生用バイナリデータに変換します。
16ビット⇒8ビット変換は単純計算でビット深度を下げているので最初から波形編集ツールで変換した方が音質が良いはずです。

httpまたはhttpsから始まるURIのみ指定可能です。(ローカルファイルは不可)
またHTMLとWAVファイルが同じドメイン上に存在する必要があります。
ドメインをまたぐとサーバがクロスオリジンを許可していない限りCORSエラーが出て変換に失敗します。
<script src="https://unpkg.com/obniz@3.x/obniz.js"></script>
<script src="SerDAC.js"></script>

<script>
var obniz = new Obniz("OBNIZ_ID_HERE");

obniz.onconnect = async function () {
  // パーツライブラリの登録
  Obniz.PartsRegistrate(SerDAC);

  var dac = obniz.wired("SerDAC", { rx:9, tx:10, gnd:11 });
  var convertedData = await dac.convertFromURI("https://~~~/sound.wav");
}
</script>

[async] convertFromB64(base64)


引数で指定されたBASE64形式のWAVファイル(44,100Hz モノラル Unsigned 8bit(推奨) または Signed 16bit)を再生用バイナリデータに変換します。
16ビット⇒8ビット変換は単純計算でビット深度を下げているので最初から波形編集ツールで変換した方が音質が良いはずです。
<script src="https://unpkg.com/obniz@3.x/obniz.js"></script>
<script src="SerDAC.js"></script>

<script>
var obniz = new Obniz("OBNIZ_ID_HERE");

obniz.onconnect = async function () {
  // パーツライブラリの登録
  Obniz.PartsRegistrate(SerDAC);

  var dac = obniz.wired("SerDAC", { rx:9, tx:10, gnd:11 });
  var convertedData = await dac.convertFromB64("BASE64形式のWAVファイル");
}
</script>

[async] play(data)


あらかじめ変換した再生用バイナリデータを再生します。
<script src="https://unpkg.com/obniz@3.x/obniz.js"></script>
<script src="SerDAC.js"></script>

<script>
var obniz = new Obniz("OBNIZ_ID_HERE");

obniz.onconnect = async function () {
  // パーツライブラリの登録
  Obniz.PartsRegistrate(SerDAC);

  var dac = obniz.wired("SerDAC", { rx:9, tx:10, gnd:11 });
  var convertedData = await dac.convertFromB64("BASE64形式のWAVファイル");
  dac.play(convertedData);
}
</script>

stop()


再生を停止します。
<script src="https://unpkg.com/obniz@3.x/obniz.js"></script>
<script src="SerDAC.js"></script>

<script>
var obniz = new Obniz("OBNIZ_ID_HERE");

obniz.onconnect = async function () {
  // パーツライブラリの登録
  Obniz.PartsRegistrate(SerDAC);

  var dac = obniz.wired("SerDAC", { rx:9, tx:10, gnd:11 });
  var convertedData = await dac.convertFromB64("BASE64形式のWAVファイル");
  dac.play(convertedData);
  dac.stop();
}
</script>

obniz用パーツライブラリ使用例1 BASE64形式のWAVファイルを再生
<!doctype html>
  <html>
  <head>
  <meta charset="utf-8">
  <title>SerDAC</title>
  <script src="https://unpkg.com/obniz@3.x.0/obniz.js"></script>
  <script src="SerDAC.js"></script>
  
  <script>
  const data = "BASE64形式のWAVファイル";
  
  var obniz = new Obniz("OBNIZ_ID_HERE");
  
  var convertedData = null;
  var dac = null;
  
  obniz.onconnect = async function () {
    Obniz.PartsRegistrate(SerDAC);
  
    dac = obniz.wired("SerDAC", { rx:9, tx:10, gnd:11 });
    convertedData = await dac.convertFromB64(data);
  }
  
  function play() {
    dac.play(convertedData);
  }
  
  function stop() {
    dac.stop();
  }
  </script>
  </head>
  
  <body>
  <p>
  <input type="button" value="Play" onclick="play();"><br>
  <br>
  <input type="button" value="Stop" onclick="stop();">
  </p>
  </body>
  </html>

obniz用パーツライブラリ使用例2 WAVギロチンで変換済みデータを使って再生
<!doctype html>
  <html>
  <head>
  <meta charset="utf-8">
  <title>SerDAC</title>
  <script src="https://unpkg.com/obniz@3.x.0/obniz.js"></script>
  <script src="SerDAC.js"></script>
  
  <script>
  // ここに変換済みデータを配置
  const BINDATA = [
    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    ~(省略)~
  ];
  
  var obniz = new Obniz("OBNIZ_ID_HERE");
  
  var dac = null;
  
  obniz.onconnect = async function () {
    Obniz.PartsRegistrate(SerDAC);
  
    dac = obniz.wired("SerDAC", { rx:9, tx:10, gnd:11 });
  }
  
  function play() {
    dac.play(BINDATA);
  }
  
  function stop() {
    dac.stop();
  }
  </script>
  </head>
  
  <body>
  <p>
  <input type="button" value="Play" onclick="play();"><br>
  <br>
  <input type="button" value="Stop" onclick="stop();">
  </p>
  </body>
  </html>

ダウンロード
SerDAC.ino(ESP8266用UART-DAC)
SerDAC.js(obniz用パーツライブラリ)


戻る