Аудиоэффекты Java - алгоритм искажения на Android - PullRequest
0 голосов
/ 22 февраля 2011

Я работаю над приложением для 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 ]

2 голосов
/ 24 февраля 2011

Насколько я вижу, в конце концов вы получаете только отсечение источника с порогом клипа, который соответствует пропорции 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);
    }
 }
0 голосов
/ 23 февраля 2011

Если вы умножите 2 коротких целых числа, результат требует длинного целого числа, или результат может переполниться.

например. 1000 * 1000 = 1000000, что слишком велико для 16-битного короткого целого числа.

Таким образом, вам нужно выполнить операцию масштабирования (деление или сдвиг вправо) до , чтобы преобразовать результат умножения в короткое значение для хранения. Что-то вроде:

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