前回汎用の「時間で変化するdouble値を保持するクラス」DoubleMapクラスを作ったので以前作ったFrequencyMapを廃止したいと思います。FrequencyMapを使っていたオシレーター読み込みクラスをDoubleMapを使うように修正します。またインデックスはDoubleMap内部で管理するようにしたのでindexも外しました。ずいぶんすっきりした実装になりました。
OscillatorReaderのソース
package mocha.sound; public class OscillatorReader implements SoundReadable { public static final int CHANNELS = 1; Oscillatable oscillatable; DoubleMap freqMap; double seconds; public OscillatorReader(Oscillatable oscillatable, DoubleMap freqMap, double seconds) { this.oscillatable = oscillatable; this.freqMap = freqMap; this.seconds = seconds; } @Override public long length() { return (long) (WavFileWriter.SAMPLE_RATE * CHANNELS * seconds); } @Override public int getChannel() { return CHANNELS; } @Override public double read() { return oscillatable.read(freqMap.next(), 1); } }
WavFileWriterのファイル書き出しstaticメソッド
ファイル作成の処理も定型化してきたのでメソッドを作ります。SoundReadabaleと出力先ファイルが指定されていれば自動で音量最大化したwavファイルを書き出します。
public static void create(SoundReadable readable, File wavFile) throws IOException { wavFile.getParentFile().mkdirs(); WavFileWriter ss = new WavFileWriter(readable); AudioSystem.write( new AudioInputStream(ss, ss.getFormat(), ss.length()), AudioFileFormat.Type.WAVE, wavFile); ss.terminate(); System.out.println("wav file:" + wavFile.getAbsolutePath()); }
音声作成ロジック
いろいろメソッドにしたので音を作ることにだんだん専念できるようになってきました。以下が音を作るロジックです。
- 3秒間の2チャンネルwavファイルを作成
- 波形はサイン波
- 周波数は440Hzで始まり2秒後に880Hzまで変化しその後固定
- パンは右から始まり3秒後に左になるまで変化する
DoubleMap freqMap = new DoubleMap(440.0); freqMap.putSecondValue(2.0, 880.0); DoubleMap panMap = new DoubleMap(0.0); panMap.putSecondValue(3.0, 1.0); WavFileWriter.create(new Panner( new OscillatorReader(new SineOscillator(), freqMap, 3), panMap), new File("wav/panned.wav"));
実行結果
実行した結果作成されたファイルです。ヘッドフォンをつかうとパンが右から左に移動するのがわかると思います。
また音量の変化をグラフにしたものが下の画像です。上段が左チャンネル、下段が右チャンネルです。