Olav SørensenUpdate ft2_main.c7c6a6293 years agoHistory
461 lines · 11.6 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 <math.h> // modf()#ifdef _WIN32#define WIN32_MEAN_AND_LEAN#include <windows.h>#include <SDL2/SDL_syswm.h>#else#include <unistd.h> // chdir()#endif#include "ft2_header.h"#include "ft2_gui.h"#include "ft2_video.h"#include "ft2_audio.h"#include "ft2_mouse.h"#include "ft2_keyboard.h"#include "ft2_config.h"#include "ft2_sample_ed.h"#include "ft2_diskop.h"#include "scopes/ft2_scopes.h"#include "ft2_about.h"#include "ft2_pattern_ed.h"#include "ft2_module_loader.h"#include "ft2_sampling.h"#include "ft2_audioselector.h"#include "ft2_help.h"#include "ft2_midi.h"#include "ft2_events.h"#include "ft2_bmp.h"#include "ft2_structs.h"#include "ft2_hpc.h" #ifdef HAS_MIDIstatic SDL_Thread *initMidiThread;#endif static void initializeVars(void);static void cleanUpAndExit(void); // never call this inside the main loop#ifdef __APPLE__static void osxSetDirToProgramDirFromArgs(char **argv);#endif #ifdef _WIN32static void disableWasapi(void);#endif int main(int argc, char *argv[]){#if defined _WIN32 || defined __APPLE__	SDL_version sdlVer;#endif 	// for finding memory leaks in debug mode with Visual Studio#if defined _DEBUG && defined _MSC_VER	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);#endif #if SDL_MAJOR_VERSION == 2 && SDL_MINOR_VERSION == 0 && SDL_PATCHLEVEL < 5#pragma message("WARNING: The SDL2 dev lib is older than ver 2.0.5. You'll get fullscreen mode issues and no audio input sampling.")#pragma message("At least version 2.0.7 is recommended.")#endif 	SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);	SDL_EnableScreenSaver(); // allow screensaver to activate 	initializeVars();	setupCrashHandler(); 	// on Windows and macOS, test what version SDL2.DLL is (against library version used in compilation)#if defined _WIN32 || defined __APPLE__	SDL_GetVersion(&sdlVer);	if (sdlVer.major != SDL_MAJOR_VERSION || sdlVer.minor != SDL_MINOR_VERSION || sdlVer.patch != SDL_PATCHLEVEL)	{#ifdef _WIN32		showErrorMsgBox("SDL2.dll is not the expected version, the program will terminate.\n\n" \		                "Loaded dll version: %d.%d.%d\n" \		                "Required (compiled with) version: %d.%d.%d\n\n",		                sdlVer.major, sdlVer.minor, sdlVer.patch,		                SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL);#else		showErrorMsgBox("The loaded SDL2 library is not the expected version, the program will terminate.\n\n" \		                "Loaded library version: %d.%d.%d\n" \		                "Required (compiled with) version: %d.%d.%d",		                sdlVer.major, sdlVer.minor, sdlVer.patch,		                SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL);#endif		return 0;	}#endif 	// ALT+F4 is used in FT2, but is "close program" in some cases...#if SDL_MINOR_VERSION >= 24 || (SDL_MINOR_VERSION == 0 && SDL_PATCHLEVEL >= 4)	SDL_SetHint("SDL_WINDOWS_NO_CLOSE_ON_ALT_F4", "1");#endif #ifdef _WIN32#ifndef _MSC_VER	SetProcessDPIAware();#endif 	if (!cpu.hasSSE)	{		showErrorMsgBox("Your computer's processor doesn't have the SSE instruction set\n" \		                "which is needed for this program to run. Sorry!");		return 0;	} 	if (!cpu.hasSSE2)	{		showErrorMsgBox("Your computer's processor doesn't have the SSE2 instruction set\n" \		                "which is needed for this program to run. Sorry!");		return 0;	} 	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 	/* SDL 2.0.9 for Windows has a serious bug where you need to initialize the joystick subsystem	** (even if you don't use it) or else weird things happen like random stutters, keyboard (rarely) being	** reinitialized in Windows and what not.	** Ref.: https://bugzilla.libsdl.org/show_bug.cgi?id=4391	*/#if defined _WIN32 && SDL_MAJOR_VERSION == 2 && SDL_MINOR_VERSION == 0 && SDL_PATCHLEVEL == 9	if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) != 0)#else	if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) != 0)#endif	{		showErrorMsgBox("Couldn't initialize SDL:\n%s", SDL_GetError());		return 1;	}	SDL_EventState(SDL_DROPFILE, SDL_ENABLE); 	/* Text input is started by default in SDL2, turn it off to remove ~2ms spikes per key press.	** We manuallay start it again when a text edit box is activated, and stop it when done.	** Ref.: https://bugzilla.libsdl.org/show_bug.cgi?id=4166	*/	SDL_StopTextInput(); 	hpc_Init();	hpc_SetDurationInHz(&video.vblankHpc, VBLANK_HZ); #ifdef __APPLE__	osxSetDirToProgramDirFromArgs(argv);#endif	if (!setupExecutablePath() || !loadBMPs())	{		cleanUpAndExit();		return 1;	} 	if (!calcWindowedSincTables()) // must be called before config is loaded	{		cleanUpAndExit();		return false;	} 	loadConfigOrSetDefaults();	if (!setupWindow() || !setupRenderer())	{		// error message was shown in the functions above		cleanUpAndExit();		return 1;	} #ifdef _WIN32	// allow only one instance, and send arguments to it (what song to play)	if (handleSingleInstancing(argc, argv))	{		cleanUpAndExit();		return 0; // close current instance, the main instance got a message now	}#endif 	if (!setupDiskOp())	{		cleanUpAndExit();		return 1;	} 	audio.currOutputDevice = getAudioOutputDeviceFromConfig();	audio.currInputDevice = getAudioInputDeviceFromConfig(); 	if (!setupAudio(CONFIG_HIDE_ERRORS)) // can we open the audio device?	{		// nope, try with the default audio device		setToDefaultAudioOutputDevice(); 		if (!setupAudio(CONFIG_HIDE_ERRORS)) // does it work this time?		{			// nope, try safe values (44.1kHz 16-bit @ 1024 samples)			config.audioFreq = 44100;			config.specialFlags &= ~(BITDEPTH_32 + BUFFSIZE_512 + BUFFSIZE_2048);			config.specialFlags |=  (BITDEPTH_16 + BUFFSIZE_1024); 			if (!setupAudio(CONFIG_SHOW_ERRORS)) // this time it surely must work?!			{				cleanUpAndExit(); // well, nope!				return 1;			}		}	} 	if (!setupReplayer() || !setupGUI() || !initScopes())	{		cleanUpAndExit();		return 1;	} 	pauseAudio();	resumeAudio();	rescanAudioDevices(); #ifdef _WIN32 // on Windows we show the window at this point	SDL_ShowWindow(video.window);#endif 	if (config.windowFlags & START_IN_FULLSCR)	{		video.fullscreen = true;		enterFullscreen();	} #ifdef HAS_MIDI	// set up MIDI input (in a thread because it can take quite a while on f.ex. macOS)	initMidiThread = SDL_CreateThread(initMidiFunc, NULL, NULL);	if (initMidiThread == NULL)	{		showErrorMsgBox("Couldn't create MIDI initialization thread!");		cleanUpAndExit();		return 1;	}	SDL_DetachThread(initMidiThread); // don't wait for this thread, let it clean up when done#endif 	hpc_ResetCounters(&video.vblankHpc); // quirk: this is needed for potential okBox() calls in handleModuleLoadFromArg()	handleModuleLoadFromArg(argc, argv); 	editor.mainLoopOngoing = true;	hpc_ResetCounters(&video.vblankHpc); // this must be the last thing we do before entering the main loop 	while (editor.programRunning)	{		beginFPSCounter();		handleThreadEvents();		readInput();		handleEvents();		handleRedrawing();		flipFrame();		endFPSCounter();	} 	if (config.cfg_AutoSave)		saveConfig(CONFIG_HIDE_ERRORS); 	cleanUpAndExit();	return 0;} static void initializeVars(void){	cpu.hasSSE = SDL_HasSSE();	cpu.hasSSE2 = SDL_HasSSE2(); 	// clear common structs	memset(&video, 0, sizeof (video));	memset(&keyb, 0, sizeof (keyb));	memset(&mouse, 0, sizeof (mouse));	memset(&editor, 0, sizeof (editor));	memset(&pattMark, 0, sizeof (pattMark));	memset(&pattSync, 0, sizeof (pattSync));	memset(&chSync, 0, sizeof (chSync));	memset(&song, 0, sizeof (song)); 	// used for scopes and sampling position line (sampler screen)	for (int32_t i = 0; i < MAX_CHANNELS; i++)	{		lastChInstr[i].instrNum = 255;		lastChInstr[i].smpNum = 255;	} 	// now set data that must be initialized to non-zero values... 	audio.locked = true;	audio.rescanAudioDevicesSupported = true; 	// set non-zero values 	editor.moduleSaveMode = MOD_SAVE_MODE_XM;	editor.sampleSaveMode = SMP_SAVE_MODE_WAV; 	ui.sampleDataOrLoopDrag = -1; 	mouse.lastUsedObjectID = OBJECT_ID_NONE; 	editor.editRowSkip = 1;	editor.srcInstr = 1;	editor.curInstr = 1;	editor.curOctave = 4;	editor.smpEd_NoteNr = 48 + 1; // middle-C 	editor.ptnJumpPos[0] = 0x00;	editor.ptnJumpPos[1] = 0x10;	editor.ptnJumpPos[2] = 0x20;	editor.ptnJumpPos[3] = 0x30; 	editor.copyMaskEnable = true;	memset(editor.copyMask, 1, sizeof (editor.copyMask));	memset(editor.pasteMask, 1, sizeof (editor.pasteMask)); #ifdef HAS_MIDI	midi.enable = true;#endif 	editor.diskOpReadOnOpen = true;	editor.programRunning = true; 	audio.linearPeriodsFlag = true; 	calcReplayerLogTab();} static void cleanUpAndExit(void) // never call this inside the main loop!{#ifdef HAS_MIDI	if (midi.closeMidiOnExit)	{		closeMidiInDevice();		freeMidiIn();	}#endif 	closeAudio();	closeReplayer();	closeVideo();	freeSprites();	freeDiskOp();	clearCopyBuffer();	freeAudioDeviceSelectorBuffers();#ifdef HAS_MIDI	freeMidiInputDeviceList();#endif	windUpFTHelp();	freeTextBoxes();	freeMouseCursors();	freeBMPs(); #ifdef HAS_MIDI	if (midi.inputDeviceName != NULL)	{		free(midi.inputDeviceName);		midi.inputDeviceName = NULL;	}#endif 	if (editor.audioDevConfigFileLocationU != NULL)	{		free(editor.audioDevConfigFileLocationU);		editor.audioDevConfigFileLocationU = NULL;	} 	if (editor.configFileLocationU != NULL)	{		free(editor.configFileLocationU);		editor.configFileLocationU = NULL;	} 	if (editor.midiConfigFileLocationU != NULL)	{		free(editor.midiConfigFileLocationU);		editor.midiConfigFileLocationU = NULL;	} 	if (editor.binaryPathU != NULL)	{		free(editor.binaryPathU);		editor.binaryPathU = NULL;	} #ifdef _WIN32	closeSingleInstancing();#endif 	SDL_Quit();} #ifdef __APPLE__static void osxSetDirToProgramDirFromArgs(char **argv){	/* OS X/macOS: hackish way of setting the current working directory to the place where we double clicked	** on the icon (for protracker.ini loading)	*/ 	// if we launched from the terminal, argv[0][0] would be '.'	if (argv[0] != NULL && argv[0][0] == DIR_DELIMITER) // don't do the hack if we launched from the terminal	{		char *tmpPath = strdup(argv[0]);		if (tmpPath != NULL)		{			// cut off program filename			int32_t tmpPathLen = strlen(tmpPath);			for (int32_t i = tmpPathLen - 1; i >= 0; i--)			{				if (tmpPath[i] == DIR_DELIMITER)				{					tmpPath[i] = '\0';					break;				}			} 			chdir(tmpPath); // path to binary			chdir("../../../"); // we should now be in the directory where the config can be 			free(tmpPath);		}	}}#endif #ifdef _WIN32static void disableWasapi(void){	// disable problematic WASAPI SDL2 audio driver on Windows (causes clicks/pops sometimes...) 	const int32_t numAudioDrivers = SDL_GetNumAudioDrivers();	if (numAudioDrivers <= 1)		return; 	// look for directsound and enable it if found	for (int32_t i = 0; i < numAudioDrivers; i++)	{		const char *audioDriver = SDL_GetAudioDriver(i);		if (audioDriver != NULL && strcmp("directsound", audioDriver) == 0)		{			SDL_setenv("SDL_AUDIODRIVER", "directsound", true);			audio.rescanAudioDevicesSupported = false;			return;		}	} 	// directsound is not available, try winmm	for (int32_t i = 0; i < numAudioDrivers; i++)	{		const char *audioDriver = SDL_GetAudioDriver(i);		if (audioDriver != NULL && strcmp("winmm", audioDriver) == 0)		{			SDL_setenv("SDL_AUDIODRIVER", "winmm", true);			audio.rescanAudioDevicesSupported = false;			return;		}	} 	// we didn't find directsound or winmm, let's use wasapi after all...}#endif

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