/* This file contains the routines for the following sample editor functions:** - Resampler** - Echo** - Mix** - Volume**/ // for finding memory leaks in debug mode with Visual Studio#if defined _DEBUG && defined _MSC_VER#include <crtdbg.h>#endif #include <stdio.h>#include <stdint.h>#include <stdbool.h>#include <math.h>#include "ft2_header.h"#include "ft2_mouse.h"#include "ft2_audio.h"#include "ft2_gui.h"#include "ft2_events.h"#include "ft2_video.h"#include "ft2_inst_ed.h"#include "ft2_sample_ed.h"#include "ft2_keyboard.h"#include "ft2_tables.h"#include "ft2_structs.h" static volatile bool stopThread; static int8_t smpEd_RelReSmp, mix_Balance = 50;static bool echo_AddMemory, exitFlag, outOfMemory;static int16_t echo_nEcho = 1, echo_VolChange = 30;static int32_t echo_Distance = 0x100;static double dVol_StartVol = 100.0, dVol_EndVol = 100.0;static SDL_Thread *thread; static void pbExit(void){ ui.sysReqShown = false; exitFlag = true;} static void windowOpen(void){ ui.sysReqShown = true; ui.sysReqEnterPressed = false; unstuckLastUsedGUIElement(); SDL_EventState(SDL_DROPFILE, SDL_DISABLE);} static void windowClose(bool rewriteSample){ SDL_EventState(SDL_DROPFILE, SDL_ENABLE); if (exitFlag || rewriteSample) writeSample(true); else updateNewSample(); mouseAnimOff();} static void sbSetResampleTones(uint32_t pos){ if (smpEd_RelReSmp != (int8_t)(pos - 36)) smpEd_RelReSmp = (int8_t)(pos - 36);} static void pbResampleTonesDown(void){ if (smpEd_RelReSmp > -36) smpEd_RelReSmp--;} static void pbResampleTonesUp(void){ if (smpEd_RelReSmp < 36) smpEd_RelReSmp++;} static int32_t SDLCALL resampleThread(void *ptr){ smpPtr_t sp; if (instr[editor.curInstr] == NULL) return true; sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp]; bool sample16Bit = !!(s->flags & SAMPLE_16BIT); const double dRatio = exp2((int32_t)smpEd_RelReSmp / 12.0); double dNewLen = s->length * dRatio; if (dNewLen > (double)MAX_SAMPLE_LEN) dNewLen = (double)MAX_SAMPLE_LEN; const uint32_t newLen = (int32_t)floor(dNewLen); if (!allocateSmpDataPtr(&sp, newLen, sample16Bit)) { outOfMemory = true; setMouseBusy(false); ui.sysReqShown = false; return true; } int8_t *dst = sp.ptr; int8_t *src = s->dataPtr; // 32.32 fixed-point logic const uint64_t delta64 = (const uint64_t)round((UINT32_MAX+1.0) / dRatio); uint64_t posFrac64 = 0; pauseAudio(); unfixSample(s); /* Nearest-neighbor resampling (no interpolation). ** ** Could benefit from windowed-sinc interpolation, ** but it seems like some people prefer no resampling ** interpolation (like FT2). */ if (newLen > 0) { if (sample16Bit) { const int16_t *src16 = (const int16_t *)src; int16_t *dst16 = (int16_t *)dst; for (uint32_t i = 0; i < newLen; i++) { const uint32_t position = posFrac64 >> 32; dst16[i] = src16[position]; posFrac64 += delta64; } } else // 8-bit { const int8_t *src8 = src; int8_t *dst8 = dst; for (uint32_t i = 0; i < newLen; i++) { const uint32_t position = posFrac64 >> 32; dst8[i] = src8[position]; posFrac64 += delta64; } } } freeSmpData(s); setSmpDataPtr(s, &sp); s->relativeNote += smpEd_RelReSmp; s->length = newLen; s->loopStart = (int32_t)(s->loopStart * dRatio); s->loopLength = (int32_t)(s->loopLength * dRatio); sanitizeSample(s); fixSample(s); resumeAudio(); setSongModifiedFlag(); setMouseBusy(false); ui.sysReqShown = false; return true; (void)ptr;} static void pbDoResampling(void){ mouseAnimOn(); thread = SDL_CreateThread(resampleThread, NULL, NULL); if (thread == NULL) { okBox(0, "System message", "Couldn't create thread!"); return; } SDL_DetachThread(thread);} static void drawResampleBox(void){ char sign; const int16_t x = 209; const int16_t y = 230; const int16_t w = 214; const int16_t h = 54; // main fill fillRect(x + 1, y + 1, w - 2, h - 2, PAL_BUTTONS); // outer border vLine(x, y, h - 1, PAL_BUTTON1); hLine(x + 1, y, w - 2, PAL_BUTTON1); vLine(x + w - 1, y, h, PAL_BUTTON2); hLine(x, y + h - 1, w - 1, PAL_BUTTON2); // inner border vLine(x + 2, y + 2, h - 5, PAL_BUTTON2); hLine(x + 3, y + 2, w - 6, PAL_BUTTON2); vLine(x + w - 3, y + 2, h - 4, PAL_BUTTON1); hLine(x + 2, y + h - 3, w - 4, PAL_BUTTON1); sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp]; double dLenMul = exp2(smpEd_RelReSmp * (1.0 / 12.0)); double dNewLen = s->length * dLenMul; if (dNewLen > (double)MAX_SAMPLE_LEN) dNewLen = (double)MAX_SAMPLE_LEN; textOutShadow(215, 236, PAL_FORGRND, PAL_BUTTON2, "Rel. h.tones"); textOutShadow(215, 250, PAL_FORGRND, PAL_BUTTON2, "New sample size"); hexOut(361, 250, PAL_FORGRND, (int32_t)dNewLen, 8); if (smpEd_RelReSmp == 0) sign = ' '; else if (smpEd_RelReSmp < 0) sign = '-'; else sign = '+'; uint16_t val = ABS(smpEd_RelReSmp); if (val > 9) { charOut(291, 236, PAL_FORGRND, sign); charOut(298, 236, PAL_FORGRND, '0' + ((val / 10) % 10)); charOut(305, 236, PAL_FORGRND, '0' + (val % 10)); } else { charOut(298, 236, PAL_FORGRND, sign); charOut(305, 236, PAL_FORGRND, '0' + (val % 10)); }} static void setupResampleBoxWidgets(void){ pushButton_t *p; scrollBar_t *s; // "Apply" pushbutton p = &pushButtons[0]; memset(p, 0, sizeof (pushButton_t)); p->caption = "Apply"; p->x = 214; p->y = 264; p->w = 73; p->h = 16; p->callbackFuncOnUp = pbDoResampling; p->visible = true; // "Exit" pushbutton p = &pushButtons[1]; memset(p, 0, sizeof (pushButton_t)); p->caption = "Exit"; p->x = 345; p->y = 264; p->w = 73; p->h = 16; p->callbackFuncOnUp = pbExit; p->visible = true; // scrollbar buttons p = &pushButtons[2]; memset(p, 0, sizeof (pushButton_t)); p->caption = ARROW_LEFT_STRING; p->x = 314; p->y = 234; p->w = 23; p->h = 13; p->preDelay = 1; p->delayFrames = 3; p->callbackFuncOnDown = pbResampleTonesDown; p->visible = true; p = &pushButtons[3]; memset(p, 0, sizeof (pushButton_t)); p->caption = ARROW_RIGHT_STRING; p->x = 395; p->y = 234; p->w = 23; p->h = 13; p->preDelay = 1; p->delayFrames = 3; p->callbackFuncOnDown = pbResampleTonesUp; p->visible = true; // echo num scrollbar s = &scrollBars[0]; memset(s, 0, sizeof (scrollBar_t)); s->x = 337; s->y = 234; s->w = 58; s->h = 13; s->callbackFunc = sbSetResampleTones; s->visible = true; setScrollBarPageLength(0, 1); setScrollBarEnd(0, 36 * 2);} void pbSampleResample(void){ uint16_t i; if (editor.curInstr == 0 || instr[editor.curInstr] == NULL || instr[editor.curInstr]->smp[editor.curSmp].dataPtr == NULL) { return; } setupResampleBoxWidgets(); windowOpen(); outOfMemory = false; exitFlag = false; while (ui.sysReqShown) { readInput(); if (ui.sysReqEnterPressed) pbDoResampling(); setSyncedReplayerVars(); handleRedrawing(); drawResampleBox(); setScrollBarPos(0, smpEd_RelReSmp + 36, false); drawCheckBox(0); for (i = 0; i < 4; i++) drawPushButton(i); drawScrollBar(0); flipFrame(); } for (i = 0; i < 4; i++) hidePushButton(i); hideScrollBar(0); windowClose(false); if (outOfMemory) okBox(0, "System message", "Not enough memory!");} static void cbEchoAddMemory(void){ echo_AddMemory ^= 1;} static void sbSetEchoNumPos(uint32_t pos){ if (echo_nEcho != (int32_t)pos) echo_nEcho = (int16_t)pos;} static void sbSetEchoDistPos(uint32_t pos){ if (echo_Distance != (int32_t)pos) echo_Distance = (int32_t)pos;} static void sbSetEchoFadeoutPos(uint32_t pos){ if (echo_VolChange != (int32_t)pos) echo_VolChange = (int16_t)pos;} static void pbEchoNumDown(void){ if (echo_nEcho > 0) echo_nEcho--;} static void pbEchoNumUp(void){ if (echo_nEcho < 64) echo_nEcho++;} static void pbEchoDistDown(void){ if (echo_Distance > 0) echo_Distance--;} static void pbEchoDistUp(void){ if (echo_Distance < 16384) echo_Distance++;} static void pbEchoFadeoutDown(void){ if (echo_VolChange > 0) echo_VolChange--;} static void pbEchoFadeoutUp(void){ if (echo_VolChange < 100) echo_VolChange++;} static int32_t SDLCALL createEchoThread(void *ptr){ smpPtr_t sp; if (echo_nEcho < 1) { ui.sysReqShown = false; return true; } sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp]; int32_t readLen = s->length; int8_t *readPtr = s->dataPtr; bool sample16Bit = !!(s->flags & SAMPLE_16BIT); int32_t distance = echo_Distance * 16; double dVolChange = echo_VolChange / 100.0; // calculate real number of echoes double dSmp = sample16Bit ? 32768.0 : 128.0; int32_t k = 0; while (k++ < echo_nEcho && dSmp >= 1.0) dSmp *= dVolChange; int32_t nEchoes = k + 1; if (nEchoes < 1) { ui.sysReqShown = false; return true; } // set write length (either original length or full echo length) int32_t writeLen = readLen; if (echo_AddMemory) { int64_t tmp64 = (int64_t)distance * (nEchoes - 1); tmp64 += writeLen; if (tmp64 > MAX_SAMPLE_LEN) tmp64 = MAX_SAMPLE_LEN; writeLen = (uint32_t)tmp64; } if (!allocateSmpDataPtr(&sp, writeLen, sample16Bit)) { outOfMemory = true; setMouseBusy(false); ui.sysReqShown = false; return false; } pauseAudio(); unfixSample(s); int32_t writeIdx = 0; if (sample16Bit) { const int16_t *readPtr16 = (const int16_t *)readPtr; int16_t *writePtr16 = (int16_t *)sp.ptr; while (writeIdx < writeLen) { double dSmpOut = 0.0; double dSmpMul = 1.0; int32_t echoRead = writeIdx; int32_t echoCycle = nEchoes; while (!stopThread) { if (echoRead < readLen) dSmpOut += (int32_t)readPtr16[echoRead] * dSmpMul; dSmpMul *= dVolChange; echoRead -= distance; if (echoRead <= 0 || --echoCycle <= 0) break; } DROUND(dSmpOut); int32_t smp32 = (int32_t)dSmpOut; CLAMP16(smp32); writePtr16[writeIdx++] = (int16_t)smp32; } } else // 8-bit {Lines 1–500 of 1664. Load more
/* This file contains the routines for the following sample editor functions: ** - Resampler ** - Echo ** - Mix ** - Volume **/ // for finding memory leaks in debug mode with Visual Studio #if defined _DEBUG && defined _MSC_VER #include <crtdbg.h> #endif #include <stdio.h> #include <stdint.h> #include <stdbool.h> #include <math.h> #include "ft2_header.h" #include "ft2_mouse.h" #include "ft2_audio.h" #include "ft2_gui.h" #include "ft2_events.h" #include "ft2_video.h" #include "ft2_inst_ed.h" #include "ft2_sample_ed.h" #include "ft2_keyboard.h" #include "ft2_tables.h" #include "ft2_structs.h" static volatile bool stopThread; static int8_t smpEd_RelReSmp, mix_Balance = 50; static bool echo_AddMemory, exitFlag, outOfMemory; static int16_t echo_nEcho = 1, echo_VolChange = 30; static int32_t echo_Distance = 0x100; static double dVol_StartVol = 100.0, dVol_EndVol = 100.0; static SDL_Thread *thread; static void pbExit(void) { ui.sysReqShown = false; exitFlag = true; } static void windowOpen(void) { ui.sysReqShown = true; ui.sysReqEnterPressed = false; unstuckLastUsedGUIElement(); SDL_EventState(SDL_DROPFILE, SDL_DISABLE); } static void windowClose(bool rewriteSample) { SDL_EventState(SDL_DROPFILE, SDL_ENABLE); if (exitFlag || rewriteSample) writeSample(true); else updateNewSample(); mouseAnimOff(); } static void sbSetResampleTones(uint32_t pos) { if (smpEd_RelReSmp != (int8_t)(pos - 36)) smpEd_RelReSmp = (int8_t)(pos - 36); } static void pbResampleTonesDown(void) { if (smpEd_RelReSmp > -36) smpEd_RelReSmp--; } static void pbResampleTonesUp(void) { if (smpEd_RelReSmp < 36) smpEd_RelReSmp++; } static int32_t SDLCALL resampleThread(void *ptr) { smpPtr_t sp; if (instr[editor.curInstr] == NULL) return true; sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp]; bool sample16Bit = !!(s->flags & SAMPLE_16BIT); const double dRatio = exp2((int32_t)smpEd_RelReSmp / 12.0); double dNewLen = s->length * dRatio; if (dNewLen > (double)MAX_SAMPLE_LEN) dNewLen = (double)MAX_SAMPLE_LEN; const uint32_t newLen = (int32_t)floor(dNewLen); if (!allocateSmpDataPtr(&sp, newLen, sample16Bit)) { outOfMemory = true; setMouseBusy(false); ui.sysReqShown = false; return true; } int8_t *dst = sp.ptr; int8_t *src = s->dataPtr; // 32.32 fixed-point logic const uint64_t delta64 = (const uint64_t)round((UINT32_MAX+1.0) / dRatio); uint64_t posFrac64 = 0; pauseAudio(); unfixSample(s); /* Nearest-neighbor resampling (no interpolation). ** ** Could benefit from windowed-sinc interpolation, ** but it seems like some people prefer no resampling ** interpolation (like FT2). */ if (newLen > 0) { if (sample16Bit) { const int16_t *src16 = (const int16_t *)src; int16_t *dst16 = (int16_t *)dst; for (uint32_t i = 0; i < newLen; i++) { const uint32_t position = posFrac64 >> 32; dst16[i] = src16[position]; posFrac64 += delta64; } } else // 8-bit { const int8_t *src8 = src; int8_t *dst8 = dst; for (uint32_t i = 0; i < newLen; i++) { const uint32_t position = posFrac64 >> 32; dst8[i] = src8[position]; posFrac64 += delta64; } } } freeSmpData(s); setSmpDataPtr(s, &sp); s->relativeNote += smpEd_RelReSmp; s->length = newLen; s->loopStart = (int32_t)(s->loopStart * dRatio); s->loopLength = (int32_t)(s->loopLength * dRatio); sanitizeSample(s); fixSample(s); resumeAudio(); setSongModifiedFlag(); setMouseBusy(false); ui.sysReqShown = false; return true; (void)ptr; } static void pbDoResampling(void) { mouseAnimOn(); thread = SDL_CreateThread(resampleThread, NULL, NULL); if (thread == NULL) { okBox(0, "System message", "Couldn't create thread!"); return; } SDL_DetachThread(thread); } static void drawResampleBox(void) { char sign; const int16_t x = 209; const int16_t y = 230; const int16_t w = 214; const int16_t h = 54; // main fill fillRect(x + 1, y + 1, w - 2, h - 2, PAL_BUTTONS); // outer border vLine(x, y, h - 1, PAL_BUTTON1); hLine(x + 1, y, w - 2, PAL_BUTTON1); vLine(x + w - 1, y, h, PAL_BUTTON2); hLine(x, y + h - 1, w - 1, PAL_BUTTON2); // inner border vLine(x + 2, y + 2, h - 5, PAL_BUTTON2); hLine(x + 3, y + 2, w - 6, PAL_BUTTON2); vLine(x + w - 3, y + 2, h - 4, PAL_BUTTON1); hLine(x + 2, y + h - 3, w - 4, PAL_BUTTON1); sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp]; double dLenMul = exp2(smpEd_RelReSmp * (1.0 / 12.0)); double dNewLen = s->length * dLenMul; if (dNewLen > (double)MAX_SAMPLE_LEN) dNewLen = (double)MAX_SAMPLE_LEN; textOutShadow(215, 236, PAL_FORGRND, PAL_BUTTON2, "Rel. h.tones"); textOutShadow(215, 250, PAL_FORGRND, PAL_BUTTON2, "New sample size"); hexOut(361, 250, PAL_FORGRND, (int32_t)dNewLen, 8); if (smpEd_RelReSmp == 0) sign = ' '; else if (smpEd_RelReSmp < 0) sign = '-'; else sign = '+'; uint16_t val = ABS(smpEd_RelReSmp); if (val > 9) { charOut(291, 236, PAL_FORGRND, sign); charOut(298, 236, PAL_FORGRND, '0' + ((val / 10) % 10)); charOut(305, 236, PAL_FORGRND, '0' + (val % 10)); } else { charOut(298, 236, PAL_FORGRND, sign); charOut(305, 236, PAL_FORGRND, '0' + (val % 10)); } } static void setupResampleBoxWidgets(void) { pushButton_t *p; scrollBar_t *s; // "Apply" pushbutton p = &pushButtons[0]; memset(p, 0, sizeof (pushButton_t)); p->caption = "Apply"; p->x = 214; p->y = 264; p->w = 73; p->h = 16; p->callbackFuncOnUp = pbDoResampling; p->visible = true; // "Exit" pushbutton p = &pushButtons[1]; memset(p, 0, sizeof (pushButton_t)); p->caption = "Exit"; p->x = 345; p->y = 264; p->w = 73; p->h = 16; p->callbackFuncOnUp = pbExit; p->visible = true; // scrollbar buttons p = &pushButtons[2]; memset(p, 0, sizeof (pushButton_t)); p->caption = ARROW_LEFT_STRING; p->x = 314; p->y = 234; p->w = 23; p->h = 13; p->preDelay = 1; p->delayFrames = 3; p->callbackFuncOnDown = pbResampleTonesDown; p->visible = true; p = &pushButtons[3]; memset(p, 0, sizeof (pushButton_t)); p->caption = ARROW_RIGHT_STRING; p->x = 395; p->y = 234; p->w = 23; p->h = 13; p->preDelay = 1; p->delayFrames = 3; p->callbackFuncOnDown = pbResampleTonesUp; p->visible = true; // echo num scrollbar s = &scrollBars[0]; memset(s, 0, sizeof (scrollBar_t)); s->x = 337; s->y = 234; s->w = 58; s->h = 13; s->callbackFunc = sbSetResampleTones; s->visible = true; setScrollBarPageLength(0, 1); setScrollBarEnd(0, 36 * 2); } void pbSampleResample(void) { uint16_t i; if (editor.curInstr == 0 || instr[editor.curInstr] == NULL || instr[editor.curInstr]->smp[editor.curSmp].dataPtr == NULL) { return; } setupResampleBoxWidgets(); windowOpen(); outOfMemory = false; exitFlag = false; while (ui.sysReqShown) { readInput(); if (ui.sysReqEnterPressed) pbDoResampling(); setSyncedReplayerVars(); handleRedrawing(); drawResampleBox(); setScrollBarPos(0, smpEd_RelReSmp + 36, false); drawCheckBox(0); for (i = 0; i < 4; i++) drawPushButton(i); drawScrollBar(0); flipFrame(); } for (i = 0; i < 4; i++) hidePushButton(i); hideScrollBar(0); windowClose(false); if (outOfMemory) okBox(0, "System message", "Not enough memory!"); } static void cbEchoAddMemory(void) { echo_AddMemory ^= 1; } static void sbSetEchoNumPos(uint32_t pos) { if (echo_nEcho != (int32_t)pos) echo_nEcho = (int16_t)pos; } static void sbSetEchoDistPos(uint32_t pos) { if (echo_Distance != (int32_t)pos) echo_Distance = (int32_t)pos; } static void sbSetEchoFadeoutPos(uint32_t pos) { if (echo_VolChange != (int32_t)pos) echo_VolChange = (int16_t)pos; } static void pbEchoNumDown(void) { if (echo_nEcho > 0) echo_nEcho--; } static void pbEchoNumUp(void) { if (echo_nEcho < 64) echo_nEcho++; } static void pbEchoDistDown(void) { if (echo_Distance > 0) echo_Distance--; } static void pbEchoDistUp(void) { if (echo_Distance < 16384) echo_Distance++; } static void pbEchoFadeoutDown(void) { if (echo_VolChange > 0) echo_VolChange--; } static void pbEchoFadeoutUp(void) { if (echo_VolChange < 100) echo_VolChange++; } static int32_t SDLCALL createEchoThread(void *ptr) { smpPtr_t sp; if (echo_nEcho < 1) { ui.sysReqShown = false; return true; } sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp]; int32_t readLen = s->length; int8_t *readPtr = s->dataPtr; bool sample16Bit = !!(s->flags & SAMPLE_16BIT); int32_t distance = echo_Distance * 16; double dVolChange = echo_VolChange / 100.0; // calculate real number of echoes double dSmp = sample16Bit ? 32768.0 : 128.0; int32_t k = 0; while (k++ < echo_nEcho && dSmp >= 1.0) dSmp *= dVolChange; int32_t nEchoes = k + 1; if (nEchoes < 1) { ui.sysReqShown = false; return true; } // set write length (either original length or full echo length) int32_t writeLen = readLen; if (echo_AddMemory) { int64_t tmp64 = (int64_t)distance * (nEchoes - 1); tmp64 += writeLen; if (tmp64 > MAX_SAMPLE_LEN) tmp64 = MAX_SAMPLE_LEN; writeLen = (uint32_t)tmp64; } if (!allocateSmpDataPtr(&sp, writeLen, sample16Bit)) { outOfMemory = true; setMouseBusy(false); ui.sysReqShown = false; return false; } pauseAudio(); unfixSample(s); int32_t writeIdx = 0; if (sample16Bit) { const int16_t *readPtr16 = (const int16_t *)readPtr; int16_t *writePtr16 = (int16_t *)sp.ptr; while (writeIdx < writeLen) { double dSmpOut = 0.0; double dSmpMul = 1.0; int32_t echoRead = writeIdx; int32_t echoCycle = nEchoes; while (!stopThread) { if (echoRead < readLen) dSmpOut += (int32_t)readPtr16[echoRead] * dSmpMul; dSmpMul *= dVolChange; echoRead -= distance; if (echoRead <= 0 || --echoCycle <= 0) break; } DROUND(dSmpOut); int32_t smp32 = (int32_t)dSmpOut; CLAMP16(smp32); writePtr16[writeIdx++] = (int16_t)smp32; } } else // 8-bit {