ジンジャー研究室

長めのつぶやき。難しいことは書きません。

TOEICのリスニングCDを分割するWebアプリを作った

TOEICのリスニング問題集をやっていて「ムキーッ!」となることありませんか?

私は2つほどあります。1つは「ひとつの問題を繰り返して聞きたいのにファイルが分かれていない」こと、もう1つは「何を言ってるのかさっぱり分からない」ことです。そこで今回、1つめの問題を解決すべく、CD音源を複数の問題別に分割するWebアプリを作りました。

Wave Cutter for TOEIC®Source

f:id:jinjor:20151228012935p:plain

ChromeFirefox、Edgeで動作確認済みですので、ぜひ遊んでみてください。

使い方

  1. MP3ファイルを読ませると自動的に空白を判断して分割します
  2. 自動分割で上手くいかなかったところを手動で調整します
  3. 完了ボタンを押すとZIPファイルが手に入ります

2に関しては、出力予定のファイル名(左側)と波形データの内容(右側)を一致させるゲームだと思うと手っ取り早いです。

主な機能

  • 波形の削除、分割、結合、再生
  • 分割後のファイル名の付け方の指定
  • Undo/Redo
  • 自動保存

技術的な解説

大掛かりなフレームワークに飽きてきたのでミニマルな感じで攻めてみました。

Virtual DOM

Virtual DOM実装としてSnabbdomを使いました。理由は以下です。

  • 軽い: コアが200行程度
  • 簡潔な記法: h('div#foo.bar.baz')のようにNodeがさくさく書ける
  • Hook機能: パッチを充てる前後などに処理を書ける

Hook機能は、canvas要素のようなVirtual DOM的な思想から外れるものを扱うときに便利です。 今回は音声処理という重い処理を扱うので、Modelが変更されていなければrenderXXX()を走らせないということもしています。

それから、requestAnimationFrame()を使ってレンダリングの頻度を抑えています。 これはModelからViewを生成する関数が純粋であることが前提です。

簡易Flux

ライブラリなしで簡単にFluxしました。

Actionを溜めておくことでUndo/Redoへの対応が楽になりました。最初の状態とActionのリストさえ覚えておけば任意の状態を再計算できます。ただし全てのActionを溜めてしまうと、hoverやらtickみたいな頻度の高いActionに汚染されてしまうので最小限に。言い換えると、Undo/Redoを完全にフレームワーク任せにすることはできません。

今回はModel(Store)をObserverにする必要は無いのでカット。というより、ModelからViewへの紐づけをObserverでやるのはBackbone.jsでカオスになった事があって懲りています。

File API

読み込みと書き込みに使用。

Web Audio API

音声処理に必須です。

Web Workers

編集後、MP3に再エンコードする時に画面がフリーズしたので急遽導入。

用途をTOEICに限定するメリット

無駄に汎用的に作りたくなる気持ちを封じることでメリットを出します。

  • 空白時間はおよそ決まっているので、ユーザーがしきい値などを設定する必要がない。
  • 波形の分割ポイントを「空白の最後(次の波形の直前)」に限定できるので、分割ポイントを選択しやすい。
  • ファイル名の付け方のパターンが決め打ちできる。例えば、Part3からは41-43.pm3などの名前が嬉しいと分かっている。

まとめ

最新のWeb技術を使って役立ちそうなものを作ることができました。残タスクは以下です。

  • MP3エンコードの高速化
  • メモリ不足対策
  • CDによる差異を埋めるために分割ロジックを賢くする
  • UIを洗練させる
  • リスニングを克服する

以上。