Stephen Hawking Discordボットを作った

# Stephen Hawkingボットを作ったよ
皆さんの好きな科学者は誰だろうか？

アリストテレス・アインシュタイン・ノイマン・エジソン…
偉大な科学者を上げていったらきりがないと思う。

私の一番好きな科学者はStephen Hawkingである。
彼の半生を描いた映画、「[The theory of everything](https://www.amazon.co.jp/gp/video/detail/amzn1.dv.gti.9ca9f49d-831f-fbfd-07b0-54b5be9d3720)」は一見の価値があると思う。

ホーキングといえば、車椅子姿に機械音声でしゃべるというのが大きな特徴で、病気にも負けずに真理を追い求める姿には誰もが感動すると思う。
私も勉強のモチベーションが上がらないときは、ホーキング先生の写真を見てモチベーションを上げている。そんな時に、今回のアイデアを思いついてしまった。「ホーキングの声で応援されたら、やる気出るんじゃないか？」と。

## Hawkingの声を作る
Googleで「Hawking voice generator」だとか、「Stephen Hawking voice」とかを調べると、以下のようなサイトに引っかかった。
[Stephen Hawking Voice Generator](https://lingojam.com/StephenHawkingVoiceGenerator)

どうやら、[eSpeak](https://en.wikipedia.org/wiki/ESpeak)というライブラリを利用してホーキングっぽい声を生成しているらしい。
そこで、このライブラリを利用してHawkingの声でしゃべるbotを作成することにした

## Discord botの準備
1. [Discord Developer Portal](https://discord.com/developers/applications/885014370973782076/information)にアクセスし、Discord Botを作成する。
1. Bot => Generate Tokenでトークンを生成し、どこかに保存しておく。
1. 自分の好きなサーバーにBotを参加させる。
1. [このレポジトリ](https://github.com/sitepoint-editors/discord-bot-sitepoint)をclone
1. [ここ](https://github.com/kripken/speak.js/blob/master/speakGenerator.js)からespeakのライブラリをダウンロードしてルートディレクトリに配置
1. ``index.js``の4行目を自分のトークンに置き換え。

``` javascript
// const TOKEN = process.env.TOKEN;
const TOKEN = "<先ほど取得したトークン>";
```

## ボットの起動
``> node index.js ``でボットを起動してDiscord上でボットがオンラインになったら成功

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305662/6226799e-d286-bc41-b535-19894e6b8ae0.png)

## コードを書く
``index.js``を書き換えて、Botにしゃべらせる
### 必要ライブラリのインポート

``` javascript
const Discord = require('discord.js');
const Speak = require('./speakGenerator.js');
const fs = require('fs')
```

### しゃべらせる
espeakライブラリを使って、音声データを生成する場合は次のようにすればよい。
``` javascript
var speech = Speak.speak("<words what you want bot to speak>",{pitch:36.8,speed:152});
```

しゃべらせようと思い、公式ドキュメントを調べたが、バイト列を音声として発言させるようなものが見つからなかったので、ファイルに保存してから再生するようにした。

``` javascript
const byteCharacters = Buffer.from(encode64(speech), 'base64')
fs.writeFileSync("./audio.wav",byteCharacters);   // audioとして一時保存
connection.playFile("audio.wav",{},function(err){ // playFileで再生
channel.leave();
});
```

### すべてのコード
``` javascript
const Discord = require('discord.js');
const Speak = require('./speakGenerator.js');
const fs = require('fs')
const bot = new Discord.Client();
const TOKEN = "<先ほど取得したトークン>";

// base64に変換するための関数
function encode64(data) {
  var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  var PAD = '=';
  var ret = '';
  var leftchar = 0;
  var leftbits = 0;
  for (var i = 0; i < data.length; i++) {
    leftchar = (leftchar << 8) | data[i];
    leftbits += 8;
    while (leftbits >= 6) {
      var curr = (leftchar >> (leftbits-6)) & 0x3f;
      leftbits -= 6;
      ret += BASE[curr];
    }
  }
  if (leftbits == 2) {
    ret += BASE[(leftchar&3) << 4];
    ret += PAD + PAD;
  } else if (leftbits == 4) {
    ret += BASE[(leftchar&0xf) << 2];
    ret += PAD;
  }
  return ret;
}

// tokenでログインする
bot.login(TOKEN);

bot.on('ready', () => {
  console.info(`Logged in as ${bot.user.tag}!`);
});

// メッセージを受け取った際に呼ばれる
bot.on('message', msg => {
  if (msg.content.startsWith('!sh ')) { // メッセージが!shから始まるならコマンドとして処理
    if(msg.member.voiceChannelID){
      let channel = bot.channels.get(msg.member.voiceChannelID)  // メッセージ発言者の現在入っているボイスチャンネルを取得
      
      channel.join().then(connection => {  // メッセージ発言者のボイスチャンネルに参加
        var speech = Speak.speak(msg.content.substring(4),{pitch:36.8,speed:152}); // espeakでボイスを生成
        const byteCharacters = Buffer.from(encode64(speech), 'base64')  // ボイスデータをbase64に変換
        fs.writeFileSync("./audio.wav",byteCharacters);  // ボイスデータをファイルとして保存
        connection.playFile("audio.wav",{},function(err){ // ファイルとして保存したボイスデータをチャンネル内で再生
          channel.leave();
        });
      });
    }
  }
});

```
## 使ってみる
``!sh <some words>``と発言すればホーキングボットが喋ってくれる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305662/5fcd44f1-e25b-2d4e-3f16-7d880e75cc4f.png)

なんか途切れ途切れだけど一応しゃべってくれた。
## まとめ

こんな感じでボットが作れました。
でも英語できないので特に喋らせることもできません。

よかったら、みなさんも自作ボットを作ってみてはいかかでしょうか？