プログラミングの勉強も兼ねてjavaで音響合成。
コードを適当なエディタに書き込んで、Jpeg.javaという名前で保存。
javac Jpeg.java
でコンパイルして、
java Jpeg 周波数 長さ 波形
で音が鳴ります。明らかにおかしい音だけど。波形はsine, saw, triangle, square。例えば440Hzのサイン波を1秒鳴らす場合、
java Jpeg 440 1000 sine
とします。明らかにおかしい音だけど。
今はメソッドで波形を変えてるけど、ここの呼び出し方がもっと綺麗にならないかな。for文の中でif文てどうなんだろう。実用的なものを作りたい訳ではないし、途中で波形を変えられたりしておかしなことにできる可能性もあるからとりあえずはいいかな。とはいえ適当すぎると音鳴らないから勉強するとこはしないと。
波形クラスを作って、ポリモーフィズムとか使えばスマートにいけそうな気がする。時間かけてじっくりやっていこうと思います。
import javax.sound.sampled.*;
public class Jpeg {
public void sound(int freq, int msecs, String waveForm)
throws LineUnavailableException {
byte[] buf = new byte[1];
String wave = waveForm;
System.out.println(wave + ": " +
freq + "hz " + msecs + "msecs");
AudioFormat af = new AudioFormat(8000, 8, 1, true, false);
SourceDataLine sdl = AudioSystem.getSourceDataLine(af);
sdl.open(af);
sdl.start();
for (int i=0; i<8*msecs; i++) {
double angle = i / (8000.0 / freq) * 2.0 * Math.PI;
if(wave.equals("sine")) {
buf[0] = (byte)(sineWave(angle) * 110d);
} else if(wave.equals("square")) {
buf[0] = (byte)(squareWave(angle) * 110d);
} else if(wave.equals("triangle")) {
buf[0] = (byte)(triangleWave(angle) * 110d);
} else {
buf[0] = (byte)(sawWave(angle) * 110d);
}
sdl.write(buf,0,1);
}
sdl.drain();
sdl.stop();
sdl.close();
System.exit(0);
}
public double sineWave(double angle) {
return Math.sin(angle);
}
public double squareWave(double angle) {
double ratio = angle % Math.PI / Math.PI;
if (ratio <= 0.5)
return 1.0;
return -1.0;
}
public double triangleWave(double rad) {
double ratio = rad % Math.PI / Math.PI;
if (ratio < 0.25)
return ratio*4;
if (ratio >= 0.25 && ratio < 0.5)
return 1.0-(ratio-0.25)*4;
if (ratio >= 0.5 && ratio < 0.75)
return -(ratio-0.5)*4;
return -1.0+(ratio-0.75)*4;
}
public double sawWave(double angle){
return 1.0 - 2 * (angle % Math.PI / Math.PI);
}
public static void main(String[] args) {
int freq = Integer.parseInt(args[0]);
int dur = Integer.parseInt(args[1]);
String waveForm = args[2];
Jpeg generate = new Jpeg();
try {
generate.sound(freq, dur, waveForm);
} catch (LineUnavailableException lue) {
System.out.println(lue);
}
}
}