Print SF2 text INFO chunks

This commit is contained in:
Chris Robinson 2014-07-01 00:36:44 -07:00
parent c06bb88756
commit 3c6752e765
2 changed files with 95 additions and 52 deletions

View File

@ -17,8 +17,13 @@ typedef struct Reader {
void *ptr; void *ptr;
int error; int error;
} Reader; } Reader;
#define READ(x_, buf_, len_) ((x_)->cb((buf_), (len_), (x_)->ptr)) inline size_t Reader_read(Reader *self, void *buf, size_t len)
#define READERR(x_) ((x_)->error) {
size_t got = (!self->error) ? self->cb(buf, len, self->ptr) : 0;
if(got < len) self->error = 1;
return got;
}
#define READERR(x_) ((x_)->error)
ALboolean loadSf2(Reader *stream, struct ALsoundfont *sfont, ALCcontext *context); ALboolean loadSf2(Reader *stream, struct ALsoundfont *sfont, ALCcontext *context);

View File

@ -12,34 +12,27 @@
#include "midi/base.h" #include "midi/base.h"
extern inline size_t Reader_read(Reader *self, void *buf, size_t len);
static ALuint read_le32(Reader *stream) static ALuint read_le32(Reader *stream)
{ {
ALubyte buf[4]; ALubyte buf[4];
if(READ(stream, buf, 4) != 4) if(Reader_read(stream, buf, 4) != 4)
{
READERR(stream) = 1;
return 0; return 0;
}
return (buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0]; return (buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0];
} }
static ALushort read_le16(Reader *stream) static ALushort read_le16(Reader *stream)
{ {
ALubyte buf[2]; ALubyte buf[2];
if(READ(stream, buf, 2) != 2) if(Reader_read(stream, buf, 2) != 2)
{
READERR(stream) = 1;
return 0; return 0;
}
return (buf[1]<<8) | buf[0]; return (buf[1]<<8) | buf[0];
} }
static ALubyte read_8(Reader *stream) static ALubyte read_8(Reader *stream)
{ {
ALubyte buf[1]; ALubyte buf[1];
if(READ(stream, buf, 1) != 1) if(Reader_read(stream, buf, 1) != 1)
{
READERR(stream) = 1;
return 0; return 0;
}
return buf[0]; return buf[0];
} }
static void skip(Reader *stream, ALuint amt) static void skip(Reader *stream, ALuint amt)
@ -47,13 +40,7 @@ static void skip(Reader *stream, ALuint amt)
while(amt > 0 && !READERR(stream)) while(amt > 0 && !READERR(stream))
{ {
char buf[4096]; char buf[4096];
size_t got; amt -= Reader_read(stream, buf, minu(sizeof(buf), amt));
got = READ(stream, buf, minu(sizeof(buf), amt));
if(got == 0 || got > amt)
READERR(stream) = 1;
amt -= (ALuint)got;
} }
} }
@ -167,8 +154,7 @@ typedef struct PresetHeader {
} PresetHeader; } PresetHeader;
static void PresetHeader_read(PresetHeader *self, Reader *stream) static void PresetHeader_read(PresetHeader *self, Reader *stream)
{ {
if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName)) Reader_read(stream, self->mName, sizeof(self->mName));
READERR(stream) = 1;
self->mPreset = read_le16(stream); self->mPreset = read_le16(stream);
self->mBank = read_le16(stream); self->mBank = read_le16(stream);
self->mZoneIdx = read_le16(stream); self->mZoneIdx = read_le16(stream);
@ -183,13 +169,12 @@ typedef struct InstrumentHeader {
} InstrumentHeader; } InstrumentHeader;
static void InstrumentHeader_read(InstrumentHeader *self, Reader *stream) static void InstrumentHeader_read(InstrumentHeader *self, Reader *stream)
{ {
if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName)) Reader_read(stream, self->mName, sizeof(self->mName));
READERR(stream) = 1;
self->mZoneIdx = read_le16(stream); self->mZoneIdx = read_le16(stream);
} }
typedef struct SampleHeader { typedef struct SampleHeader {
ALchar mName[20]; // 20 bytes ALchar mName[20];
ALuint mStart; ALuint mStart;
ALuint mEnd; ALuint mEnd;
ALuint mStartloop; ALuint mStartloop;
@ -202,8 +187,7 @@ typedef struct SampleHeader {
} SampleHeader; } SampleHeader;
static void SampleHeader_read(SampleHeader *self, Reader *stream) static void SampleHeader_read(SampleHeader *self, Reader *stream)
{ {
if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName)) Reader_read(stream, self->mName, sizeof(self->mName));
READERR(stream) = 1;
self->mStart = read_le32(stream); self->mStart = read_le32(stream);
self->mEnd = read_le32(stream); self->mEnd = read_le32(stream);
self->mStartloop = read_le32(stream); self->mStartloop = read_le32(stream);
@ -976,6 +960,22 @@ static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCco
GenModList_Destruct(&gzone); GenModList_Destruct(&gzone);
} }
static size_t printStringChunk(Reader *stream, const RiffHdr *chnk, const char *title)
{
size_t len = 0;
if(chnk->mSize == 0 || (chnk->mSize&1))
ERR("Invalid %c%c%c%c size: %d\n", FOURCCARGS(chnk->mCode), chnk->mSize);
else
{
char *str = calloc(1, chnk->mSize+1);
len = Reader_read(stream, str, chnk->mSize);
TRACE("%s: %s\n", title, str);
free(str);
}
return len;
}
ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context) ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
{ {
ALsfpreset **presets = NULL; ALsfpreset **presets = NULL;
@ -1006,21 +1006,37 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
list.mSize -= 4; list.mSize -= 4;
while(list.mSize > 0 && !READERR(stream)) while(list.mSize > 0 && !READERR(stream))
{ {
RiffHdr info; RiffHdr chnk;
RiffHdr_read(&info, stream); if(list.mSize < 8)
list.mSize -= 8;
if(info.mCode == FOURCC('i','f','i','l'))
{ {
if(info.mSize != 4) WARN("Unexpected end of INFO list (%u extra bytes)\n", list.mSize);
ERR("Invalid ifil chunk size: %d\n", info.mSize); skip(stream, list.mSize);
list.mSize = 0;
break;
}
RiffHdr_read(&chnk, stream);
list.mSize -= 8;
if(list.mSize < chnk.mSize)
{
WARN("INFO sub-chunk '%c%c%c%c' has %u bytes, but only %u bytes remain\n",
FOURCCARGS(chnk.mCode), chnk.mSize, list.mSize);
skip(stream, list.mSize);
list.mSize = 0;
break;
}
list.mSize -= chnk.mSize;
if(chnk.mCode == FOURCC('i','f','i','l'))
{
if(chnk.mSize != 4)
ERR("Invalid ifil chunk size: %d\n", chnk.mSize);
else else
{ {
ALushort major = read_le16(stream); ALushort major = read_le16(stream);
ALushort minor = read_le16(stream); ALushort minor = read_le16(stream);
chnk.mSize -= 4;
list.mSize -= 4;
info.mSize -= 4;
if(major != 2) if(major != 2)
ERROR_GOTO(error, "Unsupported SF2 format version: %d.%02d\n", major, minor); ERROR_GOTO(error, "Unsupported SF2 format version: %d.%02d\n", major, minor);
@ -1029,26 +1045,48 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
sfont.ifil = (major<<16) | minor; sfont.ifil = (major<<16) | minor;
} }
} }
else if(info.mCode == FOURCC('i','r','o','m')) else if(chnk.mCode == FOURCC('i','r','o','m'))
{ {
if(info.mSize == 0 || (info.mSize&1)) if(chnk.mSize == 0 || (chnk.mSize&1))
ERR("Invalid irom size: %d\n", info.mSize); ERR("Invalid irom size: %d\n", chnk.mSize);
else else
{ {
free(sfont.irom); free(sfont.irom);
sfont.irom = calloc(1, info.mSize+1); sfont.irom = calloc(1, chnk.mSize+1);
READ(stream, sfont.irom, info.mSize); chnk.mSize -= Reader_read(stream, sfont.irom, chnk.mSize);
list.mSize -= info.mSize;
info.mSize -= info.mSize;
TRACE("SF2 ROM ID: %s\n", sfont.irom); TRACE("SF2 ROM ID: %s\n", sfont.irom);
} }
} }
else else
TRACE("Skipping INFO sub-chunk '%c%c%c%c' (%u bytes)\n", FOURCCARGS(info.mCode), info.mSize); {
list.mSize -= info.mSize; static const struct {
skip(stream, info.mSize); ALuint code;
char title[16];
} listinfos[] = {
{ FOURCC('i','s','n','g'), "Engine ID" },
{ FOURCC('I','N','A','M'), "Name" },
{ FOURCC('I','C','R','D'), "Creation Date" },
{ FOURCC('I','E','N','G'), "Creator" },
{ FOURCC('I','P','R','D'), "Product ID" },
{ FOURCC('I','C','O','P'), "Copyright" },
{ FOURCC('I','C','M','T'), "Comment" },
{ FOURCC('I','S','F','T'), "Created With" },
{ 0, "" },
};
for(i = 0;listinfos[i].code;i++)
{
if(listinfos[i].code == chnk.mCode)
{
chnk.mSize -= printStringChunk(stream, &chnk, listinfos[i].title);
break;
}
}
if(!listinfos[i].code)
TRACE("Skipping INFO sub-chunk '%c%c%c%c' (%u bytes)\n", FOURCCARGS(chnk.mCode), chnk.mSize);
}
skip(stream, chnk.mSize);
} }
if(READERR(stream) != 0) if(READERR(stream) != 0)
@ -1074,17 +1112,18 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
if(smpl.mSize > list.mSize) if(smpl.mSize > list.mSize)
ERROR_GOTO(error, "Invalid Format, sample chunk size mismatch\n"); ERROR_GOTO(error, "Invalid Format, sample chunk size mismatch\n");
list.mSize -= smpl.mSize;
buffer = NewBuffer(context); buffer = NewBuffer(context);
if(!buffer) if(!buffer)
SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, error); SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, error);
/* Sample rate it unimportant, the individual fontsounds will specify it. */ /* Sample rate is unimportant, the individual fontsounds will specify it. */
if((err=LoadData(buffer, 22050, AL_MONO16_SOFT, smpl.mSize/2, UserFmtMono, UserFmtShort, NULL, 1, AL_FALSE)) != AL_NO_ERROR) if((err=LoadData(buffer, 22050, AL_MONO16_SOFT, smpl.mSize/2, UserFmtMono, UserFmtShort, NULL, 1, AL_FALSE)) != AL_NO_ERROR)
SET_ERROR_AND_GOTO(context, err, error); SET_ERROR_AND_GOTO(context, err, error);
ptr = buffer->data; ptr = buffer->data;
if(IS_LITTLE_ENDIAN) if(IS_LITTLE_ENDIAN)
READ(stream, ptr, smpl.mSize); smpl.mSize -= Reader_read(stream, ptr, smpl.mSize);
else else
{ {
ALuint total = 0; ALuint total = 0;
@ -1094,14 +1133,13 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
ALuint todo = minu(smpl.mSize-total, sizeof(buf)); ALuint todo = minu(smpl.mSize-total, sizeof(buf));
ALuint i; ALuint i;
READ(stream, buf, todo); smpl.mSize -= Reader_read(stream, buf, todo);
for(i = 0;i < todo;i++) for(i = 0;i < todo;i++)
ptr[total+i] = buf[i^1]; ptr[total+i] = buf[i^1];
total += todo; total += todo;
} }
} }
list.mSize -= smpl.mSize;
skip(stream, list.mSize); skip(stream, list.mSize);
} }