Mercurial > hg > dmlib
diff jloadjss.c @ 0:32250b436bca
Initial re-import.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 28 Sep 2012 01:54:23 +0300 |
parents | |
children | 6bf5220fa47e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jloadjss.c Fri Sep 28 01:54:23 2012 +0300 @@ -0,0 +1,533 @@ +/* + * miniJSS - JSSMOD module loader + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2007-2009 Tecnic Software productions (TNSP) + */ +#include "jssmod.h" +#include <string.h> + + +#ifdef JM_SUP_PATMODE_ALL +#define JM_SUP_PATMODE_1 1 +#define JM_SUP_PATMODE_2 1 +#define JM_SUP_PATMODE_3 1 +#define JM_SUP_PATMODE_4 1 +#define JM_SUP_PATMODE_5 1 +#endif + + +static BOOL jsGetBufData(Uint8 **buf, size_t *bufLeft, void *data, const size_t dataSize) +{ + if (*bufLeft >= dataSize) + { + memcpy(data, *buf, dataSize); + *buf += dataSize; + *bufLeft -= dataSize; + return TRUE; + } + else + return FALSE; +} + + +static BOOL jsGetBufByte(Uint8 **buf, size_t *bufLeft, Uint8 *data) +{ + if (*bufLeft > 0) + { + *data = **buf; + (*buf)++; + (*bufLeft)--; + return TRUE; + } + else + return FALSE; +} + + +#define JSGETBUF(XV, XT) if (!jsGetBufData(buf, bufLeft, XV, sizeof(XT))) return DMERR_OUT_OF_DATA +#define JSGETBYTE(XV) if (!jsGetBufByte(buf, bufLeft, XV)) return DMERR_OUT_OF_DATA + + +#if defined(JM_SUP_PATMODE_ALL) || defined(JM_SUP_PATMODE_1) || defined(JM_SUP_PATMODE_3) +static int jssGetConvertedNote(Uint8 **buf, size_t *bufLeft, JSSNote *note) +{ + Uint8 tmp; + + JSGETBYTE(&tmp); + + if (tmp == 127) + note->note = jsetNoteOff; + else if (tmp == 0) + note->note = jsetNotSet; + else + note->note = tmp - 1; + + JSGETBYTE(&tmp); + note->instrument = (tmp > 0) ? tmp - 1 : jsetNotSet; + + JSGETBYTE(&tmp); + note->volume = (tmp > 0) ? tmp - 1 : jsetNotSet; + + JSGETBYTE(&tmp); + note->effect = (tmp > 0) ? tmp - 1 : jsetNotSet; + + JSGETBYTE(&tmp); + note->param = (tmp == 0 && note->effect == jsetNotSet) ? jsetNotSet : tmp; + + return DMERR_OK; +} +#endif + + +#if defined(JM_SUP_PATMODE_ALL) || defined(JM_SUP_PATMODE_2) || defined(JM_SUP_PATMODE_4) +static int jssGetCompressedNote(Uint8 **buf, size_t *bufLeft, JSSNote *note) +{ + Uint8 packb, tmp; + + JSGETBYTE(&packb); + if (packb & 0x80) + { + if (packb & COMP_NOTE) + { + JSGETBYTE(&tmp); + if (tmp == 127) + note->note = jsetNoteOff; + else + note->note = tmp; + } + + if (packb & COMP_INSTRUMENT) + { + JSGETBYTE(&tmp); + note->instrument = tmp; + } + + if (packb & COMP_VOLUME) + { + JSGETBYTE(&tmp); + note->volume = tmp; + } + + if (packb & COMP_EFFECT) + { + JSGETBYTE(&tmp); + note->effect = tmp; + note->param = 0; + } + + if (packb & COMP_PARAM) + { + JSGETBYTE(&tmp); + note->param = tmp; + } + } + else + { + tmp = packb; + + if (tmp == 127) + note->note = jsetNoteOff; + else if (tmp == 0) + note->note = jsetNotSet; + else + note->note = tmp - 1; + + JSGETBYTE(&tmp); + note->instrument = (tmp > 0) ? tmp - 1 : jsetNotSet; + + JSGETBYTE(&tmp); + note->volume = (tmp > 0) ? tmp - 1 : jsetNotSet; + + JSGETBYTE(&tmp); + note->effect = (tmp > 0) ? tmp - 1 : jsetNotSet; + + JSGETBYTE(&tmp); + note->param = (tmp == 0 && note->effect == jsetNotSet) ? jsetNotSet : tmp; + } + + return DMERR_OK; +} +#endif + + +#if defined(JM_SUP_PATMODE_ALL) || defined(JM_SUP_PATMODE_2) +static int jssGetPatternCompHoriz(Uint8 *buf, size_t *bufLeft, JSSPattern *pattern) +{ + int row, channel; + + assert(buf != NULL); + assert(pattern != NULL); + + for (row = 0; row < pattern->nrows; row++) + for (channel = 0; channel < pattern->nchannels; channel++) + { + JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + int res = jssGetCompressedNote(&buf, bufLeft, note); + if (res != DMERR_OK) + JSSERROR(res, res, "Error uncompressing note on row=%d, chn=%d\n", row, channel); + } + + return DMERR_OK; +} +#endif + + +#if defined(JM_SUP_PATMODE_ALL) || defined(JM_SUP_PATMODE_4) +static int jssGetPatternCompVert(Uint8 *buf, size_t *bufLeft, JSSPattern *pattern) +{ + int row, channel; + + assert(buf != NULL); + assert(pattern != NULL); + + for (channel = 0; channel < pattern->nchannels; channel++) + for (row = 0; row < pattern->nrows; row++) + { + JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + int res = jssGetCompressedNote(&buf, bufLeft, note); + if (res != DMERR_OK) + JSSERROR(res, res, "Error uncompressing note on row=%d, chn=%d\n", row, channel); + } + + return DMERR_OK; +} +#endif + + +#if defined(JM_SUP_PATMODE_ALL) || defined(JM_SUP_PATMODE_1) +static int jssGetPatternRawHoriz(Uint8 *buf, size_t *bufLeft, JSSPattern *pattern) +{ + int row, channel; + + assert(buf != NULL); + assert(pattern != NULL); + + for (row = 0; row < pattern->nrows; row++) + for (channel = 0; channel < pattern->nchannels; channel++) + { + JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + int res = jssGetConvertedNote(&buf, bufLeft, note); + if (res != DMERR_OK) + JSSERROR(res, res, "Error converting note on row=%d, chn=%d\n", row, channel); + } + + return DMERR_OK; +} +#endif + + +#if defined(JM_SUP_PATMODE_ALL) || defined(JM_SUP_PATMODE_3) +static int jssGetPatternRawVert(Uint8 *buf, size_t *bufLeft, JSSPattern *pattern) +{ + int row, channel; + + assert(buf != NULL); + assert(pattern != NULL); + + for (channel = 0; channel < pattern->nchannels; channel++) + for (row = 0; row < pattern->nrows; row++) + { + JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + int res = jssGetConvertedNote(&buf, bufLeft, note); + if (res != DMERR_OK) + JSSERROR(res, res, "Error converting note on row=%d, chn=%d\n", row, channel); + } + + return DMERR_OK; +} +#endif + + +#if defined(JM_SUP_PATMODE_ALL) || defined(JM_SUP_PATMODE_5) +static int jssGetPatternRawVertElem(Uint8 *buf, size_t *bufLeft, JSSPattern *pattern) +{ + int row, channel; + + assert(buf != NULL); + assert(pattern != NULL); + + return DMERR_OK; +} +#endif + + +#undef JSGETBUF +#undef JSGETBYTE +#define JSGETBUF(XV, XT) do { \ + if (!jsGetBufData(&buf, &bufLeft, XV, sizeof(XT))) \ + JSSERROR(DMERR_OUT_OF_DATA, DMERR_OUT_OF_DATA, \ + "Out of data at getting " # XT " (%d bytes)\n", sizeof(XT)); \ +} while (0) +#define JSGETBYTE(XV) if (!jsGetBufByte(&buf, &bufLeft, XV)) return DMERR_OUT_OF_DATA + + +#ifdef JM_SUP_EXT_INSTR +static void jssCopyEnvelope(JSSEnvelope *e, JSSMODEnvelope *je) +{ + int i; + + e->flags = je->flags; + e->npoints = je->npoints; + e->sustain = je->sustain; + e->loopS = je->loopS; + e->loopE = je->loopE; + + for (i = 0; i < je->npoints; i++) + { + e->points[i].frame = je->points[i].frame; + e->points[i].value = je->points[i].value; + } +} +#endif + + +int jssLoadJSSMOD(Uint8 *bufStart, const size_t bufSize, JSSModule **ppModule) +{ + JSSModule *module; + JSSMODHeader jssH; + Uint8 *buf = bufStart; + size_t bufLeft = bufSize; + int index; + + assert(ppModule != NULL); + assert(bufStart != NULL); + *ppModule = NULL; + + // Check the JSSMOD header + JSGETBUF(&jssH, JSSMODHeader); + + if (memcmp(jssH.idMagic, "JM", 2) != 0) + { + JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Not a valid JSSMOD file, header signature missing!\n"); + } + + if (jssH.idVersion != JSSMOD_VERSION) + { + JSSERROR(DMERR_VERSION, DMERR_VERSION, + "Unsupported version of JSSMOD 0x%4x, this version only supports 0x%4x!\n", + jssH.idVersion, JSSMOD_VERSION); + } + + // Allocate the module + module = jssAllocateModule(); + if (module == NULL) + { + JSSERROR(DMERR_MALLOC, DMERR_MALLOC, + "Could not allocate memory for module structure.\n"); + } + *ppModule = module; + + // Copy header information + module->norders = jssH.norders; + module->npatterns = jssH.npatterns; + module->nchannels = jssH.nchannels; + module->nextInstruments = jssH.nextInstruments; + module->ninstruments = jssH.ninstruments; + module->defFlags = jssH.defFlags; + module->intVersion = jssH.intVersion; + module->defRestartPos = jssH.defRestartPos; + module->defSpeed = jssH.defSpeed; + module->defTempo = jssH.defTempo; + + // Get the orders list + for (index = 0; index < module->norders; index++) + { + Sint16 order; + JSGETBUF(&order, Sint16); + module->orderList[index] = order; + } + + // Parse the patterns + for (index = 0; index < module->npatterns; index++) + { + JSSMODPattern jssP; + int result = DMERR_INVALID_DATA; + size_t bufSize; + + // Get header and check size + JSGETBUF(&jssP, JSSMODPattern); + bufSize = jssP.size; + if (bufLeft < jssP.size) + { + JSSERROR(DMERR_OUT_OF_DATA, DMERR_OUT_OF_DATA, + "Out of data for pattern #%d.\n", index); + } + + // Allocate pattern + module->patterns[index] = jssAllocatePattern(jssP.nrows, module->nchannels); + if (module->patterns[index] == NULL) + { + JSSERROR(DMERR_MALLOC, DMERR_MALLOC, + "Could not allocate memory for pattern #%d.\n", index); + } + + // Get pattern data + switch (jssH.patMode) + { +#ifdef JM_SUP_PATMODE_1 + case PATMODE_RAW_HORIZ: + result = jssGetPatternRawHoriz(buf, &bufSize, module->patterns[index]); + break; +#endif +#ifdef JM_SUP_PATMODE_2 + case PATMODE_COMP_HORIZ: + result = jssGetPatternCompHoriz(buf, &bufSize, module->patterns[index]); + break; +#endif +#ifdef JM_SUP_PATMODE_3 + case PATMODE_RAW_VERT: + result = jssGetPatternRawVert(buf, &bufSize, module->patterns[index]); + break; +#endif +#ifdef JM_SUP_PATMODE_4 + case PATMODE_COMP_VERT: + result = jssGetPatternCompVert(buf, &bufSize, module->patterns[index]); + break; +#endif +#ifdef JM_SUP_PATMODE_5 + case PATMODE_RAW_ELEM: + result = jssGetPatternRawVertElem(buf, &bufSize, module->patterns[index]); + break; +#endif + default: + JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Unsupported pattern mode %d. Check compilation options.", jssH.patMode); + break; + } + + if (bufSize > 0) + { + JSSWARNING(DMERR_EXTRA_DATA, DMERR_EXTRA_DATA, + "Unparsed data after pattern (%d bytes), possibly broken file.\n", bufSize); + } + + if (result != DMERR_OK) + { + JSSERROR(result, result, "Error in unpacking pattern #%i data\n", index); + } + + buf += jssP.size; + bufLeft -= jssP.size; + } + +#ifdef JM_SUP_EXT_INSTR + // Read extended instruments + for (index = 0; index < module->nextInstruments; index++) + { + JSSMODExtInstrument jssE; + JSSExtInstrument *einst; + int i; + + JSGETBUF(&jssE, JSSMODExtInstrument); + + if ((einst = jssAllocateExtInstrument()) == NULL) + { + JSSERROR(DMERR_MALLOC, DMERR_MALLOC, + "Could not allocate extended instrument structure #%i\n", index); + } + + module->extInstruments[index] = einst; + + einst->nsamples = jssE.nsamples; + einst->vibratoType = jssE.vibratoType; + einst->vibratoSweep = jssE.vibratoSweep; + einst->vibratoDepth = jssE.vibratoDepth; + einst->vibratoRate = jssE.vibratoRate; + einst->fadeOut = jssE.fadeOut; + + for (i = 0; i < jsetNNotes; i++) + { + int snum = jssE.sNumForNotes[i]; + einst->sNumForNotes[i] = (snum > 0) ? snum : jsetNotSet; + } + + jssCopyEnvelope(&(einst->volumeEnv), &jssE.volumeEnv); + jssCopyEnvelope(&(einst->panningEnv), &jssE.panningEnv); + } + +#ifdef JM_SUP_INSTR + // Read sample instrument headers + for (index = 0; index < module->ninstruments; index++) + { + JSSMODInstrument jssI; + JSSInstrument *inst; + + JSGETBUF(&jssI, JSSMODInstrument); + + if ((inst = jssAllocateInstrument()) == NULL) + { + JSSERROR(DMERR_MALLOC, DMERR_MALLOC, + "Could not allocate instrument structure #%i\n", index); + } + + module->instruments[index] = inst; + + inst->size = jssI.size; + inst->loopS = jssI.loopS; + inst->loopE = jssI.loopE; + inst->volume = jssI.volume; + inst->flags = jssI.flags; + inst->C4BaseSpeed = jssI.C4BaseSpeed; + inst->ERelNote = jssI.ERelNote; + inst->EFineTune = jssI.EFineTune; + inst->EPanning = jssI.EPanning; + inst->hasData = jssI.hasData; + inst->convFlags = jssI.convFlags; + } + +#ifdef JM_SUP_SAMPLES + // Read sample data + for (index = 0; index < module->ninstruments; index++) + { + JSSInstrument *inst = module->instruments[index]; + + if (inst && inst->hasData) + { + size_t sz; + + // Calculate data size + if (inst->flags & jsf16bit) + sz = inst->size * sizeof(Uint16); + else + sz = inst->size * sizeof(Uint8); + + // Check if we can get as much? + if (bufLeft < sz) + { + JSSERROR(DMERR_OUT_OF_DATA, DMERR_OUT_OF_DATA, + "Out of data for instrument sample #%d (%d < %d)\n", + index, bufLeft, sz); + } + + // Allocate + if ((inst->data = dmMalloc(sz)) == NULL) + { + JSSERROR(DMERR_MALLOC, DMERR_MALLOC, + "Could not allocate sample data #%d\n", index); + } + + // Copy data + memcpy(inst->data, buf, sz); + buf += sz; + bufLeft -= sz; + + // Convert, if needed + if (inst->flags & jsf16bit) + jssDecodeSample16(inst->data, inst->size, inst->convFlags); + else + jssDecodeSample8(inst->data, inst->size, inst->convFlags); + } + } +#else +#warning Not including JSSMOD sample loading! +#endif // JM_SUP_SAMPLES +#else +#warning Not including JSSMOD instrument loading! +#endif // JM_SUP_INSTR +#else +#warning Not including JSSMOD ext.instrument loading! +#endif // JM_SUP_EXT_INSTR + + return DMERR_OK; +}