History

Pushed v1.07 code

- Bugfix: After deleting the very last vol/pan envelope point, the currently selected point wouldn't be properly set. This is actually a behavior/bug from real FT2, but I wanted to fix it anyway. - Bugfix: Attempting to add a vol/pan envelope point to a completely empty envelope would mess things up. Empty envelopes in an allocated instrument shouldn't happen, but it happens when loading certain non-FT2 XMs. - Bugfix: The envelope plotter could display garbage on envelopes with tick offsets above 324. Now it just cuts off at the end instead. Also yes, such envelopes can be made! OpenMPT, f.ex., has no 0..324 limit for envelope ticks in XM mode. - Bugfix: A couple of system request dialogs had the wrong button captions. (Yes/No instead of OK/Cancel). - When pressing Esc. and the song is unmodified/saved, you'll now get the classic joke quit dialogs from FT2 asking if you really want to quit. - Some minor optimizations and minor fixups. Nothing to write home about... - Windows 32-bit: This version now requires your CPU to have the SSE2 instruction set. Intel CPUs from around 2000 (AMD around 2003) and later have it. In other words, it's not worth my time trying to make the clone run on such old machines!

Olav Sørensen committed 6 years ago

Commit fe46cb41 parent 8eb89a132 files · +945 −731Browse files

Unified · Split

32 files
  1. .gitignore +2 −0
  2. src/ft2_about.c +8 −4
  3. src/ft2_audio.c +33 −25
  4. src/ft2_audio.h +1 −1
  5. src/ft2_config.c +10 −2
  6. src/ft2_diskop.c +1 −1
  7. src/ft2_edit.c +1 −1
  8. src/ft2_gui.c +16 −16
  9. src/ft2_header.h +4 −1
  10. src/ft2_inst_ed.c +89 −60
  11. src/ft2_keyboard.c +13 −7
  12. src/ft2_main.c +8 −0
  13. src/ft2_module_loader.c +50 −14
  14. src/ft2_module_loader.h +1 −0
  15. src/ft2_mouse.c +22 −12
  16. src/ft2_mouse.h +0 −1
  17. src/ft2_palette.c +5 −0
  18. src/ft2_palette.h +5 −0
  19. src/ft2_pattern_draw.c +439 −464
  20. src/ft2_pattern_draw.h +3 −2
  21. src/ft2_pattern_ed.c +26 −13
  22. src/ft2_pattern_ed.h +0 −1
  23. src/ft2_replayer.c +31 −36
  24. src/ft2_scopes.c +9 −5
  25. src/ft2_scrollbars.c +20 −1
  26. src/ft2_scrollbars.h +1 −0
  27. src/ft2_sysreqs.c +84 −27
  28. src/ft2_sysreqs.h +11 −4
  29. src/ft2_video.c +39 −25
  30. src/ft2_video.h +8 −7
  31. src/gfxdata/bmp/patternfonts.bmp +0 −0
  32. vs2019_project/ft2-clone/ft2-clone.vcxproj +6 −2
