# HG changeset patch # User Matti Hamalainen # Date 1425441686 -7200 # Node ID b8bfd9fbe1d9e82470cce91d4c7fc449125ecc50 # Parent c023fae92620304541e282e9637ef09ece4ff304 Modularize the XM loader somewhat by splitting to more functions. diff -r c023fae92620 -r b8bfd9fbe1d9 minijss/jloadxm.c --- a/minijss/jloadxm.c Wed Mar 04 04:42:38 2015 +0200 +++ b/minijss/jloadxm.c Wed Mar 04 06:01:26 2015 +0200 @@ -227,8 +227,8 @@ // Convert other values d->npoints = s->npoints; d->sustain = s->sustain; - d->loopS = s->loopS; - d->loopE = s->loopE; + d->loopS = s->loopS; + d->loopE = s->loopE; // Check if the envelope is used if (s->flags & 0x01) @@ -278,6 +278,131 @@ } +static int jssXMLoadInstrument(DMResource *inFile, JSSModule *module, int ninst, int nsample, int *xmConvTable) +{ + XMSample xmS; + JSSInstrument *inst; + + // Read header data + if (!dmf_read_le32(inFile, &xmS.size) || + !dmf_read_le32(inFile, &xmS.loopS) || + !dmf_read_le32(inFile, &xmS.loopL) || + !dmf_read_byte(inFile, &xmS.volume) || + !dmf_read_byte(inFile, (Uint8 *) &xmS.fineTune) || + !dmf_read_byte(inFile, &xmS.type) || + !dmf_read_byte(inFile, &xmS.panning) || + !dmf_read_byte(inFile, (Uint8 *) &xmS.relNote) || + !dmf_read_byte(inFile, &xmS.ARESERVED) || + !dmf_read_str(inFile, &xmS.sampleName, sizeof(xmS.sampleName))) + { + JSSERROR(DMERR_FREAD, DMERR_FREAD, + "Error reading instrument sample header #%d/%d [%d]", + ninst, nsample, module->ninstruments); + } + + if (xmS.size <= 0) + return DMERR_OK; + + // Allocate sample instrument + JSSDEBUG("Allocating sample #%d/%d [%d]\n", + ninst, nsample, module->ninstruments); + + xmConvTable[nsample] = module->ninstruments; + inst = module->instruments[module->ninstruments] = jssAllocateInstrument(); + if (inst == NULL) + { + JSSERROR(DMERR_MALLOC, DMERR_MALLOC, + "Could not allocate sample #%d/%d [%d]\n", + ninst, nsample, module->ninstruments); + } + module->ninstruments++; + + // Copy values + if (xmS.volume > XM_MaxSampleVolume) + { + JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Samp #%d/%d: volume > MAX\n", ninst, nsample); + xmS.volume = XM_MaxSampleVolume; + } + + inst->volume = xmS.volume; + inst->ERelNote = xmS.relNote; + inst->EFineTune = xmS.fineTune; + inst->EPanning = xmS.panning; +#ifndef JSS_LIGHT + inst->desc = jssASCIItoStr(xmS.sampleName, 0, sizeof(xmS.sampleName)); +#endif + + // Convert flags + switch (xmS.type & 0x03) + { + case 0: inst->flags = 0; break; + case 1: inst->flags = jsfLooped; break; + case 2: inst->flags = jsfLooped | jsfBiDi; break; + default: + inst->flags = 0; + JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Samp #%d/%d: Invalid sample type 0x%x\n", + ninst, nsample, xmS.type); + break; + } + + if (xmS.type & 0x10) + { + // 16-bit sample + JSFSET(inst->flags, jsf16bit); + + inst->size = xmS.size / sizeof(Uint16); + inst->loopS = xmS.loopS / sizeof(Uint16); + inst->loopE = ((xmS.loopS + xmS.loopL) / sizeof(Uint16)); + } + else + { + // 8-bit sample + inst->size = xmS.size; + inst->loopS = xmS.loopS; + inst->loopE = (xmS.loopS + xmS.loopL); + } + + if (xmS.loopL == 0) + { + // Always unset loop, if loop length is zero + JSFUNSET(inst->flags, jsfLooped); + } + + if (inst->flags & jsfLooped) + { + if (inst->loopS >= inst->size) + { + JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Samp #%d/%d: loopS >= size (%d >= %d)\n", + ninst, nsample, inst->loopS, inst->size); + JSFUNSET(inst->flags, jsfLooped); + } + + if (inst->loopE > inst->size) + { + JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Samp #%d/%d: loopE > size (%d > %d)\n", + ninst, nsample, inst->loopE, inst->size); + JSFUNSET(inst->flags, jsfLooped); + } + } + + // Allocate memory for sample data + if (inst->flags & jsf16bit) + inst->data = dmCalloc(inst->size, sizeof(Uint16)); + else + inst->data = dmCalloc(inst->size, sizeof(Uint8)); + + if (inst->data == NULL) + JSSERROR(DMERR_MALLOC, DMERR_MALLOC, + "Could not allocate sample data #%d/%d.\n", ninst, nsample); + + return DMERR_OK; +} + + /* Load XM-format extended instrument from file-stream into JSS module's given inst */ static int jssXMLoadExtInstrument(DMResource *inFile, int ninst, JSSModule *module) @@ -299,7 +424,6 @@ int i, nsample, tmp; int xmConvTable[XM_MaxInstruments + 1]; JSSExtInstrument *pEInst; - JSSInstrument *pInst; XMInstrument2 xmI2; // Allocate instrument @@ -397,137 +521,17 @@ // Read sample headers for (nsample = 0; nsample < xmI1.nsamples; nsample++) { - XMSample xmS; - - // Read header data - if (!dmf_read_le32(inFile, &xmS.size) || - !dmf_read_le32(inFile, &xmS.loopS) || - !dmf_read_le32(inFile, &xmS.loopL) || - !dmf_read_byte(inFile, &xmS.volume) || - !dmf_read_byte(inFile, (Uint8 *) &xmS.fineTune) || - !dmf_read_byte(inFile, &xmS.type) || - !dmf_read_byte(inFile, &xmS.panning) || - !dmf_read_byte(inFile, (Uint8 *) &xmS.relNote) || - !dmf_read_byte(inFile, &xmS.ARESERVED) || - !dmf_read_str(inFile, &xmS.sampleName, sizeof(xmS.sampleName))) - { - JSSERROR(DMERR_FREAD, DMERR_FREAD, - "Error reading instrument sample header #%d/%d [%d]", - ninst, nsample, module->ninstruments); - } - - if (xmS.size > 0) - { - // Allocate sample instrument - JSSDEBUG("Allocating sample #%d/%d [%d]\n", - ninst, nsample, module->ninstruments); - - xmConvTable[nsample] = module->ninstruments; - pInst = module->instruments[module->ninstruments] = jssAllocateInstrument(); - if (pInst == NULL) - { - JSSERROR(DMERR_MALLOC, DMERR_MALLOC, - "Could not allocate sample #%d/%d [%d]\n", - ninst, nsample, module->ninstruments); - } - module->ninstruments++; - } else - pInst = NULL; - - // Check and convert sample information - if (pInst != NULL) - { - // Copy values - if (xmS.volume > XM_MaxSampleVolume) - { - JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, - "Samp #%d/%d: volume > MAX\n", ninst, nsample); - xmS.volume = XM_MaxSampleVolume; - } - - pInst->volume = xmS.volume; - pInst->ERelNote = xmS.relNote; - pInst->EFineTune = xmS.fineTune; - pInst->EPanning = xmS.panning; -#ifndef JSS_LIGHT - pInst->desc = jssASCIItoStr(xmS.sampleName, 0, sizeof(xmS.sampleName)); -#endif - - // Convert flags - switch (xmS.type & 0x03) - { - case 0: pInst->flags = 0; break; - case 1: pInst->flags = jsfLooped; break; - case 2: pInst->flags = jsfLooped | jsfBiDi; break; - default: - pInst->flags = 0; - JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, - "Samp #%d/%d: Invalid sample type 0x%x\n", - ninst, nsample, xmS.type); - break; - } - - if (xmS.type & 0x10) - { - // 16-bit sample - JSFSET(pInst->flags, jsf16bit); - - pInst->size = xmS.size / sizeof(Uint16); - pInst->loopS = xmS.loopS / sizeof(Uint16); - pInst->loopE = ((xmS.loopS + xmS.loopL) / sizeof(Uint16)); - } - else - { - // 8-bit sample - pInst->size = xmS.size; - pInst->loopS = xmS.loopS; - pInst->loopE = (xmS.loopS + xmS.loopL); - } - - if (xmS.loopL == 0) - { - // Always unset loop, if loop length is zero - JSFUNSET(pInst->flags, jsfLooped); - } - - if (pInst->flags & jsfLooped) - { - if (pInst->loopS >= pInst->size) - { - JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, - "Samp #%d/%d: loopS >= size (%d >= %d)\n", - ninst, nsample, pInst->loopS, pInst->size); - JSFUNSET(pInst->flags, jsfLooped); - } - - if (pInst->loopE > pInst->size) - { - JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, - "Samp #%d/%d: loopE > size (%d > %d)\n", - ninst, nsample, pInst->loopE, pInst->size); - JSFUNSET(pInst->flags, jsfLooped); - } - } - - - // Allocate memory for sample data - if (pInst->flags & jsf16bit) - pInst->data = dmCalloc(pInst->size, sizeof(Uint16)); - else - pInst->data = dmCalloc(pInst->size, sizeof(Uint8)); - - if (pInst->data == NULL) - JSSERROR(DMERR_MALLOC, DMERR_MALLOC, - "Could not allocate sample data #%d/%d.\n", ninst, nsample); - } + int result; + if ((result = jssXMLoadInstrument(inFile, module, ninst, nsample, xmConvTable)) != DMERR_OK) + return result; } // Read sample data for (nsample = 0; nsample < xmI1.nsamples; nsample++) if (xmConvTable[nsample] != jsetNotSet) { - pInst = module->instruments[xmConvTable[nsample]]; - if (pInst) + JSSInstrument *inst = module->instruments[xmConvTable[nsample]]; + if (inst) { JSSDEBUG("desc....: '%s'\n" "size....: %d\n" @@ -535,20 +539,20 @@ "loopE...: %d\n" "volume..: %d\n" "flags...: %x\n", - pInst->desc, - pInst->size, pInst->loopS, pInst->loopE, - pInst->volume, pInst->flags); + inst->desc, + inst->size, inst->loopS, inst->loopE, + inst->volume, inst->flags); - if (pInst->flags & jsf16bit) + if (inst->flags & jsf16bit) { // Read sampledata - if (dmfread(pInst->data, sizeof(Uint16), pInst->size, inFile) != (size_t) pInst->size) + if (dmfread(inst->data, sizeof(Uint16), inst->size, inFile) != (size_t) inst->size) JSSERROR(DMERR_FREAD, DMERR_FREAD, "Error reading sampledata for instrument #%d/%d, %d words.\n", - ninst, nsample, pInst->size); + ninst, nsample, inst->size); // Convert data - jssDecodeSample16((Uint16 *) pInst->data, pInst->size, + jssDecodeSample16((Uint16 *) inst->data, inst->size, #if (SDL_BYTEORDER == SDL_BIG_ENDIAN) (jsampDelta | jsampSwapEndianess) #else @@ -559,13 +563,13 @@ else { // Read sampledata - if (dmfread(pInst->data, sizeof(Uint8), pInst->size, inFile) != (size_t) pInst->size) + if (dmfread(inst->data, sizeof(Uint8), inst->size, inFile) != (size_t) inst->size) JSSERROR(DMERR_FREAD, DMERR_FREAD, "Error reading sampledata for instrument #%d/%d, %d bytes.\n", - ninst, nsample, pInst->size); + ninst, nsample, inst->size); // Convert data - jssDecodeSample8((Uint8 *) pInst->data, pInst->size, + jssDecodeSample8((Uint8 *) inst->data, inst->size, (jsampDelta | jsampFlipSign)); } } @@ -597,153 +601,18 @@ } } - return 0; + return DMERR_OK; } -/* Load XM-format module from given file-stream - */ -int jssLoadXM(DMResource *inFile, JSSModule **ppModule, BOOL probe) +static int jssXMLoadPatterns(DMResource *inFile, JSSModule *module, XMHeader *xmH) { - JSSModule *module; - XMHeader xmH; - int result, index, tmp; - - assert(ppModule != NULL); - assert(inFile != NULL); - *ppModule = NULL; - - // Try to get the XM-header - if (!dmf_read_str(inFile, &xmH.idMagic, sizeof(xmH.idMagic)) || - !dmf_read_str(inFile, &xmH.songName, sizeof(xmH.songName)) || - !dmf_read_byte(inFile, &xmH.unUsed1A) || - !dmf_read_str(inFile, &xmH.trackerName, sizeof(xmH.trackerName)) || - !dmf_read_le16(inFile, &xmH.version) || - !dmf_read_le32(inFile, &xmH.headSize) || - !dmf_read_le16(inFile, &xmH.norders) || - !dmf_read_le16(inFile, &xmH.defRestartPos) || - !dmf_read_le16(inFile, &xmH.nchannels) || - !dmf_read_le16(inFile, &xmH.npatterns) || - !dmf_read_le16(inFile, &xmH.ninstruments) || - !dmf_read_le16(inFile, &xmH.flags) || - !dmf_read_le16(inFile, &xmH.defSpeed) || - !dmf_read_le16(inFile, &xmH.defTempo)) - return DMERR_FREAD; - - - // Check the fields, none of these are considered fatal - if (strncmp(xmH.idMagic, "Extended Module: ", 17) != 0) - { - if (probe) - return DMERR_NOT_SUPPORTED; - else - JSSERROR(DMERR_NOT_SUPPORTED, DMERR_NOT_SUPPORTED, - "Not a FT2 Extended Module (XM), header signature mismatch!\n"); - } - - if (xmH.version != 0x0104) - { - JSSWARNING(DMERR_NOT_SUPPORTED, DMERR_NOT_SUPPORTED, - "Unsupported version of XM format 0x%04x instead of expected 0x0104.\n", - xmH.version); - } - - if (xmH.unUsed1A != 0x1a) - { - JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, - "Possibly modified or corrupted XM [%x]\n", xmH.unUsed1A); - } - - if (xmH.norders > XM_MaxOrders) - { - JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, - "Number of orders %d > %d, possibly broken module.\n", - xmH.norders, XM_MaxOrders); - xmH.norders = XM_MaxOrders; - } - - if (xmH.norders == 0) - { - JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, - "Number of orders was zero.\n"); - } + int index, result; + XMPattern xmP; - if (xmH.npatterns > XM_MaxPatterns) - { - JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, - "Number of patterns %d > %d, possibly broken module.\n", - xmH.npatterns, XM_MaxPatterns); - xmH.npatterns = XM_MaxPatterns; - } - - if (xmH.npatterns == 0) - { - JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, - "Number of patterns was zero.\n"); - } - - if (xmH.nchannels <= 0 || xmH.nchannels > XM_MaxChannels) - { - JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, - "Number of channels was invalid, %d (should be 1 - %d).\n", - xmH.nchannels, XM_MaxChannels); - } - - if (xmH.ninstruments <= 0 || xmH.ninstruments > XM_MaxInstruments) - { - JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, - "Number of instruments was invalid, %d (should be 1 - %d).\n", - xmH.ninstruments, XM_MaxInstruments); - } - - // Read orders list - if (!dmf_read_str(inFile, &xmH.orderList, sizeof(xmH.orderList))) - { - JSSERROR(DMERR_FREAD, DMERR_FREAD, - "Error reading pattern order list.\n"); - } - - /* Okay, allocate a module structure - */ - module = jssAllocateModule(); - if (module == NULL) - { - JSSERROR(DMERR_MALLOC, DMERR_MALLOC, - "Could not allocate memory for module structure.\n"); - } - *ppModule = module; - - - // Convert and check the header data - module->moduleType = jmdtXM; - module->intVersion = xmH.version; -#ifndef JSS_LIGHT - module->moduleName = jssASCIItoStr(xmH.songName, 0, sizeof(xmH.songName)); - module->trackerName = jssASCIItoStr(xmH.trackerName, 0, sizeof(xmH.trackerName)); -#endif - module->defSpeed = xmH.defSpeed; - module->defTempo = xmH.defTempo; - module->nextInstruments = xmH.ninstruments; - module->ninstruments = 0; - module->npatterns = xmH.npatterns; - module->norders = xmH.norders; - module->nchannels = xmH.nchannels; - module->defFlags = jmdfStereo | jmdfFT2Replay; - module->defRestartPos = xmH.defRestartPos; - - if ((xmH.flags & 1) == 0) - module->defFlags |= jmdfAmigaPeriods; - - // Setup the default pannings - for (index = 0; index < jsetNChannels; index++) - module->defPanning[index] = jchPanMiddle; - - /* Read patterns - */ for (index = 0; index < module->npatterns; index++) { off_t pos, remainder; - XMPattern xmP; // Get the pattern header pos = dmftell(inFile); @@ -798,21 +667,165 @@ */ for (index = 0; index < module->norders; index++) { - tmp = xmH.orderList[index]; + int tmp = xmH->orderList[index]; if (tmp >= module->npatterns || module->patterns[tmp] == NULL) tmp = jsetMaxPatterns; module->orderList[index] = tmp; } - /* Read instruments - */ + return DMERR_OK; +} + + +static int jssXMLoadInstruments(DMResource *inFile, JSSModule *module) +{ + int index; for (index = 0; index < module->nextInstruments; index++) { - result = jssXMLoadExtInstrument(inFile, index, module); + int result = jssXMLoadExtInstrument(inFile, index, module); if (result != 0) JSSERROR(result, result, "Errors while reading instrument #%d\n", index); } + return DMERR_OK; +} + + +/* Load XM-format module from given file-stream + */ +int jssLoadXM(DMResource *inFile, JSSModule **ppModule, BOOL probe) +{ + JSSModule *module; + XMHeader xmH; + int index, result; + + assert(ppModule != NULL); + assert(inFile != NULL); + *ppModule = NULL; + + // Try to get the XM-header + if (!dmf_read_str(inFile, &xmH.idMagic, sizeof(xmH.idMagic)) || + !dmf_read_str(inFile, &xmH.songName, sizeof(xmH.songName)) || + !dmf_read_byte(inFile, &xmH.unUsed1A) || + !dmf_read_str(inFile, &xmH.trackerName, sizeof(xmH.trackerName)) || + !dmf_read_le16(inFile, &xmH.version) || + !dmf_read_le32(inFile, &xmH.headSize) || + !dmf_read_le16(inFile, &xmH.norders) || + !dmf_read_le16(inFile, &xmH.defRestartPos) || + !dmf_read_le16(inFile, &xmH.nchannels) || + !dmf_read_le16(inFile, &xmH.npatterns) || + !dmf_read_le16(inFile, &xmH.ninstruments) || + !dmf_read_le16(inFile, &xmH.flags) || + !dmf_read_le16(inFile, &xmH.defSpeed) || + !dmf_read_le16(inFile, &xmH.defTempo)) + return DMERR_FREAD; + + + // Check the fields, none of these are considered fatal + if (strncmp(xmH.idMagic, "Extended Module: ", 17) != 0) + { + if (probe) + return DMERR_NOT_SUPPORTED; + else + JSSERROR(DMERR_NOT_SUPPORTED, DMERR_NOT_SUPPORTED, + "Not a FT2 Extended Module (XM), header signature mismatch!\n"); + } + + if (xmH.unUsed1A != 0x1a) + { + JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Possibly modified or corrupted XM [%x]\n", xmH.unUsed1A); + } + + if (xmH.norders > XM_MaxOrders) + { + JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Number of orders %d > %d, possibly broken module.\n", + xmH.norders, XM_MaxOrders); + xmH.norders = XM_MaxOrders; + } + + if (xmH.norders == 0) + { + JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Number of orders was zero.\n"); + } + + if (xmH.npatterns > XM_MaxPatterns) + { + JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Number of patterns %d > %d, possibly broken module.\n", + xmH.npatterns, XM_MaxPatterns); + xmH.npatterns = XM_MaxPatterns; + } + + if (xmH.npatterns == 0) + { + JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Number of patterns was zero.\n"); + } + + if (xmH.nchannels <= 0 || xmH.nchannels > XM_MaxChannels) + { + JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Number of channels was invalid, %d (should be 1 - %d).\n", + xmH.nchannels, XM_MaxChannels); + } + + if (xmH.ninstruments <= 0 || xmH.ninstruments > XM_MaxInstruments) + { + JSSWARNING(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Number of instruments was invalid, %d (should be 1 - %d).\n", + xmH.ninstruments, XM_MaxInstruments); + } + + if (!dmf_read_str(inFile, &xmH.orderList, sizeof(xmH.orderList))) + { + JSSERROR(DMERR_FREAD, DMERR_FREAD, + "Error reading pattern order list.\n"); + } + + /* Okay, allocate a module structure + */ + module = jssAllocateModule(); + if (module == NULL) + { + JSSERROR(DMERR_MALLOC, DMERR_MALLOC, + "Could not allocate memory for module structure.\n"); + } + *ppModule = module; + + + // Convert and check the header data + module->moduleType = jmdtXM; + module->intVersion = xmH.version; +#ifndef JSS_LIGHT + module->moduleName = jssASCIItoStr(xmH.songName, 0, sizeof(xmH.songName)); + module->trackerName = jssASCIItoStr(xmH.trackerName, 0, sizeof(xmH.trackerName)); +#endif + module->defSpeed = xmH.defSpeed; + module->defTempo = xmH.defTempo; + module->nextInstruments = xmH.ninstruments; + module->ninstruments = 0; + module->npatterns = xmH.npatterns; + module->norders = xmH.norders; + module->nchannels = xmH.nchannels; + module->defFlags = jmdfStereo | jmdfFT2Replay; + module->defRestartPos = xmH.defRestartPos; + + if ((xmH.flags & 1) == 0) + module->defFlags |= jmdfAmigaPeriods; + + // Setup the default pannings + for (index = 0; index < jsetNChannels; index++) + module->defPanning[index] = jchPanMiddle; + + // Load rest of the module + if ((result = jssXMLoadPatterns(inFile, module, &xmH)) != DMERR_OK) + return result; + + if ((result = jssXMLoadInstruments(inFile, module)) != DMERR_OK) + return result; return DMERR_OK; }