За последние 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;
}
Для начала я проверил бы сквозной сценарий без обработки в середине. Вы должны получить то, что вы вложили. Могу ли я предложить написать некоторые модульные тесты? Вы также можете попробовать выполнить это с помощью отладчика. Я обратил бы особое внимание на разделение float на целое число ('(float) audioShorts [i])/0x8000'). Невозможно запомнить правила продвижения вне игры для Java, но это выглядит правдоподобной причиной. Попробуйте переделать это как '(float) audioShorts [i])/32768.0f'. У вас может быть такая же проблема и в другом направлении. – marko
Спасибо за ваш вход, я пробовал без обработки в середине, и данные проходят через штраф, я также попробовал ваше предложение, и шум все еще присутствовал, я озадачен тем, почему это происходит, знаю, почему это происходит. Я не могу написать какие-либо тесты юнита. –
Прежде чем попробовать такой сложный тест, попробуйте что-то простое, например деление на 2. –