// for finding memory leaks in debug mode with Visual Studio#if defined _DEBUG && defined _MSC_VER#include <crtdbg.h>#endif #include <stdint.h>#include <stdbool.h>#include <stdio.h>#include <math.h>#include "ft2_header.h"#include "ft2_sample_ed.h"#include "ft2_gui.h"#include "scopes/ft2_scopes.h"#include "ft2_pattern_ed.h"#include "ft2_replayer.h"#include "ft2_audio.h"#include "ft2_mouse.h"#include "ft2_structs.h" // this is truly a mess, but it works... static char byteFormatBuffer[64], tmpInstrName[1 + MAX_INST][22 + 1], tmpInstName[MAX_INST][22 + 1];static bool removePatt, removeInst, removeSamp, removeChans, removeSmpDataAfterLoop, convSmpsTo8Bit;static uint8_t instrUsed[MAX_INST], instrOrder[MAX_INST], pattUsed[MAX_PATTERNS], pattOrder[MAX_PATTERNS];static int16_t oldPattLens[MAX_PATTERNS], tmpPattLens[MAX_PATTERNS];static int64_t xmSize64 = -1, xmAfterTrimSize64 = -1, spaceSaved64 = -1;static note_t *oldPatts[MAX_PATTERNS], *tmpPatt[MAX_PATTERNS];static instr_t *tmpInstr[1 + MAX_INST], *tmpInst[MAX_INST]; // tmpInstr[x] = copy of instr[x] for "after trim" size calculationstatic SDL_Thread *trimThread; void pbTrimCalc(void); static void freeTmpInstruments(void){ for (int32_t i = 0; i <= MAX_INST; i++) { if (tmpInstr[i] != NULL) { // don't free samples, as the pointers are shared with main instruments... free(tmpInstr[i]); tmpInstr[i] = NULL; } }} static bool setTmpInstruments(void){ freeTmpInstruments(); for (int32_t i = 0; i <= MAX_INST; i++) { if (instr[i] != NULL) { tmpInstr[i] = (instr_t *)malloc(sizeof (instr_t)); if (tmpInstr[i] == NULL) { freeTmpInstruments(); return false; } *tmpInstr[i] = *instr[i]; } } return true;} static void remapInstrInSong(uint8_t src, uint8_t dst, int32_t ap){ for (int32_t i = 0; i < ap; i++) { note_t *pattPtr = pattern[i]; if (pattPtr == NULL) continue; const int32_t readLen = patternNumRows[i] * MAX_CHANNELS; note_t *p = pattPtr; for (int32_t j = 0; j < readLen; j++, p++) { if (p->instr == src) p->instr = dst; } }} static int16_t getUsedTempSamples(uint16_t insNum){ if (tmpInstr[insNum] == NULL) return 0; instr_t *ins = tmpInstr[insNum]; int16_t i = 16 - 1; while (i >= 0 && ins->smp[i].dataPtr == NULL && ins->smp[i].name[0] == '\0') i--; /* Yes, 'i' can be -1 here, and will be set to at least 0 ** because of ins->ta values. Possibly an FT2 bug... **/ for (int16_t j = 0; j < 96; j++) { if (ins->note2SampleLUT[j] > i) i = ins->note2SampleLUT[j]; } return i+1;} static int64_t getTempInsAndSmpSize(void){ int16_t j; int16_t ai = MAX_INST; while (ai > 0 && getUsedTempSamples(ai) == 0 && tmpInstrName[ai][0] == '\0') ai--; int64_t currSize64 = 0; // count instrument and sample data size in song for (int16_t i = 1; i <= ai; i++) { if (tmpInstr[i] == NULL) j = 0; else j = i; const int16_t a = getUsedTempSamples(i); if (a > 0) currSize64 += INSTR_HEADER_SIZE + (a * sizeof (xmSmpHdr_t)); else currSize64 += 22+11; instr_t *ins = tmpInstr[j]; for (int16_t k = 0; k < a; k++) { sample_t *s = &ins->smp[k]; if (s->dataPtr != NULL && s->length > 0) { if (s->flags & SAMPLE_16BIT) currSize64 += s->length << 1; else currSize64 += s->length; } } } return currSize64;} static void wipeInstrUnused(bool testWipeSize, int16_t *ai, int32_t ap, int32_t antChn){ int16_t numRows; int32_t i, j, k; note_t *p; int32_t numInsts = *ai; // calculate what instruments are used memset(instrUsed, 0, numInsts); for (i = 0; i < ap; i++) { if (testWipeSize) { p = tmpPatt[i]; numRows = tmpPattLens[i]; } else { p = pattern[i]; numRows = patternNumRows[i]; } if (p == NULL) continue; for (j = 0; j < numRows; j++) { for (k = 0; k < antChn; k++) { uint8_t ins = p[(j * MAX_CHANNELS) + k].instr; if (ins > 0 && ins <= MAX_INST) instrUsed[ins-1] = true; } } } int16_t instToDel = 0; uint8_t newInst = 0; int16_t newNumInsts = 0; memset(instrOrder, 0, numInsts); for (i = 0; i < numInsts; i++) { if (instrUsed[i]) { newNumInsts++; instrOrder[i] = newInst++; } else { instToDel++; } } if (instToDel == 0) return; if (testWipeSize) { for (i = 0; i < numInsts; i++) { if (!instrUsed[i] && tmpInstr[1+i] != NULL) { free(tmpInstr[1+i]); tmpInstr[1+i] = NULL; } } // relocate instruments memcpy(tmpInstName, &tmpInstrName[1], MAX_INST * sizeof (song.instrName[0])); memcpy(tmpInst, &tmpInstr[1], MAX_INST * sizeof (instr[0])); memset(&tmpInstr[1], 0, numInsts * sizeof (tmpInstr[0])); memset(&tmpInstrName[1], 0, numInsts * sizeof (tmpInstrName[0])); for (i = 0; i < numInsts; i++) { if (instrUsed[i]) { newInst = instrOrder[i]; memcpy(&tmpInstr[1+newInst], &tmpInst[i], sizeof (tmpInst[0])); strcpy(tmpInstrName[1+newInst], tmpInstName[i]); } } *ai = newNumInsts; return; } // clear unused instruments for (i = 0; i < numInsts; i++) { if (!instrUsed[i]) freeInstr(1 + i); } // relocate instruments memcpy(tmpInstName, &song.instrName[1], MAX_INST * sizeof (song.instrName[0])); memcpy(tmpInst, &instr[1], MAX_INST * sizeof (instr[0])); memset(&instr[1], 0, numInsts * sizeof (instr[0])); memset(song.instrName[1], 0, numInsts * sizeof (song.instrName[0])); // XXX: Is this safe? for (i = 0; i < numInsts; i++) { if (instrUsed[i]) { newInst = instrOrder[i]; remapInstrInSong(1 + (uint8_t)i, 1 + newInst, ap); memcpy(&instr[1+newInst], &tmpInst[i], sizeof (instr[0])); strcpy(song.instrName[1+newInst], tmpInstName[i]); } } *ai = newNumInsts; setTmpInstruments();} static void wipePattsUnused(bool testWipeSize, int16_t *ap){ uint8_t newPatt; int16_t i, *pLens; note_t **p; int16_t usedPatts = *ap; memset(pattUsed, 0, usedPatts); int16_t newUsedPatts = 0; for (i = 0; i < song.songLength; i++) { newPatt = song.orders[i]; if (newPatt < usedPatts && !pattUsed[newPatt]) { pattUsed[newPatt] = true; newUsedPatts++; } } if (newUsedPatts == 0 || newUsedPatts == usedPatts) return; // nothing to do! newPatt = 0; memset(pattOrder, 0, usedPatts); for (i = 0; i < usedPatts; i++) { if (pattUsed[i]) pattOrder[i] = newPatt++; } if (testWipeSize) { p = tmpPatt; pLens = tmpPattLens; } else { p = pattern; pLens = patternNumRows; } memcpy(oldPatts, p, usedPatts * sizeof (note_t *)); memcpy(oldPattLens, pLens, usedPatts * sizeof (int16_t)); memset(p, 0, usedPatts * sizeof (note_t *)); memset(pLens, 0, usedPatts * sizeof (int16_t)); // relocate patterns for (i = 0; i < usedPatts; i++) { p[i] = NULL; if (!pattUsed[i]) { if (!testWipeSize && oldPatts[i] != NULL) { free(oldPatts[i]); oldPatts[i] = NULL; } } else { newPatt = pattOrder[i]; p[newPatt] = oldPatts[i]; pLens[newPatt] = oldPattLens[i]; } } if (!testWipeSize) { for (i = 0; i < MAX_PATTERNS; i++) { if (pattern[i] == NULL) patternNumRows[i] = 64; } // reorder order list (and clear unused entries) for (i = 0; i < 256; i++) { if (i < song.songLength) song.orders[i] = pattOrder[song.orders[i]]; else song.orders[i] = 0; } } *ap = newUsedPatts;} static void wipeSamplesUnused(bool testWipeSize, int16_t ai){ uint8_t smpUsed[16], smpOrder[16]; int16_t j, k, l; instr_t *ins; sample_t tempSamples[16]; for (int16_t i = 1; i <= ai; i++) { if (!testWipeSize) { if (instr[i] == NULL) l = 0; else l = i; ins = instr[l]; l = getUsedSamples(i); } else { if (tmpInstr[i] == NULL) l = 0; else l = i; ins = tmpInstr[l]; l = getUsedTempSamples(i); } memset(smpUsed, 0, l); if (l > 0) { sample_t *s = ins->smp; for (j = 0; j < l; j++, s++) { // check if sample is referenced in instrument for (k = 0; k < 96; k++) { if (ins->note2SampleLUT[k] == j) { smpUsed[j] = true; break; // sample is used } } if (k == 96) { // sample is unused if (s->dataPtr != NULL && !testWipeSize) freeSmpData(s); memset(s, 0, sizeof (sample_t)); } } // create re-order list uint8_t newSamp = 0; memset(smpOrder, 0, l); for (j = 0; j < l; j++) { if (smpUsed[j]) smpOrder[j] = newSamp++; } // re-order samples memcpy(tempSamples, ins->smp, l * sizeof (sample_t)); memset(ins->smp, 0, l * sizeof (sample_t)); for (j = 0; j < l; j++) { if (smpUsed[j]) ins->smp[smpOrder[j]] = tempSamples[j]; } // re-order note->sample list for (j = 0; j < 96; j++) { newSamp = ins->note2SampleLUT[j]; if (smpUsed[newSamp]) ins->note2SampleLUT[j] = smpOrder[newSamp]; else ins->note2SampleLUT[j] = 0; } } }} static void wipeSmpDataAfterLoop(bool testWipeSize, int16_t ai){ int16_t l; instr_t *ins; for (int16_t i = 1; i <= ai; i++) { if (!testWipeSize) { if (instr[i] == NULL) l = 0; else l = i; ins = instr[l]; l = getUsedSamples(i); } else { if (tmpInstr[i] == NULL) l = 0; else l = i; ins = tmpInstr[l]; l = getUsedTempSamples(i); } sample_t *s = ins->smp; for (int16_t j = 0; j < l; j++, s++) { if (s->dataPtr != NULL && GET_LOOPTYPE(s->flags) != LOOP_OFF && s->length > 0 && s->length > s->loopStart+s->loopLength) { if (!testWipeSize) unfixSample(s); s->length = s->loopStart + s->loopLength; if (!testWipeSize) { if (s->length <= 0) { s->length = 0; freeSmpData(s); } else {Lines 1–500 of 1212. Load more
// for finding memory leaks in debug mode with Visual Studio #if defined _DEBUG && defined _MSC_VER #include <crtdbg.h> #endif #include <stdint.h> #include <stdbool.h> #include <stdio.h> #include <math.h> #include "ft2_header.h" #include "ft2_sample_ed.h" #include "ft2_gui.h" #include "scopes/ft2_scopes.h" #include "ft2_pattern_ed.h" #include "ft2_replayer.h" #include "ft2_audio.h" #include "ft2_mouse.h" #include "ft2_structs.h" // this is truly a mess, but it works... static char byteFormatBuffer[64], tmpInstrName[1 + MAX_INST][22 + 1], tmpInstName[MAX_INST][22 + 1]; static bool removePatt, removeInst, removeSamp, removeChans, removeSmpDataAfterLoop, convSmpsTo8Bit; static uint8_t instrUsed[MAX_INST], instrOrder[MAX_INST], pattUsed[MAX_PATTERNS], pattOrder[MAX_PATTERNS]; static int16_t oldPattLens[MAX_PATTERNS], tmpPattLens[MAX_PATTERNS]; static int64_t xmSize64 = -1, xmAfterTrimSize64 = -1, spaceSaved64 = -1; static note_t *oldPatts[MAX_PATTERNS], *tmpPatt[MAX_PATTERNS]; static instr_t *tmpInstr[1 + MAX_INST], *tmpInst[MAX_INST]; // tmpInstr[x] = copy of instr[x] for "after trim" size calculation static SDL_Thread *trimThread; void pbTrimCalc(void); static void freeTmpInstruments(void) { for (int32_t i = 0; i <= MAX_INST; i++) { if (tmpInstr[i] != NULL) { // don't free samples, as the pointers are shared with main instruments... free(tmpInstr[i]); tmpInstr[i] = NULL; } } } static bool setTmpInstruments(void) { freeTmpInstruments(); for (int32_t i = 0; i <= MAX_INST; i++) { if (instr[i] != NULL) { tmpInstr[i] = (instr_t *)malloc(sizeof (instr_t)); if (tmpInstr[i] == NULL) { freeTmpInstruments(); return false; } *tmpInstr[i] = *instr[i]; } } return true; } static void remapInstrInSong(uint8_t src, uint8_t dst, int32_t ap) { for (int32_t i = 0; i < ap; i++) { note_t *pattPtr = pattern[i]; if (pattPtr == NULL) continue; const int32_t readLen = patternNumRows[i] * MAX_CHANNELS; note_t *p = pattPtr; for (int32_t j = 0; j < readLen; j++, p++) { if (p->instr == src) p->instr = dst; } } } static int16_t getUsedTempSamples(uint16_t insNum) { if (tmpInstr[insNum] == NULL) return 0; instr_t *ins = tmpInstr[insNum]; int16_t i = 16 - 1; while (i >= 0 && ins->smp[i].dataPtr == NULL && ins->smp[i].name[0] == '\0') i--; /* Yes, 'i' can be -1 here, and will be set to at least 0 ** because of ins->ta values. Possibly an FT2 bug... **/ for (int16_t j = 0; j < 96; j++) { if (ins->note2SampleLUT[j] > i) i = ins->note2SampleLUT[j]; } return i+1; } static int64_t getTempInsAndSmpSize(void) { int16_t j; int16_t ai = MAX_INST; while (ai > 0 && getUsedTempSamples(ai) == 0 && tmpInstrName[ai][0] == '\0') ai--; int64_t currSize64 = 0; // count instrument and sample data size in song for (int16_t i = 1; i <= ai; i++) { if (tmpInstr[i] == NULL) j = 0; else j = i; const int16_t a = getUsedTempSamples(i); if (a > 0) currSize64 += INSTR_HEADER_SIZE + (a * sizeof (xmSmpHdr_t)); else currSize64 += 22+11; instr_t *ins = tmpInstr[j]; for (int16_t k = 0; k < a; k++) { sample_t *s = &ins->smp[k]; if (s->dataPtr != NULL && s->length > 0) { if (s->flags & SAMPLE_16BIT) currSize64 += s->length << 1; else currSize64 += s->length; } } } return currSize64; } static void wipeInstrUnused(bool testWipeSize, int16_t *ai, int32_t ap, int32_t antChn) { int16_t numRows; int32_t i, j, k; note_t *p; int32_t numInsts = *ai; // calculate what instruments are used memset(instrUsed, 0, numInsts); for (i = 0; i < ap; i++) { if (testWipeSize) { p = tmpPatt[i]; numRows = tmpPattLens[i]; } else { p = pattern[i]; numRows = patternNumRows[i]; } if (p == NULL) continue; for (j = 0; j < numRows; j++) { for (k = 0; k < antChn; k++) { uint8_t ins = p[(j * MAX_CHANNELS) + k].instr; if (ins > 0 && ins <= MAX_INST) instrUsed[ins-1] = true; } } } int16_t instToDel = 0; uint8_t newInst = 0; int16_t newNumInsts = 0; memset(instrOrder, 0, numInsts); for (i = 0; i < numInsts; i++) { if (instrUsed[i]) { newNumInsts++; instrOrder[i] = newInst++; } else { instToDel++; } } if (instToDel == 0) return; if (testWipeSize) { for (i = 0; i < numInsts; i++) { if (!instrUsed[i] && tmpInstr[1+i] != NULL) { free(tmpInstr[1+i]); tmpInstr[1+i] = NULL; } } // relocate instruments memcpy(tmpInstName, &tmpInstrName[1], MAX_INST * sizeof (song.instrName[0])); memcpy(tmpInst, &tmpInstr[1], MAX_INST * sizeof (instr[0])); memset(&tmpInstr[1], 0, numInsts * sizeof (tmpInstr[0])); memset(&tmpInstrName[1], 0, numInsts * sizeof (tmpInstrName[0])); for (i = 0; i < numInsts; i++) { if (instrUsed[i]) { newInst = instrOrder[i]; memcpy(&tmpInstr[1+newInst], &tmpInst[i], sizeof (tmpInst[0])); strcpy(tmpInstrName[1+newInst], tmpInstName[i]); } } *ai = newNumInsts; return; } // clear unused instruments for (i = 0; i < numInsts; i++) { if (!instrUsed[i]) freeInstr(1 + i); } // relocate instruments memcpy(tmpInstName, &song.instrName[1], MAX_INST * sizeof (song.instrName[0])); memcpy(tmpInst, &instr[1], MAX_INST * sizeof (instr[0])); memset(&instr[1], 0, numInsts * sizeof (instr[0])); memset(song.instrName[1], 0, numInsts * sizeof (song.instrName[0])); // XXX: Is this safe? for (i = 0; i < numInsts; i++) { if (instrUsed[i]) { newInst = instrOrder[i]; remapInstrInSong(1 + (uint8_t)i, 1 + newInst, ap); memcpy(&instr[1+newInst], &tmpInst[i], sizeof (instr[0])); strcpy(song.instrName[1+newInst], tmpInstName[i]); } } *ai = newNumInsts; setTmpInstruments(); } static void wipePattsUnused(bool testWipeSize, int16_t *ap) { uint8_t newPatt; int16_t i, *pLens; note_t **p; int16_t usedPatts = *ap; memset(pattUsed, 0, usedPatts); int16_t newUsedPatts = 0; for (i = 0; i < song.songLength; i++) { newPatt = song.orders[i]; if (newPatt < usedPatts && !pattUsed[newPatt]) { pattUsed[newPatt] = true; newUsedPatts++; } } if (newUsedPatts == 0 || newUsedPatts == usedPatts) return; // nothing to do! newPatt = 0; memset(pattOrder, 0, usedPatts); for (i = 0; i < usedPatts; i++) { if (pattUsed[i]) pattOrder[i] = newPatt++; } if (testWipeSize) { p = tmpPatt; pLens = tmpPattLens; } else { p = pattern; pLens = patternNumRows; } memcpy(oldPatts, p, usedPatts * sizeof (note_t *)); memcpy(oldPattLens, pLens, usedPatts * sizeof (int16_t)); memset(p, 0, usedPatts * sizeof (note_t *)); memset(pLens, 0, usedPatts * sizeof (int16_t)); // relocate patterns for (i = 0; i < usedPatts; i++) { p[i] = NULL; if (!pattUsed[i]) { if (!testWipeSize && oldPatts[i] != NULL) { free(oldPatts[i]); oldPatts[i] = NULL; } } else { newPatt = pattOrder[i]; p[newPatt] = oldPatts[i]; pLens[newPatt] = oldPattLens[i]; } } if (!testWipeSize) { for (i = 0; i < MAX_PATTERNS; i++) { if (pattern[i] == NULL) patternNumRows[i] = 64; } // reorder order list (and clear unused entries) for (i = 0; i < 256; i++) { if (i < song.songLength) song.orders[i] = pattOrder[song.orders[i]]; else song.orders[i] = 0; } } *ap = newUsedPatts; } static void wipeSamplesUnused(bool testWipeSize, int16_t ai) { uint8_t smpUsed[16], smpOrder[16]; int16_t j, k, l; instr_t *ins; sample_t tempSamples[16]; for (int16_t i = 1; i <= ai; i++) { if (!testWipeSize) { if (instr[i] == NULL) l = 0; else l = i; ins = instr[l]; l = getUsedSamples(i); } else { if (tmpInstr[i] == NULL) l = 0; else l = i; ins = tmpInstr[l]; l = getUsedTempSamples(i); } memset(smpUsed, 0, l); if (l > 0) { sample_t *s = ins->smp; for (j = 0; j < l; j++, s++) { // check if sample is referenced in instrument for (k = 0; k < 96; k++) { if (ins->note2SampleLUT[k] == j) { smpUsed[j] = true; break; // sample is used } } if (k == 96) { // sample is unused if (s->dataPtr != NULL && !testWipeSize) freeSmpData(s); memset(s, 0, sizeof (sample_t)); } } // create re-order list uint8_t newSamp = 0; memset(smpOrder, 0, l); for (j = 0; j < l; j++) { if (smpUsed[j]) smpOrder[j] = newSamp++; } // re-order samples memcpy(tempSamples, ins->smp, l * sizeof (sample_t)); memset(ins->smp, 0, l * sizeof (sample_t)); for (j = 0; j < l; j++) { if (smpUsed[j]) ins->smp[smpOrder[j]] = tempSamples[j]; } // re-order note->sample list for (j = 0; j < 96; j++) { newSamp = ins->note2SampleLUT[j]; if (smpUsed[newSamp]) ins->note2SampleLUT[j] = smpOrder[newSamp]; else ins->note2SampleLUT[j] = 0; } } } } static void wipeSmpDataAfterLoop(bool testWipeSize, int16_t ai) { int16_t l; instr_t *ins; for (int16_t i = 1; i <= ai; i++) { if (!testWipeSize) { if (instr[i] == NULL) l = 0; else l = i; ins = instr[l]; l = getUsedSamples(i); } else { if (tmpInstr[i] == NULL) l = 0; else l = i; ins = tmpInstr[l]; l = getUsedTempSamples(i); } sample_t *s = ins->smp; for (int16_t j = 0; j < l; j++, s++) { if (s->dataPtr != NULL && GET_LOOPTYPE(s->flags) != LOOP_OFF && s->length > 0 && s->length > s->loopStart+s->loopLength) { if (!testWipeSize) unfixSample(s); s->length = s->loopStart + s->loopLength; if (!testWipeSize) { if (s->length <= 0) { s->length = 0; freeSmpData(s); } else {