日曜日, 10月 29, 2006

jpeg

Java code for Pure Electronica Generator
プログラミングの勉強も兼ねて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);
}
}
}

2 件のコメント:

yosuke hayashi さんのコメント...

ソースコードのコピーペーストがうまくいっていなかったのに気付いていませんでした。正しいものに書き換えました。

yosuke hayashi さんのコメント...

今見ると変数名の付け方とか全然なってないな!コンストラクタとか理解してなかったし。今でもまだスマートな書き方はよくわかってないけど、ちょっと整理した。あとやっぱfor文の中でif文使うのやめた。なんとなく。インデントが見にくいのでファイルアップしました。
Jpeg2