2022-02-14 22:12:20 -05:00
/**
* Furnace Tracker - multi - system chiptune tracker
2024-01-16 21:26:57 -05:00
* Copyright ( C ) 2021 - 2024 tildearrow and contributors
2022-02-14 22:12:20 -05:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2021-05-11 16:08:08 -04:00
# include <stdio.h>
2022-01-17 21:08:14 -05:00
# include <stdint.h>
2023-09-20 01:24:55 -04:00
# include "pch.h"
2022-07-25 17:21:39 -04:00
# ifdef HAVE_SDL2
2022-01-26 03:00:58 -05:00
# include "SDL_events.h"
2022-01-27 04:25:16 -05:00
# endif
2021-05-11 16:08:08 -04:00
# include "ta-log.h"
2022-01-20 05:04:03 -05:00
# include "fileutils.h"
2021-05-11 16:08:08 -04:00
# include "engine/engine.h"
2021-05-28 16:25:55 -04:00
# ifdef _WIN32
# include <windows.h>
2022-06-09 17:10:51 -04:00
# include <combaseapi.h>
2021-12-16 15:51:19 -05:00
# include <shellapi.h>
2024-06-18 19:28:10 -04:00
# include "utfutils.h"
2023-01-14 23:16:29 -05:00
# include "gui/shellScalingStub.h"
typedef HRESULT ( WINAPI * SPDA ) ( PROCESS_DPI_AWARENESS ) ;
2021-05-28 16:25:55 -04:00
# else
2023-07-09 20:19:37 -04:00
# include <signal.h>
2021-05-28 16:25:55 -04:00
# include <unistd.h>
2023-07-09 20:19:37 -04:00
2024-02-03 15:33:17 -05:00
struct sigaction termsa ;
2021-05-28 16:25:55 -04:00
# endif
2024-05-01 16:16:55 -04:00
# ifdef SUPPORT_XP
# define TUT_INTRO_PLAYED true
# else
# define TUT_INTRO_PLAYED false
# endif
2024-06-16 00:59:25 -04:00
# ifdef HAVE_LOCALE
2024-05-30 20:34:34 -04:00
# ifdef HAVE_MOMO
# define TA_BINDTEXTDOMAIN momo_bindtextdomain
# define TA_TEXTDOMAIN momo_textdomain
# else
# define TA_BINDTEXTDOMAIN bindtextdomain
# define TA_TEXTDOMAIN textdomain
# endif
2024-06-13 15:41:01 -04:00
# ifdef HAVE_SETLOCALE
# include <locale.h>
# endif
2024-05-31 20:55:56 -04:00
# ifndef LC_CTYPE
# define LC_CTYPE 0
# endif
# ifndef LC_MESSAGES
# define LC_MESSAGES 1
# endif
2024-06-16 00:59:25 -04:00
# endif
2024-05-31 20:55:56 -04:00
2022-07-25 18:23:56 -04:00
# include "cli/cli.h"
2021-12-11 03:11:40 -05:00
# ifdef HAVE_GUI
# include "gui/gui.h"
# endif
2021-05-11 16:08:08 -04:00
DivEngine e ;
2021-12-11 03:11:40 -05:00
# ifdef HAVE_GUI
FurnaceGUI g ;
# endif
2022-07-25 18:23:56 -04:00
FurnaceCLI cli ;
2021-12-07 12:21:23 -05:00
String outName ;
2022-01-24 13:15:07 -05:00
String vgmOutName ;
2022-05-26 01:24:21 -04:00
String zsmOutName ;
2022-08-04 16:18:48 -04:00
String cmdOutName ;
2022-07-19 18:01:19 -04:00
int benchMode = 0 ;
2023-05-19 01:49:05 -04:00
int subsong = - 1 ;
2024-05-10 21:01:12 -04:00
DivAudioExportOptions exportOptions ;
2021-12-07 12:21:23 -05:00
2021-12-11 03:11:40 -05:00
# ifdef HAVE_GUI
bool consoleMode = false ;
# else
bool consoleMode = true ;
# endif
2024-04-23 05:38:08 -04:00
bool consoleNoStatus = false ;
bool consoleNoControls = false ;
2022-02-05 23:48:56 -05:00
bool displayEngineFailError = false ;
2024-06-14 04:10:19 -04:00
bool displayLocaleFailError = false ;
2022-10-17 15:25:30 -04:00
bool vgmOutDirect = false ;
2022-02-05 23:48:56 -05:00
2023-10-16 07:53:21 -04:00
bool safeMode = false ;
2023-10-16 15:01:30 -04:00
bool safeModeWithAudio = false ;
2023-10-16 07:53:21 -04:00
2023-10-17 15:11:35 -04:00
bool infoMode = false ;
2021-06-09 04:33:03 -04:00
std : : vector < TAParam > params ;
2024-06-16 00:59:25 -04:00
# ifdef HAVE_LOCALE
char localeDir [ 4096 ] ;
const char * localeDirs [ ] = {
" locale " ,
2024-06-18 19:00:22 -04:00
" .. " DIR_SEPARATOR_STR " share " DIR_SEPARATOR_STR " locale " ,
" .. " DIR_SEPARATOR_STR " po " DIR_SEPARATOR_STR " locale " ,
2024-06-16 00:59:25 -04:00
# ifdef LOCALE_DIR
LOCALE_DIR ,
# endif
NULL
} ;
# endif
2024-06-18 19:00:22 -04:00
bool getExePath ( char * argv0 , char * exePath , size_t maxSize ) {
if ( argv0 = = NULL ) return false ;
2024-06-18 19:13:48 -04:00
# ifdef _WIN32
wchar_t exePathW [ 4096 ] ;
WString argv0W = utf8To16 ( argv0 ) ;
if ( GetFullPathNameW ( argv0W . c_str ( ) , 4095 , exePathW , NULL ) = = 0 ) return false ;
String exePathS = utf16To8 ( exePathW . c_str ( ) ) ;
strncpy ( exePath , exePathS . c_str ( ) , maxSize ) ;
# else
2024-06-18 19:00:22 -04:00
if ( realpath ( argv0 , exePath ) = = NULL ) return false ;
2024-06-18 19:13:48 -04:00
# endif
2024-06-18 19:00:22 -04:00
char * lastChar = strrchr ( exePath , DIR_SEPARATOR ) ;
if ( lastChar = = NULL ) return false ;
* lastChar = 0 ;
return true ;
}
2022-04-25 16:54:31 -04:00
TAParamResult pHelp ( String ) {
2021-06-09 04:33:03 -04:00
printf ( " usage: furnace [params] [filename] \n "
" you may specify the following parameters: \n " ) ;
for ( auto & i : params ) {
if ( i . value ) {
printf ( " -%s %s: %s \n " , i . name . c_str ( ) , i . valName . c_str ( ) , i . desc . c_str ( ) ) ;
} else {
printf ( " -%s: %s \n " , i . name . c_str ( ) , i . desc . c_str ( ) ) ;
}
}
2022-04-25 16:54:31 -04:00
return TA_PARAM_QUIT ;
2021-06-09 04:33:03 -04:00
}
2022-04-25 16:54:31 -04:00
TAParamResult pAudio ( String val ) {
2022-01-22 23:50:49 -05:00
if ( outName ! = " " ) {
2022-04-10 23:12:02 -04:00
logE ( " can't use -audio and -output at the same time. " ) ;
2022-04-25 16:54:31 -04:00
return TA_PARAM_ERROR ;
2022-01-22 23:50:49 -05:00
}
2021-06-09 04:33:03 -04:00
if ( val = = " jack " ) {
e . setAudio ( DIV_AUDIO_JACK ) ;
} else if ( val = = " sdl " ) {
e . setAudio ( DIV_AUDIO_SDL ) ;
2023-10-16 07:53:21 -04:00
} else if ( val = = " portaudio " ) {
e . setAudio ( DIV_AUDIO_PORTAUDIO ) ;
2024-04-23 05:38:08 -04:00
} else if ( val = = " pipe " ) {
e . setAudio ( DIV_AUDIO_PIPE ) ;
changeLogOutput ( stderr ) ;
2021-06-09 04:33:03 -04:00
} else {
2024-04-23 05:38:08 -04:00
logE ( " invalid value for audio engine! valid values are: jack, sdl, portaudio, pipe. " ) ;
2022-04-25 16:54:31 -04:00
return TA_PARAM_ERROR ;
2021-06-09 04:33:03 -04:00
}
2022-04-25 16:54:31 -04:00
return TA_PARAM_SUCCESS ;
2021-06-09 04:33:03 -04:00
}
2022-04-25 16:54:31 -04:00
TAParamResult pView ( String val ) {
2021-06-09 04:33:03 -04:00
if ( val = = " pattern " ) {
e . setView ( DIV_STATUS_PATTERN ) ;
} else if ( val = = " commands " ) {
e . setView ( DIV_STATUS_COMMANDS ) ;
} else if ( val = = " nothing " ) {
e . setView ( DIV_STATUS_NOTHING ) ;
} else {
2022-04-10 23:12:02 -04:00
logE ( " invalid value for view type! valid values are: pattern, commands, nothing. " ) ;
2022-04-25 16:54:31 -04:00
return TA_PARAM_ERROR ;
2021-06-09 04:33:03 -04:00
}
2022-04-25 16:54:31 -04:00
return TA_PARAM_SUCCESS ;
2021-06-09 04:33:03 -04:00
}
2022-04-25 16:54:31 -04:00
TAParamResult pConsole ( String val ) {
2021-12-11 03:11:40 -05:00
consoleMode = true ;
2022-04-25 16:54:31 -04:00
return TA_PARAM_SUCCESS ;
2021-12-11 03:11:40 -05:00
}
2024-04-23 05:38:08 -04:00
TAParamResult pNoStatus ( String val ) {
consoleNoStatus = true ;
return TA_PARAM_SUCCESS ;
}
TAParamResult pNoControls ( String val ) {
consoleNoControls = true ;
return TA_PARAM_SUCCESS ;
}
2023-10-16 07:53:21 -04:00
TAParamResult pSafeMode ( String val ) {
2023-10-16 15:55:01 -04:00
# ifdef HAVE_GUI
2023-10-16 07:53:21 -04:00
safeMode = true ;
return TA_PARAM_SUCCESS ;
2023-10-16 15:55:01 -04:00
# else
logE ( " Furnace was compiled without the GUI. safe mode is pointless. " ) ;
return TA_PARAM_ERROR ;
# endif
2023-10-16 07:53:21 -04:00
}
2023-10-16 15:01:30 -04:00
TAParamResult pSafeModeAudio ( String val ) {
2023-10-16 15:55:01 -04:00
# ifdef HAVE_GUI
2023-10-16 15:01:30 -04:00
safeMode = true ;
safeModeWithAudio = true ;
return TA_PARAM_SUCCESS ;
2023-10-16 15:55:01 -04:00
# else
logE ( " Furnace was compiled without the GUI. safe mode is pointless. " ) ;
return TA_PARAM_ERROR ;
# endif
2023-10-16 15:01:30 -04:00
}
2022-10-17 15:25:30 -04:00
TAParamResult pDirect ( String val ) {
vgmOutDirect = true ;
return TA_PARAM_SUCCESS ;
}
2023-10-17 15:11:35 -04:00
TAParamResult pInfo ( String val ) {
infoMode = true ;
return TA_PARAM_SUCCESS ;
}
2022-04-25 16:54:31 -04:00
TAParamResult pLogLevel ( String val ) {
2022-03-23 23:05:09 -04:00
if ( val = = " trace " ) {
logLevel = LOGLEVEL_TRACE ;
} else if ( val = = " debug " ) {
2021-06-09 13:28:46 -04:00
logLevel = LOGLEVEL_DEBUG ;
} else if ( val = = " info " ) {
logLevel = LOGLEVEL_INFO ;
} else if ( val = = " warning " ) {
logLevel = LOGLEVEL_WARN ;
} else if ( val = = " error " ) {
logLevel = LOGLEVEL_ERROR ;
} else {
2022-04-10 23:12:02 -04:00
logE ( " invalid value for loglevel! valid values are: trace, debug, info, warning, error. " ) ;
2022-04-25 16:54:31 -04:00
return TA_PARAM_ERROR ;
2021-06-09 13:28:46 -04:00
}
2022-04-25 16:54:31 -04:00
return TA_PARAM_SUCCESS ;
2021-06-09 13:28:46 -04:00
}
2022-04-25 16:54:31 -04:00
TAParamResult pVersion ( String ) {
2022-04-01 06:20:00 -04:00
printf ( " Furnace version " DIV_VERSION " . \n \n " ) ;
2024-01-16 21:26:57 -05:00
printf ( " copyright (C) 2021-2024 tildearrow and contributors. \n " ) ;
2022-02-14 21:59:26 -05:00
printf ( " licensed under the GNU General Public License version 2 or later \n " ) ;
2021-06-09 04:33:03 -04:00
printf ( " <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>. \n \n " ) ;
printf ( " this is free software with ABSOLUTELY NO WARRANTY. \n " ) ;
printf ( " pass the -warranty parameter for more information. \n \n " ) ;
printf ( " DISCLAIMER: this program is not affiliated with Delek in any form. \n " ) ;
2021-12-07 13:01:59 -05:00
printf ( " \n " ) ;
2022-04-01 06:20:00 -04:00
printf ( " furnace is powered by: \n " ) ;
2021-12-07 13:01:59 -05:00
printf ( " - libsndfile by Erik de Castro Lopo and rest of libsndfile team (LGPLv2.1) \n " ) ;
printf ( " - SDL2 by Sam Lantinga (zlib license) \n " ) ;
printf ( " - zlib by Jean-loup Gailly and Mark Adler (zlib license) \n " ) ;
2023-08-30 18:38:45 -04:00
printf ( " - PortAudio (PortAudio license) \n " ) ;
2023-09-13 21:10:09 -04:00
printf ( " - Weak-JACK by x42 (GPLv2) \n " ) ;
2022-06-29 05:57:05 -04:00
printf ( " - RtMidi by Gary P. Scavone (RtMidi license) \n " ) ;
printf ( " - backward-cpp by Google (MIT) \n " ) ;
2021-12-11 03:11:40 -05:00
printf ( " - Dear ImGui by Omar Cornut (MIT) \n " ) ;
2023-10-16 07:53:21 -04:00
# ifdef HAVE_FREETYPE
printf ( " - FreeType (GPLv2) \n " ) ;
# endif
2022-06-29 05:57:05 -04:00
printf ( " - Portable File Dialogs by Sam Hocevar (WTFPL) \n " ) ;
printf ( " - Native File Dialog (modified version) by Frogtoss Games (zlib license) \n " ) ;
printf ( " - FFTW by Matteo Frigo and Steven G. Johnson (GPLv2) \n " ) ;
2023-11-23 18:30:47 -05:00
printf ( " - Nuked-OPM by nukeykt (LGPLv2.1) \n " ) ;
printf ( " - Nuked-OPN2 by nukeykt (LGPLv2.1) \n " ) ;
printf ( " - Nuked-OPL3 by nukeykt (LGPLv2.1) \n " ) ;
printf ( " - Nuked-OPLL by nukeykt (GPLv2) \n " ) ;
printf ( " - Nuked-PSG (modified version) by nukeykt (GPLv2) \n " ) ;
printf ( " - YM3812-LLE by nukeykt (GPLv2) \n " ) ;
printf ( " - YMF262-LLE by nukeykt (GPLv2) \n " ) ;
2023-11-25 17:46:46 -05:00
printf ( " - YMF276-LLE by nukeykt (GPLv2) \n " ) ;
2024-04-25 20:54:57 -04:00
printf ( " - YM2608-LLE by nukeykt (GPLv2) \n " ) ;
2024-03-11 14:21:50 -04:00
printf ( " - ESFMu (modified version) by Kagamiin~ (LGPLv2.1) \n " ) ;
2021-12-11 03:11:40 -05:00
printf ( " - ymfm by Aaron Giles (BSD 3-clause) \n " ) ;
2024-04-06 19:49:43 -04:00
printf ( " - emu2413 by Digital Sound Antiques (MIT) \n " ) ;
2022-06-29 05:57:05 -04:00
printf ( " - adpcm by superctr (public domain) \n " ) ;
2024-03-17 16:05:07 -04:00
printf ( " - adpcm-xq by David Bryant (BSD 3-clause) \n " ) ;
2021-12-07 13:01:59 -05:00
printf ( " - MAME SN76496 emulation core by Nicola Salmoria (BSD 3-clause) \n " ) ;
2022-01-13 02:52:19 -05:00
printf ( " - MAME AY-3-8910 emulation core by Couriersud (BSD 3-clause) \n " ) ;
2022-01-16 01:47:19 -05:00
printf ( " - MAME SAA1099 emulation core by Juergen Buchmueller and Manuel Abadia (BSD 3-clause) \n " ) ;
2022-06-29 05:57:05 -04:00
printf ( " - MAME Namco WSG by Nicola Salmoria and Aaron Giles (BSD 3-clause) \n " ) ;
printf ( " - MAME RF5C68 core by Olivier Galibert and Aaron Giles (BSD 3-clause) \n " ) ;
2022-10-02 20:12:31 -04:00
printf ( " - MAME MSM5232 core by Jarek Burczynski and Hiromitsu Shioya (GPLv2) \n " ) ;
2022-06-29 05:57:05 -04:00
printf ( " - MAME MSM6258 core by Barry Rodewald (BSD 3-clause) \n " ) ;
printf ( " - MAME YMZ280B core by Aaron Giles (BSD 3-clause) \n " ) ;
2022-12-24 23:39:44 -05:00
printf ( " - MAME GA20 core by Acho A. Tang and R. Belmont (BSD 3-clause) \n " ) ;
2023-02-10 02:01:23 -05:00
printf ( " - MAME SegaPCM core by Hiromitsu Shioya and Olivier Galibert (BSD 3-clause) \n " ) ;
2022-06-29 05:57:05 -04:00
printf ( " - QSound core by superctr (BSD 3-clause) \n " ) ;
printf ( " - VICE VIC-20 by Rami Rasanen and viznut (GPLv2) \n " ) ;
2023-07-23 06:26:25 -04:00
printf ( " - VICE TED by Andreas Boose, Tibor Biczo and Marco van den Heuvel (GPLv2) \n " ) ;
2022-06-29 05:57:05 -04:00
printf ( " - VERA core by Frank van den Hoef (BSD 2-clause) \n " ) ;
printf ( " - SAASound by Dave Hooper and Simon Owen (BSD 3-clause) \n " ) ;
2021-12-07 13:01:59 -05:00
printf ( " - SameBoy by Lior Halphon (MIT) \n " ) ;
2022-10-11 03:23:29 -04:00
printf ( " - Mednafen PCE, WonderSwan and Virtual Boy by Mednafen Team (GPLv2) \n " ) ;
printf ( " - Mednafen T6W28 by Blargg (GPLv2) \n " ) ;
2022-10-02 20:12:31 -04:00
printf ( " - SNES DSP core by Blargg (LGPLv2.1) \n " ) ;
2021-12-07 13:01:59 -05:00
printf ( " - puNES by FHorse (GPLv2) \n " ) ;
2022-06-29 05:57:05 -04:00
printf ( " - NSFPlay by Brad Smith and Brezza (unknown open-source license) \n " ) ;
2021-12-07 13:01:59 -05:00
printf ( " - reSID by Dag Lem (GPLv2) \n " ) ;
2022-08-28 16:10:16 -04:00
printf ( " - reSIDfp by Dag Lem, Antti Lankila and Leandro Nini (GPLv2) \n " ) ;
2023-07-05 21:38:31 -04:00
printf ( " - dSID by DefleMask Team (based on jsSID by Hermit) (MIT) \n " ) ;
2022-01-14 03:37:36 -05:00
printf ( " - Stella by Stella Team (GPLv2) \n " ) ;
2022-09-18 00:19:08 -04:00
printf ( " - vgsound_emu (second version, modified version) by cam900 (zlib license) \n " ) ;
2022-12-15 06:03:54 -05:00
printf ( " - MAME GA20 core by Acho A. Tang, R. Belmont, Valley Bell (BSD 3-clause) \n " ) ;
2022-12-22 19:25:11 -05:00
printf ( " - Atari800 mzpokeysnd POKEY emulator by Michael Borisov (GPLv2) \n " ) ;
printf ( " - ASAP POKEY emulator by Piotr Fusik ported to C++ by laoo (GPLv2) \n " ) ;
2023-08-08 08:27:12 -04:00
printf ( " - SM8521 emulator (modified version) by cam900 (zlib license) \n " ) ;
printf ( " - D65010G031 emulator (modified version) by cam900 (zlib license) \n " ) ;
2023-08-27 16:52:54 -04:00
printf ( " - C140/C219 emulator (modified version) by cam900 (zlib license) \n " ) ;
2024-01-25 13:33:22 -05:00
printf ( " - PowerNoise emulator by scratchminer (MIT) \n " ) ;
2024-02-10 21:49:20 -05:00
printf ( " - ep128emu by Istvan Varga (GPLv2) \n " ) ;
printf ( " - NDS sound emulator by cam900 (zlib license) \n " ) ;
2022-04-25 16:54:31 -04:00
return TA_PARAM_QUIT ;
2021-06-09 04:33:03 -04:00
}
2022-04-25 16:54:31 -04:00
TAParamResult pWarranty ( String ) {
2021-06-09 04:33:03 -04:00
printf ( " This program is free software; you can redistribute it and/or \n "
" modify it under the terms of the GNU General Public License \n "
" as published by the Free Software Foundation; either version 2 \n "
" of the License, or (at your option) any later version. \n \n "
" This program is distributed in the hope that it will be useful, \n "
" but WITHOUT ANY WARRANTY; without even the implied warranty of \n "
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \n "
" GNU General Public License for more details. \n \n "
" You should have received a copy of the GNU General Public License \n "
" along with this program; if not, write to the Free Software \n "
" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. \n " ) ;
2022-04-25 16:54:31 -04:00
return TA_PARAM_QUIT ;
2021-06-09 04:33:03 -04:00
}
2022-04-25 16:54:31 -04:00
TAParamResult pLoops ( String val ) {
2021-12-07 04:22:36 -05:00
try {
int count = std : : stoi ( val ) ;
if ( count < 0 ) {
2024-05-10 21:01:12 -04:00
exportOptions . loops = 0 ;
2021-12-07 04:22:36 -05:00
} else {
2024-05-10 21:01:12 -04:00
exportOptions . loops = count ;
2021-12-07 04:22:36 -05:00
}
} catch ( std : : exception & e ) {
2022-04-10 23:12:02 -04:00
logE ( " loop count shall be a number. " ) ;
2022-04-25 16:54:31 -04:00
return TA_PARAM_ERROR ;
2021-12-07 04:22:36 -05:00
}
2022-04-25 16:54:31 -04:00
return TA_PARAM_SUCCESS ;
2021-12-07 04:22:36 -05:00
}
2023-05-19 01:49:05 -04:00
TAParamResult pSubSong ( String val ) {
try {
int v = std : : stoi ( val ) ;
if ( v < 0 ) {
logE ( " sub-song shall be 0 or higher. " ) ;
return TA_PARAM_ERROR ;
}
subsong = v ;
} catch ( std : : exception & e ) {
logE ( " sub-song shall be a number. " ) ;
return TA_PARAM_ERROR ;
}
return TA_PARAM_SUCCESS ;
}
2022-04-25 16:54:31 -04:00
TAParamResult pOutMode ( String val ) {
2022-01-22 23:50:49 -05:00
if ( val = = " one " ) {
2024-05-10 21:01:12 -04:00
exportOptions . mode = DIV_EXPORT_MODE_ONE ;
2022-01-22 23:50:49 -05:00
} else if ( val = = " persys " ) {
2024-05-10 21:01:12 -04:00
exportOptions . mode = DIV_EXPORT_MODE_MANY_SYS ;
2022-01-22 23:50:49 -05:00
} else if ( val = = " perchan " ) {
2024-05-10 21:01:12 -04:00
exportOptions . mode = DIV_EXPORT_MODE_MANY_CHAN ;
2022-01-22 23:50:49 -05:00
} else {
2022-04-10 23:12:02 -04:00
logE ( " invalid value for outmode! valid values are: one, persys and perchan. " ) ;
2022-04-25 16:54:31 -04:00
return TA_PARAM_ERROR ;
2022-01-22 23:50:49 -05:00
}
2022-04-25 16:54:31 -04:00
return TA_PARAM_SUCCESS ;
2022-01-22 23:50:49 -05:00
}
2022-07-19 18:01:19 -04:00
TAParamResult pBenchmark ( String val ) {
if ( val = = " render " ) {
benchMode = 1 ;
} else if ( val = = " seek " ) {
benchMode = 2 ;
} else {
logE ( " invalid value for benchmark! valid values are: render and seek. " ) ;
return TA_PARAM_ERROR ;
}
e . setAudio ( DIV_AUDIO_DUMMY ) ;
return TA_PARAM_SUCCESS ;
}
2022-04-25 16:54:31 -04:00
TAParamResult pOutput ( String val ) {
2021-12-07 12:21:23 -05:00
outName = val ;
2022-01-22 23:50:49 -05:00
e . setAudio ( DIV_AUDIO_DUMMY ) ;
2022-04-25 16:54:31 -04:00
return TA_PARAM_SUCCESS ;
2021-12-07 04:22:36 -05:00
}
2022-04-25 16:54:31 -04:00
TAParamResult pVGMOut ( String val ) {
2022-01-24 13:15:07 -05:00
vgmOutName = val ;
e . setAudio ( DIV_AUDIO_DUMMY ) ;
2022-04-25 16:54:31 -04:00
return TA_PARAM_SUCCESS ;
2022-01-24 13:15:07 -05:00
}
2022-05-26 01:24:21 -04:00
TAParamResult pZSMOut ( String val ) {
zsmOutName = val ;
e . setAudio ( DIV_AUDIO_DUMMY ) ;
return TA_PARAM_SUCCESS ;
}
2022-08-04 16:18:48 -04:00
TAParamResult pCmdOut ( String val ) {
cmdOutName = val ;
e . setAudio ( DIV_AUDIO_DUMMY ) ;
return TA_PARAM_SUCCESS ;
}
2021-06-09 04:33:03 -04:00
bool needsValue ( String param ) {
for ( size_t i = 0 ; i < params . size ( ) ; i + + ) {
if ( params [ i ] . name = = param ) {
return params [ i ] . value ;
}
}
return false ;
}
void initParams ( ) {
params . push_back ( TAParam ( " h " , " help " , false , pHelp , " " , " display this help " ) ) ;
2024-04-23 05:38:08 -04:00
params . push_back ( TAParam ( " a " , " audio " , true , pAudio , " jack|sdl|portaudio|pipe " , " set audio engine (SDL by default) " ) ) ;
2021-12-07 04:22:36 -05:00
params . push_back ( TAParam ( " o " , " output " , true , pOutput , " <filename> " , " output audio to file " ) ) ;
2022-01-24 13:15:07 -05:00
params . push_back ( TAParam ( " O " , " vgmout " , true , pVGMOut , " <filename> " , " output .vgm data " ) ) ;
2022-10-17 15:25:30 -04:00
params . push_back ( TAParam ( " D " , " direct " , false , pDirect , " " , " set VGM export direct stream mode " ) ) ;
2022-05-26 01:24:21 -04:00
params . push_back ( TAParam ( " Z " , " zsmout " , true , pZSMOut , " <filename> " , " output .zsm data for Commander X16 Zsound " ) ) ;
2022-08-04 16:18:48 -04:00
params . push_back ( TAParam ( " C " , " cmdout " , true , pCmdOut , " <filename> " , " output command stream " ) ) ;
2021-06-09 13:28:46 -04:00
params . push_back ( TAParam ( " L " , " loglevel " , true , pLogLevel , " debug|info|warning|error " , " set the log level (info by default) " ) ) ;
2023-11-01 14:48:17 -04:00
params . push_back ( TAParam ( " v " , " view " , true , pView , " pattern|commands|nothing " , " set visualization (nothing by default) " ) ) ;
2023-10-17 15:11:35 -04:00
params . push_back ( TAParam ( " i " , " info " , false , pInfo , " " , " get info about a song " ) ) ;
2021-12-11 03:11:40 -05:00
params . push_back ( TAParam ( " c " , " console " , false , pConsole , " " , " enable console mode " ) ) ;
2024-04-23 05:38:08 -04:00
params . push_back ( TAParam ( " n " , " nostatus " , false , pNoStatus , " " , " disable playback status in console mode " ) ) ;
params . push_back ( TAParam ( " N " , " nocontrols " , false , pNoControls , " " , " disable standard input controls in console mode " ) ) ;
2021-06-09 04:33:03 -04:00
2024-05-10 21:01:12 -04:00
params . push_back ( TAParam ( " l " , " loops " , true , pLoops , " <count> " , " set number of loops " ) ) ;
2023-05-19 01:49:05 -04:00
params . push_back ( TAParam ( " s " , " subsong " , true , pSubSong , " <number> " , " set sub-song " ) ) ;
2022-01-22 23:50:49 -05:00
params . push_back ( TAParam ( " o " , " outmode " , true , pOutMode , " one|persys|perchan " , " set file output mode " ) ) ;
2023-10-16 07:53:21 -04:00
params . push_back ( TAParam ( " S " , " safemode " , false , pSafeMode , " " , " enable safe mode (software rendering and no audio) " ) ) ;
2023-10-16 15:01:30 -04:00
params . push_back ( TAParam ( " A " , " safeaudio " , false , pSafeModeAudio , " " , " enable safe mode (with audio " ) ) ;
2021-12-07 04:22:36 -05:00
2022-07-19 18:01:19 -04:00
params . push_back ( TAParam ( " B " , " benchmark " , true , pBenchmark , " render|seek " , " run performance test " ) ) ;
2022-04-01 06:20:00 -04:00
params . push_back ( TAParam ( " V " , " version " , false , pVersion , " " , " view information about Furnace. " ) ) ;
2021-06-09 04:33:03 -04:00
params . push_back ( TAParam ( " W " , " warranty " , false , pWarranty , " " , " view warranty disclaimer. " ) ) ;
}
2022-06-29 00:42:34 -04:00
# ifdef _WIN32
void reportError ( String what ) {
logE ( " %s " , what ) ;
MessageBox ( NULL , what . c_str ( ) , " Furnace " , MB_OK | MB_ICONERROR ) ;
}
2024-04-14 17:41:04 -04:00
# elif defined(ANDROID) || defined(__APPLE__)
2022-11-05 19:17:54 -04:00
void reportError ( String what ) {
logE ( " %s " , what ) ;
# ifdef HAVE_SDL2
SDL_ShowSimpleMessageBox ( SDL_MESSAGEBOX_ERROR , " Error " , what . c_str ( ) , NULL ) ;
# endif
}
2022-06-29 00:42:34 -04:00
# else
void reportError ( String what ) {
logE ( " %s " , what ) ;
}
# endif
2023-07-09 20:19:37 -04:00
# ifndef _WIN32
# ifdef HAVE_GUI
static void handleTermGUI ( int ) {
g . requestQuit ( ) ;
}
# endif
# endif
2022-04-15 17:00:21 -04:00
// TODO: CoInitializeEx on Windows?
2022-04-18 04:17:11 -04:00
// TODO: add crash log
2021-05-11 16:08:08 -04:00
int main ( int argc , char * * argv ) {
2023-07-10 22:48:41 -04:00
// uncomment these if you want Furnace to play in the background on Android.
// not recommended. it lags.
# if defined(HAVE_SDL2) && defined(ANDROID)
//SDL_SetHint(SDL_HINT_ANDROID_BLOCK_ON_PAUSE,"0");
//SDL_SetHint(SDL_HINT_ANDROID_BLOCK_ON_PAUSE_PAUSEAUDIO,"0");
# endif
2023-02-25 03:20:51 -05:00
// Windows console thing - thanks dj.tuBIG/MaliceX
2023-02-13 19:26:37 -05:00
# ifdef _WIN32
2024-05-04 17:46:41 -04:00
# ifndef TA_SUBSYSTEM_CONSOLE
2023-02-25 03:20:51 -05:00
if ( AttachConsole ( ATTACH_PARENT_PROCESS ) ) {
freopen ( " CONOUT$ " , " w " , stdout ) ;
freopen ( " CONOUT$ " , " w " , stderr ) ;
freopen ( " CONIN$ " , " r " , stdin ) ;
}
2024-05-04 17:46:41 -04:00
# endif
2023-02-13 19:26:37 -05:00
# endif
2023-03-01 15:26:05 -05:00
srand ( time ( NULL ) ) ;
2024-04-23 05:38:08 -04:00
initLog ( stdout ) ;
2022-06-09 17:10:51 -04:00
# ifdef _WIN32
2023-01-14 23:16:29 -05:00
// set DPI awareness
HMODULE shcore = LoadLibraryW ( L " shcore.dll " ) ;
if ( shcore ! = NULL ) {
SPDA ta_SetProcessDpiAwareness = ( SPDA ) GetProcAddress ( shcore , " SetProcessDpiAwareness " ) ;
if ( ta_SetProcessDpiAwareness ! = NULL ) {
HRESULT result = ta_SetProcessDpiAwareness ( PROCESS_PER_MONITOR_DPI_AWARE ) ;
if ( result ! = S_OK ) {
// ???
}
}
if ( ! FreeLibrary ( shcore ) ) {
// ???
}
}
// co initialize ex
2022-06-09 17:10:51 -04:00
HRESULT coResult = CoInitializeEx ( NULL , COINIT_MULTITHREADED ) ;
if ( coResult ! = S_OK ) {
logE ( " CoInitializeEx failed! " ) ;
}
2022-02-08 17:35:41 -05:00
# endif
2021-12-07 12:21:23 -05:00
outName = " " ;
2022-01-24 13:15:07 -05:00
vgmOutName = " " ;
2022-05-26 01:24:21 -04:00
zsmOutName = " " ;
2022-08-04 16:18:48 -04:00
cmdOutName = " " ;
2021-06-09 04:33:03 -04:00
2024-06-01 17:36:00 -04:00
// load config for locale
e . prePreInit ( ) ;
2024-05-26 04:57:26 -04:00
# ifdef HAVE_LOCALE
2024-06-01 17:36:00 -04:00
String reqLocale = e . getConfString ( " locale " , " " ) ;
2024-06-17 03:16:37 -04:00
if ( ! reqLocale . empty ( ) ) {
if ( reqLocale . find ( " . " ) = = String : : npos ) {
reqLocale + = " .UTF-8 " ;
}
}
2024-05-26 04:57:26 -04:00
const char * localeRet = NULL ;
2024-06-09 05:27:48 -04:00
# ifdef HAVE_SETLOCALE
2024-06-09 04:31:16 -04:00
if ( ( localeRet = setlocale ( LC_CTYPE , reqLocale . c_str ( ) ) ) = = NULL ) {
2024-05-29 04:40:01 -04:00
logE ( " could not set locale (CTYPE)! " ) ;
2024-06-14 04:10:19 -04:00
displayLocaleFailError = true ;
2024-05-29 04:40:01 -04:00
} else {
logV ( " locale: %s " , localeRet ) ;
}
2024-06-09 04:31:16 -04:00
if ( ( localeRet = setlocale ( LC_MESSAGES , reqLocale . c_str ( ) ) ) = = NULL ) {
2024-05-29 04:40:01 -04:00
logE ( " could not set locale (MESSAGES)! " ) ;
2024-06-14 04:10:19 -04:00
displayLocaleFailError = true ;
2024-06-09 04:31:16 -04:00
# ifdef HAVE_MOMO
if ( momo_setlocale ( LC_MESSAGES , reqLocale . c_str ( ) ) = = NULL ) {
logV ( " Momo: could not set locale! " ) ;
}
# endif
2024-05-26 04:57:26 -04:00
} else {
logV ( " locale: %s " , localeRet ) ;
2024-06-09 04:31:16 -04:00
# ifdef HAVE_MOMO
if ( momo_setlocale ( LC_MESSAGES , localeRet ) = = NULL ) {
logV ( " Momo: could not set locale! " ) ;
}
# endif
2024-05-26 04:57:26 -04:00
}
2024-06-09 05:27:48 -04:00
# else
if ( ( localeRet = momo_setlocale ( LC_MESSAGES , reqLocale . c_str ( ) ) ) = = NULL ) {
logV ( " Momo: could not set locale! " ) ;
} else {
logV ( " locale: %s " , localeRet ) ;
}
# endif
2024-06-09 04:31:16 -04:00
2024-06-18 19:00:22 -04:00
char exePath [ 4096 ] ;
# ifdef ANDROID
memset ( exePath , 0 , 4096 ) ;
# else
if ( ! getExePath ( argv [ 0 ] , exePath , 4096 ) ) memset ( exePath , 0 , 4096 ) ;
# endif
2024-06-16 00:59:25 -04:00
bool textDomainBound = false ;
for ( int i = 0 ; localeDirs [ i ] ; i + + ) {
2024-06-18 19:00:22 -04:00
if ( exePath [ 0 ] ! = 0 & & localeDirs [ i ] [ 0 ] ! = DIR_SEPARATOR ) {
strncpy ( localeDir , exePath , 4095 ) ;
strncat ( localeDir , DIR_SEPARATOR_STR , 4095 ) ;
strncat ( localeDir , localeDirs [ i ] , 4095 ) ;
} else {
strncpy ( localeDir , localeDirs [ i ] , 4095 ) ;
}
2024-06-16 00:59:25 -04:00
logV ( " bind text domain: %s " , localeDir ) ;
if ( ! dirExists ( localeDir ) ) continue ;
if ( ( localeRet = TA_BINDTEXTDOMAIN ( " furnace " , localeDir ) ) = = NULL ) {
continue ;
2024-06-02 22:56:18 -04:00
} else {
2024-06-16 00:59:25 -04:00
textDomainBound = true ;
2024-06-02 22:56:18 -04:00
logV ( " text domain 1: %s " , localeRet ) ;
2024-06-16 00:59:25 -04:00
break ;
2024-06-02 22:56:18 -04:00
}
2024-05-26 04:57:26 -04:00
}
2024-06-16 00:59:25 -04:00
if ( ! textDomainBound ) {
logE ( " could not bind text domain! " ) ;
2024-05-26 04:57:26 -04:00
} else {
2024-06-16 00:59:25 -04:00
if ( ( localeRet = TA_TEXTDOMAIN ( " furnace " ) ) = = NULL ) {
logE ( " could not text domain! " ) ;
} else {
logV ( " text domain 2: %s " , localeRet ) ;
}
2024-05-26 04:57:26 -04:00
}
# endif
2021-06-09 04:33:03 -04:00
initParams ( ) ;
// parse arguments
String arg , val , fileName ;
size_t eqSplit , argStart ;
for ( int i = 1 ; i < argc ; i + + ) {
arg = " " ; val = " " ;
if ( argv [ i ] [ 0 ] = = ' - ' ) {
if ( argv [ i ] [ 1 ] = = ' - ' ) {
argStart = 2 ;
} else {
argStart = 1 ;
}
arg = & argv [ i ] [ argStart ] ;
eqSplit = arg . find_first_of ( ' = ' ) ;
if ( eqSplit = = String : : npos ) {
if ( needsValue ( arg ) ) {
if ( ( i + 1 ) < argc ) {
val = argv [ i + 1 ] ;
i + + ;
} else {
2022-06-29 00:42:34 -04:00
reportError ( fmt : : sprintf ( " incomplete param %s. " , arg . c_str ( ) ) ) ;
2021-06-09 04:33:03 -04:00
return 1 ;
}
}
} else {
val = arg . substr ( eqSplit + 1 ) ;
arg = arg . substr ( 0 , eqSplit ) ;
}
for ( size_t j = 0 ; j < params . size ( ) ; j + + ) {
if ( params [ j ] . name = = arg | | params [ j ] . shortName = = arg ) {
2022-04-25 16:54:31 -04:00
switch ( params [ j ] . func ( val ) ) {
case TA_PARAM_ERROR :
return 1 ;
break ;
case TA_PARAM_SUCCESS :
break ;
case TA_PARAM_QUIT :
return 0 ;
break ;
}
2021-06-09 04:33:03 -04:00
break ;
}
}
} else {
fileName = argv [ i ] ;
}
}
2024-04-23 05:38:08 -04:00
e . setConsoleMode ( consoleMode , ! consoleNoStatus ) ;
2021-12-18 04:26:17 -05:00
# ifdef _WIN32
if ( consoleMode ) {
HANDLE winin = GetStdHandle ( STD_INPUT_HANDLE ) ;
HANDLE winout = GetStdHandle ( STD_OUTPUT_HANDLE ) ;
int termprop = 0 ;
int termpropi = 0 ;
GetConsoleMode ( winout , ( LPDWORD ) & termprop ) ;
GetConsoleMode ( winin , ( LPDWORD ) & termpropi ) ;
termprop | = ENABLE_VIRTUAL_TERMINAL_PROCESSING ;
termpropi & = ~ ENABLE_LINE_INPUT ;
SetConsoleMode ( winout , termprop ) ;
SetConsoleMode ( winin , termpropi ) ;
}
# endif
2021-12-13 14:40:03 -05:00
if ( fileName . empty ( ) & & consoleMode ) {
2022-04-10 23:12:02 -04:00
logI ( " usage: %s file " , argv [ 0 ] ) ;
2021-05-11 16:08:08 -04:00
return 1 ;
}
2022-12-18 01:55:21 -05:00
2023-10-17 15:11:35 -04:00
if ( fileName . empty ( ) & & ( benchMode | | infoMode | | outName ! = " " | | vgmOutName ! = " " | | cmdOutName ! = " " ) ) {
logE ( " provide a file! " ) ;
return 1 ;
}
2023-10-16 15:55:01 -04:00
# ifdef HAVE_GUI
2023-10-17 15:11:35 -04:00
if ( e . preInit ( consoleMode | | benchMode | | infoMode | | outName ! = " " | | vgmOutName ! = " " | | cmdOutName ! = " " ) ) {
if ( consoleMode | | benchMode | | infoMode | | outName ! = " " | | vgmOutName ! = " " | | cmdOutName ! = " " ) {
2023-10-16 15:55:01 -04:00
logW ( " engine wants safe mode, but Furnace GUI is not going to start. " ) ;
} else {
safeMode = true ;
}
}
# else
if ( e . preInit ( true ) ) {
logW ( " engine wants safe mode, but Furnace GUI is not available. " ) ;
}
# endif
2023-10-17 15:11:35 -04:00
if ( safeMode & & ( consoleMode | | benchMode | | infoMode | | outName ! = " " | | vgmOutName ! = " " | | cmdOutName ! = " " ) ) {
2023-10-16 15:55:01 -04:00
logE ( " you can't use safe mode and console/export mode together. " ) ;
2023-11-01 20:09:30 -04:00
return 1 ;
2023-10-16 15:55:01 -04:00
}
2022-12-18 01:55:21 -05:00
2023-10-16 15:01:30 -04:00
if ( safeMode & & ! safeModeWithAudio ) {
2023-10-16 07:53:21 -04:00
e . setAudio ( DIV_AUDIO_DUMMY ) ;
}
2024-05-01 16:16:55 -04:00
if ( ! fileName . empty ( ) & & ( ( ! e . getConfBool ( " tutIntroPlayed " , TUT_INTRO_PLAYED ) ) | | e . getConfInt ( " alwaysPlayIntro " , 0 ) ! = 3 | | consoleMode | | benchMode | | infoMode | | outName ! = " " | | vgmOutName ! = " " | | cmdOutName ! = " " ) ) {
2022-04-10 23:12:02 -04:00
logI ( " loading module... " ) ;
2022-01-20 05:04:03 -05:00
FILE * f = ps_fopen ( fileName . c_str ( ) , " rb " ) ;
2021-12-13 14:40:03 -05:00
if ( f = = NULL ) {
2022-06-29 00:42:34 -04:00
reportError ( fmt : : sprintf ( " couldn't open file! (%s) " , strerror ( errno ) ) ) ;
2023-10-29 01:33:02 -04:00
e . everythingOK ( ) ;
2022-12-21 01:20:56 -05:00
finishLogFile ( ) ;
2021-12-13 14:40:03 -05:00
return 1 ;
}
if ( fseek ( f , 0 , SEEK_END ) < 0 ) {
2022-06-29 00:42:34 -04:00
reportError ( fmt : : sprintf ( " couldn't open file! (couldn't get file size: %s) " , strerror ( errno ) ) ) ;
2023-10-29 01:33:02 -04:00
e . everythingOK ( ) ;
2021-12-13 14:40:03 -05:00
fclose ( f ) ;
2022-12-21 01:20:56 -05:00
finishLogFile ( ) ;
2021-12-13 14:40:03 -05:00
return 1 ;
}
ssize_t len = ftell ( f ) ;
2022-01-17 21:08:14 -05:00
if ( len = = ( SIZE_MAX > > 1 ) ) {
2022-06-29 00:42:34 -04:00
reportError ( fmt : : sprintf ( " couldn't open file! (couldn't get file length: %s) " , strerror ( errno ) ) ) ;
2023-10-29 01:33:02 -04:00
e . everythingOK ( ) ;
2021-12-13 14:40:03 -05:00
fclose ( f ) ;
2022-12-21 01:20:56 -05:00
finishLogFile ( ) ;
2021-12-13 14:40:03 -05:00
return 1 ;
}
if ( len < 1 ) {
if ( len = = 0 ) {
2022-06-29 00:42:34 -04:00
reportError ( " that file is empty! " ) ;
2021-12-13 14:40:03 -05:00
} else {
2022-06-29 00:42:34 -04:00
reportError ( fmt : : sprintf ( " couldn't open file! (tell error: %s) " , strerror ( errno ) ) ) ;
2021-12-13 14:40:03 -05:00
}
2023-10-29 01:33:02 -04:00
e . everythingOK ( ) ;
2021-12-13 14:40:03 -05:00
fclose ( f ) ;
2022-12-21 01:20:56 -05:00
finishLogFile ( ) ;
2021-12-13 14:40:03 -05:00
return 1 ;
}
unsigned char * file = new unsigned char [ len ] ;
if ( fseek ( f , 0 , SEEK_SET ) < 0 ) {
2022-06-29 00:42:34 -04:00
reportError ( fmt : : sprintf ( " couldn't open file! (size error: %s) " , strerror ( errno ) ) ) ;
2023-10-29 01:33:02 -04:00
e . everythingOK ( ) ;
2021-12-13 14:40:03 -05:00
fclose ( f ) ;
2021-12-16 02:21:43 -05:00
delete [ ] file ;
2022-12-21 01:20:56 -05:00
finishLogFile ( ) ;
2021-12-13 14:40:03 -05:00
return 1 ;
}
if ( fread ( file , 1 , ( size_t ) len , f ) ! = ( size_t ) len ) {
2022-06-29 00:42:34 -04:00
reportError ( fmt : : sprintf ( " couldn't open file! (read error: %s) " , strerror ( errno ) ) ) ;
2023-10-29 01:33:02 -04:00
e . everythingOK ( ) ;
2021-12-13 14:40:03 -05:00
fclose ( f ) ;
2021-12-16 02:21:43 -05:00
delete [ ] file ;
2022-12-21 01:20:56 -05:00
finishLogFile ( ) ;
2021-12-13 14:40:03 -05:00
return 1 ;
2021-05-11 16:08:08 -04:00
}
fclose ( f ) ;
2024-03-16 13:16:09 -04:00
if ( ! e . load ( file , ( size_t ) len , fileName . c_str ( ) ) ) {
2022-06-29 00:42:34 -04:00
reportError ( fmt : : sprintf ( " could not open file! (%s) " , e . getLastError ( ) ) ) ;
2023-10-29 01:33:02 -04:00
e . everythingOK ( ) ;
2022-12-21 01:20:56 -05:00
finishLogFile ( ) ;
2021-12-13 14:40:03 -05:00
return 1 ;
}
2021-05-11 16:08:08 -04:00
}
2023-10-17 15:11:35 -04:00
if ( infoMode ) {
e . dumpSongInfo ( ) ;
finishLogFile ( ) ;
return 0 ;
}
2022-01-16 23:32:13 -05:00
if ( ! e . init ( ) ) {
2022-02-05 23:48:56 -05:00
if ( consoleMode ) {
2022-06-29 00:42:34 -04:00
reportError ( " could not initialize engine! " ) ;
2022-12-21 01:20:56 -05:00
finishLogFile ( ) ;
2022-02-05 23:48:56 -05:00
return 1 ;
} else {
2022-06-29 00:42:34 -04:00
logE ( " could not initialize engine! " ) ;
2022-02-06 16:21:48 -05:00
displayEngineFailError = true ;
2022-02-05 23:48:56 -05:00
}
2021-05-11 16:08:08 -04:00
}
2023-10-18 15:33:12 -04:00
if ( subsong ! = - 1 ) {
e . changeSongP ( subsong ) ;
}
2022-07-19 18:01:19 -04:00
if ( benchMode ) {
logI ( " starting benchmark! " ) ;
if ( benchMode = = 2 ) {
e . benchmarkSeek ( ) ;
} else {
e . benchmarkPlayback ( ) ;
}
2022-12-21 01:20:56 -05:00
finishLogFile ( ) ;
2022-07-19 18:01:19 -04:00
return 0 ;
}
2023-10-18 15:33:12 -04:00
2022-08-04 16:18:48 -04:00
if ( outName ! = " " | | vgmOutName ! = " " | | cmdOutName ! = " " ) {
if ( cmdOutName ! = " " ) {
2024-03-09 18:20:17 -05:00
SafeWriter * w = e . saveCommand ( ) ;
2022-08-04 16:18:48 -04:00
if ( w ! = NULL ) {
FILE * f = fopen ( cmdOutName . c_str ( ) , " wb " ) ;
if ( f ! = NULL ) {
fwrite ( w - > getFinalBuf ( ) , 1 , w - > size ( ) , f ) ;
fclose ( f ) ;
} else {
reportError ( fmt : : sprintf ( " could not open file! (%s) " , e . getLastError ( ) ) ) ;
}
w - > finish ( ) ;
delete w ;
} else {
reportError ( " could not write command stream! " ) ;
}
}
2022-01-24 13:15:07 -05:00
if ( vgmOutName ! = " " ) {
2022-10-17 15:25:30 -04:00
SafeWriter * w = e . saveVGM ( NULL , true , 0x171 , false , vgmOutDirect ) ;
2022-01-24 13:15:07 -05:00
if ( w ! = NULL ) {
FILE * f = fopen ( vgmOutName . c_str ( ) , " wb " ) ;
if ( f ! = NULL ) {
fwrite ( w - > getFinalBuf ( ) , 1 , w - > size ( ) , f ) ;
fclose ( f ) ;
} else {
2022-06-29 00:42:34 -04:00
reportError ( fmt : : sprintf ( " could not open file! (%s) " , e . getLastError ( ) ) ) ;
2022-01-24 13:15:07 -05:00
}
w - > finish ( ) ;
delete w ;
} else {
2022-06-29 00:42:34 -04:00
reportError ( " could not write VGM! " ) ;
2022-01-24 13:15:07 -05:00
}
}
if ( outName ! = " " ) {
e . setConsoleMode ( true ) ;
2024-05-10 21:01:12 -04:00
e . saveAudio ( outName . c_str ( ) , exportOptions ) ;
2022-01-24 13:15:07 -05:00
e . waitAudioFile ( ) ;
}
2022-12-21 01:20:56 -05:00
finishLogFile ( ) ;
2022-01-22 23:50:49 -05:00
return 0 ;
}
2021-12-11 03:11:40 -05:00
if ( consoleMode ) {
2022-07-25 18:23:56 -04:00
bool cliSuccess = false ;
2024-04-23 05:38:08 -04:00
if ( consoleNoStatus ) {
cli . noStatus ( ) ;
}
if ( consoleNoControls ) {
cli . noControls ( ) ;
}
2022-07-25 18:23:56 -04:00
cli . bindEngine ( & e ) ;
if ( ! cli . init ( ) ) {
reportError ( " error while starting CLI! " ) ;
} else {
cliSuccess = true ;
}
2022-04-10 23:12:02 -04:00
logI ( " playing... " ) ;
2021-12-11 03:11:40 -05:00
e . play ( ) ;
2022-07-25 18:23:56 -04:00
if ( cliSuccess ) {
cli . loop ( ) ;
cli . finish ( ) ;
e . quit ( ) ;
2022-12-21 01:20:56 -05:00
finishLogFile ( ) ;
2022-07-25 18:23:56 -04:00
return 0 ;
} else {
2022-07-25 17:21:39 -04:00
# ifdef HAVE_SDL2
2022-07-25 18:23:56 -04:00
SDL_Event ev ;
while ( true ) {
SDL_WaitEvent ( & ev ) ;
if ( ev . type = = SDL_QUIT ) break ;
}
e . quit ( ) ;
2022-12-21 01:20:56 -05:00
finishLogFile ( ) ;
2022-07-25 18:23:56 -04:00
return 0 ;
2022-01-27 04:25:16 -05:00
# else
2022-07-25 18:23:56 -04:00
while ( true ) {
2022-01-27 04:25:16 -05:00
# ifdef _WIN32
2022-07-25 18:23:56 -04:00
Sleep ( 500 ) ;
2022-01-27 04:25:16 -05:00
# else
2022-07-25 18:23:56 -04:00
usleep ( 500000 ) ;
2022-01-27 04:25:16 -05:00
# endif
2022-07-25 18:23:56 -04:00
}
2022-01-27 04:25:16 -05:00
# endif
2022-07-25 18:23:56 -04:00
}
2021-05-11 16:08:08 -04:00
}
2021-12-11 03:11:40 -05:00
2021-12-11 13:34:11 -05:00
# ifdef HAVE_GUI
2023-10-16 07:53:21 -04:00
if ( safeMode ) g . enableSafeMode ( ) ;
2021-12-11 03:11:40 -05:00
g . bindEngine ( & e ) ;
2022-06-29 00:42:34 -04:00
if ( ! g . init ( ) ) {
2022-10-02 17:12:02 -04:00
reportError ( g . getLastError ( ) ) ;
2022-12-21 01:20:56 -05:00
finishLogFile ( ) ;
2023-10-16 15:55:01 -04:00
e . everythingOK ( ) ;
2022-06-29 00:42:34 -04:00
return 1 ;
}
2021-12-11 03:11:40 -05:00
2022-02-05 23:48:56 -05:00
if ( displayEngineFailError ) {
2022-04-10 23:12:02 -04:00
logE ( " displaying engine fail error. " ) ;
2022-02-05 23:48:56 -05:00
g . showError ( " error while initializing audio! " ) ;
}
2024-06-14 04:10:19 -04:00
if ( displayLocaleFailError ) {
2024-06-17 15:48:46 -04:00
# ifndef HAVE_MOMO
2024-06-14 04:10:19 -04:00
# ifdef __unix__
g . showError ( " could not load language! \n apparently your system does not support this language correctly. \n make sure you've generated language data by editing /etc/locale.gen \n and then running locale-gen as root. " ) ;
# else
g . showError ( " could not load language! \n this is a bug! " ) ;
2024-06-17 15:48:46 -04:00
# endif
2024-06-14 04:10:19 -04:00
# endif
}
2022-02-02 01:14:21 -05:00
if ( ! fileName . empty ( ) ) {
g . setFileName ( fileName ) ;
}
2023-07-10 03:08:52 -04:00
# ifndef _WIN32
2023-07-09 20:19:37 -04:00
sigemptyset ( & termsa . sa_mask ) ;
termsa . sa_flags = 0 ;
termsa . sa_handler = handleTermGUI ;
sigaction ( SIGTERM , & termsa , NULL ) ;
2023-07-10 03:08:52 -04:00
# endif
2023-07-09 20:19:37 -04:00
2021-12-11 03:11:40 -05:00
g . loop ( ) ;
2022-04-10 23:12:02 -04:00
logI ( " closing GUI. " ) ;
2024-03-14 15:32:06 -04:00
g . finish ( true ) ;
2021-12-11 13:34:11 -05:00
# else
2022-04-10 23:12:02 -04:00
logE ( " GUI requested but GUI not compiled! " ) ;
2021-12-11 13:34:11 -05:00
# endif
2021-12-13 17:09:46 -05:00
2022-04-10 23:12:02 -04:00
logI ( " stopping engine. " ) ;
2024-03-14 15:32:06 -04:00
e . quit ( false ) ;
2022-06-09 17:10:51 -04:00
2022-12-18 01:55:21 -05:00
finishLogFile ( ) ;
2022-06-09 17:10:51 -04:00
# ifdef _WIN32
if ( coResult = = S_OK | | coResult = = S_FALSE ) {
CoUninitialize ( ) ;
}
# endif
2023-10-16 15:55:01 -04:00
e . everythingOK ( ) ;
2021-05-11 16:08:08 -04:00
return 0 ;
}