我让合成器能够生成三种基本类型的声音并对其进行过滤。对于过滤,我使用了TarsosDSP中的代码。
然而,声音的过滤是正确的,但是有很多噪音,这比声音本身更响亮。 我没有对代码进行任何重大更改,只添加了转换浮点数 - >简而言之,因为我使用Audiotrack的短裤缓冲区。
以下是代码:
int amp = 32767;
double phase = 0.0;
float cutOffFrequency = 200;
protected void onCreate(Bundle savedInstanceState) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
String nativeParam = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
sampleRate = Integer.parseInt(nativeParam);
nativeParam = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
bufSize = Integer.parseInt(nativeParam);
}
else {
sampleRate = 44100;
bufSize = AudioTrack.getMinBufferSize(sampleRate,
AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
}
audioOutput = new AudioOutput();
audioOutput.Start(sampleRate, bufSize);
samples = new short[bufSize];
playTask.execute();
}
class PlayTask extends AsyncTask<Object, Void, Void> {
@Override
protected Void doInBackground(Object[] params) {
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
while (!this.isCancelled()) {
phase = 0.0;
while (touched) {
generateTone();
generateFilter();
audioOutput.write(samples, 0, samples.length);
}
}
return null;
}
}
private void generateTone() {
double phaseIncrement = (2 * Math.PI) / sampleRate;
switch (currentShape) {
case SINE:
for (int i = 0; i < bufSize; i++) {
samples[i] = (short) (amp * Math.sin(phase));
phase += phaseIncrement * freq;
if (phase > 2 * Math.PI)
phase -= 2 * Math.PI;
}
break;
case SAWTOOTH:
for (int i = 0; i < bufSize; i++) {
samples[i] = (short) (amp * (phase - amp));
phase += phaseIncrement * freq;
if (phase > 2 * Math.PI)
phase -= 2 * Math.PI;
}
break;
case SQUARE:
for (int i = 0; i < bufSize; i++) {
if (phase < Math.PI)
samples[i] = (short) amp;
else
samples[i] = (short) -amp;
phase += phaseIncrement * freq;
if (phase > 2 * Math.PI)
phase -= 2 * Math.PI;
}
break;
}
}
private void generateFilter() {
LowPassFilter lpf = new LowPassFilter(cutOffFrequency, sampleRate);
samples = lpf.process(samples);
}
public class AudioOutput {
public void Start(int sampleRate, int bufferSize) {
Stop();
mFrameRate = sampleRate;
mAudioTrack = createAudioTrack(bufferSize);
mAudioTrack.play();
}
private AudioTrack createAudioTrack(int buffsize) {
return new AudioTrack(AudioManager.STREAM_MUSIC,
mFrameRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, buffsize,
AudioTrack.MODE_STREAM);
}
public int write(short[] buffer, int offset, int length) {
return write = mAudioTrack.write(buffer, offset, length);
}
public void Stop() {
if (mAudioTrack != null) {
mAudioTrack.stop();
mAudioTrack.release();
mAudioTrack = null;
}
}
}
public class LowPassFilter extends IIRFilter {
public LowPassFilter(float freq, int sampleRate) {
super(freq > 60 ? freq : 60, sampleRate);
}
@Override
protected void calcCoeff() {
float freqFrac = getFrequency() / getSampleRate();
float x = (float) Math.exp(-14.445 * freqFrac);
a = new float[] { (float) Math.pow(1 - x, 4) };
b = new float[] { 4 * x, -6 * x * x, 4 * x * x * x, -x * x * x * x };
}
}
public abstract class IIRFilter {
/** The b coefficients. */
protected float[] b;
/** The a coefficients. */
protected float[] a;
/**
* The input values to the left of the output value currently being
* calculated.
*/
protected float[] in;
/** The previous output values. */
protected float[] out;
private float frequency;
private float sampleRate;
public IIRFilter(float cutOffFreq, int sampleRate) {
this.sampleRate = sampleRate;
this.frequency = cutOffFreq;
calcCoeff();
in = new float[a.length];
out = new float[b.length];
}
public void setFrequency(float freq){
this.frequency = freq;
calcCoeff();
}
public float getFrequency() {
return frequency;
}
public float getSampleRate(){
return sampleRate;
}
private float[] getFloatBuffer(short[] buffer) {
float[] floaters = new float[buffer.length];
for (int i = 0; i < buffer.length; i++) {
floaters[i] = buffer[i];
}
return floaters;
}
private short[] getShortBuffer(float[] buffer) {
short[] shorts = new short[buffer.length];
for (int i = 0; i < buffer.length; i++) {
shorts[i] = (short)buffer[i];
}
return shorts;
}
protected abstract void calcCoeff() ;
public short[] process(short[] input) {
float[] audioFloatBuffer = getFloatBuffer(input);
for (int i = 0; i < audioFloatBuffer.length; i++) {
//shift the in array
System.arraycopy(in, 0, in, 1, in.length - 1);
in[0] = audioFloatBuffer[i];
//calculate y based on a and b coefficients
//and in and out.
float y = 0;
for(int j = 0 ; j < a.length ; j++){
y += a[j] * in[j];
}
for(int j = 0 ; j < b.length ; j++){
y += b[j] * out[j];
}
//shift the out array
System.arraycopy(out, 0, out, 1, out.length - 1);
out[0] = y;
audioFloatBuffer[i] = y;
}
return getShortBuffer(audioFloatBuffer);
}
}
这里记录波形,图案随频率变化,频率越低越快。
低通滤波器本身应该是正确的,用matlab检查。