2013-09-07 2 views
2

За последние 2 дня я пытался с легкостью управлять 16-битными данными PCM на Android. В настоящее время я использую WAV recorder для захвата аудио. В методе onPeriodicNotification(AudioRecord recorder) до того, как буфер написан с помощью randomAccessWriter, я отправляю буфер в пользовательский класс, чтобы манипулировать образцами и сохранять образцы обратно в буфер. Метод в моем пользовательском классе выглядит следующим образом:Подписанные 16-битные преобразования PCM не работают. Зачем?

Поскольку буфер представляет собой массив байтов, я сначала преобразовываю их в шорты, теперь один короткий представляет собой кадр (есть только один канал). Я буду реализовывать алгоритмы FFT, как только я пройду через это препятствие, которым нужен вход, чтобы быть массивом с плавающей точкой, поэтому я конвертирую каждый короткий в float. Теперь randomAccessWriter, который записывает данные в WAV-файл, принимает массив байтов и ожидает, что каждый кадр будет 2 байта. Поэтому я конвертирую каждый float обратно в короткий и использую ByteBuffer для восстановления массива байтов, который затем возвращается. Когда я запускаю свое приложение для рекордера, при этом буфер отправляется через указанный код, все в порядке.

Я стараюсь с использованием простого алгоритма модуляции голоса, чтобы проверить, если запись будет изменена, то алгоритм помещается где TODO комментарий:

Теперь, если я использовал приведенный выше код на моем iPhone аудио образцы будут преобразованы , хотя данные являются изначально 32-битными поплавками. Тем не менее, на Android, когда я снова запускаю приложение-рекордер, с вставленным выше кодом, все, что было сделано, это белый шум. Пока я не смогу успешно модифицировать образцы с указанным выше кодом, я не могу продолжить свои алгоритмы FFT.

Почему это происходит? Я был бы признателен, если бы кто-то, кто знал об этом, мог пролить свет на эту тему.

РЕШИТЬ - Бьорн Roche

Основные причины: Запись была давать данные в Little Endian, тогда как Java шорты в Big Endian; при применении функции с использованием двух разных форм создается белый шум. В приведенном ниже коде показано, как взять массив байтов Little Endian, преобразовать в массив Big Endian float и вернуться к массиву Little Endian. В то время как поплавки вы можете делать все, что угодно, я буду теперь использовать свои алгоритмы быстрого преобразования Фурье:

public byte[] manipulateSamples(byte[] data, 
           int samplingRate, 
           int numFrames, 
           short numChannels) { 

    // Convert byte[] to short[] (16 bit) to float[] (32 bit) (End result: Big Endian) 
    ShortBuffer sbuf = ByteBuffer.wrap(data).asShortBuffer(); 
    short[] audioShorts = new short[sbuf.capacity()]; 
    sbuf.get(audioShorts); 

    float[] audioFloats = new float[audioShorts.length]; 

    for (int i = 0; i < audioShorts.length; i++) { 
     audioFloats[i] = ((float)Short.reverseBytes(audioShorts[i])/0x8000); 
    } 

    // Do your tasks here. 

    // Convert float[] to short[] to byte[] (End result: Little Endian) 
    audioShorts = new short[audioFloats.length]; 
    for (int i = 0; i < audioFloats.length; i++) { 
     audioShorts[i] = Short.reverseBytes((short) ((audioFloats[i])*0x8000)); 
    } 

    byte byteArray[] = new byte[audioShorts.length * 2]; 
    ByteBuffer buffer = ByteBuffer.wrap(byteArray); 
    sbuf = buffer.asShortBuffer(); 
    sbuf.put(audioShorts); 
    data = buffer.array(); 

    return data; 

} 
+0

Для начала я проверил бы сквозной сценарий без обработки в середине. Вы должны получить то, что вы вложили. Могу ли я предложить написать некоторые модульные тесты? Вы также можете попробовать выполнить это с помощью отладчика. Я обратил бы особое внимание на разделение float на целое число ('(float) audioShorts [i])/0x8000'). Невозможно запомнить правила продвижения вне игры для Java, но это выглядит правдоподобной причиной. Попробуйте переделать это как '(float) audioShorts [i])/32768.0f'. У вас может быть такая же проблема и в другом направлении. – marko

+0

Спасибо за ваш вход, я пробовал без обработки в середине, и данные проходят через штраф, я также попробовал ваше предложение, и шум все еще присутствовал, я озадачен тем, почему это происходит, знаю, почему это происходит. Я не могу написать какие-либо тесты юнита. –

+0

Прежде чем попробовать такой сложный тест, попробуйте что-то простое, например деление на 2. –

ответ

4

Ваша проблема заключается в том, что шорты в Java являются bigendian, но если вы получили ваши данные из WAV файла данных мало обратный порядок байт.

+0

В любом случае я мог бы преобразовать их в Little Endian, выполнить преобразование образцов, затем вернуться в Big Endian (как ожидается RandomAccessWriter), или мне нужно сохранить wav-файл, а затем снова открыть его, а затем сделать то, что я хочу сделать с образцами? –

+0

Подождите, я просто прочитал, что вы сказали. Данные уже находятся в Big Endian, данные записываются с Mic.Итак, поэтому я не должен делать трансформацию в том, как я пытаюсь? –

+0

Возможно, мне это не хватает, но, глядя на код для wav-рекордера, я не вижу обмена байтов между записью и записью в файл. Это означает, что конечная запись записи такая же, как и файл, а файлы WAV - малорисковые, поэтому запись немного ориентирована. –