mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-14 18:47:39 +01:00
Clean AIFF code
This commit is contained in:
parent
7562b00b60
commit
f4d9ebfe47
126
src/meta/aifc.c
126
src/meta/aifc.c
@ -4,20 +4,20 @@
|
|||||||
|
|
||||||
|
|
||||||
/* for reading integers inexplicably packed into 80-bit ('double extended') floats */
|
/* for reading integers inexplicably packed into 80-bit ('double extended') floats */
|
||||||
static uint32_t read80bitSANE(off_t offset, STREAMFILE *streamFile) {
|
static uint32_t read_f80be(off_t offset, STREAMFILE* sf) {
|
||||||
uint8_t buf[0x0a];
|
uint8_t buf[0x0a];
|
||||||
int32_t exponent;
|
int32_t exponent;
|
||||||
int32_t mantissa;
|
int32_t mantissa;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (read_streamfile(buf,offset,0x0a,streamFile) != 0x0a)
|
if (read_streamfile(buf, offset, sizeof(buf), sf) != sizeof(buf))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
exponent = ((buf[0]<<8)|(buf[1]))&0x7fff;
|
exponent = ((buf[0]<<8) | (buf[1])) & 0x7fff;
|
||||||
exponent -= 16383;
|
exponent -= 16383;
|
||||||
|
|
||||||
mantissa = 0;
|
mantissa = 0;
|
||||||
for (i=0;i<8;i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
int32_t shift = exponent-7-i*8;
|
int32_t shift = exponent-7-i*8;
|
||||||
if (shift >= 0)
|
if (shift >= 0)
|
||||||
mantissa |= buf[i+2] << shift;
|
mantissa |= buf[i+2] << shift;
|
||||||
@ -25,46 +25,45 @@ static uint32_t read80bitSANE(off_t offset, STREAMFILE *streamFile) {
|
|||||||
mantissa |= buf[i+2] >> -shift;
|
mantissa |= buf[i+2] >> -shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mantissa*((buf[0]&0x80)?-1:1);
|
return mantissa * ((buf[0]&0x80) ? -1 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t find_marker(STREAMFILE *streamFile, off_t mark_offset, int marker_id) {
|
static uint32_t find_marker(STREAMFILE* sf, off_t mark_offset, int marker_id) {
|
||||||
uint16_t marker_count;
|
uint16_t marker_count;
|
||||||
int i;
|
|
||||||
off_t marker_offset;
|
off_t marker_offset;
|
||||||
|
int i;
|
||||||
|
|
||||||
marker_count = read_16bitBE(mark_offset+8,streamFile);
|
marker_count = read_u16be(mark_offset + 0x00,sf);
|
||||||
marker_offset = mark_offset+10;
|
marker_offset = mark_offset + 0x02;
|
||||||
for (i=0;i<marker_count;i++) {
|
for (i = 0; i < marker_count; i++) {
|
||||||
int name_length;
|
int name_length;
|
||||||
|
|
||||||
if (read_16bitBE(marker_offset,streamFile) == marker_id)
|
if (read_u16be(marker_offset + 0x00, sf) == marker_id)
|
||||||
return read_32bitBE(marker_offset+2,streamFile);
|
return read_u32be(marker_offset + 0x02,sf);
|
||||||
|
|
||||||
name_length = (uint8_t)read_8bit(marker_offset+6,streamFile) + 1;
|
name_length = read_u8(marker_offset + 0x06,sf) + 1;
|
||||||
if (name_length % 2) name_length++;
|
if (name_length % 2) name_length++;
|
||||||
marker_offset += 6 + name_length;
|
marker_offset += 0x06 + name_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Audio Interchange File Format AIFF/AIFF-C - from Mac/3DO games */
|
/* AIFF/AIFF-C (Audio Interchange File Format) - Apple format, from Mac/3DO/other games */
|
||||||
VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
off_t start_offset = 0;
|
off_t start_offset = 0;
|
||||||
size_t file_size;
|
size_t file_size;
|
||||||
coding_t coding_type = 0;
|
coding_t coding_type = 0;
|
||||||
int channel_count = 0, sample_count = 0, sample_size = 0, sample_rate = 0;
|
int channel_count = 0, sample_count = 0, sample_size = 0, sample_rate = 0;
|
||||||
int interleave = 0;
|
int interleave = 0;
|
||||||
|
|
||||||
int loop_flag = 0;
|
int loop_flag = 0;
|
||||||
int32_t loop_start = 0, loop_end = 0;
|
int32_t loop_start = 0, loop_end = 0;
|
||||||
|
|
||||||
int is_aiff_ext = 0, is_aifc_ext = 0, is_aiff = 0, is_aifc = 0;
|
int is_aiff_ext = 0, is_aifc_ext = 0, is_aiff = 0, is_aifc = 0;
|
||||||
int fver_found = 0, comm_found = 0, data_found = 0, mark_found = 0, inst_found = 0;
|
int fver_found = 0, comm_found = 0, data_found = 0;
|
||||||
off_t mark_offset = -1, inst_offset = -1;
|
off_t mark_offset = 0, inst_offset = 0;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
@ -78,30 +77,30 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
|
|||||||
* .ai: Dragon Force (SAT)
|
* .ai: Dragon Force (SAT)
|
||||||
* (extensionless: Doom (3DO)
|
* (extensionless: Doom (3DO)
|
||||||
* .fda: Homeworld 2 (PC) */
|
* .fda: Homeworld 2 (PC) */
|
||||||
if (check_extensions(streamFile, "aif,laif,")) {
|
if (check_extensions(sf, "aif,laif,")) {
|
||||||
is_aifc_ext = 1;
|
is_aifc_ext = 1;
|
||||||
is_aiff_ext = 1;
|
is_aiff_ext = 1;
|
||||||
}
|
}
|
||||||
else if (check_extensions(streamFile, "aifc,laifc,aifcl,afc,cbd2,bgm,fda")) {
|
else if (check_extensions(sf, "aifc,laifc,aifcl,afc,cbd2,bgm,fda")) {
|
||||||
is_aifc_ext = 1;
|
is_aifc_ext = 1;
|
||||||
}
|
}
|
||||||
else if (check_extensions(streamFile, "aiff,laiff,acm,adp,ai,aiffl")) {
|
else if (check_extensions(sf, "aiff,laiff,acm,adp,ai,aiffl")) {
|
||||||
is_aiff_ext = 1;
|
is_aiff_ext = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_size = get_streamfile_size(streamFile);
|
file_size = get_streamfile_size(sf);
|
||||||
if ((uint32_t)read_32bitBE(0x00,streamFile) != 0x464F524D && /* "FORM" */
|
if (read_u32be(0x00,sf) != 0x464F524D && /* "FORM" */
|
||||||
(uint32_t)read_32bitBE(0x04,streamFile)+0x08 != file_size)
|
read_u32be(0x04,sf)+0x08 != file_size)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if ((uint32_t)read_32bitBE(0x08,streamFile) == 0x41494643) { /* "AIFC" */
|
if (read_u32be(0x08,sf) == 0x41494643) { /* "AIFC" */
|
||||||
if (!is_aifc_ext) goto fail;
|
if (!is_aifc_ext) goto fail;
|
||||||
is_aifc = 1;
|
is_aifc = 1;
|
||||||
}
|
}
|
||||||
else if ((uint32_t)read_32bitBE(0x08,streamFile) == 0x41494646) { /* "AIFF" */
|
else if (read_u32be(0x08,sf) == 0x41494646) { /* "AIFF" */
|
||||||
if (!is_aiff_ext) goto fail;
|
if (!is_aiff_ext) goto fail;
|
||||||
is_aiff = 1;
|
is_aiff = 1;
|
||||||
}
|
}
|
||||||
@ -112,17 +111,20 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
/* read through chunks to verify format and find metadata */
|
/* read through chunks to verify format and find metadata */
|
||||||
{
|
{
|
||||||
off_t current_chunk = 0x0c; /* start with first chunk within FORM */
|
off_t offset = 0x0c; /* start with first chunk within FORM */
|
||||||
|
|
||||||
while (current_chunk < file_size) {
|
while (offset < file_size) {
|
||||||
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile);
|
uint32_t chunk_type = read_u32be(offset + 0x00,sf);
|
||||||
off_t chunk_size = read_32bitBE(current_chunk+0x04,streamFile);
|
uint32_t chunk_size = read_u32be(offset + 0x04,sf);
|
||||||
|
|
||||||
/* chunks must be padded to an even number of bytes but chunk
|
/* chunks must be padded to an even number of bytes but chunk
|
||||||
* size does not include that padding */
|
* size does not include that padding */
|
||||||
if (chunk_size % 2) chunk_size++;
|
if (chunk_size % 2)
|
||||||
|
chunk_size++;
|
||||||
|
|
||||||
if (current_chunk+8+chunk_size > file_size) goto fail;
|
offset += 0x08;
|
||||||
|
if (offset + chunk_size > file_size)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
switch(chunk_type) {
|
switch(chunk_type) {
|
||||||
case 0x46564552: /* "FVER" (version info) */
|
case 0x46564552: /* "FVER" (version info) */
|
||||||
@ -134,22 +136,23 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
|
|||||||
if (chunk_size != 4) goto fail;
|
if (chunk_size != 4) goto fail;
|
||||||
|
|
||||||
/* Version 1 of AIFF-C spec timestamp */
|
/* Version 1 of AIFF-C spec timestamp */
|
||||||
if ((uint32_t)read_32bitBE(current_chunk+0x08,streamFile) != 0xA2805140) goto fail;
|
if (read_u32be(offset + 0x00,sf) != 0xA2805140)
|
||||||
|
goto fail;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x434F4D4D: /* "COMM" (main header) */
|
case 0x434F4D4D: /* "COMM" (main header) */
|
||||||
if (comm_found) goto fail;
|
if (comm_found) goto fail;
|
||||||
comm_found = 1;
|
comm_found = 1;
|
||||||
|
|
||||||
channel_count = read_16bitBE(current_chunk+8,streamFile);
|
channel_count = read_u16be(offset + 0x00,sf);
|
||||||
if (channel_count <= 0) goto fail;
|
if (channel_count <= 0) goto fail;
|
||||||
|
|
||||||
sample_count = (uint32_t)read_32bitBE(current_chunk+0x0a,streamFile); /* sometimes number of blocks */
|
sample_count = read_u32be(offset + 0x02,sf); /* sometimes number of blocks */
|
||||||
sample_size = read_16bitBE(current_chunk+0x0e,streamFile);
|
sample_size = read_u16be(offset + 0x06,sf);
|
||||||
sample_rate = read80bitSANE(current_chunk+0x10,streamFile);
|
sample_rate = read_f80be(offset + 0x08,sf);
|
||||||
|
|
||||||
if (is_aifc) {
|
if (is_aifc) {
|
||||||
uint32_t codec = read_32bitBE(current_chunk+0x1a,streamFile);
|
uint32_t codec = read_u32be(offset + 0x12,sf);
|
||||||
switch (codec) {
|
switch (codec) {
|
||||||
case 0x53445832: /* "SDX2" [3DO games: Super Street Fighter II Turbo (3DO), etc] */
|
case 0x53445832: /* "SDX2" [3DO games: Super Street Fighter II Turbo (3DO), etc] */
|
||||||
coding_type = coding_SDX2;
|
coding_type = coding_SDX2;
|
||||||
@ -174,10 +177,10 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
case 0x434F4D50: { /* "COMP" (generic compression) */
|
case 0x434F4D50: { /* "COMP" (generic compression) */
|
||||||
uint8_t comp_name[255] = {0};
|
uint8_t comp_name[255] = {0};
|
||||||
uint8_t comp_size = read_8bit(current_chunk + 0x1e, streamFile);
|
uint8_t comp_size = read_u8(offset + 0x16, sf);
|
||||||
if (comp_size >= sizeof(comp_name) - 1) goto fail;
|
if (comp_size >= sizeof(comp_name) - 1) goto fail;
|
||||||
|
|
||||||
read_streamfile(comp_name, current_chunk + 0x1f, comp_size, streamFile);
|
read_streamfile(comp_name, offset + 0x17, comp_size, sf);
|
||||||
if (memcmp(comp_name, "Relic Codec v1.6", comp_size) == 0) { /* Homeworld 2 (PC) */
|
if (memcmp(comp_name, "Relic Codec v1.6", comp_size) == 0) { /* Homeworld 2 (PC) */
|
||||||
coding_type = coding_RELIC;
|
coding_type = coding_RELIC;
|
||||||
sample_count = sample_count * 512;
|
sample_count = sample_count * 512;
|
||||||
@ -219,30 +222,23 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
|
|||||||
if (data_found) goto fail;
|
if (data_found) goto fail;
|
||||||
data_found = 1;
|
data_found = 1;
|
||||||
|
|
||||||
start_offset = current_chunk + 0x10 + read_32bitBE(current_chunk+0x08,streamFile);
|
start_offset = offset + 0x08 + read_u32be(offset + 0x00,sf);
|
||||||
/* when "APCM" XA frame size is at 0x0c, fixed to 0x914 */
|
/* when "APCM" XA frame size is at 0x0c, fixed to 0x914 */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x4D41524B: /* "MARK" (loops) */
|
case 0x4D41524B: /* "MARK" (loops) */
|
||||||
if (mark_found) goto fail;
|
mark_offset = offset;
|
||||||
mark_found = 1;
|
|
||||||
|
|
||||||
mark_offset = current_chunk;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x494E5354: /* "INST" (loops) */
|
case 0x494E5354: /* "INST" (loops) */
|
||||||
if (inst_found) goto fail;
|
inst_offset = offset;
|
||||||
inst_found = 1;
|
|
||||||
|
|
||||||
inst_offset = current_chunk;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* spec says we can skip unrecognized chunks */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_chunk += 0x08+chunk_size;
|
offset += chunk_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,26 +252,25 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
|
|
||||||
/* read loop points */
|
/* read loop points */
|
||||||
if (inst_found && mark_found) {
|
if (inst_offset && mark_offset) {
|
||||||
int start_marker;
|
int start_marker;
|
||||||
int end_marker;
|
int end_marker;
|
||||||
/* use the sustain loop */
|
|
||||||
/* if playMode=ForwardLooping */
|
/* use the 'sustain loop', if playMode=ForwardLooping */
|
||||||
if (read_16bitBE(inst_offset+16,streamFile) == 1) {
|
if (read_u16be(inst_offset + 0x08,sf) == 1) {
|
||||||
start_marker = read_16bitBE(inst_offset+18,streamFile);
|
start_marker = read_u16be(inst_offset + 0x0a,sf);
|
||||||
end_marker = read_16bitBE(inst_offset+20,streamFile);
|
end_marker = read_u16be(inst_offset + 0x0c,sf);
|
||||||
/* check for sustain markers != 0 (invalid marker no) */
|
/* check for sustain markers != 0 (invalid marker no) */
|
||||||
if (start_marker && end_marker) {
|
if (start_marker && end_marker) {
|
||||||
/* find start marker */
|
/* find start marker */
|
||||||
loop_start = find_marker(streamFile,mark_offset,start_marker);
|
loop_start = find_marker(sf, mark_offset, start_marker);
|
||||||
loop_end = find_marker(streamFile,mark_offset,end_marker);
|
loop_end = find_marker(sf, mark_offset, end_marker);
|
||||||
|
|
||||||
/* find_marker is type uint32_t as the spec says that's the type
|
/* find_marker is type uint32_t as the spec says that's the type
|
||||||
* of the position value, but it returns a -1 on error, and the
|
* of the position value, but it returns a -1 on error, and the
|
||||||
* loop_start and loop_end variables are int32_t, so the error
|
* loop_start and loop_end variables are int32_t, so the error
|
||||||
* will become apparent.
|
* will become apparent.
|
||||||
* We shouldn't have a loop point that overflows an int32_t
|
* We shouldn't have a loop point that overflows an int32_t anyway. */
|
||||||
* anyway. */
|
|
||||||
loop_flag = 1;
|
loop_flag = 1;
|
||||||
if (loop_start==loop_end)
|
if (loop_start==loop_end)
|
||||||
loop_flag = 0;
|
loop_flag = 0;
|
||||||
@ -304,7 +299,7 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case coding_RELIC: {
|
case coding_RELIC: {
|
||||||
int bitrate = read_16bitBE(start_offset, streamFile);
|
int bitrate = read_u16be(start_offset, sf);
|
||||||
start_offset += 0x02;
|
start_offset += 0x02;
|
||||||
|
|
||||||
vgmstream->codec_data = init_relic(channel_count, bitrate, sample_rate);
|
vgmstream->codec_data = init_relic(channel_count, bitrate, sample_rate);
|
||||||
@ -314,6 +309,7 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
|
|||||||
vgmstream->sample_rate = 44100; /* fixed output */
|
vgmstream->sample_rate = 44100; /* fixed output */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
vgmstream->layout_type = (channel_count > 1) ? layout_interleave : layout_none;
|
vgmstream->layout_type = (channel_count > 1) ? layout_interleave : layout_none;
|
||||||
vgmstream->interleave_block_size = interleave;
|
vgmstream->interleave_block_size = interleave;
|
||||||
@ -326,7 +322,7 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
|
|||||||
vgmstream->meta_type = meta_AIFF;
|
vgmstream->meta_type = meta_AIFF;
|
||||||
|
|
||||||
|
|
||||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user