Merge pull request #350 from sonninnos/audio-update

Libretro: Update audio before video_cb
This commit is contained in:
ds22x 2024-05-14 23:47:33 +02:00 committed by GitHub
commit c921b37bd9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 786 additions and 588 deletions

View File

@ -397,6 +397,16 @@ int cdd_load(char *filename, char *header)
return -1; return -1;
} }
#ifdef __LIBRETRO__
if (config.cd_precache)
{
log_cb(RETRO_LOG_INFO, "Pre-caching \"%s\" ...\n", filename);
if (chd_precache(cdd.chd.file) != CHDERR_NONE)
return -1;
log_cb(RETRO_LOG_INFO, "Pre-cache done.\n");
}
#endif
/* retrieve CHD header */ /* retrieve CHD header */
head = chd_get_header(cdd.chd.file); head = chd_get_header(cdd.chd.file);

View File

@ -1,7 +1,6 @@
/* license:BSD-3-Clause /* license:BSD-3-Clause
* copyright-holders:Aaron Giles * copyright-holders:Aaron Giles
*/ ***************************************************************************
/***************************************************************************
bitstream.c bitstream.c
@ -9,8 +8,8 @@
***************************************************************************/ ***************************************************************************/
#include "bitstream.h"
#include <stdlib.h> #include <stdlib.h>
#include <libchdr/bitstream.h>
/*************************************************************************** /***************************************************************************
* INLINE FUNCTIONS * INLINE FUNCTIONS
@ -108,9 +107,10 @@ uint32_t bitstream_read_offset(struct bitstream* bitstream)
} }
//------------------------------------------------- /*-------------------------------------------------
// flush - flush to the nearest byte * flush - flush to the nearest byte
//------------------------------------------------- *-------------------------------------------------
*/
uint32_t bitstream_flush(struct bitstream* bitstream) uint32_t bitstream_flush(struct bitstream* bitstream)
{ {

View File

@ -1,6 +1,6 @@
/* license:BSD-3-Clause /* license:BSD-3-Clause
* copyright-holders:Aaron Giles * copyright-holders:Aaron Giles
*************************************************************************** ***************************************************************************
bitstream.h bitstream.h

View File

@ -1,6 +1,6 @@
// license:BSD-3-Clause /* license:BSD-3-Clause
// copyright-holders:Aaron Giles * copyright-holders:Aaron Giles
/*************************************************************************** ***************************************************************************
cdrom.c cdrom.c
@ -15,12 +15,12 @@
schemes will differ after track 1! schemes will differ after track 1!
***************************************************************************/ ***************************************************************************/
#ifdef WANT_RAW_DATA_SECTOR
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include "cdrom.h" #include <libchdr/cdrom.h>
#ifdef WANT_RAW_DATA_SECTOR
/*************************************************************************** /***************************************************************************
DEBUGGING DEBUGGING
@ -64,8 +64,6 @@ void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
#define LOG(x) #define LOG(x)
#endif #endif
/*************************************************************************** /***************************************************************************
CONSTANTS CONSTANTS
***************************************************************************/ ***************************************************************************/
@ -92,8 +90,6 @@ void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
/** @brief 43 bytes each. */ /** @brief 43 bytes each. */
#define ECC_Q_COMP 43 #define ECC_Q_COMP 43
/** /**
* @brief ------------------------------------------------- * @brief -------------------------------------------------
* ECC lookup tables pre-calculated tables for ECC data calcs * ECC lookup tables pre-calculated tables for ECC data calcs
@ -301,16 +297,16 @@ static const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP] =
{ 0x867,0x003,0x05b,0x0b3,0x10b,0x163,0x1bb,0x213,0x26b,0x2c3,0x31b,0x373,0x3cb,0x423,0x47b,0x4d3,0x52b,0x583,0x5db,0x633,0x68b,0x6e3,0x73b,0x793,0x7eb,0x843,0x89b,0x037,0x08f,0x0e7,0x13f,0x197,0x1ef,0x247,0x29f,0x2f7,0x34f,0x3a7,0x3ff,0x457,0x4af,0x507,0x55f } { 0x867,0x003,0x05b,0x0b3,0x10b,0x163,0x1bb,0x213,0x26b,0x2c3,0x31b,0x373,0x3cb,0x423,0x47b,0x4d3,0x52b,0x583,0x5db,0x633,0x68b,0x6e3,0x73b,0x793,0x7eb,0x843,0x89b,0x037,0x08f,0x0e7,0x13f,0x197,0x1ef,0x247,0x29f,0x2f7,0x34f,0x3a7,0x3ff,0x457,0x4af,0x507,0x55f }
}; };
/*-------------------------------------------------
* ecc_source_byte - return data from the sector
* at the given offset, masking anything
* particular to a mode
*-------------------------------------------------
*/
//------------------------------------------------- INLINE uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset)
// ecc_source_byte - return data from the sector
// at the given offset, masking anything
// particular to a mode
//-------------------------------------------------
static inline uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset)
{ {
// in mode 2 always treat these as 0 bytes /* in mode 2 always treat these as 0 bytes */
return (sector[MODE_OFFSET] == 2 && offset < 4) ? 0x00 : sector[SYNC_OFFSET + SYNC_NUM_BYTES + offset]; return (sector[MODE_OFFSET] == 2 && offset < 4) ? 0x00 : sector[SYNC_OFFSET + SYNC_NUM_BYTES + offset];
} }
@ -330,8 +326,9 @@ static inline uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset)
void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t *val1, uint8_t *val2) void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t *val1, uint8_t *val2)
{ {
int component;
*val1 = *val2 = 0; *val1 = *val2 = 0;
for (int component = 0; component < rowlen; component++) for (component = 0; component < rowlen; component++)
{ {
*val1 ^= ecc_source_byte(sector, row[component]); *val1 ^= ecc_source_byte(sector, row[component]);
*val2 ^= ecc_source_byte(sector, row[component]); *val2 ^= ecc_source_byte(sector, row[component]);
@ -355,8 +352,9 @@ void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, u
int ecc_verify(const uint8_t *sector) int ecc_verify(const uint8_t *sector)
{ {
// first verify P bytes int byte;
for (int byte = 0; byte < ECC_P_NUM_BYTES; byte++) /* first verify P bytes */
for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)
{ {
uint8_t val1, val2; uint8_t val1, val2;
ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &val1, &val2); ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &val1, &val2);
@ -364,8 +362,8 @@ int ecc_verify(const uint8_t *sector)
return 0; return 0;
} }
// then verify Q bytes /* then verify Q bytes */
for (int byte = 0; byte < ECC_Q_NUM_BYTES; byte++) for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
{ {
uint8_t val1, val2; uint8_t val1, val2;
ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &val1, &val2); ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &val1, &val2);
@ -388,12 +386,13 @@ int ecc_verify(const uint8_t *sector)
void ecc_generate(uint8_t *sector) void ecc_generate(uint8_t *sector)
{ {
// first verify P bytes int byte;
for (int byte = 0; byte < ECC_P_NUM_BYTES; byte++) /* first verify P bytes */
for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)
ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &sector[ECC_P_OFFSET + byte], &sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte]); ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &sector[ECC_P_OFFSET + byte], &sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte]);
// then verify Q bytes /* then verify Q bytes */
for (int byte = 0; byte < ECC_Q_NUM_BYTES; byte++) for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &sector[ECC_Q_OFFSET + byte], &sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte]); ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &sector[ECC_Q_OFFSET + byte], &sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte]);
} }

