Merge pull request #233 from DrChat/audio_decoding

Cleanup Audio System Code
This commit is contained in:
Ben Vanik 2015-06-02 08:22:10 -07:00
commit 99718fd3ce
4 changed files with 106 additions and 60 deletions

View File

@ -13,6 +13,7 @@
#include "xenia/apu/audio_decoder.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/ring_buffer.h"
#include "xenia/cpu/processor.h"
#include "xenia/cpu/thread_state.h"
#include "xenia/emulator.h"
@ -360,8 +361,6 @@ void AudioSystem::ProcessXmaContext(XMAContext& context, XMAContextData& data) {
// 3 - 48 kHz ?
// SPUs also support stereo decoding. (data.is_stereo)
bool output_written_bytes = false;
while (data.output_buffer_valid) {
// Check the output buffer - we cannot decode anything else if it's
// unavailable.
@ -372,25 +371,9 @@ void AudioSystem::ProcessXmaContext(XMAContext& context, XMAContextData& data) {
uint32_t output_write_offset_bytes = data.output_buffer_write_offset * 256;
uint32_t output_read_offset_bytes = data.output_buffer_read_offset * 256;
uint32_t output_remaining_bytes = 0;
bool output_wraparound = false;
bool output_all = false;
if (output_write_offset_bytes < output_read_offset_bytes) {
// Case 1: write -> read
output_remaining_bytes =
output_read_offset_bytes - output_write_offset_bytes;
} else if (output_read_offset_bytes < output_write_offset_bytes) {
// Case 2: write -> end -> read
output_remaining_bytes = output_size_bytes - output_write_offset_bytes;
output_remaining_bytes += output_read_offset_bytes;
// Doesn't count if it's 0!
output_wraparound = true;
} else if (!output_written_bytes) {
output_remaining_bytes = output_size_bytes;
output_all = true;
}
RingBuffer out_buffer(out, output_size_bytes, output_write_offset_bytes);
size_t output_remaining_bytes
= out_buffer.DistanceToOffset(output_read_offset_bytes);
if (!output_remaining_bytes) {
// Can't write any more data. Break.
@ -404,47 +387,13 @@ void AudioSystem::ProcessXmaContext(XMAContext& context, XMAContextData& data) {
// Copies one frame at a time, so keep calling this until size == 0
int read_bytes = 0;
int decode_attempts_remaining = 3;
uint8_t tmp_buff[XMAContextData::kOutputMaxSizeBytes];
while (decode_attempts_remaining) {
// TODO: We need a ringbuffer util class!
if (output_all) {
read_bytes = context.decoder->DecodePacket(out,
output_write_offset_bytes,
output_size_bytes
- output_write_offset_bytes);
} else if (output_wraparound) {
// write -> end
int r1 = context.decoder->DecodePacket(out,
output_write_offset_bytes,
output_size_bytes
- output_write_offset_bytes);
if (r1 < 0) {
--decode_attempts_remaining;
continue;
}
// begin -> read
// FIXME: If it fails here this'll break stuff
int r2 = context.decoder->DecodePacket(out, 0,
output_read_offset_bytes);
if (r2 < 0) {
--decode_attempts_remaining;
continue;
}
read_bytes = r1 + r2;
} else {
// write -> read
read_bytes = context.decoder->DecodePacket(out,
output_write_offset_bytes,
output_read_offset_bytes
- output_write_offset_bytes);
}
if (read_bytes > 0) {
output_written_bytes = true;
}
read_bytes = context.decoder->DecodePacket(tmp_buff, 0,
output_remaining_bytes);
if (read_bytes >= 0) {
out_buffer.Write(tmp_buff, read_bytes);
// Ok.
break;
} else {

View File

@ -43,6 +43,9 @@ struct XMAContextData {
static const uint32_t kSamplesPerFrame = 512;
static const uint32_t kSamplesPerSubframe = 128;
static const uint32_t kOutputBytesPerBlock = 256;
static const uint32_t kOutputMaxSizeBytes = 31 * kOutputBytesPerBlock;
// DWORD 0
uint32_t input_buffer_0_packet_count : 12; // XMASetInputBuffer0, number of
// 2KB packets. Max 4095 packets.

View File

@ -0,0 +1,56 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/base/ring_buffer.h"
namespace xe {
RingBuffer::RingBuffer(uint8_t *raw_buffer, size_t size, size_t write_offset)
: raw_buffer_(raw_buffer),
size_(size),
write_offset_(write_offset) {}
int RingBuffer::Write(uint8_t *buffer, size_t num_bytes) {
size_t bytes_written = 0;
size_t input_offset = 0;
size_t bytes_to_write = 0;
// write offset -> end
bytes_to_write =
num_bytes < size_ - write_offset_ ? num_bytes : size_ - write_offset_;
std::memcpy(raw_buffer_ + write_offset_, buffer, bytes_to_write);
input_offset = bytes_to_write;
write_offset_ += bytes_to_write;
// Wraparound (begin -> num_bytes)
if (input_offset < num_bytes) {
bytes_to_write = num_bytes - input_offset;
std::memcpy(raw_buffer_, buffer + input_offset, bytes_to_write);
write_offset_ = bytes_to_write;
}
return 0;
}
size_t RingBuffer::DistanceToOffset(size_t offset) {
if (offset < size_ && offset >= write_offset_) {
// Doesn't wraparound.
return offset - write_offset_;
} else {
// Wraparound.
size_t dist = size_ - write_offset_;
dist += offset;
return dist;
}
}
} // namespace xe

View File

@ -0,0 +1,38 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_BASE_RING_BUFFER_H_
#define XENIA_BASE_RING_BUFFER_H_
#include <cstdint>
#include <string>
#include <vector>
namespace xe {
class RingBuffer {
public:
RingBuffer(uint8_t *raw_buffer, size_t size, size_t write_offset = 0);
int Write(uint8_t *buffer, size_t num_bytes);
size_t DistanceToOffset(size_t offset);
void set_write_offset(size_t write_offset) { write_offset_ = write_offset; }
size_t write_offset() { return write_offset_; }
private:
uint8_t *raw_buffer_;
size_t size_;
size_t write_offset_;
};
} // namespace xe
#endif // XENIA_BASE_RING_BUFFER_H_