プログラミング言語のおすすめは?MacのTTSで英語のシャドウイングを練習しよう

これからプログラミングを学びたい人や、インターシップで技術者志望の学生さんから、「勉強するならどの言語が良いか?」という質問を受けることがあります。僕は、これについては概ね次の様に答えています。
プログラミング言語はパラダイムが同じものであれば、一つ覚えると2つ目を覚えるのはそんなに難しくありません。そして今、メジャーなパラダイムには「オブジェクト指向型言語」と「関数型言語」の二つがあります。そのためまずはこれらから一つづつ、自分に合いそうなものを直感で選んで、それをまずモノにしていくと良いと思います。
また、さらに即戦力的技術を重視したいということであれば「オブジェクト指向型言語」を先にやった方が良いというアドバイスもできるでしょう。なぜなら、オブジェクト指向型言語は複数の人と共同でプログラミングをするときに捗る様にデザインされていまして、仕事でプログラミングするというのは、共同作業の効率が重視されるためです。

ところで共同作業の効率ということを考えるのであれば、プログラミング言語も良いですが、コミュニケーション能力を高めるというのも良さそうです。今求められているコミュニケーション能力は「潤滑油的」なそれではなく、書かれていることが読めるという「文章読解力」や「英語力」というベーシックなものです。
そういう自分はどうなんだ?ということを考えると、英語が苦手です。しかし最近はセミナーなどで英語話者の方と情報交換をすることも増えてきましたので、簡単な会話は交わせる様にしたいと思っていまして、再学習を行なっています。
さて、次に考えるのは「どうすれば効率良く勉強ができ、話せる様になるか?」ということです。これは英語を勉強する人であれば何度も考えたことでしょう。僕も御多分に洩れず、考え・様々な方法を試しています。そして一つわかったことがあります。この「効率良く勉強したい」という様に考えを巡らすことが、そもそも間違いの始まりなのではないかと。

昨年、思い付きで「般若心経」を暗唱できる様に訓練しました。短い経文なのでそんなに苦労しないだろうと思ったのですが、いざやってみるとこれがなかなか覚えるのが大変です。意味がわからないため、音で覚えるしかありません。何度も繰り返し聞いて、全て覚えるまでに1ヶ月程度はかかったと思います。しかし一度覚えてしまうと、今度は「なぜこんなものが覚えられなかったのか?」となり、また仏教における「空性」についても少しわかった気になるから不思議です。
このセルフ修行で自分が得た教訓は「覚えてしまえば意味は後から付いてくる」ということです。また覚えることに効率はあまり関係がありません、ただひたすら時間をかけ「聞いて」を繰り返すだけです。英語もこれと同じなのではないか?そう考える様になったのです。あれこれ考えず全て覚えればOK。シンプルですね。
では、どうやって覚えるのか。これは色々と工夫ができるところです。私はMacを使っていますが、MacにはTTS(TextToSpeech)という機能が標準でついています。アクセシビリティを確保するためや、Siriの様なエージェント型インターフェースを実現するために必要なのですね。TTSは日本語はまだうまくいかない部分も多いですが、英語は音素片の数などが限られていたり、また話者が多く研究が進んでいることもあって、ネイティブを騙せるぐらいのレベルまで進んでいます。そこでこのTTSを使って、シャドウイングをやってみるのはどうか試してみました。

MacのTTSはターミナルからコマンドで動かすことができ、またAIFFファイルの書き出しにも対応しています。AIFFだとサイズがでかいのでMP3に圧縮したい。これにはLAMEが使えます。
brew install lame
繰り返しシャドウイングをするためには、直前に聞いた文章と同じぐらいの長さの空白を入れておくと便利です。MacのTTSは文章中にトークン記述を埋め込むことで、ある程度動作を制御できます。文字の長さと句読点?の数からざっくりとそれを計算し、無音を入れる様に制御します。
for(let s of sentences){
let l = s.length;
let w = s.split(/[\.,!\?]/).length;
let wait = `[[slnc ${l*60+w*600}]]\n`;
for(let i=0;i<repeat;i++) work =+ `${s} ${wait}`;
work += "[[slnc 2000]]";
}
こうやって制御トークン入り文章を作り、TTSでAIFFに変換した後、MP3にコンバートしてiCloud Driveに保存する。最後にAutomator(Macに標準でついている自動化ソフト)を使って、ファイルのDrag&Dropに対応すればもう少し便利になります。

できました。動画はこちらです。(音声にディレイがかかっているのは録音に使ったツールの関係です。)
これで毎日シャドウイングを練習しましょう。私がイヤホンをつけて遠い目でブツブツ言っている様でしたら、おそらくこの練習です。疲れたりおかしくなった訳ではありませんのでお気になさらず…。自分のマックにもインストールしたい!という人がいましたら、ソースはこちらです(TypeScript)。
namespace Shadowing{
const fs = require("fs");
const argv = require("argv");
const exec = require("child_process").execSync;
const path = require("path");
argv.option({
name: "file",
short: "f",
type: "string",
description: "file path"
});
argv.option({
name: "voice",
short: "v",
type: "string",
description: "TTS speaker"
});
argv.option({
name: "outdir",
short: "o",
type: "string",
description: "output dir"
});
argv.option({
name: "repeat",
short: "r",
type: "number",
description: "number of repeat"
});
const args = argv.run();
const filepath = args.options.file;
if (!filepath) {
console.log("filepath is needed.");
process.exit();
}
const basename = path.basename(filepath).split(".")[0];
let outdir = args.options.outdir;
let repeat = args.options.repeat;
let voice = args.options.voice;
if(!repeat) repeat = 5;
if (!voice) voice = "Tom";
if (!outdir) outdir = "./mp3";
const sentences = fs.readFileSync(filepath, "utf-8").split("\n");
let work = "";
for (let s of sentences) {
let l = s.length;
let w = s.split(/[\.,!\?]/).length;
let wait = `[[slnc ${l * 60 + w * 600}]]\n`;
for (let i = 0; i < repeat; i++) work += s + " " + wait;
work += "[[slnc 2000]]\n";
}
const temptxt = `${basename}-temp-shadow.txt`;
const tempaif = `${basename}-temp-shadow.aiff`;
fs.writeFileSync(temptxt, work);
exec(`say -v "${voice}" -f "${temptxt}" -o "${tempaif}"`);
exec(`lame -m m "${tempaif}" "${outdir}/${basename}-shadowing.mp3"`);
fs.unlinkSync(temptxt);
fs.unlinkSync(tempaif);
}