// for finding memory leaks in debug mode with Visual Studio #if defined _DEBUG && defined _MSC_VER#include <crtdbg.h>#endif #include <stdio.h>#include <stdlib.h>#include <stdint.h>#include <stdbool.h>#include <math.h>#include "pt2_helpers.h"#include "pt2_textout.h"#include "pt2_audio.h"#include "pt2_tables.h"#include "pt2_visuals.h"#include "pt2_scopes.h"#include "pt2_sampler.h"#include "pt2_config.h"#include "pt2_bmp.h"#include "pt2_rcfilters.h"#include "pt2_chordmaker.h"#include "pt2_replayer.h"#include "pt2_visuals_sync.h" #define CENTER_LINE_COLOR 0x303030#define MARK_COLOR_1 0x666666 /* inverted background */#define MARK_COLOR_2 0xCCCCCC /* inverted waveform */#define MARK_COLOR_3 0x7D7D7D /* inverted center line */ #define SAMPLE_AREA_Y_CENTER 169#define SAMPLE_AREA_HEIGHT 64 static int32_t samOffsetScaled, lastDrawX, lastDrawY;static uint16_t TToneBit;static uint32_t waveInvertTable[8]; sampler_t sampler; // globalized static const int8_t tuneToneData[32] = // Tuning Tone (sine, regenerated with 127-scale instead of 128){ 0, 25, 49, 71, 90, 106, 117, 125, 127, 125, 117, 106, 90, 71, 49, 25, 0, -25, -49, -71, -90, -106, -117, -125, -127, -125, -117, -106, -90, -71, -49, -25}; void killSample(void){ if (editor.sampleZero) { statusNotSampleZero(); return; } turnOffVoices(); moduleSample_t *s = &song->samples[editor.currSample]; s->fineTune = 0; s->volume = 0; s->length = 0; s->loopStart = 0; s->loopLength = 2; memset(s->text, 0, sizeof (s->text)); memset(&song->sampleData[(editor.currSample * config.maxSampleLength)], 0, config.maxSampleLength); editor.samplePos = 0; updateCurrSample(); ui.updateSongSize = true; updateWindowTitle(MOD_IS_MODIFIED);} void upSample(void){ if (editor.sampleZero) { statusNotSampleZero(); return; } moduleSample_t *s = &song->samples[editor.currSample]; int32_t newLength = (s->length >> 1) & config.maxSampleLength; if (newLength < 2) return; turnOffVoices(); // upsample int8_t *ptr8 = &song->sampleData[s->offset]; for (int32_t i = 0; i < newLength; i++) ptr8[i] = ptr8[i << 1]; // clear junk after shrunk sample if (newLength < config.maxSampleLength) memset(&ptr8[newLength], 0, config.maxSampleLength - newLength); s->length = newLength; s->loopStart = (s->loopStart >> 1) & ~1; s->loopLength = (s->loopLength >> 1) & ~1; if (s->loopLength < 2) { s->loopStart = 0; s->loopLength = 2; } fixSampleBeep(s); updateCurrSample(); ui.updateSongSize = true; updateWindowTitle(MOD_IS_MODIFIED);} void downSample(void){ if (editor.sampleZero) { statusNotSampleZero(); return; } moduleSample_t *s = &song->samples[editor.currSample]; int32_t newLength = s->length << 1; if (newLength > config.maxSampleLength) newLength = config.maxSampleLength; turnOffVoices(); // downsample int8_t *ptr8 = &song->sampleData[s->offset]; int8_t *ptr8_2 = ptr8 - 1; for (int32_t i = s->length-1; i > 0; i--) { ptr8[i<<1] = ptr8[i]; ptr8_2[i<<1] = ptr8_2[i]; } s->length = newLength; if (s->loopLength > 2) { int32_t loopStart = s->loopStart << 1; int32_t loopLength = s->loopLength << 1; if (loopStart+loopLength > s->length) { loopStart = 0; loopLength = 2; } s->loopStart = loopStart; s->loopLength = loopLength; } fixSampleBeep(s); updateCurrSample(); ui.updateSongSize = true; updateWindowTitle(MOD_IS_MODIFIED);} void createSampleMarkTable(void){ // used for invertRange() (sample data marking) waveInvertTable[0] = 0x00000000 | video.palette[PAL_BACKGRD]; waveInvertTable[1] = 0x01000000 | video.palette[PAL_QADSCP]; waveInvertTable[2] = 0x02000000 | CENTER_LINE_COLOR; waveInvertTable[3] = 0x03000000; // spacer, not used waveInvertTable[4] = 0x04000000 | MARK_COLOR_1; waveInvertTable[5] = 0x05000000 | MARK_COLOR_2; waveInvertTable[6] = 0x06000000 | MARK_COLOR_3; waveInvertTable[7] = 0x07000000; // spacer, not used} static void updateSamOffset(void){ if (sampler.samDisplay == 0) samOffsetScaled = 0; else samOffsetScaled = (sampler.samOffset * SAMPLE_AREA_WIDTH) / sampler.samDisplay; // truncate here} void fixSampleBeep(moduleSample_t *s){ if (s->length >= 2 && s->loopStart+s->loopLength <= 2) { song->sampleData[s->offset+0] = 0; song->sampleData[s->offset+1] = 0; }} void updateSamplePos(void){ moduleSample_t *s; assert(editor.currSample >= 0 && editor.currSample <= 30); if (editor.currSample >= 0 && editor.currSample <= 30) { s = &song->samples[editor.currSample]; if (editor.samplePos > s->length) editor.samplePos = s->length; if (ui.editOpScreenShown && ui.editOpScreen == 2) ui.updatePosText = true; }} void fillSampleFilterUndoBuffer(void){ moduleSample_t *s; assert(editor.currSample >= 0 && editor.currSample <= 30); if (editor.currSample >= 0 && editor.currSample <= 30) { s = &song->samples[editor.currSample]; memcpy(editor.tempSample, &song->sampleData[s->offset], s->length); }} void sampleLine(int32_t line_x1, int32_t line_x2, int32_t line_y1, int32_t line_y2){ const uint32_t color = 0x01000000 | video.palette[PAL_QADSCP]; // set alpha to 0x10 ( used for invertRange() as a hack ) assert(line_x1 >= 0 || line_x2 >= 0 || line_x1 < SCREEN_W || line_x2 < SCREEN_W); assert(line_y1 >= 0 || line_y2 >= 0 || line_y1 < SCREEN_H || line_y2 < SCREEN_H); int32_t dx = line_x2 - line_x1; int32_t ax = ABS(dx) * 2; int32_t sx = SGN(dx); int32_t dy = line_y2 - line_y1; int32_t ay = ABS(dy) * 2; int32_t sy = SGN(dy); int32_t x = line_x1; int32_t y = line_y1; if (ax > ay) { int32_t d = ay - ((uint16_t)ax >> 1); while (true) { assert(y >= 0 || x >= 0 || y < SCREEN_H || x < SCREEN_W); video.frameBuffer[(y * SCREEN_W) + x] = color; if (x == line_x2) break; if (d >= 0) { y += sy; d -= ax; } x += sx; d += ay; } } else { int32_t d = ax - ((uint16_t)ay >> 1); while (true) { assert(y >= 0 || x >= 0 || y < SCREEN_H || x < SCREEN_W); video.frameBuffer[(y * SCREEN_W) + x] = color; if (y == line_y2) break; if (d >= 0) { x += sx; d -= ay; } y += sy; d += ax; } }} static void setDragBar(void){ // clear drag bar background fillRect(4, 206, 312, 4, video.palette[PAL_BACKGRD]); if (sampler.samLength > 0 && sampler.samDisplay != sampler.samLength) { const int32_t roundingBias = sampler.samLength >> 1; // update drag bar coordinates int32_t pos = 4 + (((sampler.samOffset * 311) + roundingBias) / sampler.samLength); sampler.dragStart = (uint16_t)CLAMP(pos, 4, 315); pos = 5 + ((((sampler.samDisplay + sampler.samOffset) * 311) + roundingBias) / sampler.samLength); sampler.dragEnd = (uint16_t)CLAMP(pos, 5, 316); if (sampler.dragStart > sampler.dragEnd-1) sampler.dragStart = sampler.dragEnd-1; // draw drag bar const uint32_t dragWidth = sampler.dragEnd - sampler.dragStart; if (dragWidth > 0) fillRect(sampler.dragStart, 206, dragWidth, 4, video.palette[PAL_QADSCP]); }} static int8_t getScaledSample(int32_t index){ if (sampler.samLength <= 0 || index < 0 || index > sampler.samLength) return 0; const int8_t *ptr8 = sampler.samStart; if (ptr8 == NULL) return 0; return ptr8[index] >> 2;} int32_t smpPos2Scr(int32_t pos) // sample pos -> screen x pos{ if (sampler.samDisplay == 0) return 0; const uint32_t roundingBias = (const uint32_t)sampler.samDisplay >> 1; pos = (((uint32_t)pos * SAMPLE_AREA_WIDTH) + roundingBias) / (uint32_t)sampler.samDisplay; // rounded pos -= samOffsetScaled; return pos;} int32_t scr2SmpPos(int32_t x) // screen x pos -> sample pos{ if (sampler.samDisplay == 0) return 0; if (x < 0) x = 0; x += samOffsetScaled; x = (uint32_t)(x * sampler.samDisplay) / SAMPLE_AREA_WIDTH; // truncate here if (x > sampler.samLength) x = sampler.samLength; return x;} static void getSampleDataPeak(int8_t *smpPtr, int32_t numBytes, int16_t *outMin, int16_t *outMax){ int8_t smpMin = 127; int8_t smpMax = -128; for (int32_t i = 0; i < numBytes; i++) { int8_t smp = smpPtr[i]; if (smp < smpMin) smpMin = smp; if (smp > smpMax) smpMax = smp; } *outMin = SAMPLE_AREA_Y_CENTER - (smpMin >> 2); *outMax = SAMPLE_AREA_Y_CENTER - (smpMax >> 2);} void renderSampleData(void){ moduleSample_t *s = &song->samples[editor.currSample]; // clear sample data background fillRect(3, 138, SAMPLE_AREA_WIDTH, SAMPLE_VIEW_HEIGHT, video.palette[PAL_BACKGRD]); // display center line (if enabled) if (config.waveformCenterLine) { uint32_t *dstPtr = &video.frameBuffer[(SAMPLE_AREA_Y_CENTER * SCREEN_W) + 3]; for (int32_t x = 0; x < SAMPLE_AREA_WIDTH; x++) dstPtr[x] = 0x02000000 | CENTER_LINE_COLOR; } // render sample data if (sampler.samDisplay >= 0 && sampler.samDisplay <= config.maxSampleLength) { int16_t y1 = SAMPLE_AREA_Y_CENTER - getScaledSample(scr2SmpPos(0)); if (sampler.samDisplay <= SAMPLE_AREA_WIDTH) { // 1:1 or zoomed in for (int32_t x = 1; x < SAMPLE_AREA_WIDTH; x++) { int16_t y2 = SAMPLE_AREA_Y_CENTER - getScaledSample(scr2SmpPos(x)); sampleLine(x + 2, x + 3, y1, y2); y1 = y2; } } else { // zoomed out int16_t min, max; int16_t oldMin = y1; int16_t oldMax = y1; int8_t *smpPtr = &song->sampleData[s->offset]; for (int32_t x = 0; x < SAMPLE_AREA_WIDTH; x++) { int32_t smpIdx = scr2SmpPos(x); int32_t smpNum = scr2SmpPos(x+1) - smpIdx; // prevent look-up overflow (yes, this can happen near the end of the sample) if (smpIdx+smpNum > sampler.samLength) smpNum = sampler.samLength - smpNum; if (smpNum < 1) smpNum = 1; getSampleDataPeak(&smpPtr[smpIdx], smpNum, &min, &max); if (x > 0) { if (min > oldMax) sampleLine(x + 2, x + 3, oldMax, min); if (max < oldMin) sampleLine(x + 2, x + 3, oldMin, max); } sampleLine(x + 3, x + 3, max, min); oldMin = min; oldMax = max; } } } if (ui.samplingBoxShown) return; // render "sample display" text 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 { 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();} void invertRange(void){ if (editor.markStartOfs == -1) return; // no marking int32_t start = smpPos2Scr(editor.markStartOfs); int32_t end = smpPos2Scr(editor.markEndOfs); if (sampler.samDisplay < sampler.samLength && (start >= SAMPLE_AREA_WIDTH || end < 0)) return; // range is outside of view start = CLAMP(start, 0, SAMPLE_AREA_WIDTH-1); end = CLAMP(end, 0, SAMPLE_AREA_WIDTH-1); int32_t rangeLen = (end + 1) - start; if (rangeLen < 1) rangeLen = 1; uint32_t *dstPtr = &video.frameBuffer[(138 * SCREEN_W) + (start + 3)]; for (int32_t y = 0; y < 64; y++) { for (int32_t x = 0; x < rangeLen; x++) dstPtr[x] = waveInvertTable[((dstPtr[x] >> 24) & 7) ^ 4]; // ptr[x]>>24 = wave/invert color number dstPtr += SCREEN_W; }} void displaySample(void){ if (!ui.samplerScreenShown) return; renderSampleData(); if (editor.markStartOfs != -1) invertRange(); Lines 1–500 of 2605. Load more
// for finding memory leaks in debug mode with Visual Studio #if defined _DEBUG && defined _MSC_VER #include <crtdbg.h> #endif #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <stdbool.h> #include <math.h> #include "pt2_helpers.h" #include "pt2_textout.h" #include "pt2_audio.h" #include "pt2_tables.h" #include "pt2_visuals.h" #include "pt2_scopes.h" #include "pt2_sampler.h" #include "pt2_config.h" #include "pt2_bmp.h" #include "pt2_rcfilters.h" #include "pt2_chordmaker.h" #include "pt2_replayer.h" #include "pt2_visuals_sync.h" #define CENTER_LINE_COLOR 0x303030 #define MARK_COLOR_1 0x666666 /* inverted background */ #define MARK_COLOR_2 0xCCCCCC /* inverted waveform */ #define MARK_COLOR_3 0x7D7D7D /* inverted center line */ #define SAMPLE_AREA_Y_CENTER 169 #define SAMPLE_AREA_HEIGHT 64 static int32_t samOffsetScaled, lastDrawX, lastDrawY; static uint16_t TToneBit; static uint32_t waveInvertTable[8]; sampler_t sampler; // globalized static const int8_t tuneToneData[32] = // Tuning Tone (sine, regenerated with 127-scale instead of 128) { 0, 25, 49, 71, 90, 106, 117, 125, 127, 125, 117, 106, 90, 71, 49, 25, 0, -25, -49, -71, -90, -106, -117, -125, -127, -125, -117, -106, -90, -71, -49, -25 }; void killSample(void) { if (editor.sampleZero) { statusNotSampleZero(); return; } turnOffVoices(); moduleSample_t *s = &song->samples[editor.currSample]; s->fineTune = 0; s->volume = 0; s->length = 0; s->loopStart = 0; s->loopLength = 2; memset(s->text, 0, sizeof (s->text)); memset(&song->sampleData[(editor.currSample * config.maxSampleLength)], 0, config.maxSampleLength); editor.samplePos = 0; updateCurrSample(); ui.updateSongSize = true; updateWindowTitle(MOD_IS_MODIFIED); } void upSample(void) { if (editor.sampleZero) { statusNotSampleZero(); return; } moduleSample_t *s = &song->samples[editor.currSample]; int32_t newLength = (s->length >> 1) & config.maxSampleLength; if (newLength < 2) return; turnOffVoices(); // upsample int8_t *ptr8 = &song->sampleData[s->offset]; for (int32_t i = 0; i < newLength; i++) ptr8[i] = ptr8[i << 1]; // clear junk after shrunk sample if (newLength < config.maxSampleLength) memset(&ptr8[newLength], 0, config.maxSampleLength - newLength); s->length = newLength; s->loopStart = (s->loopStart >> 1) & ~1; s->loopLength = (s->loopLength >> 1) & ~1; if (s->loopLength < 2) { s->loopStart = 0; s->loopLength = 2; } fixSampleBeep(s); updateCurrSample(); ui.updateSongSize = true; updateWindowTitle(MOD_IS_MODIFIED); } void downSample(void) { if (editor.sampleZero) { statusNotSampleZero(); return; } moduleSample_t *s = &song->samples[editor.currSample]; int32_t newLength = s->length << 1; if (newLength > config.maxSampleLength) newLength = config.maxSampleLength; turnOffVoices(); // downsample int8_t *ptr8 = &song->sampleData[s->offset]; int8_t *ptr8_2 = ptr8 - 1; for (int32_t i = s->length-1; i > 0; i--) { ptr8[i<<1] = ptr8[i]; ptr8_2[i<<1] = ptr8_2[i]; } s->length = newLength; if (s->loopLength > 2) { int32_t loopStart = s->loopStart << 1; int32_t loopLength = s->loopLength << 1; if (loopStart+loopLength > s->length) { loopStart = 0; loopLength = 2; } s->loopStart = loopStart; s->loopLength = loopLength; } fixSampleBeep(s); updateCurrSample(); ui.updateSongSize = true; updateWindowTitle(MOD_IS_MODIFIED); } void createSampleMarkTable(void) { // used for invertRange() (sample data marking) waveInvertTable[0] = 0x00000000 | video.palette[PAL_BACKGRD]; waveInvertTable[1] = 0x01000000 | video.palette[PAL_QADSCP]; waveInvertTable[2] = 0x02000000 | CENTER_LINE_COLOR; waveInvertTable[3] = 0x03000000; // spacer, not used waveInvertTable[4] = 0x04000000 | MARK_COLOR_1; waveInvertTable[5] = 0x05000000 | MARK_COLOR_2; waveInvertTable[6] = 0x06000000 | MARK_COLOR_3; waveInvertTable[7] = 0x07000000; // spacer, not used } static void updateSamOffset(void) { if (sampler.samDisplay == 0) samOffsetScaled = 0; else samOffsetScaled = (sampler.samOffset * SAMPLE_AREA_WIDTH) / sampler.samDisplay; // truncate here } void fixSampleBeep(moduleSample_t *s) { if (s->length >= 2 && s->loopStart+s->loopLength <= 2) { song->sampleData[s->offset+0] = 0; song->sampleData[s->offset+1] = 0; } } void updateSamplePos(void) { moduleSample_t *s; assert(editor.currSample >= 0 && editor.currSample <= 30); if (editor.currSample >= 0 && editor.currSample <= 30) { s = &song->samples[editor.currSample]; if (editor.samplePos > s->length) editor.samplePos = s->length; if (ui.editOpScreenShown && ui.editOpScreen == 2) ui.updatePosText = true; } } void fillSampleFilterUndoBuffer(void) { moduleSample_t *s; assert(editor.currSample >= 0 && editor.currSample <= 30); if (editor.currSample >= 0 && editor.currSample <= 30) { s = &song->samples[editor.currSample]; memcpy(editor.tempSample, &song->sampleData[s->offset], s->length); } } void sampleLine(int32_t line_x1, int32_t line_x2, int32_t line_y1, int32_t line_y2) { const uint32_t color = 0x01000000 | video.palette[PAL_QADSCP]; // set alpha to 0x10 ( used for invertRange() as a hack ) assert(line_x1 >= 0 || line_x2 >= 0 || line_x1 < SCREEN_W || line_x2 < SCREEN_W); assert(line_y1 >= 0 || line_y2 >= 0 || line_y1 < SCREEN_H || line_y2 < SCREEN_H); int32_t dx = line_x2 - line_x1; int32_t ax = ABS(dx) * 2; int32_t sx = SGN(dx); int32_t dy = line_y2 - line_y1; int32_t ay = ABS(dy) * 2; int32_t sy = SGN(dy); int32_t x = line_x1; int32_t y = line_y1; if (ax > ay) { int32_t d = ay - ((uint16_t)ax >> 1); while (true) { assert(y >= 0 || x >= 0 || y < SCREEN_H || x < SCREEN_W); video.frameBuffer[(y * SCREEN_W) + x] = color; if (x == line_x2) break; if (d >= 0) { y += sy; d -= ax; } x += sx; d += ay; } } else { int32_t d = ax - ((uint16_t)ay >> 1); while (true) { assert(y >= 0 || x >= 0 || y < SCREEN_H || x < SCREEN_W); video.frameBuffer[(y * SCREEN_W) + x] = color; if (y == line_y2) break; if (d >= 0) { x += sx; d -= ay; } y += sy; d += ax; } } } static void setDragBar(void) { // clear drag bar background fillRect(4, 206, 312, 4, video.palette[PAL_BACKGRD]); if (sampler.samLength > 0 && sampler.samDisplay != sampler.samLength) { const int32_t roundingBias = sampler.samLength >> 1; // update drag bar coordinates int32_t pos = 4 + (((sampler.samOffset * 311) + roundingBias) / sampler.samLength); sampler.dragStart = (uint16_t)CLAMP(pos, 4, 315); pos = 5 + ((((sampler.samDisplay + sampler.samOffset) * 311) + roundingBias) / sampler.samLength); sampler.dragEnd = (uint16_t)CLAMP(pos, 5, 316); if (sampler.dragStart > sampler.dragEnd-1) sampler.dragStart = sampler.dragEnd-1; // draw drag bar const uint32_t dragWidth = sampler.dragEnd - sampler.dragStart; if (dragWidth > 0) fillRect(sampler.dragStart, 206, dragWidth, 4, video.palette[PAL_QADSCP]); } } static int8_t getScaledSample(int32_t index) { if (sampler.samLength <= 0 || index < 0 || index > sampler.samLength) return 0; const int8_t *ptr8 = sampler.samStart; if (ptr8 == NULL) return 0; return ptr8[index] >> 2; } int32_t smpPos2Scr(int32_t pos) // sample pos -> screen x pos { if (sampler.samDisplay == 0) return 0; const uint32_t roundingBias = (const uint32_t)sampler.samDisplay >> 1; pos = (((uint32_t)pos * SAMPLE_AREA_WIDTH) + roundingBias) / (uint32_t)sampler.samDisplay; // rounded pos -= samOffsetScaled; return pos; } int32_t scr2SmpPos(int32_t x) // screen x pos -> sample pos { if (sampler.samDisplay == 0) return 0; if (x < 0) x = 0; x += samOffsetScaled; x = (uint32_t)(x * sampler.samDisplay) / SAMPLE_AREA_WIDTH; // truncate here if (x > sampler.samLength) x = sampler.samLength; return x; } static void getSampleDataPeak(int8_t *smpPtr, int32_t numBytes, int16_t *outMin, int16_t *outMax) { int8_t smpMin = 127; int8_t smpMax = -128; for (int32_t i = 0; i < numBytes; i++) { int8_t smp = smpPtr[i]; if (smp < smpMin) smpMin = smp; if (smp > smpMax) smpMax = smp; } *outMin = SAMPLE_AREA_Y_CENTER - (smpMin >> 2); *outMax = SAMPLE_AREA_Y_CENTER - (smpMax >> 2); } void renderSampleData(void) { moduleSample_t *s = &song->samples[editor.currSample]; // clear sample data background fillRect(3, 138, SAMPLE_AREA_WIDTH, SAMPLE_VIEW_HEIGHT, video.palette[PAL_BACKGRD]); // display center line (if enabled) if (config.waveformCenterLine) { uint32_t *dstPtr = &video.frameBuffer[(SAMPLE_AREA_Y_CENTER * SCREEN_W) + 3]; for (int32_t x = 0; x < SAMPLE_AREA_WIDTH; x++) dstPtr[x] = 0x02000000 | CENTER_LINE_COLOR; } // render sample data if (sampler.samDisplay >= 0 && sampler.samDisplay <= config.maxSampleLength) { int16_t y1 = SAMPLE_AREA_Y_CENTER - getScaledSample(scr2SmpPos(0)); if (sampler.samDisplay <= SAMPLE_AREA_WIDTH) { // 1:1 or zoomed in for (int32_t x = 1; x < SAMPLE_AREA_WIDTH; x++) { int16_t y2 = SAMPLE_AREA_Y_CENTER - getScaledSample(scr2SmpPos(x)); sampleLine(x + 2, x + 3, y1, y2); y1 = y2; } } else { // zoomed out int16_t min, max; int16_t oldMin = y1; int16_t oldMax = y1; int8_t *smpPtr = &song->sampleData[s->offset]; for (int32_t x = 0; x < SAMPLE_AREA_WIDTH; x++) { int32_t smpIdx = scr2SmpPos(x); int32_t smpNum = scr2SmpPos(x+1) - smpIdx; // prevent look-up overflow (yes, this can happen near the end of the sample) if (smpIdx+smpNum > sampler.samLength) smpNum = sampler.samLength - smpNum; if (smpNum < 1) smpNum = 1; getSampleDataPeak(&smpPtr[smpIdx], smpNum, &min, &max); if (x > 0) { if (min > oldMax) sampleLine(x + 2, x + 3, oldMax, min); if (max < oldMin) sampleLine(x + 2, x + 3, oldMin, max); } sampleLine(x + 3, x + 3, max, min); oldMin = min; oldMax = max; } } } if (ui.samplingBoxShown) return; // render "sample display" text 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 { 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(); } void invertRange(void) { if (editor.markStartOfs == -1) return; // no marking int32_t start = smpPos2Scr(editor.markStartOfs); int32_t end = smpPos2Scr(editor.markEndOfs); if (sampler.samDisplay < sampler.samLength && (start >= SAMPLE_AREA_WIDTH || end < 0)) return; // range is outside of view start = CLAMP(start, 0, SAMPLE_AREA_WIDTH-1); end = CLAMP(end, 0, SAMPLE_AREA_WIDTH-1); int32_t rangeLen = (end + 1) - start; if (rangeLen < 1) rangeLen = 1; uint32_t *dstPtr = &video.frameBuffer[(138 * SCREEN_W) + (start + 3)]; for (int32_t y = 0; y < 64; y++) { for (int32_t x = 0; x < rangeLen; x++) dstPtr[x] = waveInvertTable[((dstPtr[x] >> 24) & 7) ^ 4]; // ptr[x]>>24 = wave/invert color number dstPtr += SCREEN_W; } } void displaySample(void) { if (!ui.samplerScreenShown) return; renderSampleData(); if (editor.markStartOfs != -1) invertRange();