人形を喋らせて、呪いの人形にする

# はじめに

昔、X68000というパソコン用に「悪魔城ドラキュラ」というゲームがあり、その中に「人形の塔」というステージがありました。
人形に近づくと、抑揚の無い声で「お前は誰？」「帰りなさい」と喋り攻撃をしてきます。複数の人形が同時に喋りながら迫ってくるのはかなりの緊張・恐怖感がありました。

前回、「[人形の目を光らせ、呪いの人形にする](http://qiita.com/tsurime/items/ad9778256eff26aeb3d4)」として、自作の球体関節人形の目を光らせました。この人形に「お前は誰？」などと喋らせる機能を追加してみたいと思います。

# やること

前回のLED制御と同じくarduinoを使い、音声合成LSIである AquesTalk pico LSI を制御して喋らせます。

# 用意するもの

前回と同様、人形とarudinoを用意します。arduinoはUNOを使いました。

そして今回の核となる AquesTalk pico LSI も用意します。AquesTalk pico LSIには種類がいくつかありますが、今回は「[音声合成LSI ATP3011F4-PU（かわいい女性の音声）](http://akizukidenshi.com/catalog/g/gI-05665/)」 を利用しました。
男性の声のICもあります。そちらを使うと悪魔城ドラキュラの隠しドキュメントにあった「サンプリングレートを間違えたまま人形の塔に突入したらオカマの集団に襲われ」たシーンを再現できるのでしょうか？

AquesTalkPicoの周辺部品は、[メーカー製品情報ページ](http://www.a-quest.com/products/aquestalkpicolsi.html) にあるデータシートや「[\[Arduino\] AquesTalk ライブラリ （N.Yamazaki's blog）](http://blog-yama.a-quest.com/?eid=970151)」を参考にそろえます。
というか、今回やることはこちらのサイトとデータシートに全て載ってますので熟読してください。

アンプとスピーカー、人形に組み込める小型のものということでアンプには[PAM8012使用2ワットD級アンプモジュール](http://akizukidenshi.com/catalog/g/gK-08217/)を使いました。スピーカーは家に転がっていたのでわかりません。

# Arduino と AquesTalk pico の接続
データシートや先のサイトを参考に接続します。参考というか、書いてある通りに繋ぎます。
目に仕込んだLEDは前回つなげたままにしています。

# スケッチ
スケッチを書きはじめる前に、AquesTalk picoをarduinoで使うためのライブラリを用意します。
ライブラリマネージャで「AquesTalk pico」を探すか、先のサイトから持ってきます。

前回組み込んだLEDで目を光らせつつ喋らせる、ということをしたため長くなっていますが、大したことはしてません。talk 関数の部分だけ見ていただけば、ほぼ結構です。

```cpp:doll_ledtalk.ino
#include <Adafruit_NeoPixel.h>
#include <AquesTalk.h>
#include <Wire.h>

#define LEDPIN 2
#define NUMLED 2

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMLED, LEDPIN, NEO_RGB + NEO_KHZ800);
AquesTalk atp;

typedef struct {
  int r;
  int g;
  int b;
} RGB;

String eyes_color[] = {"#000000", "#00ffff", "#ff0000", "ff8844", "#ffffff"};
int eyes_colorCount = sizeof(eyes_color) / sizeof(eyes_color[0]);
RGB from, to;

const String TblKoe[] = {
  "oma';ewa/da're?",
  "kaeri';nasa'i?",
  "ya';me';te'?",
  "i';ya'?",
};

RGB rgb_hex2dec(String hexstr){
  RGB rgb;
  long val = strtol(&hexstr[1], NULL, 16);
  rgb.r = (int) (val >> 16 & 0xff);
  rgb.g = (int) (val >> 8 & 0xff);
  rgb.b = (int) (val & 0xff);

  return rgb;
}

boolean compareRGB(RGB a, RGB b){
  return ((a.r == b.r)&&(a.g == b.g)&&(a.b == b.b));
}

void changeLED(RGB from1, RGB to1, RGB from2, RGB to2,int speed){
  RGB s[] = {from1, from2},
      t[] = {to1, to2},
      d[2];

  for(int i=0; i<2; i++){
    d[i].r= (s[i].r < t[i].r)?1:((s[i].r > t[i].r)?-1:0);
    d[i].g= (s[i].g < t[i].g)?1:((s[i].g > t[i].g)?-1:0);
    d[i].b= (s[i].b < t[i].b)?1:((s[i].b > t[i].b)?-1:0);
  }

  while(!compareRGB(s[0],t[0]) && !compareRGB(s[1],t[1])){
    for(int i=0; i<2; i++){
      if(s[i].r != t[i].r){  s[i].r += d[i].r;  }
      if(s[i].g != t[i].g){  s[i].g += d[i].g;  }
      if(s[i].b != t[i].b){  s[i].b += d[i].b;  }
    }
    
    setLED(s[0], s[1]);
    delay(speed);
  }
}

void setLED(RGB rgb1, RGB rgb2) {
  strip.setPixelColor(0, strip.Color(rgb1.r, rgb1.g, rgb1.b));
  strip.setPixelColor(1, strip.Color(rgb2.r, rgb2.g, rgb2.b));
  strip.show();
}

void setup() {
  strip.begin();
  strip.setBrightness(10);
  setLED(rgb_hex2dec(eyes_color[0]), rgb_hex2dec(eyes_color[0])); 
  
}

void talk(String s){
  atp.SyntheS(s);
  while( atp.IsBusy()) {}
}

void loop() {
  delay(5000);
  
  from = rgb_hex2dec(eyes_color[0]);
  to = rgb_hex2dec(eyes_color[1]);
  changeLED(from, to, from, to, 15);
  talk(TblKoe[0]);
  delay(2000);

  from = to;
  to = rgb_hex2dec(eyes_color[2]);
  changeLED(from, to, from, to, 5);
  talk(TblKoe[1]);
  delay(4000);

  from = to;
  to = rgb_hex2dec(eyes_color[3]);
  changeLED(from, to, from, to, 5);
  talk(TblKoe[2]);
  delay(500);

  from = to;
  to = rgb_hex2dec(eyes_color[4]);
  changeLED(from, to, from, to, 3);
  talk(TblKoe[3]);

  from = to;
  to = rgb_hex2dec(eyes_color[0]);
  changeLED(from, to, from, to, 1);
}
```

AquesTalk のライブラリを利用した部分を少しだけ解説をしますと

1. インスタンスの作成。 `AquesTalk atp;`
2. String型で、発声する音声記号やコマンド文字列を指定し音声合成を行う `atp.SyntheS(s);`
3. 発生が終わるまで待つ `while( atp.IsBusy()) {}`

ライブラリで使ったのは、これだけです。

発話される内容は以下の通りです。

```cpp:音声指定配列
const String TblKoe[] = {
  "oma';ewa/da're?",
  "kaeri';nasa'i?",
  "ya';me';te'?",
  "i';ya'?",
};
```

台詞は「お前は誰？」「帰りなさい」「やめて」「いや」の4通りです。
発話記号の書き方は [メーカーのダウンロードページ](http://www.a-quest.com/download/index.html) に音声記号列仕様書がありますのでそちらを見ながら指定します。

# 人形への組み込みと動作

組み込んだ結果はこちら。
<blockquote class="twitter-video" data-lang="ja"><p lang="ja" dir="ltr">喋る球体関節人形 <a href="https://t.co/lszQgJwBwN">pic.twitter.com/lszQgJwBwN</a></p>&mdash; 球体関節人形 (@CursedDoll_1103) <a href="https://twitter.com/CursedDoll_1103/status/850985069061718016">2017年4月9日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

動画だと人形が喋ってる感はありませんし、電子音声っぽさがかなり出てしまっていますが。実際に目にするとやはりちょっとしたホラーです。

# 終わりに

今回はarduino + ATP3011 という組み合わせで喋らせてみました。

人感センサあたりを組み込み、人が近づくと目を光らせながら「お前は誰？」「帰りなさい」と喋る、というようにすれば防犯目的に使えるでしょうか？
……廊下にそんな人形があったら夜トイレに行けなくなりそうな仕掛けです。

# おまけ

AquesTalkPico のラインナップには、 
「[音声合成LSI ATP3011F1-PU（ゆっくりな女性の音声）](http://akizukidenshi.com/catalog/g/gI-06220/)」
というのがありまして……これはどんなものかというと、まぁ俗に「ゆっくりボイス」といわれるような発話をしてくれます。
となると

<blockquote class="twitter-video" data-lang="ja"><p lang="ja" dir="ltr">ゆっくりしていってね！ <a href="https://t.co/o0ByErr0nu">pic.twitter.com/o0ByErr0nu</a></p>&mdash; 球体関節人形 (@CursedDoll_1103) <a href="https://twitter.com/CursedDoll_1103/status/850986488401494016">2017年4月9日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

やりたくなりますよね？