1
0
Fork 0

Add partial DAE support for compressed Redbook-compliant tracks

This commit is contained in:
krcroft 2020-02-14 07:56:18 -08:00 committed by Patryk Obara
parent fdf103a111
commit c132263116
2 changed files with 79 additions and 16 deletions

View file

@ -40,6 +40,8 @@
#define BYTES_PER_RAW_REDBOOK_FRAME 2352
#define BYTES_PER_COOKED_REDBOOK_FRAME 2048
#define REDBOOK_FRAMES_PER_SECOND 75
#define REDBOOK_CHANNELS 2
#define REDBOOK_PCM_FRAMES_PER_SECOND 44100
#define MAX_REDBOOK_FRAMES 400000 // frames are Redbook's data unit
#define MAX_REDBOOK_SECTOR 399999 // a sector is the index to a frame
#define MAX_REDBOOK_TRACKS 99
@ -127,8 +129,10 @@ private:
TrackFile(Bit16u _chunkSize) : chunkSize(_chunkSize) {}
public:
virtual ~TrackFile() = default;
virtual bool read(Bit8u *buffer, int seek, int count) = 0;
virtual bool seek(Bit32u offset) = 0;
virtual bool read(uint8_t *buffer,
const uint32_t offset,
const uint32_t requested_bytes) = 0;
virtual bool seek(const uint32_t offset) = 0;
virtual uint64_t decode(Bit16s *buffer, uint32_t desired_track_frames) = 0;
virtual Bit16u getEndian() = 0;
virtual Bit32u getRate() = 0;
@ -146,8 +150,10 @@ private:
BinaryFile (const BinaryFile&) = delete; // prevent copying
BinaryFile& operator= (const BinaryFile&) = delete; // prevent assignment
bool read(Bit8u *buffer, int seek, int count);
bool seek(Bit32u offset);
bool read(uint8_t *buffer,
const uint32_t offset,
const uint32_t requested_bytes);
bool seek(const uint32_t offset);
uint64_t decode(Bit16s *buffer, Bit32u desired_track_frames);
Bit16u getEndian();
Bit32u getRate() { return 44100; }
@ -166,12 +172,10 @@ private:
AudioFile (const AudioFile&) = delete; // prevent copying
AudioFile& operator= (const AudioFile&) = delete; // prevent assignment
bool read(Bit8u *buffer, int seek, int count) {
(void)buffer; // unused but part of the API
(void)seek; // ...
(void)count; // ...
return false; }
bool seek(Bit32u offset);
bool read(uint8_t *buffer,
const uint32_t offset,
const uint32_t requested_bytes);
bool seek(const uint32_t offset);
uint64_t decode(Bit16s *buffer, Bit32u desired_track_frames);
Bit16u getEndian();
Bit32u getRate();
@ -179,6 +183,7 @@ private:
int getLength();
private:
Sound_Sample *sample;
uint32_t position;
};
public:

View file

