Вопросы по Android AudioRecord?
Я возился с функцией AudioRecord в Android API и обнаружил странное поведение с ней.
Справочная информация: мой телефон HTC Incredible. Я использую плагин Eclipse для разработки под Android с эмулятором. Целевая платформа или ОС - 2.2... Так как это то, что использует мой телефон.
Некоторый код:
bufferSize = AudioRecord.getMinBufferSize(FREQUENCY, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, FREQUENCY, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
Это код, который я использую для установки API AudioRecord. Теперь эмулятору нравится, когда для параметра FREQUENCY установлено значение 8000. Возвращается с размером буфера 640. Для телефона я использую 44100. Одна проблема здесь, кажется, что получающиеся данные PCM для волны, кажется, являются волной со знаком 8 битов. Я получаю значения от -127 до 128. Я думал, что значение AudioFormat.ENCODING_PCM_16BIT
будет производить что-то другое.
Я обрабатываю аудио с потоком,
public void run() {
while(isRecording) {
audioRecord.startRecording();
byte[] data = new byte[bufferSize];
audioRecord.read(data, 0, bufferSize);
listener.setData(data);
handleData(data);
}
audioRecord.release();
}
У меня есть способ графически отобразить соответствующую волну в режиме реального времени, используя SurfaceView
, Кажется, от микрофона исходит много шума. Я получаю этот шум от эмулятора и телефона, а также. Нужно ли проводить данные через какой-то фильтр (ы)? Я хотел бы использовать эти данные для расчета некоторого забавного БПФ и прочего, чтобы просто поиграть с волной. Но мне нужно как-то уменьшить шум.
Кто-нибудь еще испытал это? у кого-нибудь есть решение?
Я оценил ваше время и отзывы, спасибо, д.к.
4 ответа
Когда вы читаете байты из потока "AudioFormat.ENCODING_PCM_16BIT", он фактически дает вам как верхний, так и нижний байты каждого сэмпла как 2 последовательных байта. Это будет казаться чрезвычайно шумным, если вы просто возьмете каждый байт в качестве образца (вместо того, чтобы на самом деле считать половину сэмпла), плюс подпись будет неправильной для первого байта (в младшем порядке).
Чтобы получить значимые данные из потока, прочитайте через шорты, например,
public void run() {
while(isRecording) {
audioRecord.startRecording();
short[] data = new short[bufferSize/2];
audioRecord.read(data, 0, bufferSize/2);
listener.setData(data);
handleData(data);
}
audioRecord.release();
}
Прошло много времени с тех пор, как был задан этот вопрос, поэтому я не знаю, уместен ли ответ на него.
Причина, по которой вы получаете значения от -127 до 128, заключается в том, что вы читаете массив байтов, каждый из которых содержит 8-битное число со знаком. Для 16-битного звука прочитайте массив шортов.
Боюсь, я не могу помочь с проблемой шума.
Я мог бы помочь немного. Однако я нахожусь в той же ситуации, что и вы, поэтому могу рассказать вам только о своем опыте.
Я полагаю, что вы можете получить предпочтительный sampleRate вашего устройства, например, так:
int sampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_SYSTEM);
Режим кодирования 16 бит является единственным, который работает с AudioRecord. Я не уверен, почему вы получаете 8-битный вывод (верно?). Может кто знает.
Я также не уверен, как вы извлекаете амплитуду из извлеченных байтов, вы это сделали?
Наконец, я считаю, что вам нужно использовать функции периодического прослушивателя, например:
int sampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_SYSTEM);
int channelMode = AudioFormat.CHANNEL_IN_MONO;
int encodingMode = AudioFormat.ENCODING_PCM_16BIT;
int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelMode, encodingMode);
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelMode, encodingMode, bufferSize);
recorder.setPositionNotificationPeriod(intervalFrames);
recorder.setRecordPositionUpdateListener(recordListener);
recorder.startRecording();
private RecordListener recordListener = new RecordListener();
private class RecordListener implements AudioRecord.OnRecordPositionUpdateListener {
public void onMarkerReached(AudioRecord recorder) {
Log.v("MicInfoService", "onMarkedReached CALL");
}
public void onPeriodicNotification(AudioRecord recorder) {
Log.v("MicInfoService", "onPeriodicNotification CALL");
}
}
Здесь есть два больших вопроса, на которые я не могу ответить и хочу знать ответ и на себя:
- Что должно быть установлено в качестве intervalFrames?
- Почему методы слушателя никогда не вызываются?
Я хотел бы помочь больше.
Этот проект с открытым исходным кодом имеет большое количество вспомогательных классов, которые помогут вам получить аудиоданные и поэкспериментировать с их анализом:
https://github.com/gast-lib/gast-lib
Имеет AsyncTask
У этого есть кое-что, что управляет AudioRecorder
Он даже имеет простой алгоритм оценки частоты