【问题标题】:Java audio effects - Distortion algorithm on AndroidJava 音效 - Android 上的失真算法
【发布时间】:2011-02-22 19:45:56
【问题描述】:

我正在开发一个用于对来自麦克风的音频进行实时处理的 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);
        }

buffers 数组是一个 2D 的 short 数组,处理只在数组中的一个数组中完成,这里是 buffers[ix]。

【问题讨论】:

    标签: java android audio signal-processing


    【解决方案1】:

    据我所知,你最终得到的只是一个剪辑阈值,其剪辑阈值遵循比例 clipThr/max(input)=distLvlSho/0x7fff。这种方式的大部分输入基本不变。

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

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

    最简单的是对称软剪辑(参见第 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);
        }
     }
    

    【讨论】:

      【解决方案2】:

      如果将 2 个短整数相乘,则结果需要一个长整数,否则结果可能会溢出。

      例如1000 * 1000 = 1000000 ,对于 16 位短整数来说太大了。

      因此,您需要在将乘法结果转换为用于存储的短值之前执行缩放操作(除法或右移)。比如:

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

      【讨论】:

      • 应该提到这一点,开始使用的 maxValue 函数找到我正在使用的数组的最大值,所以 multiplier short 应该将数组中的值乘以最多值的限制空头可以持有,32767。
      猜你喜欢
      • 2015-06-29
      • 1970-01-01
      • 2016-08-11
      • 2011-06-26
      • 2022-08-13
      • 2023-01-29
      • 2015-07-15
      • 1970-01-01
      • 2018-08-11
      相关资源
      最近更新 更多