From fedf7357a5938e58999efc85b74a11668e4e0349 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sat, 30 May 2015 21:01:55 -0500 Subject: [PATCH 1/3] Remove variable bits per sample - it's always 16. --- src/xenia/apu/audio_decoder.cc | 36 ++++++++++++---------------------- src/xenia/apu/audio_decoder.h | 3 +-- src/xenia/apu/audio_system.cc | 2 +- 3 files changed, 14 insertions(+), 27 deletions(-) diff --git a/src/xenia/apu/audio_decoder.cc b/src/xenia/apu/audio_decoder.cc index 33d241a94..d91a4efec 100644 --- a/src/xenia/apu/audio_decoder.cc +++ b/src/xenia/apu/audio_decoder.cc @@ -46,20 +46,13 @@ AudioDecoder::~AudioDecoder() { } } -int AudioDecoder::Initialize(int bits) { +int AudioDecoder::Initialize() { static bool avcodec_initialized = false; if (!avcodec_initialized) { avcodec_register_all(); avcodec_initialized = true; } - if (bits <= 0 || bits > 32 || (bits % 8) != 0) { - assert_always(); - } - - // Output bits per sample - bits_ = bits; - // Allocate important stuff codec_ = avcodec_find_decoder(AV_CODEC_ID_WMAPRO); if (!codec_) { @@ -154,7 +147,6 @@ int AudioDecoder::DecodePacket(uint8_t *output, size_t output_offset, size_t output_size) { size_t to_copy = 0; size_t original_offset = output_offset; - uint32_t sample_size = bits_ / 8; // We're holding onto an already-decoded frame. Copy it out. if (current_frame_pos_ != frame_samples_size_) { @@ -204,27 +196,23 @@ int AudioDecoder::DecodePacket(uint8_t *output, size_t output_offset, float *sample_array = (float *)decoded_frame_->data[0]; // Loop through every sample, convert and drop it into the output array. - if (sample_size == 2) { - for (int i = 0; i < decoded_frame_->nb_samples; i++) { - // Raw sample should be within [-1, 1]. - // Clamp it, just in case. - float raw_sample = xe::saturate(sample_array[i]); + for (int i = 0; i < decoded_frame_->nb_samples; i++) { + // Raw sample should be within [-1, 1]. + // Clamp it, just in case. + float raw_sample = xe::saturate(sample_array[i]); - // Convert the sample and output it in big endian. - float scaled_sample = raw_sample * (1 << (bits_ - 1)); - int sample = static_cast(scaled_sample); - xe::store_and_swap(¤t_frame_[i * 2], - sample & 0xFFFF); - } - } else { - // 1 byte? 4 bytes? - assert_unhandled_case(sample_size); + // Convert the sample and output it in big endian. + float scaled_sample = raw_sample * (1 << 15); + int sample = static_cast(scaled_sample); + xe::store_and_swap(¤t_frame_[i * 2], + sample & 0xFFFF); } current_frame_pos_ = 0; // Total size of the frame's samples + // Magic number 2 is sizeof the output frame_samples_size_ = - context_->channels * decoded_frame_->nb_samples * sample_size; + context_->channels * decoded_frame_->nb_samples * 2; to_copy = std::min(output_size, (size_t)(frame_samples_size_)); std::memcpy(output + output_offset, current_frame_, to_copy); diff --git a/src/xenia/apu/audio_decoder.h b/src/xenia/apu/audio_decoder.h index b5396434f..bf08b2442 100644 --- a/src/xenia/apu/audio_decoder.h +++ b/src/xenia/apu/audio_decoder.h @@ -36,7 +36,7 @@ class AudioDecoder { AudioDecoder(); ~AudioDecoder(); - int Initialize(int bits); + int Initialize(); int PreparePacket(uint8_t* input, size_t seq_offset, size_t size, int sample_rate, int channels); @@ -51,7 +51,6 @@ class AudioDecoder { AVPacket* packet_; uint8_t bits_per_frame_; - uint32_t bits_; size_t current_frame_pos_; uint8_t* current_frame_; uint32_t frame_samples_size_; diff --git a/src/xenia/apu/audio_system.cc b/src/xenia/apu/audio_system.cc index 8eb30db7f..24eaaf437 100644 --- a/src/xenia/apu/audio_system.cc +++ b/src/xenia/apu/audio_system.cc @@ -102,7 +102,7 @@ X_STATUS AudioSystem::Setup() { // Needed because some data needs to be persisted across calls // TODO: Need to destroy this on class destruction context.decoder = new AudioDecoder(); - context.decoder->Initialize(16); + context.decoder->Initialize(); } registers_.next_context = 1; From dfd689e22b1394bf6b1871e1089967922da9e513 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sat, 30 May 2015 21:27:59 -0500 Subject: [PATCH 2/3] Whoops, we should be converting samples from more than one channel! --- src/xenia/apu/audio_decoder.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/xenia/apu/audio_decoder.cc b/src/xenia/apu/audio_decoder.cc index d91a4efec..e7ac90651 100644 --- a/src/xenia/apu/audio_decoder.cc +++ b/src/xenia/apu/audio_decoder.cc @@ -84,7 +84,7 @@ int AudioDecoder::Initialize() { // Current frame stuff whatever // samples per frame * 2 max channels * output bytes current_frame_ = - new uint8_t[XMAContextData::kSamplesPerFrame * 2 * (bits / 8)]; + new uint8_t[XMAContextData::kSamplesPerFrame * 2 * 2]; current_frame_pos_ = 0; frame_samples_size_ = 0; @@ -196,7 +196,8 @@ int AudioDecoder::DecodePacket(uint8_t *output, size_t output_offset, float *sample_array = (float *)decoded_frame_->data[0]; // Loop through every sample, convert and drop it into the output array. - for (int i = 0; i < decoded_frame_->nb_samples; i++) { + for (int i = 0; i < context_->channels * decoded_frame_->nb_samples; + i++) { // Raw sample should be within [-1, 1]. // Clamp it, just in case. float raw_sample = xe::saturate(sample_array[i]); From 128bf762053a5e4dcff68ce2aae035bdf5cd189e Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Sat, 30 May 2015 22:32:01 -0500 Subject: [PATCH 3/3] Fixed up multi-channel audio, works better now. --- src/xenia/apu/audio_decoder.cc | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/xenia/apu/audio_decoder.cc b/src/xenia/apu/audio_decoder.cc index e7ac90651..a8f6d94c4 100644 --- a/src/xenia/apu/audio_decoder.cc +++ b/src/xenia/apu/audio_decoder.cc @@ -192,26 +192,30 @@ int AudioDecoder::DecodePacket(uint8_t *output, size_t output_offset, return -4; } - // Output sample array - float *sample_array = (float *)decoded_frame_->data[0]; - // Loop through every sample, convert and drop it into the output array. - for (int i = 0; i < context_->channels * decoded_frame_->nb_samples; - i++) { - // Raw sample should be within [-1, 1]. - // Clamp it, just in case. - float raw_sample = xe::saturate(sample_array[i]); + // If more than one channel, the game wants the samples from each channel + // interleaved next to eachother + uint32_t o = 0; + for (int i = 0; i < decoded_frame_->nb_samples; i++) { + for (int j = 0; j < context_->channels; j++) { + // Select the appropriate array based on the current channel. + float *sample_array = (float *)decoded_frame_->data[j]; - // Convert the sample and output it in big endian. - float scaled_sample = raw_sample * (1 << 15); - int sample = static_cast(scaled_sample); - xe::store_and_swap(¤t_frame_[i * 2], - sample & 0xFFFF); + // Raw sample should be within [-1, 1]. + // Clamp it, just in case. + float raw_sample = xe::saturate(sample_array[i]); + + // Convert the sample and output it in big endian. + float scaled_sample = raw_sample * (1 << 15); + int sample = static_cast(scaled_sample); + xe::store_and_swap(¤t_frame_[o++ * 2], + sample & 0xFFFF); + } } current_frame_pos_ = 0; // Total size of the frame's samples - // Magic number 2 is sizeof the output + // Magic number 2 is sizeof an output sample frame_samples_size_ = context_->channels * decoded_frame_->nb_samples * 2; @@ -224,7 +228,7 @@ int AudioDecoder::DecodePacket(uint8_t *output, size_t output_offset, } } - // Return number of bytes written (typically 2048) + // Return number of bytes written return (int)(output_offset - original_offset); }