我在java中有一個基本的波形發生器,但我需要一些東西來消除當波的幅度急劇變化時我得到的點擊。也就是說,當我開始/停止播放一個波時,特別是如果我有嘟嘟聲。我是否正確地在Java中實現了這個基本的低通濾波器(Phrogz濾波器!)?
Phrogz's answer on SO給了一個非常好的和簡單的功能,但我不知道我執行它的權利。
當我第一次嘗試使用它,我無法得到它的工作,但我似乎記得它的工作非常好......因爲我已經擺弄了很多我的代碼,現在它不似乎再次運作良好。
因此,這裏是最接近我能得到一個SSCCE:
如果你玩這個,你會發現,當過濾是(過濾=真)浪更安靜和點擊稍顯不足,但這似乎主要是由於數量減少。還有每個嗶明顯的「打擊」,我不想要的,我不記得以前在那裏......
import javax.sound.sampled.*;
public class Oscillator{
private static int SAMPLE_RATE = 22050;
private static short MAX_AMPLITUDE = Short.MAX_VALUE;
private static AudioFormat af = null;
private static SourceDataLine line = null;
private int frequency = 440; //Hz
private int numLoops = 1000;
private int beep = 100;
// set to true to apply low-pass filter
private boolean filter = true;
// set the amount of "smoothing" here
private int smoothing = 100;
private double oldValue;
public Oscillator(){
prepareLine();
}
public static void main(String[] args) {
System.out.println("Playing oscillator");
Oscillator osc = new Oscillator();
osc.play();
}
private void prepareLine(){
af = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, SAMPLE_RATE, 16, 2, 4, SAMPLE_RATE, false);
try {
DataLine.Info info = new DataLine.Info(SourceDataLine.class, af);
if (!AudioSystem.isLineSupported(info)) {
System.out.println("Line does not support: " + af);
System.exit(0);
}
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(af);
}
catch (Exception e) {
System.out.println(e.getMessage());
System.exit(0);
}
}
private void play() {
System.out.println("play");
int maxSize = (int) Math.round((SAMPLE_RATE * af.getFrameSize())/ frequency);
byte[] samples = new byte[maxSize];
line.start();
double volume = 1;
int count = 0;
for (int i = 0; i < numLoops; i ++){
if (count == beep) {
if(volume==1) volume = 0;
else volume = 1;
count = 0;
}
count ++;
playWave(frequency, volume, samples);
}
line.drain();
line.stop();
line.close();
System.exit(0);
}
private void playWave(int frequency, double volLevel, byte[] samples) {
double amplitude = volLevel * MAX_AMPLITUDE;
int numSamplesInWave = (int) Math.round(((double) SAMPLE_RATE)/frequency);
int index = 0;
for (int i = 0; i < numSamplesInWave; i++) {
double theta = (double)i/numSamplesInWave;
double wave = getWave(theta);
int sample = (int) (wave * amplitude);
if (filter) sample = applyLowPassFilter(sample);
// left sample
samples[index + 0] = (byte) (sample & 0xFF);
samples[index + 1] = (byte) ((sample >> 8) & 0xFF);
// right sample
samples[index + 2] = (byte) (sample & 0xFF);
samples[index + 3] = (byte) ((sample >> 8) & 0xFF);
index += 4;
}
int offset = 0;
while (offset < index){
double increment =line.write(samples, offset, index-offset);
offset += increment;
}
}
private double getWave(double theta){
double value = 0;
theta = theta * 2 * Math.PI;
value = getSin(theta);
//value = getSqr(theta);
return value;
}
private double getSin(double theta){
return Math.sin(theta);
}
private int getSqr(double theta){
if (theta <= Math.PI) return 1;
else return 0;
}
// implementation of basic low-pass filter
private int applyLowPassFilter(int sample){
int newValue = sample;
double filteredValue = oldValue + (newValue - oldValue)/smoothing;
oldValue = filteredValue;
return (int) filteredValue;
}
}
相關的方法是在年底。如果有人測試這個,如果你有耳機請注意音量!
因此,要麼:
- 這是工作,我只是期望太高了這樣一個簡單的實現
- 我做錯了什麼,愚蠢和明顯的...
如果它只是1.我應該如何擺脫由於突然振幅變化而導致的惡劣節拍/擊中/點擊?
如果是2好,應該是太長的問題,一個V簡短的回答。
啊好的,謝謝。我只是覺得在做一個更好的工作之前,現在我的代碼似乎在減少音量。我會嘗試將其應用於振幅,並考慮實施ADSR信封。出於好奇,有沒有一個最大的幅度變化,你肯定會聽到點擊? – kiman
@kiman:爲了避免點擊,振幅應該平穩改變。小的不連續幅度變化仍然可以產生點擊。 – Shannon
@kiman:根據上下文,平滑幅度在1-10毫秒內變化可能足以避免明顯的點擊。 – Shannon