View File

@ -1,6 +1,6 @@
/* license:BSD-3-Clause */ /* license:BSD-3-Clause
/* copyright-holders:Aaron Giles */ * copyright-holders:Aaron Giles
/*************************************************************************** ***************************************************************************
cdrom.h cdrom.h
@ -14,15 +14,14 @@
#define __CDROM_H__ #define __CDROM_H__
#include <stdint.h> #include <stdint.h>
#include <libchdr/chdconfig.h>
/*************************************************************************** /***************************************************************************
CONSTANTS CONSTANTS
***************************************************************************/ ***************************************************************************/
/* tracks are padded to a multiple of this many frames */ /* tracks are padded to a multiple of this many frames */
#define CD_TRACK_PADDING (4) #define CD_TRACK_PADDING (4)
#define CD_MAX_TRACKS (99) /* AFAIK the theoretical limit */ #define CD_MAX_TRACKS (99) /* AFAIK the theoretical limit */
#define CD_MAX_SECTOR_DATA (2352) #define CD_MAX_SECTOR_DATA (2352)
#define CD_MAX_SUBCODE_DATA (96) #define CD_MAX_SUBCODE_DATA (96)
@ -53,8 +52,8 @@ enum
CD_SUB_NONE /* no subcode data stored */ CD_SUB_NONE /* no subcode data stored */
}; };
#define CD_FLAG_GDROM 0x00000001 // disc is a GD-ROM, all tracks should be stored with GD-ROM metadata #define CD_FLAG_GDROM 0x00000001 /* disc is a GD-ROM, all tracks should be stored with GD-ROM metadata */
#define CD_FLAG_GDROMLE 0x00000002 // legacy GD-ROM, with little-endian CDDA data #define CD_FLAG_GDROMLE 0x00000002 /* legacy GD-ROM, with little-endian CDDA data */
/*************************************************************************** /***************************************************************************
FUNCTION PROTOTYPES FUNCTION PROTOTYPES
@ -67,4 +66,45 @@ void ecc_generate(uint8_t *sector);
void ecc_clear(uint8_t *sector); void ecc_clear(uint8_t *sector);
#endif #endif
/***************************************************************************
INLINE FUNCTIONS
***************************************************************************/
INLINE uint32_t msf_to_lba(uint32_t msf)
{
return ( ((msf&0x00ff0000)>>16) * 60 * 75) + (((msf&0x0000ff00)>>8) * 75) + ((msf&0x000000ff)>>0);
}
INLINE uint32_t lba_to_msf(uint32_t lba)
{
uint8_t m, s, f;
m = lba / (60 * 75);
lba -= m * (60 * 75);
s = lba / 75;
f = lba % 75;
return ((m / 10) << 20) | ((m % 10) << 16) |
((s / 10) << 12) | ((s % 10) << 8) |
((f / 10) << 4) | ((f % 10) << 0);
}
/**
* segacd needs it like this.. investigate
* Angelo also says PCE tracks often start playing at the
* wrong address.. related?
**/
INLINE uint32_t lba_to_msf_alt(int lba)
{
uint32_t ret = 0;
ret |= ((lba / (60 * 75))&0xff)<<16;
ret |= (((lba / 75) % 60)&0xff)<<8;
ret |= ((lba % 75)&0xff)<<0;
return ret;
}
#endif /* __CDROM_H__ */ #endif /* __CDROM_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -46,8 +46,8 @@
extern "C" { extern "C" {
#endif #endif
#include "coretypes.h" #include <libchdr/coretypes.h>
#include <libchdr/chdconfig.h>
/*************************************************************************** /***************************************************************************
@ -194,12 +194,21 @@ extern "C" {
#define CHDFLAGS_IS_WRITEABLE 0x00000002 #define CHDFLAGS_IS_WRITEABLE 0x00000002
#define CHDFLAGS_UNDEFINED 0xfffffffc #define CHDFLAGS_UNDEFINED 0xfffffffc
#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
/* compression types */ /* compression types */
#define CHDCOMPRESSION_NONE 0 #define CHDCOMPRESSION_NONE 0
#define CHDCOMPRESSION_ZLIB 1 #define CHDCOMPRESSION_ZLIB 1
#define CHDCOMPRESSION_ZLIB_PLUS 2 #define CHDCOMPRESSION_ZLIB_PLUS 2
#define CHDCOMPRESSION_AV 3 #define CHDCOMPRESSION_AV 3
#define CHD_CODEC_NONE 0
#define CHD_CODEC_ZLIB CHD_MAKE_TAG('z','l','i','b')
/* general codecs with CD frontend */
#define CHD_CODEC_CD_ZLIB CHD_MAKE_TAG('c','d','z','l')
#define CHD_CODEC_CD_LZMA CHD_MAKE_TAG('c','d','l','z')
#define CHD_CODEC_CD_FLAC CHD_MAKE_TAG('c','d','f','l')
/* A/V codec configuration parameters */ /* A/V codec configuration parameters */
#define AV_CODEC_COMPRESS_CONFIG 1 #define AV_CODEC_COMPRESS_CONFIG 1
#define AV_CODEC_DECOMPRESS_CONFIG 2 #define AV_CODEC_DECOMPRESS_CONFIG 2
@ -212,33 +221,34 @@ extern "C" {
#define CHD_MDFLAGS_CHECKSUM 0x01 /* indicates data is checksummed */ #define CHD_MDFLAGS_CHECKSUM 0x01 /* indicates data is checksummed */
/* standard hard disk metadata */ /* standard hard disk metadata */
#define HARD_DISK_METADATA_TAG 0x47444444 /* 'GDDD' */ #define HARD_DISK_METADATA_TAG CHD_MAKE_TAG('G','D','D','D')
#define HARD_DISK_METADATA_FORMAT "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d" #define HARD_DISK_METADATA_FORMAT "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d"
/* hard disk identify information */ /* hard disk identify information */
#define HARD_DISK_IDENT_METADATA_TAG 0x49444e54 /* 'IDNT' */ #define HARD_DISK_IDENT_METADATA_TAG CHD_MAKE_TAG('I','D','N','T')
/* hard disk key information */ /* hard disk key information */
#define HARD_DISK_KEY_METADATA_TAG 0x4b455920 /* 'KEY ' */ #define HARD_DISK_KEY_METADATA_TAG CHD_MAKE_TAG('K','E','Y',' ')
/* pcmcia CIS information */ /* pcmcia CIS information */
#define PCMCIA_CIS_METADATA_TAG 0x43495320 /* 'CIS ' */ #define PCMCIA_CIS_METADATA_TAG CHD_MAKE_TAG('C','I','S',' ')
/* standard CD-ROM metadata */ /* standard CD-ROM metadata */
#define CDROM_OLD_METADATA_TAG 0x43484344 /* 'CHCD' */ #define CDROM_OLD_METADATA_TAG CHD_MAKE_TAG('C','H','C','D')
#define CDROM_TRACK_METADATA_TAG 0x43485452 /* 'CHTR' */ #define CDROM_TRACK_METADATA_TAG CHD_MAKE_TAG('C','H','T','R')
#define CDROM_TRACK_METADATA_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d" #define CDROM_TRACK_METADATA_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d"
#define CDROM_TRACK_METADATA2_TAG 0x43485432 /* 'CHT2' */ #define CDROM_TRACK_METADATA2_TAG CHD_MAKE_TAG('C','H','T','2')
#define CDROM_TRACK_METADATA2_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d" #define CDROM_TRACK_METADATA2_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"
#define GDROM_TRACK_METADATA_TAG 0x43484744 /* 'CHTD' */ #define GDROM_OLD_METADATA_TAG CHD_MAKE_TAG('C','H','G','T')
#define GDROM_TRACK_METADATA_TAG CHD_MAKE_TAG('C', 'H', 'G', 'D')
#define GDROM_TRACK_METADATA_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PAD:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d" #define GDROM_TRACK_METADATA_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PAD:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"
/* standard A/V metadata */ /* standard A/V metadata */
#define AV_METADATA_TAG 0x41564156 /* 'AVAV' */ #define AV_METADATA_TAG CHD_MAKE_TAG('A','V','A','V')
#define AV_METADATA_FORMAT "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d" #define AV_METADATA_FORMAT "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d"
/* A/V laserdisc frame metadata */ /* A/V laserdisc frame metadata */
#define AV_LD_METADATA_TAG 0x41564C44 /* 'AVLD' */ #define AV_LD_METADATA_TAG CHD_MAKE_TAG('A','V','L','D')
/* CHD open values */ /* CHD open values */
#define CHD_OPEN_READ 1 #define CHD_OPEN_READ 1
@ -337,6 +347,19 @@ struct _chd_verify_result
FUNCTION PROTOTYPES FUNCTION PROTOTYPES
***************************************************************************/ ***************************************************************************/
#ifdef _MSC_VER
#ifdef CHD_DLL
#ifdef CHD_DLL_EXPORTS
#define CHD_EXPORT __declspec(dllexport)
#else
#define CHD_EXPORT __declspec(dllimport)
#endif
#else
#define CHD_EXPORT
#endif
#else
#define CHD_EXPORT __attribute__ ((visibility("default")))
#endif
/* ----- CHD file management ----- */ /* ----- CHD file management ----- */
@ -347,25 +370,27 @@ struct _chd_verify_result
/* chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); */ /* chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); */
/* open an existing CHD file */ /* open an existing CHD file */
chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd); CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd);
chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd); CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd);
/* precache underlying file */
CHD_EXPORT chd_error chd_precache(chd_file *chd);
/* close a CHD file */ /* close a CHD file */
void chd_close(chd_file *chd); CHD_EXPORT void chd_close(chd_file *chd);
/* return the associated core_file */ /* return the associated core_file */
core_file *chd_core_file(chd_file *chd); CHD_EXPORT core_file *chd_core_file(chd_file *chd);
/* return an error string for the given CHD error */ /* return an error string for the given CHD error */
const char *chd_error_string(chd_error err); CHD_EXPORT const char *chd_error_string(chd_error err);
/* ----- CHD header management ----- */ /* ----- CHD header management ----- */
/* return a pointer to the extracted CHD header data */ /* return a pointer to the extracted CHD header data */
const chd_header *chd_get_header(chd_file *chd); CHD_EXPORT const chd_header *chd_get_header(chd_file *chd);
@ -373,14 +398,14 @@ const chd_header *chd_get_header(chd_file *chd);
/* ----- core data read/write ----- */ /* ----- core data read/write ----- */
/* read one hunk from the CHD file */ /* read one hunk from the CHD file */
chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer); CHD_EXPORT chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer);
/* ----- metadata management ----- */ /* ----- metadata management ----- */
/* get indexed metadata of a particular sort */ /* get indexed metadata of a particular sort */
chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags); CHD_EXPORT chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags);
@ -388,10 +413,10 @@ chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex,
/* ----- codec interfaces ----- */ /* ----- codec interfaces ----- */
/* set internal codec parameters */ /* set internal codec parameters */
chd_error chd_codec_config(chd_file *chd, int param, void *config); CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config);
/* return a string description of a codec */ /* return a string description of a codec */
const char *chd_get_codec_name(UINT32 codec); CHD_EXPORT const char *chd_get_codec_name(UINT32 codec);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,6 +1,6 @@
// license:BSD-3-Clause /* license:BSD-3-Clause
// copyright-holders:Aaron Giles * copyright-holders:Aaron Giles
/*************************************************************************** ***************************************************************************
flac.c flac.c
@ -10,28 +10,35 @@
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include "flac.h"
//************************************************************************** #include <libchdr/flac.h>
// FLAC DECODER #define DR_FLAC_IMPLEMENTATION
//************************************************************************** #include <dr_libs/dr_flac.h>
static FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); /***************************************************************************
FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes); * FLAC DECODER
static void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); ***************************************************************************
static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); */
static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void* client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]); static size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes);
static void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); static drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin);
static void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata);
static void flac_decoder_write_callback(void *userdata, void *buffer, size_t len);
/* getters (valid after reset) */
static uint32_t sample_rate(flac_decoder *decoder) { return decoder->sample_rate; }
static uint8_t channels(flac_decoder *decoder) { return decoder->channels; }
static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; }
/*------------------------------------------------- /*-------------------------------------------------
* flac_decoder - constructor * flac_decoder - constructor
*------------------------------------------------- *-------------------------------------------------
*/ */
void flac_decoder_init(flac_decoder *decoder) int flac_decoder_init(flac_decoder *decoder)
{ {
decoder->decoder = FLAC__stream_decoder_new(); decoder->decoder = NULL;
decoder->sample_rate = 0; decoder->sample_rate = 0;
decoder->channels = 0; decoder->channels = 0;
decoder->bits_per_sample = 0; decoder->bits_per_sample = 0;
@ -43,6 +50,7 @@ void flac_decoder_init(flac_decoder *decoder)
decoder->uncompressed_offset = 0; decoder->uncompressed_offset = 0;
decoder->uncompressed_length = 0; decoder->uncompressed_length = 0;
decoder->uncompressed_swap = 0; decoder->uncompressed_swap = 0;
return 0;
} }
/*------------------------------------------------- /*-------------------------------------------------
@ -53,10 +61,10 @@ void flac_decoder_init(flac_decoder *decoder)
void flac_decoder_free(flac_decoder* decoder) void flac_decoder_free(flac_decoder* decoder)
{ {
if ((decoder != NULL) && (decoder->decoder != NULL)) if ((decoder != NULL) && (decoder->decoder != NULL))
FLAC__stream_decoder_delete(decoder->decoder); drflac_close(decoder->decoder);
decoder->decoder = NULL;
} }
/*------------------------------------------------- /*-------------------------------------------------
* reset - reset state with the original * reset - reset state with the original
* parameters * parameters
@ -66,21 +74,13 @@ void flac_decoder_free(flac_decoder* decoder)
static int flac_decoder_internal_reset(flac_decoder* decoder) static int flac_decoder_internal_reset(flac_decoder* decoder)
{ {
decoder->compressed_offset = 0; decoder->compressed_offset = 0;
if (FLAC__stream_decoder_init_stream(decoder->decoder, flac_decoder_free(decoder);
&flac_decoder_read_callback_static, decoder->decoder = drflac_open_with_metadata(
NULL, flac_decoder_read_callback, flac_decoder_seek_callback,
&flac_decoder_tell_callback_static, flac_decoder_metadata_callback, decoder, NULL);
NULL, return (decoder->decoder != NULL);
NULL,
&flac_decoder_write_callback_static,
&flac_decoder_metadata_callback_static,
&flac_decoder_error_callback_static, decoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
return 0;
return FLAC__stream_decoder_process_until_end_of_metadata(decoder->decoder);
} }
/*------------------------------------------------- /*-------------------------------------------------
* reset - reset state with new memory parameters * reset - reset state with new memory parameters
* and a custom-generated header * and a custom-generated header
@ -94,43 +94,46 @@ int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_
{ {
0x66, 0x4C, 0x61, 0x43, /* +00: 'fLaC' stream header */ 0x66, 0x4C, 0x61, 0x43, /* +00: 'fLaC' stream header */
0x80, /* +04: metadata block type 0 (STREAMINFO), */ 0x80, /* +04: metadata block type 0 (STREAMINFO), */
/* flagged as last block */ /* flagged as last block */
0x00, 0x00, 0x22, /* +05: metadata block length = 0x22 */ 0x00, 0x00, 0x22, /* +05: metadata block length = 0x22 */
0x00, 0x00, /* +08: minimum block size */ 0x00, 0x00, /* +08: minimum block size */
0x00, 0x00, /* +0A: maximum block size */ 0x00, 0x00, /* +0A: maximum block size */
0x00, 0x00, 0x00, /* +0C: minimum frame size (0 == unknown) */ 0x00, 0x00, 0x00, /* +0C: minimum frame size (0 == unknown) */
0x00, 0x00, 0x00, /* +0F: maximum frame size (0 == unknown) */ 0x00, 0x00, 0x00, /* +0F: maximum frame size (0 == unknown) */
0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, /* +12: sample rate (0x0ac44 == 44100), */ 0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, /* +12: sample rate (0x0ac44 == 44100), */
/* numchannels (2), sample bits (16), */ /* numchannels (2), sample bits (16), */
/* samples in stream (0 == unknown) */ /* samples in stream (0 == unknown) */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* +1A: MD5 signature (0 == none) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* +1A: MD5 signature (0 == none) */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* +2A: start of stream data */
/* +2A: start of stream data */
}; };
memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template)); memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template));
decoder->custom_header[0x08] = decoder->custom_header[0x0a] = block_size >> 8; decoder->custom_header[0x08] = decoder->custom_header[0x0a] = (block_size*num_channels) >> 8;
decoder->custom_header[0x09] = decoder->custom_header[0x0b] = block_size & 0xff; decoder->custom_header[0x09] = decoder->custom_header[0x0b] = (block_size*num_channels) & 0xff;
decoder->custom_header[0x12] = sample_rate >> 12; decoder->custom_header[0x12] = sample_rate >> 12;
decoder->custom_header[0x13] = sample_rate >> 4; decoder->custom_header[0x13] = sample_rate >> 4;
decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1); decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1);
/* configure the header ahead of the provided buffer */ /* configure the header ahead of the provided buffer */
decoder->compressed_start = (const FLAC__byte *)(decoder->custom_header); decoder->compressed_start = (const uint8_t *)(decoder->custom_header);
decoder->compressed_length = sizeof(decoder->custom_header); decoder->compressed_length = sizeof(decoder->custom_header);
decoder->compressed2_start = (const FLAC__byte *)(buffer); decoder->compressed2_start = (const uint8_t *)(buffer);
decoder->compressed2_length = length; decoder->compressed2_length = length;
return flac_decoder_internal_reset(decoder); return flac_decoder_internal_reset(decoder);
} }
/*------------------------------------------------- /*-------------------------------------------------
* decode_interleaved - decode to an interleaved * decode_interleaved - decode to an interleaved
* sound stream * sound stream
*------------------------------------------------- *-------------------------------------------------
*/ */
#define BUFFER 2352 /* bytes per CD audio sector */
int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian) int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian)
{ {
int16_t buffer[BUFFER];
uint32_t buf_samples;
/* configure the uncompressed buffer */ /* configure the uncompressed buffer */
memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start)); memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start));
decoder->uncompressed_start[0] = samples; decoder->uncompressed_start[0] = samples;
@ -138,45 +141,18 @@ int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uin
decoder->uncompressed_length = num_samples; decoder->uncompressed_length = num_samples;
decoder->uncompressed_swap = swap_endian; decoder->uncompressed_swap = swap_endian;
buf_samples = BUFFER / channels(decoder);
/* loop until we get everything we want */ /* loop until we get everything we want */
while (decoder->uncompressed_offset < decoder->uncompressed_length) while (decoder->uncompressed_offset < decoder->uncompressed_length) {
if (!FLAC__stream_decoder_process_single(decoder->decoder)) uint32_t frames = (num_samples < buf_samples ? num_samples : buf_samples);
if (!drflac_read_pcm_frames_s16(decoder->decoder, frames, buffer))
return 0; return 0;
flac_decoder_write_callback(decoder, buffer, frames*sizeof(*buffer)*channels(decoder));
num_samples -= frames;
}
return 1; return 1;
} }
#if 0
/*
*-------------------------------------------------
* decode - decode to an multiple independent
* data streams
*-------------------------------------------------
*/
bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_endian)
{
/* make sure we don't have too many channels */
int chans = channels();
if (chans > ARRAY_LENGTH(m_uncompressed_start))
return false;
/* configure the uncompressed buffer */
memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start));
for (int curchan = 0; curchan < chans; curchan++)
m_uncompressed_start[curchan] = samples[curchan];
m_uncompressed_offset = 0;
m_uncompressed_length = num_samples;
m_uncompressed_swap = swap_endian;
/* loop until we get everything we want */
while (m_uncompressed_offset < m_uncompressed_length)
if (!FLAC__stream_decoder_process_single(m_decoder))
return false;
return true;
}
#endif
/*------------------------------------------------- /*-------------------------------------------------
* finish - finish up the decode * finish - finish up the decode
*------------------------------------------------- *-------------------------------------------------
@ -185,19 +161,24 @@ bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_end
uint32_t flac_decoder_finish(flac_decoder* decoder) uint32_t flac_decoder_finish(flac_decoder* decoder)
{ {
/* get the final decoding position and move forward */ /* get the final decoding position and move forward */
FLAC__uint64 position = 0; drflac *flac = decoder->decoder;
FLAC__stream_decoder_get_decode_position(decoder->decoder, &position); uint64_t position = decoder->compressed_offset;
FLAC__stream_decoder_finish(decoder->decoder);
/* ugh... there's no function to obtain bytes used in drflac :-/ */
position -= DRFLAC_CACHE_L2_LINES_REMAINING(&flac->bs) * sizeof(drflac_cache_t);
position -= DRFLAC_CACHE_L1_BITS_REMAINING(&flac->bs) / 8;
position -= flac->bs.unalignedByteCount;
/* adjust position if we provided the header */ /* adjust position if we provided the header */
if (position == 0) if (position == 0)
return 0; return 0;
if (decoder->compressed_start == (const FLAC__byte *)(decoder->custom_header)) if (decoder->compressed_start == (const uint8_t *)(decoder->custom_header))
position -= decoder->compressed_length; position -= decoder->compressed_length;
flac_decoder_free(decoder);
return position; return position;
} }
/*------------------------------------------------- /*-------------------------------------------------
* read_callback - handle reads from the input * read_callback - handle reads from the input
* stream * stream
@ -206,128 +187,119 @@ uint32_t flac_decoder_finish(flac_decoder* decoder)
#define MIN(x, y) ((x) < (y) ? (x) : (y)) #define MIN(x, y) ((x) < (y) ? (x) : (y))
FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) static size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes)
{ {
return flac_decoder_read_callback(client_data, buffer, bytes); flac_decoder* decoder = (flac_decoder*)userdata;
} uint8_t *dst = buffer;
FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes)
{
flac_decoder* decoder = (flac_decoder*)client_data;
uint32_t expected = *bytes;
/* copy from primary buffer first */ /* copy from primary buffer first */
uint32_t outputpos = 0; uint32_t outputpos = 0;
if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length) if (outputpos < bytes && decoder->compressed_offset < decoder->compressed_length)
{ {
uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed_length - decoder->compressed_offset); uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed_length - decoder->compressed_offset);
memcpy(&buffer[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy); memcpy(&dst[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy);
outputpos += bytes_to_copy; outputpos += bytes_to_copy;
decoder->compressed_offset += bytes_to_copy; decoder->compressed_offset += bytes_to_copy;
} }
/* once we're out of that, copy from the secondary buffer */ /* once we're out of that, copy from the secondary buffer */
if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length) if (outputpos < bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length)
{ {
uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length)); uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length));
memcpy(&buffer[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy); memcpy(&dst[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy);
outputpos += bytes_to_copy; outputpos += bytes_to_copy;
decoder->compressed_offset += bytes_to_copy; decoder->compressed_offset += bytes_to_copy;
} }
*bytes = outputpos;
/* return based on whether we ran out of data */ return outputpos;
return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
} }
/*------------------------------------------------- /*-------------------------------------------------
* metadata_callback - handle STREAMINFO metadata * metadata_callback - handle STREAMINFO metadata
*------------------------------------------------- *-------------------------------------------------
*/ */
void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) static void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata)
{ {
flac_decoder *fldecoder; flac_decoder *decoder = userdata;
/* ignore all but STREAMINFO metadata */ /* ignore all but STREAMINFO metadata */
if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO) if (metadata->type != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO)
return; return;
/* parse out the data we care about */ /* parse out the data we care about */
fldecoder = (flac_decoder *)(client_data); decoder->sample_rate = metadata->data.streaminfo.sampleRate;
fldecoder->sample_rate = metadata->data.stream_info.sample_rate; decoder->bits_per_sample = metadata->data.streaminfo.bitsPerSample;
fldecoder->bits_per_sample = metadata->data.stream_info.bits_per_sample; decoder->channels = metadata->data.streaminfo.channels;
fldecoder->channels = metadata->data.stream_info.channels;
} }
/*-------------------------------------------------
* tell_callback - handle requests to find out
* where in the input stream we are
*-------------------------------------------------
*/
FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
{
*absolute_byte_offset = ((flac_decoder *)client_data)->compressed_offset;
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
}
/*------------------------------------------------- /*-------------------------------------------------
* write_callback - handle writes to the output * write_callback - handle writes to the output
* stream * stream
*------------------------------------------------- *-------------------------------------------------
*/ */
FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) static void flac_decoder_write_callback(void *userdata, void *buffer, size_t bytes)
{
return flac_decoder_write_callback(client_data, frame, buffer);
}
FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void *client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
{ {
int sampnum, chan; int sampnum, chan;
int shift, blocksize; int shift, blocksize;
flac_decoder * decoder = (flac_decoder *)client_data; flac_decoder * decoder = (flac_decoder *)userdata;
int16_t *sampbuf = (int16_t *)buffer;
assert(frame->header.channels == decoder->channels); int sampch = channels(decoder);
uint32_t offset = decoder->uncompressed_offset;
uint16_t usample;
/* interleaved case */ /* interleaved case */
shift = decoder->uncompressed_swap ? 8 : 0; shift = decoder->uncompressed_swap ? 8 : 0;
blocksize = frame->header.blocksize; blocksize = bytes / (sampch * sizeof(sampbuf[0]));
if (decoder->uncompressed_start[1] == NULL) if (decoder->uncompressed_start[1] == NULL)
{ {
int16_t *dest = decoder->uncompressed_start[0] + decoder->uncompressed_offset * frame->header.channels; int16_t *dest = decoder->uncompressed_start[0] + offset * sampch;
for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++) for (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++)
for (chan = 0; chan < frame->header.channels; chan++) for (chan = 0; chan < sampch; chan++) {
*dest++ = (int16_t)((((uint16_t)buffer[chan][sampnum]) << shift) | (((uint16_t)buffer[chan][sampnum]) >> shift)); usample = (uint16_t)*sampbuf++;
*dest++ = (int16_t)((usample << shift) | (usample >> shift));
}
} }
/* non-interleaved case */ /* non-interleaved case */
else else
{ {
for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++) for (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++)
for (chan = 0; chan < frame->header.channels; chan++) for (chan = 0; chan < sampch; chan++) {
usample = (uint16_t)*sampbuf++;
if (decoder->uncompressed_start[chan] != NULL) if (decoder->uncompressed_start[chan] != NULL)
decoder->uncompressed_start[chan][decoder->uncompressed_offset] = (int16_t) ( (((uint16_t)(buffer[chan][sampnum])) << shift) | ( ((uint16_t)(buffer[chan][sampnum])) >> shift) ); decoder->uncompressed_start[chan][offset] = (int16_t) ((usample << shift) | (usample >> shift));
}
} }
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; decoder->uncompressed_offset = offset;
} }
/**
* @fn void flac_decoder::error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) /*-------------------------------------------------
* * seek_callback - handle seeks on the output
* @brief ------------------------------------------------- * stream
* error_callback - handle errors (ignore them) *-------------------------------------------------
* -------------------------------------------------.
*
* @param decoder The decoder.
* @param status The status.
* @param [in,out] client_data If non-null, information describing the client.
*/ */
void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) static drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin)
{ {
flac_decoder * decoder = (flac_decoder *)userdata;
uint32_t length = decoder->compressed_length + decoder->compressed2_length;
if (origin == drflac_seek_origin_start) {
uint32_t pos = offset;
if (pos <= length) {
decoder->compressed_offset = pos;
return 1;
}
} else if (origin == drflac_seek_origin_current) {
uint32_t pos = decoder->compressed_offset + offset;
if (pos <= length) {
decoder->compressed_offset = pos;
return 1;
}
}
return 0;
} }

