Android oboe c ++ Некоторые звуки искажаются при воспроизведении

Я использую библиотеку гобоев Android для высококачественного звука в музыкальной игре.

В папке с ресурсами у меня есть 2 файла .raw (оба, 16-битные PCM wav с частотой 48000 Гц и около 60 КБ) std_kit_sn.raw std_kit_ht.raw

Они загружаются в память как звукозаписи и добавляются в микшер. kSampleRateHz - 48000:

stdSN= SoundRecording::loadFromAssets(mAssetManager, "std_kit_sn.raw");
stdHT= SoundRecording::loadFromAssets(mAssetManager, "std_kit_ht.raw");
mMixer.addTrack(stdSN);
mMixer.addTrack(stdFT);

// Create a builder
AudioStreamBuilder builder;
builder.setFormat(AudioFormat::I16);
builder.setChannelCount(1);
builder.setSampleRate(kSampleRateHz);
builder.setCallback(this);
builder.setPerformanceMode(PerformanceMode::LowLatency);
builder.setSharingMode(SharingMode::Exclusive);
LOGD("After creating a builder");

// Open stream
Result result = builder.openStream(&mAudioStream);
if (result != Result::OK){
    LOGE("Failed to open stream. Error: %s", convertToText(result));
}
LOGD("After openstream");

// Reduce stream latency by setting the buffer size to a multiple of the burst size
mAudioStream->setBufferSizeInFrames(mAudioStream->getFramesPerBurst() * 2);

// Start the stream
result = mAudioStream->requestStart();
if (result != Result::OK){
    LOGE("Failed to start stream. Error: %s", convertToText(result));
}
LOGD("After starting stream");

Они вызываются соответственно для игры со стандартным кодом (согласно руководствам Google) в необходимое время:

stdSN->setPlaying(true);
stdHT->setPlaying(true); //Nasty Sound

Звуковой обратный вызов является стандартным (согласно руководствам Google):

DataCallbackResult SoundFunctions::onAudioReady(AudioStream *mAudioStream, void *audioData, int32_t numFrames) {

    // Play the stream
    mMixer.renderAudio(static_cast<int16_t*>(audioData), numFrames);
    return DataCallbackResult::Continue;

}

Std_kit_sn.raw работает нормально. Но std_kit_ht.raw имеет неприятное искажение. Оба играют с малой задержкой. Почему один играет хорошо, а другой имеет ужасные искажения?


person TomV    schedule 07.12.2018    source источник
comment
Как это звучит, если вы играете только в std_kit_ht.raw? Это плохо только при воспроизведении одновременно с другим семплом? Если да, то, возможно, смеситель переполнен. Он должен масштабировать несколько дорожек, смешивать их в буфер с плавающей запятой или int32, а затем обрезать перед записью в массив int16_t audioData.   -  person philburk    schedule 07.12.2018
comment
Да, звучит плохо, когда проигрываешь std_kit_ht.raw отдельно и одновременно с другим сэмплом. Если я загружу его в звуковое программное обеспечение, например Audacity, он будет звучать нормально. Если я играю через чистый Android Soundpool, звучит нормально. В Android C ++ есть что-то, что заставляет std_kit_ht.raw играть с некоторыми неприятными искажениями.   -  person TomV    schedule 07.12.2018
comment
Между этими образцами должна быть какая-то разница. Вы загружаете необработанные файлы в Audacity, чтобы проверить их? Или играть в оригиналы. Амплитуда одного выше другого? Может быть проблема с порядком байтов. Они должны быть сохранены как LittleEndian для ARM или x86.   -  person philburk    schedule 10.12.2018
comment
Std_kit_ht.raw напоминает звук барабана высокого тома. Std_kit_sn.raw напоминает звук малого барабана. Оба образца обрабатывались одинаково. Образцы изначально были в формате wav, поэтому для преобразования в .raw я использовал тип файла экспорта Audacity (другой несжатый файл), заголовок (необработанный без заголовка), кодировку (подписанный 16-битный PCM). Нет возможности сохранить в LittleEndian для ARM или x86. Для тестирования в Audacity я импортирую необработанные данные с кодировкой 16-битного pcm со знаком и прямым порядком байтов.   -  person TomV    schedule 10.12.2018
comment
Мне удалось минимизировать неприятный шум искажения std_kit_ht.raw, уменьшив размер файла с 60 КБ до 20 КБ. Как ни странно, std_kit_sn.raw работает хорошо, как и ожидалось, поскольку размер файла составляет 65 КБ.   -  person TomV    schedule 12.12.2018
comment
Доказательства указывают на проблему в ваших исходных аудиофайлах, возможно, стоит опубликовать полный проект на github, включая эти файлы, чтобы другие могли легко воспроизвести проблему.   -  person donturner    schedule 17.12.2018
comment
Отличная идея. Вот проект: github.com/ThomasVeitch/DrumLoopsAndMetronomePro Когда вы загружаете и запускаете его в Android Studio, вы сможете проверить std_kit_ht.raw, выбрав Меню- ›Настройки-› Заполнить звук- ›Изменить на Высокий Том. Затем в Меню- ›Играть, если вы нажмете на анимированный зеленый / желтый кружок в правом нижнем углу, вы заметите, что этот звук неправильный.   -  person TomV    schedule 22.12.2018


Ответы (1)


Я загрузил ваш образец проекта и считаю, что искажение, которое вы слышите, вызвано ограничением / переходом во время микширования звуков.

Объект Mixer из выборки представляет собой суммирующий смеситель. Он просто складывает значения каждой дорожки вместе и выводит сумма.

Вам нужно добавить код, чтобы уменьшить громкость каждого трека, чтобы избежать превышения ограничений int16_t (хотя вы можете сообщить об ошибке в проекте гобоя, и я постараюсь добавить это в следующей версии). Если вы превысите этот предел, вы получите искажение, вызывающее искажение.

Кроме того, ваше приложение жестко запрограммировано для работы со скоростью 22050 кадров / сек. Это приведет к неоптимальной задержке на большинстве мобильных устройств, поскольку поток принудительно повышается до собственной частоты кадров аудиоустройства. Лучшим подходом было бы оставить неопределенную частоту дискретизации при открытии потока - это даст вам оптимальную частоту кадров для текущего аудиоустройства - а затем использовать ресамплер в исходных файлах для передачи звука с этой частотой кадров.

person donturner    schedule 27.12.2018
comment
Возможно я наивен, но как в API гобоя выставить громкость каждого трека. Не нашел. - person TomV; 30.12.2018
comment
Вы бы не использовали для этого Oboe API, вам просто нужно было бы обновить класс Mixer (который является частью примера кода, а не базовым API). Для этого вы просто отслеживаете громкость для каждой дорожки (используя значение с плавающей запятой между 0 и 1), и когда пришло время рендерить эту дорожку, вы умножаете каждое значение семпла на громкость дорожки. - person donturner; 30.12.2018
comment
void Mixer :: renderAudio (int16_t * audioData, int32_t numFrames) {void Mixer :: addTrack (RenderableAudio * renderer) {Я что-то упустил. Кажется, что переменные и методы в классе Mixer не содержат информации об объеме? - person TomV; 31.12.2018
comment
В гобое нет понятия объема. Если вы хотите иметь громкость, вам придется изменить (масштабировать) значение аудиоданных в обратном вызове на основе вашей переменной громкости. - person Steven Haggerty; 02.09.2019