Использование AudioTrack в Android для воспроизведения файла WAV
Я работаю с Android и пытаюсь заставить мое приложение AudioTrack воспроизводить файл.wav для Windows (Tada.wav). Честно говоря, это не должно быть так сложно, но я слышу много странных вещей. Файл сохранен на мини-SD-карте моего телефона, и чтение содержимого, кажется, не является проблемой, но когда я воспроизводю файл (с параметрами, я только ДОВОЛЬНО УВЕРЕН, что прав), я получаю несколько секунд белого шума прежде чем звук, кажется, превращается в нечто, что может быть правильным.
Я успешно записал и воспроизвел свой голос на телефоне - я создал файл.pcm в соответствии с инструкциями в этом примере:
http://emeadev.blogspot.com/2009/09/raw-audio-manipulation-in-android.html
(без обратной маскировки)...
Кто-нибудь получил некоторые предложения или осведомленность о примере в Интернете для воспроизведения WAV-файла на Android?
Спасибо, Р.
6 ответов
Я наткнулся на ответ (честно говоря, пытаясь &^@! Я не думал, что будет работать), на случай, если кто-то заинтересован... В моем оригинальном коде (который получен из примера в ссылке в оригинальном сообщении), данные читаются из файла следующим образом:
InputStream is = new FileInputStream (file);
BufferedInputStream bis = new BufferedInputStream (is, 8000);
DataInputStream dis = new DataInputStream (bis); // Create a DataInputStream to read the audio data from the saved file
int i = 0; // Read the file into the "music" array
while (dis.available() > 0)
{
music[i] = dis.readShort(); // This assignment does not reverse the order
i++;
}
dis.close(); // Close the input stream
В этой версии music[] - это массив SHORTS. Таким образом, метод readShort(), по-видимому, имеет здесь смысл, поскольку данные представляют собой 16-разрядные PCM... Однако на Android это, похоже, является проблемой. Я изменил этот код на следующее:
music=new byte[(int) file.length()];//size & length of the file
InputStream is = new FileInputStream (file);
BufferedInputStream bis = new BufferedInputStream (is, 8000);
DataInputStream dis = new DataInputStream (bis); // Create a DataInputStream to read the audio data from the saved file
int i = 0; // Read the file into the "music" array
while (dis.available() > 0)
{
music[i] = dis.readByte(); // This assignment does not reverse the order
i++;
}
dis.close(); // Close the input stream
В этой версии music[] представляет собой массив байтов. Я до сих пор говорю AudioTrack, что это 16-битные данные PCM, и у моего Android, похоже, нет проблем с записью массива байтов в AudioTrack, настроенный таким образом... В любом случае, он, наконец, звучит правильно, так что если кто-то еще кто-то хочет воспроизводить звуки Windows на своих Android, по какой-то причине это решение. Ах, Endianness......
Р.
Я нашел много длинных ответов на этот вопрос. Мое окончательное решение, которое с учетом того, что все вырезки и вставки едва ли являются моими, сводится к следующему:
public boolean play() {
int i = 0;
byte[] music = null;
InputStream is = mContext.getResources().openRawResource(R.raw.noise);
at = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
minBufferSize, AudioTrack.MODE_STREAM);
try{
music = new byte[512];
at.play();
while((i = is.read(music)) != -1)
at.write(music, 0, i);
} catch (IOException e) {
e.printStackTrace();
}
at.stop();
at.release();
return STOPPED;
}
STOPPED - это просто "true", отправленный обратно в качестве сигнала для сброса кнопки паузы / воспроизведения. И в инициализаторе класса:
public Mp3Track(Context context) {
mContext = context;
minBufferSize = AudioTrack.getMinBufferSize(44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
}
Контекст - это просто "это" из вызывающей деятельности. Вы можете использовать FileInputStream на SD-карте и т. Д. Мои файлы находятся в res / raw
Вы пропускаете первые 44 байта файла перед тем, как выгружать оставшиеся данные файла в буфер? Первые 44 байта являются заголовком WAVE, и они будут звучать как случайный шум, если вы попытаетесь их воспроизвести.
Кроме того, вы уверены, что создаете AudioTrack с теми же свойствами, что и WAVE, который вы пытаетесь воспроизвести (частота дискретизации, битрейт, количество каналов и т. Д.)? Windows на самом деле хорошо справляется с этой задачей на странице свойств файла:
Как сказал Aaron C, вы должны пропустить первые 44 байта или (как я предпочитаю) прочитать первые 44 байта, которые являются заголовком WAVE. Таким образом, вы знаете, сколько каналов, бит на семпл, длину и т. Д.... содержит WAVE.
Здесь вы можете найти хорошую реализацию анализатора / записи заголовка WAVE.
Пожалуйста, не увековечивайте ужасный код разбора. Синтаксический анализ WAV очень прост в реализации http://soundfile.sapp.org/doc/WaveFormat/ и вы будете благодарны, если сможете анализировать такие вещи, как частота дискретизации, битовая глубина и количество каналов.
Кроме того, x86 и ARM (по крайней мере по умолчанию) оба имеют порядок байтов, поэтому WAV-файлы с прямым порядком байтов должны работать без перестановок.
Просто подтвердите, если у вас есть AudioTrack.MODE_STREAM
и не AudioTrack.MODE_STATIC
в AudioTrack
конструктор:
AudioTrack at = new AudioTrack(
AudioManager.STREAM_MUSIC,
sampleRate,
AudioFormat.CHANNEL_IN_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
// buffer length in bytes
outputBufferSize,
AudioTrack.MODE_STREAM
);
Пример файла WAV:
http://www.mauvecloud.net/sounds/pcm1644m.wav
Образец кода:
public class AudioTrackPlayer {
Context mContext;
int minBufferSize;
AudioTrack at;
boolean STOPPED;
public AudioTrackPlayer(Context context) {
Log.d("------","init");
mContext = context;
minBufferSize = AudioTrack.getMinBufferSize(44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
}
public boolean play() {
Log.d("------","play");
int i = 0;
byte[] music = null;
InputStream is = mContext.getResources().openRawResource(R.raw.pcm1644m);
at = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
minBufferSize, AudioTrack.MODE_STREAM);
try {
music = new byte[512];
at.play();
while ((i = is.read(music)) != -1)
at.write(music, 0, i);
} catch (IOException e) {
e.printStackTrace();
}
at.stop();
at.release();
return STOPPED;
}
}