Audio: Implement PCM8.
This commit is contained in:
parent
aa57048a0e
commit
b481a5b701
2 changed files with 47 additions and 14 deletions
|
@ -11,6 +11,8 @@
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
namespace Audio {
|
namespace Audio {
|
||||||
|
std::vector<u16> DecodeADPCM(u8* data, size_t sample_count, u16 adpcm_ps, s16 adpcm_yn[2], std::array<u8, 16> adpcm_coeff);
|
||||||
|
|
||||||
static const int BASE_SAMPLE_RATE = 22050;
|
static const int BASE_SAMPLE_RATE = 22050;
|
||||||
|
|
||||||
struct Buffer {
|
struct Buffer {
|
||||||
|
@ -63,8 +65,9 @@ namespace Audio {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALuint source, buffer;
|
ALuint silencebuffer;
|
||||||
ALCint dev_rate;
|
ALCint dev_rate;
|
||||||
|
std::array<u8, 10000> silence;
|
||||||
|
|
||||||
void Init() {
|
void Init() {
|
||||||
InitAL();
|
InitAL();
|
||||||
|
@ -92,21 +95,51 @@ namespace Audio {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnqueueBuffer(int chanid, u16 buffer_id,
|
void EnqueueBuffer(int chanid, u16 buffer_id,
|
||||||
void* data, int sample_count,
|
void* data, int sample_count,
|
||||||
bool has_adpcm, u16 adpcm_ps, s16 adpcm_yn[2],
|
bool has_adpcm, u16 adpcm_ps, s16 adpcm_yn[2],
|
||||||
bool is_looping) {
|
bool is_looping) {
|
||||||
|
|
||||||
if (chans[chanid].format != FORMAT_PCM16) {
|
if (is_looping) {
|
||||||
LOG_ERROR(Audio, "Unimplemented format");
|
LOG_WARNING(Audio, "Looped buffers are unimplemented");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: ADPCM processing should happen here
|
|
||||||
|
|
||||||
ALuint b;
|
ALuint b;
|
||||||
alGenBuffers(1, &b);
|
alGenBuffers(1, &b);
|
||||||
alBufferData(b, AL_FORMAT_MONO16, data, sample_count*2, BASE_SAMPLE_RATE);
|
|
||||||
if (alGetError() != AL_NO_ERROR) LOG_CRITICAL(Audio, "Failed to init buffer");
|
if (chans[chanid].format == FORMAT_PCM16) {
|
||||||
|
switch (chans[chanid].mono_or_stereo) {
|
||||||
|
case 2:
|
||||||
|
alBufferData(b, AL_FORMAT_STEREO16, data, sample_count * 4, BASE_SAMPLE_RATE);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
default:
|
||||||
|
alBufferData(b, AL_FORMAT_MONO16, data, sample_count * 2, BASE_SAMPLE_RATE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (alGetError() != AL_NO_ERROR) LOG_CRITICAL(Audio, "Failed to init buffer");
|
||||||
|
} else if (chans[chanid].format == FORMAT_PCM8) {
|
||||||
|
switch (chans[chanid].mono_or_stereo) {
|
||||||
|
case 2:
|
||||||
|
alBufferData(b, AL_FORMAT_STEREO8, data, sample_count * 2, BASE_SAMPLE_RATE);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
default:
|
||||||
|
alBufferData(b, AL_FORMAT_MONO8, data, sample_count * 1, BASE_SAMPLE_RATE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (alGetError() != AL_NO_ERROR) LOG_CRITICAL(Audio, "Failed to init buffer");
|
||||||
|
} /*else if (chans[chanid].format == FORMAT_ADPCM) {
|
||||||
|
if (chans[chanid].mono_or_stereo != 1) {
|
||||||
|
LOG_ERROR(Audio, "Being fed non-mono ADPCM");
|
||||||
|
}
|
||||||
|
std::vector<u16> decoded = DecodeADPCM(data, sample_count, adpcm_ps, adpcm_yn, chans[chanid].adpcm_coeff);
|
||||||
|
alBufferData(b, AL_FORMAT_MONO16, decoded.data(), decoded.size() * 2, BASE_SAMPLE_RATE);
|
||||||
|
if (alGetError() != AL_NO_ERROR) LOG_CRITICAL(Audio, "Failed to init buffer");
|
||||||
|
}*/ else {
|
||||||
|
LOG_ERROR(Audio, "Unrecognised audio format in buffer 0x%04x (size: %i samples)", buffer_id, sample_count);
|
||||||
|
alBufferData(b, AL_FORMAT_MONO8, silence.data(), silence.size(), BASE_SAMPLE_RATE);
|
||||||
|
if (alGetError() != AL_NO_ERROR) LOG_CRITICAL(Audio, "Failed to init buffer");
|
||||||
|
}
|
||||||
|
|
||||||
chans[chanid].queue.emplace( Buffer { buffer_id, b, is_looping });
|
chans[chanid].queue.emplace( Buffer { buffer_id, b, is_looping });
|
||||||
}
|
}
|
||||||
|
@ -119,7 +152,7 @@ namespace Audio {
|
||||||
alSourceQueueBuffers(c.source, 1, &c.queue.top().buffer);
|
alSourceQueueBuffers(c.source, 1, &c.queue.top().buffer);
|
||||||
if (alGetError() != AL_NO_ERROR) LOG_CRITICAL(Audio, "Failed to enqueue buffer");
|
if (alGetError() != AL_NO_ERROR) LOG_CRITICAL(Audio, "Failed to enqueue buffer");
|
||||||
c.playing.emplace(c.queue.top());
|
c.playing.emplace(c.queue.top());
|
||||||
LOG_INFO(Audio, "Enqueued buffer id %i", c.queue.top().id);
|
LOG_INFO(Audio, "Enqueued buffer id 0x%04x", c.queue.top().id);
|
||||||
c.queue.pop();
|
c.queue.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +174,7 @@ namespace Audio {
|
||||||
alSourceUnqueueBuffers(c.source, 1, &buf);
|
alSourceUnqueueBuffers(c.source, 1, &buf);
|
||||||
processed--;
|
processed--;
|
||||||
|
|
||||||
LOG_INFO(Audio, "Finished buffer id %i", c.playing.front().id);
|
LOG_INFO(Audio, "Finished buffer id 0x%04x", c.playing.front().id);
|
||||||
|
|
||||||
while (!c.playing.empty() && c.playing.front().buffer != buf) {
|
while (!c.playing.empty() && c.playing.front().buffer != buf) {
|
||||||
c.playing.pop();
|
c.playing.pop();
|
||||||
|
|
|
@ -201,7 +201,7 @@ static void AudioTick(u64, int cycles_late) {
|
||||||
|
|
||||||
if (TestAndUnsetBit(ctx.dirty, 16)) {
|
if (TestAndUnsetBit(ctx.dirty, 16)) {
|
||||||
// Is Active?
|
// Is Active?
|
||||||
LOG_WARNING(Service_DSP, "Unimplemented dirty bit 16");
|
//LOG_WARNING(Service_DSP, "Unimplemented dirty bit 16");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TestAndUnsetBit(ctx.dirty, 2)) {
|
if (TestAndUnsetBit(ctx.dirty, 2)) {
|
||||||
|
|
Loading…
Reference in a new issue