mirror of
https://github.com/libretro/Genesis-Plus-GX.git
synced 2024-11-27 02:20:39 +00:00
Merge pull request #350 from sonninnos/audio-update
Libretro: Update audio before video_cb
This commit is contained in:
commit
c921b37bd9
@ -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);
|
||||||
|
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* license:BSD-3-Clause
|
/* license:BSD-3-Clause
|
||||||
* copyright-holders:Aaron Giles
|
* copyright-holders:Aaron Giles
|
||||||
***************************************************************************
|
***************************************************************************
|
||||||
|
|
||||||
bitstream.h
|
bitstream.h
|
||||||
|
|
||||||
|
@ -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, §or[ECC_P_OFFSET + byte], §or[ECC_P_OFFSET + 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
|
/* 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, §or[ECC_Q_OFFSET + byte], §or[ECC_Q_OFFSET + 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 */
|
/* 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
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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__ */
|
||||||
|
@ -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 */
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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",
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user