changeset 1124:b8bfd9fbe1d9

Modularize the XM loader somewhat by splitting to more functions.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 04 Mar 2015 06:01:26 +0200
parents c023fae92620
children 44ed439b1c6b
files minijss/jloadxm.c
diffstat 1 files changed, 294 insertions(+), 281 deletions(-) [+]
line wrap: on
line diff
--- 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;
 }