mirror of
https://github.com/libretro/Genesis-Plus-GX.git
synced 2024-11-26 18:10:32 +00:00
libchdr update + precache option
This commit is contained in:
parent
a1b8039c35
commit
f00b1d1e3e
@ -397,6 +397,16 @@ int cdd_load(char *filename, char *header)
|
||||
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 */
|
||||
head = chd_get_header(cdd.chd.file);
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
/* license:BSD-3-Clause
|
||||
* copyright-holders:Aaron Giles
|
||||
*/
|
||||
/***************************************************************************
|
||||
* copyright-holders:Aaron Giles
|
||||
***************************************************************************
|
||||
|
||||
bitstream.c
|
||||
|
||||
@ -9,8 +8,8 @@
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "bitstream.h"
|
||||
#include <stdlib.h>
|
||||
#include <libchdr/bitstream.h>
|
||||
|
||||
/***************************************************************************
|
||||
* 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)
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* license:BSD-3-Clause
|
||||
* copyright-holders:Aaron Giles
|
||||
***************************************************************************
|
||||
***************************************************************************
|
||||
|
||||
bitstream.h
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Aaron Giles
|
||||
/***************************************************************************
|
||||
/* license:BSD-3-Clause
|
||||
* copyright-holders:Aaron Giles
|
||||
***************************************************************************
|
||||
|
||||
cdrom.c
|
||||
|
||||
@ -15,12 +15,12 @@
|
||||
schemes will differ after track 1!
|
||||
|
||||
***************************************************************************/
|
||||
#ifdef WANT_RAW_DATA_SECTOR
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cdrom.h"
|
||||
#include <libchdr/cdrom.h>
|
||||
|
||||
#ifdef WANT_RAW_DATA_SECTOR
|
||||
|
||||
/***************************************************************************
|
||||
DEBUGGING
|
||||
@ -64,8 +64,6 @@ void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
|
||||
#define LOG(x)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CONSTANTS
|
||||
***************************************************************************/
|
||||
@ -92,8 +90,6 @@ void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
|
||||
/** @brief 43 bytes each. */
|
||||
#define ECC_Q_COMP 43
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief -------------------------------------------------
|
||||
* 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 }
|
||||
};
|
||||
|
||||
/*-------------------------------------------------
|
||||
* ecc_source_byte - return data from the sector
|
||||
* at the given offset, masking anything
|
||||
* particular to a mode
|
||||
*-------------------------------------------------
|
||||
*/
|
||||
|
||||
//-------------------------------------------------
|
||||
// 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)
|
||||
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];
|
||||
}
|
||||
|
||||
@ -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)
|
||||
{
|
||||
int component;
|
||||
*val1 = *val2 = 0;
|
||||
for (int component = 0; component < rowlen; component++)
|
||||
for (component = 0; component < rowlen; component++)
|
||||
{
|
||||
*val1 ^= 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)
|
||||
{
|
||||
// first verify P bytes
|
||||
for (int byte = 0; byte < ECC_P_NUM_BYTES; byte++)
|
||||
int byte;
|
||||
/* first verify P bytes */
|
||||
for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)
|
||||
{
|
||||
uint8_t 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;
|
||||
}
|
||||
|
||||
// then verify Q bytes
|
||||
for (int byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
|
||||
/* then verify Q bytes */
|
||||
for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
|
||||
{
|
||||
uint8_t 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)
|
||||
{
|
||||
// first verify P bytes
|
||||
for (int byte = 0; byte < ECC_P_NUM_BYTES; byte++)
|
||||
int byte;
|
||||
/* first verify P bytes */
|
||||
for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)
|
||||
ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, §or[ECC_P_OFFSET + byte], §or[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte]);
|
||||
|
||||
// then verify Q bytes
|
||||
for (int byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
|
||||
/* then verify Q bytes */
|
||||
for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
|
||||
ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, §or[ECC_Q_OFFSET + byte], §or[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte]);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* license:BSD-3-Clause */
|
||||
/* copyright-holders:Aaron Giles */
|
||||
/***************************************************************************
|
||||
/* license:BSD-3-Clause
|
||||
* copyright-holders:Aaron Giles
|
||||
***************************************************************************
|
||||
|
||||
cdrom.h
|
||||
|
||||
@ -14,15 +14,14 @@
|
||||
#define __CDROM_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libchdr/chdconfig.h>
|
||||
|
||||
/***************************************************************************
|
||||
CONSTANTS
|
||||
***************************************************************************/
|
||||
|
||||
/* 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_SECTOR_DATA (2352)
|
||||
#define CD_MAX_SUBCODE_DATA (96)
|
||||
@ -53,8 +52,8 @@ enum
|
||||
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_GDROMLE 0x00000002 // legacy GD-ROM, with little-endian CDDA data
|
||||
#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 */
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
@ -67,4 +66,45 @@ void ecc_generate(uint8_t *sector);
|
||||
void ecc_clear(uint8_t *sector);
|
||||
#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__ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -46,8 +46,8 @@
|
||||
extern "C" {
|
||||
#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_UNDEFINED 0xfffffffc
|
||||
|
||||
#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
|
||||
|
||||
/* compression types */
|
||||
#define CHDCOMPRESSION_NONE 0
|
||||
#define CHDCOMPRESSION_ZLIB 1
|
||||
#define CHDCOMPRESSION_ZLIB_PLUS 2
|
||||
#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 */
|
||||
#define AV_CODEC_COMPRESS_CONFIG 1
|
||||
#define AV_CODEC_DECOMPRESS_CONFIG 2
|
||||
@ -212,33 +221,34 @@ extern "C" {
|
||||
#define CHD_MDFLAGS_CHECKSUM 0x01 /* indicates data is checksummed */
|
||||
|
||||
/* 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"
|
||||
|
||||
/* 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 */
|
||||
#define HARD_DISK_KEY_METADATA_TAG 0x4b455920 /* 'KEY ' */
|
||||
#define HARD_DISK_KEY_METADATA_TAG CHD_MAKE_TAG('K','E','Y',' ')
|
||||
|
||||
/* 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 */
|
||||
#define CDROM_OLD_METADATA_TAG 0x43484344 /* 'CHCD' */
|
||||
#define CDROM_TRACK_METADATA_TAG 0x43485452 /* 'CHTR' */
|
||||
#define CDROM_OLD_METADATA_TAG CHD_MAKE_TAG('C','H','C','D')
|
||||
#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_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 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"
|
||||
|
||||
/* 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"
|
||||
|
||||
/* 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 */
|
||||
#define CHD_OPEN_READ 1
|
||||
@ -305,9 +315,9 @@ struct _chd_header
|
||||
UINT8 parentmd5[CHD_MD5_BYTES]; /* overall MD5 checksum of parent */
|
||||
UINT8 sha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum */
|
||||
UINT8 rawsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */
|
||||
UINT8 parentsha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum of parent */
|
||||
UINT8 parentsha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum of parent */
|
||||
UINT32 unitbytes; /* TODO V5 */
|
||||
UINT64 unitcount; /* TODO V5 */
|
||||
UINT64 unitcount; /* TODO V5 */
|
||||
UINT32 hunkcount; /* TODO V5 */
|
||||
|
||||
/* map information */
|
||||
@ -337,6 +347,19 @@ struct _chd_verify_result
|
||||
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 ----- */
|
||||
|
||||
@ -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); */
|
||||
|
||||
/* open an existing CHD file */
|
||||
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_file(core_file *file, 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 */
|
||||
void chd_close(chd_file *chd);
|
||||
CHD_EXPORT void chd_close(chd_file *chd);
|
||||
|
||||
/* 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 */
|
||||
const char *chd_error_string(chd_error err);
|
||||
CHD_EXPORT const char *chd_error_string(chd_error err);
|
||||
|
||||
|
||||
|
||||
/* ----- CHD header management ----- */
|
||||
|
||||
/* 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 ----- */
|
||||
|
||||
/* 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 ----- */
|
||||
|
||||
/* 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 ----- */
|
||||
|
||||
/* 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 */
|
||||
const char *chd_get_codec_name(UINT32 codec);
|
||||
CHD_EXPORT const char *chd_get_codec_name(UINT32 codec);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Aaron Giles
|
||||
/***************************************************************************
|
||||
/* license:BSD-3-Clause
|
||||
* copyright-holders:Aaron Giles
|
||||
***************************************************************************
|
||||
|
||||
flac.c
|
||||
|
||||
@ -10,28 +10,35 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "flac.h"
|
||||
|
||||
//**************************************************************************
|
||||
// FLAC DECODER
|
||||
//**************************************************************************
|
||||
#include <libchdr/flac.h>
|
||||
#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);
|
||||
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 void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
|
||||
/***************************************************************************
|
||||
* FLAC DECODER
|
||||
***************************************************************************
|
||||
*/
|
||||
|
||||
static size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes);
|
||||
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
|
||||
*-------------------------------------------------
|
||||
*/
|
||||
|
||||
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->channels = 0;
|
||||
decoder->bits_per_sample = 0;
|
||||
@ -43,6 +50,7 @@ void flac_decoder_init(flac_decoder *decoder)
|
||||
decoder->uncompressed_offset = 0;
|
||||
decoder->uncompressed_length = 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)
|
||||
{
|
||||
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
|
||||
* parameters
|
||||
@ -66,21 +74,13 @@ void flac_decoder_free(flac_decoder* decoder)
|
||||
static int flac_decoder_internal_reset(flac_decoder* decoder)
|
||||
{
|
||||
decoder->compressed_offset = 0;
|
||||
if (FLAC__stream_decoder_init_stream(decoder->decoder,
|
||||
&flac_decoder_read_callback_static,
|
||||
NULL,
|
||||
&flac_decoder_tell_callback_static,
|
||||
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);
|
||||
flac_decoder_free(decoder);
|
||||
decoder->decoder = drflac_open_with_metadata(
|
||||
flac_decoder_read_callback, flac_decoder_seek_callback,
|
||||
flac_decoder_metadata_callback, decoder, NULL);
|
||||
return (decoder->decoder != NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* reset - reset state with new memory parameters
|
||||
* 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 */
|
||||
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, /* +08: minimum block size */
|
||||
0x00, 0x00, /* +0A: maximum block size */
|
||||
0x00, 0x00, 0x00, /* +0C: minimum 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), */
|
||||
/* numchannels (2), sample bits (16), */
|
||||
/* samples in stream (0 == unknown) */
|
||||
/* numchannels (2), sample bits (16), */
|
||||
/* 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 /* */
|
||||
/* +2A: start of stream data */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* +2A: start of stream data */
|
||||
};
|
||||
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[0x09] = decoder->custom_header[0x0b] = block_size & 0xff;
|
||||
decoder->custom_header[0x08] = decoder->custom_header[0x0a] = (block_size*num_channels) >> 8;
|
||||
decoder->custom_header[0x09] = decoder->custom_header[0x0b] = (block_size*num_channels) & 0xff;
|
||||
decoder->custom_header[0x12] = sample_rate >> 12;
|
||||
decoder->custom_header[0x13] = sample_rate >> 4;
|
||||
decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1);
|
||||
|
||||
/* 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->compressed2_start = (const FLAC__byte *)(buffer);
|
||||
decoder->compressed2_start = (const uint8_t *)(buffer);
|
||||
decoder->compressed2_length = length;
|
||||
return flac_decoder_internal_reset(decoder);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* decode_interleaved - decode to an interleaved
|
||||
* 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)
|
||||
{
|
||||
int16_t buffer[BUFFER];
|
||||
uint32_t buf_samples;
|
||||
|
||||
/* configure the uncompressed buffer */
|
||||
memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start));
|
||||
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_swap = swap_endian;
|
||||
|
||||
buf_samples = BUFFER / channels(decoder);
|
||||
/* loop until we get everything we want */
|
||||
while (decoder->uncompressed_offset < decoder->uncompressed_length)
|
||||
if (!FLAC__stream_decoder_process_single(decoder->decoder))
|
||||
while (decoder->uncompressed_offset < decoder->uncompressed_length) {
|
||||
uint32_t frames = (num_samples < buf_samples ? num_samples : buf_samples);
|
||||
if (!drflac_read_pcm_frames_s16(decoder->decoder, frames, buffer))
|
||||
return 0;
|
||||
flac_decoder_write_callback(decoder, buffer, frames*sizeof(*buffer)*channels(decoder));
|
||||
num_samples -= frames;
|
||||
}
|
||||
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
|
||||
*-------------------------------------------------
|
||||
@ -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)
|
||||
{
|
||||
/* get the final decoding position and move forward */
|
||||
FLAC__uint64 position = 0;
|
||||
FLAC__stream_decoder_get_decode_position(decoder->decoder, &position);
|
||||
FLAC__stream_decoder_finish(decoder->decoder);
|
||||
drflac *flac = decoder->decoder;
|
||||
uint64_t position = decoder->compressed_offset;
|
||||
|
||||
/* 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 */
|
||||
if (position == 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;
|
||||
|
||||
flac_decoder_free(decoder);
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* read_callback - handle reads from the input
|
||||
* stream
|
||||
@ -206,128 +187,119 @@ uint32_t flac_decoder_finish(flac_decoder* decoder)
|
||||
|
||||
#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__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;
|
||||
flac_decoder* decoder = (flac_decoder*)userdata;
|
||||
uint8_t *dst = buffer;
|
||||
|
||||
/* copy from primary buffer first */
|
||||
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);
|
||||
memcpy(&buffer[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy);
|
||||
uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed_length - decoder->compressed_offset);
|
||||
memcpy(&dst[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy);
|
||||
outputpos += bytes_to_copy;
|
||||
decoder->compressed_offset += bytes_to_copy;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
memcpy(&buffer[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy);
|
||||
uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length));
|
||||
memcpy(&dst[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy);
|
||||
outputpos += bytes_to_copy;
|
||||
decoder->compressed_offset += bytes_to_copy;
|
||||
}
|
||||
*bytes = outputpos;
|
||||
|
||||
/* return based on whether we ran out of data */
|
||||
return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
||||
return outputpos;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* 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 */
|
||||
if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO)
|
||||
if (metadata->type != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO)
|
||||
return;
|
||||
|
||||
/* parse out the data we care about */
|
||||
fldecoder = (flac_decoder *)(client_data);
|
||||
fldecoder->sample_rate = metadata->data.stream_info.sample_rate;
|
||||
fldecoder->bits_per_sample = metadata->data.stream_info.bits_per_sample;
|
||||
fldecoder->channels = metadata->data.stream_info.channels;
|
||||
decoder->sample_rate = metadata->data.streaminfo.sampleRate;
|
||||
decoder->bits_per_sample = metadata->data.streaminfo.bitsPerSample;
|
||||
decoder->channels = metadata->data.streaminfo.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
|
||||
* stream
|
||||
*-------------------------------------------------
|
||||
*/
|
||||
|
||||
FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
|
||||
{
|
||||
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[])
|
||||
static void flac_decoder_write_callback(void *userdata, void *buffer, size_t bytes)
|
||||
{
|
||||
int sampnum, chan;
|
||||
int shift, blocksize;
|
||||
flac_decoder * decoder = (flac_decoder *)client_data;
|
||||
|
||||
assert(frame->header.channels == decoder->channels);
|
||||
int shift, blocksize;
|
||||
flac_decoder * decoder = (flac_decoder *)userdata;
|
||||
int16_t *sampbuf = (int16_t *)buffer;
|
||||
int sampch = channels(decoder);
|
||||
uint32_t offset = decoder->uncompressed_offset;
|
||||
uint16_t usample;
|
||||
|
||||
/* interleaved case */
|
||||
shift = decoder->uncompressed_swap ? 8 : 0;
|
||||
blocksize = frame->header.blocksize;
|
||||
blocksize = bytes / (sampch * sizeof(sampbuf[0]));
|
||||
if (decoder->uncompressed_start[1] == NULL)
|
||||
{
|
||||
int16_t *dest = decoder->uncompressed_start[0] + decoder->uncompressed_offset * frame->header.channels;
|
||||
for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++)
|
||||
for (chan = 0; chan < frame->header.channels; chan++)
|
||||
*dest++ = (int16_t)((((uint16_t)buffer[chan][sampnum]) << shift) | (((uint16_t)buffer[chan][sampnum]) >> shift));
|
||||
int16_t *dest = decoder->uncompressed_start[0] + offset * sampch;
|
||||
for (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++)
|
||||
for (chan = 0; chan < sampch; chan++) {
|
||||
usample = (uint16_t)*sampbuf++;
|
||||
*dest++ = (int16_t)((usample << shift) | (usample >> shift));
|
||||
}
|
||||
}
|
||||
|
||||
/* non-interleaved case */
|
||||
else
|
||||
{
|
||||
for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++)
|
||||
for (chan = 0; chan < frame->header.channels; chan++)
|
||||
for (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++)
|
||||
for (chan = 0; chan < sampch; chan++) {
|
||||
usample = (uint16_t)*sampbuf++;
|
||||
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)
|
||||
*
|
||||
* @brief -------------------------------------------------
|
||||
* 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.
|
||||
|
||||
/*-------------------------------------------------
|
||||
* seek_callback - handle seeks on the output
|
||||
* stream
|
||||
*-------------------------------------------------
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Aaron Giles
|
||||
/***************************************************************************
|
||||
/* license:BSD-3-Clause
|
||||
* copyright-holders:Aaron Giles
|
||||
***************************************************************************
|
||||
|
||||
flac.h
|
||||
|
||||
@ -14,38 +14,37 @@
|
||||
#define __FLAC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "FLAC/ordinals.h"
|
||||
#include "FLAC/stream_decoder.h"
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
/***************************************************************************
|
||||
* TYPE DEFINITIONS
|
||||
***************************************************************************
|
||||
*/
|
||||
|
||||
typedef struct _flac_decoder flac_decoder;
|
||||
struct _flac_decoder {
|
||||
// output state
|
||||
FLAC__StreamDecoder* decoder; // actual encoder
|
||||
uint32_t sample_rate; // decoded sample rate
|
||||
uint8_t channels; // decoded number of channels
|
||||
uint8_t bits_per_sample; // decoded bits per sample
|
||||
uint32_t compressed_offset; // current offset in compressed data
|
||||
const FLAC__byte * compressed_start; // start of compressed data
|
||||
uint32_t compressed_length; // length of compressed data
|
||||
const FLAC__byte * compressed2_start; // start 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)
|
||||
uint32_t uncompressed_offset; // current position in uncompressed data
|
||||
uint32_t uncompressed_length; // length of uncompressed data
|
||||
int uncompressed_swap; // swap uncompressed sample data
|
||||
uint8_t custom_header[0x2a]; // custom header
|
||||
/* output state */
|
||||
void * decoder; /* actual encoder */
|
||||
uint32_t sample_rate; /* decoded sample rate */
|
||||
uint8_t channels; /* decoded number of channels */
|
||||
uint8_t bits_per_sample; /* decoded bits per sample */
|
||||
uint32_t compressed_offset; /* current offset in compressed data */
|
||||
const uint8_t * compressed_start; /* start of compressed data */
|
||||
uint32_t compressed_length; /* length of compressed data */
|
||||
const uint8_t * compressed2_start; /* start 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) */
|
||||
uint32_t uncompressed_offset; /* current position in uncompressed data */
|
||||
uint32_t uncompressed_length; /* length of uncompressed data */
|
||||
int uncompressed_swap; /* swap uncompressed sample data */
|
||||
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);
|
||||
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);
|
||||
uint32_t flac_decoder_finish(flac_decoder* decoder);
|
||||
|
||||
#endif // __FLAC_H__
|
||||
#endif /* __FLAC_H__ */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* license:BSD-3-Clause
|
||||
* copyright-holders:Aaron Giles
|
||||
***************************************************************************
|
||||
****************************************************************************
|
||||
|
||||
huffman.c
|
||||
|
||||
@ -101,7 +101,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "huffman.h"
|
||||
#include <libchdr/huffman.h>
|
||||
|
||||
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
@ -112,10 +112,9 @@
|
||||
|
||||
#define MAKE_LOOKUP(code,bits) (((code) << 5) | ((bits) & 0x1f))
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* IMPLEMENTATION
|
||||
* **************************************************************************
|
||||
***************************************************************************
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------
|
||||
@ -126,7 +125,8 @@
|
||||
|
||||
struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits)
|
||||
{
|
||||
struct huffman_decoder* decoder;
|
||||
struct huffman_decoder* decoder = NULL;
|
||||
|
||||
/* limit to 24 bits */
|
||||
if (maxbits > 24)
|
||||
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 error;
|
||||
int numbits, curnode;
|
||||
enum huffman_error error;
|
||||
|
||||
/* bits per entry depends on the maxbits */
|
||||
int numbits;
|
||||
int curnode;
|
||||
if (decoder->maxbits >= 16)
|
||||
numbits = 5;
|
||||
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)
|
||||
{
|
||||
int start;
|
||||
int last = 0;
|
||||
int count = 0;
|
||||
int index;
|
||||
int curcode;
|
||||
uint32_t temp;
|
||||
enum huffman_error error;
|
||||
uint8_t rlefullbits = 0;
|
||||
int index, count = 0;
|
||||
int start;
|
||||
uint32_t temp;
|
||||
enum huffman_error error;
|
||||
/* start by parsing the lengths for the small tree */
|
||||
struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6);
|
||||
|
||||
smallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3);
|
||||
start = bitstream_read(bitbuf, 3) + 1;
|
||||
|
||||
for (index = 1; index < 24; index++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* compute_tree_from_histo - common backend for
|
||||
* 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)
|
||||
{
|
||||
/* compute the number of data items in the histogram */
|
||||
int i;
|
||||
uint32_t upperweight;
|
||||
uint32_t lowerweight = 0;
|
||||
uint32_t lowerweight;
|
||||
uint32_t upperweight;
|
||||
/* compute the number of data items in the histogram */
|
||||
uint32_t sdatacount = 0;
|
||||
for (i = 0; i < decoder->numcodes; i++)
|
||||
sdatacount += decoder->datahisto[i];
|
||||
|
||||
/* binary search to achieve the optimum encoding */
|
||||
lowerweight = 0;
|
||||
upperweight = sdatacount * 2;
|
||||
while (1)
|
||||
{
|
||||
@ -352,8 +351,6 @@ enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decod
|
||||
return huffman_assign_canonical_codes(decoder);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* build_tree - build a huffman tree based on the
|
||||
* 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 nextalloc;
|
||||
int curcode;
|
||||
int nextalloc;
|
||||
int listitems = 0;
|
||||
int maxbits = 0;
|
||||
/* make a list of all non-zero nodes */
|
||||
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]));
|
||||
for (curcode = 0; curcode < decoder->numcodes; curcode++)
|
||||
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)
|
||||
decoder->huffnode[curcode].weight = 1;
|
||||
}
|
||||
/*
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "Pre-sort:\n");
|
||||
for (int i = 0; i < listitems; i++) {
|
||||
fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
/* sort the list by weight, largest weight first */
|
||||
qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare);
|
||||
/*
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "Post-sort:\n");
|
||||
for (int i = 0; i < listitems; i++) {
|
||||
fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
|
||||
}
|
||||
fprintf(stderr, "===================\n");
|
||||
*/
|
||||
#endif
|
||||
|
||||
/* now build the tree */
|
||||
nextalloc = decoder->numcodes;
|
||||
|
||||
while (listitems > 1)
|
||||
{
|
||||
int curitem;
|
||||
@ -453,7 +453,7 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint
|
||||
node->numbits = 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)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* assign_canonical_codes - assign canonical codes
|
||||
* 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)
|
||||
{
|
||||
int curcode, codelen;
|
||||
uint32_t curstart = 0;
|
||||
/* build up a histogram of bit lengths */
|
||||
int curcode, codelen;
|
||||
uint32_t bithisto[33] = { 0 };
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* build_lookup_table - build a lookup table for
|
||||
* 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)
|
||||
{
|
||||
/* iterate over all codes */
|
||||
int curcode;
|
||||
/* iterate over all codes */
|
||||
for (curcode = 0; curcode < decoder->numcodes; curcode++)
|
||||
{
|
||||
/* process all nodes which have non-zero bits */
|
||||
|
@ -1,6 +1,6 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Aaron Giles
|
||||
/***************************************************************************
|
||||
/* license:BSD-3-Clause
|
||||
* copyright-holders:Aaron Giles
|
||||
***************************************************************************
|
||||
|
||||
huffman.h
|
||||
|
||||
@ -13,12 +13,13 @@
|
||||
#ifndef __HUFFMAN_H__
|
||||
#define __HUFFMAN_H__
|
||||
|
||||
#include "bitstream.h"
|
||||
#include <libchdr/bitstream.h>
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// CONSTANTS
|
||||
//**************************************************************************
|
||||
/***************************************************************************
|
||||
* CONSTANTS
|
||||
***************************************************************************
|
||||
*/
|
||||
|
||||
enum huffman_error
|
||||
{
|
||||
@ -31,49 +32,50 @@ enum huffman_error
|
||||
HUFFERR_TOO_MANY_CONTEXTS
|
||||
};
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
/***************************************************************************
|
||||
* TYPE DEFINITIONS
|
||||
***************************************************************************
|
||||
*/
|
||||
|
||||
typedef uint16_t lookup_value;
|
||||
|
||||
// a node in the huffman tree
|
||||
/* a node in the huffman tree */
|
||||
struct node_t
|
||||
{
|
||||
struct node_t* parent; // pointer to parent node
|
||||
uint32_t count; // number of hits on this node
|
||||
uint32_t weight; // assigned weight of this node
|
||||
uint32_t bits; // bits used to encode the node
|
||||
uint8_t numbits; // number of bits needed for this node
|
||||
struct node_t* parent; /* pointer to parent node */
|
||||
uint32_t count; /* number of hits on this node */
|
||||
uint32_t weight; /* assigned weight of this node */
|
||||
uint32_t bits; /* bits used to encode the 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
|
||||
{
|
||||
// internal state
|
||||
uint32_t numcodes; // number of total codes being processed
|
||||
uint8_t maxbits; // maximum bits per code
|
||||
uint8_t prevdata; // value of the previous data (for delta-RLE encoding)
|
||||
int rleremaining; // number of RLE bytes remaining (for delta-RLE encoding)
|
||||
lookup_value * lookup; // pointer to the lookup table
|
||||
struct node_t * huffnode; // array of nodes
|
||||
uint32_t * datahisto; // histogram of data values
|
||||
/* internal state */
|
||||
uint32_t numcodes; /* number of total codes being processed */
|
||||
uint8_t maxbits; /* maximum bits per code */
|
||||
uint8_t prevdata; /* value of the previous data (for delta-RLE encoding) */
|
||||
int rleremaining; /* number of RLE bytes remaining (for delta-RLE encoding) */
|
||||
lookup_value * lookup; /* pointer to the lookup table */
|
||||
struct node_t * huffnode; /* array of nodes */
|
||||
uint32_t * datahisto; /* histogram of data values */
|
||||
|
||||
// array versions of the info we need
|
||||
//node_t* huffnode_array; //[_NumCodes];
|
||||
//lookup_value* lookup_array; //[1 << _MaxBits];
|
||||
/* array versions of the info we need */
|
||||
#if 0
|
||||
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);
|
||||
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);
|
||||
|
||||
enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf);
|
||||
|
@ -2528,7 +2528,7 @@ static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes)
|
||||
|
||||
/* handle an error */
|
||||
if (err != CHDERR_NONE)
|
||||
free(data);
|
||||
zlib_codec_free(data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ static const void *g_rom_data = NULL;
|
||||
static size_t g_rom_size = 0;
|
||||
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_input_poll_t input_poll_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 (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;
|
||||
}
|
||||
|
||||
@ -426,7 +426,7 @@ int load_archive(char *filename, unsigned char *buffer, int maxsize, char *exten
|
||||
size = maxsize;
|
||||
|
||||
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 */
|
||||
left = size;
|
||||
@ -1710,6 +1710,15 @@ static void check_variables(bool first_run)
|
||||
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";
|
||||
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
|
||||
{
|
||||
|
@ -936,9 +936,9 @@ struct retro_core_option_v2_definition option_defs_us[] = {
|
||||
},
|
||||
{
|
||||
"genesis_plus_gx_cd_latency",
|
||||
"CD access time",
|
||||
"CD Access Time",
|
||||
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,
|
||||
"hacks",
|
||||
{
|
||||
@ -948,6 +948,20 @@ struct retro_core_option_v2_definition option_defs_us[] = {
|
||||
},
|
||||
"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
|
||||
{
|
||||
"genesis_plus_gx_show_advanced_audio_settings",
|
||||
|
@ -136,6 +136,7 @@ typedef struct
|
||||
uint8 enhanced_vscroll;
|
||||
uint8 enhanced_vscroll_limit;
|
||||
uint8 cd_latency;
|
||||
bool cd_precache;
|
||||
#ifdef USE_PER_SOUND_CHANNELS_CONFIG
|
||||
unsigned int psg_ch_volumes[4];
|
||||
int32 md_ch_volumes[6];
|
||||
@ -161,6 +162,7 @@ extern char MS_BIOS_JP[256];
|
||||
extern void osd_input_update(void);
|
||||
extern int load_archive(char *filename, unsigned char *buffer, int maxsize, char *extension);
|
||||
extern void ROMCheatUpdate(void);
|
||||
extern retro_log_printf_t log_cb;
|
||||
|
||||
#ifndef cdStream
|
||||
#define cdStream RFILE
|
||||
|
Loading…
Reference in New Issue
Block a user