Olav SørensenPushed v1.23 code986a9df6 years agoHistory
2692 lines · 59.9 KB · C
RawDownload
// 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>#ifndef _WIN32#include <unistd.h>#endif#include "ft2_header.h"#include "ft2_config.h"#include "ft2_scopes.h"#include "ft2_trim.h"#include "ft2_inst_ed.h"#include "ft2_sample_ed.h"#include "ft2_wav_renderer.h"#include "ft2_pattern_ed.h"#include "ft2_gui.h"#include "ft2_diskop.h"#include "ft2_sample_loader.h"#include "ft2_mouse.h"#include "ft2_midi.h"#include "ft2_events.h"#include "ft2_video.h"#include "ft2_tables.h"#include "ft2_structs.h" /* This is a *HUGE* mess!** I hope you never have to modify it, and you probably shouldn't either.** You will experience a lot of headaches if you dig into this file...** If something looks to be wrong, it's probably right!**** The actual module load routines are ported from FT2 and slightly modified.*/ enum{	FORMAT_NONE = 0,	FORMAT_XM = 1,	FORMAT_MOD = 2,	FORMAT_S3M = 3,	FORMAT_STM = 4}; // .MOD typesenum{	FORMAT_MK, // ProTracker or compatible	FORMAT_FLT, // StarTrekker (4-channel modules only)	FORMAT_FT2, // FT2 (or other trackers, multichannel)	FORMAT_STK, // The Ultimate SoundTracker (15 samples)	FORMAT_NT, // NoiseTracker	FORMAT_HMNT, // His Master's NoiseTracker (special one) 	FORMAT_UNKNOWN // may be The Ultimate Soundtracker (set to FORMAT_STK later)}; // DO NOT TOUCH THESE STRUCTS! #ifdef _MSC_VER#pragma pack(push)#pragma pack(1)#endiftypedef struct songSTMinstrHeaderTyp_t{	char name[12];	uint8_t nul, insDisk;	uint16_t reserved1, len, repS, repE;	uint8_t vol, reserved2;	uint16_t rate;	int32_t reserved3;	uint16_t paraLen;}#ifdef __GNUC____attribute__ ((packed))#endifsongSTMinstrHeaderTyp; typedef struct songSTMHeaderTyp_t{	char name[20], sig[8];	uint8_t id1a, typ;	uint8_t verMajor, verMinor;	uint8_t tempo, ap, vol, reserved[13];	songSTMinstrHeaderTyp instr[31];	uint8_t songTab[128];}#ifdef __GNUC____attribute__ ((packed))#endifsongSTMHeaderTyp; typedef struct songS3MinstrHeaderTyp_t{	uint8_t typ;	char dosName[12];	uint8_t memSegH;	uint16_t memSeg;	int32_t len, repS, repE;	uint8_t vol, dsk, pack, flags;	int32_t c2Spd, res1;	uint16_t gusPos;	uint8_t res2[6];	char name[28], id[4];}#ifdef __GNUC____attribute__ ((packed))#endifsongS3MinstrHeaderTyp; typedef struct songS3MHeaderTyp_t{	char name[28];	uint8_t id1a, typ;	uint16_t res1;	int16_t songTabLen, antInstr, antPatt;	uint16_t flags, trackerID, ver;	char id[4];	uint8_t globalVol, defSpeed, defTempo, masterVol, res2[12], chanType[32];}#ifdef __GNUC____attribute__ ((packed))#endifsongS3MHeaderTyp;#ifdef _MSC_VER#pragma pack(pop)#endif static volatile uint8_t loadedFormat;static volatile bool linearFreqTable, musicIsLoading, moduleLoaded, moduleFailedToLoad;static uint8_t oldPlayMode, pattBuff[12288], packedPattData[65536];static const uint8_t stmEff[16] = { 0, 0, 11, 0, 10, 2, 1, 3, 4, 7, 0, 5 ,6, 0, 0, 0 };static SDL_Thread *thread; // these temporarily read to, then copied to real struct if load was OK (should not need to be volatile'd)static int16_t pattLensTmp[MAX_PATTERNS];static tonTyp *pattTmp[MAX_PATTERNS];static instrTyp *instrTmp[1 + MAX_INST];static songTyp songTmp; static void setupLoadedModule(void);static void freeTmpModule(void);static bool loadInstrHeader(FILE *f, uint16_t i);static bool loadInstrSample(FILE *f, uint16_t i);void unpackPatt(uint8_t *dst, uint8_t *src, uint16_t len, int32_t antChn);static bool tmpPatternEmpty(uint16_t nr);static bool loadPatterns(FILE *f, uint16_t antPtn); void checkSampleRepeat(sampleTyp *s); // ft2_replayer.cextern const char modSig[32][5]; static bool allocateTmpInstr(int16_t nr){	instrTyp *p; 	if (instrTmp[nr] != NULL)		return false; // already allocated 	p = (instrTyp *)malloc(sizeof (instrTyp));	if (p == NULL)		return false; 	memset(p, 0, sizeof (instrTyp)); 	for (int8_t i = 0; i < 16; i++) // set standard sample pan/vol	{		p->samp[i].pan = 128;		p->samp[i].vol = 64;	} 	instrTmp[nr] = p;	return true;} #define IS_ID(s, b) !strncmp(s, b, 4) static uint8_t getModType(uint8_t *numChannels, const char *id){	uint8_t modFormat = FORMAT_UNKNOWN;	*numChannels = 4; 	if (IS_ID("M.K.", id) || IS_ID("M!K!", id) || IS_ID("NSMS", id) || IS_ID("LARD", id) || IS_ID("PATT", id))	{		modFormat = FORMAT_MK; // ProTracker or compatible	}	else if (id[1] == 'C' && id[2] == 'H' && id[3] == 'N')	{		modFormat = FORMAT_FT2; // FT2 or generic multichannel		*numChannels = id[0] - '0';	}	else if (id[2] == 'C' && (id[3] == 'H' || id[3] == 'N'))	{		modFormat = FORMAT_FT2; // FT2 or generic multichannel		*numChannels = ((id[0] - '0') * 10) + (id[1] - '0');	}	else if (IS_ID("FLT4", id))	{		modFormat = FORMAT_FLT; // StarTrekker (4-channel modules only)	}	else if (IS_ID("N.T.", id))	{		modFormat = FORMAT_NT; // NoiseTracker	}	else if (IS_ID("M&K!", id) || IS_ID("FEST", id))	{		modFormat = FORMAT_HMNT; // His Master's NoiseTracker	} 	return modFormat;} static bool loadMusicMOD(FILE *f, uint32_t fileLength, bool fromExternalThread){	char ID[16];	bool mightBeSTK, lateSTKVerFlag, veryLateSTKVerFlag;	uint8_t bytes[4], modFormat, numChannels;	int16_t i, j, k, ai;	uint16_t a, b, period;	tonTyp *ton;	sampleTyp *s;	songMOD31HeaderTyp h_MOD31;	songMOD15HeaderTyp h_MOD15;	int16_t (*showMsg)(int16_t, const char *, const char *); 	showMsg = fromExternalThread ? okBoxThreadSafe : okBox; 	veryLateSTKVerFlag = false; // "DFJ SoundTracker III" nad later	lateSTKVerFlag = false; // "TJC SoundTracker II" and later	mightBeSTK = false; 	memset(&songTmp, 0, sizeof (songTmp));	memset(&h_MOD31, 0, sizeof (songMOD31HeaderTyp));	memset(&h_MOD15, 0, sizeof (songMOD15HeaderTyp)); 	// start loading MOD 	loadedFormat = FORMAT_MOD; 	rewind(f);	fread(ID, 1, 16, f);	fseek(f, 0x1D, SEEK_SET);	fread(bytes, 1, 1, f);	rewind(f);		// since .mod is the last format tested, check if the file is an .it module (Impulse Tracker)	if (!memcmp(ID, "IMPM", 4) && bytes[0] == 0)	{		showMsg(0, "System message", "Error: Impulse Tracker modules are not supported!");		goto modLoadError;	} 	// check if the file to load is a WAV, if so reject it	if (!memcmp(ID, "RIFF", 4) && !memcmp(&ID[8], "WAVEfmt", 7))	{		showMsg(0, "System message", "Error: Can't load a .wav file as a module!");		goto modLoadError;	} 	if (fileLength < 1596 || fileLength > 20842494) // minimum and maximum possible size for a supported .mod	{		showMsg(0, "System message", "Error: This file is either not a module, or is not supported.");		goto modLoadError;	} 	if (fread(&h_MOD31, 1, sizeof (h_MOD31), f) != sizeof (h_MOD31))	{		showMsg(0, "System message", "Error: This file is either not a module, or is not supported.");		goto modLoadError;	} 	modFormat = getModType(&numChannels, h_MOD31.sig); 	if (modFormat == FORMAT_FLT && numChannels == 8)	{		showMsg(0, "System message", "8-channel Startrekker modules are not supported!");		goto modLoadError;	} 	if (modFormat != FORMAT_UNKNOWN)	{		if (fileLength < sizeof (h_MOD31))		{			showMsg(0, "System message", "Error: This file is either not a module, or is not supported.");			goto modLoadError;		} 		songTmp.antChn = numChannels;		songTmp.len = h_MOD31.len;		songTmp.repS = h_MOD31.repS;		memcpy(songTmp.songTab, h_MOD31.songTab, 128);		ai = 31;	}	else	{		mightBeSTK = true;		if (fileLength < sizeof (h_MOD15))		{			showMsg(0, "System message", "Error: This file is not a module!");			goto modLoadError;		} 		rewind(f);		if (fread(&h_MOD15, 1, sizeof (h_MOD15), f) != sizeof (h_MOD15))		{			showMsg(0, "System message", "Error: This file is either not a module, or is not supported.");			goto modLoadError;		} 		songTmp.antChn = numChannels;		songTmp.len = h_MOD15.len;		songTmp.repS = h_MOD15.repS;		memcpy(songTmp.songTab, h_MOD15.songTab, 128);		ai = 15;	} 	if (modFormat == FORMAT_MK && songTmp.len == 129)		songTmp.len = 127; // fixes a specific copy of beatwave.mod 	if (songTmp.antChn == 0 || songTmp.len < 1 || songTmp.len > 128 || (mightBeSTK && songTmp.repS > 220))	{		showMsg(0, "System message", "Error: This file is either not a module, or is not supported.");		goto modLoadError;	} 	for (a = 0; a < ai; a++)	{		songMODInstrHeaderTyp *smp = &h_MOD31.instr[a]; 		if (modFormat != FORMAT_HMNT) // most of "His Master's Noisetracker" songs have junk sample names, so let's not load them		{			// trim off spaces at end of name			for (i = 21; i >= 0; i--)			{				if (smp->name[i] == ' ' || smp->name[i] == 0x1A)					smp->name[i] = '\0';				else					break;			} 			memcpy(songTmp.instrName[1+a], smp->name, 22);			songTmp.instrName[1+a][22] = '\0';		} 		/* 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.		*/		if (mightBeSTK && 2*SWAP16(smp->len) > 9999)			lateSTKVerFlag = true;	} 	songTmp.speed = 125;	if (mightBeSTK)	{		/* If we're still here at this point and the mightBeSTK flag is set,		** then it's most likely a proper The Ultimate SoundTracker (STK/UST) module.		*/		modFormat = FORMAT_STK; 		if (songTmp.repS == 0)			songTmp.repS = 120; 		// jjk55.mod by Jesper Kyd has a bogus STK tempo value that should be ignored (hackish!)		if (!strcmp("jjk55", h_MOD31.name))			songTmp.repS = 120; 		// The "restart pos" field in STK is the inital tempo (must be converted to BPM first)		if (songTmp.repS != 120) // 120 is a special case and means 50Hz (125BPM)		{			if (songTmp.repS > 220)				songTmp.repS = 220; 			// convert UST tempo to BPM			uint16_t ciaPeriod = (240 - songTmp.repS) * 122;			double dHz = 709379.0 / ciaPeriod;			int32_t BPM = (int32_t)((dHz * 2.5) + 0.5); 			songTmp.speed = (uint16_t)BPM;		} 		songTmp.repS = 0;	}	else if (songTmp.repS >= songTmp.len)	{		songTmp.repS = 0;	} 	// trim off spaces at end of name	for (i = 19; i >= 0; i--)	{		if (h_MOD31.name[i] == ' ' || h_MOD31.name[i] == 0x1A)			h_MOD31.name[i] = '\0';		else			break;	} 	memcpy(songTmp.name, h_MOD31.name, 20);	songTmp.name[20] = '\0'; 	// count number of patterns	b = 0;	for (a = 0; a < 128; a++)	{		if (songTmp.songTab[a] > b)			b = songTmp.songTab[a];	}	b++; 	for (a = 0; a < b; a++)	{		pattTmp[a] = (tonTyp *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1);		if (pattTmp[a] == NULL)		{			showMsg(0, "System message", "Not enough memory!");			goto modLoadError;		} 		pattLensTmp[a] = 64;		for (j = 0; j < 64; j++)		{			for (k = 0; k < songTmp.antChn; k++)			{				ton = &pattTmp[a][(j * MAX_VOICES) + k]; 				if (fread(bytes, 1, 4, f) != 4)				{					showMsg(0, "System message", "Error: This file is either not a module, or is not supported.");					goto modLoadError;				} 				// period to note				period = ((bytes[0] & 0x0F) << 8) | bytes[1];				for (i = 0; i < 8*12; i++)				{					if (period >= amigaPeriod[i])					{						ton->ton = (uint8_t)i + 1;						break;					}				} 				ton->instr = (bytes[0] & 0xF0) | (bytes[2] >> 4);				ton->effTyp = bytes[2] & 0x0F;				ton->eff = bytes[3]; 				if (modFormat == FORMAT_STK)				{					if (ton->effTyp == 0xC || ton->effTyp == 0xD || ton->effTyp == 0xE)					{						// "TJC SoundTracker II" and later						lateSTKVerFlag = true;					} 					if (ton->effTyp == 0xF)					{						// "DFJ SoundTracker III" and later						lateSTKVerFlag = true;						veryLateSTKVerFlag = true;					}				} 				if (ton->effTyp == 0xC)				{					if (ton->eff > 64)						ton->eff = 64;				}				else if (ton->effTyp == 0x1)				{					if (ton->eff == 0)						ton->effTyp = 0;				}				else if (ton->effTyp == 0x2)				{					if (ton->eff == 0)						ton->effTyp = 0;				}				else if (ton->effTyp == 0x5)				{					if (ton->eff == 0)						ton->effTyp = 0x3;				}				else if (ton->effTyp == 0x6)				{					if (ton->eff == 0)						ton->effTyp = 0x4;				}				else if (ton->effTyp == 0xA)				{					if (ton->eff == 0)						ton->effTyp = 0;				}				else if (ton->effTyp == 0xE)				{					// check if certain E commands are empty					if (ton->eff == 0x10 || ton->eff == 0x20 || ton->eff == 0xA0 || ton->eff == 0xB0)					{						ton->effTyp = 0;

Lines 1–500 of 2692.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t