Декодер FFT для аудиосигнала в Android

Я пытаюсь создать декодер в Android для проекта, опубликованного https://github.com/rraval/pied-piper Они уже создали декодер на питоне, на питоне это было довольно просто с помощью пакета numpy, а вот на джаве у меня туго. Шаги, используемые в python, включают:

def dominant(frame_rate,chunk):
  w=numpy.fft.fft(chunk)
  numpy.fft.fftfreq(len(chunk))
  peak_coeff = numpy.argmax(numpy.abs(w))
  peak_freq = freqs[peak_coeff]
  return abs(peak_freq * frame_rate) # in Hz

Приведенный выше код возвращает частоту аудиоданных в кусках [].

Я пытаюсь создать код Android, который реализует ту же логику. Моя работа на данный момент представлена ​​ниже:

public class MicReadThread3 extends Thread {

static final int HANDSHAKE_START_HZ = 8192;
static final int HANDSHAKE_END_HZ = 8192 + 512;
static final int START_HZ = 1024;
static final int STEP_HZ = 256;
static final int BITS = 4;
static final int FEC_BYTES = 4;
static final int sample_size=8;
boolean callBack_done=false;

private static final int AUDIO_SOURCE = MediaRecorder.AudioSource.MIC;
private static final int SAMPLE_RATE = 44100; // Hz
private static final int ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private static final int CHANNEL_MASK = AudioFormat.CHANNEL_IN_MONO;
private static final int BUFFER_SIZE = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_MASK, ENCODING);
private static final int blockSize=BUFFER_SIZE;



public MicReadThread3(){
    setPriority(Thread.MAX_PRIORITY);
}

@Override
public void run(){

    System.out.println("Buffer Size : "+BUFFER_SIZE);
    AudioRecord audioRecord=null;
    double dom;
    byte[] buffer=new byte[blockSize];
    short[] bufferShort =new short[blockSize];
    audioRecord = new AudioRecord(AUDIO_SOURCE, SAMPLE_RATE, CHANNEL_MASK, ENCODING, BUFFER_SIZE);
    audioRecord.startRecording();
    while(true){
        audioRecord.read(buffer, 0, blockSize);
        dom = dominant(SAMPLE_RATE, buffer);
        System.out.println("Dominant="+dom);
        if(match(dom,HANDSHAKE_START_HZ)){
            System.out.println("Found Handshake start freq :"+dom);
        }

        if(match(dom,HANDSHAKE_END_HZ)){
            System.out.println("Found Handshake end freq :"+dom);
        }
    }

}

public boolean match(double freq1, double freq2) {
    return Math.abs(freq1 - freq2) < 20;
}

public double dominant(int frame_rate, byte[] chunk){
    int len=chunk.length;
    double[] waveTransformReal=new double[len];
    double[] waveTransformImg=new double[len];
    for(int i=0;i<len;i++){
        waveTransformReal[i]=chunk[i];
    }

    Fft.transform(waveTransformReal,waveTransformImg);

    //Calculating abs
    double[] abs=new double[len];

    for(int i=0;i<len;i++) {
        abs[i] = (Math.sqrt(waveTransformReal[i] * waveTransformReal[i] + waveTransformImg[i] * waveTransformImg[i]));

    }
    int maxIndex=0;
    for(int i=0;i<len;i++) {
        if (abs[i] > abs[maxIndex])
            maxIndex = i;
    }
    //frame_rate is sampling freq and len is no. of datapoints
    double dominantFrequency=(maxIndex*frame_rate)/len;
    return dominantFrequency;
}

}

Класс, который я использую для получения Fft, можно найти по приведенной ниже ссылке: https://www.nayuki.io/res/free-small-fft-in-multiple-languages/Fft.java

Я должен напечатать доминирующую частоту, если она равна частотам рукопожатия.

Но когда я печатаю значения, я получаю просто значения нежелательной частоты, такие как 1000,42050,2000,...

В python код был в порядке, но в Android становится все сложнее... Пожалуйста, помогите, мой проект должен быть представлен на следующей неделе. Это только часть моего проекта, мы отстаем из-за этой проблемы! Спасибо заранее.


person AKHIL KUMAR    schedule 14.04.2017    source источник
comment
Привет Ахил, просто проверяю, смог ли ты заставить работать расшифровку. Я пытался заставить его работать на Android и не смог этого сделать. Какую библиотеку БПФ вы использовали?   -  person Arun    schedule 15.11.2018
comment
Простой ответ: НЕТ, я не мог. Мы завершили проект по-другому.   -  person AKHIL KUMAR    schedule 16.11.2018


Ответы (1)


Я слишком быстро ответил на свой первоначальный ответ

    double dominantFrequency=(maxIndex*frame_rate)/len;

Что касается вашего комментария, я еще раз посмотрел и увидел разницу между кодом github и тем, который вы разместили: github запрашивает 8-битное аудио, а здесь это ENCODING_PCM_16BIT.

Таким образом, каждое значение в waveTransformReal[] будет только частичным, потому что оно берется из байтовых данных chunk[], где 2 байта составляют полное значение. В качестве быстрого теста попробуйте использовать ENCODING_PCM_8BIT и посмотрите, получите ли вы правильный результат.

person hg123    schedule 14.04.2017
comment
Спасибо за ваш ответ @hg123, я получил уравнение из темы: stackoverflow.com/questions/7674877/, также я правильно расшифровал частоту в java-программе, которая работает на моем ПК. используя ту же логику, тот же класс fft, единственная разница заключалась в том, что класс использовался для чтения с микрофона. Вы можете найти ссылку на мою Java-программу здесь: github.com/akvishnuta/MainProject/blob /master/getDominant - person AKHIL KUMAR; 15.04.2017
comment
Я уже пробовал это, но ENCODING_PCM_8BIT не поддерживается в Android. Если использовать его тогда, AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_MASK, ENCODING) вернет -2, что в конечном итоге приведет к исключению отрицательного массива. - person AKHIL KUMAR; 15.04.2017
comment
Вам нужно будет взять 2 байта для каждого значения, тогда IE, чанк [0] и чанк [1] ​​составляют waveTransformReal [0]. Обратите внимание, что количество сэмплов будет разделено на 2, если вы используете 16 бит. - person hg123; 15.04.2017
comment
О, спасибо, я изменил тип данных блока и буфера на короткий. Теперь определяет частоты, но только с другого телефона. Моя проблема частично решена. Код Python, который я использую для кодирования на ПК, приведен ниже: github.com/akvishnuta/MainProject /дерево/мастер - person AKHIL KUMAR; 16.04.2017
comment
Я думаю, вы могли бы попробовать отладить свой код на обоих телефонах (или отобразить некоторые значения на экране). Похоже, ваша первоначальная проблема выявлена ​​(если не решена полностью). Удачи! - person hg123; 16.04.2017