Android AudioTrack не воспроизводит все образцы

Я использую AudioTrack для воспроизведения последовательности синусоид, но когда я запускаю его на своем HTC M9, он воспроизводит только часть сэмплов, а продолжительность воспроизведения зависит от случайных значений. е. грамм. У меня есть 20 тонов, но я играю только от 2 до 17,5 тонов из них. И да он даже остановится посреди тона.

Вот мой код из другого ответа:

    ArrayList<double[]> samples = new ArrayList<>();
    int numSamples = 0;
    for (final ToneSegment seg : sequence) {
        int num =  seg.getDuration() * sampleRate / 1000;
        double[] sample = new double[num];
        for (int i = 0; i < num; ++i) {
            sample[i] = Math.sin(2 * Math.PI * i * seg.getPitch() / sampleRate);
        }
        samples.add(sample);
        numSamples += num;
    }

    byte generatedSnd[] = new byte[2 * numSamples];
    int idx = 0;
    for (double[] sample : samples) {
        for (final double dVal : sample) {
            final short val = (short) ((dVal * 32767));
            generatedSnd[idx++] = (byte) (val & 0x00ff);
            generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
        }
    }

    audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
            sampleRate, AudioFormat.CHANNEL_OUT_MONO,
            AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length,
            AudioTrack.MODE_STATIC);
    audioTrack.write(generatedSnd, 0, generatedSnd.length);
    audioTrack.play();

У кого-нибудь есть идеи? Спасибо!


person Romulus Urakagi Ts'ai    schedule 19.01.2016    source источник


Ответы (2)


Вы используете AudioTrack.MODE_STATIC, который предназначен для коротких звуков и требований с малой задержкой, в то время как вам следует использовать AudioTrack.MODE_STREAM. AudioTrack.MODE_STREAM предназначен для более длинных потоков, но я не знаю, какова длина ваших сэмплов. Итак, вы можете попробовать изменить AudioTrack:

audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
        sampleRate, AudioFormat.CHANNEL_OUT_MONO,
        AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length,
        AudioTrack.MODE_STREAM);

Также для AudioTrack требуется размер буфера в байтах, короткое значение необходимо умножить на два, чтобы рассчитать правильное количество требуемых байтов. Вы можете взломать его следующим образом:

audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
        sampleRate, AudioFormat.CHANNEL_OUT_MONO,
        AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length*2,
        AudioTrack.MODE_STREAM);
person jobbert    schedule 03.05.2016
comment
Я попробовал MODE_STREAM, но это то же самое. Мои образцы воспроизводятся только от 3 до 7 секунд. - person Romulus Urakagi Ts'ai; 04.05.2016
comment
Они играют в течение случайной продолжительности? Вы пробовали более короткие или другие аудиосэмплы? И вы тоже умножили количество байтов? - person jobbert; 04.05.2016
comment
Да, я пробовал другие образцы. Они не случайной продолжительности. На что умножить количество байт? - person Romulus Urakagi Ts'ai; 04.05.2016
comment
сгенерированныйSnd.length*2? - person jobbert; 04.05.2016
comment
Это не работает. Кроме того, этот код иногда работает, но не всегда. - person Romulus Urakagi Ts'ai; 09.05.2016
comment
Я играю одни и те же сэмплы несколько раз, иногда они проигрываются до конца, а иногда останавливаются до конца. Если это 5-секундный клип, он может останавливаться и иметь любую длину, например 0,5 секунды, 1 секунду, 4 секунды и т. д. - person Romulus Urakagi Ts'ai; 09.05.2016
comment
Можете ли вы расширить свой код, чтобы я мог полностью запустить часть, которая воспроизводит аудиосэмпл? И, может быть, получить образец аудиофайла, чтобы я мог попытаться исправить это для вас? - person jobbert; 09.05.2016
comment
Класс ToneSegment содержит всего два поля: длительность и высоту тона. Это длинный вызов стека, поэтому я не могу предоставить автономный исполняемый код, но, например, будет 26 ToneSegment, каждый по 128 мс, с шагом 1828, 1875, 1968, 1031, 1078, 1125, 1171... и так далее. . - person Romulus Urakagi Ts'ai; 10.05.2016

Вероятно, проблема связана со сборкой мусора. Я писал этот код в методе, возвращающемся немедленно, так как объект audioTrack потеряет ссылку на него. Если сборка мусора произойдет во время воспроизведения, audioTrack будет финализирован и воспроизведение тонов прекратится. Таким образом, эта проблема возникает время от времени, в зависимости от того, насколько активен GC при воспроизведении тонов.

Поэтому мне нужно сохранить ссылку на объект AudioTrack до окончания воспроизведения. Я думаю, что есть много способов сделать это, но, наконец, я использую самый простой способ:

class Player {
    private static AudioTrack sAudioTrack;
}

MediaPlayer также имеет эту ловушку, и именно так я обнаружил проблему, поскольку она будет записывать в журнал, что она завершена до выпуска.

person Romulus Urakagi Ts'ai    schedule 27.06.2016