cdrom: cd audio / xa mixing moved from SPU to CDROM

This commit is contained in:
Jakub Czekański 2020-01-26 19:26:49 +01:00
parent 6cca4451c3
commit 8a10036c48
6 changed files with 69 additions and 57 deletions

View file

@ -67,18 +67,13 @@ void CDROM::step() {
}
}
if (!this->mute) {
if (!mute) {
// Decode Red Book Audio (16bit Stereo 44100Hz)
bool channel = true;
for (size_t i = 0; i < rawSector.size(); i += 2) {
int16_t sample = rawSector[i] | (rawSector[i + 1] << 8);
for (size_t i = 0; i < rawSector.size(); i += 4) {
int16_t left = rawSector[i + 0] | (rawSector[i + 1] << 8);
int16_t right = rawSector[i + 2] | (rawSector[i + 3] << 8);
if (channel) {
audio.first.push_back(sample);
} else {
audio.second.push_back(sample);
}
channel = !channel;
audio.push_back(mixSample(std::make_pair(left, right)));
}
}
} else if (trackType == disc::TrackType::DATA && stat.read) {
@ -126,9 +121,11 @@ void CDROM::step() {
}
if (this->mode.xaEnabled && !this->mute) {
auto [left, right] = ADPCM::decodeXA(rawSector.data() + 24, codinginfo);
audio.first.insert(audio.first.end(), left.begin(), left.end());
audio.second.insert(audio.second.end(), right.begin(), right.end());
auto frame = ADPCM::decodeXA(rawSector.data() + 24, codinginfo);
for (auto sample : frame) {
audio.push_back(mixSample(sample));
}
}
if (submode.endOfFile) {
@ -374,5 +371,26 @@ void CDROM::write(uint32_t address, uint8_t data) {
fmt::print("CDROM{}.{}<-W UNIMPLEMENTED WRITE 0x{:02x}\n", address, static_cast<int>(status.index), data);
}
std::pair<int16_t, int16_t> CDROM::mixSample(std::pair<int16_t, int16_t> input) {
int16_t left = input.first;
int16_t right = input.second;
// TODO: Fixed-point + clipping
// TODO: Verify mixing with HW (capture channels)
// 0x00 - disabled
// 0x80 - 1x vol
// 0xff - 2x vol
float l_l = volumeLeftToLeft / (float)0x80;
float l_r = volumeLeftToRight / (float)0x80;
float r_l = volumeRightToLeft / (float)0x80;
float r_r = volumeRightToRight / (float)0x80;
int16_t mixedLeft = clamp<int32_t>((left * l_l) + (right * r_l), INT16_MIN, INT16_MAX);
int16_t mixedRight = clamp<int32_t>((left * l_r) + (right * r_r), INT16_MIN, INT16_MAX);
return std::make_pair(mixedLeft, mixedRight);
}
} // namespace cdrom
} // namespace device

View file

@ -114,6 +114,10 @@ class CDROM {
Mode mode;
Filter filter;
uint8_t volumeLeftToLeft = 0;
uint8_t volumeLeftToRight = 0;
uint8_t volumeRightToLeft = 0;
uint8_t volumeRightToRight = 0;
System* sys;
int readSector = 0;
@ -174,13 +178,10 @@ class CDROM {
}
std::string dumpFifo(const FIFO& f);
std::pair<int16_t, int16_t> mixSample(std::pair<int16_t, int16_t> sample);
public:
uint8_t volumeLeftToLeft = 0;
uint8_t volumeLeftToRight = 0;
uint8_t volumeRightToLeft = 0;
uint8_t volumeRightToRight = 0;
std::pair<std::deque<int16_t>, std::deque<int16_t>> audio;
std::deque<std::pair<int16_t, int16_t>> audio;
std::vector<uint8_t> rawSector;
std::vector<uint8_t> dataBuffer;

View file

@ -381,8 +381,7 @@ void CDROM::cmdGetId() {
void CDROM::cmdReadS() {
readSector = seekSector;
audio.first.clear();
audio.second.clear();
audio.clear();
stat.setMode(StatusCode::Mode::Reading);
postInterrupt(3);

View file

@ -87,8 +87,24 @@ void SPU::step(device::cdrom::CDROM* cdrom) {
}
}
sumLeft *= mainVolume.getLeft();
sumRight *= mainVolume.getRight();
// Mix with cd
Sample cdLeft = 0, cdRight = 0;
if (!cdrom->audio.empty()) {
std::tie(cdLeft, cdRight) = cdrom->audio.front();
// TODO: Refactor to use ring buffer
cdrom->audio.pop_front();
if (control.cdEnable) {
sumLeft += cdLeft * cdVolume.getLeft();
sumRight += cdRight * cdVolume.getRight();
if (control.cdReverb) {
sumReverbLeft += cdLeft * cdVolume.getLeft();
sumReverbRight += cdRight * cdVolume.getRight();
}
}
}
if (!forceReverbOff && control.masterReverb) {
static int16_t reverbLeft = 0, reverbRight = 0;
@ -100,37 +116,14 @@ void SPU::step(device::cdrom::CDROM* cdrom) {
sumRight += reverbRight;
}
sumLeft *= std::min<int16_t>(0x3fff, mainVolume.getLeft()) * 2;
sumRight *= std::min<int16_t>(0x3fff, mainVolume.getRight()) * 2;
if (!control.unmute) {
sumLeft = 0;
sumRight = 0;
}
// Mix with cd
int16_t cdLeft = 0, cdRight = 0;
if (!cdrom->audio.first.empty()) {
cdLeft = cdrom->audio.first.front();
cdRight = cdrom->audio.second.front();
// TODO: Refactor to use ring buffer
cdrom->audio.first.pop_front();
cdrom->audio.second.pop_front();
if (control.cdEnable) {
// 0x80 - full volume
// 0xff - 2x volume
int32_t l_l = 255 * cdrom->volumeLeftToLeft;
int32_t l_r = 255 * cdrom->volumeLeftToRight;
int32_t r_l = 255 * cdrom->volumeRightToLeft;
int32_t r_r = 255 * cdrom->volumeRightToRight;
sumLeft += (cdLeft * l_l) >> 15;
sumRight += (cdLeft * l_r) >> 15;
sumLeft += (cdLeft * r_l) >> 15;
sumRight += (cdLeft * r_r) >> 15;
}
}
audioBuffer[audioBufferPos] = sumLeft;
audioBuffer[audioBufferPos + 1] = sumRight;

View file

@ -148,12 +148,11 @@ std::vector<int16_t> decodePacket(uint8_t buffer[128], int32_t prevSample[2], bo
return decoded;
}
std::pair<std::vector<int16_t>, std::vector<int16_t>> decodeXA(uint8_t buffer[128 * 18], cd::Codinginfo codinginfo) {
std::vector<std::pair<int16_t, int16_t>> decodeXA(uint8_t buffer[128 * 18], cd::Codinginfo codinginfo) {
static int32_t prevSampleLeft[2] = {};
static int32_t prevSampleRight[2] = {};
std::vector<int16_t> left;
std::vector<int16_t> right;
std::vector<std::pair<int16_t, int16_t>> frame;
// Each sector contains of 18 128-byte portions
for (int packet = 0; packet < 18; packet++) {
@ -161,15 +160,17 @@ std::pair<std::vector<int16_t>, std::vector<int16_t>> decodeXA(uint8_t buffer[12
auto l = decodePacket<Channel::left>(buffer + packet * 128, prevSampleLeft, codinginfo.sampleRate);
auto r = decodePacket<Channel::right>(buffer + packet * 128, prevSampleRight, codinginfo.sampleRate);
left.insert(left.end(), l.begin(), l.end());
right.insert(right.end(), r.begin(), r.end());
for (int i = 0; i < l.size(); i++) {
frame.emplace_back(l[i], r[i]);
}
} else {
auto mono = decodePacket<Channel::mono>(buffer + packet * 128, prevSampleLeft, codinginfo.sampleRate);
left.insert(left.end(), mono.begin(), mono.end());
right.insert(right.end(), mono.begin(), mono.end());
for (auto sample : mono) {
frame.emplace_back(sample, sample);
}
}
}
return std::make_pair(left, right);
return frame;
}
} // namespace ADPCM

View file

@ -18,5 +18,5 @@ enum Flag {
// 0 - Nothing
};
std::vector<int16_t> decode(uint8_t buffer[16], int32_t prevSample[2]);
std::pair<std::vector<int16_t>, std::vector<int16_t>> decodeXA(uint8_t buffer[128 * 18], cd::Codinginfo codinginfo);
std::vector<std::pair<int16_t, int16_t>> decodeXA(uint8_t buffer[128 * 18], cd::Codinginfo codinginfo);
}; // namespace ADPCM