View File

@ -1,6 +1,6 @@
// license:BSD-3-Clause /* license:BSD-3-Clause
// copyright-holders:Aaron Giles * copyright-holders:Aaron Giles
/*************************************************************************** ***************************************************************************
flac.h flac.h
@ -14,38 +14,37 @@
#define __FLAC_H__ #define __FLAC_H__
#include <stdint.h> #include <stdint.h>
#include "FLAC/ordinals.h"
#include "FLAC/stream_decoder.h"
//************************************************************************** /***************************************************************************
// TYPE DEFINITIONS * TYPE DEFINITIONS
//************************************************************************** ***************************************************************************
*/
typedef struct _flac_decoder flac_decoder; typedef struct _flac_decoder flac_decoder;
struct _flac_decoder { struct _flac_decoder {
// output state /* output state */
FLAC__StreamDecoder* decoder; // actual encoder void * decoder; /* actual encoder */
uint32_t sample_rate; // decoded sample rate uint32_t sample_rate; /* decoded sample rate */
uint8_t channels; // decoded number of channels uint8_t channels; /* decoded number of channels */
uint8_t bits_per_sample; // decoded bits per sample uint8_t bits_per_sample; /* decoded bits per sample */
uint32_t compressed_offset; // current offset in compressed data uint32_t compressed_offset; /* current offset in compressed data */
const FLAC__byte * compressed_start; // start of compressed data const uint8_t * compressed_start; /* start of compressed data */
uint32_t compressed_length; // length of compressed data uint32_t compressed_length; /* length of compressed data */
const FLAC__byte * compressed2_start; // start of compressed data const uint8_t * compressed2_start; /* start of compressed data */
uint32_t compressed2_length; // length of compressed data uint32_t compressed2_length; /* length of compressed data */
int16_t * uncompressed_start[8]; // pointer to start of uncompressed data (up to 8 streams) int16_t * uncompressed_start[8]; /* pointer to start of uncompressed data (up to 8 streams) */
uint32_t uncompressed_offset; // current position in uncompressed data uint32_t uncompressed_offset; /* current position in uncompressed data */
uint32_t uncompressed_length; // length of uncompressed data uint32_t uncompressed_length; /* length of uncompressed data */
int uncompressed_swap; // swap uncompressed sample data int uncompressed_swap; /* swap uncompressed sample data */
uint8_t custom_header[0x2a]; // custom header uint8_t custom_header[0x2a]; /* custom header */
}; };
// ======================> flac_decoder /* ======================> flac_decoder */
void flac_decoder_init(flac_decoder* decoder); int flac_decoder_init(flac_decoder* decoder);
void flac_decoder_free(flac_decoder* decoder); void flac_decoder_free(flac_decoder* decoder);
int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length); int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length);
int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian); int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian);
uint32_t flac_decoder_finish(flac_decoder* decoder); uint32_t flac_decoder_finish(flac_decoder* decoder);
#endif // __FLAC_H__ #endif /* __FLAC_H__ */

