Использование AudioTrack в Android для воспроизведения WAV файла

Я работаю с Android, пытаясь заставить приложение AudioTrack воспроизводить Windows.wav файл (Tada.wav). Честно говоря, это не должно быть так сложно, но я слышу много странных вещей. Файл сохраняется на моей мини-карте mini SD и чтение содержимого не кажется проблемой, но когда я играю в файл (с параметрами я только PRETTY SURE прав), я получаю несколько секунд белого шума прежде чем звук, кажется, разрешит себя во что-то, что просто может быть правильным.

Я успешно записал и воспроизвел свой собственный голос на телефоне - я создал файл .pcm в соответствии с указаниями в этом примере:

http://emeadev.blogspot.com/2009/09/raw-audio-manipulation-in-android.html

(без маскировки назад)...

У кого-нибудь есть какие-то предложения или понимание примера в Интернете для воспроизведения WAV файла на Android?

Спасибо, R.

Ответ 1

Я наткнулся на ответ (честно говоря, пытаясь & ^ @! Я не думал, что это сработает), если кто-то заинтересован... В моем исходном коде (который получен из примера в ссылке в оригинальное сообщение), данные считываются из файла следующим образом:

    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

В этой версии музыка [] представляет собой массив 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

В этой версии музыка [] представляет собой массив BYTES. Я все еще говорю AudioTrack, что 16-битные данные PCM, и у моего Android, похоже, не проблема с записью массива байтов в конфигурацию AudioTrack, настроенную таким образом... Во всяком случае, это, наконец, звучит правильно, поэтому, если кто-нибудь другой хочет воспроизвести звуки Windows на своем Android, почему-то, что решение. Ах, Endianness......

R.

Ответ 2

Я нашел много длинных ответов на этот вопрос. Мое окончательное решение, которое давало все вырезание и склеивание, вряд ли мое, сводится к:

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 - это просто "истина", отправленная в качестве сигнала на reset кнопку паузы/воспроизведения. И в инициализаторе класса:

public Mp3Track(Context context) {
    mContext = context;
    minBufferSize = AudioTrack.getMinBufferSize(44100,
        AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
}

Контекст - это просто "this" из вызывающей активности. Вы можете использовать FileInputStream на SD-карте и т.д. Мои файлы находятся в res/raw

Ответ 3

Пропускаете ли вы первые 44 байта файла, прежде чем вы оставите остальную часть данных файла в буфере? Первые 44 байта - это заголовок WAVE, и они будут звучать как случайный шум, если вы попытаетесь воспроизвести их.

Также вы уверены, что создаете AudioTrack с теми же свойствами, что и WAVE, который вы пытаетесь воспроизвести (частота дискретизации, скорость передачи, количество каналов и т.д.)? Windows действительно хорошо справляется с предоставлением этой информации на странице "Свойства файла": alt text

Ответ 4

Как сказано Aaron C, вам нужно пропустить начальные 44 байта или (как я предпочитаю) читать первые 44 байта, которые являются заголовком WAVE. Таким образом, вы знаете, сколько каналов, бит на выборку, длину и т.д. Содержит WAVE.

Здесь вы можете найти хорошую реализацию анализатора WAVE заголовка/записи.

Ответ 5

Пожалуйста, не увековечивайте ужасный код синтаксического анализа. Разбор WAV тривиально для реализации http://soundfile.sapp.org/doc/WaveFormat/ и вы поблагодарите себя за то, что сможете анализировать такие вещи, как частота дискретизации, глубина бит и количество каналов.

Кроме того, x86 и ARM (по крайней мере, по умолчанию) являются минимальными, поэтому файлы WAV с открытым контентом должны быть хорошими без перетасовки.

Ответ 6

Пример файла 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;
}

}

Ответ 7

Просто подтвердите, есть ли у вас 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
);