Вопрос по fft, android, java – Как преобразовать 16-битный байтовый массив PCM в массив double или float?

8

Я пытаюсь выполнить быстрое преобразование Фурье для аудиофайла .3gpp. Файл содержит небольшую 5-секундную запись с частотой 44100 кГц от микрофона телефона.

Каждый алгоритм Java FFT, который я могу найти, по понятным причинам принимает только входы double [], float [] или Complex [], но я читаю аудиофайл в байтовом массиве, так что я немного запутался в том, что куда я иду отсюда Единственное, что я смог найти - это ответ на предыдущий вопрос:

Android аудио FFT для получения определенной частоты с использованием аудиозаписи

Но я не уверен, правильно ли это сделано. Кто-нибудь с пониманием?

Ваш Ответ

2   ответа
13

ассива отдельно.

Я делаю то же самое для шорт, которые я делаю как поплавки:

public static float[] floatMe(short[] pcms) {
    float[] floaters = new float[pcms.length];
    for (int i = 0; i < pcms.length; i++) {
        floaters[i] = pcms[i];
    }
    return floaters;
}
EDIT 4/26/2012 based on comments

Если у вас действительно есть 16-битный PCM, но он есть как байт [], то вы можете сделать это:

public static short[] shortMe(byte[] bytes) {
    short[] out = new short[bytes.length / 2]; // will drop last byte if odd number
    ByteBuffer bb = ByteBuffer.wrap(bytes);
    for (int i = 0; i < out.length; i++) {
        out[i] = bb.getShort();
    }
    return out;
}

затем

float[] pcmAsFloats = floatMe(shortMe(bytes));

Если вы не работаете со странным и плохо спроектированным классом, который в первую очередь предоставил вам байтовый массив, разработчики этого класса должны были упаковать байты, чтобы соответствовать способу, которым Java преобразует байты (по 2 за раз) в шорты.

Спасибо за редактирование mwengler. Однако не должно ли t pcmAsFloats быть половиной длины короткого массива? 1 float = 4 байта, 1 short = 2 байта? soren.qvist
Не говоря уже о том, что он должен быть такой же длины, что и короткий массив, так как это такое же количество выборок. soren.qvist
Спасибо, я просто запутался, что Java знает, как интерпретировать эти данные. Может быть, я получил полное представление о том, как он хранится неправильно (посмотрите на мой комментарий к ответу Кайла). В любом случае, любой код приветствуется, я буду его использовать, если не пойму иначе. soren.qvist
-3
byte[] yourInitialData;
double[] yourOutputData = ByteBuffer.wrap(bytes).getDouble()
Просматривая документацию, я вижу, что getDouble () на самом деле возвращает double, а не double []. Так что это не сработает. soren.qvist
ByteBuffer.getDouble (); неправильно.
@ Кайл Это неправильный ответ. Неправильно, что он даже не скомпилируется. -getDouble() возвращает типdouble неdouble[], Это останавливает компиляцию. - getDouble () захватывает 4 байта за раз, связывает их вместе в 32-битные и интерпретирует все какdouble, Поскольку байтовый массив не был сохранен какdoubles, это приведет к бессмысленным результатам, и только 1/2doubles можно извлечь из массива, как былоshortS положить в массив. - Смотрите мой ответ выше для способа использования ByteBuffer для преобразованияbyte[] вshort[] это работает.
Это выглядит элегантно, но я думаю, что меня смущает то, что это выглядит слишком произвольно (я зеленый, когда речь заходит об аудио в Java). Если 16-битный PCM хранится в байтах таким образом, что он представляет мощность аналогового сигнала во времени, то не должен ли процесс преобразования знать об этой структуре? Я имею в виду, как getDouble () вообще знает, что это аудио файл? soren.qvist

Похожие вопросы