View File

@ -1,6 +1,6 @@
/* license:BSD-3-Clause /* license:BSD-3-Clause
* copyright-holders:Aaron Giles * copyright-holders:Aaron Giles
*************************************************************************** ****************************************************************************
huffman.c huffman.c
@ -101,7 +101,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "huffman.h" #include <libchdr/huffman.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y)) #define MAX(x,y) ((x) > (y) ? (x) : (y))
@ -112,10 +112,9 @@
#define MAKE_LOOKUP(code,bits) (((code) << 5) | ((bits) & 0x1f)) #define MAKE_LOOKUP(code,bits) (((code) << 5) | ((bits) & 0x1f))
/*************************************************************************** /***************************************************************************
* IMPLEMENTATION * IMPLEMENTATION
* ************************************************************************** ***************************************************************************
*/ */
/*------------------------------------------------- /*-------------------------------------------------
@ -126,7 +125,8 @@
struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits) struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits)
{ {
struct huffman_decoder* decoder; struct huffman_decoder* decoder = NULL;
/* limit to 24 bits */ /* limit to 24 bits */
if (maxbits > 24) if (maxbits > 24)
return NULL; return NULL;
@ -181,10 +181,10 @@ uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* b
enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf) enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf)
{ {
enum huffman_error error; int numbits, curnode;
enum huffman_error error;
/* bits per entry depends on the maxbits */ /* bits per entry depends on the maxbits */
int numbits;
int curnode;
if (decoder->maxbits >= 16) if (decoder->maxbits >= 16)
numbits = 5; numbits = 5;
else if (decoder->maxbits >= 8) else if (decoder->maxbits >= 8)
@ -243,19 +243,18 @@ enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, stru
enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf) enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf)
{ {
int start;
int last = 0; int last = 0;
int count = 0;
int index;
int curcode; int curcode;
uint32_t temp;
enum huffman_error error;
uint8_t rlefullbits = 0; uint8_t rlefullbits = 0;
int index, count = 0; uint32_t temp;
int start; enum huffman_error error;
/* start by parsing the lengths for the small tree */ /* start by parsing the lengths for the small tree */
struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6); struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6);
smallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3); smallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3);
start = bitstream_read(bitbuf, 3) + 1; start = bitstream_read(bitbuf, 3) + 1;
for (index = 1; index < 24; index++) for (index = 1; index < 24; index++)
{ {
if (index < start || count == 7) if (index < start || count == 7)
@ -310,7 +309,6 @@ enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder,
return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE; return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
} }
/*------------------------------------------------- /*-------------------------------------------------
* compute_tree_from_histo - common backend for * compute_tree_from_histo - common backend for
* computing a tree based on the data histogram * computing a tree based on the data histogram
@ -319,15 +317,16 @@ enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder,
enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder) enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder)
{ {
/* compute the number of data items in the histogram */
int i; int i;
uint32_t upperweight; uint32_t lowerweight;
uint32_t lowerweight = 0; uint32_t upperweight;
/* compute the number of data items in the histogram */
uint32_t sdatacount = 0; uint32_t sdatacount = 0;
for (i = 0; i < decoder->numcodes; i++) for (i = 0; i < decoder->numcodes; i++)
sdatacount += decoder->datahisto[i]; sdatacount += decoder->datahisto[i];
/* binary search to achieve the optimum encoding */ /* binary search to achieve the optimum encoding */
lowerweight = 0;
upperweight = sdatacount * 2; upperweight = sdatacount * 2;
while (1) while (1)
{ {
@ -352,8 +351,6 @@ enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decod
return huffman_assign_canonical_codes(decoder); return huffman_assign_canonical_codes(decoder);
} }
/*************************************************************************** /***************************************************************************
* INTERNAL FUNCTIONS * INTERNAL FUNCTIONS
*************************************************************************** ***************************************************************************
@ -376,7 +373,6 @@ static int huffman_tree_node_compare(const void *item1, const void *item2)
return (int)node1->bits - (int)node2->bits; return (int)node1->bits - (int)node2->bits;
} }
/*------------------------------------------------- /*-------------------------------------------------
* build_tree - build a huffman tree based on the * build_tree - build a huffman tree based on the
* data distribution * data distribution
@ -385,11 +381,12 @@ static int huffman_tree_node_compare(const void *item1, const void *item2)
int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight) int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight)
{ {
int nextalloc; int curcode;
int nextalloc;
int listitems = 0;
int maxbits = 0; int maxbits = 0;
/* make a list of all non-zero nodes */ /* make a list of all non-zero nodes */
struct node_t** list = (struct node_t**)malloc(sizeof(struct node_t*) * decoder->numcodes * 2); struct node_t** list = (struct node_t**)malloc(sizeof(struct node_t*) * decoder->numcodes * 2);
int curcode, listitems = 0;
memset(decoder->huffnode, 0, decoder->numcodes * sizeof(decoder->huffnode[0])); memset(decoder->huffnode, 0, decoder->numcodes * sizeof(decoder->huffnode[0]));
for (curcode = 0; curcode < decoder->numcodes; curcode++) for (curcode = 0; curcode < decoder->numcodes; curcode++)
if (decoder->datahisto[curcode] != 0) if (decoder->datahisto[curcode] != 0)
@ -403,24 +400,27 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint
if (decoder->huffnode[curcode].weight == 0) if (decoder->huffnode[curcode].weight == 0)
decoder->huffnode[curcode].weight = 1; decoder->huffnode[curcode].weight = 1;
} }
/*
#if 0
fprintf(stderr, "Pre-sort:\n"); fprintf(stderr, "Pre-sort:\n");
for (int i = 0; i < listitems; i++) { for (int i = 0; i < listitems; i++) {
fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits); fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
} }
*/ #endif
/* sort the list by weight, largest weight first */ /* sort the list by weight, largest weight first */
qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare); qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare);
/*
#if 0
fprintf(stderr, "Post-sort:\n"); fprintf(stderr, "Post-sort:\n");
for (int i = 0; i < listitems; i++) { for (int i = 0; i < listitems; i++) {
fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits); fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
} }
fprintf(stderr, "===================\n"); fprintf(stderr, "===================\n");
*/ #endif
/* now build the tree */ /* now build the tree */
nextalloc = decoder->numcodes; nextalloc = decoder->numcodes;
while (listitems > 1) while (listitems > 1)
{ {
int curitem; int curitem;
@ -453,7 +453,7 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint
node->numbits = 0; node->numbits = 0;
node->bits = 0; node->bits = 0;
// if we have a non-zero weight, compute the number of bits /* if we have a non-zero weight, compute the number of bits */
if (node->weight > 0) if (node->weight > 0)
{ {
/* determine the number of bits for this node */ /* determine the number of bits for this node */
@ -469,7 +469,6 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint
return maxbits; return maxbits;
} }
/*------------------------------------------------- /*-------------------------------------------------
* assign_canonical_codes - assign canonical codes * assign_canonical_codes - assign canonical codes
* to all the nodes based on the number of bits * to all the nodes based on the number of bits
@ -479,9 +478,9 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint
enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder) enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder)
{ {
int curcode, codelen;
uint32_t curstart = 0; uint32_t curstart = 0;
/* build up a histogram of bit lengths */ /* build up a histogram of bit lengths */
int curcode, codelen;
uint32_t bithisto[33] = { 0 }; uint32_t bithisto[33] = { 0 };
for (curcode = 0; curcode < decoder->numcodes; curcode++) for (curcode = 0; curcode < decoder->numcodes; curcode++)
{ {
@ -512,7 +511,6 @@ enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decode
return HUFFERR_NONE; return HUFFERR_NONE;
} }
/*------------------------------------------------- /*-------------------------------------------------
* build_lookup_table - build a lookup table for * build_lookup_table - build a lookup table for
* fast decoding * fast decoding
@ -521,8 +519,8 @@ enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decode
void huffman_build_lookup_table(struct huffman_decoder* decoder) void huffman_build_lookup_table(struct huffman_decoder* decoder)
{ {
/* iterate over all codes */
int curcode; int curcode;
/* iterate over all codes */
for (curcode = 0; curcode < decoder->numcodes; curcode++) for (curcode = 0; curcode < decoder->numcodes; curcode++)
{ {
/* process all nodes which have non-zero bits */ /* process all nodes which have non-zero bits */

View File

@ -1,6 +1,6 @@
// license:BSD-3-Clause /* license:BSD-3-Clause
// copyright-holders:Aaron Giles * copyright-holders:Aaron Giles
/*************************************************************************** ***************************************************************************
huffman.h huffman.h
@ -13,12 +13,13 @@
#ifndef __HUFFMAN_H__ #ifndef __HUFFMAN_H__
#define __HUFFMAN_H__ #define __HUFFMAN_H__
#include "bitstream.h" #include <libchdr/bitstream.h>
//************************************************************************** /***************************************************************************
// CONSTANTS * CONSTANTS
//************************************************************************** ***************************************************************************
*/
enum huffman_error enum huffman_error
{ {
@ -31,49 +32,50 @@ enum huffman_error
HUFFERR_TOO_MANY_CONTEXTS HUFFERR_TOO_MANY_CONTEXTS
}; };
/***************************************************************************
* TYPE DEFINITIONS
//************************************************************************** ***************************************************************************
// TYPE DEFINITIONS */
//**************************************************************************
typedef uint16_t lookup_value; typedef uint16_t lookup_value;
// a node in the huffman tree /* a node in the huffman tree */
struct node_t struct node_t
{ {
struct node_t* parent; // pointer to parent node struct node_t* parent; /* pointer to parent node */
uint32_t count; // number of hits on this node uint32_t count; /* number of hits on this node */
uint32_t weight; // assigned weight of this node uint32_t weight; /* assigned weight of this node */
uint32_t bits; // bits used to encode the node uint32_t bits; /* bits used to encode the node */
uint8_t numbits; // number of bits needed for this node uint8_t numbits; /* number of bits needed for this node */
}; };
// ======================> huffman_context_base /* ======================> huffman_context_base */
// context class for decoding /* context class for decoding */
struct huffman_decoder struct huffman_decoder
{ {
// internal state /* internal state */
uint32_t numcodes; // number of total codes being processed uint32_t numcodes; /* number of total codes being processed */
uint8_t maxbits; // maximum bits per code uint8_t maxbits; /* maximum bits per code */
uint8_t prevdata; // value of the previous data (for delta-RLE encoding) uint8_t prevdata; /* value of the previous data (for delta-RLE encoding) */
int rleremaining; // number of RLE bytes remaining (for delta-RLE encoding) int rleremaining; /* number of RLE bytes remaining (for delta-RLE encoding) */
lookup_value * lookup; // pointer to the lookup table lookup_value * lookup; /* pointer to the lookup table */
struct node_t * huffnode; // array of nodes struct node_t * huffnode; /* array of nodes */
uint32_t * datahisto; // histogram of data values uint32_t * datahisto; /* histogram of data values */
// array versions of the info we need /* array versions of the info we need */
//node_t* huffnode_array; //[_NumCodes]; #if 0
//lookup_value* lookup_array; //[1 << _MaxBits]; node_t* huffnode_array; /* [_NumCodes]; */
lookup_value* lookup_array; /* [1 << _MaxBits]; */
#endif
}; };
// ======================> huffman_decoder /* ======================> huffman_decoder */
struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits); struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits);
void delete_huffman_decoder(struct huffman_decoder* decoder); void delete_huffman_decoder(struct huffman_decoder* decoder);
// single item operations /* single item operations */
uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf); uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf);
enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf); enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf);

