- More improvements to S3M loader. Fixes "satellite one.s3m" and other S3Ms. - Up/down pushbutton delay has been increased even more, to prevent accidentally skipping too much. - Some other small miscellaneous changes not worth of a mention
Showing the changes to src/ft2_module_loader.c (1 of 25 files). Show all
Unified · Split
| @@ -184,7 +184,7 @@ static uint8_t getModType(uint8_t *numChannels, const char *id) · 183 unmodified lines | |||
| 184 | 184 | ||
| 185 | if (IS_ID("M.K.", id) || IS_ID("M!K!", id) || IS_ID("NSMS", id) || IS_ID("LARD", id) || IS_ID("PATT", id)) | 185 | if (IS_ID("M.K.", id) || IS_ID("M!K!", id) || IS_ID("NSMS", id) || IS_ID("LARD", id) || IS_ID("PATT", id)) |
| 186 | { | 186 | { |
| 187 | modFormat = FORMAT_MK; // ProTracker or compatible | 187 | modFormat = FORMAT_MK; // ProTracker or compatible |
| 188 | } | 188 | } |
| 189 | else if (id[1] == 'C' && id[2] == 'H' && id[3] == 'N') | 189 | else if (id[1] == 'C' && id[2] == 'H' && id[3] == 'N') |
| 190 | { | 190 | { |
| @@ -200,11 +200,6 @@ static uint8_t getModType(uint8_t *numChannels, const char *id) · 9 unmodified lines | |||
| 200 | { | 200 | { |
| 201 | modFormat = FORMAT_FLT; // StarTrekker (4-channel modules only) | 201 | modFormat = FORMAT_FLT; // StarTrekker (4-channel modules only) |
| 202 | } | 202 | } |
| 203 | else if (IS_ID("FLT8", id)) | ||
| 204 | { | ||
| 205 | modFormat = FORMAT_FLT; // StarTrekker (4-channel modules only) | ||
| 206 | *numChannels = 8; | ||
| 207 | } | ||
| 208 | else if (IS_ID("N.T.", id)) | 203 | else if (IS_ID("N.T.", id)) |
| 209 | { | 204 | { |
| 210 | modFormat = FORMAT_NT; // NoiseTracker | 205 | modFormat = FORMAT_NT; // NoiseTracker |
| @@ -364,23 +359,23 @@ static bool loadMusicMOD(FILE *f, uint32_t fileLength, bool fromExternalThread) · 153 unmodified lines | |||
| 364 | */ | 359 | */ |
| 365 | modFormat = FORMAT_STK; | 360 | modFormat = FORMAT_STK; |
| 366 | 361 | ||
| 367 | if (h_MOD15.repS == 0) | 362 | if (songTmp.repS == 0) |
| 368 | h_MOD15.repS = 120; | 363 | songTmp.repS = 120; |
| 369 | 364 | ||
| 370 | // jjk55.mod by Jesper Kyd has a bogus STK tempo value that should be ignored | 365 | // jjk55.mod by Jesper Kyd has a bogus STK tempo value that should be ignored (hackish!) |
| 371 | if (!strcmp("jjk55", h_MOD31.name)) | 366 | if (!strcmp("jjk55", h_MOD31.name)) |
| 372 | h_MOD15.repS = 120; | 367 | songTmp.repS = 120; |
| 373 | 368 | ||
| 374 | // The "restart pos" field in STK is the inital tempo (must be converted to BPM first) | 369 | // The "restart pos" field in STK is the inital tempo (must be converted to BPM first) |
| 375 | if (h_MOD15.repS != 120) // 120 is a special case and means 50Hz (125BPM) | 370 | if (songTmp.repS != 120) // 120 is a special case and means 50Hz (125BPM) |
| 376 | { | 371 | { |
| 377 | if (h_MOD15.repS > 220) | 372 | if (songTmp.repS > 220) |
| 378 | h_MOD15.repS = 220; | 373 | songTmp.repS = 220; |
| 379 | 374 | ||
| 380 | // convert UST tempo to BPM | 375 | // convert UST tempo to BPM |
| 381 | uint16_t ciaPeriod = (240 - songTmp.repS) * 122; | 376 | uint16_t ciaPeriod = (240 - songTmp.repS) * 122; |
| 382 | double dHz = 709379.0 / ciaPeriod; | 377 | double dHz = 709379.0 / ciaPeriod; |
| 383 | int32_t BPM = (int32_t)((dHz * (125.0 / 50.0)) + 0.5); | 378 | int32_t BPM = (int32_t)((dHz * 2.5) + 0.5); |
| 384 | 379 | ||
| 385 | songTmp.speed = (uint16_t)BPM; | 380 | songTmp.speed = (uint16_t)BPM; |
| 386 | } | 381 | } |
| @@ -450,7 +445,7 @@ static bool loadMusicMOD(FILE *f, uint32_t fileLength, bool fromExternalThread) · 63 unmodified lines | |||
| 450 | ton->effTyp = bytes[2] & 0x0F; | 445 | ton->effTyp = bytes[2] & 0x0F; |
| 451 | ton->eff = bytes[3]; | 446 | ton->eff = bytes[3]; |
| 452 | 447 | ||
| 453 | if (mightBeSTK) | 448 | if (modFormat == FORMAT_STK) |
| 454 | { | 449 | { |
| 455 | if (ton->effTyp == 0xC || ton->effTyp == 0xD || ton->effTyp == 0xE) | 450 | if (ton->effTyp == 0xC || ton->effTyp == 0xD || ton->effTyp == 0xE) |
| 456 | { | 451 | { |
| @@ -519,7 +514,7 @@ static bool loadMusicMOD(FILE *f, uint32_t fileLength, bool fromExternalThread) · 62 unmodified lines | |||
| 519 | } | 514 | } |
| 520 | 515 | ||
| 521 | // pattern command conversion for non-PT formats | 516 | // pattern command conversion for non-PT formats |
| 522 | if (modFormat == FORMAT_STK || modFormat == FORMAT_FT2 || modFormat == FORMAT_NT || modFormat == FORMAT_HMNT || modFormat == FORMAT_FLT) | 517 | if (modFormat == FORMAT_STK || modFormat == FORMAT_NT || modFormat == FORMAT_HMNT || modFormat == FORMAT_FLT) |
| 523 | { | 518 | { |
| 524 | for (a = 0; a < b; a++) | 519 | for (a = 0; a < b; a++) |
| 525 | { | 520 | { |
| @@ -690,7 +685,7 @@ static bool loadMusicMOD(FILE *f, uint32_t fileLength, bool fromExternalThread) · 164 unmodified lines | |||
| 690 | /* For Ultimate SoundTracker modules, only the loop area of a looped sample is played. | 685 | /* For Ultimate SoundTracker modules, only the loop area of a looped sample is played. |
| 691 | ** Skip loading of eventual data present before loop start. | 686 | ** Skip loading of eventual data present before loop start. |
| 692 | */ | 687 | */ |
| 693 | if (modFormat == FORMAT_STK && (s->repS > 0 && s->repL < s->len)) | 688 | if (modFormat == FORMAT_STK && s->repS > 0 && s->repL < s->len) |
| 694 | { | 689 | { |
| 695 | s->len -= s->repS; | 690 | s->len -= s->repS; |
| 696 | fseek(f, s->repS, SEEK_CUR); | 691 | fseek(f, s->repS, SEEK_CUR); |
| @@ -705,7 +700,7 @@ static bool loadMusicMOD(FILE *f, uint32_t fileLength, bool fromExternalThread) · 8 unmodified lines | |||
| 705 | } | 700 | } |
| 706 | 701 | ||
| 707 | // clear repL and repS on non-looping samples... | 702 | // clear repL and repS on non-looping samples... |
| 708 | if ((s->typ & 3) == 0) | 703 | if (s->typ == 0) |
| 709 | { | 704 | { |
| 710 | s->repL = 0; | 705 | s->repL = 0; |
| 711 | s->repS = 0; | 706 | s->repS = 0; |
| @@ -735,18 +730,15 @@ static uint8_t stmTempoToBPM(uint8_t tempo) // ported from original ST2.3 replay · 23 unmodified lines | |||
| 735 | uint16_t hz = 50; | 730 | uint16_t hz = 50; |
| 736 | 731 | ||
| 737 | hz -= ((slowdowns[tempo >> 4] * (tempo & 15)) >> 4); // can and will underflow | 732 | hz -= ((slowdowns[tempo >> 4] * (tempo & 15)) >> 4); // can and will underflow |
| 738 | 733 | bpm = (hz << 1) + (hz >> 1); // BPM = hz * 2.5 | |
| 739 | bpm = (int32_t)((hz * 2.5) + 0.5); | ||
| 740 | 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... |
| 741 | } | 735 | } |
| 742 | 736 | ||
| 743 | static bool loadMusicSTM(FILE *f, uint32_t fileLength, bool fromExternalThread) | 737 | static bool loadMusicSTM(FILE *f, uint32_t fileLength, bool fromExternalThread) |
| 744 | { | 738 | { |
| 745 | bool check3xx; | 739 | uint8_t typ, tempo; |
| 746 | uint8_t typ, tmp8, tempo; | ||
| 747 | int16_t i, j, k, ai, ap, tmp; | 740 | int16_t i, j, k, ai, ap, tmp; |
| 748 | uint16_t a; | 741 | uint16_t a; |
| 749 | int32_t len; | ||
| 750 | tonTyp *ton; | 742 | tonTyp *ton; |
| 751 | sampleTyp *s; | 743 | sampleTyp *s; |
| 752 | songSTMHeaderTyp h_STM; | 744 | songSTMHeaderTyp h_STM; |
| @@ -887,19 +879,6 @@ static bool loadMusicSTM(FILE *f, uint32_t fileLength, bool fromExternalThread) · 134 unmodified lines | |||
| 887 | ton->eff = 0; | 879 | ton->eff = 0; |
| 888 | } | 880 | } |
| 889 | 881 | ||
| 890 | /* Remove any EDx with no note. | ||
| 891 | ** SDx with no note in ST3 = does nothing | ||
| 892 | ** EDx with no note in FT2 = still retriggers | ||
| 893 | */ | ||
| 894 | if (ton->effTyp == 0xE && (ton->eff & 0xF0) == 0xD0) | ||
| 895 | { | ||
| 896 | if (ton->ton == 0 || ton->ton == 97) | ||
| 897 | { | ||
| 898 | ton->eff = 0; | ||
| 899 | ton->effTyp = 0; | ||
| 900 | } | ||
| 901 | } | ||
| 902 | |||
| 903 | if (ton->effTyp > 35) | 882 | if (ton->effTyp > 35) |
| 904 | { | 883 | { |
| 905 | ton->effTyp = 0; | 884 | ton->effTyp = 0; |
| @@ -986,77 +965,6 @@ static bool loadMusicSTM(FILE *f, uint32_t fileLength, bool fromExternalThread) · 80 unmodified lines | |||
| 986 | } | 965 | } |
| 987 | } | 966 | } |
| 988 | 967 | ||
| 989 | // non-FT2: fix overflown 9xx and illegal 3xx | ||
| 990 | |||
| 991 | for (i = 0; i < ap; i++) | ||
| 992 | { | ||
| 993 | if (pattTmp[i] == NULL) | ||
| 994 | continue; | ||
| 995 | |||
| 996 | for (k = 0; k < songTmp.antChn; k++) | ||
| 997 | { | ||
| 998 | check3xx = false; | ||
| 999 | for (j = 0; j < 64; j++) | ||
| 1000 | { | ||
| 1001 | ton = &pattTmp[i][(j * MAX_VOICES) + k]; | ||
| 1002 | |||
| 1003 | if (ton->ton > 0 && ton->ton < 97 && ton->effTyp != 0x3) | ||
| 1004 | check3xx = true; | ||
| 1005 | |||
| 1006 | if (ton->ton > 0 && ton->ton < 97 && ton->effTyp == 0x3) | ||
| 1007 | check3xx = false; | ||
| 1008 | |||
| 1009 | if (check3xx && ton->effTyp == 0x3) | ||
| 1010 | { | ||
| 1011 | if (ton->ton == 0 || ton->ton == 97) | ||
| 1012 | { | ||
| 1013 | ton->effTyp = 0; | ||
| 1014 | ton->eff = 0; | ||
| 1015 | } | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | if (ton->effTyp == 0x9 && ton->eff > 0) | ||
| 1019 | { | ||
| 1020 | if (ton->instr != 0 && ton->instr <= ai) | ||
| 1021 | { | ||
| 1022 | s = &instrTmp[ton->instr]->samp[0]; | ||
| 1023 | len = s->len; | ||
| 1024 | |||
| 1025 | tmp8 = 0; | ||
| 1026 | if (len > 0) | ||
| 1027 | { | ||
| 1028 | tmp8 = ton->eff; | ||
| 1029 | |||
| 1030 | int32_t newLen = len >> 8; | ||
| 1031 | if (tmp8 >= newLen) | ||
| 1032 | { | ||
| 1033 | if (newLen < 1) | ||
| 1034 | tmp8 = 0; | ||
| 1035 | else | ||
| 1036 | tmp8 = (uint8_t)(newLen - 1); | ||
| 1037 | } | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | if (tmp8 > 0) | ||
| 1041 | { | ||
| 1042 | ton->eff = tmp8; | ||
| 1043 | } | ||
| 1044 | else | ||
| 1045 | { | ||
| 1046 | ton->effTyp = 0; | ||
| 1047 | ton->eff = 0; | ||
| 1048 | } | ||
| 1049 | } | ||
| 1050 | else | ||
| 1051 | { | ||
| 1052 | ton->effTyp = 0; | ||
| 1053 | ton->eff = 0; | ||
| 1054 | } | ||
| 1055 | } | ||
| 1056 | } | ||
| 1057 | } | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | fclose(f); | 968 | fclose(f); |
| 1061 | 969 | ||
| 1062 | moduleLoaded = true; | 970 | moduleLoaded = true; |
| @@ -1102,14 +1010,14 @@ static int8_t countS3MChannels(uint16_t antPtn) · 39 unmodified lines | |||
| 1102 | static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) | 1010 | static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) |
| 1103 | { | 1011 | { |
| 1104 | int8_t *tmpSmp; | 1012 | int8_t *tmpSmp; |
| 1105 | bool check3xx, illegalUxx; | 1013 | bool illegalUxx; |
| 1106 | uint8_t ha[2048]; | 1014 | uint8_t ha[2048]; |
| 1107 | uint8_t s3mLastDEff[32], s3mLastEEff[32], s3mLastFEff[32]; | 1015 | uint8_t alastnfo[32], alastefx[32], alastvibnfo[32], s3mLastGInstr[32]; |
| 1108 | uint8_t s3mLastSEff[32], s3mLastJEff[32], s3mLastGInstr[32], typ; | 1016 | uint8_t typ; |
| 1109 | int16_t ai, ap, ver, ii, kk, tmp; | 1017 | int16_t ai, ap, ver, ii, kk, tmp; |
| 1110 | uint16_t ptnOfs[256]; | 1018 | uint16_t ptnOfs[256]; |
| 1111 | int32_t i, j, k, len; | 1019 | int32_t i, j, k, len; |
| 1112 | tonTyp ton, *pattTon; | 1020 | tonTyp ton; |
| 1113 | sampleTyp *s; | 1021 | sampleTyp *s; |
| 1114 | songS3MHeaderTyp h_S3M; | 1022 | songS3MHeaderTyp h_S3M; |
| 1115 | songS3MinstrHeaderTyp h_S3MInstr; | 1023 | songS3MinstrHeaderTyp h_S3MInstr; |
| @@ -1143,13 +1051,7 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 27 unmodified lines | |||
| 1143 | goto s3mLoadError; | 1051 | goto s3mLoadError; |
| 1144 | } | 1052 | } |
| 1145 | 1053 | ||
| 1146 | // count real song table entries | 1054 | songTmp.len = h_S3M.songTabLen; |
| 1147 | songTmp.len = 256; | ||
| 1148 | while (songTmp.len > 0 && songTmp.songTab[songTmp.len-1] == 255) | ||
| 1149 | songTmp.len--; | ||
| 1150 | |||
| 1151 | if (songTmp.len == 256) | ||
| 1152 | songTmp.len = 255; | ||
| 1153 | 1055 | ||
| 1154 | // remove pattern separators (254) | 1056 | // remove pattern separators (254) |
| 1155 | k = 0; | 1057 | k = 0; |
| @@ -1165,11 +1067,20 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 9 unmodified lines | |||
| 1165 | if (k <= songTmp.len) | 1067 | if (k <= songTmp.len) |
| 1166 | songTmp.len -= (uint16_t)k; | 1068 | songTmp.len -= (uint16_t)k; |
| 1167 | else | 1069 | else |
| 1168 | songTmp.len = 0; | 1070 | songTmp.len = 1; |
| 1071 | |||
| 1072 | for (i = 1; i < songTmp.len; i++) | ||
| 1073 | { | ||
| 1074 | if (songTmp.songTab[i] == 255) | ||
| 1075 | { | ||
| 1076 | songTmp.len = (uint16_t)i; | ||
| 1077 | break; | ||
| 1078 | } | ||
| 1079 | } | ||
| 1169 | 1080 | ||
| 1170 | // clear unused song table entries | 1081 | // clear unused song table entries |
| 1171 | if (songTmp.len < 255) | 1082 | if (songTmp.len < 255) |
| 1172 | memset(&songTmp.songTab[songTmp.len], 0, 256 - songTmp.len); | 1083 | memset(&songTmp.songTab[songTmp.len], 0, 255-songTmp.len); |
| 1173 | 1084 | ||
| 1174 | songTmp.speed = h_S3M.defTempo; | 1085 | songTmp.speed = h_S3M.defTempo; |
| 1175 | if (songTmp.speed < 32) | 1086 | if (songTmp.speed < 32) |
| @@ -1226,11 +1137,9 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 50 unmodified lines | |||
| 1226 | if (ptnOfs[i] == 0) | 1137 | if (ptnOfs[i] == 0) |
| 1227 | continue; // empty pattern | 1138 | continue; // empty pattern |
| 1228 | 1139 | ||
| 1229 | memset(s3mLastDEff, 0, sizeof (s3mLastDEff)); | 1140 | memset(alastnfo, 0, sizeof (alastnfo)); |
| 1230 | memset(s3mLastEEff, 0, sizeof (s3mLastEEff)); | 1141 | memset(alastefx, 0, sizeof (alastefx)); |
| 1231 | memset(s3mLastFEff, 0, sizeof (s3mLastFEff)); | 1142 | memset(alastvibnfo, 0, sizeof (alastvibnfo)); |
| 1232 | memset(s3mLastSEff, 0, sizeof (s3mLastSEff)); | ||
| 1233 | memset(s3mLastJEff, 0, sizeof (s3mLastJEff)); | ||
| 1234 | memset(s3mLastGInstr, 0, sizeof (s3mLastGInstr)); | 1143 | memset(s3mLastGInstr, 0, sizeof (s3mLastGInstr)); |
| 1235 | 1144 | ||
| 1236 | fseek(f, ptnOfs[i] << 4, SEEK_SET); | 1145 | fseek(f, ptnOfs[i] << 4, SEEK_SET); |
| @@ -1295,7 +1204,7 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 58 unmodified lines | |||
| 1295 | } | 1204 | } |
| 1296 | } | 1205 | } |
| 1297 | 1206 | ||
| 1298 | // volume | 1207 | // volume column |
| 1299 | if (typ & 64) | 1208 | if (typ & 64) |
| 1300 | { | 1209 | { |
| 1301 | ton.vol = pattBuff[k++]; | 1210 | ton.vol = pattBuff[k++]; |
| @@ -1312,28 +1221,42 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 10 unmodified lines | |||
| 1312 | ton.effTyp = pattBuff[k++]; | 1221 | ton.effTyp = pattBuff[k++]; |
| 1313 | ton.eff = pattBuff[k++]; | 1222 | ton.eff = pattBuff[k++]; |
| 1314 | 1223 | ||
| 1315 | if (ton.eff == 0) | 1224 | if (ton.eff > 0) |
| 1316 | { | 1225 | { |
| 1317 | if (ton.effTyp == 4) | 1226 | alastnfo[ii] = ton.eff; |
| 1318 | { | 1227 | if (ton.effTyp == 8 || ton.effTyp == 21) |
| 1319 | if ((s3mLastDEff[ii] & 0xF0) == 0xF0 || (s3mLastDEff[ii] & 0x0F) == 0x0F) | 1228 | alastvibnfo[ii] = ton.eff; // H/U |
| 1320 | ton.eff = s3mLastDEff[ii]; | ||
| 1321 | } | ||
| 1322 | else if (ton.effTyp == 5) ton.eff = s3mLastEEff[ii]; | ||
| 1323 | else if (ton.effTyp == 6) ton.eff = s3mLastFEff[ii]; | ||
| 1324 | else if (ton.effTyp == 10) ton.eff = s3mLastJEff[ii]; | ||
| 1325 | else if (ton.effTyp == 19) ton.eff = s3mLastSEff[ii]; | ||
| 1326 | } | 1229 | } |
| 1327 | 1230 | ||
| 1328 | if (ton.eff != 0) | 1231 | // in ST3, a lot of effects directly share the same memory! |
| 1232 | if (ton.eff == 0 && ton.effTyp != 7) // G | ||
| 1329 | { | 1233 | { |
| 1330 | if (ton.effTyp == 4) s3mLastDEff[ii] = ton.eff; | 1234 | uint8_t efx = ton.effTyp; |
| 1331 | else if (ton.effTyp == 5) s3mLastEEff[ii] = ton.eff; | 1235 | if (efx == 8 || efx == 21) // H/U |
| 1332 | else if (ton.effTyp == 6) s3mLastFEff[ii] = ton.eff; | 1236 | ton.eff = alastvibnfo[ii]; |
| 1333 | else if (ton.effTyp == 10) s3mLastJEff[ii] = ton.eff; | 1237 | else if ((efx >= 4 && efx <= 12) || (efx >= 17 && efx <= 19)) // D/E/F/I/J/K/L/Q/R/S |
| 1334 | else if (ton.effTyp == 19) s3mLastSEff[ii] = ton.eff; | 1238 | ton.eff = alastnfo[ii]; |
| 1239 | |||
| 1240 | /* If effect data is zero and effect type was the same as last one, clear out | ||
| 1241 | ** data if it's not J or S (those have no memory in the equivalent XM effects). | ||
| 1242 | ** Also goes for extra fine pitch slides and fine volume slides, | ||
| 1243 | ** since they get converted to other effects. | ||
| 1244 | */ | ||
| 1245 | if (efx == alastefx[ii] && ton.effTyp != 10 && ton.effTyp != 19) // J/S | ||
| 1246 | { | ||
| 1247 | uint8_t nfo = ton.eff; | ||
| 1248 | bool extraFinePitchSlides = (efx == 5 || efx == 6) && ((nfo & 0xF0) == 0xE0); | ||
| 1249 | bool fineVolSlides = (efx == 4 || efx == 11) && | ||
| 1250 | ((nfo > 0xF0) || (((nfo & 0xF) == 0xF) && ((nfo & 0xF0) > 0))); | ||
| 1251 | |||
| 1252 | if (!extraFinePitchSlides && !fineVolSlides) | ||
| 1253 | ton.eff = 0; | ||
| 1254 | } | ||
| 1335 | } | 1255 | } |
| 1336 | 1256 | ||
| 1257 | if (ton.effTyp > 0) | ||
| 1258 | alastefx[ii] = ton.effTyp; | ||
| 1259 | |||
| 1337 | switch (ton.effTyp) | 1260 | switch (ton.effTyp) |
| 1338 | { | 1261 | { |
| 1339 | case 1: // A | 1262 | case 1: // A |
| @@ -1351,14 +1274,12 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 11 unmodified lines | |||
| 1351 | case 3: ton.effTyp = 0xD; break; // C | 1274 | case 3: ton.effTyp = 0xD; break; // C |
| 1352 | case 4: // D | 1275 | case 4: // D |
| 1353 | { | 1276 | { |
| 1354 | if ((ton.eff & 0xF0) == 0) ton.effTyp = 0xA; | 1277 | if (ton.eff > 0xF0) // fine slide up |
| 1355 | else if ((ton.eff & 0x0F) == 0) ton.effTyp = 0xA; | ||
| 1356 | else if ((ton.eff & 0xF0) == 0xF0) | ||
| 1357 | { | 1278 | { |
| 1358 | ton.effTyp = 0xE; | 1279 | ton.effTyp = 0xE; |
| 1359 | ton.eff = 0xB0 | (ton.eff & 15); | 1280 | ton.eff = 0xB0 | (ton.eff & 0xF); |
| 1360 | } | 1281 | } |
| 1361 | else if ((ton.eff & 0x0F) == 0x0F) | 1282 | else if ((ton.eff & 0x0F) == 0x0F && (ton.eff & 0xF0) > 0) // fine slide down |
| 1362 | { | 1283 | { |
| 1363 | ton.effTyp = 0xE; | 1284 | ton.effTyp = 0xE; |
| 1364 | ton.eff = 0xA0 | (ton.eff >> 4); | 1285 | ton.eff = 0xA0 | (ton.eff >> 4); |
| @@ -1366,10 +1287,8 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 1 unmodified line | |||
| 1366 | else | 1287 | else |
| 1367 | { | 1288 | { |
| 1368 | ton.effTyp = 0xA; | 1289 | ton.effTyp = 0xA; |
| 1369 | if (ton.eff & 0x0F) | 1290 | if (ton.eff & 0x0F) // on D/K, last nybble has first priority in ST3 |
| 1370 | ton.eff &= 0x0F; | 1291 | ton.eff &= 0x0F; |
| 1371 | else | ||
| 1372 | ton.eff &= 0xF0; | ||
| 1373 | } | 1292 | } |
| 1374 | } | 1293 | } |
| 1375 | break; | 1294 | break; |
| @@ -1379,6 +1298,7 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 3 unmodified lines | |||
| 1379 | { | 1298 | { |
| 1380 | if ((ton.eff & 0xF0) >= 0xE0) | 1299 | if ((ton.eff & 0xF0) >= 0xE0) |
| 1381 | { | 1300 | { |
| 1301 | // convert to fine slide | ||
| 1382 | if ((ton.eff & 0xF0) == 0xE0) | 1302 | if ((ton.eff & 0xF0) == 0xE0) |
| 1383 | tmp = 0x21; | 1303 | tmp = 0x21; |
| 1384 | else | 1304 | else |
| @@ -1392,9 +1312,15 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 7 unmodified lines | |||
| 1392 | ton.eff |= 0x10; | 1312 | ton.eff |= 0x10; |
| 1393 | 1313 | ||
| 1394 | ton.effTyp = (uint8_t)tmp; | 1314 | ton.effTyp = (uint8_t)tmp; |
| 1315 | |||
| 1316 | if (ton.effTyp == 0x21 && ton.eff == 0) | ||
| 1317 | { | ||
| 1318 | ton.effTyp = 0; | ||
| 1319 | } | ||
| 1395 | } | 1320 | } |
| 1396 | else | 1321 | else |
| 1397 | { | 1322 | { |
| 1323 | // convert to normal 1xx/2xx slide | ||
| 1398 | ton.effTyp = 7 - ton.effTyp; | 1324 | ton.effTyp = 7 - ton.effTyp; |
| 1399 | } | 1325 | } |
| 1400 | } | 1326 | } |
| @@ -1402,18 +1328,46 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 1 unmodified line | |||
| 1402 | 1328 | ||
| 1403 | case 7: // G | 1329 | case 7: // G |
| 1404 | { | 1330 | { |
| 1331 | ton.effTyp = 0x03; | ||
| 1332 | |||
| 1405 | // fix illegal slides (to new instruments) | 1333 | // fix illegal slides (to new instruments) |
| 1406 | if (ton.instr != 0 && ton.instr != s3mLastGInstr[ii]) | 1334 | if (ton.instr != 0 && ton.instr != s3mLastGInstr[ii]) |
| 1407 | ton.instr = s3mLastGInstr[ii]; | 1335 | ton.instr = s3mLastGInstr[ii]; |
| 1336 | } | ||
| 1337 | break; | ||
| 1408 | 1338 | ||
| 1409 | ton.effTyp = 0x03; | 1339 | case 11: // K |
| 1340 | { | ||
| 1341 | if (ton.eff > 0xF0) // fine slide up | ||
| 1342 | { | ||
| 1343 | ton.effTyp = 0xE; | ||
| 1344 | ton.eff = 0xB0 | (ton.eff & 0xF); | ||
| 1345 | |||
| 1346 | // if volume column is unoccupied, set to vibrato | ||
| 1347 | if (ton.vol == 0) | ||
| 1348 | ton.vol = 0xB0; | ||
| 1349 | } | ||
| 1350 | else if ((ton.eff & 0x0F) == 0x0F && (ton.eff & 0xF0) > 0) // fine slide down | ||
| 1351 | { | ||
| 1352 | ton.effTyp = 0xE; | ||
| 1353 | ton.eff = 0xA0 | (ton.eff >> 4); | ||
| 1354 | |||
| 1355 | // if volume column is unoccupied, set to vibrato | ||
| 1356 | if (ton.vol == 0) | ||
| 1357 | ton.vol = 0xB0; | ||
| 1358 | } | ||
| 1359 | else | ||
| 1360 | { | ||
| 1361 | ton.effTyp = 0x6; | ||
| 1362 | if (ton.eff & 0x0F) // on D/K, last nybble has first priority in ST3 | ||
| 1363 | ton.eff &= 0x0F; | ||
| 1364 | } | ||
| 1410 | } | 1365 | } |
| 1411 | break; | 1366 | break; |
| 1412 | 1367 | ||
| 1413 | case 8: ton.effTyp = 0x04; break; // H | 1368 | case 8: ton.effTyp = 0x04; break; // H |
| 1414 | case 9: ton.effTyp = 0x1D; break; // I | 1369 | case 9: ton.effTyp = 0x1D; break; // I |
| 1415 | case 10: ton.effTyp = 0x00; break; // J | 1370 | case 10: ton.effTyp = 0x00; break; // J |
| 1416 | case 11: ton.effTyp = 0x06; break; // K | ||
| 1417 | case 12: ton.effTyp = 0x05; break; // L | 1371 | case 12: ton.effTyp = 0x05; break; // L |
| 1418 | case 15: ton.effTyp = 0x09; break; // O | 1372 | case 15: ton.effTyp = 0x09; break; // O |
| 1419 | case 17: ton.effTyp = 0x1B; break; // Q | 1373 | case 17: ton.effTyp = 0x1B; break; // Q |
| @@ -1429,10 +1383,37 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 9 unmodified lines | |||
| 1429 | else if (tmp == 0x2) ton.eff |= 0x50; | 1383 | else if (tmp == 0x2) ton.eff |= 0x50; |
| 1430 | else if (tmp == 0x3) ton.eff |= 0x40; | 1384 | else if (tmp == 0x3) ton.eff |= 0x40; |
| 1431 | else if (tmp == 0x4) ton.eff |= 0x70; | 1385 | else if (tmp == 0x4) ton.eff |= 0x70; |
| 1432 | // we ignore S8x (set 4-bit pan) becuase it's not compatible with FT2 panning | 1386 | // ignore S8x becuase it's not compatible with FT2 panning |
| 1433 | else if (tmp == 0xB) ton.eff |= 0x60; | 1387 | else if (tmp == 0xB) ton.eff |= 0x60; |
| 1434 | else if (tmp == 0xC) ton.eff |= 0xC0; | 1388 | else if (tmp == 0xC) // Note Cut |
| 1435 | else if (tmp == 0xD) ton.eff |= 0xD0; | 1389 | { |
| 1390 | ton.eff |= 0xC0; | ||
| 1391 | if (ton.eff == 0xC0) | ||
| 1392 | { | ||
| 1393 | // EC0 does nothing in ST3 but cuts voice in FT2, remove effect | ||
| 1394 | ton.effTyp = 0; | ||
| 1395 | ton.eff = 0; | ||
| 1396 | } | ||
| 1397 | } | ||
| 1398 | else if (tmp == 0xD) // Note Delay | ||
| 1399 | { | ||
| 1400 | ton.eff |= 0xD0; | ||
| 1401 | if (ton.ton == 0 || ton.ton == 97) | ||
| 1402 | { | ||
| 1403 | // EDx without a note does nothing in ST3 but retrigs in FT2, remove effect | ||
| 1404 | ton.effTyp = 0; | ||
| 1405 | ton.eff = 0; | ||
| 1406 | } | ||
| 1407 | else if (ton.eff == 0xD0) | ||
| 1408 | { | ||
| 1409 | // ED0 prevents note/smp/vol from updating in ST3, remove everything | ||
| 1410 | ton.ton = 0; | ||
| 1411 | ton.instr = 0; | ||
| 1412 | ton.vol = 0; | ||
| 1413 | ton.effTyp = 0; | ||
| 1414 | ton.eff = 0; | ||
| 1415 | } | ||
| 1416 | } | ||
| 1436 | else if (tmp == 0xE) ton.eff |= 0xE0; | 1417 | else if (tmp == 0xE) ton.eff |= 0xE0; |
| 1437 | else if (tmp == 0xF) ton.eff |= 0xF0; | 1418 | else if (tmp == 0xF) ton.eff |= 0xF0; |
| 1438 | else | 1419 | else |
| @@ -1454,40 +1435,18 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 15 unmodified lines | |||
| 1454 | } | 1435 | } |
| 1455 | break; | 1436 | break; |
| 1456 | 1437 | ||
| 1457 | case 21: // U (fine vibrato, doesn't exist in FT2, do a poor conversion to normal vibrato) | 1438 | case 22: // V |
| 1458 | { | 1439 | { |
| 1459 | if ((ton.eff & 0x0F) != 0) | 1440 | ton.effTyp = 0x10; |
| 1441 | if (ton.eff > 0x40) | ||
| 1460 | { | 1442 | { |
| 1461 | ton.eff = (ton.eff & 0xF0) | (((ton.eff & 15) + 1) >> 2); // divide depth by 4 | 1443 | // Vxx > 0x40 does nothing in ST3 |
| 1462 | if ((ton.eff & 0x0F) == 0) // depth too low, remove effect | 1444 | ton.effTyp = 0; |
| 1463 | { | 1445 | ton.eff = 0; |
| 1464 | illegalUxx = true; | ||
| 1465 | ton.effTyp = 0; | ||
| 1466 | ton.eff = 0; | ||
| 1467 | } | ||
| 1468 | else | ||
| 1469 | { | ||
| 1470 | illegalUxx = false; | ||
| 1471 | ton.effTyp = 0x04; | ||
| 1472 | } | ||
| 1473 | } | ||
| 1474 | else | ||
| 1475 | { | ||
| 1476 | if (!illegalUxx) | ||
| 1477 | { | ||
| 1478 | ton.effTyp = 0x04; | ||
| 1479 | } | ||
| 1480 | else | ||
| 1481 | { | ||
| 1482 | ton.effTyp = 0; | ||
| 1483 | ton.eff = 0; | ||
| 1484 | } | ||
| 1485 | } | 1446 | } |
| 1486 | } | 1447 | } |
| 1487 | break; | 1448 | break; |
| 1488 | 1449 | ||
| 1489 | case 22: ton.effTyp = 0x10; break; // V | ||
| 1490 | |||
| 1491 | default: | 1450 | default: |
| 1492 | { | 1451 | { |
| 1493 | ton.effTyp = 0; | 1452 | ton.effTyp = 0; |
| @@ -1500,40 +1459,6 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 6 unmodified lines | |||
| 1500 | if (ton.instr != 0 && ton.effTyp != 0x3) | 1459 | if (ton.instr != 0 && ton.effTyp != 0x3) |
| 1501 | s3mLastGInstr[ii] = ton.instr; | 1460 | s3mLastGInstr[ii] = ton.instr; |
| 1502 | 1461 | ||
| 1503 | // EDx with no note does nothing in ST3 but retrigs in FT2, remove effect | ||
| 1504 | if (ton.effTyp == 0xE && (ton.eff & 0xF0) == 0xD0) | ||
| 1505 | { | ||
| 1506 | if (ton.ton == 0 || ton.ton == 97) | ||
| 1507 | { | ||
| 1508 | ton.effTyp = 0; | ||
| 1509 | ton.eff = 0; | ||
| 1510 | } | ||
| 1511 | } | ||
| 1512 | |||
| 1513 | // EDx with a zero will prevent note/instr/vol from updating in ST3, remove everything | ||
| 1514 | if (ton.effTyp == 0xE && ton.eff == 0xD0) | ||
| 1515 | { | ||
| 1516 | ton.ton = 0; | ||
| 1517 | ton.instr = 0; | ||
| 1518 | ton.vol = 0; | ||
| 1519 | ton.effTyp = 0; | ||
| 1520 | ton.eff = 0; | ||
| 1521 | } | ||
| 1522 | |||
| 1523 | // ECx with a zero does nothing in ST3 but cuts voice in FT2, remove effect | ||
| 1524 | if (ton.effTyp == 0xE && ton.eff == 0xC0) | ||
| 1525 | { | ||
| 1526 | ton.effTyp = 0; | ||
| 1527 | ton.eff = 0; | ||
| 1528 | } | ||
| 1529 | |||
| 1530 | // Vxx with a value higher than 64 (0x40) does nothing in ST3, remove effect | ||
| 1531 | if (ton.effTyp == 0x10 && ton.eff > 0x40) | ||
| 1532 | { | ||
| 1533 | ton.effTyp = 0; | ||
| 1534 | ton.eff = 0; | ||
| 1535 | } | ||
| 1536 | |||
| 1537 | if (ton.effTyp > 35) | 1462 | if (ton.effTyp > 35) |
| 1538 | { | 1463 | { |
| 1539 | ton.effTyp = 0; | 1464 | ton.effTyp = 0; |
| @@ -1610,10 +1535,10 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 70 unmodified lines | |||
| 1610 | bool is16Bit = (h_S3MInstr.flags >> 2) & 1; | 1535 | bool is16Bit = (h_S3MInstr.flags >> 2) & 1; |
| 1611 | 1536 | ||
| 1612 | if (is16Bit) // 16-bit | 1537 | if (is16Bit) // 16-bit |
| 1613 | len *= 2; | 1538 | len <<= 1; |
| 1614 | 1539 | ||
| 1615 | if (stereoSample) // stereo | 1540 | if (stereoSample) // stereo |
| 1616 | len *= 2; | 1541 | len <<= 1; |
| 1617 | 1542 | ||
| 1618 | tmpSmp = (int8_t *)malloc(len + LOOP_FIX_LEN); | 1543 | tmpSmp = (int8_t *)malloc(len + LOOP_FIX_LEN); |
| 1619 | if (tmpSmp == NULL) | 1544 | if (tmpSmp == NULL) |
| @@ -1683,9 +1608,9 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 63 unmodified lines | |||
| 1683 | s->origPek = tmpSmp; | 1608 | s->origPek = tmpSmp; |
| 1684 | s->pek = s->origPek + SMP_DAT_OFFSET; | 1609 | s->pek = s->origPek + SMP_DAT_OFFSET; |
| 1685 | 1610 | ||
| 1686 | s->len *= 2; | 1611 | s->len <<= 1; |
| 1687 | s->repS *= 2; | 1612 | s->repS <<= 1; |
| 1688 | s->repL *= 2; | 1613 | s->repL <<= 1; |
| 1689 | } | 1614 | } |
| 1690 | else | 1615 | else |
| 1691 | { | 1616 | { |
| @@ -1712,74 +1637,6 @@ static bool loadMusicS3M(FILE *f, uint32_t dataLength, bool fromExternalThread) · 20 unmodified lines | |||
| 1712 | } | 1637 | } |
| 1713 | } | 1638 | } |
| 1714 | 1639 | ||
| 1715 | // non-FT2: fix overflown 9xx and illegal 3xx slides | ||
| 1716 | |||
| 1717 | for (i = 0; i < ap; i++) | ||
| 1718 | { | ||
| 1719 | if (pattTmp[i] == NULL) | ||
| 1720 | continue; | ||
| 1721 | |||
| 1722 | for (k = 0; k < songTmp.antChn; k++) | ||
| 1723 | { | ||
| 1724 | check3xx = false; | ||
| 1725 | for (j = 0; j < 64; j++) | ||
| 1726 | { | ||
| 1727 | pattTon = &pattTmp[i][(j * MAX_VOICES) + k]; | ||
| 1728 | |||
| 1729 | // fix illegal 3xx slides | ||
| 1730 | |||
| 1731 | if (pattTon->ton > 0 && pattTon->ton < 97) | ||
| 1732 | check3xx = pattTon->effTyp != 0x3; | ||
| 1733 | |||
| 1734 | if (check3xx && pattTon->effTyp == 0x3) | ||
| 1735 | { | ||
| 1736 | if (pattTon->ton == 0 || pattTon->ton == 97) | ||
| 1737 | { | ||
| 1738 | pattTon->effTyp = 0; | ||
| 1739 | pattTon->eff = 0; | ||
| 1740 | } | ||
| 1741 | } | ||
| 1742 | |||
| 1743 | /* In ST3 in GUS mode, an overflowed sample offset behaves like this: | ||
| 1744 | ** - Non-looped sample: Cut voice | ||
| 1745 | ** - Looped sample: Wrap around loop point | ||
| 1746 | ** | ||
| 1747 | ** What we do here is to change the sample offset value to point to | ||
| 1748 | ** the wrapped sample loop position. This may be off by up to 256 bytes | ||
| 1749 | ** though... | ||
| 1750 | */ | ||
| 1751 | |||
| 1752 | if (pattTon->effTyp == 0x9 && pattTon->eff > 0 && pattTon->instr > 0 && pattTon->instr <= ai && ai <= 128) | ||
| 1753 | { | ||
| 1754 | instrTyp *ins = instrTmp[pattTon->instr]; | ||
| 1755 | if (ins == NULL) | ||
| 1756 | continue; // empty instrument (sample) | ||
| 1757 | |||
| 1758 | s = &ins->samp[0]; | ||
| 1759 | if (s->len > 0 && (s->typ & 1)) // only handle non-empty looping samples | ||
| 1760 | { | ||
| 1761 | uint32_t loopEnd = s->repS + s->repL; | ||
| 1762 | uint32_t offset = pattTon->eff * 256; | ||
| 1763 | |||
| 1764 | if (offset >= loopEnd) | ||
| 1765 | { | ||
| 1766 | if (s->repL >= 2) | ||
| 1767 | offset = s->repS + ((offset - loopEnd) % s->repL); | ||
| 1768 | else | ||
| 1769 | offset = s->repS; | ||
| 1770 | |||
| 1771 | offset = (offset + (1 << 7)) >> 8; // convert to rounded sample offset value | ||
| 1772 | if (offset > 255) | ||
| 1773 | offset = 255; | ||
| 1774 | |||
| 1775 | pattTon->eff = (uint8_t)offset; | ||
| 1776 | } | ||
| 1777 | } | ||
| 1778 | } | ||
| 1779 | } | ||
| 1780 | } | ||
| 1781 | } | ||
| 1782 | |||
| 1783 | fclose(f); | 1640 | fclose(f); |
| 1784 | 1641 | ||
| 1785 | songTmp.antChn = countS3MChannels(ap); | 1642 | songTmp.antChn = countS3MChannels(ap); |
| @@ -2566,30 +2423,37 @@ static void setupLoadedModule(void) · 780 unmodified lines | |||
| 2566 | // support non-even channel numbers | 2423 | // support non-even channel numbers |
| 2567 | if (song.antChn & 1) | 2424 | if (song.antChn & 1) |
| 2568 | { | 2425 | { |
| 2569 | if (++song.antChn > MAX_VOICES) | 2426 | song.antChn++; |
| 2427 | if (song.antChn > MAX_VOICES) | ||
| 2570 | song.antChn = MAX_VOICES; | 2428 | song.antChn = MAX_VOICES; |
| 2571 | } | 2429 | } |
| 2572 | 2430 | ||
| 2573 | if (song.repS > song.len) | 2431 | if (song.len == 0) |
| 2432 | song.len = 1; | ||
| 2433 | |||
| 2434 | if (song.repS >= song.len) | ||
| 2574 | song.repS = 0; | 2435 | song.repS = 0; |
| 2575 | 2436 | ||
| 2576 | song.globVol = 64; | 2437 | song.globVol = 64; |
| 2577 | song.timer = 1; | ||
| 2578 | 2438 | ||
| 2579 | setScrollBarEnd(SB_POS_ED, (song.len - 1) + 5); | 2439 | setScrollBarEnd(SB_POS_ED, (song.len - 1) + 5); |
| 2580 | setScrollBarPos(SB_POS_ED, 0, false); | 2440 | setScrollBarPos(SB_POS_ED, 0, false); |
| 2581 | 2441 | ||
| 2582 | resetChannels(); | 2442 | resetChannels(); |
| 2583 | setPos(0, 0, false); | 2443 | setPos(0, 0, true); |
| 2584 | setSpeed(song.speed); | 2444 | setSpeed(song.speed); |
| 2585 | 2445 | ||
| 2586 | editor.tmpPattern = editor.editPattern; // set kludge variable | 2446 | editor.tmpPattern = editor.editPattern; // set kludge variable |
| 2587 | editor.speed = song.speed; | 2447 | editor.speed = song.speed; |
| 2588 | editor.tempo = song.tempo; | 2448 | editor.tempo = song.tempo; |
| 2589 | editor.timer = 1; | 2449 | editor.timer = song.timer; |
| 2590 | editor.globalVol = song.globVol; | 2450 | editor.globalVol = song.globVol; |
| 2591 | 2451 | ||
| 2592 | setFrqTab((loadedFormat == FORMAT_XM) ? linearFreqTable : false); | 2452 | if (loadedFormat == FORMAT_XM) |
| 2453 | setFrqTab(linearFreqTable); | ||
| 2454 | else | ||
| 2455 | setFrqTab(false); | ||
| 2456 | |||
| 2593 | unlockMixerCallback(); | 2457 | unlockMixerCallback(); |
| 2594 | 2458 | ||
| 2595 | editor.currVolEnvPoint = 0; | 2459 | editor.currVolEnvPoint = 0; |
| @@ -2602,9 +2466,10 @@ static void setupLoadedModule(void) · 6 unmodified lines | |||
| 2602 | updateChanNums(); | 2466 | updateChanNums(); |
| 2603 | resetWavRenderer(); | 2467 | resetWavRenderer(); |
| 2604 | clearPattMark(); | 2468 | clearPattMark(); |
| 2605 | song.musicTime = 0; | ||
| 2606 | resetTrimSizes(); | 2469 | resetTrimSizes(); |
| 2607 | 2470 | ||
| 2471 | song.musicTime = 0; | ||
| 2472 | |||
| 2608 | diskOpSetFilename(DISKOP_ITEM_MODULE, editor.tmpFilenameU); | 2473 | diskOpSetFilename(DISKOP_ITEM_MODULE, editor.tmpFilenameU); |
| 2609 | 2474 | ||
| 2610 | // redraw top part of screen | 2475 | // redraw top part of screen |