.gitignore+2−0
@@ -15,3 +15,5 @@ vs2019_project/.vs/ft2-clone/v16/.suo · 14 unmodified lines
1515 vs2019_project/ft2-clone/Release/ft2-clone.vcxproj.FileListAbsolute.txt
1616 vs2019_project/ft2-clone/x64/Debug/ft2-clone.vcxproj.FileListAbsolute.txt
1717 *.cod
18+vs2019_project/ft2-clone/Debug/ft2-clone.vcxproj.FileListAbsolute.txt
19+*.opendb
src/ft2_about.c+8−4
@@ -7,7 +7,7 @@ · 6 unmodified lines
77
88 // ported from original FT2 code
99
10−#define NUM_STARS 650
10+#define NUM_STARS 512
1111 #define ABOUT_SCREEN_W 626
1212 #define ABOUT_SCREEN_H 167
1313 #define FT2_LOGO_W 449
@@ -231,6 +231,8 @@ void aboutFrame(void) · 217 unmodified lines
231231
232232 void showAboutScreen(void) // called once when About screen is opened
233233 {
234+#define TEXT_BORDER_COL 0x2E2E2E
235+
234236 const char *infoString = "Clone by Olav \"8bitbubsy\" S\025rensen - https://16-bits.org";
235237 char verText[32];
236238 uint16_t x, y;
@@ -246,16 +248,18 @@ void showAboutScreen(void) // called once when About screen is opened · 9 unmodified lines
246248 showPushButton(PB_EXIT_ABOUT);
247249
248250 blit32(91, 31, ft2Logo, FT2_LOGO_W, FT2_LOGO_H);
249− blit(146, 113, aboutText, ABOUT_TEXT_W, ABOUT_TEXT_H);
251+ blit(146, 113, aboutText, ABOUT_TEXT_W, ABOUT_TEXT_H);
252+
253+ setCustomPalColor(TEXT_BORDER_COL); // sets PAL_CUSTOM
250254
251255 x = 5 + (SCREEN_W - textWidth(infoString)) / 2;
252256 y = 147;
253− textOutBorder(x, y, PAL_FORGRND, PAL_BUTTON2, infoString);
257+ textOutBorder(x, y, PAL_FORGRND, PAL_CUSTOM, infoString);
254258
255259 sprintf(verText, "v%s (compiled on %s)", PROG_VER_STR, __DATE__);
256260 x = ((3 + ABOUT_SCREEN_W) - textWidth(verText)) / 2;
257261 y = (3 + ABOUT_SCREEN_H) - ((FONT1_CHAR_H - 2) + 3);
258− textOutBorder(x, y, PAL_FORGRND, PAL_BUTTON2, verText);
262+ textOutBorder(x, y, PAL_FORGRND, PAL_CUSTOM, verText);
259263
260264 aboutInit();
261265
src/ft2_audio.c+33−25
@@ -20,7 +20,7 @@ · 19 unmodified lines
2020
2121 static int8_t pmpCountDiv, pmpChannels = 2;
2222 static uint16_t smpBuffSize;
23−static int32_t masterVol, amp, oldAudioFreq, speedVal, pmpLeft, randSeed = INITIAL_DITHER_SEED;
23+static int32_t masterVol, masterAmp, oldAudioFreq, speedVal, pmpLeft, randSeed = INITIAL_DITHER_SEED;
2424 static uint32_t tickTimeLen, tickTimeLenFrac, oldSFrq, oldSFrqRev = 0xFFFFFFFF;
2525 static float fAudioAmpMul;
2626 static voice_t voice[MAX_VOICES * 2];
@@ -124,9 +124,9 @@ void setAudioAmp(int16_t ampFactor, int16_t master, bool bitDepth32Flag) · 97 unmodified lines
124124
125125 // calculate channel amp
126126
127− if (amp != ampFactor)
127+ if (masterAmp != ampFactor)
128128 {
129− amp = ampFactor;
129+ masterAmp = ampFactor;
130130
131131 // make all channels update volume because of amp change
132132 for (uint32_t i = 0; i < song.antChn; i++)
@@ -164,10 +164,18 @@ void setSpeed(uint16_t bpm) · 31 unmodified lines
164164 // number of samples per tick -> tick length for performance counter
165165 dFrac = modf(speedVal * audio.dSpeedValMul, &dInt);
166166
167− // integer part
168− tickTimeLen = (uint32_t)dInt;
169−
170− // fractional part (scaled to 0..2^32-1)
167+ /* - integer part -
168+ ** Cast to int32_t so that the compiler will use fast SSE2 float->int instructions.
169+ ** This result won't be above 2^31, so this is safe.
170+ */
171+ tickTimeLen = (int32_t)dInt;
172+
173+ /* - fractional part (scaled to 0..2^32-1) -
174+ ** We have to resort to slow float->int conversion here because the result
175+ ** can be above 2^31. In 64-bit mode, this will still use a fast SSE2 instruction.
176+ ** Anyhow, this function won't be called that many times a second in worst case,
177+ ** so it's not a big issue at all.
178+ */
171179 dFrac *= UINT32_MAX;
172180 tickTimeLenFrac = (uint32_t)(dFrac + 0.5);
173181 }
@@ -194,7 +202,7 @@ static inline void voiceUpdateVolumes(uint8_t i, uint8_t status) · 20 unmodified lines
194202
195203 v = &voice[i];
196204
197− volL = v->SVol * amp; // 0..2047 * 1..32 = 0..65504
205+ volL = v->SVol * masterAmp; // 0..2047 * 1..32 = 0..65504
198206
199207 // (0..65504 * 0..65536) >> 4 = 0..268304384
200208 volR = ((uint32_t)volL * panningTab[v->SPan]) >> 4;
@@ -331,7 +339,6 @@ void mix_SaveIPVolumes(void) // for volume ramping · 130 unmodified lines
331339 void mix_UpdateChannelVolPanFrq(void)
332340 {
333341 uint8_t status;
334− uint16_t vol;
335342 stmTyp *ch;
336343 voice_t *v;
337344
@@ -347,13 +354,7 @@ void mix_UpdateChannelVolPanFrq(void) · 9 unmodified lines
347354
348355 // volume change
349356 if (status & IS_Vol)
350− {
351− vol = ch->finalVol;
352− if (vol > 0) // yes, FT2 does this!
353− vol--;
354−
355− v->SVol = vol;
356− }
357+ v->SVol = ch->finalVol;
357358
358359 // panning change
359360 if (status & IS_Pan)
@@ -1063,28 +1064,35 @@ static bool setupAudioBuffers(void) · 703 unmodified lines
10631064 {
10641065 const uint32_t sampleSize = sizeof (int32_t);
10651066
1066− audio.mixBufferL = (int32_t *)malloc(MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize);
1067− audio.mixBufferR = (int32_t *)malloc(MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize);
1067+ audio.mixBufferLUnaligned = (int32_t *)MALLOC_PAD(MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize, 256);
1068+ audio.mixBufferRUnaligned = (int32_t *)MALLOC_PAD(MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize, 256);
10681069
1069− if (audio.mixBufferL == NULL || audio.mixBufferR == NULL)
1070+ if (audio.mixBufferLUnaligned == NULL || audio.mixBufferRUnaligned == NULL)
10701071 return false;
10711072
1073+ // make aligned main pointers
1074+ audio.mixBufferL = (int32_t *)ALIGN_PTR(audio.mixBufferLUnaligned, 256);
1075+ audio.mixBufferR = (int32_t *)ALIGN_PTR(audio.mixBufferRUnaligned, 256);
1076+
10721077 return true;
10731078 }
10741079
10751080 static void freeAudioBuffers(void)
10761081 {
1077− if (audio.mixBufferL != NULL)
1082+ if (audio.mixBufferLUnaligned != NULL)
10781083 {
1079− free(audio.mixBufferL);
1080− audio.mixBufferL = NULL;
1084+ free(audio.mixBufferLUnaligned);
1085+ audio.mixBufferLUnaligned = NULL;
10811086 }
10821087
1083− if (audio.mixBufferR != NULL)
1088+ if (audio.mixBufferRUnaligned != NULL)
10841089 {
1085− free(audio.mixBufferR);
1086− audio.mixBufferR = NULL;
1090+ free(audio.mixBufferRUnaligned);
1091+ audio.mixBufferRUnaligned = NULL;
10871092 }
1093+
1094+ audio.mixBufferL = NULL;
1095+ audio.mixBufferR = NULL;
10881096 }
10891097
10901098 void updateSendAudSamplesRoutine(bool lockMixer)
src/ft2_audio.h+1−1
@@ -26,7 +26,7 @@ struct audio_t · 25 unmodified lines
2626 volatile bool locked, resetSyncTickTimeFlag, volumeRampingFlag, interpolationFlag;
2727 bool linearFreqTable, rescanAudioDevicesSupported;
2828 int32_t inputDeviceNum, outputDeviceNum, lastWorkingAudioFreq, lastWorkingAudioBits;
29− int32_t quickVolSizeVal, *mixBufferL, *mixBufferR;
29+ int32_t quickVolSizeVal, *mixBufferL, *mixBufferR, *mixBufferLUnaligned, *mixBufferRUnaligned;
3030 uint32_t freq;
3131 uint32_t audLatencyPerfValInt, audLatencyPerfValFrac;
3232 uint64_t tickTime64, tickTime64Frac;
src/ft2_config.c+10−2
@@ -29,6 +29,7 @@ · 28 unmodified lines
2929 #include "ft2_midi.h"
3030 #include "ft2_gfxdata.h"
3131 #include "ft2_palette.h"
32+#include "ft2_pattern_draw.h"
3233
3334 // defined at the bottom of this file
3435 extern const uint8_t defConfigData[CONFIG_FILE_SIZE];
@@ -190,6 +191,7 @@ static void loadConfigFromBuffer(uint8_t defaults) · 155 unmodified lines
190191 changeBadgeType(config.id_TritonProd);
191192 editor.ui.maxVisibleChannels = (uint8_t)(2 + ((config.ptnMaxChannels + 1) * 2));
192193 setPal16(palTable[config.cfg_StdPalNr], true);
194+ updatePattFontPtrs();
193195
194196 unlockMixerCallback();
195197 }
@@ -813,8 +815,10 @@ void setConfigIORadioButtonStates(void) // accessed by other .c files · 617 unmodified lines
813815 uncheckRadioButtonGroup(RB_GROUP_CONFIG_SOUND_BUFF_SIZE);
814816
815817 tmpID = RB_CONFIG_SBS_1024;
816− if (config.specialFlags & BUFFSIZE_512) tmpID = RB_CONFIG_SBS_512;
817− else if (config.specialFlags & BUFFSIZE_2048) tmpID = RB_CONFIG_SBS_2048;
818+ if (config.specialFlags & BUFFSIZE_512)
819+ tmpID = RB_CONFIG_SBS_512;
820+ else if (config.specialFlags & BUFFSIZE_2048)
821+ tmpID = RB_CONFIG_SBS_2048;
818822
819823 radioButtons[tmpID].state = RADIOBUTTON_CHECKED;
820824
@@ -1873,6 +1877,7 @@ void rbConfigFontCapitals(void) · 1052 unmodified lines
18731877 {
18741878 config.ptnFont = PATT_FONT_CAPITALS;
18751879 checkRadioButton(RB_CONFIG_FONT_CAPITALS);
1880+ updatePattFontPtrs();
18761881 redrawPatternEditor();
18771882 }
18781883
@@ -1880,6 +1885,7 @@ void rbConfigFontLowerCase(void) · 1 unmodified line
18801885 {
18811886 config.ptnFont = PATT_FONT_LOWERCASE;
18821887 checkRadioButton(RB_CONFIG_FONT_LOWERCASE);
1888+ updatePattFontPtrs();
18831889 redrawPatternEditor();
18841890 }
18851891
@@ -1887,6 +1893,7 @@ void rbConfigFontFuture(void) · 1 unmodified line
18871893 {
18881894 config.ptnFont = PATT_FONT_FUTURE;
18891895 checkRadioButton(RB_CONFIG_FONT_FUTURE);
1896+ updatePattFontPtrs();
18901897 redrawPatternEditor();
18911898 }
18921899
@@ -1894,6 +1901,7 @@ void rbConfigFontBold(void) · 1 unmodified line
18941901 {
18951902 config.ptnFont = PATT_FONT_BOLD;
18961903 checkRadioButton(RB_CONFIG_FONT_BOLD);
1904+ updatePattFontPtrs();
18971905 redrawPatternEditor();
18981906 }
18991907
src/ft2_diskop.c+1−1
@@ -1089,7 +1089,7 @@ static void fileListPressed(int32_t index) · 1088 unmodified lines
10891089 // in case of UTF8 -> CP437 encoding failure, there can be question marks. Remove them...
10901090 removeQuestionmarksFromString(FReq_NameTemp);
10911091
1092− if (inputBox(2, dirEntry->isDir ? "Enter new directory name:" : "Enter new filename:", FReq_NameTemp, PATH_MAX - 1) == 1)
1092+ if (inputBox(1, dirEntry->isDir ? "Enter new directory name:" : "Enter new filename:", FReq_NameTemp, PATH_MAX - 1) == 1)
10931093 {
10941094 if ((FReq_NameTemp == NULL) || (FReq_NameTemp[0] == '\0'))
10951095 {
src/ft2_edit.c+1−1
@@ -1858,7 +1858,7 @@ static bool askForScaleFade(char *msg) · 1857 unmodified lines
18581858 uint8_t err;
18591859
18601860 sprintf(volstr, "%0.2f,%0.2f", dVolScaleFK1, dVolScaleFK2);
1861− if (inputBox(2, msg, volstr, sizeof (volstr) - 1) != 1)
1861+ if (inputBox(1, msg, volstr, sizeof (volstr) - 1) != 1)
18621862 return false;
18631863
18641864 err = false;
src/ft2_gui.c+16−16
@@ -734,22 +734,22 @@ void fillRect(uint16_t xPos, uint16_t yPos, uint16_t w, uint16_t h, uint8_t pale · 733 unmodified lines
734734
735735 void blit32(uint16_t xPos, uint16_t yPos, const uint32_t* srcPtr, uint16_t w, uint16_t h)
736736 {
737− uint32_t* dstPtr;
738−
739− assert(srcPtr != NULL && xPos < SCREEN_W && yPos < SCREEN_H && (xPos + w) <= SCREEN_W && (yPos + h) <= SCREEN_H);
740−
741− dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
742− for (uint32_t y = 0; y < h; y++)
743− {
744− for (uint32_t x = 0; x < w; x++)
745− {
746− if (srcPtr[x] != 0x00FF00)
747− dstPtr[x] = srcPtr[x] | 0xFF000000; // most significant 8 bits = palette number. 0xFF because no true palette
748− }
749−
750− srcPtr += w;
751− dstPtr += SCREEN_W;
752− }
737+ uint32_t* dstPtr;
738+
739+ assert(srcPtr != NULL && xPos < SCREEN_W && yPos < SCREEN_H && (xPos + w) <= SCREEN_W && (yPos + h) <= SCREEN_H);
740+
741+ dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
742+ for (uint32_t y = 0; y < h; y++)
743+ {
744+ for (uint32_t x = 0; x < w; x++)
745+ {
746+ if (srcPtr[x] != 0x00FF00)
747+ dstPtr[x] = srcPtr[x] | 0xFF000000; // most significant 8 bits = palette number. 0xFF because no true palette
748+ }
749+
750+ srcPtr += w;
751+ dstPtr += SCREEN_W;
752+ }
753753 }
754754
755755 void blit(uint16_t xPos, uint16_t yPos, const uint8_t *srcPtr, uint16_t w, uint16_t h)
src/ft2_header.h+4−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
1212 #endif
1313 #include "ft2_replayer.h"
1414
15−#define PROG_VER_STR "1.06"
15+#define PROG_VER_STR "1.07"
1616
1717 // do NOT change these! It will only mess things up...
1818
@@ -55,6 +55,9 @@ · 36 unmodified lines
5555 // fast 32-bit -> 16-bit clamp
5656 #define CLAMP16(i) if ((int16_t)(i) != i) i = 0x7FFF ^ (i >> 31)
5757
58+#define ALIGN_PTR(p, x) (((uintptr_t)(p) + ((x)-1)) & ~((x)-1))
59+#define MALLOC_PAD(size, pad) (malloc((size) + (pad)))
60+
5861 #define SWAP16(value) \
5962 ( \
6063 (((uint16_t)((value) & 0x00FF)) << 8) | \
src/ft2_inst_ed.c+89−60
@@ -788,24 +788,28 @@ void relToneDown(void) · 787 unmodified lines
788788
789789 void volEnvAdd(void)
790790 {
791− int16_t i;
791+ int16_t i, ant;
792792 instrTyp *ins = instr[editor.curInstr];
793793
794− if (ins == NULL || editor.curInstr == 0 || ins->envVPAnt >= 12)
794+ ant = ins->envVPAnt;
795+ if (ins == NULL || editor.curInstr == 0 || ant >= 12)
795796 return;
796797
797798 i = (int16_t)editor.currVolEnvPoint;
799+ if (i < 0 || i >= ant)
800+ {
801+ i = ant-1;
802+ if (i < 0)
803+ i = 0;
804+ }
798805
799− if (i < 0 || i >= ins->envVPAnt)
800− i = ins->envVPAnt - 1;
801−
802− if (i < ins->envVPAnt-1 && ins->envVP[i+1][0]-ins->envVP[i][0] < 2)
806+ if (i < ant-1 && ins->envVP[i+1][0]-ins->envVP[i][0] < 2)
803807 return;
804808
805809 if (ins->envVP[i][0] >= 323)
806810 return;
807811
808− for (int16_t j = ins->envVPAnt; j > i; j--)
812+ for (int16_t j = ant; j > i; j--)
809813 {
810814 ins->envVP[j][0] = ins->envVP[j-1][0];
811815 ins->envVP[j][1] = ins->envVP[j-1][1];
@@ -815,7 +819,7 @@ void volEnvAdd(void) · 3 unmodified lines
815819 if (ins->envVRepS > i) { ins->envVRepS++; drawVolEnvRepS(); }
816820 if (ins->envVRepE > i) { ins->envVRepE++; drawVolEnvRepE(); }
817821
818− if (i < ins->envVPAnt-1)
822+ if (i < ant-1)
819823 {
820824 ins->envVP[i+1][0] = (ins->envVP[i][0] + ins->envVP[i+2][0]) / 2;
821825 ins->envVP[i+1][1] = (ins->envVP[i][1] + ins->envVP[i+2][1]) / 2;
@@ -840,7 +844,6 @@ void volEnvDel(void) · 18 unmodified lines
840844 uint8_t drawSust, drawRepS, drawRepE;
841845 int16_t i;
842846 instrTyp *ins = instr[editor.curInstr];
843−
844847 if (ins == NULL || editor.curInstr == 0 || ins->envVPAnt <= 2)
845848 return;
846849
@@ -873,6 +876,11 @@ void volEnvDel(void) · 26 unmodified lines
873876 if (drawRepS) drawVolEnvRepS();
874877 if (drawRepE) drawVolEnvRepE();
875878
879+ if (ins->envVPAnt == 0)
880+ editor.currVolEnvPoint = 0;
881+ else if (editor.currVolEnvPoint >= ins->envVPAnt)
882+ editor.currVolEnvPoint = ins->envVPAnt-1;
883+
876884 updateVolEnv = true;
877885 setSongModifiedFlag();
878886 }
@@ -880,7 +888,6 @@ void volEnvDel(void) · 1 unmodified line
880888 void volEnvSusUp(void)
881889 {
882890 instrTyp *ins = instr[editor.curInstr];
883−
884891 if (ins == NULL || editor.curInstr == 0)
885892 return;
886893
@@ -896,7 +903,6 @@ void volEnvSusUp(void) · 9 unmodified lines
896903 void volEnvSusDown(void)
897904 {
898905 instrTyp *ins = instr[editor.curInstr];
899−
900906 if (ins == NULL || editor.curInstr == 0)
901907 return;
902908
@@ -912,7 +918,6 @@ void volEnvSusDown(void) · 9 unmodified lines
912918 void volEnvRepSUp(void)
913919 {
914920 instrTyp *ins = instr[editor.curInstr];
915−
916921 if (ins == NULL || editor.curInstr == 0)
917922 return;
918923
@@ -928,7 +933,6 @@ void volEnvRepSUp(void) · 9 unmodified lines
928933 void volEnvRepSDown(void)
929934 {
930935 instrTyp *ins = instr[editor.curInstr];
931−
932936 if (ins == NULL || editor.curInstr == 0)
933937 return;
934938
@@ -944,7 +948,6 @@ void volEnvRepSDown(void) · 9 unmodified lines
944948 void volEnvRepEUp(void)
945949 {
946950 instrTyp *ins = instr[editor.curInstr];
947−
948951 if (ins == NULL || editor.curInstr == 0)
949952 return;
950953
@@ -960,7 +963,6 @@ void volEnvRepEUp(void) · 9 unmodified lines
960963 void volEnvRepEDown(void)
961964 {
962965 instrTyp *ins = instr[editor.curInstr];
963−
964966 if (ins == NULL || editor.curInstr == 0)
965967 return;
966968
@@ -975,24 +977,28 @@ void volEnvRepEDown(void) · 8 unmodified lines
975977
976978 void panEnvAdd(void)
977979 {
978− int16_t i;
980+ int16_t i, ant;
979981 instrTyp *ins = instr[editor.curInstr];
980982
981− if (ins == NULL || editor.curInstr == 0 || ins->envPPAnt >= 12)
983+ ant = ins->envPPAnt;
984+ if (ins == NULL || editor.curInstr == 0 || ant >= 12)
982985 return;
983986
984987 i = (int16_t)editor.currPanEnvPoint;
988+ if (i < 0 || i >= ant)
989+ {
990+ i = ant-1;
991+ if (i < 0)
992+ i = 0;
993+ }
985994
986− if (i < 0 || i >= ins->envPPAnt)
987− i = ins->envPPAnt - 1;
988−
989− if (i < ins->envPPAnt-1 && ins->envPP[i+1][0]-ins->envPP[i][0] < 2)
995+ if (i < ant-1 && ins->envPP[i+1][0]-ins->envPP[i][0] < 2)
990996 return;
991997
992998 if (ins->envPP[i][0] >= 323)
993999 return;
9941000
995− for (int16_t j = ins->envPPAnt; j > i; j--)
1001+ for (int16_t j = ant; j > i; j--)
9961002 {
9971003 ins->envPP[j][0] = ins->envPP[j-1][0];
9981004 ins->envPP[j][1] = ins->envPP[j-1][1];
@@ -1002,7 +1008,7 @@ void panEnvAdd(void) · 3 unmodified lines
10021008 if (ins->envPRepS > i) { ins->envPRepS++; drawPanEnvRepS(); }
10031009 if (ins->envPRepE > i) { ins->envPRepE++; drawPanEnvRepE(); }
10041010
1005− if (i < ins->envPPAnt-1)
1011+ if (i < ant-1)
10061012 {
10071013 ins->envPP[i+1][0] = (ins->envPP[i][0] + ins->envPP[i+2][0]) / 2;
10081014 ins->envPP[i+1][1] = (ins->envPP[i][1] + ins->envPP[i+2][1]) / 2;
@@ -1027,7 +1033,6 @@ void panEnvDel(void) · 18 unmodified lines
10271033 uint8_t drawSust, drawRepS, drawRepE;
10281034 int16_t i;
10291035 instrTyp *ins = instr[editor.curInstr];
1030−
10311036 if (ins == NULL || editor.curInstr == 0 || ins->envPPAnt <= 2)
10321037 return;
10331038
@@ -1060,6 +1065,11 @@ void panEnvDel(void) · 26 unmodified lines
10601065 if (drawRepS) drawPanEnvRepS();
10611066 if (drawRepE) drawPanEnvRepE();
10621067
1068+ if (ins->envPPAnt == 0)
1069+ editor.currPanEnvPoint = 0;
1070+ else if (editor.currPanEnvPoint >= ins->envPPAnt)
1071+ editor.currPanEnvPoint = ins->envPPAnt-1;
1072+
10631073 updatePanEnv = true;
10641074 setSongModifiedFlag();
10651075 }
@@ -1067,7 +1077,6 @@ void panEnvDel(void) · 1 unmodified line
10671077 void panEnvSusUp(void)
10681078 {
10691079 instrTyp *ins = instr[editor.curInstr];
1070−
10711080 if (ins == NULL || editor.curInstr == 0)
10721081 return;
10731082
@@ -1083,7 +1092,6 @@ void panEnvSusUp(void) · 9 unmodified lines
10831092 void panEnvSusDown(void)
10841093 {
10851094 instrTyp *ins = instr[editor.curInstr];
1086−
10871095 if (ins == NULL || editor.curInstr == 0)
10881096 return;
10891097
@@ -1099,7 +1107,6 @@ void panEnvSusDown(void) · 9 unmodified lines
10991107 void panEnvRepSUp(void)
11001108 {
11011109 instrTyp *ins = instr[editor.curInstr];
1102−
11031110 if (ins == NULL || editor.curInstr == 0)
11041111 return;
11051112
@@ -1115,7 +1122,6 @@ void panEnvRepSUp(void) · 9 unmodified lines
11151122 void panEnvRepSDown(void)
11161123 {
11171124 instrTyp *ins = instr[editor.curInstr];
1118−
11191125 if (ins == NULL || editor.curInstr == 0)
11201126 return;
11211127
@@ -1131,7 +1137,6 @@ void panEnvRepSDown(void) · 9 unmodified lines
11311137 void panEnvRepEUp(void)
11321138 {
11331139 instrTyp *ins = instr[editor.curInstr];
1134−
11351140 if (ins == NULL || editor.curInstr == 0)
11361141 return;
11371142
@@ -1147,7 +1152,6 @@ void panEnvRepEUp(void) · 9 unmodified lines
11471152 void panEnvRepEDown(void)
11481153 {
11491154 instrTyp *ins = instr[editor.curInstr];
1150−
11511155 if (ins == NULL || editor.curInstr == 0)
11521156 return;
11531157
@@ -1975,7 +1979,7 @@ static void writeEnvelope(int32_t nr) · 821 unmodified lines
19751979
19761980 // draw center line on pan envelope
19771981 if (nr == 1)
1978− envelopeLine(nr, 8, 33, 335, 33, PAL_BLCKMRK);
1982+ envelopeLine(nr, 8, 33, 332, 33, PAL_BLCKMRK);
19791983
19801984 if (ins == NULL)
19811985 return;
@@ -2035,38 +2039,48 @@ static void writeEnvelope(int32_t nr) · 53 unmodified lines
20352039 // draw envelope
20362040 for (i = 0; i < nd; i++)
20372041 {
2038− x = curEnvP[i][0]; x = CLAMP(x, 0, 340);
2039− y = curEnvP[i][1]; y = CLAMP(y, 0, 64);
2042+ x = curEnvP[i][0];
2043+ y = curEnvP[i][1];
20402044
2041− envelopeDot(nr, 7 + x, 64 - y);
2045+ x = CLAMP(x, 0, 324);
2046+
2047+ if (nr == 0)
2048+ y = CLAMP(y, 0, 64);
2049+ else
2050+ y = CLAMP(y, 0, 63);
20422051
2043− // draw "envelope selected" data
2044− if (i == selected)
2052+ if ((uint16_t)curEnvP[i][0] <= 324)
20452053 {
2046− envelopeLine(nr, 5 + x, 64 - y, 5 + x, 66 - y, PAL_BLCKTXT);
2047− envelopeLine(nr, 11 + x, 64 - y, 11 + x, 66 - y, PAL_BLCKTXT);
2048− envelopePixel(nr, 5, 65 - y, PAL_BLCKTXT);
2049− envelopePixel(nr, 8 + x, 65, PAL_BLCKTXT);
2050− }
2054+ envelopeDot(nr, 7 + x, 64 - y);
20512055
2052− // draw loop start marker
2053− if (i == ls)
2054− {
2055− envelopeLine(nr, x + 6, 1, x + 10, 1, PAL_PATTEXT);
2056− envelopeLine(nr, x + 7, 2, x + 9, 2, PAL_PATTEXT);
2057− envelopeVertLine(nr, x + 8, 1, PAL_PATTEXT);
2058− }
2056+ // draw "envelope selected" data
2057+ if (i == selected)
2058+ {
2059+ envelopeLine(nr, 5 + x, 64 - y, 5 + x, 66 - y, PAL_BLCKTXT);
2060+ envelopeLine(nr, 11 + x, 64 - y, 11 + x, 66 - y, PAL_BLCKTXT);
2061+ envelopePixel(nr, 5, 65 - y, PAL_BLCKTXT);
2062+ envelopePixel(nr, 8 + x, 65, PAL_BLCKTXT);
2063+ }
20592064
2060− // draw sustain marker
2061− if (i == sp)
2062− envelopeVertLine(nr, x + 8, 1, PAL_BLCKTXT);
2065+ // draw loop start marker
2066+ if (i == ls)
2067+ {
2068+ envelopeLine(nr, x + 6, 1, x + 10, 1, PAL_PATTEXT);
2069+ envelopeLine(nr, x + 7, 2, x + 9, 2, PAL_PATTEXT);
2070+ envelopeVertLine(nr, x + 8, 1, PAL_PATTEXT);
2071+ }
20632072
2064− // draw loop end marker
2065− if (i == le)
2066− {
2067− envelopeLine(nr, x + 6, 65, x + 10, 65, PAL_PATTEXT);
2068− envelopeLine(nr, x + 7, 64, x + 9, 64, PAL_PATTEXT);
2069− envelopeVertLine(nr, x + 8, 1, PAL_PATTEXT);
2073+ // draw sustain marker
2074+ if (i == sp)
2075+ envelopeVertLine(nr, x + 8, 1, PAL_BLCKTXT);
2076+
2077+ // draw loop end marker
2078+ if (i == le)
2079+ {
2080+ envelopeLine(nr, x + 6, 65, x + 10, 65, PAL_PATTEXT);
2081+ envelopeLine(nr, x + 7, 64, x + 9, 64, PAL_PATTEXT);
2082+ envelopeVertLine(nr, x + 8, 1, PAL_PATTEXT);
2083+ }
20702084 }
20712085
20722086 // draw envelope line
@@ -2465,7 +2479,7 @@ bool testInstrVolEnvMouseDown(bool mouseButtonDown) · 392 unmodified lines
24652479 if (editor.currVolEnvPoint == ant-1)
24662480 {
24672481 minX = ins->envVP[editor.currVolEnvPoint-1][0] + 1;
2468− maxX = 325;
2482+ maxX = 324;
24692483 }
24702484 else
24712485 {
@@ -2473,6 +2487,9 @@ bool testInstrVolEnvMouseDown(bool mouseButtonDown) · 1 unmodified line
24732487 maxX = ins->envVP[editor.currVolEnvPoint+1][0] - 1;
24742488 }
24752489
2490+ minX = CLAMP(minX, 0, 324);
2491+ maxX = CLAMP(maxX, 0, 324);
2492+
24762493 ins->envVP[editor.currVolEnvPoint][0] = (int16_t)(CLAMP(mx, minX, maxX));
24772494 updateVolEnv = true;
24782495
@@ -2561,7 +2578,7 @@ bool testInstrPanEnvMouseDown(bool mouseButtonDown) · 82 unmodified lines
25612578 if (editor.currPanEnvPoint == ant-1)
25622579 {
25632580 minX = ins->envPP[editor.currPanEnvPoint-1][0] + 1;
2564− maxX = 325;
2581+ maxX = 324;
25652582 }
25662583 else
25672584 {
@@ -2569,6 +2586,9 @@ bool testInstrPanEnvMouseDown(bool mouseButtonDown) · 1 unmodified line
25692586 maxX = ins->envPP[editor.currPanEnvPoint+1][0] - 1;
25702587 }
25712588
2589+ minX = CLAMP(minX, 0, 324);
2590+ maxX = CLAMP(maxX, 0, 324);
2591+
25722592 ins->envPP[editor.currPanEnvPoint][0] = (int16_t)(CLAMP(mx, minX, maxX));
25732593 updatePanEnv = true;
25742594
@@ -3102,7 +3122,7 @@ static int32_t SDLCALL loadInstrThread(void *ptr) · 527 unmodified lines
31023122 goto loadDone;
31033123 }
31043124
3105− // sanitize stuff for malicious instruments
3125+ // sanitize stuff for broken/unsupported instruments
31063126 ih.midiProgram = CLAMP(ih.midiProgram, 0, 127);
31073127 ih.midiBend = CLAMP(ih.midiBend, 0, 36);
31083128
@@ -3127,6 +3147,15 @@ static int32_t SDLCALL loadInstrThread(void *ptr) · 18 unmodified lines
31273147 if (ih.envPRepS > 11) ih.envPRepS = 11;
31283148 if (ih.envPRepE > 11) ih.envPRepE = 11;
31293149 if (ih.envPSust > 11) ih.envPSust = 11;
3150+
3151+ for (int16_t i = 0; i < 12; i++)
3152+ {
3153+ if ((uint16_t)ih.envVP[i][0] > 32767) ih.envVP[i][0] = 32767;
3154+ if ((uint16_t)ih.envPP[i][0] > 32767) ih.envPP[i][0] = 32767;
3155+ if ((uint16_t)ih.envVP[i][1] > 64) ih.envVP[i][1] = 64;
3156+ if ((uint16_t)ih.envPP[i][1] > 63) ih.envPP[i][1] = 63;
3157+ }
3158+
31303159 // ----------------------------------------
31313160
31323161 memcpy(instr[editor.curInstr]->ta, ih.ta, INSTR_SIZE);
src/ft2_keyboard.c+13−7
@@ -107,8 +107,10 @@ void keyDownHandler(SDL_Scancode scancode, SDL_Keycode keycode, bool keyWasRepea · 106 unmodified lines
107107
108108 if (editor.ui.sysReqShown)
109109 {
110− if (keycode == SDLK_RETURN) editor.ui.sysReqEnterPressed = true;
111− else if (keycode == SDLK_ESCAPE) editor.ui.sysReqShown = false;
110+ if (keycode == SDLK_RETURN)
111+ editor.ui.sysReqEnterPressed = true;
112+ else if (keycode == SDLK_ESCAPE)
113+ editor.ui.sysReqShown = false;
112114
113115 return;
114116 }
@@ -858,7 +860,7 @@ static bool checkModifiedKeys(SDL_Keycode keycode) · 743 unmodified lines
858860 video.showFPSCounter ^= 1;
859861 if (!video.showFPSCounter)
860862 {
861− if (editor.ui.extended) // Mr. Kludge, my only friend
863+ if (editor.ui.extended) // yet another kludge...
862864 exitPatternEditorExtended();
863865
864866 showTopScreen(false);
@@ -1025,15 +1027,19 @@ static bool checkModifiedKeys(SDL_Keycode keycode) · 160 unmodified lines
10251027 case SDLK_v:
10261028 if (keyb.leftAltPressed)
10271029 {
1028− if (editor.ui.sampleEditorShown) sampPaste();
1029− else if (!editor.ui.instEditorShown) scaleFadeVolumeBlock();
1030+ if (editor.ui.sampleEditorShown)
1031+ sampPaste();
1032+ else if (!editor.ui.instEditorShown)
1033+ scaleFadeVolumeBlock();
10301034
10311035 return true;
10321036 }
10331037 else if (keyb.leftCtrlPressed || keyb.leftCommandPressed)
10341038 {
1035− if (editor.ui.sampleEditorShown) sampPaste();
1036− else if (!editor.ui.instEditorShown) scaleFadeVolumePattern();
1039+ if (editor.ui.sampleEditorShown)
1040+ sampPaste();
1041+ else if (!editor.ui.instEditorShown)
1042+ scaleFadeVolumePattern();
10371043
10381044 return true;
10391045 }
src/ft2_main.c+8−0
@@ -103,6 +103,13 @@ int main(int argc, char *argv[]) · 102 unmodified lines
103103 return 0;
104104 }
105105
106+ if (!cpu.hasSSE2)
107+ {
108+ showErrorMsgBox("Your computer's processor doesn't have the SSE2 instruction set\n" \
109+ "which is needed for this program to run. Sorry!");
110+ return 0;
111+ }
112+
106113 setupWin32Usleep();
107114 disableWasapi(); // disable problematic WASAPI SDL2 audio driver on Windows (causes clicks/pops sometimes...)
108115 #endif
@@ -192,6 +199,7 @@ int main(int argc, char *argv[]) · 83 unmodified lines
192199 #ifdef _WIN32 // on Windows we show the window at this point
193200 SDL_ShowWindow(video.window);
194201 #endif
202+
195203 if (config.windowFlags & START_IN_FULLSCR)
196204 {
197205 video.fullscreen = true;
src/ft2_module_loader.c+50−14
@@ -1810,8 +1810,6 @@ xmLoadError: · 1809 unmodified lines
18101810
18111811 void loadMusic(UNICHAR *filenameU)
18121812 {
1813− int32_t i;
1814−
18151813 if (musicIsLoading)
18161814 return;
18171815
@@ -1831,7 +1829,7 @@ void loadMusic(UNICHAR *filenameU) · 13 unmodified lines
18311829 // prevent stuck instrument names from previous module
18321830 memset(&songTmp, 0, sizeof (songTmp));
18331831
1834− for (i = 0; i < MAX_PATTERNS; i++)
1832+ for (uint32_t i = 0; i < MAX_PATTERNS; i++)
18351833 pattLensTmp[i] = 64;
18361834
18371835 thread = SDL_CreateThread(loadMusicThread, NULL, NULL);
@@ -1846,6 +1844,35 @@ void loadMusic(UNICHAR *filenameU) · 8 unmodified lines
18461844 SDL_DetachThread(thread);
18471845 }
18481846
1847+bool loadMusicUnthreaded(UNICHAR *filenameU) // for development testing
1848+{
1849+ if (editor.tmpFilenameU == NULL)
1850+ return false;
1851+
1852+ // clear deprecated pointers from possible last loading session (super important)
1853+ memset(pattTmp, 0, sizeof (pattTmp));
1854+ memset(instrTmp, 0, sizeof (instrTmp));
1855+
1856+ // prevent stuck instrument names from previous module
1857+ memset(&songTmp, 0, sizeof (songTmp));
1858+
1859+ for (uint32_t i = 0; i < MAX_PATTERNS; i++)
1860+ pattLensTmp[i] = 64;
1861+
1862+ UNICHAR_STRCPY(editor.tmpFilenameU, filenameU);
1863+
1864+ loadMusicThread(NULL);
1865+ editor.loadMusicEvent = EVENT_NONE;
1866+
1867+ if (moduleLoaded)
1868+ {
1869+ setupLoadedModule();
1870+ return true;
1871+ }
1872+
1873+ return false;
1874+}
1875+
18491876 static void freeTmpModule(void)
18501877 {
18511878 uint16_t i;
@@ -1925,7 +1952,7 @@ static bool loadInstrHeader(FILE *f, uint16_t i) · 73 unmodified lines
19251952 if (!allocateTmpInstr(i))
19261953 return false;
19271954
1928− // sanitize stuff for malicious instruments
1955+ // sanitize stuff for broken/unsupported instruments
19291956 ih.midiProgram = CLAMP(ih.midiProgram, 0, 127);
19301957 ih.midiBend = CLAMP(ih.midiBend, 0, 36);
19311958
@@ -1941,20 +1968,29 @@ static bool loadInstrHeader(FILE *f, uint16_t i) · 9 unmodified lines
19411968 if (ih.ta[j] > 15)
19421969 ih.ta[j] = 15;
19431970 }
1971+
1972+ if (ih.envVPAnt > 12) ih.envVPAnt = 12;
1973+ if (ih.envVRepS > 11) ih.envVRepS = 11;
1974+ if (ih.envVRepE > 11) ih.envVRepE = 11;
1975+ if (ih.envVSust > 11) ih.envVSust = 11;
1976+ if (ih.envPPAnt > 12) ih.envPPAnt = 12;
1977+ if (ih.envPRepS > 11) ih.envPRepS = 11;
1978+ if (ih.envPRepE > 11) ih.envPRepE = 11;
1979+ if (ih.envPSust > 11) ih.envPSust = 11;
1980+
1981+ for (j = 0; j < 12; j++)
1982+ {
1983+ if ((uint16_t)ih.envVP[j][0] > 32767) ih.envVP[j][0] = 32767;
1984+ if ((uint16_t)ih.envPP[j][0] > 32767) ih.envPP[j][0] = 32767;
1985+ if ((uint16_t)ih.envVP[j][1] > 64) ih.envVP[j][1] = 64;
1986+ if ((uint16_t)ih.envPP[j][1] > 63) ih.envPP[j][1] = 63;
1987+
1988+ }
19441989 // ----------------------------------------
19451990
19461991 // copy over final instrument data from temp buffer
19471992 memcpy(instrTmp[i], ih.ta, INSTR_SIZE);
19481993 instrTmp[i]->antSamp = ih.antSamp;
1949−
1950− if (instrTmp[i]->envVPAnt > 12) instrTmp[i]->envVPAnt = 12;
1951− if (instrTmp[i]->envVRepS > 11) instrTmp[i]->envVRepS = 11;
1952− if (instrTmp[i]->envVRepE > 11) instrTmp[i]->envVRepE = 11;
1953− if (instrTmp[i]->envVSust > 11) instrTmp[i]->envVSust = 11;
1954− if (instrTmp[i]->envPPAnt > 12) instrTmp[i]->envPPAnt = 12;
1955− if (instrTmp[i]->envPRepS > 11) instrTmp[i]->envPRepS = 11;
1956− if (instrTmp[i]->envPRepE > 11) instrTmp[i]->envPRepE = 11;
1957− if (instrTmp[i]->envPSust > 11) instrTmp[i]->envPSust = 11;
19581994 }
19591995
19601996 if (fread(ih.samp, ih.antSamp * sizeof (sampleHeaderTyp), 1, f) != 1)
@@ -2501,7 +2537,7 @@ void loadDroppedFile(char *fullPathUTF8, bool songModifiedCheck) · 540 unmodified lines
25012537 SDL_RestoreWindow(video.window);
25022538 SDL_RaiseWindow(video.window);
25032539
2504− if (okBox(2, "System request", "You have unsaved changes in your song. Load new song and lose all changes?") != 1)
2540+ if (!askUnsavedChanges(ASK_TYPE_LOAD_SONG))
25052541 {
25062542 free(fullPathU);
25072543 return;
src/ft2_module_loader.h+1−0
@@ -5,6 +5,7 @@ · 4 unmodified lines
55 #include "ft2_unicode.h"
66
77 void loadMusic(UNICHAR *filenameU);
8+bool loadMusicUnthreaded(UNICHAR *filenameU); // for development testing
89 bool handleModuleLoadFromArg(int argc, char **argv);
910 void loadDroppedFile(char *fullPathUTF8, bool songModifiedCheck);
1011 void handleLoadMusicEvents(void);
src/ft2_mouse.c+22−12
@@ -667,19 +667,29 @@ void mouseButtonDownHandler(uint8_t mouseButton) · 666 unmodified lines
667667 return;
668668 }
669669
670− if (mouseButton == SDL_BUTTON_LEFT) mouse.leftButtonPressed = true;
671− else if (mouseButton == SDL_BUTTON_RIGHT) mouse.rightButtonPressed = true;
672−
673− mouse.leftButtonReleased = false;
674− mouse.rightButtonReleased = false;
675−
676670 // mouse 0,0 = open exit dialog
677− if (mouse.x == 0 && mouse.y == 0 && quitBox(false) == 1)
671+ if (mouse.x == 0 && mouse.y == 0)
678672 {
679− editor.throwExit = true;
673+ if (quitBox(false) == 1)
674+ editor.throwExit = true;
675+
676+ // release button presses from okBox()
677+ mouse.leftButtonPressed = false;
678+ mouse.rightButtonPressed = false;
679+ mouse.leftButtonReleased = false;
680+ mouse.rightButtonReleased = false;
681+
680682 return;
681683 }
682684
685+ if (mouseButton == SDL_BUTTON_LEFT)
686+ mouse.leftButtonPressed = true;
687+ else if (mouseButton == SDL_BUTTON_RIGHT)
688+ mouse.rightButtonPressed = true;
689+
690+ mouse.leftButtonReleased = false;
691+ mouse.rightButtonReleased = false;
692+
683693 // don't do mouse down testing here if we already are using an object
684694 if (mouse.lastUsedObjectType != OBJECT_NONE)
685695 return;
@@ -762,8 +772,8 @@ void handleLastGUIObjectDown(void) · 76 unmodified lines
762772
763773 void updateMouseScaling(void)
764774 {
765− video.dMouseXMul = (double)SCREEN_W / video.renderW;
766− video.dMouseYMul = (double)SCREEN_H / video.renderH;
775+ if (video.renderW > 0.0) video.dMouseXMul = (double)SCREEN_W / video.renderW;
776+ if (video.renderH > 0.0) video.dMouseYMul = (double)SCREEN_H / video.renderH;
767777 }
768778
769779 void readMouseXY(void)
@@ -818,8 +828,8 @@ void readMouseXY(void) · 48 unmodified lines
818828 if (my < 0) mx = 0;
819829
820830 // multiply coords by video upscaling factors (don't round)
821− mx = (uint32_t)(mx * video.dMouseXMul);
822− my = (uint32_t)(my * video.dMouseYMul);
831+ mx = (int32_t)(mx * video.dMouseXMul);
832+ my = (int32_t)(my * video.dMouseYMul);
823833
824834 if (mx >= SCREEN_W) mx = SCREEN_W - 1;
825835 if (my >= SCREEN_H) my = SCREEN_H - 1;
src/ft2_mouse.h+0−1
@@ -32,7 +32,6 @@ struct mouse_t · 31 unmodified lines
3232
3333 void freeMouseCursors(void);
3434 bool createMouseCursors(void);
35−
3635 void setMousePosToCenter(void);
3736 void setMouseShape(int16_t shape);
3837 void setMouseMode(uint8_t mode);
src/ft2_palette.c+5−0
@@ -18,6 +18,11 @@ static uint8_t palContrast[12][2] = // palette desktop/button contrasts · 17 unmodified lines
1818 {66, 62}, {68, 57}, {46, 57}, {57, 55}, {62, 57}, {52, 57}
1919 };
2020
21+void setCustomPalColor(uint32_t color)
22+{
23+ video.palette[PAL_CUSTOM] = (PAL_CUSTOM << 24) | color;
24+}
25+
2126 void setPal16(pal16 *p, bool redrawScreen)
2227 {
2328 #define LOOP_PIN_COL_SUB 118
src/ft2_palette.h+5−0
@@ -38,6 +38,9 @@ enum · 37 unmodified lines
3838 PAL_TEXTMRK = 17,
3939 PAL_BOXSLCT = 18,
4040
41+ // modifiable with setCustomPalColor()
42+ PAL_CUSTOM = 19,
43+
4144 PAL_NUM
4245 };
4346
@@ -49,6 +52,8 @@ typedef struct pal16_t · 5 unmodified lines
4952 extern uint8_t cfg_ColorNr;
5053 extern pal16 palTable[12][16];
5154
55+void setCustomPalColor(uint32_t color);
56+
5257 uint8_t palMax(int32_t c);
5358 void setPal16(pal16 *p, bool redrawScreen);
5459
src/ft2_pattern_draw.c+439−464
@@ -12,6 +12,9 @@ · 11 unmodified lines
1212 #include "ft2_gui.h"
1313 #include "ft2_video.h"
1414
15+static tonTyp emptyPattern[MAX_VOICES * MAX_PATT_LEN];
16+
17+static const uint8_t *font4Ptr, *font5Ptr;
1518 static const uint8_t vol2charTab1[16] = { 39, 0, 1, 2, 3, 4, 36, 52, 53, 54, 28, 31, 25, 58, 59, 22 };
1619 static const uint8_t vol2charTab2[16] = { 42, 0, 1, 2, 3, 4, 36, 37, 38, 39, 28, 31, 25, 40, 41, 22 };
1720 static const uint8_t columnModeTab[12] = { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 3 };
@@ -28,29 +31,229 @@ static const uint16_t sharpNote2Char_big[12] = { 36*16, 37*16, 36*16, 37*16, 36* · 10 unmodified lines
2831 static const uint16_t flatNote1Char_big[12] = { 12*16, 13*16, 13*16, 14*16, 14*16, 15*16, 16*16, 16*16, 10*16, 10*16, 11*16, 11*16 };
2932 static const uint16_t flatNote2Char_big[12] = { 36*16, 38*16, 36*16, 38*16, 36*16, 36*16, 38*16, 36*16, 38*16, 36*16, 38*16, 36*16 };
3033
31−static tonTyp emptyNote;
34+static const uint8_t noteTab1[96] =
35+{
36+ 0,1,2,3,4,5,6,7,8,9,10,11,
37+ 0,1,2,3,4,5,6,7,8,9,10,11,
38+ 0,1,2,3,4,5,6,7,8,9,10,11,
39+ 0,1,2,3,4,5,6,7,8,9,10,11,
40+ 0,1,2,3,4,5,6,7,8,9,10,11,
41+ 0,1,2,3,4,5,6,7,8,9,10,11,
42+ 0,1,2,3,4,5,6,7,8,9,10,11,
43+ 0,1,2,3,4,5,6,7,8,9,10,11
44+};
45+
46+static const uint8_t noteTab2[96] =
47+{
48+ 0,0,0,0,0,0,0,0,0,0,0,0,
49+ 1,1,1,1,1,1,1,1,1,1,1,1,
50+ 2,2,2,2,2,2,2,2,2,2,2,2,
51+ 3,3,3,3,3,3,3,3,3,3,3,3,
52+ 4,4,4,4,4,4,4,4,4,4,4,4,
53+ 5,5,5,5,5,5,5,5,5,5,5,5,
54+ 6,6,6,6,6,6,6,6,6,6,6,6,
55+ 7,7,7,7,7,7,7,7,7,7,7,7
56+};
57+
58+static const uint8_t hex2Dec[256] =
59+{
60+ 0,1,2,3,4,5,6,7,8,9,
61+ 16,17,18,19,20,21,22,23,24,25,
62+ 32,33,34,35,36,37,38,39,40,41,
63+ 48,49,50,51,52,53,54,55,56,57,
64+ 64,65,66,67,68,69,70,71,72,73,
65+ 80,81,82,83,84,85,86,87,88,89,
66+ 96,97,98,99,100,101,102,103,104,105,
67+ 112,113,114,115,116,117,118,119,120,121,
68+ 128,129,130,131,132,133,134,135,136,137,
69+ 144,145,146,147,148,149,150,151,152,153,
70+
71+ 0,1,2,3,4,5,6,7,8,9,
72+ 16,17,18,19,20,21,22,23,24,25,
73+ 32,33,34,35,36,37,38,39,40,41,
74+ 48,49,50,51,52,53,54,55,56,57,
75+ 64,65,66,67,68,69,70,71,72,73,
76+ 80,81,82,83,84,85,86,87,88,89,
77+ 96,97,98,99,100,101,102,103,104,105,
78+ 112,113,114,115,116,117,118,119,120,121,
79+ 128,129,130,131,132,133,134,135,136,137,
80+ 144,145,146,147,148,149,150,151,152,153,
81+
82+ 0,1,2,3,4,5,6,7,8,9,
83+ 16,17,18,19,20,21,22,23,24,25,
84+ 32,33,34,35,36,37,38,39,40,41,
85+ 48,49,50,51,52,53,54,55,56,57,
86+ 64,65,66,67,68,69,70,71,72,73,
87+ 80,81,82,83,84,85
88+};
89+
90+static const pattCoord_t pattCoordTable[2][2][2] =
91+{
92+ // no pattern stretch
93+ {
94+ // no pattern channel scroll
95+ {
96+ { 176, 292, 177, 283, 293, 13, 13 }, // normal pattern editor
97+ { 56, 228, 57, 219, 229, 20, 21 }, // extended pattern editor
98+ },
99+
100+ // pattern channel scroll
101+ {
102+ { 176, 285, 177, 276, 286, 12, 12 }, // normal pattern editor
103+ { 56, 221, 57, 212, 222, 19, 20 }, // extended pattern editor
104+ }
105+ },
106+
107+ // pattern stretch
108+ {
109+ // no pattern channel scroll
110+ {
111+ { 177, 286, 178, 277, 288, 9, 10 }, // normal pattern editor
112+ { 56, 232, 58, 223, 234, 15, 15 }, // extended pattern editor
113+ },
114+
115+ // pattern channel scroll
116+ {
117+ { 176, 285, 177, 276, 286, 9, 9 }, // normal pattern editor
118+ { 56, 220, 57, 211, 221, 14, 15 }, // extended pattern editor
119+ },
120+ }
121+};
122+
123+static const pattCoord2_t pattCoord2Table[2][2][2] =
124+{
125+ // no pattern stretch
126+ {
127+ // no pattern channel scroll
128+ {
129+ { 175, 291, 107, 107 }, // normal pattern editor
130+ { 55, 227, 163, 171 }, // extended pattern editor
131+ },
132+
133+ // pattern channel scroll
134+ {
135+ { 175, 284, 100, 100 }, // normal pattern editor
136+ { 55, 220, 156, 164 }, // extended pattern editor
137+ }
138+ },
139+
140+ // pattern stretch
141+ {
142+ // no pattern channel scroll
143+ {
144+ { 175, 285, 101, 113 }, // normal pattern editor
145+ { 55, 231, 167, 167 }, // extended pattern editor
146+ },
147+
148+ // pattern channel scroll
149+ {
150+ { 175, 284, 100, 100 }, // normal pattern editor
151+ { 55, 219, 155, 165 }, // extended pattern editor
152+ },
153+ }
154+};
155+
156+static const markCoord_t markCoordTable[2][2][2] =
157+{
158+ // no pattern stretch
159+ {
160+ // no pattern channel scroll
161+ {
162+ { 177, 281, 293 }, // normal pattern editor
163+ { 57, 217, 229 }, // extended pattern editor
164+ },
165+
166+ // pattern channel scroll
167+ {
168+ { 177, 274, 286 }, // normal pattern editor
169+ { 57, 210, 222 }, // extended pattern editor
170+ }
171+ },
172+
173+ // pattern stretch
174+ {
175+ // no pattern channel scroll
176+ {
177+ { 176, 275, 286 }, // normal pattern editor
178+ { 56, 221, 232 }, // extended pattern editor
179+ },
180+
181+ // pattern channel scroll
182+ {
183+ { 175, 274, 284 }, // normal pattern editor
184+ { 55, 209, 219 }, // extended pattern editor
185+ },
186+ }
187+};
188+
189+static const uint8_t pattCursorXTab[2 * 4 * 8] =
190+{
191+ // no volume column shown
192+ 32, 88, 104, 0, 0, 120, 136, 152, // 4 columns visible
193+ 32, 80, 88, 0, 0, 96, 104, 112, // 6 columns visible
194+ 32, 56, 64, 0, 0, 72, 80, 88, // 8 columns visible
195+ 32, 52, 56, 0, 0, 60, 64, 68, // 12 columns visible
196+
197+ // volume column shown
198+ 32, 96, 104, 120, 128, 144, 152, 160, // 4 columns visible
199+ 32, 56, 64, 80, 88, 96, 104, 112, // 6 columns visible
200+ 32, 60, 64, 72, 76, 84, 88, 92, // 8 columns visible
201+ 32, 60, 64, 72, 76, 84, 88, 92, // 12 columns visible
202+};
203+
204+static const uint8_t pattCursorWTab[2 * 4 * 8] =
205+{
206+ // no volume column shown
207+ 48, 16, 16, 0, 0, 16, 16, 16, // 4 columns visible
208+ 48, 8, 8, 0, 0, 8, 8, 8, // 6 columns visible
209+ 24, 8, 8, 0, 0, 8, 8, 8, // 8 columns visible
210+ 16, 4, 4, 0, 0, 4, 4, 4, // 12 columns visible
211+
212+ // volume column shown
213+ 48, 8, 8, 8, 8, 8, 8, 8, // 4 columns visible
214+ 24, 8, 8, 8, 8, 8, 8, 8, // 6 columns visible
215+ 24, 4, 4, 4, 4, 4, 4, 4, // 8 columns visible
216+ 24, 4, 4, 4, 4, 4, 4, 4 // 12 columns visible
217+};
218+
219+// global tables
220+
221+const char chDecTab1[MAX_VOICES+1] =
222+{
223+ '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
224+ '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
225+ '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
226+ '3', '3', '3'
227+};
228+
229+const char chDecTab2[MAX_VOICES+1] =
230+{
231+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
232+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
233+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
234+ '0', '1', '2'
235+};
32236
33237 // ft2_pattern_ed.c
34238 extern const uint16_t chanWidths[6];
35239
36−// defined at the bottom of this file
37−extern const pattCoord_t pattCoordTable[2][2][2];
38−extern const pattCoord2_t pattCoord2Table[2][2][2];
39−extern const markCoord_t markCoordTable[2][2][2];
40−extern const uint8_t pattCursorXTab[2 * 4 * 8];
41−extern const uint8_t pattCursorWTab[2 * 4 * 8];
42−
43−static void rowNumOut(uint32_t yPos, uint8_t paletteIndex, uint8_t rowChar1, uint8_t rowChar2);
44−static void pattCharOut(uint32_t xPos, uint32_t yPos, uint8_t paletteIndex, uint8_t chr, uint8_t fontType);
45−static void drawEmptyNoteSmall(uint16_t x, uint16_t y, uint8_t paletteIndex);
46−static void drawKeyOffSmall(uint16_t x, uint16_t y, uint8_t paletteIndex);
47−static void drawNoteSmall(uint16_t x, uint16_t y, uint8_t paletteIndex, int16_t ton);
48−static void drawEmptyNoteMedium(uint16_t x, uint16_t y, uint8_t paletteIndex);
49−static void drawKeyOffMedium(uint16_t x, uint16_t y, uint8_t paletteIndex);
50−static void drawNoteMedium(uint16_t x, uint16_t y, uint8_t paletteIndex, int16_t ton);
51−static void drawEmptyNoteBig(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex);
52−static void drawKeyOffBig(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex);
53−static void drawNoteBig(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, int16_t ton);
240+static void pattCharOut(uint32_t xPos, uint32_t yPos, uint8_t chr, uint8_t fontType, uint32_t color);
241+static void drawEmptyNoteSmall(uint32_t xPos, uint32_t yPos, uint32_t color);
242+static void drawKeyOffSmall(uint32_t xPos, uint32_t yPos, uint32_t color);
243+static void drawNoteSmall(uint32_t xPos, uint32_t yPos, int32_t ton, uint32_t color);
244+static void drawEmptyNoteMedium(uint32_t xPos, uint32_t yPos, uint32_t color);
245+static void drawKeyOffMedium(uint32_t xPos, uint32_t yPos, uint32_t color);
246+static void drawNoteMedium(uint32_t xPos, uint32_t yPos, int32_t ton, uint32_t color);
247+static void drawEmptyNoteBig(uint32_t xPos, uint32_t yPos, uint32_t color);
248+static void drawKeyOffBig(uint32_t xPos, uint32_t yPos, uint32_t color);
249+static void drawNoteBig(uint32_t xPos, uint32_t yPos, int32_t ton, uint32_t color);
250+
251+void updatePattFontPtrs(void)
252+{
253+ //config.ptnFont is pre-clamped and safe
254+ font4Ptr = &font4Data[config.ptnFont * (FONT4_WIDTH * FONT4_CHAR_H)];
255+ font5Ptr = &font5Data[config.ptnFont * (FONT5_WIDTH * FONT5_CHAR_H)];
256+}
54257
55258 void drawPatternBorders(void)
56259 {
@@ -141,11 +344,11 @@ void drawPatternBorders(void) · 84 unmodified lines
141344 drawFramework(xOffs, pattCoord->upperRowsY, chanWidth, pattCoord->upperRowsH, FRAMEWORK_TYPE2); // top part
142345 drawFramework(xOffs, pattCoord->lowerRowsY, chanWidth, pattCoord->lowerRowsH, FRAMEWORK_TYPE2); // bottom part
143346
144− xOffs += (chanWidth + 1);
347+ xOffs += chanWidth+1;
145348 }
146349
147− vLine(xOffs - 1, pattCoord->upperRowsY, pattCoord->upperRowsH, PAL_DESKTOP);
148− vLine(xOffs - 1, pattCoord->lowerRowsY, pattCoord->lowerRowsH + 1, PAL_DESKTOP);
350+ vLine(xOffs-1, pattCoord->upperRowsY, pattCoord->upperRowsH, PAL_DESKTOP);
351+ vLine(xOffs-1, pattCoord->lowerRowsY, pattCoord->lowerRowsH+1, PAL_DESKTOP);
149352 }
150353 else
151354 {
@@ -203,11 +406,9 @@ static void writeCursor(void) · 51 unmodified lines
203406 }
204407 }
205408
206−static void writePatternBlockMark(int16_t currRow, uint16_t rowHeight, const pattCoord_t *pattCoord)
409+static void writePatternBlockMark(int32_t currRow, uint32_t rowHeight, const pattCoord_t *pattCoord)
207410 {
208− uint8_t startCh, endCh;
209− int16_t startRow, endRow, x1, x2, y1, y2;
210− uint16_t pattYStart, pattYEnd;
411+ int32_t startCh, endCh, startRow, endRow, x1, x2, y1, y2, pattYStart, pattYEnd;
211412 uint32_t w, h, *ptr32;
212413 const markCoord_t *markCoord;
213414
@@ -311,53 +512,79 @@ static void writePatternBlockMark(int16_t currRow, uint16_t rowHeight, const pat · 97 unmodified lines
311512
312513 static void drawChannelNumbering(uint16_t yPos)
313514 {
314− uint8_t chNum;
315− uint16_t xPos;
515+#define CH_NUM_XPOS 29
516+
517+ uint16_t xPos = CH_NUM_XPOS;
518+ int32_t ch = editor.ui.channelOffset + 1;
316519
317− xPos = 29;
318520 for (uint8_t i = 0; i < editor.ui.numChannelsShown; i++)
319521 {
320− chNum = editor.ui.channelOffset + i + 1;
321− if (chNum < 10)
522+ if (ch < 10)
322523 {
323− charOutOutlined(xPos, yPos, PAL_MOUSEPT, '0' + chNum);
524+ charOutOutlined(xPos, yPos, PAL_MOUSEPT, '0' + (char)ch);
324525 }
325526 else
326527 {
327− charOutOutlined(xPos, yPos, PAL_MOUSEPT, '0' + (chNum / 10));
328− charOutOutlined(xPos + 9, yPos, PAL_MOUSEPT, '0' + (chNum % 10));
528+ charOutOutlined(xPos, yPos, PAL_MOUSEPT, chDecTab1[ch]);
529+ charOutOutlined(xPos + (FONT1_CHAR_W + 1), yPos, PAL_MOUSEPT, chDecTab2[ch]);
329530 }
330531
532+ ch++;
331533 xPos += editor.ui.patternChannelWidth;
332534 }
333535 }
334536
335−static void drawRowNum(uint16_t yPos, uint16_t row, bool middleRowFlag)
537+static void drawRowNums(int32_t yPos, uint8_t row, bool selectedRowFlag)
336538 {
337− uint8_t pal;
539+#define LEFT_ROW_XPOS 8
540+#define RIGHT_ROW_XPOS 608
541+
542+ const uint8_t *src1Ptr, *src2Ptr;
543+ uint32_t *dst1Ptr, *dst2Ptr, pixVal;
338544
339545 // set color based on some conditions
340− if (middleRowFlag)
341− pal = PAL_FORGRND;
342− else if ((row & 3) == 0 && config.ptnLineLight)
343− pal = PAL_BLCKTXT;
546+ if (selectedRowFlag)
547+ pixVal = video.palette[PAL_FORGRND];
548+ else if (config.ptnLineLight && !(row & 3))
549+ pixVal = video.palette[PAL_BLCKTXT];
344550 else
345− pal = PAL_PATTEXT;
551+ pixVal = video.palette[PAL_PATTEXT];
346552
347− if (config.ptnHex)
348− {
349− rowNumOut(yPos, pal, (uint8_t)(row >> 4), row & 0x0F);
350− }
351− else
553+ if (!config.ptnHex)
554+ row = hex2Dec[row];
555+
556+ src1Ptr = &font4Ptr[(row >> 4) * FONT4_CHAR_W];
557+ src2Ptr = &font4Ptr[(row & 0x0F) * FONT4_CHAR_W];
558+ dst1Ptr = &video.frameBuffer[(yPos * SCREEN_W) + LEFT_ROW_XPOS];
559+ dst2Ptr = dst1Ptr + (RIGHT_ROW_XPOS - LEFT_ROW_XPOS);
560+
561+ for (uint32_t y = 0; y < FONT4_CHAR_H; y++)
352562 {
353− row %= 100;
354− rowNumOut(yPos, pal, (uint8_t)(row / 10), row % 10);
563+ for (uint32_t x1 = 0; x1 < FONT4_CHAR_W; x1++)
564+ {
565+ if (src1Ptr[x1])
566+ {
567+ dst1Ptr[x1] = pixVal; // left side
568+ dst2Ptr[x1] = pixVal; // right side
569+ }
570+
571+ if (src2Ptr[x1])
572+ {
573+ dst1Ptr[FONT4_CHAR_W + x1] = pixVal; // left side
574+ dst2Ptr[FONT4_CHAR_W + x1] = pixVal; // right side
575+ }
576+ }
577+
578+ src1Ptr += FONT4_WIDTH;
579+ src2Ptr += FONT4_WIDTH;
580+ dst1Ptr += SCREEN_W;
581+ dst2Ptr += SCREEN_W;
355582 }
356583 }
357584
358585 // DRAWING ROUTINES (WITH VOLUME COLUMN)
359586
360−static void showNoteNum(uint8_t pal, uint16_t xPos, uint16_t yPos, int16_t ton)
587+static void showNoteNum(uint32_t xPos, uint32_t yPos, int16_t ton, uint32_t color)
361588 {
362589 xPos += 3;
363590
@@ -366,24 +593,24 @@ static void showNoteNum(uint8_t pal, uint16_t xPos, uint16_t yPos, int16_t ton) · 2 unmodified lines
366593 if (editor.ui.numChannelsShown <= 4)
367594 {
368595 if (ton <= 0 || ton > 97)
369− drawEmptyNoteBig(xPos, yPos, pal);
596+ drawEmptyNoteBig(xPos, yPos, color);
370597 else if (ton == 97)
371− drawKeyOffBig(xPos, yPos, pal);
598+ drawKeyOffBig(xPos, yPos, color);
372599 else
373− drawNoteBig(xPos, yPos, pal, ton);
600+ drawNoteBig(xPos, yPos, ton, color);
374601 }
375602 else
376603 {
377604 if (ton <= 0 || ton > 97)
378− drawEmptyNoteMedium(xPos, yPos, pal);
605+ drawEmptyNoteMedium(xPos, yPos, color);
379606 else if (ton == 97)
380− drawKeyOffMedium(xPos, yPos, pal);
607+ drawKeyOffMedium(xPos, yPos, color);
381608 else
382− drawNoteMedium(xPos, yPos, pal, ton);
609+ drawNoteMedium(xPos, yPos, ton, color);
383610 }
384611 }
385612
386−static void showInstrNum(uint8_t pal, uint16_t xPos, uint16_t yPos, uint8_t ins)
613+static void showInstrNum(uint32_t xPos, uint32_t yPos, uint8_t ins, uint32_t color)
387614 {
388615 uint8_t chr1, chr2, charW, fontType;
389616
@@ -408,8 +635,8 @@ static void showInstrNum(uint8_t pal, uint16_t xPos, uint16_t yPos, uint8_t ins) · 18 unmodified lines
408635
409636 if (config.ptnInstrZero)
410637 {
411− pattCharOut(xPos, yPos, pal, ins >> 4, fontType);
412− pattCharOut(xPos + charW, yPos, pal, ins & 0x0F, fontType);
638+ pattCharOut(xPos, yPos, ins >> 4, fontType, color);
639+ pattCharOut(xPos + charW, yPos, ins & 0x0F, fontType, color);
413640 }
414641 else
415642 {
@@ -417,14 +644,14 @@ static void showInstrNum(uint8_t pal, uint16_t xPos, uint16_t yPos, uint8_t ins) · 1 unmodified line
417644 chr2 = ins & 0x0F;
418645
419646 if (chr1 > 0)
420− pattCharOut(xPos, yPos, pal, chr1, fontType);
647+ pattCharOut(xPos, yPos, chr1, fontType, color);
421648
422649 if (chr1 > 0 || chr2 > 0)
423− pattCharOut(xPos + charW, yPos, pal, chr2, fontType);
650+ pattCharOut(xPos + charW, yPos, chr2, fontType, color);
424651 }
425652 }
426653
427−static void showVolEfx(uint8_t pal, uint16_t xPos, uint16_t yPos, uint8_t vol)
654+static void showVolEfx(uint32_t xPos, uint32_t yPos, uint8_t vol, uint32_t color)
428655 {
429656 uint8_t char1, char2, fontType, charW;
430657
@@ -465,11 +692,11 @@ static void showVolEfx(uint8_t pal, uint16_t xPos, uint16_t yPos, uint8_t vol) · 34 unmodified lines
465692 char2 = vol & 0x0F;
466693 }
467694
468− pattCharOut(xPos, yPos, pal, char1, fontType);
469− pattCharOut(xPos + charW, yPos, pal, char2, fontType);
695+ pattCharOut(xPos, yPos, char1, fontType, color);
696+ pattCharOut(xPos + charW, yPos, char2, fontType, color);
470697 }
471698
472−static void showEfx(uint8_t pal, uint16_t xPos, uint16_t yPos, uint8_t effTyp, uint8_t eff)
699+static void showEfx(uint32_t xPos, uint32_t yPos, uint8_t effTyp, uint8_t eff, uint32_t color)
473700 {
474701 uint8_t fontType, charW;
475702
@@ -492,14 +719,14 @@ static void showEfx(uint8_t pal, uint16_t xPos, uint16_t yPos, uint8_t effTyp, u · 16 unmodified lines
492719 xPos += 55;
493720 }
494721
495− pattCharOut(xPos, yPos, pal, effTyp, fontType);
496− pattCharOut(xPos + charW, yPos, pal, eff >> 4, fontType);
497− pattCharOut(xPos + (charW * 2), yPos, pal, eff & 0x0F, fontType);
722+ pattCharOut(xPos, yPos, effTyp, fontType, color);
723+ pattCharOut(xPos + charW, yPos, eff >> 4, fontType, color);
724+ pattCharOut(xPos + (charW * 2), yPos, eff & 0x0F, fontType, color);
498725 }
499726
500727 // DRAWING ROUTINES (WITHOUT VOLUME COLUMN)
501728
502−static void showNoteNumNoVolColumn(uint8_t pal, uint16_t xPos, uint16_t yPos, int16_t ton)
729+static void showNoteNumNoVolColumn(uint32_t xPos, uint32_t yPos, int16_t ton, uint32_t color)
503730 {
504731 xPos += 3;
505732
@@ -508,33 +735,33 @@ static void showNoteNumNoVolColumn(uint8_t pal, uint16_t xPos, uint16_t yPos, in · 2 unmodified lines
508735 if (editor.ui.numChannelsShown <= 6)
509736 {
510737 if (ton <= 0 || ton > 97)
511− drawEmptyNoteBig(xPos, yPos, pal);
738+ drawEmptyNoteBig(xPos, yPos, color);
512739 else if (ton == 97)
513− drawKeyOffBig(xPos, yPos, pal);
740+ drawKeyOffBig(xPos, yPos, color);
514741 else
515− drawNoteBig(xPos, yPos, pal, ton);
742+ drawNoteBig(xPos, yPos, ton, color);
516743 }
517744 else if (editor.ui.numChannelsShown <= 8)
518745 {
519746 if (ton <= 0 || ton > 97)
520− drawEmptyNoteMedium(xPos, yPos, pal);
747+ drawEmptyNoteMedium(xPos, yPos, color);
521748 else if (ton == 97)
522− drawKeyOffMedium(xPos, yPos, pal);
749+ drawKeyOffMedium(xPos, yPos, color);
523750 else
524− drawNoteMedium(xPos, yPos, pal, ton);
751+ drawNoteMedium(xPos, yPos, ton, color);
525752 }
526753 else
527754 {
528755 if (ton <= 0 || ton > 97)
529− drawEmptyNoteSmall(xPos, yPos, pal);
756+ drawEmptyNoteSmall(xPos, yPos, color);
530757 else if (ton == 97)
531− drawKeyOffSmall(xPos, yPos, pal);
758+ drawKeyOffSmall(xPos, yPos, color);
532759 else
533− drawNoteSmall(xPos, yPos, pal, ton);
760+ drawNoteSmall(xPos, yPos, ton, color);
534761 }
535762 }
536763
537−static void showInstrNumNoVolColumn(uint8_t pal, uint16_t xPos, uint16_t yPos, uint8_t ins)
764+static void showInstrNumNoVolColumn(uint32_t xPos, uint32_t yPos, uint8_t ins, uint32_t color)
538765 {
539766 uint8_t chr1, chr2, charW, fontType;
540767
@@ -565,8 +792,8 @@ static void showInstrNumNoVolColumn(uint8_t pal, uint16_t xPos, uint16_t yPos, u · 24 unmodified lines
565792
566793 if (config.ptnInstrZero)
567794 {
568− pattCharOut(xPos, yPos, pal, ins >> 4, fontType);
569− pattCharOut(xPos + charW, yPos, pal, ins & 0x0F, fontType);
795+ pattCharOut(xPos, yPos, ins >> 4, fontType, color);
796+ pattCharOut(xPos + charW, yPos, ins & 0x0F, fontType, color);
570797 }
571798 else
572799 {
@@ -574,23 +801,23 @@ static void showInstrNumNoVolColumn(uint8_t pal, uint16_t xPos, uint16_t yPos, u · 1 unmodified line
574801 chr2 = ins & 0x0F;
575802
576803 if (chr1 > 0)
577− pattCharOut(xPos, yPos, pal, chr1, fontType);
804+ pattCharOut(xPos, yPos, chr1, fontType, color);
578805
579806 if (chr1 > 0 || chr2 > 0)
580− pattCharOut(xPos + charW, yPos, pal, chr2, fontType);
807+ pattCharOut(xPos + charW, yPos, chr2, fontType, color);
581808 }
582809 }
583810
584−static void showNoVolEfx(uint8_t pal, uint16_t xPos, uint16_t yPos, uint8_t vol)
811+static void showNoVolEfx(uint32_t xPos, uint32_t yPos, uint8_t vol, uint32_t color)
585812 {
586813 // make compiler happy
587− (void)pal;
588814 (void)xPos;
589815 (void)yPos;
590816 (void)vol;
817+ (void)color;
591818 }
592819
593−static void showEfxNoVolColumn(uint8_t pal, uint16_t xPos, uint16_t yPos, uint8_t effTyp, uint8_t eff)
820+static void showEfxNoVolColumn(uint32_t xPos, uint32_t yPos, uint8_t effTyp, uint8_t eff, uint32_t color)
594821 {
595822 uint8_t charW, fontType;
596823
@@ -619,65 +846,32 @@ static void showEfxNoVolColumn(uint8_t pal, uint16_t xPos, uint16_t yPos, uint8_ · 22 unmodified lines
619846 xPos += 31;
620847 }
621848
622− pattCharOut(xPos, yPos, pal, effTyp, fontType);
623− pattCharOut(xPos + charW, yPos, pal, eff >> 4, fontType);
624− pattCharOut(xPos + (charW * 2), yPos, pal, eff & 0x0F, fontType);
625−}
626−
627−static void drawRowNumbers(const pattCoord_t *pattCoord, int16_t currRow, uint16_t rowHeight, uint16_t upperRowsYEnd, uint16_t pattLen)
628−{
629− int16_t j, rowYPos, numRows;
630−
631− // upper rows
632− numRows = currRow;
633− if (numRows > 0)
634− {
635− if (numRows > pattCoord->numUpperRows)
636− numRows = pattCoord->numUpperRows;
637−
638− rowYPos = upperRowsYEnd;
639− for (j = 0; j < numRows; j++)
640− {
641− drawRowNum(rowYPos, currRow - j - 1, false);
642− rowYPos -= rowHeight;
643− }
644− }
645−
646− // current row
647− drawRowNum(pattCoord->midRowTextY, currRow, true);
648−
649− // lower rows
650− numRows = (pattLen - 1) - currRow;
651− if (numRows > 0)
652− {
653− if (numRows > pattCoord->numLowerRows)
654− numRows = pattCoord->numLowerRows;
655−
656− rowYPos = pattCoord->lowerRowsTextY;
657− for (j = 0; j < numRows; j++)
658− {
659− drawRowNum(rowYPos, currRow + j + 1, false);
660− rowYPos += rowHeight;
661− }
662− }
849+ pattCharOut(xPos, yPos, effTyp, fontType, color);
850+ pattCharOut(xPos + charW, yPos, eff >> 4, fontType, color);
851+ pattCharOut(xPos + (charW * 2), yPos, eff & 0x0F, fontType, color);
663852 }
664853
665−void writePattern(int16_t currRow, int16_t pattern)
854+void writePattern(int32_t currRow, int32_t pattern)
666855 {
667− uint8_t chans, chNum;
668− int16_t numRows, j;
669− uint16_t pattLen, xPos, rowYPos, rowHeight, chanWidth, upperRowsYEnd;
856+ int32_t row, rowsOnScreen, numRows, afterCurrRow, numChannels;
857+ int32_t textY, midRowTextY, lowerRowsTextY, xPos, xWidth;
858+ uint32_t rowHeight, chanWidth, chans, noteTextColors[2], color;
670859 tonTyp *note, *pattPtr;
671860 const pattCoord_t *pattCoord;
672− void (*drawNote)(uint8_t, uint16_t, uint16_t, int16_t);
673− void (*drawInst)(uint8_t, uint16_t, uint16_t, uint8_t);
674− void (*drawVolEfx)(uint8_t, uint16_t, uint16_t, uint8_t);
675− void (*drawEfx)(uint8_t, uint16_t, uint16_t, uint8_t, uint8_t);
676−
677− /* We're too lazy to carefully erase things as needed, just render
678− ** the whole pattern framework first (fast enough on modern PCs) */
861+ void (*drawNote)(uint32_t, uint32_t, int16_t, uint32_t);
862+ void (*drawInst)(uint32_t, uint32_t, uint8_t, uint32_t);
863+ void (*drawVolEfx)(uint32_t, uint32_t, uint8_t, uint32_t);
864+ void (*drawEfx)(uint32_t, uint32_t, uint8_t, uint8_t, uint32_t);
865+
866+ /* Draw pattern framework every time (erasing existing content).
867+ ** FT2 doesn't do this. This is quite lazy and consumes more CPU
868+ ** time than needed (overlapped drawing), but it makes the pattern
869+ ** mark/cursor drawing MUCH simpler to implement...
870+ */
679871 drawPatternBorders();
680872
873+ // setup variables
874+
681875 chans = editor.ui.numChannelsShown;
682876 if (chans > editor.ui.maxVisibleChannels)
683877 chans = editor.ui.maxVisibleChannels;
@@ -686,18 +880,26 @@ void writePattern(int16_t currRow, int16_t pattern) · 2 unmodified lines
686880
687881 // get channel width
688882 chanWidth = chanWidths[(chans / 2) - 1];
689− editor.ui.patternChannelWidth = chanWidth + 3;
883+ editor.ui.patternChannelWidth = (uint16_t)(chanWidth + 3);
690884
691885 // get heights/pos/rows depending on configuration
692− pattCoord = &pattCoordTable[config.ptnUnpressed][editor.ui.pattChanScrollShown][editor.ui.extended];
693886 rowHeight = config.ptnUnpressed ? 11 : 8;
694− upperRowsYEnd = pattCoord->upperRowsTextY + ((pattCoord->numUpperRows - 1) * rowHeight);
695−
887+ pattCoord = &pattCoordTable[config.ptnUnpressed][editor.ui.pattChanScrollShown][editor.ui.extended];
888+ midRowTextY = pattCoord->midRowTextY;
889+ lowerRowsTextY = pattCoord->lowerRowsTextY;
890+ row = currRow - pattCoord->numUpperRows;
891+ rowsOnScreen = pattCoord->numUpperRows + 1 + pattCoord->numLowerRows;
892+ textY = pattCoord->upperRowsTextY;
893+
894+ afterCurrRow = currRow + 1;
895+ numChannels = editor.ui.numChannelsShown;
696896 pattPtr = patt[pattern];
697− pattLen = pattLens[pattern];
897+ numRows = pattLens[pattern];
898+ noteTextColors[0] = video.palette[PAL_PATTEXT]; // not selected
899+ noteTextColors[1] = video.palette[PAL_FORGRND]; // selected
698900
699− // draw row numbers
700− drawRowNumbers(pattCoord, currRow, rowHeight, upperRowsYEnd, pattLen);
901+ if (pattPtr != NULL)
902+ pattPtr += editor.ui.channelOffset;
701903
702904 // set up function pointers for drawing
703905 if (config.ptnS3M)
@@ -716,148 +918,76 @@ void writePattern(int16_t currRow, int16_t pattern) · 12 unmodified lines
716918 }
717919
718920 // draw pattern data
719−
720− xPos = 29;
721− for (uint8_t i = 0; i < editor.ui.numChannelsShown; i++)
921+ for (int32_t i = 0; i < rowsOnScreen; i++)
722922 {
723− chNum = editor.ui.channelOffset + i;
724−
725− // upper rows
726− numRows = currRow;
727− if (numRows > 0)
923+ if (row >= 0)
728924 {
729− if (numRows > pattCoord->numUpperRows)
730− numRows = pattCoord->numUpperRows;
731−
732− rowYPos = upperRowsYEnd;
925+ bool selectedRowFlag = row == currRow;
733926
927+ drawRowNums(textY, (uint8_t)row, selectedRowFlag);
928+
734929 if (pattPtr == NULL)
735− note = &emptyNote;
930+ note = emptyPattern;
736931 else
737− note = &pattPtr[((currRow - 1) * MAX_VOICES) + chNum];
932+ note = &pattPtr[(uint32_t)row * MAX_VOICES];
738933
739− for (j = 0; j < numRows; j++)
740− {
741− drawNote(PAL_PATTEXT, xPos, rowYPos, note->ton);
742− drawInst(PAL_PATTEXT, xPos, rowYPos, note->instr);
743− drawVolEfx(PAL_PATTEXT, xPos, rowYPos, note->vol);
744− drawEfx(PAL_PATTEXT, xPos, rowYPos, note->effTyp, note->eff);
934+ xPos = 29;
935+ xWidth = editor.ui.patternChannelWidth;
745936
746− if (pattPtr != NULL)
747− note -= MAX_VOICES;
937+ color = noteTextColors[selectedRowFlag];
938+ for (int32_t j = 0; j < numChannels; j++)
939+ {
940+ drawNote(xPos, textY, note->ton, color);
941+ drawInst(xPos, textY, note->instr, color);
942+ drawVolEfx(xPos, textY, note->vol, color);
943+ drawEfx(xPos, textY, note->effTyp, note->eff, color);
748944
749− rowYPos -= rowHeight;
945+ xPos += xWidth;
946+ note++;
750947 }
751948 }
752949
753− // current row
950+ // next row
951+ if (++row >= numRows)
952+ break;
754953
755− if (pattPtr == NULL)
756− note = &emptyNote;
954+ // adjust textY position
955+ if (row == currRow)
956+ textY = midRowTextY;
957+ else if (row == afterCurrRow)
958+ textY = lowerRowsTextY;
757959 else
758− note = &pattPtr[(currRow * MAX_VOICES) + chNum];
759−
760− rowYPos = pattCoord->midRowTextY;
761−
762− drawNote(PAL_FORGRND, xPos, rowYPos, note->ton);
763− drawInst(PAL_FORGRND, xPos, rowYPos, note->instr);
764− drawVolEfx(PAL_FORGRND, xPos, rowYPos, note->vol);
765− drawEfx(PAL_FORGRND, xPos, rowYPos, note->effTyp, note->eff);
766−
767− // lower rows
768− numRows = (pattLen - 1) - currRow;
769− if (numRows > 0)
770− {
771− if (numRows > pattCoord->numLowerRows)
772− numRows = pattCoord->numLowerRows;
773−
774− rowYPos = pattCoord->lowerRowsTextY;
775−
776− if (pattPtr == NULL)
777− note = &emptyNote;
778− else
779− note = &pattPtr[((currRow + 1) * MAX_VOICES) + chNum];
780−
781− for (j = 0; j < numRows; j++)
782− {
783− drawNote(PAL_PATTEXT, xPos, rowYPos, note->ton);
784− drawInst(PAL_PATTEXT, xPos, rowYPos, note->instr);
785− drawVolEfx(PAL_PATTEXT, xPos, rowYPos, note->vol);
786− drawEfx(PAL_PATTEXT, xPos, rowYPos, note->effTyp, note->eff);
787−
788− if (pattPtr != NULL)
789− note += MAX_VOICES;
790−
791− rowYPos += rowHeight;
792− }
793− }
794−
795− xPos += editor.ui.patternChannelWidth;
960+ textY += rowHeight;
796961 }
797962
798963 writeCursor();
799964
800− if (pattMark.markY1 != pattMark.markY2) // do we have a pattern mark?
965+ // draw pattern marking (if anything is marked)
966+ if (pattMark.markY1 != pattMark.markY2)
801967 writePatternBlockMark(currRow, rowHeight, pattCoord);
802968
803− // channel numbers must be drawn in the very end
969+ // channel numbers must be drawn lastly
804970 if (config.ptnChnNumbers)
805971 drawChannelNumbering(pattCoord->upperRowsTextY);
806972 }
807973
808974 // ========== OPTIMIZED CHARACTER DRAWING ROUTINES FOR PATTERN EDITOR ==========
809975
810−void pattTwoHexOut(uint32_t xPos, uint32_t yPos, uint8_t paletteIndex, uint8_t val)
976+void pattTwoHexOut(uint32_t xPos, uint32_t yPos, uint8_t val, uint32_t color)
811977 {
812978 const uint8_t *ch1Ptr, *ch2Ptr;
813− uint32_t *dstPtr, pixVal, offset;
979+ uint32_t *dstPtr;
814980
815− pixVal = video.palette[paletteIndex];
816− offset = config.ptnFont * (FONT4_WIDTH * FONT4_CHAR_H);
817− ch1Ptr = &font4Data[((val >> 4) * FONT4_CHAR_W) + offset];
818− ch2Ptr = &font4Data[((val & 0x0F) * FONT4_CHAR_W) + offset];
981+ ch1Ptr = &font4Ptr[(val >> 4) * FONT4_CHAR_W];
982+ ch2Ptr = &font4Ptr[(val & 0x0F) * FONT4_CHAR_W];
819983 dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
820984
821985 for (uint32_t y = 0; y < FONT4_CHAR_H; y++)
822986 {
823987 for (uint32_t x = 0; x < FONT4_CHAR_W; x++)
824988 {
825− if (ch1Ptr[x]) dstPtr[x] = pixVal;
826− if (ch2Ptr[x]) dstPtr[FONT4_CHAR_W + x] = pixVal;
827− }
828−
829− ch1Ptr += FONT4_WIDTH;
830− ch2Ptr += FONT4_WIDTH;
831− dstPtr += SCREEN_W;
832− }
833−}
834−
835−static void rowNumOut(uint32_t yPos, uint8_t paletteIndex, uint8_t rowChar1, uint8_t rowChar2)
836−{
837− const uint8_t *ch1Ptr, *ch2Ptr;
838− uint32_t *dstPtr, pixVal, offset;
839−
840− pixVal = video.palette[paletteIndex];
841− offset = config.ptnFont * (FONT4_WIDTH * FONT4_CHAR_H);
842− ch1Ptr = &font4Data[(rowChar1 * FONT4_CHAR_W) + offset];
843− ch2Ptr = &font4Data[(rowChar2 * FONT4_CHAR_W) + offset];
844− dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + 8];
845−
846− for (uint32_t y = 0; y < FONT4_CHAR_H; y++)
847− {
848− for (uint32_t x = 0; x < FONT4_CHAR_W; x++)
849− {
850− if (ch1Ptr[x])
851− {
852− dstPtr[x] = pixVal; // left side
853− dstPtr[600 + x] = pixVal; // right side
854− }
855−
856− if (ch2Ptr[x])
857− {
858− dstPtr[ FONT4_CHAR_W + x] = pixVal; // left side
859− dstPtr[(600 + FONT4_CHAR_W) + x] = pixVal; // right side
860− }
989+ if (ch1Ptr[x]) dstPtr[x] = color;
990+ if (ch2Ptr[x]) dstPtr[FONT4_CHAR_W + x] = color;
861991 }
862992
863993 ch1Ptr += FONT4_WIDTH;
@@ -866,12 +996,11 @@ static void rowNumOut(uint32_t yPos, uint8_t paletteIndex, uint8_t rowChar1, uin · 2 unmodified lines
866996 }
867997 }
868998
869−static void pattCharOut(uint32_t xPos, uint32_t yPos, uint8_t paletteIndex, uint8_t chr, uint8_t fontType)
999+static void pattCharOut(uint32_t xPos, uint32_t yPos, uint8_t chr, uint8_t fontType, uint32_t color)
8701000 {
8711001 const uint8_t *srcPtr;
872− uint32_t x, y, *dstPtr, pixVal;
1002+ uint32_t x, y, *dstPtr;
8731003
874− pixVal = video.palette[paletteIndex];
8751004 dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
8761005
8771006 if (fontType == FONT_TYPE3)
@@ -882,7 +1011,7 @@ static void pattCharOut(uint32_t xPos, uint32_t yPos, uint8_t paletteIndex, uint · 4 unmodified lines
8821011 for (x = 0; x < FONT3_CHAR_W; x++)
8831012 {
8841013 if (srcPtr[x])
885− dstPtr[x] = pixVal;
1014+ dstPtr[x] = color;
8861015 }
8871016
8881017 srcPtr += FONT3_WIDTH;
@@ -891,13 +1020,13 @@ static void pattCharOut(uint32_t xPos, uint32_t yPos, uint8_t paletteIndex, uint · 2 unmodified lines
8911020 }
8921021 else if (fontType == FONT_TYPE4)
8931022 {
894− srcPtr = &font4Data[(chr * FONT4_CHAR_W) + (config.ptnFont * (FONT4_WIDTH * FONT4_CHAR_H))];
1023+ srcPtr = &font4Ptr[chr * FONT4_CHAR_W];
8951024 for (y = 0; y < FONT4_CHAR_H; y++)
8961025 {
8971026 for (x = 0; x < FONT4_CHAR_W; x++)
8981027 {
8991028 if (srcPtr[x])
900− dstPtr[x] = pixVal;
1029+ dstPtr[x] = color;
9011030 }
9021031
9031032 srcPtr += FONT4_WIDTH;
@@ -906,13 +1035,13 @@ static void pattCharOut(uint32_t xPos, uint32_t yPos, uint8_t paletteIndex, uint · 2 unmodified lines
9061035 }
9071036 else if (fontType == FONT_TYPE5)
9081037 {
909− srcPtr = &font5Data[(chr * FONT5_CHAR_W) + (config.ptnFont * (FONT5_WIDTH * FONT5_CHAR_H))];
1038+ srcPtr = &font5Ptr[chr * FONT5_CHAR_W];
9101039 for (y = 0; y < FONT5_CHAR_H; y++)
9111040 {
9121041 for (x = 0; x < FONT5_CHAR_W; x++)
9131042 {
9141043 if (srcPtr[x])
915− dstPtr[x] = pixVal;
1044+ dstPtr[x] = color;
9161045 }
9171046
9181047 srcPtr += FONT5_WIDTH;
@@ -927,7 +1056,7 @@ static void pattCharOut(uint32_t xPos, uint32_t yPos, uint8_t paletteIndex, uint · 8 unmodified lines
9271056 for (x = 0; x < FONT7_CHAR_W; x++)
9281057 {
9291058 if (srcPtr[x])
930− dstPtr[x] = pixVal;
1059+ dstPtr[x] = color;
9311060 }
9321061
9331062 srcPtr += FONT7_WIDTH;
@@ -936,12 +1065,11 @@ static void pattCharOut(uint32_t xPos, uint32_t yPos, uint8_t paletteIndex, uint · 2 unmodified lines
9361065 }
9371066 }
9381067
939−static void drawEmptyNoteSmall(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex)
1068+static void drawEmptyNoteSmall(uint32_t xPos, uint32_t yPos, uint32_t color)
9401069 {
9411070 const uint8_t *srcPtr;
942− uint32_t *dstPtr, pixVal;
1071+ uint32_t *dstPtr;
9431072
944− pixVal = video.palette[paletteIndex];
9451073 srcPtr = &font7Data[18 * FONT7_CHAR_W];
9461074 dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
9471075
@@ -950,7 +1078,7 @@ static void drawEmptyNoteSmall(uint16_t xPos, uint16_t yPos, uint8_t paletteInde · 2 unmodified lines
9501078 for (uint32_t x = 0; x < FONT7_CHAR_W*3; x++)
9511079 {
9521080 if (srcPtr[x])
953− dstPtr[x] = pixVal;
1081+ dstPtr[x] = color;
9541082 }
9551083
9561084 srcPtr += FONT7_WIDTH;
@@ -958,12 +1086,11 @@ static void drawEmptyNoteSmall(uint16_t xPos, uint16_t yPos, uint8_t paletteInde · 1 unmodified line
9581086 }
9591087 }
9601088
961−static void drawKeyOffSmall(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex)
1089+static void drawKeyOffSmall(uint32_t xPos, uint32_t yPos, uint32_t color)
9621090 {
9631091 const uint8_t *srcPtr;
964− uint32_t *dstPtr, pixVal;
1092+ uint32_t *dstPtr;
9651093
966− pixVal = video.palette[paletteIndex];
9671094 srcPtr = &font7Data[21 * FONT7_CHAR_W];
9681095 dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + (xPos + 2)];
9691096
@@ -972,7 +1099,7 @@ static void drawKeyOffSmall(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex) · 2 unmodified lines
9721099 for (uint32_t x = 0; x < FONT7_CHAR_W*2; x++)
9731100 {
9741101 if (srcPtr[x])
975− dstPtr[x] = pixVal;
1102+ dstPtr[x] = color;
9761103 }
9771104
9781105 srcPtr += FONT7_WIDTH;
@@ -980,18 +1107,18 @@ static void drawKeyOffSmall(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex) · 1 unmodified line
9801107 }
9811108 }
9821109
983−static void drawNoteSmall(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, int16_t ton)
1110+static void drawNoteSmall(uint32_t xPos, uint32_t yPos, int32_t ton, uint32_t color)
9841111 {
9851112 const uint8_t *ch1Ptr, *ch2Ptr, *ch3Ptr;
9861113 uint8_t note;
987− uint32_t *dstPtr, pixVal, char1, char2, char3;
1114+ uint32_t *dstPtr, char1, char2, char3;
9881115
9891116 assert(ton >= 1 && ton <= 97);
9901117
9911118 ton--;
9921119
993− note = ton % 12;
994− char3 = (ton / 12) * FONT7_CHAR_W;
1120+ note = noteTab1[ton];
1121+ char3 = noteTab2[ton] * FONT7_CHAR_W;
9951122
9961123 if (config.ptnAcc == 0)
9971124 {
@@ -1004,7 +1131,6 @@ static void drawNoteSmall(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, in · 6 unmodified lines
10041131 char2 = flatNote2Char_small[note];
10051132 }
10061133
1007− pixVal = video.palette[paletteIndex];
10081134 ch1Ptr = &font7Data[char1];
10091135 ch2Ptr = &font7Data[char2];
10101136 ch3Ptr = &font7Data[char3];
@@ -1014,9 +1140,9 @@ static void drawNoteSmall(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, in · 3 unmodified lines
10141140 {
10151141 for (uint32_t x = 0; x < FONT7_CHAR_W; x++)
10161142 {
1017− if (ch1Ptr[x]) dstPtr[ (FONT7_CHAR_W * 0) + x] = pixVal;
1018− if (ch2Ptr[x]) dstPtr[ (FONT7_CHAR_W * 1) + x] = pixVal;
1019− if (ch3Ptr[x]) dstPtr[((FONT7_CHAR_W * 2) - 2) + x] = pixVal;
1143+ if (ch1Ptr[x]) dstPtr[ (FONT7_CHAR_W * 0) + x] = color;
1144+ if (ch2Ptr[x]) dstPtr[ (FONT7_CHAR_W * 1) + x] = color;
1145+ if (ch3Ptr[x]) dstPtr[((FONT7_CHAR_W * 2) - 2) + x] = color;
10201146 }
10211147
10221148 ch1Ptr += FONT7_WIDTH;
@@ -1026,21 +1152,20 @@ static void drawNoteSmall(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, in · 3 unmodified lines
10261152 }
10271153 }
10281154
1029−static void drawEmptyNoteMedium(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex)
1155+static void drawEmptyNoteMedium(uint32_t xPos, uint32_t yPos, uint32_t color)
10301156 {
10311157 const uint8_t *srcPtr;
1032− uint32_t *dstPtr, pixVal;
1158+ uint32_t *dstPtr;
10331159
1034− pixVal = video.palette[paletteIndex];
10351160 dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
1036− srcPtr = &font4Data[(43 * FONT4_CHAR_W) + (config.ptnFont * (FONT4_WIDTH * FONT4_CHAR_H))];
1161+ srcPtr = &font4Ptr[43 * FONT4_CHAR_W];
10371162
10381163 for (uint32_t y = 0; y < FONT4_CHAR_H; y++)
10391164 {
10401165 for (uint32_t x = 0; x < FONT4_CHAR_W*3; x++)
10411166 {
10421167 if (srcPtr[x])
1043− dstPtr[x] = pixVal;
1168+ dstPtr[x] = color;
10441169 }
10451170
10461171 srcPtr += FONT4_WIDTH;
@@ -1048,13 +1173,12 @@ static void drawEmptyNoteMedium(uint16_t xPos, uint16_t yPos, uint8_t paletteInd · 1 unmodified line
10481173 }
10491174 }
10501175
1051−static void drawKeyOffMedium(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex)
1176+static void drawKeyOffMedium(uint32_t xPos, uint32_t yPos, uint32_t color)
10521177 {
10531178 const uint8_t *srcPtr;
1054− uint32_t *dstPtr, pixVal;
1179+ uint32_t *dstPtr;
10551180
1056− pixVal = video.palette[paletteIndex];
1057− srcPtr = &font4Data[(40 * FONT4_CHAR_W) + (config.ptnFont * (FONT4_WIDTH * FONT4_CHAR_H))];
1181+ srcPtr = &font4Ptr[40 * FONT4_CHAR_W];
10581182 dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
10591183
10601184 for (uint32_t y = 0; y < FONT4_CHAR_H; y++)
@@ -1062,7 +1186,7 @@ static void drawKeyOffMedium(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex) · 1 unmodified line
10621186 for (uint32_t x = 0; x < FONT4_CHAR_W*3; x++)
10631187 {
10641188 if (srcPtr[x])
1065− dstPtr[x] = pixVal;
1189+ dstPtr[x] = color;
10661190 }
10671191
10681192 srcPtr += FONT4_WIDTH;
@@ -1070,16 +1194,15 @@ static void drawKeyOffMedium(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex) · 1 unmodified line
10701194 }
10711195 }
10721196
1073−static void drawNoteMedium(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, int16_t ton)
1197+static void drawNoteMedium(uint32_t xPos, uint32_t yPos, int32_t ton, uint32_t color)
10741198 {
10751199 const uint8_t *ch1Ptr, *ch2Ptr, *ch3Ptr;
1076− uint8_t note;
1077− uint32_t *dstPtr, pixVal, fontOffset, char1, char2, char3;
1200+ uint32_t note, *dstPtr, char1, char2, char3;
10781201
10791202 ton--;
10801203
1081− note = ton % 12;
1082− char3 = (ton / 12) * FONT4_CHAR_W;
1204+ note = noteTab1[ton];
1205+ char3 = noteTab2[ton] * FONT4_CHAR_W;
10831206
10841207 if (config.ptnAcc == 0)
10851208 {
@@ -1092,20 +1215,18 @@ static void drawNoteMedium(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, i · 6 unmodified lines
10921215 char2 = flatNote2Char_med[note];
10931216 }
10941217
1095− pixVal = video.palette[paletteIndex];
1096− fontOffset = config.ptnFont * (FONT4_WIDTH * FONT4_CHAR_H);
1097− ch1Ptr = &font4Data[char1 + fontOffset];
1098− ch2Ptr = &font4Data[char2 + fontOffset];
1099− ch3Ptr = &font4Data[char3 + fontOffset];
1218+ ch1Ptr = &font4Ptr[char1];
1219+ ch2Ptr = &font4Ptr[char2];
1220+ ch3Ptr = &font4Ptr[char3];
11001221 dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
11011222
11021223 for (uint32_t y = 0; y < FONT4_CHAR_H; y++)
11031224 {
11041225 for (uint32_t x = 0; x < FONT4_CHAR_W; x++)
11051226 {
1106− if (ch1Ptr[x]) dstPtr[(FONT4_CHAR_W * 0) + x] = pixVal;
1107− if (ch2Ptr[x]) dstPtr[(FONT4_CHAR_W * 1) + x] = pixVal;
1108− if (ch3Ptr[x]) dstPtr[(FONT4_CHAR_W * 2) + x] = pixVal;
1227+ if (ch1Ptr[x]) dstPtr[(FONT4_CHAR_W * 0) + x] = color;
1228+ if (ch2Ptr[x]) dstPtr[(FONT4_CHAR_W * 1) + x] = color;
1229+ if (ch3Ptr[x]) dstPtr[(FONT4_CHAR_W * 2) + x] = color;
11091230 }
11101231
11111232 ch1Ptr += FONT4_WIDTH;
@@ -1115,13 +1236,12 @@ static void drawNoteMedium(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, i · 3 unmodified lines
11151236 }
11161237 }
11171238
1118−static void drawEmptyNoteBig(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex)
1239+static void drawEmptyNoteBig(uint32_t xPos, uint32_t yPos, uint32_t color)
11191240 {
11201241 const uint8_t *srcPtr;
1121− uint32_t *dstPtr, pixVal;
1242+ uint32_t *dstPtr;
11221243
1123− pixVal = video.palette[paletteIndex];
1124− srcPtr = &font4Data[(67 * FONT4_CHAR_W) + (config.ptnFont * (FONT4_WIDTH * FONT4_CHAR_H))];
1244+ srcPtr = &font4Ptr[67 * FONT4_CHAR_W];
11251245 dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
11261246
11271247 for (uint32_t y = 0; y < FONT4_CHAR_H; y++)
@@ -1129,7 +1249,7 @@ static void drawEmptyNoteBig(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex) · 1 unmodified line
11291249 for (uint32_t x = 0; x < FONT4_CHAR_W*6; x++)
11301250 {
11311251 if (srcPtr[x])
1132− dstPtr[x] = pixVal;
1252+ dstPtr[x] = color;
11331253 }
11341254
11351255 srcPtr += FONT4_WIDTH;
@@ -1137,13 +1257,12 @@ static void drawEmptyNoteBig(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex) · 1 unmodified line
11371257 }
11381258 }
11391259
1140−static void drawKeyOffBig(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex)
1260+static void drawKeyOffBig(uint32_t xPos, uint32_t yPos, uint32_t color)
11411261 {
11421262 const uint8_t *srcPtr;
1143− uint32_t *dstPtr, pixVal;
1263+ uint32_t *dstPtr;
11441264
1145− pixVal = video.palette[paletteIndex];
1146− srcPtr = &font4Data[(61 * FONT4_CHAR_W) + (config.ptnFont * (FONT4_WIDTH * FONT4_CHAR_H))];
1265+ srcPtr = &font4Data[61 * FONT4_CHAR_W];
11471266 dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
11481267
11491268 for (uint32_t y = 0; y < FONT4_CHAR_H; y++)
@@ -1151,7 +1270,7 @@ static void drawKeyOffBig(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex) · 1 unmodified line
11511270 for (uint32_t x = 0; x < FONT4_CHAR_W*6; x++)
11521271 {
11531272 if (srcPtr[x])
1154− dstPtr[x] = pixVal;
1273+ dstPtr[x] = color;
11551274 }
11561275
11571276 srcPtr += FONT4_WIDTH;
@@ -1159,16 +1278,16 @@ static void drawKeyOffBig(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex) · 1 unmodified line
11591278 }
11601279 }
11611280
1162−static void drawNoteBig(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, int16_t ton)
1281+static void drawNoteBig(uint32_t xPos, uint32_t yPos, int32_t ton, uint32_t color)
11631282 {
11641283 const uint8_t *ch1Ptr, *ch2Ptr, *ch3Ptr;
11651284 uint8_t note;
1166− uint32_t *dstPtr, pixVal, fontOffset, char1, char2, char3;
1285+ uint32_t *dstPtr, char1, char2, char3;
11671286
11681287 ton--;
11691288
1170− note = ton % 12;
1171− char3 = (ton / 12) * FONT5_CHAR_W;
1289+ note = noteTab1[ton];
1290+ char3 = noteTab2[ton] * FONT5_CHAR_W;
11721291
11731292 if (config.ptnAcc == 0)
11741293 {
@@ -1181,20 +1300,18 @@ static void drawNoteBig(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, int1 · 6 unmodified lines
11811300 char2 = flatNote2Char_big[note];
11821301 }
11831302
1184− pixVal = video.palette[paletteIndex];
1185− fontOffset = config.ptnFont * (FONT5_WIDTH * FONT5_CHAR_H);
1186− ch1Ptr = &font5Data[char1 + fontOffset];
1187− ch2Ptr = &font5Data[char2 + fontOffset];
1188− ch3Ptr = &font5Data[char3 + fontOffset];
1303+ ch1Ptr = &font5Ptr[char1];
1304+ ch2Ptr = &font5Ptr[char2];
1305+ ch3Ptr = &font5Ptr[char3];
11891306 dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
11901307
11911308 for (uint32_t y = 0; y < FONT5_CHAR_H; y++)
11921309 {
11931310 for (uint32_t x = 0; x < FONT5_CHAR_W; x++)
11941311 {
1195− if (ch1Ptr[x]) dstPtr[(FONT5_CHAR_W * 0) + x] = pixVal;
1196− if (ch2Ptr[x]) dstPtr[(FONT5_CHAR_W * 1) + x] = pixVal;
1197− if (ch3Ptr[x]) dstPtr[(FONT5_CHAR_W * 2) + x] = pixVal;
1312+ if (ch1Ptr[x]) dstPtr[(FONT5_CHAR_W * 0) + x] = color;
1313+ if (ch2Ptr[x]) dstPtr[(FONT5_CHAR_W * 1) + x] = color;
1314+ if (ch3Ptr[x]) dstPtr[(FONT5_CHAR_W * 2) + x] = color;
11981315 }
11991316
12001317 ch1Ptr += FONT5_WIDTH;
@@ -1203,145 +1320,3 @@ static void drawNoteBig(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, int1 · 2 unmodified lines
12031320 dstPtr += SCREEN_W;
12041321 }
12051322 }
1206−
1207−const pattCoord_t pattCoordTable[2][2][2] =
1208−{
1209− /*
1210− uint16_t upperRowsY, lowerRowsY;
1211− uint16_t upperRowsTextY, midRowTextY, lowerRowsTextY;
1212− uint16_t numUpperRows, numLowerRows;
1213− */
1214−
1215− // no pattern stretch
1216− {
1217− // no pattern channel scroll
1218− {
1219− { 176, 292, 177, 283, 293, 13, 13 }, // normal pattern editor
1220− { 56, 228, 57, 219, 229, 20, 21 }, // extended pattern editor
1221− },
1222−
1223− // pattern channel scroll
1224− {
1225− { 176, 285, 177, 276, 286, 12, 12 }, // normal pattern editor
1226− { 56, 221, 57, 212, 222, 19, 20 }, // extended pattern editor
1227− }
1228− },
1229−
1230− // pattern stretch
1231− {
1232− // no pattern channel scroll
1233− {
1234− { 177, 286, 178, 277, 288, 9, 10 }, // normal pattern editor
1235− { 56, 232, 58, 223, 234, 15, 15 }, // extended pattern editor
1236− },
1237−
1238− // pattern channel scroll
1239− {
1240− { 176, 285, 177, 276, 286, 9, 9 }, // normal pattern editor
1241− { 56, 220, 57, 211, 221, 14, 15 }, // extended pattern editor
1242− },
1243− }
1244−};
1245−
1246−const pattCoord2_t pattCoord2Table[2][2][2] =
1247−{
1248− /*
1249− uint16_t upperRowsY, lowerRowsY;
1250− uint16_t upperRowsH, lowerRowsH;
1251− */
1252−
1253− // no pattern stretch
1254− {
1255− // no pattern channel scroll
1256− {
1257− { 175, 291, 107, 107 }, // normal pattern editor
1258− { 55, 227, 163, 171 }, // extended pattern editor
1259− },
1260−
1261− // pattern channel scroll
1262− {
1263− { 175, 284, 100, 100 }, // normal pattern editor
1264− { 55, 220, 156, 164 }, // extended pattern editor
1265− }
1266− },
1267−
1268− // pattern stretch
1269− {
1270− // no pattern channel scroll
1271− {
1272− { 175, 285, 101, 113 }, // normal pattern editor
1273− { 55, 231, 167, 167 }, // extended pattern editor
1274− },
1275−
1276− // pattern channel scroll
1277− {
1278− { 175, 284, 100, 100 }, // normal pattern editor
1279− { 55, 219, 155, 165 }, // extended pattern editor
1280− },
1281− }
1282−};
1283−
1284−const markCoord_t markCoordTable[2][2][2] =
1285−{
1286− // uint16_t upperRowsY, midRowY, lowerRowsY;
1287−
1288− // no pattern stretch
1289− {
1290− // no pattern channel scroll
1291− {
1292− { 177, 281, 293 }, // normal pattern editor
1293− { 57, 217, 229 }, // extended pattern editor
1294− },
1295−
1296− // pattern channel scroll
1297− {
1298− { 177, 274, 286 }, // normal pattern editor
1299− { 57, 210, 222 }, // extended pattern editor
1300− }
1301− },
1302−
1303− // pattern stretch
1304− {
1305− // no pattern channel scroll
1306− {
1307− { 176, 275, 286 }, // normal pattern editor
1308− { 56, 221, 232 }, // extended pattern editor
1309− },
1310−
1311− // pattern channel scroll
1312− {
1313− { 175, 274, 284 }, // normal pattern editor
1314− { 55, 209, 219 }, // extended pattern editor
1315− },
1316− }
1317−};
1318−
1319−const uint8_t pattCursorXTab[2 * 4 * 8] =
1320−{
1321− // no volume column shown
1322− 32, 88, 104, 0, 0, 120, 136, 152, // 4 columns visible
1323− 32, 80, 88, 0, 0, 96, 104, 112, // 6 columns visible
1324− 32, 56, 64, 0, 0, 72, 80, 88, // 8 columns visible
1325− 32, 52, 56, 0, 0, 60, 64, 68, // 12 columns visible
1326−
1327− // volume column shown
1328− 32, 96, 104, 120, 128, 144, 152, 160, // 4 columns visible
1329− 32, 56, 64, 80, 88, 96, 104, 112, // 6 columns visible
1330− 32, 60, 64, 72, 76, 84, 88, 92, // 8 columns visible
1331− 32, 60, 64, 72, 76, 84, 88, 92, // 12 columns visible
1332−};
1333−
1334−const uint8_t pattCursorWTab[2 * 4 * 8] =
1335−{
1336− // no volume column shown
1337− 48, 16, 16, 0, 0, 16, 16, 16, // 4 columns visible
1338− 48, 8, 8, 0, 0, 8, 8, 8, // 6 columns visible
1339− 24, 8, 8, 0, 0, 8, 8, 8, // 8 columns visible
1340− 16, 4, 4, 0, 0, 4, 4, 4, // 12 columns visible
1341−
1342− // volume column shown
1343− 48, 8, 8, 8, 8, 8, 8, 8, // 4 columns visible
1344− 24, 8, 8, 8, 8, 8, 8, 8, // 6 columns visible
1345− 24, 4, 4, 4, 4, 4, 4, 4, // 8 columns visible
1346− 24, 4, 4, 4, 4, 4, 4, 4 // 12 columns visible
1347−};
src/ft2_pattern_draw.h+3−2
@@ -2,6 +2,7 @@ · 1 unmodified line
22
33 #include <stdint.h>
44
5+void updatePattFontPtrs(void);
56 void drawPatternBorders(void);
6−void writePattern(int16_t currRow, int16_t pattern);
7−void pattTwoHexOut(uint32_t xPos, uint32_t yPos, uint8_t paletteIndex, uint8_t val);
7+void writePattern(int32_t currRow, int32_t pattern);
8+void pattTwoHexOut(uint32_t xPos, uint32_t yPos, uint8_t val, uint32_t color);
src/ft2_pattern_ed.c+26−13
@@ -21,6 +21,8 @@ · 20 unmodified lines
2121 #include "ft2_mouse.h"
2222 #include "ft2_video.h"
2323
24+#include "ft2_module_loader.h"
25+
2426 // for pattern marking w/ keyboard
2527 static int8_t lastChMark;
2628 static int16_t lastRowMark;
@@ -657,7 +659,13 @@ void patternEditorExtended(void) · 630 unmodified lines
657659 drawFramework(2, 2, 51, 20, FRAMEWORK_TYPE2);
658660 drawFramework(2, 31, 51, 20, FRAMEWORK_TYPE2);
659661
662+ // force updating of end/page/length when showing scrollbar
663+ scrollBars[SB_POS_ED].oldEnd = 0xFFFFFFFF;
664+ scrollBars[SB_POS_ED].oldPage = 0xFFFFFFFF;
665+ scrollBars[SB_POS_ED].oldPos = 0xFFFFFFFF;
666+
660667 showScrollBar(SB_POS_ED);
668+
661669 showPushButton(PB_POSED_POS_UP);
662670 showPushButton(PB_POSED_POS_DOWN);
663671 showPushButton(PB_POSED_INS);
@@ -2063,6 +2071,10 @@ void drawPosEdNums(int16_t songPos) · 1399 unmodified lines
20632071 {
20642072 uint8_t y;
20652073 int16_t entry;
2074+ uint32_t color1, color2;
2075+
2076+ color1 = video.palette[PAL_PATTEXT];
2077+ color2 = video.palette[PAL_FORGRND];
20662078
20672079 if (songPos >= song.len)
20682080 songPos = song.len - 1;
@@ -2092,13 +2104,13 @@ void drawPosEdNums(int16_t songPos) · 23 unmodified lines
20922104
20932105 if (editor.ui.extended)
20942106 {
2095− pattTwoHexOut(8, 4 + (y * 9), PAL_PATTEXT, (uint8_t)entry);
2096− pattTwoHexOut(32, 4 + (y * 9), PAL_PATTEXT, song.songTab[entry]);
2107+ pattTwoHexOut(8, 4 + (y * 9), (uint8_t)entry, color1);
2108+ pattTwoHexOut(32, 4 + (y * 9), song.songTab[entry], color1);
20972109 }
20982110 else
20992111 {
2100− pattTwoHexOut(8, 4 + (y * 8), PAL_PATTEXT, (uint8_t)entry);
2101− pattTwoHexOut(32, 4 + (y * 8), PAL_PATTEXT, song.songTab[entry]);
2112+ pattTwoHexOut(8, 4 + (y * 8), (uint8_t)entry, color1);
2113+ pattTwoHexOut(32, 4 + (y * 8), song.songTab[entry], color1);
21022114 }
21032115 }
21042116
@@ -2107,13 +2119,13 @@ void drawPosEdNums(int16_t songPos) · 2 unmodified lines
21072119 // middle
21082120 if (editor.ui.extended)
21092121 {
2110− pattTwoHexOut(8, 23, PAL_FORGRND, (uint8_t)songPos);
2111− pattTwoHexOut(32, 23, PAL_FORGRND, song.songTab[songPos]);
2122+ pattTwoHexOut(8, 23, (uint8_t)songPos, color2);
2123+ pattTwoHexOut(32, 23, song.songTab[songPos], color2);
21122124 }
21132125 else
21142126 {
2115− pattTwoHexOut(8, 22, PAL_FORGRND, (uint8_t)songPos);
2116− pattTwoHexOut(32, 22, PAL_FORGRND, song.songTab[songPos]);
2127+ pattTwoHexOut(8, 22, (uint8_t)songPos, color2);
2128+ pattTwoHexOut(32, 22, song.songTab[songPos], color2);
21172129 }
21182130
21192131 // bottom two
@@ -2125,13 +2137,13 @@ void drawPosEdNums(int16_t songPos) · 5 unmodified lines
21252137
21262138 if (editor.ui.extended)
21272139 {
2128− pattTwoHexOut(8, 33 + (y * 9), PAL_PATTEXT, (uint8_t)entry);
2129− pattTwoHexOut(32, 33 + (y * 9), PAL_PATTEXT, song.songTab[entry]);
2140+ pattTwoHexOut(8, 33 + (y * 9), (uint8_t)entry, color1);
2141+ pattTwoHexOut(32, 33 + (y * 9), song.songTab[entry], color1);
21302142 }
21312143 else
21322144 {
2133− pattTwoHexOut(8, 32 + (y * 8), PAL_PATTEXT, (uint8_t)entry);
2134− pattTwoHexOut(32, 32 + (y * 8), PAL_PATTEXT, song.songTab[entry]);
2145+ pattTwoHexOut(8, 32 + (y * 8), (uint8_t)entry, color1);
2146+ pattTwoHexOut(32, 32 + (y * 8), song.songTab[entry], color1);
21352147 }
21362148 }
21372149 }
@@ -2256,7 +2268,7 @@ void drawPlaybackTime(void) · 118 unmodified lines
22562268 char str[2 + 1];
22572269 uint32_t a, MI_TimeH, MI_TimeM, MI_TimeS;
22582270
2259− a = ((song.musicTime / 256) * 5) / 512;
2271+ a = ((song.musicTime >> 8) * 5) >> 9;
22602272 MI_TimeH = a / 3600;
22612273 a -= (MI_TimeH * 3600);
22622274 MI_TimeM = a / 60;
@@ -2803,6 +2815,7 @@ void pbToggleBadge(void) · 540 unmodified lines
28032815
28042816 void resetChannelOffset(void)
28052817 {
2818+ editor.ui.pattChanScrollShown = song.antChn > getMaxVisibleChannels();
28062819 editor.cursor.object = CURSOR_NOTE;
28072820 editor.cursor.ch = 0;
28082821 setScrollBarPos(SB_CHAN_SCROLL, 0, true);
src/ft2_pattern_ed.h+0−1
@@ -74,7 +74,6 @@ void cursorLeft(void); · 73 unmodified lines
7474 void cursorRight(void);
7575 void chanLeft(void);
7676 void chanRight(void);
77−void writePattern(int16_t currRow, int16_t pattern);
7877 void showPatternEditor(void);
7978 void updateInstrumentSwitcher(void);
8079 void hidePatternEditor(void);
src/ft2_replayer.c+31−36
@@ -422,7 +422,7 @@ static void startTone(uint8_t ton, uint8_t effTyp, uint8_t eff, stmTyp *ch) · 421 unmodified lines
422422 if (ton > 96) // non-FT2 security (should never happen because I clamp in the patt loaders now)
423423 ton = 96;
424424
425− smp = ins->ta[ton-1] & 0x0F;
425+ smp = ins->ta[ton-1] & 0xF;
426426 ch->sampleNr = smp;
427427
428428 s = &ins->samp[smp];
@@ -1208,9 +1208,9 @@ static void fixaEnvelopeVibrato(stmTyp *ch) · 779 unmodified lines
12081208 uint8_t envPos;
12091209 int16_t autoVibVal, panTmp;
12101210 uint16_t autoVibAmp, tmpPeriod, envVal;
1211− int32_t vol, tmp32;
1211+ int32_t tmp32;
1212+ uint32_t vol;
12121213 instrTyp *ins;
1213− double dVol;
12141214
12151215 ins = ch->instrSeg;
12161216
@@ -1257,7 +1257,7 @@ static void fixaEnvelopeVibrato(stmTyp *ch) · 40 unmodified lines
12571257 {
12581258 envPos = ins->envVRepS;
12591259 ch->envVCnt = ins->envVP[envPos][0];
1260− ch->envVAmp = (ins->envVP[envPos][1] & 0xFF) << 8;
1260+ ch->envVAmp = ins->envVP[envPos][1] << 8;
12611261 }
12621262 }
12631263
@@ -1284,7 +1284,7 @@ static void fixaEnvelopeVibrato(stmTyp *ch) · 20 unmodified lines
12841284 ch->envVIPValue = 0;
12851285 if (ins->envVP[envPos][0] > ins->envVP[envPos-1][0])
12861286 {
1287− ch->envVIPValue = ((ins->envVP[envPos][1] - ins->envVP[envPos-1][1]) & 0xFF) << 8;
1287+ ch->envVIPValue = (ins->envVP[envPos][1] - ins->envVP[envPos-1][1]) << 8;
12881288 ch->envVIPValue /= (ins->envVP[envPos][0] - ins->envVP[envPos-1][0]);
12891289
12901290 envVal = ch->envVAmp;
@@ -1303,10 +1303,10 @@ static void fixaEnvelopeVibrato(stmTyp *ch) · 12 unmodified lines
13031303 ch->envVAmp += ch->envVIPValue;
13041304
13051305 envVal = ch->envVAmp;
1306− if ((envVal >> 8) > 0x40)
1306+ if (envVal > 64*256)
13071307 {
1308− if ((envVal >> 8) > (0x40+0xC0)/2)
1309− envVal = 16384;
1308+ if (envVal > 128*256)
1309+ envVal = 64*256;
13101310 else
13111311 envVal = 0;
13121312
@@ -1314,41 +1314,36 @@ static void fixaEnvelopeVibrato(stmTyp *ch) · 1 unmodified line
13141314 }
13151315 }
13161316
1317− /* old integer method with low precision (FT2 way)
1317+ /* original FT2 method with lower precision (finalVol = 0..256)
13181318 envVal >>= 8;
13191319 ch->finalVol = (song.globVol * (((envVal * ch->outVol) * ch->fadeOutAmp) >> (16 + 2))) >> 7;
13201320 */
13211321
1322− /* calculate with four times more precision (+ rounding).
1323− ** also, env. range is now 0..16384 instead of being shifted to 0..64. */
1322+ /* calculate with four times more precision (finalVol = 0..2048)
1323+ ** Also, vol envelope range is now 0..16384 instead of being shifted to 0..64
1324+ */
13241325
1325− dVol = song.globVol * ch->outVol * ch->fadeOutAmp;
1326− dVol *= envVal; // we need a float mul because it would overflow 32-bit integer
1327− dVol *= 1.0 / ((64.0 * 64.0 * 32768.0 * 16384.0) / 2048.0); // 0..2048 (real FT2 is 0..256)
1326+ uint32_t vol1 = song.globVol * ch->outVol * ch->fadeOutAmp; // 0..64 * 0..64 * 0..32768 = 0..134217728
1327+ uint32_t vol2 = envVal << 2; // 0..16384 * 2^2 = 0..65536
13281328
1329− vol = (int32_t)(dVol + 0.5);
1330− if (vol > 2048)
1331− vol = 2048;
1329+ vol = ((uint64_t)vol1 * vol2) >> 32; // 0..2048
13321330
1333− ch->finalVol = (uint16_t)vol;
13341331 ch->status |= IS_Vol;
13351332 }
13361333 else
13371334 {
1338− /* old integer method with low precision (FT2 way)
1335+ /* original FT2 method with lower precision (finalVol = 0..256)
13391336 ch->finalVol = (song.globVol * (((ch->outVol << 4) * ch->fadeOutAmp) >> 16)) >> 7;
13401337 */
13411338
1342− // calculate with four times more precision (+ rounding)
1343− dVol = song.globVol * ch->outVol * ch->fadeOutAmp;
1344− dVol *= 1.0 / ((64.0 * 64.0 * 32768.0) / 2048.0); // 0..2048 (real FT2 is 0..256)
1339+ // calculate with four times more precision (finalVol = 0..2048)
1340+ vol = (song.globVol * ch->outVol * ch->fadeOutAmp) >> 16; // 0..64 * 0..64 * 0..32768 = 0..2048
1341+ }
13451342
1346− vol = (int32_t)(dVol + 0.5);
1347− if (vol > 2048)
1348− vol = 2048;
1343+ if (vol > 2047)
1344+ vol = 2047; // range is now 0..2047 to prevent MUL overflow when voice volume is calculated
13491345
1350− ch->finalVol = (uint16_t)vol;
1351− }
1346+ ch->finalVol = (uint16_t)vol;
13521347 }
13531348 else
13541349 {
@@ -1365,7 +1360,7 @@ static void fixaEnvelopeVibrato(stmTyp *ch) · 10 unmodified lines
13651360
13661361 if (++ch->envPCnt == ins->envPP[envPos][0])
13671362 {
1368− ch->envPAmp = (ins->envPP[envPos][1] & 0xFF) << 8;
1363+ ch->envPAmp = ins->envPP[envPos][1] << 8;
13691364
13701365 envPos++;
13711366 if (ins->envPTyp & 4)
@@ -1379,7 +1374,7 @@ static void fixaEnvelopeVibrato(stmTyp *ch) · 7 unmodified lines
13791374 envPos = ins->envPRepS;
13801375
13811376 ch->envPCnt = ins->envPP[envPos][0];
1382− ch->envPAmp = (ins->envPP[envPos][1] & 0xFF) << 8;
1377+ ch->envPAmp = ins->envPP[envPos][1] << 8;
13831378 }
13841379 }
13851380
@@ -1406,7 +1401,7 @@ static void fixaEnvelopeVibrato(stmTyp *ch) · 20 unmodified lines
14061401 ch->envPIPValue = 0;
14071402 if (ins->envPP[envPos][0] > ins->envPP[envPos-1][0])
14081403 {
1409− ch->envPIPValue = ((ins->envPP[envPos][1] - ins->envPP[envPos-1][1]) & 0xFF) << 8;
1404+ ch->envPIPValue = (ins->envPP[envPos][1] - ins->envPP[envPos-1][1]) << 8;
14101405 ch->envPIPValue /= (ins->envPP[envPos][0] - ins->envPP[envPos-1][0]);
14111406
14121407 envVal = ch->envPAmp;
@@ -1425,10 +1420,10 @@ static void fixaEnvelopeVibrato(stmTyp *ch) · 12 unmodified lines
14251420 ch->envPAmp += ch->envPIPValue;
14261421
14271422 envVal = ch->envPAmp;
1428− if ((envVal >> 8) > 0x40)
1423+ if (envVal > 64*256)
14291424 {
1430− if ((envVal >> 8) > (0x40+0xC0)/2)
1431− envVal = 16384;
1425+ if (envVal > 128*256)
1426+ envVal = 64*256;
14321427 else
14331428 envVal = 0;
14341429
@@ -1441,9 +1436,9 @@ static void fixaEnvelopeVibrato(stmTyp *ch) · 6 unmodified lines
14411436 panTmp = 0 - panTmp;
14421437 panTmp += 128;
14431438
1444− envVal -= (32 * 256);
1439+ envVal -= 32*256;
14451440
1446− ch->finalPan = ch->outPan + ((((int16_t)envVal * (panTmp << 3)) >> 16) & 0xFF);
1441+ ch->finalPan = ch->outPan + (uint8_t)(((int16_t)envVal * panTmp) >> 13);
14471442 ch->status |= IS_Pan;
14481443 }
14491444 else
@@ -2589,7 +2584,7 @@ void updateChanNums(void) · 1139 unmodified lines
25892584 }
25902585 }
25912586
2592− editor.ui.pattChanScrollShown = (song.antChn > getMaxVisibleChannels());
2587+ editor.ui.pattChanScrollShown = song.antChn > getMaxVisibleChannels();
25932588
25942589 if (editor.ui.patternEditorShown)
25952590 {
src/ft2_scopes.c+9−5
@@ -86,6 +86,10 @@ static const uint16_t scopeLenTab[16][32] = · 85 unmodified lines
8686 /* 32 ch */ {15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15}
8787 };
8888
89+// ft2_pattern_draw.c
90+extern const char chDecTab1[MAX_VOICES+1];
91+extern char chDecTab2[MAX_VOICES+1];
92+
8993 void resetOldScopeRates(void)
9094 {
9195 oldVoiceDelta = 0;
@@ -175,8 +179,8 @@ static void drawScopeNumber(uint16_t scopeXOffs, uint16_t scopeYOffs, uint8_t ch · 83 unmodified lines
175179 }
176180 else
177181 {
178− charOutOutlined(scopeXOffs, scopeYOffs, PAL_MOUSEPT, '0' + (channel / 10));
179− charOutOutlined(scopeXOffs + 7, scopeYOffs, PAL_MOUSEPT, '0' + (channel % 10));
182+ charOutOutlined(scopeXOffs, scopeYOffs, PAL_MOUSEPT, chDecTab1[channel]);
183+ charOutOutlined(scopeXOffs + 7, scopeYOffs, PAL_MOUSEPT, chDecTab2[channel]);
180184 }
181185 }
182186 else
@@ -187,8 +191,8 @@ static void drawScopeNumber(uint16_t scopeXOffs, uint16_t scopeYOffs, uint8_t ch · 4 unmodified lines
187191 }
188192 else
189193 {
190− charOut(scopeXOffs, scopeYOffs, PAL_MOUSEPT, '0' + (channel / 10));
191− charOut(scopeXOffs + 7, scopeYOffs, PAL_MOUSEPT, '0' + (channel % 10));
194+ charOut(scopeXOffs, scopeYOffs, PAL_MOUSEPT, chDecTab1[channel]);
195+ charOut(scopeXOffs + 7, scopeYOffs, PAL_MOUSEPT, chDecTab2[channel]);
192196 }
193197 }
194198 }
@@ -597,7 +601,7 @@ void handleScopesFromChQueue(chSyncData_t *chSyncData, uint8_t *scopeUpdateStatu · 402 unmodified lines
597601 if (ch->voiceDelta != oldVoiceDelta)
598602 {
599603 oldVoiceDelta = ch->voiceDelta;
600− oldSFrq = (uint32_t)((oldVoiceDelta * audio.dScopeFreqMul) + 0.5); // rounded
604+ oldSFrq = (int32_t)((oldVoiceDelta * audio.dScopeFreqMul) + 0.5); // rounded
601605 }
602606
603607 sc->SFrq = oldSFrq;
src/ft2_scrollbars.c+20−1
@@ -355,6 +355,10 @@ void setScrollBarPos(uint16_t scrollBarID, uint32_t pos, bool triggerCallBack) · 354 unmodified lines
355355 assert(scrollBarID < NUM_SCROLLBARS);
356356 scrollBar = &scrollBars[scrollBarID];
357357
358+ if (scrollBar->oldPos == pos)
359+ return;
360+ scrollBar->oldPos = pos;
361+
358362 if (scrollBar->page == 0)
359363 {
360364 scrollBar->pos = 0;
@@ -405,8 +409,12 @@ void setScrollBarEnd(uint16_t scrollBarID, uint32_t end) · 44 unmodified lines
405409 if (end < 1)
406410 end = 1;
407411
408− scrollBar->end = end;
412+ if (scrollBar->oldEnd == end)
413+ return;
414+ scrollBar->oldEnd = end;
409415
416+ scrollBar->end = end;
417+
410418 setPos = false;
411419 if (scrollBar->pos >= end)
412420 {
@@ -439,6 +447,10 @@ void setScrollBarPageLength(uint16_t scrollBarID, uint32_t pageLength) · 26 unmodified lines
439447 if (pageLength < 1)
440448 pageLength = 1;
441449
450+ if (scrollBar->oldPage == pageLength)
451+ return;
452+ scrollBar->oldPage = pageLength;
453+
442454 scrollBar->page = pageLength;
443455 if (scrollBar->end > 0)
444456 {
@@ -618,6 +630,13 @@ void handleScrollBarsWhileMouseDown(void) · 173 unmodified lines
618630
619631 void initializeScrollBars(void)
620632 {
633+ for (int32_t i = 0; i < NUM_SCROLLBARS; i++)
634+ {
635+ scrollBars[i].oldEnd = 0xFFFFFFFF;
636+ scrollBars[i].oldPage = 0xFFFFFFFF;
637+ scrollBars[i].oldPos = 0xFFFFFFFF;
638+ }
639+
621640 // pattern editor
622641 setScrollBarPageLength(SB_CHAN_SCROLL, 8);
623642 setScrollBarEnd(SB_CHAN_SCROLL, 8);
src/ft2_scrollbars.h+1−0
@@ -75,6 +75,7 @@ typedef struct scrollBar_t // DO NOT TOUCH! · 74 unmodified lines
7575 bool visible;
7676 uint8_t state;
7777 uint32_t pos, page, end;
78+ uint32_t oldPos, oldPage, oldEnd;
7879 uint16_t thumbX, thumbY, thumbW, thumbH;
7980 } scrollBar_t;
8081
src/ft2_sysreqs.c+84−27
@@ -41,12 +41,41 @@ static SDL_Keycode shortCut[NUM_SYSREQ_TYPES][5] = · 40 unmodified lines
4141 { SDLK_m, SDLK_s, SDLK_c, 0, 0 },
4242 };
4343
44+typedef struct quitType_t
45+{
46+ const char *text;
47+ uint8_t typ;
48+} quitType_t;
49+
50+#define QUIT_MESSAGES 16
51+
52+// 8bitbubsy: Removed the MS-DOS ones...
53+static quitType_t quitMessage[QUIT_MESSAGES] =
54+{
55+ { "Do you really want to quit?", 2 },
56+ { "Musicians, press >Cancel<. Lamers, press >OK<", 1 },
57+ { "Tired already?", 2 },
58+ { "Dost thou wish to leave with such hasty abandon?", 2 },
59+ { "So, you think you can quit this easily, huh?", 2 },
60+ { "Hey, what is the matter? You are not quiting now, are you?", 2 },
61+ { "Rome was not built in one day! Quit really?", 2 },
62+ { "For Work and Worry, press YES. For Delectation and Demos, press NO.", 2 },
63+ { "Did you really press the right key?", 2 },
64+ { "You are a lamer, aren't you? Press >OK< to confirm.", 1 },
65+ { "Hope ya did some good. Press >OK< to quit.", 1 },
66+ { "Quit? Only for a good reason you are allowed to press >OK<.", 1 },
67+ { "Are we at the end of a Fasttracker round?", 2 },
68+ { "Are you just another boring user?", 2 },
69+ { "Hope you're doing the compulsory \"Exit ceremony\" before pressing >OK<.", 1 },
70+ { "Fasttracker...", 3 }
71+};
72+
4473 static void drawWindow(uint16_t w)
4574 {
4675 const uint16_t h = SYSTEM_REQUEST_H;
4776 uint16_t x, y;
4877
49− x = (SCREEN_W / 2) - (w / 2);
78+ x = (SCREEN_W - w) / 2;
5079 y = editor.ui.extended ? 91 : SYSTEM_REQUEST_Y;
5180
5281 // main fill
@@ -85,8 +114,10 @@ static bool mouseButtonDownLogic(uint8_t mouseButton) · 32 unmodified lines
85114 return false;
86115 }
87116
88− if (mouseButton == SDL_BUTTON_LEFT) mouse.leftButtonPressed = true;
89− else if (mouseButton == SDL_BUTTON_RIGHT) mouse.rightButtonPressed = true;
117+ if (mouseButton == SDL_BUTTON_LEFT)
118+ mouse.leftButtonPressed = true;
119+ else if (mouseButton == SDL_BUTTON_RIGHT)
120+ mouse.rightButtonPressed = true;
90121
91122 // don't do mouse down testing here if we already are using an object
92123 if (mouse.lastUsedObjectType != OBJECT_NONE)
@@ -105,8 +136,10 @@ static bool mouseButtonDownLogic(uint8_t mouseButton) · 12 unmodified lines
105136
106137 static bool mouseButtonUpLogic(uint8_t mouseButton)
107138 {
108− if (mouseButton == SDL_BUTTON_LEFT) mouse.leftButtonPressed = false;
109− else if (mouseButton == SDL_BUTTON_RIGHT) mouse.rightButtonPressed = false;
139+ if (mouseButton == SDL_BUTTON_LEFT)
140+ mouse.leftButtonPressed = false;
141+ else if (mouseButton == SDL_BUTTON_RIGHT)
142+ mouse.rightButtonPressed = false;
110143
111144 editor.textCursorBlinkCounter = 0;
112145
@@ -118,13 +151,12 @@ static bool mouseButtonUpLogic(uint8_t mouseButton) · 5 unmodified lines
118151 }
119152
120153 // WARNING: This routine must ONLY be called from the main input/video thread!
121−int16_t okBox(int16_t typ, char *headline, char *text)
154+int16_t okBox(int16_t typ, const char *headline, const char *text)
122155 {
123156 #define PUSHBUTTON_W 80
124157
125158 int16_t returnVal, oldLastUsedObjectID, oldLastUsedObjectType;
126159 uint16_t x, y, i, tlen, hlen, wlen, tx, knp, headlineX, textX;
127− const uint16_t mid = SCREEN_W / 2;
128160 SDL_Event inputEvent;
129161 pushButton_t *p;
130162 checkBox_t *c;
@@ -172,9 +204,9 @@ int16_t okBox(int16_t typ, char *headline, char *text) · 41 unmodified lines
172204 if (wlen > 600)
173205 wlen = 600;
174206
175− headlineX = mid - (hlen / 2);
176− textX = mid - (tlen / 2);
177− x = mid - (wlen / 2);
207+ headlineX = (SCREEN_W - hlen) / 2;
208+ textX = (SCREEN_W - tlen) / 2;
209+ x = (SCREEN_W - wlen) / 2;
178210
179211 // the box y position differs in extended pattern editor mode
180212 y = editor.ui.extended ? SYSTEM_REQUEST_Y_EXT : SYSTEM_REQUEST_Y;
@@ -184,7 +216,7 @@ int16_t okBox(int16_t typ, char *headline, char *text) · 3 unmodified lines
184216 {
185217 p = &pushButtons[i];
186218
187− p->x = (mid - (tx / 2)) + (i * 100);
219+ p->x = ((SCREEN_W - tx) / 2) + (i * 100);
188220 p->y = y + 42;
189221 p->w = PUSHBUTTON_W;
190222 p->h = 16;
@@ -231,8 +263,10 @@ int16_t okBox(int16_t typ, char *headline, char *text) · 40 unmodified lines
231263
232264 if (mouse.leftButtonPressed || mouse.rightButtonPressed)
233265 {
234− if (mouse.lastUsedObjectType == OBJECT_PUSHBUTTON) handlePushButtonsWhileMouseDown();
235− else if (mouse.lastUsedObjectType == OBJECT_CHECKBOX) handleCheckBoxesWhileMouseDown();
266+ if (mouse.lastUsedObjectType == OBJECT_PUSHBUTTON)
267+ handlePushButtonsWhileMouseDown();
268+ else if (mouse.lastUsedObjectType == OBJECT_CHECKBOX)
269+ handleCheckBoxesWhileMouseDown();
236270 }
237271
238272 while (SDL_PollEvent(&inputEvent))
@@ -330,7 +364,7 @@ int16_t okBox(int16_t typ, char *headline, char *text) · 91 unmodified lines
330364 ** - This routine must ONLY be called from the main input/video thread!!
331365 ** - edText must be null-terminated
332366 */
333−int16_t inputBox(int16_t typ, char *headline, char *edText, uint16_t maxStrLen)
367+int16_t inputBox(int16_t typ, const char *headline, char *edText, uint16_t maxStrLen)
334368 {
335369 #define PUSHBUTTON_W 80
336370 #define TEXTBOX_W 250
@@ -338,7 +372,6 @@ int16_t inputBox(int16_t typ, char *headline, char *edText, uint16_t maxStrLen) · 1 unmodified line
338372 char *inputText;
339373 int16_t returnVal, oldLastUsedObjectID, oldLastUsedObjectType;
340374 uint16_t y, wlen, tx, knp, headlineX, i;
341− const uint16_t mid = SCREEN_W / 2;
342375 SDL_Event inputEvent;
343376 pushButton_t *p;
344377 textBox_t *t;
@@ -389,7 +422,7 @@ int16_t inputBox(int16_t typ, char *headline, char *edText, uint16_t maxStrLen) · 44 unmodified lines
389422 mouseAnimOff();
390423
391424 wlen = textWidth(headline);
392− headlineX = mid - (wlen / 2);
425+ headlineX = (SCREEN_W - wlen) / 2;
393426
394427 // count number of buttons
395428 knp = 0;
@@ -412,7 +445,7 @@ int16_t inputBox(int16_t typ, char *headline, char *edText, uint16_t maxStrLen) · 16 unmodified lines
412445 y = editor.ui.extended ? SYSTEM_REQUEST_Y_EXT : SYSTEM_REQUEST_Y;
413446
414447 // set further text box settings
415− t->x = mid - (TEXTBOX_W / 2);
448+ t->x = (SCREEN_W - TEXTBOX_W) / 2;
416449 t->y = y + 24;
417450 t->visible = true;
418451
@@ -423,7 +456,7 @@ int16_t inputBox(int16_t typ, char *headline, char *edText, uint16_t maxStrLen) · 4 unmodified lines
423456
424457 p->w = PUSHBUTTON_W;
425458 p->h = 16;
426− p->x = (mid - (tx / 2)) + (i * 100);
459+ p->x = ((SCREEN_W - tx) / 2) + (i * 100);
427460 p->y = y + 42;
428461 p->caption = buttonText[typ][i];
429462 p->visible = true;
@@ -452,8 +485,10 @@ int16_t inputBox(int16_t typ, char *headline, char *edText, uint16_t maxStrLen) · 22 unmodified lines
452485
453486 if (mouse.leftButtonPressed || mouse.rightButtonPressed)
454487 {
455− if (mouse.lastUsedObjectType == OBJECT_PUSHBUTTON) handlePushButtonsWhileMouseDown();
456− else if (mouse.lastUsedObjectType == OBJECT_TEXTBOX) handleTextBoxWhileMouseDown();
488+ if (mouse.lastUsedObjectType == OBJECT_PUSHBUTTON)
489+ handlePushButtonsWhileMouseDown();
490+ else if (mouse.lastUsedObjectType == OBJECT_TEXTBOX)
491+ handleTextBoxWhileMouseDown();
457492 }
458493
459494 while (SDL_PollEvent(&inputEvent))
@@ -575,7 +610,7 @@ int16_t inputBox(int16_t typ, char *headline, char *edText, uint16_t maxStrLen) · 115 unmodified lines
575610 }
576611
577612 // WARNING: This routine must NOT be called from the main input/video thread!
578−int16_t okBoxThreadSafe(int16_t typ, char *headline, char *text)
613+int16_t okBoxThreadSafe(int16_t typ, const char *headline, const char *text)
579614 {
580615 // block multiple calls before they are completed (for safety)
581616 while (okBoxData.active)
@@ -592,10 +627,34 @@ int16_t okBoxThreadSafe(int16_t typ, char *headline, char *text) · 10 unmodified lines
592627 return okBoxData.returnData;
593628 }
594629
595−int16_t quitBox(bool skipQuitMsg)
630+static bool askQuit_RandomMsg(void)
596631 {
597− char *text;
632+ uint8_t msg = rand() % QUIT_MESSAGES;
633+ int16_t button = okBox(quitMessage[msg].typ, "System request", quitMessage[msg].text);
598634
635+ return (button == 1) ? true : false;
636+}
637+
638+bool askUnsavedChanges(uint8_t type)
639+{
640+ int16_t button;
641+
642+ if (type == ASK_TYPE_QUIT)
643+ {
644+ button = okBox(2, "System request",
645+ "You have unsaved changes in your song. Do you still want to quit and lose ALL changes?");
646+ }
647+ else
648+ {
649+ button = okBox(2, "System request",
650+ "You have unsaved changes in your song. Load new song and lose ALL changes?");
651+ }
652+
653+ return (button == 1) ? true : false;
654+}
655+
656+int16_t quitBox(bool skipQuitMsg)
657+{
599658 if (editor.ui.sysReqShown)
600659 return 0;
601660
@@ -603,9 +662,7 @@ int16_t quitBox(bool skipQuitMsg) · 1 unmodified line
603662 return 1;
604663
605664 if (song.isModified)
606− text = "You have unsaved changes in your song. Do you still want to quit and lose ALL changes?";
607− else
608− text = "Do you really want to quit?";
665+ return askUnsavedChanges(ASK_TYPE_QUIT);
609666
610− return okBox(2, "System request", text);
667+ return askQuit_RandomMsg();
611668 }
src/ft2_sysreqs.h+11−4
@@ -3,15 +3,22 @@ · 2 unmodified lines
33 #include <stdint.h>
44 #include <stdbool.h>
55
6−int16_t okBoxThreadSafe(int16_t typ, char *headline, char *text);
7−int16_t okBox(int16_t typ, char *headline, char *text);
6+int16_t okBoxThreadSafe(int16_t typ, const char *headline, const char *text);
7+int16_t okBox(int16_t typ, const char *headline, const char *text);
88 int16_t quitBox(bool skipQuitMsg);
9−int16_t inputBox(int16_t typ, char *headline, char *edText, uint16_t maxStrLen);
9+int16_t inputBox(int16_t typ, const char *headline, char *edText, uint16_t maxStrLen);
10+bool askUnsavedChanges(uint8_t type);
1011
1112 // for thread-safe version of okBox()
1213 struct
1314 {
1415 volatile bool active;
1516 int16_t typ, returnData;
16− char *headline, *text;
17+ const char *headline, *text;
1718 } okBoxData;
19+
20+enum
21+{
22+ ASK_TYPE_QUIT = 0,
23+ ASK_TYPE_LOAD_SONG = 1,
24+};
src/ft2_video.c+39−25
@@ -23,6 +23,7 @@ · 22 unmodified lines
2323 #include "ft2_mouse.h"
2424 #include "ft2_scopes.h"
2525 #include "ft2_pattern_ed.h"
26+#include "ft2_pattern_draw.h"
2627 #include "ft2_sample_ed.h"
2728 #include "ft2_nibbles.h"
2829 #include "ft2_inst_ed.h"
@@ -33,13 +34,6 @@ · 4 unmodified lines
3334 #include "ft2_module_loader.h"
3435 #include "ft2_midi.h"
3536
36−// for FPS counter
37−#define FPS_SCAN_FRAMES 60
38−#define FPS_RENDER_W 280
39−#define FPS_RENDER_H (((FONT1_CHAR_H + 1) * 8) + 1)
40−#define FPS_RENDER_X 2
41−#define FPS_RENDER_Y 2
42−
4337 static const uint8_t textCursorData[12] =
4438 {
4539 PAL_FORGRND, PAL_FORGRND, PAL_FORGRND,
@@ -49,17 +43,28 @@ static const uint8_t textCursorData[12] = · 3 unmodified lines
4943 };
5044
5145 static bool songIsModified;
52−static char buf[1024], wndTitle[128 + PATH_MAX];
53−static uint64_t frameStartTime, timeNext64, timeNext64Frac;
46+static char wndTitle[128 + PATH_MAX];
47+static uint64_t timeNext64, timeNext64Frac;
5448 static sprite_t sprites[SPRITE_NUM];
49+
50+// for FPS counter
51+#define FPS_SCAN_FRAMES 60
52+#define FPS_RENDER_W 280
53+#define FPS_RENDER_H (((FONT1_CHAR_H + 1) * 8) + 1)
54+#define FPS_RENDER_X 2
55+#define FPS_RENDER_Y 2
56+
57+static char fpsTextBuf[1024];
58+static uint64_t frameStartTime;
5559 static double dRunningFPS, dFrameTime, dAvgFPS;
60+// ------------------
5661
5762 static void drawReplayerData(void);
5863
5964 void resetFPSCounter(void)
6065 {
6166 editor.framesPassed = 0;
62− buf[0] = '\0';
67+ fpsTextBuf[0] = '\0';
6368 dRunningFPS = VBLANK_HZ;
6469 dFrameTime = 1000.0 / VBLANK_HZ;
6570 }
@@ -106,7 +111,7 @@ static void drawFPSCounter(void) · 40 unmodified lines
106111 if (dAudLatency < 0.0 || dAudLatency > 999999999.9999)
107112 dAudLatency = 999999999.9999; // prevent number from overflowing text box
108113
109− sprintf(buf, "Frames per second: %.4f\n" \
114+ sprintf(fpsTextBuf, "Frames per second: %.4f\n" \
110115 "Monitor refresh rate: %.1fHz (+/-)\n" \
111116 "59..61Hz GPU VSync used: %s\n" \
112117 "Audio frequency: %.1fkHz (expected %.1fkHz)\n" \
@@ -126,7 +131,7 @@ static void drawFPSCounter(void) · 13 unmodified lines
126131 xPos = FPS_RENDER_X + 3;
127132 yPos = FPS_RENDER_Y + 3;
128133
129− textPtr = buf;
134+ textPtr = fpsTextBuf;
130135 while (*textPtr != '\0')
131136 {
132137 ch = *textPtr++;
@@ -210,7 +215,7 @@ void showErrorMsgBox(const char *fmt, ...) · 77 unmodified lines
210215 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", strBuf, video.window);
211216 }
212217
213−void updateRenderSizeVars(void)
218+static void updateRenderSizeVars(void)
214219 {
215220 int32_t di;
216221 #ifdef __APPLE__
@@ -754,11 +759,13 @@ void closeVideo(void) · 537 unmodified lines
754759 video.window = NULL;
755760 }
756761
757− if (video.frameBuffer != NULL)
762+ if (video.frameBufferUnaligned != NULL)
758763 {
759− free(video.frameBuffer);
760− video.frameBuffer = NULL;
764+ free(video.frameBufferUnaligned);
765+ video.frameBufferUnaligned = NULL;
761766 }
767+
768+ video.frameBuffer = NULL;
762769 }
763770
764771 void setWindowSizeFromConfig(bool updateRenderer)
@@ -854,7 +861,7 @@ bool recreateTexture(void) · 89 unmodified lines
854861 video.texture = SDL_CreateTexture(video.renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SCREEN_W, SCREEN_H);
855862 if (video.texture == NULL)
856863 {
857− showErrorMsgBox("Couldn't create a %dx%d GPU texture:\n%s\n\nIs your GPU (+ driver) too old?", SCREEN_W, SCREEN_H, SDL_GetError());
864+ showErrorMsgBox("Couldn't create a %dx%d GPU texture:\n\"%s\"\n\nIs your GPU (+ driver) too old?", SCREEN_W, SCREEN_H, SDL_GetError());
858865 return false;
859866 }
860867
@@ -930,7 +937,7 @@ bool setupRenderer(void) · 69 unmodified lines
930937
931938 if (video.renderer == NULL)
932939 {
933− showErrorMsgBox("Couldn't create SDL renderer:\n%s\n\nIs your GPU (+ driver) too old?",
940+ showErrorMsgBox("Couldn't create SDL renderer:\n\"%s\"\n\nIs your GPU (+ driver) too old?",
934941 SDL_GetError());
935942 return false;
936943 }
@@ -946,19 +953,22 @@ bool setupRenderer(void) · 9 unmodified lines
946953
947954 if (!recreateTexture())
948955 {
949− showErrorMsgBox("Couldn't create a %dx%d GPU texture:\n%s\n\nIs your GPU (+ driver) too old?",
956+ showErrorMsgBox("Couldn't create a %dx%d GPU texture:\n\"%s\"\n\nIs your GPU (+ driver) too old?",
950957 SCREEN_W, SCREEN_H, SDL_GetError());
951958 return false;
952959 }
953960
954961 // framebuffer used by SDL (for texture)
955− video.frameBuffer = (uint32_t *)malloc(SCREEN_W * SCREEN_H * sizeof (int32_t));
956− if (video.frameBuffer == NULL)
962+ video.frameBufferUnaligned = (uint32_t *)MALLOC_PAD(SCREEN_W * SCREEN_H * sizeof (int32_t), 256);
963+ if (video.frameBufferUnaligned == NULL)
957964 {
958965 showErrorMsgBox("Not enough memory!");
959966 return false;
960967 }
961968
969+ // we want an aligned pointer
970+ video.frameBuffer = (uint32_t *)ALIGN_PTR(video.frameBufferUnaligned, 256);
971+
962972 if (!setupSprites())
963973 return false;
964974
@@ -1033,16 +1043,20 @@ void handleRedrawing(void) · 68 unmodified lines
10331043 if (!editor.ui.diskOpShown)
10341044 drawPlaybackTime();
10351045
1036− if (editor.ui.sampleEditorExtShown) handleSampleEditorExtRedrawing();
1037− else if (editor.ui.scopesShown) drawScopes();
1046+ if (editor.ui.sampleEditorExtShown)
1047+ handleSampleEditorExtRedrawing();
1048+ else if (editor.ui.scopesShown)
1049+ drawScopes();
10381050 }
10391051 }
10401052 }
10411053
10421054 drawReplayerData();
10431055
1044− if (editor.ui.instEditorShown) handleInstEditorRedrawing();
1045− else if (editor.ui.sampleEditorShown) handleSamplerRedrawing();
1056+ if (editor.ui.instEditorShown)
1057+ handleInstEditorRedrawing();
1058+ else if (editor.ui.sampleEditorShown)
1059+ handleSamplerRedrawing();
10461060
10471061 // blink text edit cursor
10481062 if (editor.editTextFlag && mouse.lastEditBox != -1)
src/ft2_video.h+8−7
@@ -18,16 +18,18 @@ enum · 17 unmodified lines
1818
1919 struct video_t
2020 {
21− uint8_t upscaleFactor;
22− bool fullscreen, vsync60HzPresent, showFPSCounter;
23− int32_t renderX, renderY, renderW, renderH, displayW, displayH;
24− uint32_t *frameBuffer, palette[PAL_NUM], vblankTimeLen, vblankTimeLenFrac;
21+ bool fullscreen, showFPSCounter;
2522 uint32_t xScale, yScale;
26− double dMonitorRefreshRate, dMouseXMul, dMouseYMul;
23+ uint32_t *frameBuffer, palette[PAL_NUM], vblankTimeLen, vblankTimeLenFrac;
2724 #ifdef _WIN32
2825 HWND hWnd;
2926 #endif
3027 SDL_Window *window;
28+ double dMonitorRefreshRate, dMouseXMul, dMouseYMul;
29+ uint8_t upscaleFactor;
30+ bool vsync60HzPresent;
31+ int32_t renderX, renderY, renderW, renderH, displayW, displayH;
32+ uint32_t *frameBufferUnaligned;
3133 SDL_Renderer *renderer;
3234 SDL_Texture *texture;
3335 SDL_Surface *iconSurface;
@@ -48,7 +50,6 @@ void endFPSCounter(void); · 14 unmodified lines
4850 void flipFrame(void);
4951 void showErrorMsgBox(const char *fmt, ...);
5052 void updateWindowTitle(bool forceUpdate);
51−void setPalettePreset(int16_t palettePreset);
5253 void handleScopesFromChQueue(chSyncData_t *chSyncData, uint8_t *scopeUpdateStatus);
5354 bool setupWindow(void);
5455 bool setupRenderer(void);
@@ -67,8 +68,8 @@ void hideSprite(uint8_t sprite); · 12 unmodified lines
6768 void handleRedrawing(void);
6869 void enterFullscreen(void);
6970 void leaveFullScreen(void);
70−void toggleFullScreen(void);
7171 void setWindowSizeFromConfig(bool updateRenderer);
7272 bool recreateTexture(void);
73+void toggleFullScreen(void);
7374 void setupWaitVBL(void);
7475 void waitVBL(void);
src/gfxdata/bmp/patternfonts.bmp+0−0

Binary file not shown.

vs2019_project/ft2-clone/ft2-clone.vcxproj+6−2
@@ -116,8 +116,9 @@ · 115 unmodified lines
116116 <OpenMPSupport>false</OpenMPSupport>
117117 <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
118118 <BufferSecurityCheck>false</BufferSecurityCheck>
119− <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
119+ <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
120120 <DebugInformationFormat>None</DebugInformationFormat>
121+ <LanguageStandard>stdcpplatest</LanguageStandard>
121122 </ClCompile>
122123 <Link>
123124 <AdditionalLibraryDirectories>
@@ -174,6 +175,7 @@ · 50 unmodified lines
174175 <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
175176 <BufferSecurityCheck>false</BufferSecurityCheck>
176177 <DebugInformationFormat>None</DebugInformationFormat>
178+ <LanguageStandard>stdcpplatest</LanguageStandard>
177179 </ClCompile>
178180 <Link>
179181 <AdditionalLibraryDirectories>
@@ -223,12 +225,13 @@ · 43 unmodified lines
223225 <PreprocessorDefinitions>__WINDOWS_MM__;_CRTDBG_MAP_ALLOC;DEBUG;_DEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;HAVE_M_PI;HAS_MIDI</PreprocessorDefinitions>
224226 <ExceptionHandling>false</ExceptionHandling>
225227 <FloatingPointModel>Fast</FloatingPointModel>
226− <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
228+ <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
227229 <ControlFlowGuard>false</ControlFlowGuard>
228230 <EnableParallelCodeGeneration>false</EnableParallelCodeGeneration>
229231 <CreateHotpatchableImage>false</CreateHotpatchableImage>
230232 <RuntimeTypeInfo>false</RuntimeTypeInfo>
231233 <OpenMPSupport>false</OpenMPSupport>
234+ <LanguageStandard>stdcpplatest</LanguageStandard>
232235 </ClCompile>
233236 <Link>
234237 <AdditionalLibraryDirectories>
@@ -276,6 +279,7 @@ · 41 unmodified lines
276279 <CreateHotpatchableImage>false</CreateHotpatchableImage>
277280 <RuntimeTypeInfo>false</RuntimeTypeInfo>
278281 <OpenMPSupport>false</OpenMPSupport>
282+ <LanguageStandard>stdcpplatest</LanguageStandard>
279283 </ClCompile>
280284 <Link>
281285 <AdditionalLibraryDirectories>

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