View File

@ -86,7 +86,7 @@ struct blip_t
#define BLIP_BUFFER_STATE_BUFFER_SIZE 16 #define BLIP_BUFFER_STATE_BUFFER_SIZE 16
typedef struct blip_buffer_state_t struct blip_buffer_state_t
{ {
fixed_t offset; fixed_t offset;
#ifdef BLIP_MONO #ifdef BLIP_MONO

View File

@ -2528,7 +2528,7 @@ static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes)
/* handle an error */ /* handle an error */
if (err != CHDERR_NONE) if (err != CHDERR_NONE)
free(data); zlib_codec_free(data);
return err; return err;
} }

View File

@ -152,7 +152,7 @@ static const void *g_rom_data = NULL;
static size_t g_rom_size = 0; static size_t g_rom_size = 0;
static char *save_dir = NULL; static char *save_dir = NULL;
static retro_log_printf_t log_cb; retro_log_printf_t log_cb;
static retro_video_refresh_t video_cb; static retro_video_refresh_t video_cb;
static retro_input_poll_t input_poll_cb; static retro_input_poll_t input_poll_cb;
static retro_input_state_t input_state_cb; static retro_input_state_t input_state_cb;
@ -400,7 +400,7 @@ int load_archive(char *filename, unsigned char *buffer, int maxsize, char *exten
if (!strcmp(filename,CD_BIOS_US) || !strcmp(filename,CD_BIOS_EU) || !strcmp(filename,CD_BIOS_JP)) if (!strcmp(filename,CD_BIOS_US) || !strcmp(filename,CD_BIOS_EU) || !strcmp(filename,CD_BIOS_JP))
{ {
if (log_cb) if (log_cb)
log_cb(RETRO_LOG_ERROR, "Unable to open CD BIOS: %s.\n", filename); log_cb(RETRO_LOG_ERROR, "Unable to open CD BIOS: \"%s\".\n", filename);
return 0; return 0;
} }
@ -426,7 +426,7 @@ int load_archive(char *filename, unsigned char *buffer, int maxsize, char *exten
size = maxsize; size = maxsize;
if (log_cb) if (log_cb)
log_cb(RETRO_LOG_INFO, "INFORMATION - Loading %d bytes ...\n", size); log_cb(RETRO_LOG_INFO, "Loading %d bytes ...\n", size);
/* Read into buffer */ /* Read into buffer */
left = size; left = size;
@ -1710,6 +1710,15 @@ static void check_variables(bool first_run)
config.cd_latency = 0; config.cd_latency = 0;
} }
var.key = "genesis_plus_gx_cd_precache";
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
{
if (!var.value || !strcmp(var.value, "disabled"))
config.cd_precache = 0;
else
config.cd_precache = 1;
}
var.key = "genesis_plus_gx_add_on"; var.key = "genesis_plus_gx_add_on";
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var); environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
{ {
@ -3806,6 +3815,8 @@ void retro_run(void)
bool updated = false; bool updated = false;
int vwoffset = 0; int vwoffset = 0;
int bmdoffset = 0; int bmdoffset = 0;
int soundbuffer_size = 0;
is_running = true; is_running = true;
#ifdef HAVE_OVERCLOCK #ifdef HAVE_OVERCLOCK
@ -3894,6 +3905,8 @@ void retro_run(void)
system_frame_sms(do_skip); system_frame_sms(do_skip);
} }
soundbuffer_size = audio_update(soundbuffer);
if (bitmap.viewport.changed & 9) if (bitmap.viewport.changed & 9)
{ {
bool geometry_updated = update_viewport(); bool geometry_updated = update_viewport();
@ -3956,7 +3969,7 @@ void retro_run(void)
video_cb(NULL, vwidth - vwoffset, vheight, 720 * 2); video_cb(NULL, vwidth - vwoffset, vheight, 720 * 2);
} }
audio_cb(soundbuffer, audio_update(soundbuffer)); audio_cb(soundbuffer, soundbuffer_size);
} }
#undef CHUNKSIZE #undef CHUNKSIZE

