はじめに
AudioTrackを使って生成した正弦波をリアルタイムで再生するアプリを作成。再生できるようになったが再生したい周波数と違う周波数の音(雑音)も再生されていたため、修正。
正弦波生成
周波数を引数として正弦波を生成し、byte型の値の範囲-128~127で正規化。
getSound
/**
* 正弦波生成
* @param frequency 音の周波数
* @return 音声データ
*/
public byte[] getSound(double frequency) {
frequency = frequency / 2;
// byteバッファを作成
byte[] buffer = new byte[bufferSize];
double max = 0;
double[] t = new double[buffer.length];
double hz = frequency / this.sampleRate;
for(int i = 0; i < buffer.length; i++) {
t[i] = Math.sin(i * 2 * Math.PI * hz);
if(t[i] > max) {
max = t[i];
}
}
double trans = 127 / max;
for(int i = 0; i < buffer.length; i++) {
buffer[i] = (byte)Math.round(t[i]*trans);
}
return buffer;
}
結果
20kHzの音を再生した。これ自体は非可聴音だが、可聴音も再生されてしまっている。この可聴音は雑音なので除去したい。
修正したこと
音声データをbyte型ではなくshort型にしただけ。short型の値の範囲-32768~32767で正規化することで正弦波の分解能が高くなった。
getSoundShort
/**
* 正弦波生成
* @param frequency 音の周波数
* @return 音声データ
*/
public short[] getSoundShort(double frequency) {
double[] value = new double[sampleRate];
double max = 0.0;
for(int i = 0; i < sampleRate; i++) {
value[i] = Math.sin(2.0 * Math.PI * frequency * i / sampleRate);
if(value[i] > max) {
max = value[i];
}
}
short[] buffer = toShort(value, max);
return buffer;
}
/**
* double型をshort型に変換(-32768~32767で正規化)
* @param val double型音声データ
* @param max 最大値
* @return short型音声データ
*/
public short[] toShort(double[] val, double max) {
double trans = 32767 / max;
short[] buf = new short[sampleRate];
for(int i = 0; i < sampleRate; i++) {
buf[i] = (short)Math.round(val[i] * trans);
}
return buf;
}
修正結果
同様に20kHzを再生したところ、可聴域の雑音がなくなり、20kHzの単音になった。

おそらく
詳しいことはわからないが、byte型の-128~127の範囲だと分解能が低く、誤差が生じて雑音が発生したと思われる。
AudioTrackの書込処理(writeメソッド)にはbyte型、short型、float型を用いることができるが、float型は値の範囲等が複雑なため試していない。