矩形波とは英語でsquare wave「四角い波」といいます。図で見るとこのような形になります。
音量は一定時間ごとに最大値と最小値に切り替わります。最大値になった時から最小値に切り替わりまた最大値になる直前までが波の1周期になります。例えば440Hzの音、これは音階でいうとラにあたりますが440周期がちょうど1秒になります。逆にすると1周期にかかる時間は1/440秒となります。
Javaで矩形波を作る
色々細かい部分を説明すると長くなるので今回は最初に完成した音とコードを提示して後から説明する事にします。
まず完成した音です。本来はwav形式ですがウェブページ用にmp3に変換しています。
基本的な音の情報として以下のような設定になっています。
サンプルレート | 48,000Hz |
サンプルサイズ | 16bit(2バイト) |
チャンネル | 1(モノラル) |
周波数 | 440Hz(音階のラ) |
長さ | 3秒 |
以下コードです。AudioSystem.writeでファイルに書き出しますが音源はInputStreamを引数として渡す事になっています。このためSampleSqareクラスはInputStreamクラスを継承しています。InputStreamクラスは抽象クラスでreadメソッドを実装しなければなりません。このreadメソッドが一番重要な処理になります。こちらは次回に詳しく説明します。
package mocha.sound; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.util.ArrayList; import javax.sound.sampled.AudioFileFormat; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; /** * * @author minaberger */ public class SampleSquare extends InputStream { boolean signed = true; boolean big_endian = true; float sample_rate = 48000; int sample_size_byte = 2; int channels = 1; double freq; double seconds; ArrayList<Byte> list; double index; double period; double volume; public SampleSquare(double freq, double seconds){ this.freq = freq; this.seconds = seconds; list = new ArrayList<>(); index = 0; period = sample_rate / freq; volume = Math.pow(2, sample_size_byte * 8 - 1) - 1; } @Override public int read() throws IOException { if(list.isEmpty()){ long value; if(index / period < 0.5){ value = (long)volume; }else{ value = (long)-volume; } index++; index %= period; ByteBuffer buffer = ByteBuffer.allocate(8); buffer.putLong(value); byte[] array = buffer.array(); for (int i = 8 - sample_size_byte; i < 8; i++) { list.add(array[i]); } } int ret = Byte.toUnsignedInt(list.remove(0)); return ret; } public long length(){ return (long)(sample_rate * channels * seconds); } public AudioFormat getFormat(){ return new AudioFormat(sample_rate, sample_size_byte * 8, channels, signed, big_endian); } public static void main(String[] arg) throws IOException { SampleSquare ss = new SampleSquare(440, 3); AudioSystem.write( new AudioInputStream(ss, ss.getFormat(), ss.length()), AudioFileFormat.Type.WAVE, new File("/Users/myaccount/mywork/square_440.wav")); } }