History

Support loading XMs with >32 chans and instrs. with >16 samps.

...but discard the extra channels and samples! Also did some other fixes.

Olav Sørensen committed 6 years ago

Commit 09ef04f1 parent 2f4495e1 file · +190 −89Browse files

Unified · Split

src/ft2_module_loader.c+190−89
@@ -136,17 +136,18 @@ static SDL_Thread *thread; · 135 unmodified lines
136 136
137// these temporarily read to, then copied to real struct if load was OK (should not need to be volatile'd)137// these temporarily read to, then copied to real struct if load was OK (should not need to be volatile'd)
138static int16_t pattLensTmp[MAX_PATTERNS];138static int16_t pattLensTmp[MAX_PATTERNS];
139static uint32_t extraSampleLengths[32-MAX_SMP_PER_INST]; // ModPlug Tracker & OpenMPT supports up to 32 samples per instrument in .XM
139static tonTyp *pattTmp[MAX_PATTERNS];140static tonTyp *pattTmp[MAX_PATTERNS];
140static instrTyp *instrTmp[1 + MAX_INST];141static instrTyp *instrTmp[1+MAX_INST];
141static songTyp songTmp;142static songTyp songTmp;
142 143
143static void setupLoadedModule(void);144static void setupLoadedModule(void);
144static void freeTmpModule(void);145static void freeTmpModule(void);
145static bool loadInstrHeader(FILE *f, uint16_t i);146static bool loadInstrHeader(FILE *f, uint16_t i, bool externalThreadFlag);
146static bool loadInstrSample(FILE *f, uint16_t i);147static bool loadInstrSample(FILE *f, uint16_t i, bool externalThreadFlag);
147void unpackPatt(uint8_t *dst, uint8_t *src, uint16_t len, int32_t antChn);148void unpackPatt(uint8_t *dst, uint8_t *src, uint16_t len, int32_t antChn);
148static bool tmpPatternEmpty(uint16_t nr);149static bool tmpPatternEmpty(uint16_t nr);
149static bool loadPatterns(FILE *f, uint16_t antPtn);150static bool loadPatterns(FILE *f, uint16_t antPtn, bool externalThreadFlag);
150 151
151void checkSampleRepeat(sampleTyp *s);152void checkSampleRepeat(sampleTyp *s);
152 153
@@ -160,13 +161,11 @@ static bool allocateTmpInstr(int16_t nr) · 7 unmodified lines
160 if (instrTmp[nr] != NULL)161 if (instrTmp[nr] != NULL)
161 return false; // already allocated162 return false; // already allocated
162 163
163 p = (instrTyp *)malloc(sizeof (instrTyp));164 p = (instrTyp *)calloc(1, sizeof (instrTyp));
164 if (p == NULL)165 if (p == NULL)
165 return false;166 return false;
166 167
167 memset(p, 0, sizeof (instrTyp));168 for (int8_t i = 0; i < MAX_SMP_PER_INST; i++) // set standard sample pan/vol
168
169 for (int8_t i = 0; i < 16; i++) // set standard sample pan/vol
170 {169 {
171 p->samp[i].pan = 128;170 p->samp[i].pan = 128;
172 p->samp[i].vol = 64;171 p->samp[i].vol = 64;
@@ -213,7 +212,7 @@ static uint8_t getModType(uint8_t *numChannels, const char *id) · 40 unmodified lines
213 return modFormat;212 return modFormat;
214}213}
215 214
216static bool loadMusicMOD(FILE *f, uint32_t fileLength, bool fromExternalThread)215static bool loadMusicMOD(FILE *f, uint32_t fileLength, bool externalThreadFlag)
217{216{
218 char ID[16];217 char ID[16];
219 bool mightBeSTK, lateSTKVerFlag, veryLateSTKVerFlag;218 bool mightBeSTK, lateSTKVerFlag, veryLateSTKVerFlag;
@@ -226,7 +225,7 @@ static bool loadMusicMOD(FILE *f, uint32_t fileLength, bool fromExternalThread) · 6 unmodified lines
226 songMOD15HeaderTyp h_MOD15;225 songMOD15HeaderTyp h_MOD15;
227 int16_t (*showMsg)(int16_t, const char *, const char *);226 int16_t (*showMsg)(int16_t, const char *, const char *);
228 227
229 showMsg = fromExternalThread ? okBoxThreadSafe : okBox;228 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
230 229
231 veryLateSTKVerFlag = false; // "DFJ SoundTracker III" nad later230 veryLateSTKVerFlag = false; // "DFJ SoundTracker III" nad later
232 lateSTKVerFlag = false; // "TJC SoundTracker II" and later231 lateSTKVerFlag = false; // "TJC SoundTracker II" and later
@@ -318,7 +317,7 @@ static bool loadMusicMOD(FILE *f, uint32_t fileLength, bool fromExternalThread) · 85 unmodified lines
318 }317 }
319 318
320 if (modFormat == FORMAT_MK && songTmp.len == 129)319 if (modFormat == FORMAT_MK && songTmp.len == 129)
321 songTmp.len = 127; // fixes a specific copy of beatwave.mod320 songTmp.len = 127; // fixes a specific copy of beatwave.mod (FIXME: Do we want to keep this digsuting hack?)
322 321
323 if (songTmp.antChn == 0 || songTmp.len < 1 || songTmp.len > 128 || (mightBeSTK && songTmp.repS > 220))322 if (songTmp.antChn == 0 || songTmp.len < 1 || songTmp.len > 128 || (mightBeSTK && songTmp.repS > 220))
324 {323 {
@@ -735,7 +734,7 @@ static uint8_t stmTempoToBPM(uint8_t tempo) // ported from original ST2.3 replay · 410 unmodified lines
735 return (uint8_t)CLAMP(bpm, 32, 255); // result can be slightly off, but close enough...734 return (uint8_t)CLAMP(bpm, 32, 255); // result can be slightly off, but close enough...
736}735}
737 736
738static bool loadMusicSTM(FILE *f, uint32_t fileLength, bool fromExternalThread)737static bool loadMusicSTM(FILE *f, uint32_t fileLength, bool externalThreadFlag)
739{738{
740 uint8_t typ, tempo;739 uint8_t typ, tempo;
741 int16_t i, j, k, ap, tmp;740 int16_t i, j, k, ap, tmp;
@@ -745,19 +744,19 @@ static bool loadMusicSTM(FILE *f, uint32_t fileLength, bool fromExternalThread) · 3 unmodified lines
745 songSTMHeaderTyp h_STM;744 songSTMHeaderTyp h_STM;
746 int16_t (*showMsg)(int16_t, const char *, const char *);745 int16_t (*showMsg)(int16_t, const char *, const char *);
747 746
748 showMsg = fromExternalThread ? okBoxThreadSafe : okBox;747 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
749 748
750 rewind(f);749 rewind(f);
751 750
752 // start loading STM751 // start loading STM
753 752
754 if (fread(&h_STM, 1, sizeof (h_STM), f) != sizeof (h_STM))753 if (fread(&h_STM, 1, sizeof (h_STM), f) != sizeof (h_STM))
755 return loadMusicMOD(f, fileLength, fromExternalThread); // file is not a .stm, try to load as .mod754 return loadMusicMOD(f, fileLength, externalThreadFlag); // file is not a .stm, try to load as .mod
756 755
757 if (memcmp(h_STM.sig, "!Scream!", 8) && memcmp(h_STM.sig, "BMOD2STM", 8) &&756 if (memcmp(h_STM.sig, "!Scream!", 8) && memcmp(h_STM.sig, "BMOD2STM", 8) &&
758 memcmp(h_STM.sig, "WUZAMOD!", 8) && memcmp(h_STM.sig, "SWavePro", 8))757 memcmp(h_STM.sig, "WUZAMOD!", 8) && memcmp(h_STM.sig, "SWavePro", 8))
759 {758 {
760 return loadMusicMOD(f, fileLength, fromExternalThread); // file is not a .stm, try to load as .mod759 return loadMusicMOD(f, fileLength, externalThreadFlag); // file is not a .stm, try to load as .mod
761 }760 }
762 761
763 loadedFormat = FORMAT_STM;762 loadedFormat = FORMAT_STM;
@@ -1007,7 +1006,7 @@ static int8_t countS3MChannels(uint16_t antPtn) · 243 unmodified lines
1007 return channels;1006 return channels;
1008}1007}
1009 1008
1010static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread)1009static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool externalThreadFlag)
1011{1010{
1012 int8_t *tmpSmp;1011 int8_t *tmpSmp;
1013 uint8_t ha[2048];1012 uint8_t ha[2048];
@@ -1022,17 +1021,17 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 8 unmodified lines
1022 songS3MinstrHeaderTyp h_S3MInstr;1021 songS3MinstrHeaderTyp h_S3MInstr;
1023 int16_t (*showMsg)(int16_t, const char *, const char *);1022 int16_t (*showMsg)(int16_t, const char *, const char *);
1024 1023
1025 showMsg = fromExternalThread ? okBoxThreadSafe : okBox;1024 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
1026 1025
1027 rewind(f);1026 rewind(f);
1028 1027
1029 // start loading S3M1028 // start loading S3M
1030 1029
1031 if (fread(&h_S3M, 1, sizeof (h_S3M), f) != sizeof (h_S3M))1030 if (fread(&h_S3M, 1, sizeof (h_S3M), f) != sizeof (h_S3M))
1032 return loadMusicSTM(f, dataLength, fromExternalThread); // not a .s3m, try loading as .stm1031 return loadMusicSTM(f, dataLength, externalThreadFlag); // not a .s3m, try loading as .stm
1033 1032
1034 if (memcmp(h_S3M.id, "SCRM", 4))1033 if (memcmp(h_S3M.id, "SCRM", 4))
1035 return loadMusicSTM(f, dataLength, fromExternalThread); // not a .s3m, try loading as .stm1034 return loadMusicSTM(f, dataLength, externalThreadFlag); // not a .s3m, try loading as .stm
1036 1035
1037 loadedFormat = FORMAT_S3M;1036 loadedFormat = FORMAT_S3M;
1038 1037
@@ -1651,7 +1650,7 @@ s3mLoadError: · 612 unmodified lines
1651 return false;1650 return false;
1652}1651}
1653 1652
1654bool doLoadMusic(bool fromExternalThread)1653bool doLoadMusic(bool externalThreadFlag)
1655{1654{
1656 char tmpText[128];1655 char tmpText[128];
1657 int16_t k;1656 int16_t k;
@@ -1661,7 +1660,7 @@ bool doLoadMusic(bool fromExternalThread) · 3 unmodified lines
1661 FILE *f;1660 FILE *f;
1662 int16_t (*showMsg)(int16_t, const char *, const char *);1661 int16_t (*showMsg)(int16_t, const char *, const char *);
1663 1662
1664 showMsg = fromExternalThread ? okBoxThreadSafe : okBox;1663 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
1665 1664
1666 linearFreqTable = false;1665 linearFreqTable = false;
1667 1666
@@ -1686,10 +1685,10 @@ bool doLoadMusic(bool fromExternalThread) · 18 unmodified lines
1686 1685
1687 // start loading1686 // start loading
1688 if (fread(&h, 1, sizeof (h), f) != sizeof (h))1687 if (fread(&h, 1, sizeof (h), f) != sizeof (h))
1689 return loadMusicS3M(f, filelength, fromExternalThread); // not a .xm file, try to load as .s3m1688 return loadMusicS3M(f, filelength, externalThreadFlag); // not a .xm file, try to load as .s3m
1690 1689
1691 if (memcmp(h.sig, "Extended Module: ", 17))1690 if (memcmp(h.sig, "Extended Module: ", 17))
1692 return loadMusicS3M(f, filelength, fromExternalThread); // not a .xm file, try to load as .s3m1691 return loadMusicS3M(f, filelength, externalThreadFlag); // not a .xm file, try to load as .s3m
1693 1692
1694 loadedFormat = FORMAT_XM;1693 loadedFormat = FORMAT_XM;
1695 1694
@@ -1700,7 +1699,7 @@ bool doLoadMusic(bool fromExternalThread) · 4 unmodified lines
1700 const int32_t major = (h.ver >> 8) & 0x0F;1699 const int32_t major = (h.ver >> 8) & 0x0F;
1701 const int32_t minor = h.ver & 0xFF;1700 const int32_t minor = h.ver & 0xFF;
1702 1701
1703 sprintf(tmpText, "Error loading .xm: Unsupported file version (v%01X.%02X)", major, minor);1702 sprintf(tmpText, "Error loading XM: Unsupported file version (v%01X.%02X).", major, minor);
1704 showMsg(0, "System message", tmpText);1703 showMsg(0, "System message", tmpText);
1705 1704
1706 moduleFailedToLoad = true;1705 moduleFailedToLoad = true;
@@ -1709,29 +1708,26 @@ bool doLoadMusic(bool fromExternalThread) · 2 unmodified lines
1709 1708
1710 if (h.len > MAX_ORDERS)1709 if (h.len > MAX_ORDERS)
1711 {1710 {
1712 showMsg(0, "System message", "Error loading .xm: The song has more than 256 orders!");1711 showMsg(0, "System message", "Error loading XM: The song has more than 256 orders!");
1713 goto xmLoadError;1712 goto xmLoadError;
1714 }1713 }
1715 1714
1716 if (h.antPtn > MAX_PATTERNS)1715 if (h.antPtn > MAX_PATTERNS)
1717 {1716 {
1718 showMsg(0, "System message", "Error loading .xm: The song has more than 256 patterns!");1717 showMsg(0, "System message", "Error loading XM: The song has more than 256 patterns!");
1719 goto xmLoadError;1718 goto xmLoadError;
1720 }1719 }
1721 1720
1722 if (h.antChn == 0 || h.antChn > MAX_VOICES)1721 if (h.antChn == 0)
1723 {1722 {
1724 showMsg(0, "System message", "Error loading .xm: Incompatible amount of channels!");1723 showMsg(0, "System message", "Error loading XM: This file is corrupt.");
1725 goto xmLoadError;1724 goto xmLoadError;
1726 }1725 }
1727 1726
1728 if (h.antInstrs > MAX_INST)
1729 showMsg(0, "System message", "This module has over 128 instruments! Only the first 128 will be loaded.");
1730
1731 fseek(f, 60 + h.headerSize, SEEK_SET);1727 fseek(f, 60 + h.headerSize, SEEK_SET);
1732 if (filelength != 336 && feof(f)) // 336 in length at this point = empty XM1728 if (filelength != 336 && feof(f)) // 336 in length at this point = empty XM
1733 {1729 {
1734 showMsg(0, "System message", "Error loading .xm: The module is empty!");1730 showMsg(0, "System message", "Error loading XM: The module is empty!");
1735 goto xmLoadError;1731 goto xmLoadError;
1736 }1732 }
1737 1733
@@ -1768,62 +1764,81 @@ bool doLoadMusic(bool fromExternalThread) · 30 unmodified lines
1768 else1764 else
1769 memcpy(songTmp.songTab, h.songTab, songTmp.len);1765 memcpy(songTmp.songTab, h.songTab, songTmp.len);
1770 1766
1767 // some strange XMs have the order list padded with 0xFF, remove them!
1768 for (int16_t j = 255; j >= 0; j--)
1769 {
1770 if (songTmp.songTab[j] != 0xFF)
1771 break;
1772
1773 if (songTmp.len > j)
1774 songTmp.len = j;
1775 }
1776
1777 // even though XM supports 256 orders, FT2 supports only 255...
1778 if (songTmp.len > 0xFF)
1779 songTmp.len = 0xFF;
1780
1771 if (songTmp.ver < 0x0104)1781 if (songTmp.ver < 0x0104)
1772 {1782 {
1773 // old FT2 format1783 // XM v1.02 and XM v1.03
1774 1784
1775 for (i = 1; i <= h.antInstrs; i++)1785 for (i = 1; i <= h.antInstrs; i++)
1776 {1786 {
1777 if (!loadInstrHeader(f, i))1787 if (!loadInstrHeader(f, i, externalThreadFlag))
1778 {
1779 showMsg(0, "System message", "Error loading .xm: Either a corrupt or a non-supported module!");
1780 goto xmLoadError;1788 goto xmLoadError;
1781 }
1782 }1789 }
1783 1790
1784 if (!loadPatterns(f, h.antPtn))1791 if (!loadPatterns(f, h.antPtn, externalThreadFlag))
1785 {
1786 // error message is shown inside loadPattern()
1787 goto xmLoadError;1792 goto xmLoadError;
1788 }
1789 1793
1790 for (i = 1; i <= h.antInstrs; i++)1794 for (i = 1; i <= h.antInstrs; i++)
1791 {1795 {
1792 if (!loadInstrSample(f, i))1796 if (!loadInstrSample(f, i, externalThreadFlag))
1793 {
1794 showMsg(0, "System message", "Not enough memory!");
1795 goto xmLoadError;1797 goto xmLoadError;
1796 }
1797 }1798 }
1798 }1799 }
1799 else1800 else
1800 {1801 {
1801 // current FT2 format1802 // XM v1.04 (latest version)
1802 1803
1803 if (!loadPatterns(f, h.antPtn))1804 if (!loadPatterns(f, h.antPtn, externalThreadFlag))
1804 {
1805 // error message is shown inside loadPattern()
1806 goto xmLoadError;1805 goto xmLoadError;
1807 }
1808 1806
1809 for (i = 1; i <= h.antInstrs; i++)1807 for (i = 1; i <= h.antInstrs; i++)
1810 {1808 {
1811 if (!loadInstrHeader(f, i))1809 if (!loadInstrHeader(f, i, externalThreadFlag)) goto xmLoadError;
1812 {1810 if (!loadInstrSample(f, i, externalThreadFlag)) goto xmLoadError;
1813 showMsg(0, "System message", "Error loading .xm: Either a corrupt or a non-supported module!");
1814 goto xmLoadError;
1815 }
1816
1817 if (!loadInstrSample(f, i))
1818 {
1819 showMsg(0, "System message", "Not enough memory!");
1820 goto xmLoadError;
1821 }
1822 }1811 }
1823 }1812 }
1824 1813
1825 fclose(f);1814 fclose(f);
1826 1815
1816 /* We support loading XMs with up to 32 samples per instrument (ModPlug/OpenMPT),
1817 ** but only the first 16 will be loaded. Now make sure we set the number of samples
1818 ** back to max 16 in the headers before loading is done.
1819 */
1820 bool instrHasMoreThan16Samples = false;
1821 for (i = 1; i <= MAX_INST; i++)
1822 {
1823 if (instrTmp[i] != NULL && instrTmp[i]->antSamp > MAX_SMP_PER_INST)
1824 {
1825 instrHasMoreThan16Samples = true;
1826 instrTmp[i]->antSamp = MAX_SMP_PER_INST;
1827 }
1828 }
1829
1830 if (songTmp.antChn > MAX_VOICES)
1831 {
1832 songTmp.antChn = MAX_VOICES;
1833 showMsg(0, "System message", "Warning: This XM contains >32 channels. The extra channels will be discarded!");
1834 }
1835
1836 if (h.antInstrs > MAX_INST)
1837 showMsg(0, "System message", "Warning: This XM contains >128 instruments. The extra instruments will be discarded!");
1838
1839 if (instrHasMoreThan16Samples)
1840 showMsg(0, "System message", "Warning: This XM contains instrument(s) with >16 samples. The extra samples will be discarded!");
1841
1827 moduleLoaded = true;1842 moduleLoaded = true;
1828 return true;1843 return true;
1829 1844
@@ -1908,9 +1923,9 @@ bool loadMusicUnthreaded(UNICHAR *filenameU, bool autoPlay) · 78 unmodified lines
1908 return false;1923 return false;
1909}1924}
1910 1925
1911static void freeTmpModule(void)1926static void freeTmpModule(void) // called on module load error
1912{1927{
1913 uint16_t i;1928 int32_t i, j;
1914 1929
1915 // free all patterns1930 // free all patterns
1916 for (i = 0; i < MAX_PATTERNS; i++)1931 for (i = 0; i < MAX_PATTERNS; i++)
@@ -1927,10 +1942,10 @@ static void freeTmpModule(void) · 10 unmodified lines
1927 {1942 {
1928 if (instrTmp[i] != NULL)1943 if (instrTmp[i] != NULL)
1929 {1944 {
1930 for (uint8_t j = 0; j < MAX_SMP_PER_INST; j++)1945 for (j = 0; j < MAX_SMP_PER_INST; j++)
1931 {1946 {
1932 if (instrTmp[i]->samp[j].pek != NULL)1947 if (instrTmp[i]->samp[j].origPek != NULL)
1933 free(instrTmp[i]->samp[j].pek);1948 free(instrTmp[i]->samp[j].origPek);
1934 }1949 }
1935 1950
1936 free(instrTmp[i]);1951 free(instrTmp[i]);
@@ -1939,7 +1954,7 @@ static void freeTmpModule(void) · 2 unmodified lines
1939 }1954 }
1940}1955}
1941 1956
1942static bool loadInstrHeader(FILE *f, uint16_t i)1957static bool loadInstrHeader(FILE *f, uint16_t i, bool externalThreadFlag)
1943{1958{
1944 int8_t k;1959 int8_t k;
1945 uint8_t j;1960 uint8_t j;
@@ -1948,24 +1963,38 @@ static bool loadInstrHeader(FILE *f, uint16_t i) · 2 unmodified lines
1948 instrTyp *ins;1963 instrTyp *ins;
1949 sampleHeaderTyp *src;1964 sampleHeaderTyp *src;
1950 sampleTyp *s;1965 sampleTyp *s;
1966 int16_t (*showMsg)(int16_t, const char *, const char *);
1951 1967
1952 memset(&ih, 0, INSTR_HEADER_SIZE);1968 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
1953 1969
1970 memset(extraSampleLengths, 0, sizeof (extraSampleLengths));
1971 memset(&ih, 0, sizeof (ih));
1954 fread(&ih.instrSize, 4, 1, f);1972 fread(&ih.instrSize, 4, 1, f);
1955 1973
1956 readSize = ih.instrSize;1974 readSize = ih.instrSize;
1957 if (readSize < 4 || readSize > INSTR_HEADER_SIZE)1975
1976 // yes, some XMs can have a header size of 0, and it usually means 263 bytes (INSTR_HEADER_SIZE)
1977 if (readSize == 0 || readSize > INSTR_HEADER_SIZE)
1958 readSize = INSTR_HEADER_SIZE;1978 readSize = INSTR_HEADER_SIZE;
1959 1979
1980 if (readSize < 4)
1981 {
1982 showMsg(0, "System message", "Error loading XM: This file is corrupt (or not supported)!");
1983 return false;
1984 }
1985
1960 // load instrument data into temp buffer1986 // load instrument data into temp buffer
1961 fread(ih.name, readSize-4, 1, f); // -4 = skip ih.instrSize1987 fread(ih.name, readSize-4, 1, f); // -4 = skip ih.instrSize
1962 1988
1963 // FT2 bugfix: skip instrument header data if instrSize is above INSTR_HEADER_SIZE1989 // FT2 bugfix: skip instrument header data if instrSize is above INSTR_HEADER_SIZE
1964 if (ih.instrSize > INSTR_HEADER_SIZE)1990 if (ih.instrSize > INSTR_HEADER_SIZE)
1965 fseek(f, ih.instrSize - INSTR_HEADER_SIZE, SEEK_CUR);1991 fseek(f, ih.instrSize-INSTR_HEADER_SIZE, SEEK_CUR);
1966 1992
1967 if (ih.antSamp > MAX_SMP_PER_INST)1993 if (ih.antSamp < 0 || ih.antSamp > 32)
1994 {
1995 showMsg(0, "System message", "Error loading XM: This file is corrupt (or not supported)!");
1968 return false;1996 return false;
1997 }
1969 1998
1970 if (i <= MAX_INST)1999 if (i <= MAX_INST)
1971 {2000 {
@@ -1987,7 +2016,10 @@ static bool loadInstrHeader(FILE *f, uint16_t i) · 15 unmodified lines
1987 if (i <= MAX_INST)2016 if (i <= MAX_INST)
1988 {2017 {
1989 if (!allocateTmpInstr(i))2018 if (!allocateTmpInstr(i))
2019 {
2020 showMsg(0, "System message", "Not enough memory!");
1990 return false;2021 return false;
2022 }
1991 2023
1992 // copy instrument header elements to our instrument struct2024 // copy instrument header elements to our instrument struct
1993 2025
@@ -2028,8 +2060,8 @@ static bool loadInstrHeader(FILE *f, uint16_t i) · 34 unmodified lines
2028 2060
2029 for (j = 0; j < 96; j++)2061 for (j = 0; j < 96; j++)
2030 {2062 {
2031 if (ins->ta[j] > 15)2063 if (ins->ta[j] >= MAX_SMP_PER_INST)
2032 ins->ta[j] = 15;2064 ins->ta[j] = MAX_SMP_PER_INST-1;
2033 }2065 }
2034 2066
2035 if (ins->envVPAnt > 12) ins->envVPAnt = 12;2067 if (ins->envVPAnt > 12) ins->envVPAnt = 12;
@@ -2050,12 +2082,30 @@ static bool loadInstrHeader(FILE *f, uint16_t i) · 14 unmodified lines
2050 }2082 }
2051 }2083 }
2052 2084
2053 if (fread(ih.samp, ih.antSamp * sizeof (sampleHeaderTyp), 1, f) != 1)2085 int32_t sampleHeadersToRead = ih.antSamp;
2086 if (sampleHeadersToRead > MAX_SMP_PER_INST)
2087 sampleHeadersToRead = MAX_SMP_PER_INST;
2088
2089 if (fread(ih.samp, sampleHeadersToRead * sizeof (sampleHeaderTyp), 1, f) != 1)
2090 {
2091 showMsg(0, "System message", "General I/O error during loading!");
2054 return false;2092 return false;
2093 }
2094
2095 // if instrument contains more than 16 sample headers (unsupported), skip them
2096 if (ih.antSamp > MAX_SMP_PER_INST) // can only be 0..32 at this point
2097 {
2098 const int32_t samplesToSkip = ih.antSamp-MAX_SMP_PER_INST;
2099 for (j = 0; j < samplesToSkip; j++)
2100 {
2101 fread(&extraSampleLengths[j], 4, 1, f); // used for skipping data in loadInstrSample()
2102 fseek(f, sizeof (sampleHeaderTyp)-4, SEEK_CUR);
2103 }
2104 }
2055 2105
2056 if (i <= MAX_INST)2106 if (i <= MAX_INST)
2057 {2107 {
2058 for (j = 0; j < ih.antSamp; j++)2108 for (j = 0; j < sampleHeadersToRead; j++)
2059 {2109 {
2060 s = &instrTmp[i]->samp[j];2110 s = &instrTmp[i]->samp[j];
2061 src = &ih.samp[j];2111 src = &ih.samp[j];
@@ -2105,17 +2155,23 @@ void checkSampleRepeat(sampleTyp *s) · 43 unmodified lines
2105 if (s->repL == 0) s->typ &= ~3; // non-FT2 fix: force loop off if looplen is 02155 if (s->repL == 0) s->typ &= ~3; // non-FT2 fix: force loop off if looplen is 0
2106}2156}
2107 2157
2108static bool loadInstrSample(FILE *f, uint16_t i)2158static bool loadInstrSample(FILE *f, uint16_t i, bool externalThreadFlag)
2109{2159{
2110 int8_t *newPtr;2160 int8_t *newPtr;
2111 uint16_t j, k;2161 uint16_t j, k;
2112 int32_t l, bytesToSkip;2162 int32_t l, bytesToSkip;
2113 sampleTyp *s;2163 sampleTyp *s;
2164 int16_t (*showMsg)(int16_t, const char *, const char *);
2165
2166 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
2114 2167
2115 if (i > MAX_INST || instrTmp[i] == NULL)2168 if (i > MAX_INST || instrTmp[i] == NULL)
2116 return true; // yes, let's just pretend they got loaded2169 return true; // yes, let's just pretend they got loaded
2117 2170
2118 k = instrTmp[i]->antSamp;2171 k = instrTmp[i]->antSamp;
2172 if (k > MAX_SMP_PER_INST)
2173 k = MAX_SMP_PER_INST;
2174
2119 for (j = 0; j < k; j++)2175 for (j = 0; j < k; j++)
2120 {2176 {
2121 s = &instrTmp[i]->samp[j];2177 s = &instrTmp[i]->samp[j];
@@ -2147,14 +2203,17 @@ static bool loadInstrSample(FILE *f, uint16_t i) · 25 unmodified lines
2147 s->pek = NULL;2203 s->pek = NULL;
2148 s->origPek = (int8_t *)malloc(l + LOOP_FIX_LEN);2204 s->origPek = (int8_t *)malloc(l + LOOP_FIX_LEN);
2149 if (s->origPek == NULL)2205 if (s->origPek == NULL)
2206 {
2207 showMsg(0, "System message", "Not enough memory!");
2150 return false;2208 return false;
2209 }
2151 2210
2152 s->pek = s->origPek + SMP_DAT_OFFSET;2211 s->pek = s->origPek + SMP_DAT_OFFSET;
2153 2212
2154 int32_t bytesRead = (int32_t)fread(s->pek, 1, l, f);2213 const int32_t bytesRead = (int32_t)fread(s->pek, 1, l, f);
2155 if (bytesRead < l)2214 if (bytesRead < l)
2156 {2215 {
2157 int32_t bytesToClear = l - bytesRead;2216 const int32_t bytesToClear = l - bytesRead;
2158 memset(&s->pek[bytesRead], 0, bytesToClear);2217 memset(&s->pek[bytesRead], 0, bytesToClear);
2159 }2218 }
2160 2219
@@ -2192,23 +2251,37 @@ static bool loadInstrSample(FILE *f, uint16_t i) · 31 unmodified lines
2192 fixSample(s);2251 fixSample(s);
2193 }2252 }
2194 2253
2254 if (instrTmp[i]->antSamp > MAX_SMP_PER_INST)
2255 {
2256 const int32_t samplesToSkip = instrTmp[i]->antSamp-MAX_SMP_PER_INST;
2257 for (i = 0; i < samplesToSkip; i++)
2258 {
2259 if (extraSampleLengths[i] > 0)
2260 fseek(f, extraSampleLengths[i], SEEK_CUR);
2261 }
2262 }
2263
2195 return true;2264 return true;
2196}2265}
2197 2266
2198void unpackPatt(uint8_t *dst, uint8_t *src, uint16_t len, int32_t antChn)2267void unpackPatt(uint8_t *dst, uint8_t *src, uint16_t len, int32_t antChn)
2199{2268{
2200 uint8_t note, data;2269 uint8_t note, data;
2201 int32_t srcEnd, srcIdx;2270 int32_t srcEnd, srcIdx, j;
2202 2271
2203 if (dst == NULL)2272 if (dst == NULL)
2204 return;2273 return;
2205 2274
2206 srcEnd = len * TRACK_WIDTH;2275 srcEnd = len * (sizeof (tonTyp) * antChn);
2207 srcIdx = 0;2276 srcIdx = 0;
2208 2277
2278 int32_t numChannels = antChn;
2279 if (numChannels > MAX_VOICES)
2280 numChannels = MAX_VOICES;
2281
2209 for (int32_t i = 0; i < len; i++)2282 for (int32_t i = 0; i < len; i++)
2210 {2283 {
2211 for (int32_t j = 0; j < antChn; j++)2284 for (j = 0; j < numChannels; j++)
2212 {2285 {
2213 if (srcIdx >= srcEnd)2286 if (srcIdx >= srcEnd)
2214 return; // error!2287 return; // error!
@@ -2245,8 +2318,35 @@ void unpackPatt(uint8_t *dst, uint8_t *src, uint16_t len, int32_t antChn) · 30 unmodified lines
2245 srcIdx += sizeof (tonTyp);2318 srcIdx += sizeof (tonTyp);
2246 }2319 }
2247 2320
2248 // skip unused channels2321 // if more than 32 channels, skip rest of the channels for this row
2249 dst += sizeof (tonTyp) * (MAX_VOICES - antChn);2322 for (; j < antChn; j++)
2323 {
2324 if (srcIdx >= srcEnd)
2325 return; // error!
2326
2327 note = *src++;
2328 if (note & 0x80)
2329 {
2330 if (note & 0x01) src++;
2331 if (note & 0x02) src++;
2332 if (note & 0x04) src++;
2333 if (note & 0x08) src++;
2334 if (note & 0x10) src++;
2335 }
2336 else
2337 {
2338 src++;
2339 src++;
2340 src++;
2341 src++;
2342 }
2343
2344 srcIdx += sizeof (tonTyp);
2345 }
2346
2347 // if song has <32 channels, align pointer to next row (skip unused channels)
2348 if (antChn < MAX_VOICES)
2349 dst += sizeof (tonTyp) * (MAX_VOICES - antChn);
2250 }2350 }
2251}2351}
2252 2352
@@ -2279,15 +2379,17 @@ void clearUnusedChannels(tonTyp *p, int16_t pattLen, int32_t antChn) · 26 unmodified lines
2279 memset(&p[(i * MAX_VOICES) + antChn], 0, sizeof (tonTyp) * (MAX_VOICES - antChn));2379 memset(&p[(i * MAX_VOICES) + antChn], 0, sizeof (tonTyp) * (MAX_VOICES - antChn));
2280}2380}
2281 2381
2282static bool loadPatterns(FILE *f, uint16_t antPtn)2382static bool loadPatterns(FILE *f, uint16_t antPtn, bool externalThreadFlag)
2283{2383{
2284 bool pattLenWarn;2384 bool pattLenWarn;
2285 uint8_t tmpLen;2385 uint8_t tmpLen;
2286 uint16_t i;2386 uint16_t i;
2287 patternHeaderTyp ph;2387 patternHeaderTyp ph;
2388 int16_t (*showMsg)(int16_t, const char *, const char *);
2288 2389
2289 pattLenWarn = false;2390 showMsg = externalThreadFlag ? okBoxThreadSafe : okBox;
2290 2391
2392 pattLenWarn = false;
2291 for (i = 0; i < antPtn; i++)2393 for (i = 0; i < antPtn; i++)
2292 {2394 {
2293 if (fread(&ph.patternHeaderSize, 4, 1, f) != 1)2395 if (fread(&ph.patternHeaderSize, 4, 1, f) != 1)
@@ -2337,7 +2439,7 @@ static bool loadPatterns(FILE *f, uint16_t antPtn) · 43 unmodified lines
2337 pattTmp[i] = (tonTyp *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1);2439 pattTmp[i] = (tonTyp *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1);
2338 if (pattTmp[i] == NULL)2440 if (pattTmp[i] == NULL)
2339 {2441 {
2340 okBoxThreadSafe(0, "System message", "Not enough memory!");2442 showMsg(0, "System message", "Not enough memory!");
2341 return false;2443 return false;
2342 }2444 }
2343 2445
@@ -2345,7 +2447,6 @@ static bool loadPatterns(FILE *f, uint16_t antPtn) · 1 unmodified line
2345 goto pattCorrupt;2447 goto pattCorrupt;
2346 2448
2347 unpackPatt((uint8_t *)pattTmp[i], packedPattData, pattLensTmp[i], songTmp.antChn);2449 unpackPatt((uint8_t *)pattTmp[i], packedPattData, pattLensTmp[i], songTmp.antChn);
2348
2349 clearUnusedChannels(pattTmp[i], pattLensTmp[i], songTmp.antChn);2450 clearUnusedChannels(pattTmp[i], pattLensTmp[i], songTmp.antChn);
2350 }2451 }
2351 2452
@@ -2362,12 +2463,12 @@ static bool loadPatterns(FILE *f, uint16_t antPtn) · 10 unmodified lines
2362 }2463 }
2363 2464
2364 if (pattLenWarn)2465 if (pattLenWarn)
2365 okBoxThreadSafe(0, "System message", "This module contains pattern(s) with a length above 256! They will be truncated.");2466 showMsg(0, "System message", "This module contains pattern(s) with a length above 256! They will be truncated.");
2366 2467
2367 return true;2468 return true;
2368 2469
2369pattCorrupt:2470pattCorrupt:
2370 okBoxThreadSafe(0, "System message", "Error loading .xm: Either a corrupt or a non-supported module!");2471 showMsg(0, "System message", "Error loading XM: This file is corrupt!");
2371 return false;2472 return false;
2372}2473}
2373 2474

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t