Java音效 - Android上的失真算法

时间:2011-02-22 19:45:56

标签: java android audio signal-processing

我正在开发一个Android应用程序,可以从麦克风中实时处理音频。采样和播放工作有效,但我很难实现第一个音频效果 - 失真。音频来自短路缓冲区,因此每次收到其中一个时,我会尝试将值映射到有符号短路的完整大小,然后在这些值高于某个级别时实际上剪切这些值。来自此的音频肯定是扭曲的,但不是理想的方式。我已经包含了我的代码来完成这个。谁能在这里看到错误?

public void onMarkerReached(AudioRecord recorder) {
            // TODO Auto-generated method stub
            short max = maxValue(buffers[ix]);
            short multiplier;

            if(max!=0)
                multiplier = (short) (0x7fff/max);
            else
                multiplier = 0x7fff;
            double distLvl =.8;
            short distLvlSho = 31000;
            short max2 =100;
        for(int i=0;i<buffers[ix].length;i++){
            buffers[ix][i]=(short) (buffers[ix][i]*multiplier);
            if(buffers[ix][i]>distLvlSho)
                buffers[ix][i]=distLvlSho;
            else if(buffers[ix][i]<-distLvlSho)
                buffers[ix][i]=(short)-distLvlSho;
            buffers[ix][i]=(short) (buffers[ix][i]/multiplier);
        }

缓冲区数组是一个短的二维数组,处理只在阵列中的一个数组上完成,这里是缓冲区[ix]。

2 个答案:

答案 0 :(得分:2)

据我所知,你得到的只是一个剪辑源,剪辑阈值跟随clipThr / max(输入)= distLvlSho / 0x7fff的比例。这种方式的大部分输入基本没有变化。

如果你真的想扭曲信号,你应该对整个信号应用某种非线性函数(最后在样本最大值附近剪切以模拟模拟饱和度)

本书列出了一些简单的失真模型:http://books.google.it/books?id=h90HIV0uwVsC&printsec=frontcover#v=onepage&q&f=false

最简单的是一种simmetrical软剪辑(参见第118页)。这是使用该软剪辑功能修改的方法,看看它是否适合您对失真声音的需求(我通过在输入上组成一些正弦曲线并使用excel绘制输出来测试它)

在同一章中,您将找到一个简单的管道建模和模糊滤波器建模(这些都有一些指数,所以如果性能是一个问题,您可能想要近似那些)。

    public void onMarkerReachedSoftClip(short[] buffer) {
    double th=1.0/3.0; 
     double multiplier = 1.0/0x7fff; // normalize input to double -1,1
     double out = 0.0;
     for(int i=0;i<buffer.length;i++){
        double in = multiplier*(double)buffer[i];
        double absIn = java.lang.Math.abs(in);
        if(absIn<th){
            out=(buffer[i]*2*multiplier);
        }
        else if(absIn<2*th){
            if(in>0)out= (3-(2-in*3)*(2-in*3))/3;
            else if(in<0)out=-(3-(2-absIn*3)*(2-absIn*3))/3;
        }
        else if(absIn>=2*th){
            if(in>0)out=1;
            else if(in<0)out=-1;
        }
        buffer[i] = (short)(out/multiplier);
    }
 }

答案 1 :(得分:0)

如果乘以2个短整数,结果需要一个长整数或结果可能溢出。

e.g。 1000 * 1000 = 1000000,对于16位短整数来说太大了。

因此,您需要执行缩放操作(除法或右移)之前将乘法结果转换为较短的存储值。类似的东西:

result_short = (short)( ( short_op_1 * short_op_2 ) >> 16 );