View File

@ -936,9 +936,9 @@ struct retro_core_option_v2_definition option_defs_us[] = {
}, },
{ {
"genesis_plus_gx_cd_latency", "genesis_plus_gx_cd_latency",
"CD access time", "CD Access Time",
NULL, NULL,
"Simulate original CD hardware latency when initiating a read or seeking to a specific location on loaded disc. This is required by a few CD games that crash if CD data is available too soon and also fixes CD audio desync issues in some games. Disabling this can be useful with MSU-MD games as it makes CD audio tracks loops more seamless.", "Simulate original CD hardware latency when initiating a read or seeking to a specific location on loaded disc. This is required by a few CD games that crash if CD data is available too soon and also fixes CD audio desync issues in some games. Disabling this can be useful with MSU-MD games as it makes CD audio tracks loops more seamless.",
NULL, NULL,
"hacks", "hacks",
{ {
@ -948,6 +948,20 @@ struct retro_core_option_v2_definition option_defs_us[] = {
}, },
"enabled" "enabled"
}, },
{
"genesis_plus_gx_cd_precache",
"CD Image Cache",
NULL,
"Load CD image to memory on startup. CHD supported only. Restart Required.",
NULL,
"hacks",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL },
},
"disabled"
},
#ifdef USE_PER_SOUND_CHANNELS_CONFIG #ifdef USE_PER_SOUND_CHANNELS_CONFIG
{ {
"genesis_plus_gx_show_advanced_audio_settings", "genesis_plus_gx_show_advanced_audio_settings",

View File

@ -136,6 +136,7 @@ typedef struct
uint8 enhanced_vscroll; uint8 enhanced_vscroll;
uint8 enhanced_vscroll_limit; uint8 enhanced_vscroll_limit;
uint8 cd_latency; uint8 cd_latency;
bool cd_precache;
#ifdef USE_PER_SOUND_CHANNELS_CONFIG #ifdef USE_PER_SOUND_CHANNELS_CONFIG
unsigned int psg_ch_volumes[4]; unsigned int psg_ch_volumes[4];
int32 md_ch_volumes[6]; int32 md_ch_volumes[6];
@ -161,6 +162,7 @@ extern char MS_BIOS_JP[256];
extern void osd_input_update(void); extern void osd_input_update(void);
extern int load_archive(char *filename, unsigned char *buffer, int maxsize, char *extension); extern int load_archive(char *filename, unsigned char *buffer, int maxsize, char *extension);
extern void ROMCheatUpdate(void); extern void ROMCheatUpdate(void);
extern retro_log_printf_t log_cb;
#ifndef cdStream #ifndef cdStream
#define cdStream RFILE #define cdStream RFILE