@ -71,14 +71,16 @@ CDROM_Interface_Image::BinaryFile::~BinaryFile()
file = nullptr;
}
bool CDROM_Interface_Image::BinaryFile::read(Bit8u *buffer, int seek, int count)
bool CDROM_Interface_Image::BinaryFile::read(uint8_t *buffer,
const uint32_t offset,
const uint32_t requested_bytes)
{
// Guard: only proceed with a valid file
if (file == nullptr)
return false;
file->seekg(seek, ios::beg);
file->read((char*)buffer, count);
file->seekg(offset, ios::beg);
file->read((char*)buffer, requested_bytes);
return !file->fail();
}
@ -107,7 +109,7 @@ Bit16u CDROM_Interface_Image::BinaryFile::getEndian()
}
bool CDROM_Interface_Image::BinaryFile::seek(Bit32u offset)
bool CDROM_Interface_Image::BinaryFile::seek(const uint32_t offset)
{
// Guard: only proceed with a valid file
if (file == nullptr)
@ -129,7 +131,8 @@ uint64_t CDROM_Interface_Image::BinaryFile::decode(Bit16s *buffer, Bit32u desire
CDROM_Interface_Image::AudioFile::AudioFile(const char *filename, bool &error)
: TrackFile(4096),
sample(nullptr)
sample(nullptr),
position(0)
{
// Use the audio file's actual sample rate and number of channels as opposed to overriding
Sound_AudioInfo desired = {AUDIO_S16, 0, 0};
@ -159,7 +162,7 @@ CDROM_Interface_Image::AudioFile::~AudioFile()
sample = nullptr;
}
bool CDROM_Interface_Image::AudioFile::seek(Bit32u offset)
bool CDROM_Interface_Image::AudioFile::seek(const uint32_t offset)
{
#ifdef BENCHMARK
#include <ctime>
@ -172,6 +175,9 @@ bool CDROM_Interface_Image::AudioFile::seek(Bit32u offset)
#endif
// Convert the byte-offset to a time offset (milliseconds)
const bool result = Sound_Seek(sample, lround(offset / REDBOOK_PCM_BYTES_PER_MS));
#ifdef DEBUG
LOG_MSG("CDROM: seek to byte-offset %u", offset);
#endif
#ifdef BENCHMARK
const auto end = std::chrono::steady_clock::now();
@ -182,6 +188,58 @@ bool CDROM_Interface_Image::AudioFile::seek(Bit32u offset)
return result;
}
bool CDROM_Interface_Image::AudioFile::read(uint8_t *buffer,
const uint32_t offset,
const uint32_t requested_bytes)
{
// Check for logic bugs
assertm(buffer != nullptr, "buffer needs to be allocated but is the nullptr [Bug]");
assertm(sample != nullptr, "Audio sample needs to be valid, but is the nullptr [Bug]");
// Guard again valid but no-op case
if (requested_bytes == 0)
return true;
// We support DAE from 16-bit, stereo, 44 kHz tracks. If the track doesn't conform to
// this, then inform the user. Also, we allow up to 10 DAE-attempts before informing
// the user - because some CD Player software will query this interface before using
// CDROM-directed playback (not DAE), therefore we don't want to fail in those cases.
if (getRate() != REDBOOK_PCM_FRAMES_PER_SECOND || getChannels() != REDBOOK_CHANNELS) {
static uint8_t dae_attempts = 0;
if (dae_attempts++ > 10) {
E_Exit("\n"
"CDROM: Digital Audio Extration (DAE) was attempted with a %s %u kHz\n"
" track, but DAE is currently only compatible with stereo %u kHz\n"
" tracks.",
getChannels() == 2 ? "stereo" : "mono",
getRate(),
REDBOOK_PCM_FRAMES_PER_SECOND);
}
return false; // we always correctly return false to the application in this case.
}
// Seek, but only if we have to
if (position != (offset - requested_bytes))
if (!seek(offset))
return false;
position = offset;
uint32_t decoded_frames = 0;
const uint32_t requested_frames = requested_bytes / BYTES_PER_REDBOOK_PCM_FRAME;
while (decoded_frames < requested_frames) {
if (sample->flags & (SOUND_SAMPLEFLAG_ERROR | SOUND_SAMPLEFLAG_EOF))
break;
decoded_frames += Sound_Decode_Direct(sample,
buffer + decoded_frames * BYTES_PER_REDBOOK_PCM_FRAME,
requested_frames - decoded_frames);
}
if (decoded_frames < requested_frames)
memset(buffer + decoded_frames * BYTES_PER_REDBOOK_PCM_FRAME,
0,
(requested_frames - decoded_frames) * BYTES_PER_REDBOOK_PCM_FRAME);
return !(sample->flags & SOUND_SAMPLEFLAG_ERROR);
}
uint64_t CDROM_Interface_Image::AudioFile::decode(Bit16s *buffer, Bit32u desired_track_frames)
{
return Sound_Decode_Direct(sample, (void*)buffer, desired_track_frames);