From 8950a756e1e732b610ec4e2c6b2f9cb7d1fe960d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olav=20S=C3=B8rensen?= Date: Thu, 30 Dec 2021 22:19:41 +0100 Subject: [PATCH] Pushed v1.38 code --- release/macos/protracker.ini | 19 ++ release/other/protracker.ini | 19 ++ release/win32/protracker.ini | 19 ++ release/win64/protracker.ini | 19 ++ src/gfx/pt2_gfx_editop.c | 23 ++ src/gfx/pt2_gfx_tracker.c | 25 ++ src/pt2_audio.c | 24 +- src/pt2_bmp.c | 38 +++- src/pt2_bmp.h | 8 + src/pt2_chordmaker.c | 93 ++++---- src/pt2_config.c | 18 ++ src/pt2_config.h | 3 +- src/pt2_edit.c | 46 ++-- src/pt2_header.h | 9 +- src/pt2_helpers.c | 38 ---- src/pt2_helpers.h | 7 - src/pt2_hpc.c | 121 ++++++++++ src/pt2_hpc.h | 23 ++ src/pt2_keyboard.c | 29 ++- src/pt2_main.c | 32 +-- src/pt2_module_loader.c | 25 +- src/pt2_module_saver.c | 12 +- src/pt2_mouse.c | 215 ++++++++++++------ src/pt2_pat2smp.c | 9 +- src/pt2_replayer.c | 29 +-- src/pt2_sample_loader.c | 196 ++++++++-------- src/pt2_sample_saver.c | 4 +- src/pt2_sampler.c | 187 ++++++++------- src/pt2_sampler.h | 3 +- src/pt2_sampling.c | 10 +- src/pt2_scopes.c | 51 +---- src/pt2_structs.h | 27 +-- src/pt2_tables.c | 14 +- src/pt2_textout.h | 7 +- src/pt2_visuals.c | 167 +++++++------- src/pt2_visuals.h | 4 +- vs2019_project/pt2-clone/protracker.ini | 19 ++ vs2019_project/pt2-clone/pt2-clone.vcxproj | 2 + .../pt2-clone/pt2-clone.vcxproj.filters | 4 + 39 files changed, 961 insertions(+), 637 deletions(-) create mode 100644 src/pt2_hpc.c create mode 100644 src/pt2_hpc.h diff --git a/release/macos/protracker.ini b/release/macos/protracker.ini index 05efeaa..9b0e8d6 100644 --- a/release/macos/protracker.ini +++ b/release/macos/protracker.ini @@ -11,6 +11,25 @@ ; ENTRY=VALUE (only strings can have spaces!) ; +[SAMPLE LENGTH LIMIT] +; Limit samples to 64kB (65534/$FFFE), like intended in ProTracker +; Syntax: TRUE or FALSE +; Default value: TRUE +; Comment: Setting it to FALSE will remove the 64kB (65534/$FFFE) sample +; length limit and support 128kB samples (131070/$1FFFE). +; Keep in mind that >64kB samples are not officially supported in most +; ProTracker trackers and replayers, and will often result in bugs. +; +; CAUTION: The 9xx command (Set Sample Offset) doesn't work at all if +; the sample length is above 65534/$FFFE. This is a known bug +; in all ProTracker versions. I am not fixing this bug as I +; want to keep the ProTracker 2.3D replayer quirks. +; +; Please do not change this setting unless you're aware of the problems +; you might face when creating >64k-sample PT MODs! +; +64K_LIMIT=TRUE + [VIDEO SETTINGS] ; Video scaling factor ; Syntax: 1X, 2X, 3X ... 9X diff --git a/release/other/protracker.ini b/release/other/protracker.ini index 05efeaa..9b0e8d6 100644 --- a/release/other/protracker.ini +++ b/release/other/protracker.ini @@ -11,6 +11,25 @@ ; ENTRY=VALUE (only strings can have spaces!) ; +[SAMPLE LENGTH LIMIT] +; Limit samples to 64kB (65534/$FFFE), like intended in ProTracker +; Syntax: TRUE or FALSE +; Default value: TRUE +; Comment: Setting it to FALSE will remove the 64kB (65534/$FFFE) sample +; length limit and support 128kB samples (131070/$1FFFE). +; Keep in mind that >64kB samples are not officially supported in most +; ProTracker trackers and replayers, and will often result in bugs. +; +; CAUTION: The 9xx command (Set Sample Offset) doesn't work at all if +; the sample length is above 65534/$FFFE. This is a known bug +; in all ProTracker versions. I am not fixing this bug as I +; want to keep the ProTracker 2.3D replayer quirks. +; +; Please do not change this setting unless you're aware of the problems +; you might face when creating >64k-sample PT MODs! +; +64K_LIMIT=TRUE + [VIDEO SETTINGS] ; Video scaling factor ; Syntax: 1X, 2X, 3X ... 9X diff --git a/release/win32/protracker.ini b/release/win32/protracker.ini index 05efeaa..9b0e8d6 100644 --- a/release/win32/protracker.ini +++ b/release/win32/protracker.ini @@ -11,6 +11,25 @@ ; ENTRY=VALUE (only strings can have spaces!) ; +[SAMPLE LENGTH LIMIT] +; Limit samples to 64kB (65534/$FFFE), like intended in ProTracker +; Syntax: TRUE or FALSE +; Default value: TRUE +; Comment: Setting it to FALSE will remove the 64kB (65534/$FFFE) sample +; length limit and support 128kB samples (131070/$1FFFE). +; Keep in mind that >64kB samples are not officially supported in most +; ProTracker trackers and replayers, and will often result in bugs. +; +; CAUTION: The 9xx command (Set Sample Offset) doesn't work at all if +; the sample length is above 65534/$FFFE. This is a known bug +; in all ProTracker versions. I am not fixing this bug as I +; want to keep the ProTracker 2.3D replayer quirks. +; +; Please do not change this setting unless you're aware of the problems +; you might face when creating >64k-sample PT MODs! +; +64K_LIMIT=TRUE + [VIDEO SETTINGS] ; Video scaling factor ; Syntax: 1X, 2X, 3X ... 9X diff --git a/release/win64/protracker.ini b/release/win64/protracker.ini index 05efeaa..9b0e8d6 100644 --- a/release/win64/protracker.ini +++ b/release/win64/protracker.ini @@ -11,6 +11,25 @@ ; ENTRY=VALUE (only strings can have spaces!) ; +[SAMPLE LENGTH LIMIT] +; Limit samples to 64kB (65534/$FFFE), like intended in ProTracker +; Syntax: TRUE or FALSE +; Default value: TRUE +; Comment: Setting it to FALSE will remove the 64kB (65534/$FFFE) sample +; length limit and support 128kB samples (131070/$1FFFE). +; Keep in mind that >64kB samples are not officially supported in most +; ProTracker trackers and replayers, and will often result in bugs. +; +; CAUTION: The 9xx command (Set Sample Offset) doesn't work at all if +; the sample length is above 65534/$FFFE. This is a known bug +; in all ProTracker versions. I am not fixing this bug as I +; want to keep the ProTracker 2.3D replayer quirks. +; +; Please do not change this setting unless you're aware of the problems +; you might face when creating >64k-sample PT MODs! +; +64K_LIMIT=TRUE + [VIDEO SETTINGS] ; Video scaling factor ; Syntax: 1X, 2X, 3X ... 9X diff --git a/src/gfx/pt2_gfx_editop.c b/src/gfx/pt2_gfx_editop.c index 477b478..36dea45 100644 --- a/src/gfx/pt2_gfx_editop.c +++ b/src/gfx/pt2_gfx_editop.c @@ -1,5 +1,28 @@ #include +// Final unpack length: 352 +// Decoded length: 88 (first four bytes of buffer) +const uint8_t fix128KPosPackedBMP[81] = +{ + 0x00,0x00,0x00,0x58,0xCC,0x05,0x55,0x95,0x55,0x6A,0xCC,0x04,0xAA,0xDA,0xAA,0x6A,0xCC,0x04,0xAA,0xDA, + 0xAA,0x65,0x56,0xA5,0x5A,0x95,0x5A,0xDA,0xAA,0x65,0xF5,0x97,0xD6,0x5F,0xFE,0xDA,0xAA,0x65,0x57,0xD7, + 0x97,0x95,0x6A,0xDA,0xAA,0x65,0xFF,0x97,0x97,0xAF,0x5A,0xDA,0xAA,0x65,0xEA,0xA5,0x5F,0x55,0x7E,0xDA, + 0xAA,0x6B,0xEA,0xAB,0xFE,0xBF,0xFA,0xDA,0xAA,0x6A,0xCC,0x04,0xAA,0xDA,0xAA,0xBF,0xCC,0x04,0xFF,0xEF, + 0xFF +}; + +// Final unpack length: 528 +// Decoded length: 132 (first four bytes of buffer) +const uint8_t fix128KChordPackedBMP[110] = +{ + 0x00,0x00,0x00,0x84,0xCC,0x08,0x55,0x65,0x55,0x55,0x6A,0xCC,0x07,0xAA,0xB6,0xAA,0xAA,0x6A,0xCC,0x07, + 0xAA,0xB6,0xAA,0xAA,0x6A,0xA9,0x6A,0xA5,0x55,0x96,0x96,0xAA,0xAA,0xB6,0xAA,0xAA,0x6A,0xA9,0x7A,0xA5, + 0xFF,0xD5,0x97,0xAA,0xAA,0xB6,0xAA,0xAA,0x6A,0xA9,0x7A,0xA5,0x5A,0x95,0x57,0xAA,0xAA,0xB6,0xAA,0xAA, + 0x6A,0xA9,0x7A,0xA5,0xFE,0x97,0x57,0x5A,0xAA,0xB6,0xAA,0xAA,0x6A,0xA9,0x55,0x65,0x55,0x97,0x97,0x5E, + 0xAA,0xB6,0xAA,0xAA,0x6A,0xAA,0xFF,0xFB,0xFF,0xEF,0xAF,0xBE,0xAA,0xB6,0xAA,0xAA,0x6A,0xCC,0x07,0xAA, + 0xB6,0xAA,0xAA,0xBF,0xCC,0x07,0xFF,0xFB,0xFF,0xFF +}; + // Final unpack length: 336 // Decoded length: 84 (first four bytes of buffer) const uint8_t editOpModeCharsPackedBMP[88] = diff --git a/src/gfx/pt2_gfx_tracker.c b/src/gfx/pt2_gfx_tracker.c index 37b8f1c..c77f3d0 100644 --- a/src/gfx/pt2_gfx_tracker.c +++ b/src/gfx/pt2_gfx_tracker.c @@ -1,5 +1,30 @@ #include +// Final unpack length: 2108 +// Decoded length: 527 (first four bytes of buffer) +const uint8_t tracker128KFixPackedBMP[363] = +{ + 0x00,0x00,0x02,0x0F,0xCC,0x0C,0xAA,0xFF,0xFF,0xEA,0xCC,0x0B,0xAA,0xAD,0x55,0x55,0xCC,0x0C,0xAA,0xDA, + 0xAA,0xAA,0xA9,0x6A,0xA5,0x55,0x96,0x96,0x95,0x59,0x55,0x65,0xA5,0xAA,0xAD,0xAA,0xAA,0xAA,0x97,0xAA, + 0x5F,0xFD,0x59,0x75,0xFF,0xED,0x7F,0x5E,0x5E,0xAA,0xDA,0xAA,0xAA,0xA9,0x7A,0xA5,0x56,0x95,0x57,0x5D, + 0x5A,0x97,0xA5,0x55,0xEA,0xAD,0xAA,0xAA,0xAA,0x97,0xAA,0x5F,0xF9,0x75,0x75,0xE5,0xE9,0x7A,0x5F,0x5E, + 0xAA,0xDA,0xAA,0xAA,0xA9,0x55,0x65,0x55,0x97,0x97,0x95,0x5E,0x97,0xA5,0xE5,0xEA,0xAD,0xAA,0xAA,0xAA, + 0xAF,0xFF,0xBF,0xFE,0xFA,0xFA,0xFF,0xEA,0xFA,0xBE,0xBE,0xAA,0xDA,0xCC,0x0D,0xAA,0xAD,0xCC,0x0E,0xAA, + 0xDA,0xCC,0x0D,0xAA,0xAE,0xFF,0xFF,0xCC,0x0C,0xAA,0xD5,0x55,0x5A,0xCC,0x0B,0xAA,0xAD,0xAA,0xAA,0xAA, + 0x95,0x5A,0x55,0x59,0x55,0xA5,0x55,0xA5,0x5A,0x55,0x5A,0xAA,0xDA,0xAA,0xAA,0xA9,0x7D,0x65,0xFF,0xD7, + 0xD6,0x5F,0xFD,0x7D,0x6B,0x5F,0xEA,0xAD,0xAA,0xAA,0xAA,0x95,0x5F,0x55,0x69,0x55,0xF5,0x56,0x95,0x57, + 0xA5,0xEA,0xAA,0xDA,0xAA,0xAA,0xA9,0x75,0xE5,0xFF,0x97,0xFE,0x5F,0xF9,0x7D,0x7A,0x5E,0xAA,0xAD,0xAA, + 0xAA,0xAA,0x97,0x96,0x55,0x59,0x7A,0xA5,0x55,0x97,0x97,0xA5,0xEA,0xAA,0xDA,0xAA,0xAA,0xAA,0xFA,0xFB, + 0xFF,0xEF,0xAA,0xBF,0xFE,0xFA,0xFA,0xBE,0xAA,0xAD,0xCC,0x0E,0xAA,0xDA,0xCC,0x0D,0xAA,0xAD,0xCC,0x0E, + 0xAA,0xEF,0xFF,0xFA,0xCC,0x0B,0xAA,0xAD,0x55,0x55,0xCC,0x0C,0xAA,0xDA,0xAA,0xAA,0xA9,0x55,0xA5,0x55, + 0x95,0x5A,0x5A,0xA9,0x55,0x65,0xA5,0xAA,0xAD,0xAA,0xAA,0xAA,0x97,0xD6,0x5F,0xFD,0x7D,0x65,0xEA,0x97, + 0xFF,0x56,0x5E,0xAA,0xDA,0xAA,0xAA,0xA9,0x55,0xF5,0x56,0x95,0x5F,0x5E,0xA9,0x55,0xA5,0x55,0xEA,0xAD, + 0xAA,0xAA,0xAA,0x97,0x5E,0x5F,0xF9,0x7F,0xE5,0xEA,0x97,0xFE,0x5D,0x5E,0xAA,0xDA,0xAA,0xAA,0xA9,0x79, + 0x65,0x55,0x97,0xAA,0x55,0x59,0x55,0x65,0xE5,0xEA,0xAD,0xAA,0xAA,0xAA,0xAF,0xAF,0xBF,0xFE,0xFA,0xAB, + 0xFF,0xEF,0xFF,0xBE,0xBE,0xAA,0xDA,0xCC,0x0D,0xAA,0xAD,0xCC,0x0E,0xAA,0xDA,0xAA,0xAF,0xCC,0x0B,0xFF, + 0xFE,0xFF,0xFF +}; + // Final unpack length: 81600 // Decoded length: 20400 (first four bytes of buffer) const uint8_t trackerFramePackedBMP[8486] = diff --git a/src/pt2_audio.c b/src/pt2_audio.c index 8283723..fa9288a 100644 --- a/src/pt2_audio.c +++ b/src/pt2_audio.c @@ -34,6 +34,7 @@ #include "pt2_rcfilter.h" #include "pt2_ledfilter.h" #include "pt2_downsample2x.h" +#include "pt2_hpc.h" #define STEREO_NORM_FACTOR 0.5 /* cumulative mid/side normalization factor (1/sqrt(2))*(1/sqrt(2)) */ @@ -129,14 +130,13 @@ static void calcAudioLatencyVars(int32_t audioBufferSize, int32_t audioFreq) const double dAudioLatencySecs = audioBufferSize / (double)audioFreq; - dFrac = modf(dAudioLatencySecs * editor.dPerfFreq, &dInt); + dFrac = modf(dAudioLatencySecs * hpcFreq.dFreq, &dInt); // integer part - audLatencyPerfValInt = (int32_t)dInt; + audLatencyPerfValInt = (uint32_t)dInt; // fractional part (scaled to 0..2^32-1) - dFrac *= UINT32_MAX+1.0; - audLatencyPerfValFrac = (uint32_t)dFrac; + audLatencyPerfValFrac = (uint32_t)((dFrac * (UINT32_MAX+1.0)) + 0.5); // rounded } void setSyncTickTimeLen(uint32_t timeLen, uint32_t timeLenFrac) @@ -181,7 +181,7 @@ void mixerUpdateLoops(void) // updates Paula loop (+ scopes) const moduleSample_t *s = &song->samples[editor.currSample]; paulaSetData(i, ch->n_start + s->loopStart); - paulaSetLength(i, s->loopLength >> 1); + paulaSetLength(i, (uint16_t)(s->loopLength >> 1)); } } @@ -335,7 +335,7 @@ void paulaSetData(int32_t ch, const int8_t *src) paulaVoice_t *v = &paula[ch]; if (src == NULL) - src = &song->sampleData[RESERVED_SAMPLE_OFFSET]; // 128K reserved sample + src = &song->sampleData[config.reservedSampleOffset]; // 128K reserved sample v->AUD_LC = src; @@ -362,7 +362,7 @@ void paulaStartDMA(int32_t ch) paulaVoice_t *v = &paula[ch]; if (v->AUD_LC == NULL) - v->AUD_LC = &song->sampleData[RESERVED_SAMPLE_OFFSET]; // 128K reserved sample + v->AUD_LC = &song->sampleData[config.reservedSampleOffset]; // 128K reserved sample /* This is not really accurate to what happens on Paula ** during DMA start, but it's good enough. @@ -801,8 +801,8 @@ void outputAudio(int16_t *target, int32_t numSamples) // render to sample (PAT2SMP) int32_t samplesTodo = numSamples; - if (editor.pat2SmpPos+samplesTodo > MAX_SAMPLE_LEN) - samplesTodo = MAX_SAMPLE_LEN-editor.pat2SmpPos; + if (editor.pat2SmpPos+samplesTodo > config.maxSampleLength) + samplesTodo = config.maxSampleLength-editor.pat2SmpPos; // mix channels (with 2x oversampling, PAT2SMP needs it) mixChannels(samplesTodo*2); @@ -821,7 +821,7 @@ void outputAudio(int16_t *target, int32_t numSamples) } editor.pat2SmpPos += samplesTodo; - if (editor.pat2SmpPos >= MAX_SAMPLE_LEN) + if (editor.pat2SmpPos >= config.maxSampleLength) { editor.smpRenderingDone = true; updateWindowTitle(MOD_IS_MODIFIED); @@ -1127,10 +1127,10 @@ static void generateTickLengthTable(bool vblankTimingFlag) // BPM -> Hz -> tick length for performance counter (syncing visuals to audio) double dTimeInt; - double dTimeFrac = modf(editor.dPerfFreq / dHz, &dTimeInt); + double dTimeFrac = modf(hpcFreq.dFreq / dHz, &dTimeInt); const int32_t timeInt = (int32_t)dTimeInt; - dTimeFrac = floor((UINT32_MAX+1.0) * dTimeFrac); // fractional part (scaled to 0..2^32-1) + dTimeFrac = floor((dTimeFrac * (UINT32_MAX+1.0)) + 0.5); // fractional part (scaled to 0..2^32-1) audio.tickLengthTable[bpm-32] = ((uint64_t)timeInt << 32) | (uint32_t)dTimeFrac; } diff --git a/src/pt2_bmp.c b/src/pt2_bmp.c index 885add4..035ba8d 100644 --- a/src/pt2_bmp.c +++ b/src/pt2_bmp.c @@ -20,6 +20,11 @@ uint32_t *samplerScreenBMP = NULL, *pat2SmpDialogBMP = NULL, *trackerFrameBMP uint32_t *yesNoDialogBMP = NULL, *bigYesNoDialogBMP = NULL, *sampleMonitorBMP = NULL; uint32_t *samplingBoxBMP = NULL; +// fix-bitmaps for 128K sample mode +uint32_t *fix128KTrackerBMP = NULL; +uint32_t *fix128KPosBMP = NULL; +uint32_t *fix128KChordBMP = NULL; + void createBitmaps(void) { uint8_t r8, g8, b8, r8_2, g8_2, b8_2; @@ -161,6 +166,9 @@ void createBitmaps(void) void freeBMPs(void) { + if (fix128KChordBMP != NULL) free(fix128KChordBMP); + if (fix128KPosBMP != NULL) free(fix128KPosBMP); + if (fix128KTrackerBMP != NULL) free(fix128KTrackerBMP); if (trackerFrameBMP != NULL) free(trackerFrameBMP); if (samplerScreenBMP != NULL) free(samplerScreenBMP); if (samplerVolumeBMP != NULL) free(samplerVolumeBMP); @@ -189,27 +197,29 @@ uint32_t *unpackBMP(const uint8_t *src, uint32_t packedLen) const uint8_t *packSrc; uint8_t *tmpBuffer, *packDst, byteIn; int16_t count; - uint32_t *dst, decodedLength, i; + uint32_t *dst; + + int32_t decodedLength, i; // RLE decode decodedLength = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; // 2-bit to 8-bit conversion - dst = (uint32_t *)malloc((decodedLength * 4) * sizeof (int32_t)); + dst = (uint32_t *)malloc(((decodedLength * 4) * sizeof (int32_t)) + 8); if (dst == NULL) return NULL; - tmpBuffer = (uint8_t *)malloc(decodedLength + 512); // some margin is needed, the packer is buggy + tmpBuffer = (uint8_t *)malloc(decodedLength + 128); // some margin is needed, the packer is buggy if (tmpBuffer == NULL) { free(dst); return NULL; } - packSrc = src + 4; + packSrc = src + 4; // skip "length" field packDst = tmpBuffer; - i = packedLen - 4; + i = packedLen - 4; // subtract "length" field while (i > 0) { byteIn = *packSrc++; @@ -256,6 +266,9 @@ uint32_t *unpackBMP(const uint8_t *src, uint32_t packedLen) bool unpackBMPs(void) { + fix128KChordBMP = unpackBMP(fix128KChordPackedBMP, sizeof (fix128KChordPackedBMP)); + fix128KPosBMP = unpackBMP(fix128KPosPackedBMP, sizeof (fix128KPosPackedBMP)); + fix128KTrackerBMP = unpackBMP(tracker128KFixPackedBMP, sizeof (tracker128KFixPackedBMP)); trackerFrameBMP = unpackBMP(trackerFramePackedBMP, sizeof (trackerFramePackedBMP)); samplerScreenBMP = unpackBMP(samplerScreenPackedBMP, sizeof (samplerScreenPackedBMP)); samplerVolumeBMP = unpackBMP(samplerVolumePackedBMP, sizeof (samplerVolumePackedBMP)); @@ -278,13 +291,14 @@ bool unpackBMPs(void) sampleMonitorBMP = unpackBMP(sampleMonitorPackedBMP, sizeof (sampleMonitorPackedBMP)); samplingBoxBMP = unpackBMP(samplingBoxPackedBMP, sizeof (samplingBoxPackedBMP)); - if (trackerFrameBMP == NULL || samplerScreenBMP == NULL || samplerVolumeBMP == NULL || - clearDialogBMP == NULL || diskOpScreenBMP == NULL || mod2wavBMP == NULL || - posEdBMP == NULL || spectrumVisualsBMP == NULL || yesNoDialogBMP == NULL || - editOpScreen1BMP == NULL || editOpScreen2BMP == NULL || editOpScreen3BMP == NULL || - editOpScreen4BMP == NULL || aboutScreenBMP == NULL || muteButtonsBMP == NULL || - editOpModeCharsBMP == NULL || samplerFiltersBMP == NULL || yesNoDialogBMP == NULL || - bigYesNoDialogBMP == NULL || sampleMonitorBMP == NULL || samplingBoxBMP == NULL) + if (fix128KTrackerBMP == NULL || fix128KPosBMP == NULL || fix128KChordBMP == NULL || + trackerFrameBMP == NULL || samplerScreenBMP == NULL || samplerVolumeBMP == NULL || + clearDialogBMP == NULL || diskOpScreenBMP == NULL || mod2wavBMP == NULL || + posEdBMP == NULL || spectrumVisualsBMP == NULL || yesNoDialogBMP == NULL || + editOpScreen1BMP == NULL || editOpScreen2BMP == NULL || editOpScreen3BMP == NULL || + editOpScreen4BMP == NULL || aboutScreenBMP == NULL || muteButtonsBMP == NULL || + editOpModeCharsBMP == NULL || samplerFiltersBMP == NULL || yesNoDialogBMP == NULL || + bigYesNoDialogBMP == NULL || sampleMonitorBMP == NULL || samplingBoxBMP == NULL) { showErrorMsgBox("Out of memory!"); return false; // BMPs are free'd in cleanUp() diff --git a/src/pt2_bmp.h b/src/pt2_bmp.h index e6051f3..1aec51c 100644 --- a/src/pt2_bmp.h +++ b/src/pt2_bmp.h @@ -21,6 +21,8 @@ extern const uint8_t fontBMP[6096]; extern const uint8_t aboutScreenPackedBMP[1408]; extern const uint8_t clearDialogPackedBMP[525]; extern const uint8_t diskOpScreenPackedBMP[1898]; +extern const uint8_t fix128KChordPackedBMP[110]; +extern const uint8_t fix128KPosPackedBMP[81]; extern const uint8_t editOpModeCharsPackedBMP[88]; extern const uint8_t editOpScreen1PackedBMP[1481]; extern const uint8_t editOpScreen2PackedBMP[1502]; @@ -34,6 +36,7 @@ extern const uint8_t samplerVolumePackedBMP[706]; extern const uint8_t samplerFiltersPackedBMP[933]; extern const uint8_t samplerScreenPackedBMP[3076]; extern const uint8_t spectrumVisualsPackedBMP[2217]; +extern const uint8_t tracker128KFixPackedBMP[363]; extern const uint8_t trackerFramePackedBMP[8486]; extern const uint8_t yesNoDialogPackedBMP[476]; extern const uint8_t bigYesNoDialogPackedBMP[472]; @@ -68,6 +71,11 @@ extern uint32_t *pat2SmpDialogBMP; extern uint32_t *sampleMonitorBMP; extern uint32_t *samplingBoxBMP; +// fix-bitmaps for 128K sample mode +extern uint32_t *fix128KTrackerBMP; +extern uint32_t *fix128KPosBMP; +extern uint32_t *fix128KChordBMP; + bool unpackBMPs(void); void createBitmaps(void); void freeBMPs(void); diff --git a/src/pt2_chordmaker.c b/src/pt2_chordmaker.c index de09a29..fdf1ebf 100644 --- a/src/pt2_chordmaker.c +++ b/src/pt2_chordmaker.c @@ -7,6 +7,7 @@ #include #include #include "pt2_header.h" +#include "pt2_config.h" #include "pt2_mouse.h" #include "pt2_textout.h" #include "pt2_visuals.h" @@ -111,10 +112,10 @@ void mixChordSample(void) sortNotes(); removeDuplicateNotes(); - ui.updateNote1Text = true; - ui.updateNote2Text = true; - ui.updateNote3Text = true; - ui.updateNote4Text = true; + ui.updateChordNote1Text = true; + ui.updateChordNote2Text = true; + ui.updateChordNote3Text = true; + ui.updateChordNote4Text = true; // setup some variables smpLoopStart = s->loopStart; @@ -151,14 +152,14 @@ void mixChordSample(void) editor.currSample = (int8_t)i; } - double *dMixData = (double *)calloc(MAX_SAMPLE_LEN*2, sizeof (double)); + double *dMixData = (double *)calloc(config.maxSampleLength*2, sizeof (double)); if (dMixData == NULL) { statusOutOfMemory(); return; } - s->length = smpLoopFlag ? MAX_SAMPLE_LEN : editor.chordLength; // if sample loops, set max length + s->length = smpLoopFlag ? config.maxSampleLength : editor.chordLength; // if sample loops, set max length s->loopLength = 2; s->loopStart = 0; s->text[21] = '!'; // chord sample indicator @@ -189,7 +190,7 @@ void mixChordSample(void) if (!v->active || v->dDelta == 0.0) continue; - for (int32_t j = 0; j < MAX_SAMPLE_LEN*2; j++) + for (int32_t j = 0; j < config.maxSampleLength*2; j++) { double dSmp = smpData[v->pos] * (1.0 / 128.0); @@ -247,8 +248,8 @@ void mixChordSample(void) free(dMixData); // clear unused sample data (if sample is not full already) - if (s->length < MAX_SAMPLE_LEN) - memset(&song->sampleData[s->offset + s->length], 0, MAX_SAMPLE_LEN - s->length); + if (s->length < config.maxSampleLength) + memset(&song->sampleData[s->offset + s->length], 0, config.maxSampleLength - s->length); // we're done @@ -294,14 +295,14 @@ void recalcChordLength(void) else { len = (s->length * periodTable[(37 * s->fineTune) + note]) / periodTable[24]; - if (len > MAX_SAMPLE_LEN) - len = MAX_SAMPLE_LEN; + if (len > config.maxSampleLength) + len = config.maxSampleLength; - editor.chordLength = len & 0xFFFE; + editor.chordLength = len & config.maxSampleLength; } if (ui.editOpScreenShown && ui.editOpScreen == 3) - ui.updateLengthText = true; + ui.updateChordLengthText = true; } void resetChord(void) @@ -313,10 +314,10 @@ void resetChord(void) editor.chordLengthMin = false; - ui.updateNote1Text = true; - ui.updateNote2Text = true; - ui.updateNote3Text = true; - ui.updateNote4Text = true; + ui.updateChordNote1Text = true; + ui.updateChordNote2Text = true; + ui.updateChordNote3Text = true; + ui.updateChordNote4Text = true; recalcChordLength(); } @@ -328,10 +329,10 @@ void undoChord(void) editor.note3 = editor.oldNote3; editor.note4 = editor.oldNote4; - ui.updateNote1Text = true; - ui.updateNote2Text = true; - ui.updateNote3Text = true; - ui.updateNote4Text = true; + ui.updateChordNote1Text = true; + ui.updateChordNote2Text = true; + ui.updateChordNote3Text = true; + ui.updateChordNote4Text = true; recalcChordLength(); } @@ -363,9 +364,9 @@ void setChordMajor(void) editor.note4 = 36; - ui.updateNote2Text = true; - ui.updateNote3Text = true; - ui.updateNote4Text = true; + ui.updateChordNote2Text = true; + ui.updateChordNote3Text = true; + ui.updateChordNote4Text = true; recalcChordLength(); } @@ -388,9 +389,9 @@ void setChordMinor(void) editor.note4 = 36; - ui.updateNote2Text = true; - ui.updateNote3Text = true; - ui.updateNote4Text = true; + ui.updateChordNote2Text = true; + ui.updateChordNote3Text = true; + ui.updateChordNote4Text = true; recalcChordLength(); } @@ -413,9 +414,9 @@ void setChordSus4(void) editor.note4 = 36; - ui.updateNote2Text = true; - ui.updateNote3Text = true; - ui.updateNote4Text = true; + ui.updateChordNote2Text = true; + ui.updateChordNote3Text = true; + ui.updateChordNote4Text = true; recalcChordLength(); } @@ -438,9 +439,9 @@ void setChordMajor6(void) if (editor.note3 >= 36) editor.note3 -= 12; if (editor.note4 >= 36) editor.note4 -= 12; - ui.updateNote2Text = true; - ui.updateNote3Text = true; - ui.updateNote4Text = true; + ui.updateChordNote2Text = true; + ui.updateChordNote3Text = true; + ui.updateChordNote4Text = true; recalcChordLength(); } @@ -463,9 +464,9 @@ void setChordMinor6(void) if (editor.note3 >= 36) editor.note3 -= 12; if (editor.note4 >= 36) editor.note4 -= 12; - ui.updateNote2Text = true; - ui.updateNote3Text = true; - ui.updateNote4Text = true; + ui.updateChordNote2Text = true; + ui.updateChordNote3Text = true; + ui.updateChordNote4Text = true; recalcChordLength(); } @@ -488,9 +489,9 @@ void setChordMajor7(void) if (editor.note3 >= 36) editor.note3 -= 12; if (editor.note4 >= 36) editor.note4 -= 12; - ui.updateNote2Text = true; - ui.updateNote3Text = true; - ui.updateNote4Text = true; + ui.updateChordNote2Text = true; + ui.updateChordNote3Text = true; + ui.updateChordNote4Text = true; recalcChordLength(); } @@ -513,9 +514,9 @@ void setChordMinor7(void) if (editor.note3 >= 36) editor.note3 -= 12; if (editor.note4 >= 36) editor.note4 -= 12; - ui.updateNote2Text = true; - ui.updateNote3Text = true; - ui.updateNote4Text = true; + ui.updateChordNote2Text = true; + ui.updateChordNote3Text = true; + ui.updateChordNote4Text = true; recalcChordLength(); } @@ -533,7 +534,7 @@ void selectChordNote1(void) pointerSetMode(POINTER_MODE_MSG1, NO_CARRY); } - ui.updateNote1Text = true; + ui.updateChordNote1Text = true; } void selectChordNote2(void) @@ -549,7 +550,7 @@ void selectChordNote2(void) pointerSetMode(POINTER_MODE_MSG1, NO_CARRY); } - ui.updateNote2Text = true; + ui.updateChordNote2Text = true; } void selectChordNote3(void) @@ -565,7 +566,7 @@ void selectChordNote3(void) pointerSetMode(POINTER_MODE_MSG1, NO_CARRY); } - ui.updateNote3Text = true; + ui.updateChordNote3Text = true; } void selectChordNote4(void) @@ -581,7 +582,7 @@ void selectChordNote4(void) pointerSetMode(POINTER_MODE_MSG1, NO_CARRY); } - ui.updateNote4Text = true; + ui.updateChordNote4Text = true; } void makeChord(void) diff --git a/src/pt2_config.c b/src/pt2_config.c index 9978408..680fc0e 100644 --- a/src/pt2_config.c +++ b/src/pt2_config.c @@ -68,6 +68,9 @@ void loadConfig(void) config.integerScaling = true; config.audioInputFrequency = 44100; + config.maxSampleLength = 65534; + config.reservedSampleOffset = (MOD_SAMPLES+1) * config.maxSampleLength; + #ifndef _WIN32 getcwd(oldCwd, PATH_MAX); #endif @@ -194,6 +197,21 @@ static bool loadProTrackerDotIni(FILE *f) continue; } + // 64K_LIMIT + else if (!_strnicmp(configLine, "64K_LIMIT=", 10)) + { + if (!_strnicmp(&configLine[10], "TRUE", 4)) + { + config.maxSampleLength = 65534; + config.reservedSampleOffset = (MOD_SAMPLES+1) * config.maxSampleLength; + } + else if (!_strnicmp(&configLine[10], "FALSE", 5)) + { + config.maxSampleLength = 131070; + config.reservedSampleOffset = (MOD_SAMPLES+1) * config.maxSampleLength; + } + } + // NO_DWNSMP_ON_SMP_LOAD (no dialog for 2x downsample after >22kHz sample load) else if (!_strnicmp(configLine, "NO_DWNSMP_ON_SMP_LOAD=", 22)) { diff --git a/src/pt2_config.h b/src/pt2_config.h index 852b75d..737cbb8 100644 --- a/src/pt2_config.h +++ b/src/pt2_config.h @@ -19,7 +19,8 @@ typedef struct config_t int8_t stereoSeparation, videoScaleFactor, accidental; uint8_t pixelFilter, filterModel; uint16_t quantizeValue; - uint32_t soundFrequency, soundBufferSize, audioInputFrequency; + int32_t maxSampleLength; + uint32_t soundFrequency, soundBufferSize, audioInputFrequency, reservedSampleOffset; } config_t; extern config_t config; // pt2_config.c diff --git a/src/pt2_edit.c b/src/pt2_edit.c index 5640afa..6b3a44c 100644 --- a/src/pt2_edit.c +++ b/src/pt2_edit.c @@ -240,7 +240,10 @@ void exitGetTextLine(bool updateValue) if (updateValue) { - editor.samplePos = ui.tmpDisp16; + editor.samplePos = ui.tmpDisp32; + if (editor.samplePos > config.maxSampleLength) + editor.samplePos = config.maxSampleLength; + if (editor.samplePos > song->samples[editor.currSample].length) editor.samplePos = song->samples[editor.currSample].length; @@ -499,7 +502,9 @@ void exitGetTextLine(bool updateValue) if (updateValue) { - tmp32 = ui.tmpDisp16 & 0xFFFE; // even'ify + tmp32 = ui.tmpDisp32 & ~1; // even'ify + if (tmp32 > config.maxSampleLength) + tmp32 = config.maxSampleLength; if (s->loopStart+s->loopLength > 2) { @@ -507,12 +512,12 @@ void exitGetTextLine(bool updateValue) tmp32 = s->loopStart+s->loopLength; } - tmp32 &= 0xFFFE; + tmp32 &= ~1; if (s->length != tmp32) { turnOffVoices(); - s->length = (uint16_t)tmp32; + s->length = tmp32; ui.updateCurrSampleLength = true; ui.updateSongSize = true; @@ -534,7 +539,9 @@ void exitGetTextLine(bool updateValue) if (updateValue) { - tmp32 = ui.tmpDisp16 & 0xFFFE; // even'ify + tmp32 = ui.tmpDisp32 & ~1; // even'ify + if (tmp32 > config.maxSampleLength) + tmp32 = config.maxSampleLength; if (s->length >= s->loopLength) { @@ -546,18 +553,18 @@ void exitGetTextLine(bool updateValue) tmp32 = 0; } - tmp32 &= 0xFFFE; + tmp32 &= ~1; if (s->loopStart != tmp32) { turnOffVoices(); - s->loopStart = (uint16_t)tmp32; + s->loopStart = tmp32; mixerUpdateLoops(); ui.updateCurrSampleRepeat = true; if (ui.editOpScreenShown && ui.editOpScreen == 3) - ui.updateLengthText = true; + ui.updateChordLengthText = true; if (ui.samplerScreenShown) setLoopSprites(); @@ -574,7 +581,9 @@ void exitGetTextLine(bool updateValue) if (updateValue) { - tmp32 = ui.tmpDisp16 & 0xFFFE; // even'ify + tmp32 = ui.tmpDisp32 & ~1; // even'ify + if (tmp32 > config.maxSampleLength) + tmp32 = config.maxSampleLength; if (s->length >= s->loopStart) { @@ -586,7 +595,7 @@ void exitGetTextLine(bool updateValue) tmp32 = 2; } - tmp32 &= 0xFFFE; + tmp32 &= ~1; if (tmp32 < 2) tmp32 = 2; @@ -594,12 +603,12 @@ void exitGetTextLine(bool updateValue) if (s->loopLength != tmp32) { turnOffVoices(); - s->loopLength = (uint16_t)tmp32; + s->loopLength = tmp32; mixerUpdateLoops(); ui.updateCurrSampleReplen = true; if (ui.editOpScreenShown && ui.editOpScreen == 3) - ui.updateLengthText = true; + ui.updateChordLengthText = true; if (ui.samplerScreenShown) setLoopSprites(); @@ -923,7 +932,7 @@ void handleSampleJamming(SDL_Scancode scancode) // used for the sampling feature const int8_t *n_start = &song->sampleData[s->offset]; const int8_t vol = 64; - const uint16_t n_length = s->length >> 1; + const uint16_t n_length = (uint16_t)(s->length >> 1); const uint16_t period = periodTable[((s->fineTune & 0xF) * 37) + noteVal]; paulaSetVolume(ch, vol); @@ -980,9 +989,9 @@ void jamAndPlaceSample(SDL_Scancode scancode, bool normalMode) chn->n_volume = s->volume; chn->n_period = tempPeriod; chn->n_start = &song->sampleData[s->offset]; - chn->n_length = (s->loopStart > 0) ? (s->loopStart + s->loopLength) >> 1 : s->length >> 1; + chn->n_length = (uint16_t)((s->loopStart > 0) ? (s->loopStart + s->loopLength) >> 1 : s->length >> 1); chn->n_loopstart = &song->sampleData[s->offset + s->loopStart]; - chn->n_replen = s->loopLength >> 1; + chn->n_replen = (uint16_t)(s->loopLength >> 1); if (chn->n_length == 0) chn->n_length = 1; @@ -1145,7 +1154,7 @@ void copySampleTrack(void) smpTo->loopLengthDisp = &smpTo->loopLength; // copy sample data - memcpy(&song->sampleData[smpTo->offset], &song->sampleData[smpFrom->offset], MAX_SAMPLE_LEN); + memcpy(&song->sampleData[smpTo->offset], &song->sampleData[smpFrom->offset], config.maxSampleLength); updateCurrSample(); ui.updateSongSize = true; @@ -1187,7 +1196,8 @@ void copySampleTrack(void) void exchSampleTrack(void) { int8_t smp; - uint32_t i, tmpOffset; + int32_t i; + uint32_t tmpOffset; moduleSample_t *smpFrom, *smpTo, smpTmp; note_t *noteSrc; @@ -1228,7 +1238,7 @@ void exchSampleTrack(void) smpTo->loopLengthDisp = &smpTo->loopLength; // swap sample data - for (i = 0; i < MAX_SAMPLE_LEN; i++) + for (i = 0; i < config.maxSampleLength; i++) { smp = song->sampleData[smpFrom->offset+i]; song->sampleData[smpFrom->offset+i] = song->sampleData[smpTo->offset+i]; diff --git a/src/pt2_header.h b/src/pt2_header.h index 0f08017..3a83292 100644 --- a/src/pt2_header.h +++ b/src/pt2_header.h @@ -14,7 +14,7 @@ #include "pt2_unicode.h" #include "pt2_palette.h" -#define PROG_VER_STR "1.37" +#define PROG_VER_STR "1.38" #ifdef _WIN32 #define DIR_DELIMITER '\\' @@ -38,7 +38,7 @@ /* Scopes are clocked at 64Hz instead of 60Hz to prevent the small +/- Hz ** interference from monitors not being exactly 60Hz (and unstable non-vsync mode). -** Sadly, the scopes might midly flicker from this in some cases. +** Sadly, the scopes might mildly flicker from this in some cases. */ #define SCOPE_HZ 64 @@ -50,11 +50,6 @@ #define MOD_ORDERS 128 #define MAX_PATTERNS 100 -#define MAX_SAMPLE_LEN 65534 - -// for NULL pointers -#define RESERVED_SAMPLE_OFFSET ((31+1) * MAX_SAMPLE_LEN) - #define AMIGA_VOICES 4 #define SCOPE_WIDTH 40 #define SCOPE_HEIGHT 33 diff --git a/src/pt2_helpers.c b/src/pt2_helpers.c index 99a8d97..eb802fc 100644 --- a/src/pt2_helpers.c +++ b/src/pt2_helpers.c @@ -21,44 +21,6 @@ #include "pt2_structs.h" #include "pt2_config.h" -// used for Windows usleep() implementation -#ifdef _WIN32 -static NTSTATUS (__stdcall *NtDelayExecution)(BOOL Alertable, PLARGE_INTEGER DelayInterval); -#endif - -// usleep() implementation for Windows -#ifdef _WIN32 -void usleep(uint32_t usec) -{ - LARGE_INTEGER lpDueTime; - - if (NtDelayExecution == NULL) - { - // NtDelayExecution() is not available (shouldn't happen), use regular sleep() - Sleep(usec / 1000); - } - else - { - // this prevents a 64-bit MUL (will not overflow with typical values anyway) - lpDueTime.HighPart = 0xFFFFFFFF; - lpDueTime.LowPart = (DWORD)(-10 * (int32_t)usec); - - NtDelayExecution(false, &lpDueTime); - } -} - -void setupWin32Usleep(void) -{ - NtDelayExecution = (NTSTATUS (__stdcall *)(BOOL, PLARGE_INTEGER))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtDelayExecution"); - timeBeginPeriod(0); // enter highest timer resolution -} - -void freeWin32Usleep(void) -{ - timeEndPeriod(0); // exit highest timer resolution -} -#endif - void showErrorMsgBox(const char *fmt, ...) { char strBuf[1024]; diff --git a/src/pt2_helpers.h b/src/pt2_helpers.h index 84c8b52..e76fb93 100644 --- a/src/pt2_helpers.h +++ b/src/pt2_helpers.h @@ -53,13 +53,6 @@ void showErrorMsgBox(const char *fmt, ...); -#ifdef _WIN32 -// Windows usleep() implementation -void usleep(uint32_t usec); -void setupWin32Usleep(void); -void freeWin32Usleep(void); -#endif - void sanitizeFilenameChar(char *chr); bool sampleNameIsEmpty(char *name); bool moduleNameIsEmpty(char *name); diff --git a/src/pt2_hpc.c b/src/pt2_hpc.c new file mode 100644 index 0000000..df4f3ba --- /dev/null +++ b/src/pt2_hpc.c @@ -0,0 +1,121 @@ +/* +** High Performance Counter delay routines +*/ + +#ifdef _WIN32 +#define WIN32_MEAN_AND_LEAN +#include +#else +#include +#endif +#include +#include +#include +#include "pt2_hpc.h" + +hpcFreq_t hpcFreq; + +#ifdef _WIN32 // Windows usleep() implementation + +static NTSTATUS (__stdcall *NtDelayExecution)(BOOL Alertable, PLARGE_INTEGER DelayInterval); +static NTSTATUS (__stdcall *NtQueryTimerResolution)(PULONG MinimumResolution, PULONG MaximumResolution, PULONG ActualResolution); +static NTSTATUS (__stdcall *NtSetTimerResolution)(ULONG DesiredResolution, BOOLEAN SetResolution, PULONG CurrentResolution); + +static void (*usleep)(int32_t usec); + +static void usleepGood(int32_t usec) +{ + LARGE_INTEGER delayInterval; + + // NtDelayExecution() delays in 100ns-units, and negative value = delay from current time + usec *= -10; + + delayInterval.HighPart = 0xFFFFFFFF; + delayInterval.LowPart = usec; + NtDelayExecution(false, &delayInterval); +} + +static void usleepWeak(int32_t usec) // fallback if no NtDelayExecution() +{ + Sleep((usec + 500) / 1000); +} + +static void windowsSetupUsleep(void) +{ + NtDelayExecution = (NTSTATUS (__stdcall *)(BOOL, PLARGE_INTEGER))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtDelayExecution"); + NtQueryTimerResolution = (NTSTATUS (__stdcall *)(PULONG, PULONG, PULONG))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryTimerResolution"); + NtSetTimerResolution = (NTSTATUS (__stdcall *)(ULONG, BOOLEAN, PULONG))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtSetTimerResolution"); + + usleep = (NtDelayExecution != NULL) ? usleepGood : usleepWeak; +} +#endif + +void hpc_Init(void) +{ +#ifdef _WIN32 + windowsSetupUsleep(); +#endif + hpcFreq.freq64 = SDL_GetPerformanceFrequency(); + hpcFreq.dFreq = (double)hpcFreq.freq64; + hpcFreq.dFreqMulMicro = (1000.0 * 1000.0) / hpcFreq.dFreq; +} + +void hpc_SetDurationInHz(hpc_t *hpc, const double dHz) +{ + const double dDuration = hpcFreq.dFreq / dHz; + + // break down duration into integer and frac parts + double dDurationInt; + double dDurationFrac = modf(dDuration, &dDurationInt); + + // set 64:32 values + hpc->duration64Int = (uint64_t)floor(dDurationInt); + hpc->duration64Frac = (uint64_t)((dDurationFrac * (UINT32_MAX+1.0)) + 0.5); // rounded +} + +void hpc_ResetEndTime(hpc_t *hpc) +{ + hpc->endTime64Int = SDL_GetPerformanceCounter() + hpc->duration64Int; + hpc->endTime64Frac = hpc->duration64Frac; +} + +void hpc_Wait(hpc_t *hpc) +{ +#ifdef _WIN32 // set resolution to 0.5ms (safest minium) - this is confirmed to improve NtDelayExecution() and Sleep() + ULONG originalTimerResolution, minRes, maxRes, curRes; + + if (NtQueryTimerResolution != NULL && NtSetTimerResolution != NULL) + { + if (!NtQueryTimerResolution(&minRes, &maxRes, &originalTimerResolution)) + { + if (originalTimerResolution != 5000 && maxRes <= 5000) + NtSetTimerResolution(5000, TRUE, &curRes); // set to 0.5ms (safest minimum) + } + } +#endif + + const uint64_t currTime64 = SDL_GetPerformanceCounter(); + if (currTime64 < hpc->endTime64Int) + { + uint64_t timeLeft64 = hpc->endTime64Int - currTime64; + if (timeLeft64 > INT32_MAX) + timeLeft64 = INT32_MAX; + + const int32_t timeLeft32 = (int32_t)timeLeft64; + + int32_t microSecsLeft = (int32_t)((timeLeft32 * hpcFreq.dFreqMulMicro) + 0.5); // rounded + if (microSecsLeft > 0) + usleep(microSecsLeft); + } + + // set next end time + + hpc->endTime64Int += hpc->duration64Int; + + hpc->endTime64Frac += hpc->duration64Frac; + if (hpc->endTime64Frac > UINT32_MAX) + { + hpc->endTime64Frac &= UINT32_MAX; + hpc->endTime64Int++; + } +} diff --git a/src/pt2_hpc.h b/src/pt2_hpc.h new file mode 100644 index 0000000..e1f1a29 --- /dev/null +++ b/src/pt2_hpc.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +typedef struct +{ + uint64_t freq64; + double dFreq, dFreqMulMicro; +} hpcFreq_t; + +typedef struct +{ + uint64_t duration64Int, duration64Frac; + uint64_t endTime64Int, endTime64Frac; +} hpc_t; + +extern hpcFreq_t hpcFreq; + +void hpc_Init(void); +void hpc_SetDurationInHz(hpc_t *hpc, double dHz); +void hpc_ResetEndTime(hpc_t *hpc); +void hpc_Wait(hpc_t *hpc); diff --git a/src/pt2_keyboard.c b/src/pt2_keyboard.c index 11f0085..f95c4e1 100644 --- a/src/pt2_keyboard.c +++ b/src/pt2_keyboard.c @@ -3586,22 +3586,22 @@ bool handleGeneralModes(SDL_Keycode keycode, SDL_Scancode scancode) if (ui.changingChordNote == 1) { editor.note1 = rawKey; - ui.updateNote1Text = true; + ui.updateChordNote1Text = true; } else if (ui.changingChordNote == 2) { editor.note2 = rawKey; - ui.updateNote2Text = true; + ui.updateChordNote2Text = true; } else if (ui.changingChordNote == 3) { editor.note3 = rawKey; - ui.updateNote3Text = true; + ui.updateChordNote3Text = true; } else if (ui.changingChordNote == 4) { editor.note4 = rawKey; - ui.updateNote4Text = true; + ui.updateChordNote4Text = true; } ui.changingChordNote = false; @@ -4094,15 +4094,28 @@ void handleTextEditInputChar(char textChar) else if (textChar <= 'f') textChar -= 'a'-10; - if (ui.numBits == 16) + if (ui.numBits == 17) { - *ui.numPtr16 &= ~(0xF000 >> (ui.dstPos << 2)); - *ui.numPtr16 |= (textChar << (12 - (ui.dstPos << 2))); + *ui.numPtr32 &= ~(0xF0000 >> (ui.dstPos << 2)); + *ui.numPtr32 |= textChar << (16 - (ui.dstPos << 2)); + } + else if (ui.numBits == 16) + { + if (ui.force32BitNumPtr) + { + *ui.numPtr32 &= ~(0xF000 >> (ui.dstPos << 2)); + *ui.numPtr32 |= textChar << (12 - (ui.dstPos << 2)); + } + else + { + *ui.numPtr16 &= ~(0xF000 >> (ui.dstPos << 2)); + *ui.numPtr16 |= textChar << (12 - (ui.dstPos << 2)); + } } else if (ui.numBits == 8) { *ui.numPtr8 &= ~(0xF0 >> (ui.dstPos << 2)); - *ui.numPtr8 |= (textChar << (4 - (ui.dstPos << 2))); + *ui.numPtr8 |= textChar << (4 - (ui.dstPos << 2)); } textMarkerMoveRight(); diff --git a/src/pt2_main.c b/src/pt2_main.c index a4cda81..09c9798 100644 --- a/src/pt2_main.c +++ b/src/pt2_main.c @@ -36,6 +36,7 @@ #include "pt2_bmp.h" #include "pt2_sync.h" #include "pt2_sampling.h" +#include "pt2_hpc.h" #define CRASH_TEXT "Oh no!\nThe ProTracker 2 clone has crashed...\n\nA backup .mod was hopefully " \ "saved to the current module directory.\n\nPlease report this bug if you can.\n" \ @@ -181,7 +182,6 @@ int main(int argc, char *argv[]) return 0; } - setupWin32Usleep(); disableWasapi(); // disable problematic WASAPI SDL2 audio driver on Windows (causes clicks/pops sometimes...) // 13.03.2020: This is still needed with SDL 2.0.12... #endif @@ -233,6 +233,9 @@ int main(int argc, char *argv[]) makeSureDirIsProgramDir(); #endif + hpc_Init(); + hpc_SetDurationInHz(&video.vblankHpc, VBLANK_HZ); + if (!initializeVars() || !initKaiserTable()) { cleanUp(); @@ -261,8 +264,6 @@ int main(int argc, char *argv[]) SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); #endif - setupPerfFreq(); - if (!setupAudio() || !unpackBMPs()) { cleanUp(); @@ -329,7 +330,7 @@ int main(int argc, char *argv[]) SDL_EventState(SDL_DROPFILE, SDL_ENABLE); - setupWaitVBL(); + hpc_ResetEndTime(&video.vblankHpc); while (editor.programRunning) { sinkVisualizerBars(); @@ -370,20 +371,11 @@ static void handleInput(void) else if (event.window.event == SDL_WINDOWEVENT_SHOWN) video.windowHidden = false; - if (video.vsync60HzPresent) - { - /* if we minimize the window and vsync is present, vsync is temporarily turned off. - ** recalc waitVBL() vars so that it can sleep properly in said mode. - */ - if (event.window.event == SDL_WINDOWEVENT_MINIMIZED || - event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) - { - setupWaitVBL(); - } - } + // reset vblank end time if we minimize window + if (event.window.event == SDL_WINDOWEVENT_MINIMIZED || event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) + hpc_ResetEndTime(&video.vblankHpc); } - #ifdef _WIN32 handleSysMsg(event); #endif @@ -485,13 +477,10 @@ static bool initializeVars(void) config.defModulesDir = (char *)calloc(PATH_MAX + 1, sizeof (char)); config.defSamplesDir = (char *)calloc(PATH_MAX + 1, sizeof (char)); - editor.tempSample = (int8_t *)calloc(MAX_SAMPLE_LEN, 1); + editor.tempSample = (int8_t *)calloc(131070, 1); - if (config.defModulesDir == NULL || config.defSamplesDir == NULL || - editor.tempSample == NULL) - { + if (config.defModulesDir == NULL || config.defSamplesDir == NULL || editor.tempSample == NULL) goto oom; - } turnOffVoices(); @@ -906,7 +895,6 @@ static void cleanUp(void) // never call this inside the main loop! if (editor.tempSample != NULL) free(editor.tempSample); #ifdef _WIN32 - freeWin32Usleep(); #ifndef _DEBUG UnhookWindowsHookEx(g_hKeyboardHook); #endif diff --git a/src/pt2_module_loader.c b/src/pt2_module_loader.c index bda30c4..3decf12 100644 --- a/src/pt2_module_loader.c +++ b/src/pt2_module_loader.c @@ -17,6 +17,7 @@ #include #include "pt2_mouse.h" #include "pt2_header.h" +#include "pt2_config.h" #include "pt2_sampler.h" #include "pt2_textout.h" #include "pt2_audio.h" @@ -312,7 +313,7 @@ module_t *modLoad(UNICHAR *fileName) } realSampleLengths[i] = ((mgetc(m) << 8) | mgetc(m)) * 2; - s->length = (realSampleLengths[i] > MAX_SAMPLE_LEN) ? MAX_SAMPLE_LEN : (uint16_t)realSampleLengths[i]; + s->length = (realSampleLengths[i] > config.maxSampleLength) ? config.maxSampleLength : realSampleLengths[i]; /* Only late versions of Ultimate SoundTracker could have samples larger than 9999 bytes. ** If found, we know for sure that this is a late STK module. @@ -338,16 +339,16 @@ module_t *modLoad(UNICHAR *fileName) if (loopLength < 2) loopLength = 2; // fixes empty samples in .MODs saved from FT2 - // we don't support samples bigger than 65534 bytes, disable uncompatible loops - if (loopStart > MAX_SAMPLE_LEN || loopStart+loopLength > MAX_SAMPLE_LEN) + // we don't support samples bigger than 65534 (or 128kB) bytes, disable uncompatible loops + if (loopStart > config.maxSampleLength || loopStart+loopLength > config.maxSampleLength) { s->loopStart = 0; s->loopLength = 2; } else { - s->loopStart = (uint16_t)loopStart; - s->loopLength = (uint16_t)loopLength; + s->loopStart = loopStart; + s->loopLength = loopLength; } // in The Ultimate SoundTracker, sample loop start is in bytes, not words @@ -596,7 +597,7 @@ module_t *modLoad(UNICHAR *fileName) // set sample data offsets (sample data = one huge buffer to rule them all) for (i = 0; i < MOD_SAMPLES; i++) - newMod->samples[i].offset = MAX_SAMPLE_LEN * i; + newMod->samples[i].offset = config.maxSampleLength * i; // load sample data numSamples = (modFormat == FORMAT_STK) ? 15 : 31; @@ -617,11 +618,11 @@ module_t *modLoad(UNICHAR *fileName) ** so skip overflown data in .MOD file if present. */ int32_t bytesToSkip = 0; - if (realSampleLengths[i] > MAX_SAMPLE_LEN) - bytesToSkip = realSampleLengths[i] - MAX_SAMPLE_LEN; + if (realSampleLengths[i] > config.maxSampleLength) + bytesToSkip = realSampleLengths[i] - config.maxSampleLength; // For Ultimate SoundTracker modules, don't load sample data after loop end - uint16_t loopEnd = s->loopStart + s->loopLength; + int32_t loopEnd = s->loopStart + s->loopLength; if (modFormat == FORMAT_STK && loopEnd > 2 && s->length > loopEnd) { bytesToSkip += s->length-loopEnd; @@ -643,9 +644,9 @@ module_t *modLoad(UNICHAR *fileName) if (s->length > 0 && s->loopLength > 2 && s->loopStart+s->loopLength > s->length) { loopOverflowVal = (s->loopStart + s->loopLength) - s->length; - if (s->length+loopOverflowVal <= MAX_SAMPLE_LEN) + if (s->length+loopOverflowVal <= config.maxSampleLength) { - s->length = (uint16_t)(s->length + loopOverflowVal); // this is safe, we're allocating 65534 bytes per sample slot + s->length += loopOverflowVal; // this is safe, we're allocating 65534 bytes per sample slot } else { @@ -1205,7 +1206,7 @@ module_t *createEmptyMod(void) moduleSample_t *s = newMod->samples; for (i = 0; i < MOD_SAMPLES; i++, s++) { - s->offset = MAX_SAMPLE_LEN * i; + s->offset = config.maxSampleLength * i; s->loopLength = 2; // setup GUI text pointers diff --git a/src/pt2_module_saver.c b/src/pt2_module_saver.c index 06c1cc0..285ad25 100644 --- a/src/pt2_module_saver.c +++ b/src/pt2_module_saver.c @@ -42,8 +42,8 @@ bool modSave(char *fileName) fputc(s->fineTune & 0xF, f); fputc(((uint8_t)s->volume > 64) ? 64 : s->volume, f); - uint16_t loopStart = s->loopStart; - uint16_t loopLength = s->loopLength; + int32_t loopStart = s->loopStart; + int32_t loopLength = s->loopLength; if (loopLength < 2) loopLength = 2; @@ -54,11 +54,11 @@ bool modSave(char *fileName) loopLength = 2; } - loopLength = SWAP16(loopLength >> 1); - loopStart = SWAP16(loopStart >> 1); + uint16_t loopStart16 = SWAP16(loopStart >> 1); + uint16_t loopLength16 = SWAP16(loopLength >> 1); - fwrite(&loopStart, sizeof (int16_t), 1, f); - fwrite(&loopLength, sizeof (int16_t), 1, f); + fwrite(&loopStart16, sizeof (int16_t), 1, f); + fwrite(&loopLength16, sizeof (int16_t), 1, f); } fputc((uint8_t)song->header.numOrders, f); diff --git a/src/pt2_mouse.c b/src/pt2_mouse.c index f8a316a..fc68c52 100644 --- a/src/pt2_mouse.c +++ b/src/pt2_mouse.c @@ -457,7 +457,7 @@ void edNote1UpButton(void) if (editor.note1 > 36) editor.note1 = 36; - ui.updateNote1Text = true; + ui.updateChordNote1Text = true; recalcChordLength(); } @@ -471,7 +471,7 @@ void edNote1DownButton(void) if (editor.note1 < 0) editor.note1 = 0; - ui.updateNote1Text = true; + ui.updateChordNote1Text = true; recalcChordLength(); } @@ -485,7 +485,7 @@ void edNote2UpButton(void) if (editor.note2 > 36) editor.note2 = 36; - ui.updateNote2Text = true; + ui.updateChordNote2Text = true; recalcChordLength(); } @@ -499,7 +499,7 @@ void edNote2DownButton(void) if (editor.note2 < 0) editor.note2 = 0; - ui.updateNote2Text = true; + ui.updateChordNote2Text = true; recalcChordLength(); } @@ -513,7 +513,7 @@ void edNote3UpButton(void) if (editor.note3 > 36) editor.note3 = 36; - ui.updateNote3Text = true; + ui.updateChordNote3Text = true; recalcChordLength(); } @@ -527,7 +527,7 @@ void edNote3DownButton(void) if (editor.note3 < 0) editor.note3 = 0; - ui.updateNote3Text = true; + ui.updateChordNote3Text = true; recalcChordLength(); } @@ -541,7 +541,7 @@ void edNote4UpButton(void) if (editor.note4 > 36) editor.note4 = 36; - ui.updateNote4Text = true; + ui.updateChordNote4Text = true; recalcChordLength(); } @@ -555,7 +555,7 @@ void edNote4DownButton(void) if (editor.note4 < 0) editor.note4 = 0; - ui.updateNote4Text = true; + ui.updateChordNote4Text = true; recalcChordLength(); } @@ -565,34 +565,34 @@ void edPosUpButton(bool fast) { if (fast) { - if (editor.samplePos <= 0xFFFF-64) + if (editor.samplePos <= config.maxSampleLength-64) editor.samplePos += 64; else - editor.samplePos = 0xFFFF; + editor.samplePos = config.maxSampleLength; } else { - if (editor.samplePos <= 0xFFFF-16) + if (editor.samplePos <= config.maxSampleLength-16) editor.samplePos += 16; else - editor.samplePos = 0xFFFF; + editor.samplePos = config.maxSampleLength; } } else { if (fast) { - if (editor.samplePos <= 0xFFFF-64) + if (editor.samplePos <= config.maxSampleLength-64) editor.samplePos += 64; else - editor.samplePos = 0xFFFF; + editor.samplePos = config.maxSampleLength; } else { - if (editor.samplePos < 0xFFFF) + if (editor.samplePos < config.maxSampleLength) editor.samplePos++; else - editor.samplePos = 0xFFFF; + editor.samplePos = config.maxSampleLength; } } @@ -794,7 +794,7 @@ void sampleLengthUpButton(bool fast) { int32_t val; - if (song->samples[editor.currSample].length == MAX_SAMPLE_LEN) + if (song->samples[editor.currSample].length == config.maxSampleLength) return; val = song->samples[editor.currSample].length; @@ -813,10 +813,10 @@ void sampleLengthUpButton(bool fast) val += 2; } - if (val > MAX_SAMPLE_LEN) - val = MAX_SAMPLE_LEN; + if (val > config.maxSampleLength) + val = config.maxSampleLength; - song->samples[editor.currSample].length = (uint16_t)val; + song->samples[editor.currSample].length = val; ui.updateCurrSampleLength = true; } @@ -862,7 +862,7 @@ void sampleLengthDownButton(bool fast) val = s->loopStart+s->loopLength; } - s->length = (uint16_t)val; + s->length = val; ui.updateCurrSampleLength = true; } @@ -899,7 +899,7 @@ void sampleRepeatUpButton(bool fast) if (val > len-loopLen) val = len-loopLen; - song->samples[editor.currSample].loopStart = (uint16_t)val; + song->samples[editor.currSample].loopStart = val; ui.updateCurrSampleRepeat = true; mixerUpdateLoops(); @@ -908,7 +908,7 @@ void sampleRepeatUpButton(bool fast) setLoopSprites(); if (ui.editOpScreenShown && ui.editOpScreen == 3) // sample chord editor - ui.updateLengthText = true; + ui.updateChordLengthText = true; } void sampleRepeatDownButton(bool fast) @@ -942,7 +942,7 @@ void sampleRepeatDownButton(bool fast) if (val < 0) val = 0; - song->samples[editor.currSample].loopStart = (uint16_t)val; + song->samples[editor.currSample].loopStart = val; ui.updateCurrSampleRepeat = true; mixerUpdateLoops(); @@ -951,7 +951,7 @@ void sampleRepeatDownButton(bool fast) setLoopSprites(); if (ui.editOpScreenShown && ui.editOpScreen == 3) // sample chord editor - ui.updateLengthText = true; + ui.updateChordLengthText = true; } void sampleRepeatLengthUpButton(bool fast) @@ -986,7 +986,7 @@ void sampleRepeatLengthUpButton(bool fast) if (val > len-loopStart) val = len-loopStart; - song->samples[editor.currSample].loopLength = (uint16_t)val; + song->samples[editor.currSample].loopLength = val; ui.updateCurrSampleReplen = true; mixerUpdateLoops(); @@ -995,7 +995,7 @@ void sampleRepeatLengthUpButton(bool fast) setLoopSprites(); if (ui.editOpScreenShown && ui.editOpScreen == 3) // sample chord editor - ui.updateLengthText = true; + ui.updateChordLengthText = true; } void sampleRepeatLengthDownButton(bool fast) @@ -1029,7 +1029,7 @@ void sampleRepeatLengthDownButton(bool fast) if (val < 2) val = 2; - song->samples[editor.currSample].loopLength = (uint16_t)val; + song->samples[editor.currSample].loopLength = val; ui.updateCurrSampleReplen = true; mixerUpdateLoops(); @@ -1038,7 +1038,7 @@ void sampleRepeatLengthDownButton(bool fast) setLoopSprites(); if (ui.editOpScreenShown && ui.editOpScreen == 3) // sample chord editor - ui.updateLengthText = true; + ui.updateChordLengthText = true; } void tempoUpButton(void) @@ -1721,7 +1721,7 @@ void handleSamplerFiltersBox(void) } else { - memcpy(&song->sampleData[s->offset], editor.tempSample, MAX_SAMPLE_LEN); + memcpy(&song->sampleData[s->offset], editor.tempSample, config.maxSampleLength); redrawSample(); updateWindowTitle(MOD_IS_MODIFIED); renderSamplerFiltersBox(); @@ -2270,10 +2270,10 @@ bool handleLeftMouseButton(void) ui.changingDrumPadNote = false; ui.updateResampleNote = true; - ui.updateNote1Text = true; - ui.updateNote2Text = true; - ui.updateNote3Text = true; - ui.updateNote4Text = true; + ui.updateChordNote1Text = true; + ui.updateChordNote2Text = true; + ui.updateChordNote3Text = true; + ui.updateChordNote4Text = true; setPrevStatusMessage(); pointerSetPreviousMode(); @@ -2402,6 +2402,8 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju int32_t smp32, j, modPos, oldVal, tmp32; double dSmp; moduleSample_t *s; + + ui.force32BitNumPtr = false; switch (button) { @@ -2656,14 +2658,14 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju break; } - ptr8_1 = (int8_t *)malloc(MAX_SAMPLE_LEN); + ptr8_1 = (int8_t *)malloc(config.maxSampleLength); if (ptr8_1 == NULL) { statusOutOfMemory(); return true; } - memcpy(ptr8_1, &song->sampleData[s->offset], MAX_SAMPLE_LEN); + memcpy(ptr8_1, &song->sampleData[s->offset], config.maxSampleLength); ptr8_2 = &song->sampleData[s->offset+editor.samplePos]; ptr8_3 = &song->sampleData[s->offset+s->length-1]; @@ -2791,6 +2793,9 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju case PTB_EO_POS_NUM: { + if (config.maxSampleLength == 65534 && mouse.x < 244) // yuck! + break; + if (mouse.rightButtonPressed) { editor.samplePos = 0; @@ -2798,12 +2803,25 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju } else { - ui.tmpDisp16 = editor.samplePos; - editor.samplePosDisp = &ui.tmpDisp16; - ui.numPtr16 = &ui.tmpDisp16; - ui.numLen = 4; - ui.numBits = 16; - ui.editTextPos = 2391; // (y * 40) + x + ui.force32BitNumPtr = true; + + ui.tmpDisp32 = editor.samplePos; + editor.samplePosDisp = &ui.tmpDisp32; + ui.numPtr32 = &ui.tmpDisp32; + + if (config.maxSampleLength == 65534) + { + ui.numLen = 4; + ui.numBits = 16; + ui.editTextPos = 2391; // (y * 40) + x + } + else + { + ui.numLen = 5; + ui.numBits = 17; + ui.editTextPos = 2390; // (y * 40) + x + } + getNumLine(TEXT_EDIT_HEX, PTB_EO_POS_NUM); } } @@ -2891,7 +2909,7 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju ptr8_1 = &song->sampleData[s->offset]; - ptr8_3 = (int8_t *)malloc(MAX_SAMPLE_LEN); + ptr8_3 = (int8_t *)malloc(config.maxSampleLength); if (ptr8_3 == NULL) { statusOutOfMemory(); @@ -2900,7 +2918,7 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju ptr8_2 = ptr8_3; - memcpy(ptr8_2, ptr8_1, MAX_SAMPLE_LEN); + memcpy(ptr8_2, ptr8_1, config.maxSampleLength); editor.modulateOffset = 0; editor.modulatePos = 0; @@ -3047,8 +3065,8 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju turnOffVoices(); - memcpy(&song->sampleData[s->offset], &song->sampleData[s->offset + editor.samplePos], MAX_SAMPLE_LEN - editor.samplePos); - memset(&song->sampleData[s->offset + (MAX_SAMPLE_LEN - editor.samplePos)], 0, editor.samplePos); + memcpy(&song->sampleData[s->offset], &song->sampleData[s->offset + editor.samplePos], config.maxSampleLength - editor.samplePos); + memset(&song->sampleData[s->offset + (config.maxSampleLength - editor.samplePos)], 0, editor.samplePos); if (editor.samplePos > s->loopStart) { @@ -3057,10 +3075,10 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju } else { - s->loopStart = (s->loopStart - editor.samplePos) & 0xFFFE; + s->loopStart = (s->loopStart - editor.samplePos) & config.maxSampleLength; } - s->length = (s->length - editor.samplePos) & 0xFFFE; + s->length = (s->length - editor.samplePos) & config.maxSampleLength; editor.samplePos = 0; fixSampleBeep(s); @@ -3277,7 +3295,16 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju case PTB_EO_NOTE4_DOWN: edNote4DownButton(); break; case PTB_EO_RESET: resetChord(); break; case PTB_EO_UNDO: undoChord(); break; - case PTB_EO_LENGTH: toggleChordLength(); break; + + case PTB_EO_LENGTH: + { + if (config.maxSampleLength != 65534 && mouse.x > 157) // yuck! + break; + + toggleChordLength(); + } + break; + case PTB_EO_MAJOR: setChordMajor(); break; case PTB_EO_MINOR: setChordMinor(); break; case PTB_EO_SUS4: setChordSus4(); break; @@ -3515,6 +3542,9 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju case PTB_SLENGTHS: { + if (config.maxSampleLength == 65534 && mouse.x < 62) // yuck! + break; + if (editor.sampleZero) { statusNotSampleZero(); @@ -3545,12 +3575,25 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju } else { - ui.tmpDisp16 = song->samples[editor.currSample].length; - song->samples[editor.currSample].lengthDisp = &ui.tmpDisp16; - ui.numPtr16 = &ui.tmpDisp16; - ui.numLen = 4; - ui.numBits = 16; - ui.editTextPos = 2808; // (y * 40) + x + ui.force32BitNumPtr = true; + + ui.tmpDisp32 = song->samples[editor.currSample].length; + song->samples[editor.currSample].lengthDisp = &ui.tmpDisp32; + ui.numPtr32 = &ui.tmpDisp32; + + if (config.maxSampleLength == 65534) + { + ui.numLen = 4; + ui.numBits = 16; + ui.editTextPos = 2808; // (y * 40) + x + } + else + { + ui.numLen = 5; + ui.numBits = 17; + ui.editTextPos = 2807; // (y * 40) + x + } + getNumLine(TEXT_EDIT_HEX, PTB_SLENGTHS); } } @@ -3558,6 +3601,9 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju case PTB_SREPEATS: { + if (config.maxSampleLength == 65534 && mouse.x < 62) // yuck! + break; + if (editor.sampleZero) { statusNotSampleZero(); @@ -3581,7 +3627,7 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju ui.updateCurrSampleRepeat = true; if (ui.editOpScreenShown && ui.editOpScreen == 3) - ui.updateLengthText = true; + ui.updateChordLengthText = true; if (ui.samplerScreenShown) setLoopSprites(); @@ -3591,12 +3637,25 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju } else { - ui.tmpDisp16 = song->samples[editor.currSample].loopStart; - song->samples[editor.currSample].loopStartDisp = &ui.tmpDisp16; - ui.numPtr16 = &ui.tmpDisp16; - ui.numLen = 4; - ui.numBits = 16; - ui.editTextPos = 3248; // (y * 40) + x + ui.force32BitNumPtr = true; + + ui.tmpDisp32 = song->samples[editor.currSample].loopStart; + song->samples[editor.currSample].loopStartDisp = &ui.tmpDisp32; + ui.numPtr32 = &ui.tmpDisp32; + + if (config.maxSampleLength == 65534) + { + ui.numLen = 4; + ui.numBits = 16; + ui.editTextPos = 3248; // (y * 40) + x + } + else + { + ui.numLen = 5; + ui.numBits = 17; + ui.editTextPos = 3247; // (y * 40) + x + } + getNumLine(TEXT_EDIT_HEX, PTB_SREPEATS); } } @@ -3604,6 +3663,9 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju case PTB_SREPLENS: { + if (config.maxSampleLength == 65534 && mouse.x < 62) // yuck! + break; + if (editor.sampleZero) { statusNotSampleZero(); @@ -3630,7 +3692,7 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju ui.updateCurrSampleReplen = true; if (ui.editOpScreenShown && ui.editOpScreen == 3) - ui.updateLengthText = true; + ui.updateChordLengthText = true; if (ui.samplerScreenShown) setLoopSprites(); @@ -3640,12 +3702,25 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju } else { - ui.tmpDisp16 = song->samples[editor.currSample].loopLength; - song->samples[editor.currSample].loopLengthDisp = &ui.tmpDisp16; - ui.numPtr16 = &ui.tmpDisp16; - ui.numLen = 4; - ui.numBits = 16; - ui.editTextPos = 3688; // (y * 40) + x + ui.force32BitNumPtr = true; + + ui.tmpDisp32 = song->samples[editor.currSample].loopLength; + song->samples[editor.currSample].loopLengthDisp = &ui.tmpDisp32; + ui.numPtr32 = &ui.tmpDisp32; + + if (config.maxSampleLength == 0xFFFE) + { + ui.numLen = 4; + ui.numBits = 16; + ui.editTextPos = 3688; // (y * 40) + x + } + else + { + ui.numLen = 5; + ui.numBits = 17; + ui.editTextPos = 3687; // (y * 40) + x + } + getNumLine(TEXT_EDIT_HEX, PTB_SREPLENS); } } @@ -4402,7 +4477,7 @@ static bool handleGUIButtons(int32_t button) // are you prepared to enter the ju case PTB_SLENGTHU: { - if (!editor.sampleZero && song->samples[editor.currSample].length < MAX_SAMPLE_LEN) + if (!editor.sampleZero && song->samples[editor.currSample].length < config.maxSampleLength) { sampleLengthUpButton(INCREMENT_SLOW); updateWindowTitle(MOD_IS_MODIFIED); diff --git a/src/pt2_pat2smp.c b/src/pt2_pat2smp.c index 9b5d4cc..00447cb 100644 --- a/src/pt2_pat2smp.c +++ b/src/pt2_pat2smp.c @@ -6,6 +6,7 @@ #include #include #include "pt2_header.h" +#include "pt2_config.h" #include "pt2_helpers.h" #include "pt2_visuals.h" #include "pt2_mouse.h" @@ -31,7 +32,7 @@ void doPat2Smp(void) return; } - editor.dPat2SmpBuf = (double *)malloc(MAX_SAMPLE_LEN * sizeof (double)); + editor.dPat2SmpBuf = (double *)malloc(config.maxSampleLength * sizeof (double)); if (editor.dPat2SmpBuf == NULL) { statusOutOfMemory(); @@ -101,8 +102,8 @@ void doPat2Smp(void) free(editor.dPat2SmpBuf); // clear the rest of the sample (if not full) - if (renderLength < MAX_SAMPLE_LEN) - memset(&song->sampleData[s->offset+renderLength], 0, MAX_SAMPLE_LEN - renderLength); + if (renderLength < config.maxSampleLength) + memset(&song->sampleData[s->offset+renderLength], 0, config.maxSampleLength - renderLength); if (editor.pat2SmpHQ) { @@ -115,7 +116,7 @@ void doPat2Smp(void) s->fineTune = 0; } - s->length = (uint16_t)renderLength; + s->length = renderLength; s->volume = 64; s->loopStart = 0; s->loopLength = 2; diff --git a/src/pt2_replayer.c b/src/pt2_replayer.c index 424a53d..dd2e02f 100644 --- a/src/pt2_replayer.c +++ b/src/pt2_replayer.c @@ -37,21 +37,10 @@ static const uint8_t funkTable[16] = // EFx (FunkRepeat/InvertLoop) int8_t *allocMemForAllSamples(void) { - /* Allocate memory for all sample data blocks. - ** - ** We need three extra sample slots: - ** The 1st is extra safety padding since setting a Paula length of 0 - ** results in reading (1+65535)*2 bytes. The 2nd and 3rd (64K*2 = 1x 128K) - ** are reserved for NULL pointers. This is needed for emulating a PT quirk. - ** - ** We have a padding of 4 bytes at the end for length=0 quirk safety. - ** - ** PS: I don't really know if it's possible for ProTracker to set a Paula - ** length of 0, but I fully support this Paula behavior just in case. - */ - const size_t allocLen = ((MOD_SAMPLES + 3) * MAX_SAMPLE_LEN) + 4; + // allocate memory for all sample data blocks (+ 2 extra, for quirk + safety) + const size_t allocLen = (MOD_SAMPLES + 2) * config.maxSampleLength; - return (int8_t *)calloc(1, allocLen); + return (int8_t *)calloc(allocLen, 1); } void modSetSpeed(int32_t speed) @@ -668,7 +657,7 @@ static void sampleOffset(moduleChannel_t *ch) uint16_t newOffset = ch->n_sampleoffset << 7; // this signed test is the reason for the 9xx "sample >64kB = silence" bug - if ((int16_t)newOffset < ch->n_length) + if ((int16_t)newOffset < (int16_t)ch->n_length) { ch->n_length -= newOffset; ch->n_start += newOffset << 1; @@ -871,10 +860,10 @@ static void playVoice(moduleChannel_t *ch) ch->n_start = &song->sampleData[s->offset]; ch->n_finetune = s->fineTune & 0xF; ch->n_volume = s->volume; - ch->n_length = s->length >> 1; - ch->n_replen = s->loopLength >> 1; + ch->n_length = (uint16_t)(s->length >> 1); + ch->n_replen = (uint16_t)(s->loopLength >> 1); - const uint16_t repeat = s->loopStart >> 1; + const uint16_t repeat = (uint16_t)(s->loopStart >> 1); if (repeat > 0) { ch->n_loopstart = ch->n_start + (repeat << 1); @@ -889,7 +878,7 @@ static void playVoice(moduleChannel_t *ch) // non-PT2 requirement (set safe sample space for uninitialized voices - f.ex. "the ultimate beeper.mod") if (ch->n_length == 0) - ch->n_loopstart = ch->n_wavestart = &song->sampleData[RESERVED_SAMPLE_OFFSET]; // 128K reserved sample + ch->n_loopstart = ch->n_wavestart = &song->sampleData[config.reservedSampleOffset]; // 128K reserved sample } if ((ch->n_note & 0xFFF) > 0) @@ -1491,7 +1480,7 @@ void clearSamples(void) memset(s->text, 0, sizeof (s->text)); } - memset(song->sampleData, 0, (MOD_SAMPLES + 1) * MAX_SAMPLE_LEN); + memset(song->sampleData, 0, (MOD_SAMPLES + 1) * config.maxSampleLength); editor.currSample = 0; editor.hiLowInstr = 0; diff --git a/src/pt2_sample_loader.c b/src/pt2_sample_loader.c index 80a3d0e..4d37bb3 100644 --- a/src/pt2_sample_loader.c +++ b/src/pt2_sample_loader.c @@ -58,11 +58,11 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) uint8_t *audioDataU8; int16_t *audioDataS16, tempVol; uint16_t audioFormat, numChannels, bitsPerSample; - int32_t *audioDataS32, smp32; - uint32_t *audioDataU32, i, nameLen, chunkID, chunkSize; - uint32_t sampleLength, sampleRate, filesize, loopFlags; - uint32_t loopStart, loopEnd, dataPtr, dataLen, fmtPtr, endOfChunk, bytesRead; - uint32_t fmtLen, inamPtr, inamLen, smplPtr, smplLen, xtraPtr, xtraLen; + int32_t *audioDataS32, smp32, sampleLength, loopStart, loopEnd, inamLen, nameLen, i; + uint32_t *audioDataU32, chunkID, chunkSize; + uint32_t sampleRate, filesize, loopFlags; + uint32_t dataPtr, dataLen, fmtPtr, endOfChunk, bytesRead; + uint32_t fmtLen, inamPtr, smplPtr, smplLen, xtraPtr, xtraLen; float *fAudioDataFloat; double *dAudioDataDouble; FILE *f; @@ -204,7 +204,7 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) sampleLength = dataLen; // --------------------------- - if (sampleRate == 0 || sampleLength == 0 || sampleLength >= filesize*(bitsPerSample/8)) + if (sampleRate == 0 || sampleLength == 0 || sampleLength >= (int32_t)filesize*(bitsPerSample/8)) { fclose(f); displayErrorMsg("WAV CORRUPT !"); @@ -256,12 +256,12 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) // ---- READ SAMPLE DATA ---- fseek(f, dataPtr, SEEK_SET); - int8_t *smpPtr = &song->sampleData[editor.currSample * MAX_SAMPLE_LEN]; + int8_t *smpPtr = &song->sampleData[editor.currSample * config.maxSampleLength]; if (bitsPerSample == 8) // 8-BIT INTEGER SAMPLE { - if (sampleLength > MAX_SAMPLE_LEN*4) - sampleLength = MAX_SAMPLE_LEN*4; + if (sampleLength > config.maxSampleLength*4) + sampleLength = config.maxSampleLength*4; audioDataU8 = (uint8_t *)malloc(sampleLength * sizeof (uint8_t)); if (audioDataU8 == NULL) @@ -272,7 +272,7 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) } // read sample data - if (fread(audioDataU8, 1, sampleLength, f) != sampleLength) + if (fread(audioDataU8, 1, sampleLength, f) != (size_t)sampleLength) { fclose(f); free(audioDataU8); @@ -299,8 +299,8 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) sampleLength >>= 1; } - if (sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; turnOffVoices(); for (i = 0; i < sampleLength; i++) @@ -311,8 +311,8 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) else if (bitsPerSample == 16) // 16-BIT INTEGER SAMPLE { sampleLength >>= 1; - if (sampleLength > MAX_SAMPLE_LEN*4) - sampleLength = MAX_SAMPLE_LEN*4; + if (sampleLength > config.maxSampleLength*4) + sampleLength = config.maxSampleLength*4; audioDataS16 = (int16_t *)malloc(sampleLength * sizeof (int16_t)); if (audioDataS16 == NULL) @@ -323,7 +323,7 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) } // read sample data - if (fread(audioDataS16, 2, sampleLength, f) != sampleLength) + if (fread(audioDataS16, 2, sampleLength, f) != (size_t)sampleLength) { fclose(f); free(audioDataS16); @@ -346,8 +346,8 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) sampleLength >>= 1; } - if (sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; double dAmp = 1.0; if (forceDownSampling) // we already normalized @@ -374,8 +374,8 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) else if (bitsPerSample == 24) // 24-BIT INTEGER SAMPLE { sampleLength /= 3; - if (sampleLength > MAX_SAMPLE_LEN*4) - sampleLength = MAX_SAMPLE_LEN*4; + if (sampleLength > config.maxSampleLength*4) + sampleLength = config.maxSampleLength*4; audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t)); if (audioDataS32 == NULL) @@ -412,8 +412,8 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) sampleLength >>= 1; } - if (sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; double dAmp = 1.0; if (forceDownSampling) // we already normalized @@ -440,8 +440,8 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) else if (audioFormat == WAV_FORMAT_PCM && bitsPerSample == 32) // 32-BIT INTEGER SAMPLE { sampleLength >>= 2; - if (sampleLength > MAX_SAMPLE_LEN*4) - sampleLength = MAX_SAMPLE_LEN*4; + if (sampleLength > config.maxSampleLength*4) + sampleLength = config.maxSampleLength*4; audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t)); if (audioDataS32 == NULL) @@ -452,7 +452,7 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) } // read sample data - if (fread(audioDataS32, 4, sampleLength, f) != sampleLength) + if (fread(audioDataS32, 4, sampleLength, f) != (size_t)sampleLength) { fclose(f); free(audioDataS32); @@ -478,8 +478,8 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) sampleLength >>= 1; } - if (sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; double dAmp = 1.0; if (forceDownSampling) // we already normalized @@ -506,8 +506,8 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) else if (audioFormat == WAV_FORMAT_IEEE_FLOAT && bitsPerSample == 32) // 32-BIT FLOATING POINT SAMPLE { sampleLength >>= 2; - if (sampleLength > MAX_SAMPLE_LEN*4) - sampleLength = MAX_SAMPLE_LEN*4; + if (sampleLength > config.maxSampleLength*4) + sampleLength = config.maxSampleLength*4; audioDataU32 = (uint32_t *)malloc(sampleLength * sizeof (uint32_t)); if (audioDataU32 == NULL) @@ -518,7 +518,7 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) } // read sample data - if (fread(audioDataU32, 4, sampleLength, f) != sampleLength) + if (fread(audioDataU32, 4, sampleLength, f) != (size_t)sampleLength) { fclose(f); free(audioDataU32); @@ -543,8 +543,8 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) sampleLength >>= 1; } - if (sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; float fAmp = 1.0f; const float fPeak = getFloatPeak(fAudioDataFloat, sampleLength); @@ -564,8 +564,8 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) else if (audioFormat == WAV_FORMAT_IEEE_FLOAT && bitsPerSample == 64) // 64-BIT FLOATING POINT SAMPLE { sampleLength >>= 3; - if (sampleLength > MAX_SAMPLE_LEN*4) - sampleLength = MAX_SAMPLE_LEN*4; + if (sampleLength > config.maxSampleLength*4) + sampleLength = config.maxSampleLength*4; audioDataU32 = (uint32_t *)malloc(sampleLength * (sizeof (uint32_t) * 2)); if (audioDataU32 == NULL) @@ -576,7 +576,7 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) } // read sample data - if (fread(audioDataU32, 8, sampleLength, f) != sampleLength) + if (fread(audioDataU32, 8, sampleLength, f) != (size_t)sampleLength) { fclose(f); free(audioDataU32); @@ -601,8 +601,8 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) sampleLength >>= 1; } - if (sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; double dAmp = 1.0; const double dPeak = getDoublePeak(dAudioDataDouble, sampleLength); @@ -620,17 +620,17 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) free(audioDataU32); } - if (sampleLength < MAX_SAMPLE_LEN) // clear rest of sample data - memset(&song->sampleData[s->offset + sampleLength], 0, MAX_SAMPLE_LEN - sampleLength); + if (sampleLength < config.maxSampleLength) // clear rest of sample data + memset(&song->sampleData[s->offset + sampleLength], 0, config.maxSampleLength - sampleLength); // set sample length if (sampleLength & 1) { - if (++sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (++sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; } - s->length = (uint16_t)sampleLength; + s->length = sampleLength; s->fineTune = 0; s->volume = 64; s->loopStart = 0; @@ -654,15 +654,15 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) loopEnd >>= 1; } - loopStart &= 0xFFFFFFFE; - loopEnd &= 0xFFFFFFFE; + loopStart &= ~1; + loopEnd &= ~1; if (loopFlags) { if (loopStart+(loopEnd-loopStart) <= s->length) { - s->loopStart = (uint16_t)loopStart; - s->loopLength = (uint16_t)(loopEnd - loopStart); + s->loopStart = loopStart; + s->loopLength = loopEnd - loopStart; if (s->loopLength < 2) { @@ -716,7 +716,7 @@ bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) // copy over sample name if (!wavSampleNameFound) { - nameLen = (uint32_t)strlen(entryName); + nameLen = (int32_t)strlen(entryName); for (i = 0; i < 21; i++) s->text[i] = (i < nameLen) ? (char)entryName[i] : '\0'; @@ -755,9 +755,9 @@ bool loadIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) int16_t *ptr16; int32_t filesize, smp32; uint16_t sampleRate; - uint32_t i, sampleLength, sampleLoopStart, sampleLoopLength; + int32_t i, sampleLength, sampleLoopStart, sampleLoopLength, nameLen; uint32_t sampleVolume, blockName, blockSize; - uint32_t vhdrPtr, vhdrLen, bodyPtr, bodyLen, namePtr, nameLen; + uint32_t vhdrPtr, vhdrLen, bodyPtr, bodyLen, namePtr; FILE *f; moduleSample_t *s; @@ -898,7 +898,7 @@ bool loadIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) forceDownSampling = false; } - uint32_t maxSampleLength = MAX_SAMPLE_LEN; + int32_t maxSampleLength = config.maxSampleLength; if (is16Bit) maxSampleLength *= 2; @@ -944,8 +944,8 @@ bool loadIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) sampleLength >>= 1; } - if (sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; double dAmp = 1.0; if (forceDownSampling) // we already normalized @@ -978,26 +978,26 @@ bool loadIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) sampleLength >>= 1; } - if (sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; memcpy(&song->sampleData[s->offset], sampleData, sampleLength); } free(sampleData); - if (sampleLength < MAX_SAMPLE_LEN) // clear rest of sample data - memset(&song->sampleData[s->offset + sampleLength], 0, MAX_SAMPLE_LEN - sampleLength); + if (sampleLength < config.maxSampleLength) // clear rest of sample data + memset(&song->sampleData[s->offset + sampleLength], 0, config.maxSampleLength - sampleLength); // set sample length if (sampleLength & 1) { - if (++sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (++sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; } - sampleLoopStart &= 0xFFFFFFFE; - sampleLoopLength &= 0xFFFFFFFE; + sampleLoopStart &= ~1; + sampleLoopLength &= ~1; if (sampleLoopLength < 2) { @@ -1026,9 +1026,9 @@ bool loadIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) // set sample attributes s->volume = (int8_t)sampleVolume; s->fineTune = 0; - s->length = (uint16_t)sampleLength; - s->loopStart = (uint16_t)sampleLoopStart; - s->loopLength = (uint16_t)sampleLoopLength; + s->length = sampleLength; + s->loopStart = sampleLoopStart; + s->loopLength = sampleLoopLength; // read name if (namePtr != 0 && nameLen > 0) @@ -1090,7 +1090,7 @@ bool loadIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling) bool loadRAWSample(UNICHAR *fileName, char *entryName) { uint8_t i; - uint32_t nameLen, fileSize; + int32_t nameLen, fileSize; FILE *f; moduleSample_t *s; @@ -1107,22 +1107,22 @@ bool loadRAWSample(UNICHAR *fileName, char *entryName) fileSize = ftell(f); fseek(f, 0, SEEK_SET); - fileSize &= 0xFFFFFFFE; - if (fileSize > MAX_SAMPLE_LEN) - fileSize = MAX_SAMPLE_LEN; + fileSize &= ~1; + if (fileSize > config.maxSampleLength) + fileSize = config.maxSampleLength; turnOffVoices(); fread(&song->sampleData[s->offset], 1, fileSize, f); fclose(f); - if (fileSize < MAX_SAMPLE_LEN) - memset(&song->sampleData[s->offset + fileSize], 0, MAX_SAMPLE_LEN - fileSize); + if (fileSize < config.maxSampleLength) + memset(&song->sampleData[s->offset + fileSize], 0, config.maxSampleLength - fileSize); // set sample attributes s->volume = 64; s->fineTune = 0; - s->length = (uint16_t)fileSize; + s->length = fileSize; s->loopStart = 0; s->loopLength = 2; @@ -1179,8 +1179,8 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling uint8_t *audioDataU8, sampleRateBytes[10]; int16_t *audioDataS16; uint16_t bitDepth, numChannels; - int32_t filesize, *audioDataS32, smp32; - uint32_t nameLen, i, offset, sampleRate, sampleLength, blockName, blockSize; + int32_t i, filesize, *audioDataS32, smp32, sampleLength, nameLen; + uint32_t offset, sampleRate, blockName, blockSize; uint32_t commPtr, commLen, ssndPtr, ssndLen; FILE *f; moduleSample_t *s; @@ -1336,12 +1336,12 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling forceDownSampling = false; } - int8_t *smpPtr = &song->sampleData[editor.currSample * MAX_SAMPLE_LEN]; + int8_t *smpPtr = &song->sampleData[editor.currSample * config.maxSampleLength]; if (bitDepth == 8) // 8-BIT INTEGER SAMPLE { - if (sampleLength > MAX_SAMPLE_LEN*4) - sampleLength = MAX_SAMPLE_LEN*4; + if (sampleLength > config.maxSampleLength*4) + sampleLength = config.maxSampleLength*4; audioDataS8 = (int8_t *)malloc(sampleLength * sizeof (int8_t)); if (audioDataS8 == NULL) @@ -1352,7 +1352,7 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling } // read sample data - if (fread(audioDataS8, 1, sampleLength, f) != sampleLength) + if (fread(audioDataS8, 1, sampleLength, f) != (size_t)sampleLength) { fclose(f); free(audioDataS8); @@ -1381,8 +1381,8 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling sampleLength >>= 1; } - if (sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; turnOffVoices(); for (i = 0; i < sampleLength; i++) @@ -1393,8 +1393,8 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling else if (bitDepth == 16) // 16-BIT INTEGER SAMPLE { sampleLength >>= 1; - if (sampleLength > MAX_SAMPLE_LEN*4) - sampleLength = MAX_SAMPLE_LEN*4; + if (sampleLength > config.maxSampleLength*4) + sampleLength = config.maxSampleLength*4; audioDataS16 = (int16_t *)malloc(sampleLength * sizeof (int16_t)); if (audioDataS16 == NULL) @@ -1405,7 +1405,7 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling } // read sample data - if (fread(audioDataS16, 2, sampleLength, f) != sampleLength) + if (fread(audioDataS16, 2, sampleLength, f) != (size_t)sampleLength) { fclose(f); free(audioDataS16); @@ -1432,8 +1432,8 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling sampleLength >>= 1; } - if (sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; double dAmp = 1.0; if (forceDownSampling) // we already normalized @@ -1460,8 +1460,8 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling else if (bitDepth == 24) // 24-BIT INTEGER SAMPLE { sampleLength /= 3; - if (sampleLength > MAX_SAMPLE_LEN*4) - sampleLength = MAX_SAMPLE_LEN*4; + if (sampleLength > config.maxSampleLength*4) + sampleLength = config.maxSampleLength*4; audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t)); if (audioDataS32 == NULL) @@ -1472,7 +1472,7 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling } // read sample data - if (fread(&audioDataS32[sampleLength >> 2], 3, sampleLength, f) != sampleLength) + if (fread(&audioDataS32[sampleLength >> 2], 3, sampleLength, f) != (size_t)sampleLength) { fclose(f); free(audioDataS32); @@ -1506,8 +1506,8 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling sampleLength >>= 1; } - if (sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; double dAmp = 1.0; if (forceDownSampling) // we already normalized @@ -1533,8 +1533,8 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling else if (bitDepth == 32) // 32-BIT INTEGER SAMPLE { sampleLength >>= 2; - if (sampleLength > MAX_SAMPLE_LEN*4) - sampleLength = MAX_SAMPLE_LEN*4; + if (sampleLength > config.maxSampleLength*4) + sampleLength = config.maxSampleLength*4; audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t)); if (audioDataS32 == NULL) @@ -1545,7 +1545,7 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling } // read sample data - if (fread(audioDataS32, 4, sampleLength, f) != sampleLength) + if (fread(audioDataS32, 4, sampleLength, f) != (size_t)sampleLength) { fclose(f); free(audioDataS32); @@ -1575,8 +1575,8 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling sampleLength >>= 1; } - if (sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; double dAmp = 1.0; if (forceDownSampling) // we already normalized @@ -1600,17 +1600,17 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling free(audioDataS32); } - if (sampleLength < MAX_SAMPLE_LEN) // clear rest of sample data - memset(&song->sampleData[s->offset + sampleLength], 0, MAX_SAMPLE_LEN - sampleLength); + if (sampleLength < config.maxSampleLength) // clear rest of sample data + memset(&song->sampleData[s->offset + sampleLength], 0, config.maxSampleLength - sampleLength); // set sample length if (sampleLength & 1) { - if (++sampleLength > MAX_SAMPLE_LEN) - sampleLength = MAX_SAMPLE_LEN; + if (++sampleLength > config.maxSampleLength) + sampleLength = config.maxSampleLength; } - s->length = (uint16_t)sampleLength; + s->length = sampleLength; s->fineTune = 0; s->volume = 64; s->loopStart = 0; @@ -1619,7 +1619,7 @@ bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling fclose(f); // copy over sample name - nameLen = (uint32_t)strlen(entryName); + nameLen = (int32_t)strlen(entryName); for (i = 0; i < 21; i++) s->text[i] = (i < nameLen) ? (char)entryName[i] : '\0'; diff --git a/src/pt2_sample_saver.c b/src/pt2_sample_saver.c index ffd5b47..d4492d6 100644 --- a/src/pt2_sample_saver.c +++ b/src/pt2_sample_saver.c @@ -161,8 +161,8 @@ bool saveSample(bool checkIfFileExist, bool giveNewFreeFilename) const int8_t *sampleData = &song->sampleData[s->offset]; const uint32_t sampleLength = s->length; - const uint32_t loopStart = s->loopStart & 0xFFFE; - const uint32_t loopLength = s->loopLength & 0xFFFE; + const uint32_t loopStart = s->loopStart & ~1; + const uint32_t loopLength = s->loopLength & ~1; switch (diskop.smpSaveType) { diff --git a/src/pt2_sampler.c b/src/pt2_sampler.c index d5f9146..e7c5d2d 100644 --- a/src/pt2_sampler.c +++ b/src/pt2_sampler.c @@ -55,7 +55,7 @@ void upSample(void) moduleSample_t *s = &song->samples[editor.currSample]; - uint32_t newLength = (s->length >> 1) & 0xFFFE; + int32_t newLength = (s->length >> 1) & config.maxSampleLength; if (newLength < 2) return; @@ -63,16 +63,16 @@ void upSample(void) // upsample int8_t *ptr8 = &song->sampleData[s->offset]; - for (uint32_t i = 0; i < newLength; i++) + for (int32_t i = 0; i < newLength; i++) ptr8[i] = ptr8[i << 1]; // clear junk after shrunk sample - if (newLength < MAX_SAMPLE_LEN) - memset(&ptr8[newLength], 0, MAX_SAMPLE_LEN - newLength); + if (newLength < config.maxSampleLength) + memset(&ptr8[newLength], 0, config.maxSampleLength - newLength); - s->length = (uint16_t)newLength; - s->loopStart = (s->loopStart >> 1) & 0xFFFE; - s->loopLength = (s->loopLength >> 1) & 0xFFFE; + s->length = newLength; + s->loopStart = (s->loopStart >> 1) & ~1; + s->loopLength = (s->loopLength >> 1) & ~1; if (s->loopLength < 2) { @@ -97,9 +97,9 @@ void downSample(void) moduleSample_t *s = &song->samples[editor.currSample]; - uint32_t newLength = s->length << 1; - if (newLength > MAX_SAMPLE_LEN) - newLength = MAX_SAMPLE_LEN; + int32_t newLength = s->length << 1; + if (newLength > config.maxSampleLength) + newLength = config.maxSampleLength; turnOffVoices(); @@ -113,12 +113,12 @@ void downSample(void) ptr8_2[i<<1] = ptr8_2[i]; } - s->length = (uint16_t)newLength; + s->length = newLength; if (s->loopLength > 2) { - uint32_t loopStart = s->loopStart << 1; - uint32_t loopLength = s->loopLength << 1; + int32_t loopStart = s->loopStart << 1; + int32_t loopLength = s->loopLength << 1; if (loopStart+loopLength > s->length) { @@ -126,8 +126,8 @@ void downSample(void) loopLength = 2; } - s->loopStart = (uint16_t)loopStart; - s->loopLength = (uint16_t)loopLength; + s->loopStart = loopStart; + s->loopLength = loopLength; } fixSampleBeep(s); @@ -372,7 +372,7 @@ void renderSampleData(void) } // render sample data - if (sampler.samDisplay >= 0 && sampler.samDisplay <= MAX_SAMPLE_LEN) + if (sampler.samDisplay >= 0 && sampler.samDisplay <= config.maxSampleLength) { y1 = SAMPLE_AREA_Y_CENTER - getScaledSample(scr2SmpPos(0)); @@ -426,10 +426,21 @@ void renderSampleData(void) return; // render "sample display" text - if (sampler.samStart == sampler.blankSample) - printFiveDecimalsBg(272, 214, 0, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + + if (config.maxSampleLength == 0xFFFE) + { + if (sampler.samStart == sampler.blankSample) + printFiveDecimalsBg(272, 214, 0, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + else + printFiveDecimalsBg(272, 214, sampler.samDisplay, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + } else - printFiveDecimalsBg(272, 214, sampler.samDisplay, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + { + if (sampler.samStart == sampler.blankSample) + printSixDecimalsBg(270, 214, 0, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + else + printSixDecimalsBg(270, 214, sampler.samDisplay, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + } setDragBar(); setLoopSprites(); @@ -745,12 +756,12 @@ void redoSampleData(int8_t sample) { memcpy(&song->sampleData[s->offset], editor.smpRedoBuffer[sample], editor.smpRedoLengths[sample]); - if (editor.smpRedoLengths[sample] < MAX_SAMPLE_LEN) - memset(&song->sampleData[s->offset + editor.smpRedoLengths[sample]], 0, MAX_SAMPLE_LEN - editor.smpRedoLengths[sample]); + if (editor.smpRedoLengths[sample] < config.maxSampleLength) + memset(&song->sampleData[s->offset + editor.smpRedoLengths[sample]], 0, config.maxSampleLength - editor.smpRedoLengths[sample]); } else { - memset(&song->sampleData[s->offset], 0, MAX_SAMPLE_LEN); + memset(&song->sampleData[s->offset], 0, config.maxSampleLength); } s->fineTune = editor.smpRedoFinetunes[sample]; @@ -804,8 +815,8 @@ void fillSampleRedoBuffer(int8_t sample) bool allocSamplerVars(void) { - sampler.copyBuf = (int8_t *)malloc(MAX_SAMPLE_LEN); - sampler.blankSample = (int8_t *)calloc(MAX_SAMPLE_LEN, 1); + sampler.copyBuf = (int8_t *)malloc(131070); + sampler.blankSample = (int8_t *)calloc(131070, 1); if (sampler.copyBuf == NULL || sampler.blankSample == NULL) return false; @@ -903,9 +914,9 @@ void samplerRemoveDcOffset(void) #define INTRP_LINEAR_TAPS 2 #define INTRP8_LINEAR(s1, s2, f) /* output: -127..128 */ \ s2 -= s1; \ - s2 *= (int32_t)(f); \ + s2 *= (int32_t)(f >> 16); \ s1 <<= 8; \ - s2 >>= (16 - 8); \ + s2 >>= 16-8; \ s1 += s2; \ s1 >>= 8; \ @@ -916,7 +927,7 @@ void samplerResample(void) int16_t refPeriod, newPeriod; int32_t samples[INTRP_LINEAR_TAPS], i, pos, readPos, writePos; int32_t readLength, writeLength, loopStart, loopLength; - uint32_t posFrac, delta; + uint64_t frac64, delta64; moduleSample_t *s; if (editor.sampleZero) @@ -962,18 +973,18 @@ void samplerResample(void) return; } - delta = ((uint32_t)readLength << 16) / (uint32_t)writeLength; - assert(delta != 0); + delta64 = ((uint64_t)readLength << 32) / writeLength; + assert(delta64 != 0); - writeLength = writeLength & 0xFFFFFFFE; - if (writeLength > MAX_SAMPLE_LEN) - writeLength = MAX_SAMPLE_LEN; + writeLength = writeLength & ~1; + if (writeLength > config.maxSampleLength) + writeLength = config.maxSampleLength; memcpy(readData, writeData, readLength); // resample - posFrac = 0; + frac64 = 0; turnOffVoices(); while (writePos < writeLength) @@ -988,28 +999,28 @@ void samplerResample(void) samples[i] = readData[pos]; } - INTRP8_LINEAR(samples[0], samples[1], posFrac); + INTRP8_LINEAR(samples[0], samples[1], frac64); writeData[writePos++] = (int8_t)samples[0]; - posFrac += delta; - readPos += posFrac >> 16; - posFrac &= 0xFFFF; + frac64 += delta64; + readPos += frac64 >> 32; + frac64 &= 0xFFFFFFFF; } free(readData); // wipe non-used data in new sample - if (writeLength < MAX_SAMPLE_LEN) - memset(&writeData[writePos], 0, MAX_SAMPLE_LEN - writeLength); + if (writeLength < config.maxSampleLength) + memset(&writeData[writePos], 0, config.maxSampleLength - writeLength); // update sample attributes - s->length = (uint16_t)writeLength; + s->length = writeLength; s->fineTune = 0; // scale loop points (and deactivate if overflowing) if ((s->loopStart + s->loopLength) > 2) { - loopStart = (int32_t)(((uint32_t)s->loopStart << 16) / delta) & 0xFFFFFFFE; - loopLength = (int32_t)(((uint32_t)s->loopLength << 16) / delta) & 0xFFFFFFFE; + loopStart = (int32_t)(((uint64_t)s->loopStart << 32) / delta64) & ~1; + loopLength = (int32_t)(((uint64_t)s->loopLength << 32) / delta64) & ~1; if (loopStart+loopLength > s->length) { @@ -1018,8 +1029,8 @@ void samplerResample(void) } else { - s->loopStart = (uint16_t)loopStart; - s->loopLength = (uint16_t)loopLength; + s->loopStart = loopStart; + s->loopLength = loopLength; } } @@ -1120,12 +1131,12 @@ void doMix(void) } memcpy(&song->sampleData[s3->offset], mixPtr, mixLength); - if (mixLength < MAX_SAMPLE_LEN) - memset(&song->sampleData[s3->offset + mixLength], 0, MAX_SAMPLE_LEN - mixLength); + if (mixLength < config.maxSampleLength) + memset(&song->sampleData[s3->offset + mixLength], 0, config.maxSampleLength - mixLength); free(mixPtr); - s3->length = (uint16_t)mixLength; + s3->length = mixLength; s3->volume = 64; s3->fineTune = 0; s3->loopStart = 0; @@ -1308,7 +1319,7 @@ void sampleMarkerToBeg(void) } invertRange(); - editor.samplePos = (uint16_t)editor.markEndOfs; + editor.samplePos = editor.markEndOfs; } updateSamplePos(); @@ -1347,7 +1358,7 @@ void sampleMarkerToCenter(void) } invertRange(); - editor.samplePos = (uint16_t)editor.markEndOfs; + editor.samplePos = editor.markEndOfs; } updateSamplePos(); @@ -1380,7 +1391,7 @@ void sampleMarkerToEnd(void) } invertRange(); - editor.samplePos = (uint16_t)editor.markEndOfs; + editor.samplePos = editor.markEndOfs; } updateSamplePos(); @@ -1419,7 +1430,7 @@ void samplerSamCopy(void) sampler.copyBufSize = editor.markEndOfs - editor.markStartOfs; - if ((int32_t)(editor.markStartOfs + sampler.copyBufSize) > MAX_SAMPLE_LEN) + if ((int32_t)(editor.markStartOfs + sampler.copyBufSize) > config.maxSampleLength) { displayErrorMsg("COPY ERROR !"); return; @@ -1471,7 +1482,7 @@ void samplerSamDelete(uint8_t cut) // if whole sample is marked, wipe it if (editor.markEndOfs-editor.markStartOfs >= sampleLength) { - memset(&song->sampleData[s->offset], 0, MAX_SAMPLE_LEN); + memset(&song->sampleData[s->offset], 0, config.maxSampleLength); invertRange(); editor.markStartOfs = -1; @@ -1497,7 +1508,7 @@ void samplerSamDelete(uint8_t cut) markStart = editor.markStartOfs; copyLength = (editor.markStartOfs + sampleLength) - markEnd; - if (copyLength < 2 || copyLength > MAX_SAMPLE_LEN) + if (copyLength < 2 || copyLength > config.maxSampleLength) { displayErrorMsg("SAMPLE CUT FAIL !"); return; @@ -1520,8 +1531,8 @@ void samplerSamDelete(uint8_t cut) // nuke sample data and copy over the result memcpy(&song->sampleData[s->offset], tmpBuf, copyLength); - if (copyLength < MAX_SAMPLE_LEN) - memset(&song->sampleData[s->offset+copyLength], 0, MAX_SAMPLE_LEN - copyLength); + if (copyLength < config.maxSampleLength) + memset(&song->sampleData[s->offset+copyLength], 0, config.maxSampleLength - copyLength); free(tmpBuf); @@ -1556,11 +1567,11 @@ void samplerSamDelete(uint8_t cut) if (markStart < s->loopStart+s->loopLength) { // we cut data inside the loop, increase loop length - val32 = (s->loopLength - (markEnd - markStart)) & 0xFFFFFFFE; + val32 = (s->loopLength - (markEnd - markStart)) & ~1; if (val32 < 2) val32 = 2; - s->loopLength = (uint16_t)val32; + s->loopLength = val32; } // we cut data after the loop, don't modify loop points @@ -1568,7 +1579,7 @@ void samplerSamDelete(uint8_t cut) else { // we cut data before the loop, adjust loop start point - val32 = (s->loopStart - (markEnd - markStart)) & 0xFFFFFFFE; + val32 = (s->loopStart - (markEnd - markStart)) & ~1; if (val32 < 0) { s->loopStart = 0; @@ -1576,12 +1587,12 @@ void samplerSamDelete(uint8_t cut) } else { - s->loopStart = (uint16_t)val32; + s->loopStart = val32; } } } - s->length = copyLength & 0xFFFE; + s->length = copyLength & ~1; if (sampler.samDisplay <= 2) { @@ -1604,7 +1615,7 @@ void samplerSamDelete(uint8_t cut) invertRange(); } - editor.samplePos = (uint16_t)editor.markStartOfs; + editor.samplePos = editor.markStartOfs; fixSampleBeep(s); updateSamplePos(); recalcChordLength(); @@ -1651,13 +1662,13 @@ void samplerSamPaste(void) if (s->length == 0) markStart = 0; - if (s->length+sampler.copyBufSize > MAX_SAMPLE_LEN) + if (s->length+sampler.copyBufSize > config.maxSampleLength) { displayErrorMsg("NOT ENOUGH ROOM"); return; } - tmpBuf = (int8_t *)malloc(MAX_SAMPLE_LEN); + tmpBuf = (int8_t *)malloc(config.maxSampleLength); if (tmpBuf == NULL) { statusOutOfMemory(); @@ -1687,11 +1698,11 @@ void samplerSamPaste(void) memcpy(&tmpBuf[readPos], &song->sampleData[s->offset+markStart], s->length - markStart); } - int32_t newLength = (s->length + sampler.copyBufSize) & 0xFFFFFFFE; - if (newLength > MAX_SAMPLE_LEN) - newLength = MAX_SAMPLE_LEN; + int32_t newLength = (s->length + sampler.copyBufSize) & ~1; + if (newLength > config.maxSampleLength) + newLength = config.maxSampleLength; - sampler.samLength = s->length = (uint16_t)newLength; + sampler.samLength = s->length = newLength; if (s->loopLength > 2) // loop enabled? { @@ -1701,14 +1712,14 @@ void samplerSamPaste(void) { // we pasted data inside the loop, increase loop length - if (s->loopLength+sampler.copyBufSize > MAX_SAMPLE_LEN) + if (s->loopLength+sampler.copyBufSize > config.maxSampleLength) { s->loopStart = 0; s->loopLength = 2; } else { - s->loopLength = (uint16_t)(s->loopLength + sampler.copyBufSize) & 0xFFFE; + s->loopLength = (s->loopLength + sampler.copyBufSize) & config.maxSampleLength; if (s->loopStart+s->loopLength > s->length) { s->loopStart = 0; @@ -1722,14 +1733,14 @@ void samplerSamPaste(void) else { // we pasted data before the loop, adjust loop start point - if (s->loopStart+sampler.copyBufSize > MAX_SAMPLE_LEN) + if (s->loopStart+sampler.copyBufSize > config.maxSampleLength) { s->loopStart = 0; s->loopLength = 2; } else { - s->loopStart = (uint16_t)(s->loopStart + sampler.copyBufSize) & 0xFFFE; + s->loopStart = (s->loopStart + sampler.copyBufSize) & config.maxSampleLength; if (s->loopStart+s->loopLength > s->length) { s->loopStart = 0; @@ -1742,8 +1753,8 @@ void samplerSamPaste(void) memcpy(&song->sampleData[s->offset], tmpBuf, s->length); // clear data after sample's length (if present) - if (s->length < MAX_SAMPLE_LEN) - memset(&song->sampleData[s->offset+s->length], 0, MAX_SAMPLE_LEN - s->length); + if (s->length < config.maxSampleLength) + memset(&song->sampleData[s->offset+s->length], 0, config.maxSampleLength - s->length); free(tmpBuf); @@ -1786,9 +1797,9 @@ static void playCurrSample(uint8_t chn, int32_t startOffset, int32_t endOffset, if (playWaveformFlag) { ch->n_start = &song->sampleData[s->offset]; - ch->n_length = (s->loopStart > 0) ? (uint32_t)(s->loopStart + s->loopLength) >> 1 : s->length >> 1; + ch->n_length = (uint16_t)((s->loopStart > 0) ? (s->loopStart + s->loopLength) >> 1 : s->length >> 1); ch->n_loopstart = &song->sampleData[s->offset + s->loopStart]; - ch->n_replen = s->loopLength >> 1; + ch->n_replen = (uint16_t)(s->loopLength >> 1); } else { @@ -2357,9 +2368,9 @@ void samplerSamplePressed(bool mouseButtonHeld) { sampler.lastMouseX = mouseX; - tmpPos = (scr2SmpPos(mouseX - 1) - s->loopStart) & 0xFFFFFFFE; - if (tmpPos > MAX_SAMPLE_LEN) - tmpPos = MAX_SAMPLE_LEN; + tmpPos = (scr2SmpPos(mouseX - 1) - s->loopStart) & ~1; + if (tmpPos > config.maxSampleLength) + tmpPos = config.maxSampleLength; if (s->loopStart+tmpPos >= (s->loopStart+s->loopLength)-2) { @@ -2368,10 +2379,10 @@ void samplerSamplePressed(bool mouseButtonHeld) } else { - s->loopStart = (uint16_t)(s->loopStart + tmpPos); + s->loopStart = s->loopStart + tmpPos; if (s->loopLength-tmpPos > 2) - s->loopLength -= (uint16_t)tmpPos; + s->loopLength -= tmpPos; else s->loopLength = 2; } @@ -2395,10 +2406,10 @@ void samplerSamplePressed(bool mouseButtonHeld) s = &song->samples[editor.currSample]; - tmpPos = (scr2SmpPos(mouseX - 4) - s->loopStart) & 0xFFFFFFFE; - tmpPos = CLAMP(tmpPos, 2, MAX_SAMPLE_LEN); + tmpPos = (scr2SmpPos(mouseX - 4) - s->loopStart) & ~1; + tmpPos = CLAMP(tmpPos, 2, config.maxSampleLength); - s->loopLength = (uint16_t)tmpPos; + s->loopLength = tmpPos; ui.updateCurrSampleRepeat = true; ui.updateCurrSampleReplen = true; @@ -2445,7 +2456,7 @@ void samplerSamplePressed(bool mouseButtonHeld) if (tmpPos > s->length) tmpPos = s->length; - editor.samplePos = (uint16_t)tmpPos; + editor.samplePos = tmpPos; } updateSamplePos(); @@ -2457,7 +2468,7 @@ void samplerSamplePressed(bool mouseButtonHeld) if (mouseX != sampler.lastSamPos) { - sampler.lastSamPos = (uint16_t)mouseX; + sampler.lastSamPos = mouseX; invertRange(); if (s->length == 0) @@ -2494,7 +2505,7 @@ void samplerSamplePressed(bool mouseButtonHeld) if (tmpPos > s->length) tmpPos = s->length; - editor.samplePos = (uint16_t)tmpPos; + editor.samplePos = tmpPos; } updateSamplePos(); @@ -2539,8 +2550,8 @@ void samplerLoopToggle(void) } else { - s->loopStart = (uint16_t)sampler.tmpLoopStart; - s->loopLength = (uint16_t)sampler.tmpLoopLength; + s->loopStart = sampler.tmpLoopStart; + s->loopLength = sampler.tmpLoopLength; if (s->loopStart+s->loopLength > s->length) { diff --git a/src/pt2_sampler.h b/src/pt2_sampler.h index 601e19d..1521cea 100644 --- a/src/pt2_sampler.h +++ b/src/pt2_sampler.h @@ -11,8 +11,7 @@ typedef struct sampler_t int16_t loopStartPos, loopEndPos; uint16_t dragStart, dragEnd; int32_t samPointWidth, samOffset, samDisplay, samLength, saveMouseX, lastSamPos; - int32_t lastMouseX, lastMouseY, tmpLoopStart, tmpLoopLength; - uint32_t copyBufSize; + int32_t lastMouseX, lastMouseY, tmpLoopStart, tmpLoopLength, copyBufSize; } sampler_t; extern sampler_t sampler; // pt2_sampler.c diff --git a/src/pt2_sampling.c b/src/pt2_sampling.c index 58fc338..aad377c 100644 --- a/src/pt2_sampling.c +++ b/src/pt2_sampling.c @@ -29,6 +29,7 @@ #include "pt2_config.h" #include "pt2_sampling.h" #include "pt2_math.h" // PT2_PI +#include "pt2_hpc.h" enum { @@ -478,6 +479,7 @@ void renderSamplingBox(void) { changeStatusText("PLEASE WAIT ..."); flipFrame(); + hpc_ResetEndTime(&video.vblankHpc); editor.sampleZero = false; editor.blockMarkFlag = false; @@ -604,7 +606,7 @@ static void startSampling(void) assert(roundedOutputFrequency > 0); - maxSamplingLength = (int32_t)(ceil(((double)MAX_SAMPLE_LEN*inputFrequency) / dOutputFrequency)) + 1; + maxSamplingLength = (int32_t)(ceil(((double)config.maxSampleLength*inputFrequency) / dOutputFrequency)) + 1; const int32_t allocLen = (SINC_TAPS/2) + maxSamplingLength + (SINC_TAPS/2); dSamplingBufferOrig = (double *)malloc(allocLen * sizeof (double)); @@ -637,8 +639,8 @@ static int32_t downsampleSamplingBuffer(void) const double dRatio = dOutputFrequency / inputFrequency; int32_t writeLength = (int32_t)(readLength * dRatio); - if (writeLength > MAX_SAMPLE_LEN) - writeLength = MAX_SAMPLE_LEN; + if (writeLength > config.maxSampleLength) + writeLength = config.maxSampleLength; double *dBuffer = (double *)malloc(writeLength * sizeof (double)); if (dBuffer == NULL) @@ -726,7 +728,7 @@ void stopSampling(void) } moduleSample_t *s = &song->samples[editor.currSample]; - s->length = (uint16_t)newLength; + s->length = newLength; s->fineTune = samplingFinetune; s->loopStart = 0; s->loopLength = 2; diff --git a/src/pt2_scopes.c b/src/pt2_scopes.c index b21300a..2229d2c 100644 --- a/src/pt2_scopes.c +++ b/src/pt2_scopes.c @@ -11,12 +11,12 @@ #include "pt2_tables.h" #include "pt2_structs.h" #include "pt2_config.h" +#include "pt2_hpc.h" // this uses code that is not entirely thread safe, but I have never had any issues so far... static volatile bool scopesUpdatingFlag, scopesDisplayingFlag; -static uint32_t scopeTimeLen, scopeTimeLenFrac; -static uint64_t timeNext64, timeNext64Frac; +static hpc_t scopeHpc; static SDL_Thread *scopeThread; scope_t scope[AMIGA_VOICES]; // global @@ -36,7 +36,7 @@ static int32_t getSampleSlotFromReadAddress(const int8_t *sampleReadAddress) { assert(song != NULL); const int8_t *sampleData = song->sampleData; - const int32_t sampleSlotSize = MAX_SAMPLE_LEN; + const int32_t sampleSlotSize = config.maxSampleLength; if (sampleData == NULL) // shouldn't really happen, but just in case return -1; @@ -118,7 +118,7 @@ void scopeTrigger(int32_t ch) const int8_t *newData = tempState.newData; if (newData == NULL) - newData = &song->sampleData[RESERVED_SAMPLE_OFFSET]; // 128K reserved sample + newData = &song->sampleData[config.reservedSampleOffset]; // 128K reserved sample int32_t newLength = tempState.newLength; // in bytes, not words if (newLength < 2) @@ -320,9 +320,8 @@ static int32_t SDLCALL scopeThreadFunc(void *ptr) // this is needed for scope stability (confirmed) SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); - // set next frame time - timeNext64 = SDL_GetPerformanceCounter() + scopeTimeLen; - timeNext64Frac = scopeTimeLenFrac; + hpc_SetDurationInHz(&scopeHpc, SCOPE_HZ); + hpc_ResetEndTime(&scopeHpc); while (editor.programRunning) { @@ -331,31 +330,7 @@ static int32_t SDLCALL scopeThreadFunc(void *ptr) updateScopes(); - uint64_t time64 = SDL_GetPerformanceCounter(); - if (time64 < timeNext64) - { - time64 = timeNext64 - time64; - if (time64 > UINT32_MAX) - time64 = UINT32_MAX; - - const uint32_t diff32 = (uint32_t)time64; - - // convert to microseconds and round to integer - const int32_t time32 = (int32_t)((diff32 * editor.dPerfFreqMulMicro) + 0.5); - - // delay until we have reached the next frame - if (time32 > 0) - usleep(time32); - } - - // update next tick time - timeNext64 += scopeTimeLen; - timeNext64Frac += scopeTimeLenFrac; - if (timeNext64Frac > 0xFFFFFFFF) - { - timeNext64Frac &= 0xFFFFFFFF; - timeNext64++; - } + hpc_Wait(&scopeHpc); } (void)ptr; @@ -364,18 +339,6 @@ static int32_t SDLCALL scopeThreadFunc(void *ptr) bool initScopes(void) { - double dInt, dFrac; - - // calculate scope time for performance counters and split into int/frac - dFrac = modf(editor.dPerfFreq / SCOPE_HZ, &dInt); - - // integer part - scopeTimeLen = (int32_t)dInt; - - // fractional part (scaled to 0..2^32-1) - dFrac *= UINT32_MAX+1.0; - scopeTimeLenFrac = (uint32_t)dFrac; - resetCachedScopePeriod(); scopeThread = SDL_CreateThread(scopeThreadFunc, NULL, NULL); diff --git a/src/pt2_structs.h b/src/pt2_structs.h index 1b10199..993e61a 100644 --- a/src/pt2_structs.h +++ b/src/pt2_structs.h @@ -8,6 +8,7 @@ #include #include #include "pt2_header.h" +#include "pt2_hpc.h" // for .WAV sample loading/saving typedef struct wavHeader_t @@ -57,12 +58,11 @@ typedef struct moduleHeader_t typedef struct moduleSample_t { volatile int8_t *volumeDisp; - volatile uint16_t *lengthDisp, *loopStartDisp, *loopLengthDisp; + volatile int32_t *lengthDisp, *loopStartDisp, *loopLengthDisp; char text[22 + 1]; int8_t volume; uint8_t fineTune; - uint16_t length, loopStart, loopLength; - int32_t offset; + int32_t offset, length, loopStart, loopLength; } moduleSample_t; typedef struct moduleChannel_t @@ -131,6 +131,7 @@ typedef struct video_t int32_t renderX, renderY, renderW, renderH, displayW, displayH; int32_t xScale, yScale; float fMouseXMul, fMouseYMul; + hpc_t vblankHpc; SDL_PixelFormat *pixelFormat; uint32_t *frameBuffer, *frameBufferUnaligned; @@ -153,7 +154,7 @@ typedef struct editor_t volatile uint16_t *quantizeValueDisp, *metroSpeedDisp, *metroChannelDisp, *sampleVolDisp; volatile uint16_t *vol1Disp, *vol2Disp, *currEditPatternDisp, *currPosDisp, *currPatternDisp; volatile uint16_t *currPosEdPattDisp, *currLengthDisp, *lpCutOffDisp, *hpCutOffDisp; - volatile uint16_t *samplePosDisp, *chordLengthDisp; + volatile int32_t *samplePosDisp, *chordLengthDisp; char mixText[16]; char *entryNameTmp, *currPath, *dropTempFileName; @@ -174,13 +175,12 @@ typedef struct editor_t uint8_t tuningNote, resampleNote, initialTempo, initialSpeed, editMoveAdd; int16_t modulateSpeed; - uint16_t metroSpeed, metroChannel, sampleVol, samplePos, chordLength; + uint16_t metroSpeed, metroChannel, sampleVol; uint16_t effectMacros[10], currPlayNote, vol1, vol2, lpCutOff, hpCutOff; - uint16_t smpRedoLoopStarts[MOD_SAMPLES], smpRedoLoopLengths[MOD_SAMPLES], smpRedoLengths[MOD_SAMPLES]; - int32_t oldTempo, modulatePos, modulateOffset, markStartOfs, markEndOfs, pat2SmpPos; - uint32_t vblankTimeLen, vblankTimeLenFrac; + int32_t smpRedoLoopStarts[MOD_SAMPLES], smpRedoLoopLengths[MOD_SAMPLES], smpRedoLengths[MOD_SAMPLES]; + int32_t oldTempo, modulatePos, modulateOffset, markStartOfs, markEndOfs, pat2SmpPos, samplePos, chordLength; uint64_t musicTime64; - double dPerfFreq, dPerfFreqMulMicro, *dPat2SmpBuf; + double *dPat2SmpBuf; note_t trackBuffer[MOD_ROWS], cmdsBuffer[MOD_ROWS], blockBuffer[MOD_ROWS]; note_t patternBuffer[MOD_ROWS * AMIGA_VOICES], undoBuffer[MOD_ROWS * AMIGA_VOICES]; SDL_Thread *mod2WavThread, *pat2SmpThread; @@ -214,6 +214,7 @@ typedef struct ui_t bool changingSamplingNote; + bool force32BitNumPtr; int8_t *numPtr8, tmpDisp8, pointerMode, editOpScreen, editTextType, askScreenType; int8_t visualizerMode, previousPointerMode, forceVolDrag, changingChordNote; uint8_t numLen, numBits; @@ -230,10 +231,10 @@ typedef struct ui_t bool updateMixText, updatePosText, updateModText, updateVolText; // edit op. #4 (sample chord editor) - bool updateLengthText, updateNote1Text, updateNote2Text; - bool updateNote3Text, updateNote4Text; + bool updateChordLengthText, updateChordNote1Text, updateChordNote2Text; + bool updateChordNote3Text, updateChordNote4Text; - //sampler + // sampler bool updateResampleNote, updateVolFromText, updateVolToText, updateLPText; bool updateHPText, updateNormFlag, update9xxPos; @@ -256,7 +257,7 @@ typedef struct ui_t int16_t lineCurX, lineCurY, editObject, sampleMarkingPos; uint16_t *numPtr16, tmpDisp16, *dstOffset, dstPos, textLength, editTextPos; uint16_t dstOffsetEnd, lastSampleOffset, diskOpPathTextOffset; - int32_t askTempData; + int32_t askTempData, *numPtr32, tmpDisp32; } ui_t; extern keyb_t keyb; diff --git a/src/pt2_tables.c b/src/pt2_tables.c index 4954681..05c6491 100644 --- a/src/pt2_tables.c +++ b/src/pt2_tables.c @@ -265,15 +265,15 @@ const guiButton_t bTopScreen[] = { 98, 55,108, 65, PTB_SVOLUMEU}, {109, 55,119, 65, PTB_SVOLUMED}, - { 62, 66, 97, 76, PTB_SLENGTHS}, + { 54, 66, 97, 76, PTB_SLENGTHS}, { 98, 66,108, 76, PTB_SLENGTHU}, {109, 66,119, 76, PTB_SLENGTHD}, - { 62, 77, 97, 87, PTB_SREPEATS}, + { 54, 77, 97, 87, PTB_SREPEATS}, { 98, 77,108, 87, PTB_SREPEATU}, {109, 77,119, 87, PTB_SREPEATD}, - { 62, 88, 97, 98, PTB_SREPLENS}, + { 54, 88, 97, 98, PTB_SREPLENS}, { 98, 88,108, 98, PTB_SREPLENU}, {109, 88,119, 98, PTB_SREPLEND} }; @@ -395,8 +395,8 @@ const guiButton_t bEditOp3[] = {120, 55,165, 65, PTB_EO_MIX}, {166, 55,212, 65, PTB_EO_ECHO}, - {213, 55,243, 65, PTB_DUMMY}, - {244, 55,283, 65, PTB_EO_POS_NUM}, + {213, 55,237, 65, PTB_DUMMY}, + {238, 55,283, 65, PTB_EO_POS_NUM}, {284, 55,294, 65, PTB_EO_POS_UP}, {295, 55,305, 65, PTB_EO_POS_DOWN}, {306, 55,319, 65, PTB_EO_1}, @@ -454,8 +454,8 @@ const guiButton_t bEditOp4[] = {295, 77,305, 87, PTB_EO_NOTE3_DOWN}, {306, 77,319, 87, PTB_EO_3}, - {120, 88,157, 98, PTB_EO_LENGTH}, - {158, 88,204, 98, PTB_DUMMY}, + {120, 88,165, 98, PTB_EO_LENGTH}, + {166, 88,204, 98, PTB_DUMMY}, {205, 88,251, 98, PTB_EO_MINOR6}, {251, 88,283, 98, PTB_EO_NOTE4}, {284, 88,294, 98, PTB_EO_NOTE4_UP}, diff --git a/src/pt2_textout.h b/src/pt2_textout.h index 5c92af3..52b61aa 100644 --- a/src/pt2_textout.h +++ b/src/pt2_textout.h @@ -34,11 +34,12 @@ void printFourHex(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor); void printFiveHex(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor); void printOneHexBig(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor); void printTwoHexBig(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor); -void printSixDecimals(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor); + void printTwoDecimals(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor); +void printThreeDecimals(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor); void printFourDecimals(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor); void printFiveDecimals(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor); -void printThreeDecimals(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor); +void printSixDecimals(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor); void printTwoDecimalsBig(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor); void printOneHexBg(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor, uint32_t backColor); void printTwoHexBg(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor, uint32_t backColor); @@ -49,9 +50,9 @@ void printOneHexBigBg(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor void printTwoHexBigBg(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor, uint32_t backColor); void printSixDecimalsBg(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor, uint32_t backColor); void printTwoDecimalsBg(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor, uint32_t backColor); +void printThreeDecimalsBg(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor, uint32_t backColor); void printFourDecimalsBg(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor, uint32_t backColor); void printFiveDecimalsBg(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor, uint32_t backColor); -void printThreeDecimalsBg(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor, uint32_t backColor); void printTwoDecimalsBigBg(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor, uint32_t backColor); void setPrevStatusMessage(void); diff --git a/src/pt2_visuals.c b/src/pt2_visuals.c index 8566385..75125d3 100644 --- a/src/pt2_visuals.c +++ b/src/pt2_visuals.c @@ -42,6 +42,7 @@ #include "pt2_bmp.h" #include "pt2_sampling.h" #include "pt2_chordmaker.h" +#include "pt2_hpc.h" typedef struct sprite_t { @@ -53,7 +54,6 @@ typedef struct sprite_t } sprite_t; static uint32_t vuMetersBg[4 * (10 * 48)]; -static uint64_t timeNext64, timeNext64Frac; sprite_t sprites[SPRITE_NUM]; // globalized @@ -200,64 +200,6 @@ void statusNotSampleZero(void) displayErrorMsg("NOT SAMPLE 0 !"); } -void setupPerfFreq(void) -{ - uint64_t perfFreq64; - double dInt, dFrac; - - perfFreq64 = SDL_GetPerformanceFrequency(); assert(perfFreq64 != 0); - editor.dPerfFreq = (double)perfFreq64; - editor.dPerfFreqMulMicro = 1000000.0 / editor.dPerfFreq; - - // calculate vblank time for performance counters and split into int/frac - dFrac = modf(editor.dPerfFreq / VBLANK_HZ, &dInt); - - // integer part - editor.vblankTimeLen = (int32_t)dInt; - - // fractional part (scaled to 0..2^32-1) - dFrac *= UINT32_MAX+1.0; - editor.vblankTimeLenFrac = (uint32_t)dFrac; -} - -void setupWaitVBL(void) -{ - // set next frame time - timeNext64 = SDL_GetPerformanceCounter() + editor.vblankTimeLen; - timeNext64Frac = editor.vblankTimeLenFrac; -} - -void waitVBL(void) -{ - // this routine almost never delays if we have 60Hz vsync, but it's still needed in some occasions - - uint64_t time64 = SDL_GetPerformanceCounter(); - if (time64 < timeNext64) - { - time64 = timeNext64 - time64; - if (time64 > UINT32_MAX) - time64 = UINT32_MAX; - - const uint32_t diff32 = (uint32_t)time64; - - // convert to microseconds and round to integer - const int32_t time32 = (int32_t)((diff32 * editor.dPerfFreqMulMicro) + 0.5); - - // delay until we have reached the next frame - if (time32 > 0) - usleep(time32); - } - - // update next tick time - timeNext64 += editor.vblankTimeLen; - timeNext64Frac += editor.vblankTimeLenFrac; - if (timeNext64Frac > 0xFFFFFFFF) - { - timeNext64Frac &= 0xFFFFFFFF; - timeNext64++; - } -} - void renderFrame(void) { updateMOD2WAVDialog(); // must be first to avoid flickering issues @@ -491,19 +433,30 @@ void updateSongInfo1(void) // left side of screen, when Disk Op. is hidden { ui.updateCurrSampleLength = false; if (!editor.isWAVRendering) - printFourHexBg(64, 69, *currSample->lengthDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + { + if (config.maxSampleLength == 0xFFFE) + printFourHexBg(64, 69, *currSample->lengthDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + else + printFiveHexBg(56, 69, *currSample->lengthDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + } } if (ui.updateCurrSampleRepeat) { ui.updateCurrSampleRepeat = false; - printFourHexBg(64, 80, *currSample->loopStartDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + if (config.maxSampleLength == 0xFFFE) + printFourHexBg(64, 80, *currSample->loopStartDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + else + printFiveHexBg(56, 80, *currSample->loopStartDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); } if (ui.updateCurrSampleReplen) { ui.updateCurrSampleReplen = false; - printFourHexBg(64, 91, *currSample->loopLengthDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + if (config.maxSampleLength == 0xFFFE) + printFourHexBg(64, 91, *currSample->loopLengthDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + else + printFiveHexBg(56, 91, *currSample->loopLengthDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); } } @@ -712,9 +665,7 @@ void updateSampler(void) { if (!ui.samplerVolBoxShown && !ui.samplerFiltersBoxShown && s->length > 0) { - tmpSampleOffset = (scr2SmpPos(mouse.x-3) + (1 << 7)) >> 8; // rounded - tmpSampleOffset = 0x900 + CLAMP(tmpSampleOffset, 0x00, 0xFF); - + tmpSampleOffset = 0x900 + (scr2SmpPos(mouse.x-3) >> 8); if (tmpSampleOffset != ui.lastSampleOffset) { ui.lastSampleOffset = (uint16_t)tmpSampleOffset; @@ -727,7 +678,10 @@ void updateSampler(void) if (ui.update9xxPos) { ui.update9xxPos = false; - printThreeHexBg(288, 247, ui.lastSampleOffset, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + if (ui.lastSampleOffset <= 0x900 || ui.lastSampleOffset > 0x9FF) + textOutBg(288, 247, "---", video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + else + printThreeHexBg(288, 247, ui.lastSampleOffset, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); } if (ui.updateResampleNote) @@ -1239,6 +1193,15 @@ void renderEditOpScreen(void) blit32(120, 44, 200, 55, srcPtr); + // fix graphics in 128K sample mode + if (config.maxSampleLength != 65534) + { + if (ui.editOpScreen == 2) + blit32(213, 55, 32, 11, fix128KPosBMP); + else if (ui.editOpScreen == 3) + blit32(120, 88, 48, 11, fix128KChordBMP); + } + renderEditOpMode(); // render text and content @@ -1271,11 +1234,11 @@ void renderEditOpScreen(void) { textOut(128, 47, " SAMPLE CHORD EDITOR ", video.palette[PAL_GENTXT]); - ui.updateLengthText = true; - ui.updateNote1Text = true; - ui.updateNote2Text = true; - ui.updateNote3Text = true; - ui.updateNote4Text = true; + ui.updateChordLengthText = true; + ui.updateChordNote1Text = true; + ui.updateChordNote2Text = true; + ui.updateChordNote3Text = true; + ui.updateChordNote4Text = true; } } @@ -1414,7 +1377,10 @@ void updateEditOp(void) if (ui.updatePosText) { ui.updatePosText = false; - printFourHexBg(248, 58, *editor.samplePosDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + if (config.maxSampleLength == 0xFFFE) + printFourHexBg(248, 58, *editor.samplePosDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + else + printFiveHexBg(240, 58, *editor.samplePosDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); } if (ui.updateModText) @@ -1438,13 +1404,17 @@ void updateEditOp(void) } else if (ui.editOpScreen == 3) { - if (ui.updateLengthText) + if (ui.updateChordLengthText) { - ui.updateLengthText = false; + ui.updateChordLengthText = false; // clear background - textOutBg(168, 91, " ", video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); - charOut(198, 91, ':', video.palette[PAL_GENBKG]); + if (config.maxSampleLength != 65534) + textOutBg(160, 91, " ", video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + else + textOutBg(168, 91, " ", video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); + + charOut(198, 91, ':', video.palette[PAL_GENBKG]); if (song->samples[editor.currSample].loopLength > 2 || song->samples[editor.currSample].loopStart >= 2) { @@ -1452,14 +1422,18 @@ void updateEditOp(void) } else { - printFourHex(168, 91, *editor.chordLengthDisp, video.palette[PAL_GENTXT]); // chord max length + if (config.maxSampleLength == 0xFFFE) + printFourHex(168, 91, *editor.chordLengthDisp, video.palette[PAL_GENTXT]); // chord max length + else + printFiveHex(160, 91, *editor.chordLengthDisp, video.palette[PAL_GENTXT]); // chord max length + charOut(198, 91, (editor.chordLengthMin) ? '.' : ':', video.palette[PAL_GENTXT]); // min/max flag } } - if (ui.updateNote1Text) + if (ui.updateChordNote1Text) { - ui.updateNote1Text = false; + ui.updateChordNote1Text = false; if (editor.note1 > 35) textOutBg(256, 58, "---", video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); else @@ -1467,9 +1441,9 @@ void updateEditOp(void) video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); } - if (ui.updateNote2Text) + if (ui.updateChordNote2Text) { - ui.updateNote2Text = false; + ui.updateChordNote2Text = false; if (editor.note2 > 35) textOutBg(256, 69, "---", video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); else @@ -1477,9 +1451,9 @@ void updateEditOp(void) video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); } - if (ui.updateNote3Text) + if (ui.updateChordNote3Text) { - ui.updateNote3Text = false; + ui.updateChordNote3Text = false; if (editor.note3 > 35) textOutBg(256, 80, "---", video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); else @@ -1487,9 +1461,9 @@ void updateEditOp(void) video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); } - if (ui.updateNote4Text) + if (ui.updateChordNote4Text) { - ui.updateNote4Text = false; + ui.updateChordNote4Text = false; if (editor.note4 > 35) textOutBg(256, 91, "---", video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]); else @@ -1524,14 +1498,26 @@ void displayMainScreen(void) if (ui.samplerScreenShown) { if (!ui.diskOpScreenShown) + { blit32(0, 0, 320, 121, trackerFrameBMP); + + if (config.maxSampleLength != 65534) + blit32(1, 65, 62, 34, fix128KTrackerBMP); // fix for 128kB support mode + } } else { if (!ui.diskOpScreenShown) + { blit32(0, 0, 320, 255, trackerFrameBMP); + + if (config.maxSampleLength != 65534) + blit32(1, 65, 62, 34, fix128KTrackerBMP); // fix for 128kB support mode + } else + { blit32(0, 121, 320, 134, &trackerFrameBMP[121 * SCREEN_W]); + } ui.updateSongBPM = true; ui.updateCurrPattText = true; @@ -1759,7 +1745,7 @@ void handleAskYes(void) s->loopLength = 2; memset(s->text, 0, sizeof (s->text)); - memset(&song->sampleData[(editor.currSample * MAX_SAMPLE_LEN)], 0, MAX_SAMPLE_LEN); + memset(&song->sampleData[(editor.currSample * config.maxSampleLength)], 0, config.maxSampleLength); editor.samplePos = 0; updateCurrSample(); @@ -2121,7 +2107,8 @@ void flipFrame(void) if (!video.vsync60HzPresent) { - waitVBL(); // we have no VSync, do crude thread sleeping to sync to ~60Hz + // we have no VSync, do crude thread sleeping to sync to ~60Hz + hpc_Wait(&video.vblankHpc); } else { @@ -2131,14 +2118,14 @@ void flipFrame(void) #ifdef __APPLE__ // macOS: VSync gets disabled if the window is 100% covered by another window. Let's add a (crude) fix: if (minimized || !(windowFlags & SDL_WINDOW_INPUT_FOCUS)) - waitVBL(); + hpc_Wait(&video.vblankHpc); #elif __unix__ // *NIX: VSync gets disabled in fullscreen mode (at least on some distros/systems). Let's add a fix: if (minimized || video.fullscreen) - waitVBL(); + hpc_Wait(&video.vblankHpc); #else if (minimized) - waitVBL(); + hpc_Wait(&video.vblankHpc); #endif } } diff --git a/src/pt2_visuals.h b/src/pt2_visuals.h index 1cc15b1..9534b9d 100644 --- a/src/pt2_visuals.h +++ b/src/pt2_visuals.h @@ -3,6 +3,7 @@ #include #include #include "pt2_header.h" +#include "pt2_hpc.h" enum { @@ -35,9 +36,6 @@ void statusSampleIsEmpty(void); void statusNotSampleZero(void); void changeStatusText(const char *text); -void setupPerfFreq(void); -void setupWaitVBL(void); -void waitVBL(void); void resetAllScreens(void); void handleAskNo(void); void handleAskYes(void); diff --git a/vs2019_project/pt2-clone/protracker.ini b/vs2019_project/pt2-clone/protracker.ini index 05efeaa..9b0e8d6 100644 --- a/vs2019_project/pt2-clone/protracker.ini +++ b/vs2019_project/pt2-clone/protracker.ini @@ -11,6 +11,25 @@ ; ENTRY=VALUE (only strings can have spaces!) ; +[SAMPLE LENGTH LIMIT] +; Limit samples to 64kB (65534/$FFFE), like intended in ProTracker +; Syntax: TRUE or FALSE +; Default value: TRUE +; Comment: Setting it to FALSE will remove the 64kB (65534/$FFFE) sample +; length limit and support 128kB samples (131070/$1FFFE). +; Keep in mind that >64kB samples are not officially supported in most +; ProTracker trackers and replayers, and will often result in bugs. +; +; CAUTION: The 9xx command (Set Sample Offset) doesn't work at all if +; the sample length is above 65534/$FFFE. This is a known bug +; in all ProTracker versions. I am not fixing this bug as I +; want to keep the ProTracker 2.3D replayer quirks. +; +; Please do not change this setting unless you're aware of the problems +; you might face when creating >64k-sample PT MODs! +; +64K_LIMIT=TRUE + [VIDEO SETTINGS] ; Video scaling factor ; Syntax: 1X, 2X, 3X ... 9X diff --git a/vs2019_project/pt2-clone/pt2-clone.vcxproj b/vs2019_project/pt2-clone/pt2-clone.vcxproj index 20fd92b..e93ff7c 100644 --- a/vs2019_project/pt2-clone/pt2-clone.vcxproj +++ b/vs2019_project/pt2-clone/pt2-clone.vcxproj @@ -246,6 +246,7 @@ + @@ -297,6 +298,7 @@ + diff --git a/vs2019_project/pt2-clone/pt2-clone.vcxproj.filters b/vs2019_project/pt2-clone/pt2-clone.vcxproj.filters index e15ca97..57b86d2 100644 --- a/vs2019_project/pt2-clone/pt2-clone.vcxproj.filters +++ b/vs2019_project/pt2-clone/pt2-clone.vcxproj.filters @@ -105,6 +105,9 @@ headers + + headers + @@ -194,6 +197,7 @@ +