diff options
-rw-r--r-- | Makefile.common | 1 | ||||
-rw-r--r-- | backends/platform/sdl/sdl.cpp | 14 | ||||
-rw-r--r-- | base/main.cpp | 36 | ||||
-rw-r--r-- | common/scummsys.h | 2 | ||||
-rw-r--r-- | dists/msvc9/kyra.vcproj | 6 | ||||
-rw-r--r-- | dists/msvc9/scumm.vcproj | 14 | ||||
-rw-r--r-- | dists/msvc9/scummvm-tfmx.sln | 48 | ||||
-rw-r--r-- | dists/msvc9/scummvm-tfmx.vcproj | 2107 | ||||
-rw-r--r-- | engines/scumm/module.mk | 1 | ||||
-rw-r--r-- | engines/scumm/palette.cpp | 223 | ||||
-rw-r--r-- | engines/scumm/player_v4a.cpp | 186 | ||||
-rw-r--r-- | engines/scumm/player_v4a.h | 96 | ||||
-rw-r--r-- | engines/scumm/scumm.cpp | 6 | ||||
-rw-r--r-- | engines/scumm/scumm.h | 2 | ||||
-rw-r--r-- | engines/scumm/sound.cpp | 20 | ||||
-rw-r--r-- | sound/mods/paula.cpp | 45 | ||||
-rw-r--r-- | sound/mods/paula.h | 74 | ||||
-rw-r--r-- | sound/mods/soundfx.cpp | 11 | ||||
-rw-r--r-- | sound/mods/tfmx.cpp | 996 | ||||
-rw-r--r-- | sound/mods/tfmx.h | 296 | ||||
-rw-r--r-- | sound/module.mk | 1 | ||||
-rw-r--r-- | tfmx/module.mk | 8 | ||||
-rw-r--r-- | tfmx/tfmxdebug.cpp | 200 | ||||
-rw-r--r-- | tfmx/tfmxdebug.h | 14 | ||||
-rw-r--r-- | tfmx/tfmxplayer.cpp | 170 |
25 files changed, 4373 insertions, 204 deletions
diff --git a/Makefile.common b/Makefile.common index 51261d65d9..251711301f 100644 --- a/Makefile.common +++ b/Makefile.common @@ -25,6 +25,7 @@ MODULES += \ engines \ gui \ graphics \ + tfmx \ sound \ backends \ common \ diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index b353c79495..52355f60cc 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -89,7 +89,12 @@ void OSystem_SDL::initBackend() { assert(!_inited); int joystick_num = ConfMan.getInt("joystick_num"); - uint32 sdlFlags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER; + joystick_num = 0; +#if !defined(TFMX_CMDLINE_TOOL) + uint32 sdlFlags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER; +#else + uint32 sdlFlags = /*SDL_INIT_VIDEO |*/ SDL_INIT_AUDIO | SDL_INIT_TIMER; +#endif if (ConfMan.hasKey("disable_sdl_parachute")) sdlFlags |= SDL_INIT_NOPARACHUTE; @@ -108,10 +113,11 @@ void OSystem_SDL::initBackend() { error("Could not initialize SDL: %s", SDL_GetError()); } - _graphicsMutex = createMutex(); + _graphicsMutex = createMutex(); +#if !defined(TFMX_CMDLINE_TOOL) SDL_ShowCursor(SDL_DISABLE); - + // Enable unicode support if possible SDL_EnableUNICODE(1); @@ -163,7 +169,7 @@ void OSystem_SDL::initBackend() { _savefile = new DefaultSaveFileManager(); #endif } - +#endif // Create and hook up the mixer, if none exists yet (we check for this to // allow subclasses to provide their own). if (_mixer == 0) { diff --git a/base/main.cpp b/base/main.cpp index a091c5885a..913d4a4010 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -295,6 +295,40 @@ static void setupKeymapper(OSystem &system) { } +#if defined(TFMX_CMDLINE_TOOL) +void tfmxmain(int argc, const char * const argv[]); + +extern "C" int scummvm_main(int argc, const char * const argv[]) { + Common::String specialDebug; + Common::String command; + + // Verify that the backend has been initialized (i.e. g_system has been set). + assert(g_system); + OSystem &system = *g_system; + + // Register config manager defaults + Base::registerDefaults(); + + // Load the plugins. + PluginManager::instance().loadPlugins(); + + // Init the backend. Must take place after all config data (including + // the command line params) was read. + system.initBackend(); + + // pass control to my own main-function, including arguments + tfmxmain(argc,argv); + + PluginManager::instance().unloadPlugins(); + PluginManager::destroy(); + Common::ConfigManager::destroy(); + Common::SearchManager::destroy(); + GUI::GuiManager::destroy(); + + return 0; +} +#else + extern "C" int scummvm_main(int argc, const char * const argv[]) { Common::String specialDebug; Common::String command; @@ -415,3 +449,5 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { return 0; } + +#endif diff --git a/common/scummsys.h b/common/scummsys.h index a9c5fb3266..4fa3c80f71 100644 --- a/common/scummsys.h +++ b/common/scummsys.h @@ -44,6 +44,7 @@ #ifdef _MSC_VER #pragma once + #if (_MSC_VER < 1300) #pragma warning( disable : 4068 ) // turn off "unknown pragma" warning #pragma warning( disable : 4103 ) // turn off "alignement changed after including header" warning. We use pack-start.h file #pragma warning( disable : 4244 ) // turn off "conversion type" warning @@ -54,6 +55,7 @@ #pragma warning( disable : 4610 ) // turn off "struct can never be instantiated - user defined constructor required" #pragma warning( disable : 4701 ) // turn off "potentially uninitialized variables" warning #pragma warning( disable : 4800 ) // turn off "forcing value to bool 'true' or 'false' (performance warning)" + #endif // vsnprintf is already defined in Visual Studio 2008 #if (_MSC_VER < 1500) diff --git a/dists/msvc9/kyra.vcproj b/dists/msvc9/kyra.vcproj index e3902094e5..24575c6d5d 100644 --- a/dists/msvc9/kyra.vcproj +++ b/dists/msvc9/kyra.vcproj @@ -44,7 +44,7 @@ Optimization="0" InlineFunctionExpansion="0" AdditionalIncludeDirectories="../../;../../engines" - PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;ENABLE_LOL" + PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;ENABLE_LOL" MinimalRebuild="true" ExceptionHandling="1" BasicRuntimeChecks="3" @@ -55,7 +55,6 @@ ForceConformanceInForLoopScope="true" UsePrecompiledHeader="0" WarningLevel="4" - WarnAsError="true" SuppressStartupBanner="false" Detect64BitPortabilityProblems="false" DebugInformationFormat="4" @@ -121,7 +120,7 @@ FavorSizeOrSpeed="2" OmitFramePointers="true" AdditionalIncludeDirectories="../../;../../engines" - PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;ENABLE_LOL" + PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;ENABLE_LOL" StringPooling="true" ExceptionHandling="1" RuntimeLibrary="0" @@ -131,7 +130,6 @@ ForceConformanceInForLoopScope="true" UsePrecompiledHeader="0" WarningLevel="4" - WarnAsError="true" DebugInformationFormat="0" /> <Tool diff --git a/dists/msvc9/scumm.vcproj b/dists/msvc9/scumm.vcproj index d9214f7ff0..55f2a6ed48 100644 --- a/dists/msvc9/scumm.vcproj +++ b/dists/msvc9/scumm.vcproj @@ -44,7 +44,7 @@ Optimization="0" InlineFunctionExpansion="0" AdditionalIncludeDirectories="../../;../../engines" - PreprocessorDefinitions="WIN32;_DEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB;USE_MAD;USE_VORBIS" + PreprocessorDefinitions="WIN32;_DEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB" MinimalRebuild="true" ExceptionHandling="1" BasicRuntimeChecks="3" @@ -55,7 +55,6 @@ ForceConformanceInForLoopScope="true" UsePrecompiledHeader="0" WarningLevel="4" - WarnAsError="true" SuppressStartupBanner="false" Detect64BitPortabilityProblems="false" DebugInformationFormat="4" @@ -121,7 +120,7 @@ FavorSizeOrSpeed="2" OmitFramePointers="true" AdditionalIncludeDirectories="../../;../../engines" - PreprocessorDefinitions="WIN32;NDEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB;USE_MAD;USE_VORBIS" + PreprocessorDefinitions="WIN32;NDEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB" StringPooling="true" ExceptionHandling="1" RuntimeLibrary="0" @@ -131,7 +130,6 @@ ForceConformanceInForLoopScope="true" UsePrecompiledHeader="0" WarningLevel="4" - WarnAsError="true" DebugInformationFormat="0" /> <Tool @@ -688,6 +686,14 @@ > </File> <File + RelativePath="..\..\engines\scumm\player_v4a.cpp" + > + </File> + <File + RelativePath="..\..\engines\scumm\player_v4a.h" + > + </File> + <File RelativePath="..\..\engines\scumm\resource.cpp" > </File> diff --git a/dists/msvc9/scummvm-tfmx.sln b/dists/msvc9/scummvm-tfmx.sln new file mode 100644 index 0000000000..208703fc17 --- /dev/null +++ b/dists/msvc9/scummvm-tfmx.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scummvm", "scummvm-tfmx.vcproj", "{8434CB15-D08F-427D-9E6D-581AE5B28440}" + ProjectSection(ProjectDependencies) = postProject + {B6AFD548-63D2-40CD-A652-E87095AFCBAF} = {B6AFD548-63D2-40CD-A652-E87095AFCBAF} + {9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC} = {9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scumm", "scumm.vcproj", "{B6AFD548-63D2-40CD-A652-E87095AFCBAF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kyra", "kyra.vcproj", "{9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug_Command|Win32 = Debug_Command|Win32 + Debug|Win32 = Debug|Win32 + Release_Command|Win32 = Release_Command|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8434CB15-D08F-427D-9E6D-581AE5B28440}.Debug_Command|Win32.ActiveCfg = Debug_Command|Win32 + {8434CB15-D08F-427D-9E6D-581AE5B28440}.Debug_Command|Win32.Build.0 = Debug_Command|Win32 + {8434CB15-D08F-427D-9E6D-581AE5B28440}.Debug|Win32.ActiveCfg = Debug|Win32 + {8434CB15-D08F-427D-9E6D-581AE5B28440}.Debug|Win32.Build.0 = Debug|Win32 + {8434CB15-D08F-427D-9E6D-581AE5B28440}.Release_Command|Win32.ActiveCfg = Release_Command|Win32 + {8434CB15-D08F-427D-9E6D-581AE5B28440}.Release_Command|Win32.Build.0 = Release_Command|Win32 + {8434CB15-D08F-427D-9E6D-581AE5B28440}.Release|Win32.ActiveCfg = Release|Win32 + {8434CB15-D08F-427D-9E6D-581AE5B28440}.Release|Win32.Build.0 = Release|Win32 + {B6AFD548-63D2-40CD-A652-E87095AFCBAF}.Debug_Command|Win32.ActiveCfg = Debug|Win32 + {B6AFD548-63D2-40CD-A652-E87095AFCBAF}.Debug|Win32.ActiveCfg = Debug|Win32 + {B6AFD548-63D2-40CD-A652-E87095AFCBAF}.Debug|Win32.Build.0 = Debug|Win32 + {B6AFD548-63D2-40CD-A652-E87095AFCBAF}.Release_Command|Win32.ActiveCfg = Release|Win32 + {B6AFD548-63D2-40CD-A652-E87095AFCBAF}.Release|Win32.ActiveCfg = Release|Win32 + {B6AFD548-63D2-40CD-A652-E87095AFCBAF}.Release|Win32.Build.0 = Release|Win32 + {9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC}.Debug_Command|Win32.ActiveCfg = Debug|Win32 + {9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC}.Debug_Command|Win32.Build.0 = Debug|Win32 + {9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC}.Debug|Win32.ActiveCfg = Debug|Win32 + {9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC}.Debug|Win32.Build.0 = Debug|Win32 + {9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC}.Release_Command|Win32.ActiveCfg = Release|Win32 + {9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC}.Release_Command|Win32.Build.0 = Release|Win32 + {9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC}.Release|Win32.ActiveCfg = Release|Win32 + {9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/dists/msvc9/scummvm-tfmx.vcproj b/dists/msvc9/scummvm-tfmx.vcproj new file mode 100644 index 0000000000..091f32b752 --- /dev/null +++ b/dists/msvc9/scummvm-tfmx.vcproj @@ -0,0 +1,2107 @@ +<?xml version="1.0" encoding="windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9,00" + Name="scummvm" + ProjectGUID="{8434CB15-D08F-427D-9E6D-581AE5B28440}" + RootNamespace="scummvm" + Keyword="Win32Proj" + TargetFrameworkVersion="131072" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(SolutionName)-$(ConfigurationName)" + IntermediateDirectory="$(SolutionDir)$(SolutionName)-$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + InlineFunctionExpansion="0" + AdditionalIncludeDirectories="../../;../../engines" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;ENABLE_SCUMM;ENABLE_LOL;USE_ZLIB" + MinimalRebuild="true" + ExceptionHandling="1" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + BufferSecurityCheck="true" + EnableFunctionLevelLinking="true" + DisableLanguageExtensions="false" + ForceConformanceInForLoopScope="true" + RuntimeTypeInfo="true" + UsePrecompiledHeader="0" + WarningLevel="4" + SuppressStartupBanner="false" + Detect64BitPortabilityProblems="false" + DebugInformationFormat="4" + DisableSpecificWarnings="4512" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib" + OutputFile="$(OutDir)\$(ProjectName)-tfmx.exe" + LinkIncremental="2" + IgnoreDefaultLibraryNames="libc.lib;libcmt.lib;msvcrt.lib" + GenerateDebugInformation="true" + ProgramDatabaseFile="$(OutDir)/scummvm.pdb" + SubSystem="1" + EntryPointSymbol="WinMainCRTStartup" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(SolutionName)-$(ConfigurationName)" + IntermediateDirectory="$(SolutionDir)$(SolutionName)-$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="2" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996" + Optimization="2" + EnableIntrinsicFunctions="true" + OmitFramePointers="true" + AdditionalIncludeDirectories="../../;../../engines" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;ENABLE_SCUMM;ENABLE_LOL;USE_ZLIB" + StringPooling="true" + MinimalRebuild="false" + ExceptionHandling="1" + RuntimeLibrary="0" + BufferSecurityCheck="false" + EnableFunctionLevelLinking="false" + DisableLanguageExtensions="false" + ForceConformanceInForLoopScope="true" + RuntimeTypeInfo="true" + UsePrecompiledHeader="0" + WarningLevel="4" + DebugInformationFormat="0" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="winmm.lib sdl.lib zlib.lib" + OutputFile="$(OutDir)\$(ProjectName)-tfmx.exe" + LinkIncremental="1" + SuppressStartupBanner="true" + IgnoreDefaultLibraryNames="libc.lib" + GenerateDebugInformation="false" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + EntryPointSymbol="WinMainCRTStartup" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_Command|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + InlineFunctionExpansion="0" + AdditionalIncludeDirectories="../../;../../engines" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;TFMX_CMDLINE_TOOL" + MinimalRebuild="true" + ExceptionHandling="1" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + BufferSecurityCheck="true" + EnableFunctionLevelLinking="true" + DisableLanguageExtensions="false" + ForceConformanceInForLoopScope="true" + RuntimeTypeInfo="true" + UsePrecompiledHeader="0" + WarningLevel="4" + SuppressStartupBanner="false" + Detect64BitPortabilityProblems="false" + DebugInformationFormat="4" + DisableSpecificWarnings="4512" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkLibraryDependencies="false" + AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib" + OutputFile="$(OutDir)\$(ProjectName)-tfmx.exe" + LinkIncremental="2" + IgnoreDefaultLibraryNames="libc.lib;libcmt.lib;msvcrt.lib" + GenerateDebugInformation="true" + ProgramDatabaseFile="$(OutDir)/scummvm.pdb" + SubSystem="1" + EntryPointSymbol="WinMainCRTStartup" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_Command|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="2" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996" + Optimization="2" + EnableIntrinsicFunctions="true" + OmitFramePointers="true" + AdditionalIncludeDirectories="../../;../../engines" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;TFMX_CMDLINE_TOOL" + StringPooling="true" + MinimalRebuild="false" + ExceptionHandling="1" + RuntimeLibrary="0" + BufferSecurityCheck="false" + EnableFunctionLevelLinking="false" + DisableLanguageExtensions="false" + ForceConformanceInForLoopScope="true" + RuntimeTypeInfo="true" + UsePrecompiledHeader="0" + WarningLevel="4" + DebugInformationFormat="0" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkLibraryDependencies="false" + AdditionalDependencies="winmm.lib sdl.lib" + OutputFile="$(OutDir)\$(ProjectName)-tfmx.exe" + LinkIncremental="1" + SuppressStartupBanner="true" + IgnoreDefaultLibraryNames="libc.lib" + GenerateDebugInformation="false" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + EntryPointSymbol="WinMainCRTStartup" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="base" + > + <File + RelativePath="..\..\base\commandLine.cpp" + > + </File> + <File + RelativePath="..\..\base\commandLine.h" + > + </File> + <File + RelativePath="..\..\base\internal_version.h" + > + </File> + <File + RelativePath="..\..\base\main.cpp" + > + </File> + <File + RelativePath="..\..\base\main.h" + > + </File> + <File + RelativePath="..\..\base\plugins.cpp" + > + </File> + <File + RelativePath="..\..\base\plugins.h" + > + </File> + <File + RelativePath="..\..\base\version.cpp" + > + </File> + <File + RelativePath="..\..\base\version.h" + > + </File> + </Filter> + <Filter + Name="common" + > + <File + RelativePath="..\..\common\algorithm.h" + > + </File> + <File + RelativePath="..\..\common\archive.cpp" + > + </File> + <File + RelativePath="..\..\common\archive.h" + > + </File> + <File + RelativePath="..\..\common\array.h" + > + </File> + <File + RelativePath="..\..\backends\base-backend.h" + > + </File> + <File + RelativePath="..\..\common\config-file.cpp" + > + </File> + <File + RelativePath="..\..\common\config-file.h" + > + </File> + <File + RelativePath="..\..\common\config-manager.cpp" + > + </File> + <File + RelativePath="..\..\common\config-manager.h" + > + </File> + <File + RelativePath="..\..\common\debug.cpp" + > + </File> + <File + RelativePath="..\..\common\debug.h" + > + </File> + <File + RelativePath="..\..\common\endian.h" + > + </File> + <File + RelativePath="..\..\common\error.h" + > + </File> + <File + RelativePath="..\..\common\events.h" + > + </File> + <File + RelativePath="..\..\common\file.cpp" + > + </File> + <File + RelativePath="..\..\common\file.h" + > + </File> + <File + RelativePath="..\..\common\frac.h" + > + </File> + <File + RelativePath="..\..\common\fs.cpp" + > + </File> + <File + RelativePath="..\..\common\fs.h" + > + </File> + <File + RelativePath="..\..\common\func.h" + > + </File> + <File + RelativePath="..\..\common\hash-str.h" + > + </File> + <File + RelativePath="..\..\common\hashmap.cpp" + > + </File> + <File + RelativePath="..\..\common\hashmap.h" + > + </File> + <File + RelativePath="..\..\common\iff_container.h" + > + </File> + <File + RelativePath="..\..\common\keyboard.h" + > + </File> + <File + RelativePath="..\..\common\list.h" + > + </File> + <File + RelativePath="..\..\common\list_intern.h" + > + </File> + <File + RelativePath="..\..\common\md5.cpp" + > + </File> + <File + RelativePath="..\..\common\md5.h" + > + </File> + <File + RelativePath="..\..\common\memorypool.cpp" + > + </File> + <File + RelativePath="..\..\common\memorypool.h" + > + </File> + <File + RelativePath="..\..\common\mutex.cpp" + > + </File> + <File + RelativePath="..\..\common\mutex.h" + > + </File> + <File + RelativePath="..\..\common\noncopyable.h" + > + </File> + <File + RelativePath="..\..\common\pack-end.h" + > + </File> + <File + RelativePath="..\..\common\pack-start.h" + > + </File> + <File + RelativePath="..\..\common\ptr.h" + > + </File> + <File + RelativePath="..\..\common\queue.h" + > + </File> + <File + RelativePath="..\..\common\rect.h" + > + </File> + <File + RelativePath="..\..\common\savefile.h" + > + </File> + <File + RelativePath="..\..\common\scummsys.h" + > + </File> + <File + RelativePath="..\..\common\serializer.h" + > + </File> + <File + RelativePath="..\..\common\singleton.h" + > + </File> + <File + RelativePath="..\..\common\stack.h" + > + </File> + <File + RelativePath="..\..\common\str.cpp" + > + </File> + <File + RelativePath="..\..\common\str.h" + > + </File> + <File + RelativePath="..\..\common\stream.cpp" + > + </File> + <File + RelativePath="..\..\common\stream.h" + > + </File> + <File + RelativePath="..\..\common\system.cpp" + > + </File> + <File + RelativePath="..\..\common\system.h" + > + </File> + <File + RelativePath="..\..\common\timer.h" + > + </File> + <File + RelativePath="..\..\common\unarj.cpp" + > + </File> + <File + RelativePath="..\..\common\unarj.h" + > + </File> + <File + RelativePath="..\..\common\unzip.cpp" + > + </File> + <File + RelativePath="..\..\common\unzip.h" + > + </File> + <File + RelativePath="..\..\common\util.cpp" + > + </File> + <File + RelativePath="..\..\common\util.h" + > + </File> + <File + RelativePath="..\..\common\xmlparser.cpp" + > + </File> + <File + RelativePath="..\..\common\xmlparser.h" + > + </File> + <File + RelativePath="..\..\common\zlib.cpp" + > + </File> + <File + RelativePath="..\..\common\zlib.h" + > + </File> + </Filter> + <Filter + Name="sound" + > + <File + RelativePath="..\..\sound\adpcm.cpp" + > + </File> + <File + RelativePath="..\..\sound\adpcm.h" + > + </File> + <File + RelativePath="..\..\sound\aiff.cpp" + > + </File> + <File + RelativePath="..\..\sound\aiff.h" + > + </File> + <File + RelativePath="..\..\sound\audiocd.cpp" + > + </File> + <File + RelativePath="..\..\sound\audiocd.h" + > + </File> + <File + RelativePath="..\..\sound\audiostream.cpp" + > + </File> + <File + RelativePath="..\..\sound\audiostream.h" + > + </File> + <File + RelativePath="..\..\sound\flac.cpp" + > + </File> + <File + RelativePath="..\..\sound\flac.h" + > + </File> + <File + RelativePath="..\..\sound\fmopl.cpp" + > + </File> + <File + RelativePath="..\..\sound\fmopl.h" + > + </File> + <File + RelativePath="..\..\sound\iff.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)\$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)\$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug_Command|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)\$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Release_Command|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)\$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\sound\iff.h" + > + </File> + <File + RelativePath="..\..\sound\mididrv.cpp" + > + </File> + <File + RelativePath="..\..\sound\mididrv.h" + > + </File> + <File + RelativePath="..\..\sound\midiparser.cpp" + > + </File> + <File + RelativePath="..\..\sound\midiparser.h" + > + </File> + <File + RelativePath="..\..\sound\midiparser_smf.cpp" + > + </File> + <File + RelativePath="..\..\sound\midiparser_xmidi.cpp" + > + </File> + <File + RelativePath="..\..\sound\mixer.cpp" + > + </File> + <File + RelativePath="..\..\sound\mixer.h" + > + </File> + <File + RelativePath="..\..\sound\mixer_intern.h" + > + </File> + <File + RelativePath="..\..\sound\mp3.cpp" + > + </File> + <File + RelativePath="..\..\sound\mp3.h" + > + </File> + <File + RelativePath="..\..\sound\mpu401.cpp" + > + </File> + <File + RelativePath="..\..\sound\mpu401.h" + > + </File> + <File + RelativePath="..\..\sound\musicplugin.cpp" + > + </File> + <File + RelativePath="..\..\sound\musicplugin.h" + > + </File> + <File + RelativePath="..\..\sound\null.cpp" + > + </File> + <File + RelativePath="..\..\sound\rate.cpp" + > + </File> + <File + RelativePath="..\..\sound\rate.h" + > + </File> + <File + RelativePath="..\..\sound\shorten.cpp" + > + </File> + <File + RelativePath="..\..\sound\shorten.h" + > + </File> + <File + RelativePath="..\..\sound\timestamp.cpp" + > + </File> + <File + RelativePath="..\..\sound\timestamp.h" + > + </File> + <File + RelativePath="..\..\sound\vag.cpp" + > + </File> + <File + RelativePath="..\..\sound\vag.h" + > + </File> + <File + RelativePath="..\..\sound\voc.cpp" + > + </File> + <File + RelativePath="..\..\sound\voc.h" + > + </File> + <File + RelativePath="..\..\sound\vorbis.cpp" + > + </File> + <File + RelativePath="..\..\sound\vorbis.h" + > + </File> + <File + RelativePath="..\..\sound\wave.cpp" + > + </File> + <File + RelativePath="..\..\sound\wave.h" + > + </File> + <Filter + Name="softhsynth" + > + <File + RelativePath="..\..\sound\softsynth\adlib.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)/$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)/$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug_Command|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)/$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Release_Command|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)/$(InputName)1.xdc" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\sound\softsynth\emumidi.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\fluidsynth.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)/$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)/$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug_Command|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)/$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Release_Command|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)/$(InputName)1.xdc" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\sound\softsynth\pcspk.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\pcspk.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\ym2612.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)/$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)/$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug_Command|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)/$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Release_Command|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)/$(InputName)1.xdc" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\sound\softsynth\ym2612.h" + > + </File> + <Filter + Name="mt32" + > + <File + RelativePath="..\..\sound\softsynth\mt32\freeverb.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\freeverb.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\i386.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\i386.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\mt32_file.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\mt32_file.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\mt32emu.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\part.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\part.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\partial.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\partial.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\partialManager.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\partialManager.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\structures.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\synth.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\synth.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\tables.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\mt32\tables.h" + > + </File> + </Filter> + <Filter + Name="opl" + > + <File + RelativePath="..\..\sound\softsynth\opl\dosbox.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\opl\dosbox.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\opl\mame.cpp" + > + </File> + <File + RelativePath="..\..\sound\softsynth\opl\mame.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\opl\opl_impl.h" + > + </File> + <File + RelativePath="..\..\sound\softsynth\opl\opl_inc.h" + > + </File> + </Filter> + </Filter> + <Filter + Name="mods" + > + <File + RelativePath="..\..\sound\mods\infogrames.cpp" + > + </File> + <File + RelativePath="..\..\sound\mods\infogrames.h" + > + </File> + <File + RelativePath="..\..\sound\mods\module.cpp" + > + </File> + <File + RelativePath="..\..\sound\mods\module.h" + > + </File> + <File + RelativePath="..\..\sound\mods\paula.cpp" + > + </File> + <File + RelativePath="..\..\sound\mods\paula.h" + > + </File> + <File + RelativePath="..\..\sound\mods\protracker.cpp" + > + </File> + <File + RelativePath="..\..\sound\mods\protracker.h" + > + </File> + <File + RelativePath="..\..\sound\mods\rjp1.cpp" + > + </File> + <File + RelativePath="..\..\sound\mods\rjp1.h" + > + </File> + <File + RelativePath="..\..\sound\mods\soundfx.cpp" + > + </File> + <File + RelativePath="..\..\sound\mods\soundfx.h" + > + </File> + <File + RelativePath="..\..\sound\mods\tfmx.cpp" + > + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + AssemblerOutput="2" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\sound\mods\tfmx.h" + > + </File> + </Filter> + </Filter> + <Filter + Name="txt" + > + <File + RelativePath="..\..\COPYING" + > + </File> + <File + RelativePath="..\..\NEWS" + > + </File> + <File + RelativePath="..\..\README" + > + </File> + <File + RelativePath="..\..\TODO" + > + </File> + </Filter> + <Filter + Name="rsc" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" + > + <File + RelativePath="..\..\icons\scummvm.ico" + > + </File> + <File + RelativePath="..\..\dists\scummvm.rc" + > + </File> + </Filter> + <Filter + Name="backends" + > + <File + RelativePath="..\..\backends\base-backend.cpp" + > + </File> + <Filter + Name="sdl" + > + <File + RelativePath="..\..\backends\platform\sdl\events.cpp" + > + </File> + <File + RelativePath="..\..\backends\platform\sdl\graphics.cpp" + > + </File> + <File + RelativePath="..\..\backends\platform\sdl\hardwarekeys.cpp" + > + </File> + <File + RelativePath="..\..\backends\platform\sdl\main.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)\$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)\$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug_Command|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)\$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Release_Command|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)\$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\backends\platform\sdl\sdl.cpp" + > + </File> + <File + RelativePath="..\..\backends\platform\sdl\sdl.h" + > + </File> + </Filter> + <Filter + Name="fs" + > + <File + RelativePath="..\..\backends\fs\abstract-fs.cpp" + > + </File> + <File + RelativePath="..\..\backends\fs\abstract-fs.h" + > + </File> + <File + RelativePath="..\..\backends\fs\fs-factory.h" + > + </File> + <File + RelativePath="..\..\backends\fs\stdiostream.cpp" + > + </File> + <File + RelativePath="..\..\backends\fs\stdiostream.h" + > + </File> + <Filter + Name="windows" + > + <File + RelativePath="..\..\backends\fs\windows\windows-fs-factory.cpp" + > + </File> + <File + RelativePath="..\..\backends\fs\windows\windows-fs-factory.h" + > + </File> + </Filter> + </Filter> + <Filter + Name="midi" + > + <File + RelativePath="..\..\backends\midi\windows.cpp" + > + </File> + </Filter> + <Filter + Name="timer" + > + <File + RelativePath="..\..\backends\timer\default\default-timer.cpp" + > + </File> + <File + RelativePath="..\..\backends\timer\default\default-timer.h" + > + </File> + </Filter> + <Filter + Name="saves" + > + <File + RelativePath="..\..\backends\saves\default\default-saves.cpp" + > + </File> + <File + RelativePath="..\..\backends\saves\default\default-saves.h" + > + </File> + <File + RelativePath="..\..\backends\saves\savefile.cpp" + > + </File> + </Filter> + <Filter + Name="events" + > + <Filter + Name="default" + > + <File + RelativePath="..\..\backends\events\default\default-events.cpp" + > + </File> + <File + RelativePath="..\..\backends\events\default\default-events.h" + > + </File> + </Filter> + </Filter> + <Filter + Name="keymapper" + > + <File + RelativePath="..\..\backends\keymapper\action.cpp" + > + </File> + <File + RelativePath="..\..\backends\keymapper\action.h" + > + </File> + <File + RelativePath="..\..\backends\keymapper\hardware-key.h" + > + </File> + <File + RelativePath="..\..\backends\keymapper\keymap.cpp" + > + </File> + <File + RelativePath="..\..\backends\keymapper\keymap.h" + > + </File> + <File + RelativePath="..\..\backends\keymapper\keymapper.cpp" + > + </File> + <File + RelativePath="..\..\backends\keymapper\keymapper.h" + > + </File> + <File + RelativePath="..\..\backends\keymapper\remap-dialog.cpp" + > + </File> + <File + RelativePath="..\..\backends\keymapper\remap-dialog.h" + > + </File> + <File + RelativePath="..\..\backends\keymapper\types.h" + > + </File> + </Filter> + <Filter + Name="vkeybd" + > + <File + RelativePath="..\..\backends\vkeybd\image-map.cpp" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\image-map.h" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\keycode-descriptions.h" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\polygon.cpp" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\polygon.h" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\virtual-keyboard-gui.cpp" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\virtual-keyboard-gui.h" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\virtual-keyboard-parser.cpp" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\virtual-keyboard-parser.h" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\virtual-keyboard.cpp" + > + </File> + <File + RelativePath="..\..\backends\vkeybd\virtual-keyboard.h" + > + </File> + </Filter> + </Filter> + <Filter + Name="gui" + > + <File + RelativePath="..\..\gui\about.cpp" + > + </File> + <File + RelativePath="..\..\gui\about.h" + > + </File> + <File + RelativePath="..\..\gui\browser.cpp" + > + </File> + <File + RelativePath="..\..\gui\browser.h" + > + </File> + <File + RelativePath="..\..\gui\chooser.cpp" + > + </File> + <File + RelativePath="..\..\gui\chooser.h" + > + </File> + <File + RelativePath="..\..\gui\console.cpp" + > + </File> + <File + RelativePath="..\..\gui\console.h" + > + </File> + <File + RelativePath="..\..\gui\credits.h" + > + </File> + <File + RelativePath="..\..\gui\debugger.cpp" + > + </File> + <File + RelativePath="..\..\gui\debugger.h" + > + </File> + <File + RelativePath="..\..\gui\dialog.cpp" + > + </File> + <File + RelativePath="..\..\gui\dialog.h" + > + </File> + <File + RelativePath="..\..\gui\editable.cpp" + > + </File> + <File + RelativePath="..\..\gui\editable.h" + > + </File> + <File + RelativePath="..\..\gui\EditTextWidget.cpp" + > + </File> + <File + RelativePath="..\..\gui\EditTextWidget.h" + > + </File> + <File + RelativePath="..\..\gui\GuiManager.cpp" + > + </File> + <File + RelativePath="..\..\gui\GuiManager.h" + > + </File> + <File + RelativePath="..\..\gui\Key.cpp" + > + </File> + <File + RelativePath="..\..\gui\Key.h" + > + </File> + <File + RelativePath="..\..\gui\launcher.cpp" + > + </File> + <File + RelativePath="..\..\gui\launcher.h" + > + </File> + <File + RelativePath="..\..\gui\ListWidget.cpp" + > + </File> + <File + RelativePath="..\..\gui\ListWidget.h" + > + </File> + <File + RelativePath="..\..\gui\massadd.cpp" + > + </File> + <File + RelativePath="..\..\gui\massadd.h" + > + </File> + <File + RelativePath="..\..\gui\message.cpp" + > + </File> + <File + RelativePath="..\..\gui\message.h" + > + </File> + <File + RelativePath="..\..\gui\object.cpp" + > + </File> + <File + RelativePath="..\..\gui\object.h" + > + </File> + <File + RelativePath="..\..\gui\options.cpp" + > + </File> + <File + RelativePath="..\..\gui\options.h" + > + </File> + <File + RelativePath="..\..\gui\PopUpWidget.cpp" + > + </File> + <File + RelativePath="..\..\gui\PopUpWidget.h" + > + </File> + <File + RelativePath="..\..\gui\saveload.cpp" + > + </File> + <File + RelativePath="..\..\gui\saveload.h" + > + </File> + <File + RelativePath="..\..\gui\ScrollBarWidget.cpp" + > + </File> + <File + RelativePath="..\..\gui\ScrollBarWidget.h" + > + </File> + <File + RelativePath="..\..\gui\TabWidget.cpp" + > + </File> + <File + RelativePath="..\..\gui\TabWidget.h" + > + </File> + <File + RelativePath="..\..\gui\themebrowser.cpp" + > + </File> + <File + RelativePath="..\..\gui\themebrowser.h" + > + </File> + <File + RelativePath="..\..\gui\ThemeEngine.cpp" + > + </File> + <File + RelativePath="..\..\gui\ThemeEngine.h" + > + </File> + <File + RelativePath="..\..\gui\ThemeEval.cpp" + > + </File> + <File + RelativePath="..\..\gui\ThemeLayout.cpp" + > + </File> + <File + RelativePath="..\..\gui\ThemeLayout.h" + > + </File> + <File + RelativePath="..\..\gui\ThemeParser.cpp" + > + </File> + <File + RelativePath="..\..\gui\ThemeParser.h" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCustomBuildTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug_Command|Win32" + > + <Tool + Name="VCCustomBuildTool" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\gui\widget.cpp" + > + </File> + <File + RelativePath="..\..\gui\widget.h" + > + </File> + </Filter> + <Filter + Name="graphics" + > + <File + RelativePath="..\..\graphics\colormasks.h" + > + </File> + <File + RelativePath="..\..\graphics\cursorman.cpp" + > + </File> + <File + RelativePath="..\..\graphics\cursorman.h" + > + </File> + <File + RelativePath="..\..\graphics\dither.cpp" + > + </File> + <File + RelativePath="..\..\graphics\dither.h" + > + </File> + <File + RelativePath="..\..\graphics\font.cpp" + > + </File> + <File + RelativePath="..\..\graphics\font.h" + > + </File> + <File + RelativePath="..\..\graphics\fontman.cpp" + > + </File> + <File + RelativePath="..\..\graphics\fontman.h" + > + </File> + <File + RelativePath="..\..\graphics\iff.cpp" + > + </File> + <File + RelativePath="..\..\graphics\iff.h" + > + </File> + <File + RelativePath="..\..\graphics\imagedec.cpp" + > + </File> + <File + RelativePath="..\..\graphics\imagedec.h" + > + </File> + <File + RelativePath="..\..\graphics\primitives.cpp" + > + </File> + <File + RelativePath="..\..\graphics\primitives.h" + > + </File> + <File + RelativePath="..\..\graphics\scaler.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler.h" + > + </File> + <File + RelativePath="..\..\graphics\surface.cpp" + > + </File> + <File + RelativePath="..\..\graphics\surface.h" + > + </File> + <File + RelativePath="..\..\graphics\thumbnail.cpp" + > + </File> + <File + RelativePath="..\..\graphics\thumbnail.h" + > + </File> + <File + RelativePath="..\..\graphics\VectorRenderer.cpp" + > + </File> + <File + RelativePath="..\..\graphics\VectorRenderer.h" + > + </File> + <File + RelativePath="..\..\graphics\VectorRendererSpec.cpp" + > + </File> + <File + RelativePath="..\..\graphics\VectorRendererSpec.h" + > + </File> + <Filter + Name="scaler" + > + <File + RelativePath="..\..\graphics\scaler\2xsai.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\aspect.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\hq2x.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\hq2x.h" + > + </File> + <File + RelativePath="..\..\graphics\scaler\hq2x_i386.asm" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCustomBuildTool" + CommandLine="nasm.exe -f win32 -g -o "$(OutDir)\$(InputName).obj" "$(InputPath)"
" + Outputs="$(OutDir)\$(InputName).obj" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCustomBuildTool" + CommandLine="nasm.exe -f win32 -o "$(OutDir)\$(InputName).obj" "$(InputPath)"
" + Outputs="$(OutDir)\$(InputName).obj" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug_Command|Win32" + > + <Tool + Name="VCCustomBuildTool" + CommandLine="nasm.exe -f win32 -g -o "$(OutDir)\$(InputName).obj" "$(InputPath)"
" + Outputs="$(OutDir)\$(InputName).obj" + /> + </FileConfiguration> + <FileConfiguration + Name="Release_Command|Win32" + > + <Tool + Name="VCCustomBuildTool" + CommandLine="nasm.exe -f win32 -o "$(OutDir)\$(InputName).obj" "$(InputPath)"
" + Outputs="$(OutDir)\$(InputName).obj" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\graphics\scaler\hq3x.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\hq3x.h" + > + </File> + <File + RelativePath="..\..\graphics\scaler\hq3x_i386.asm" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCustomBuildTool" + CommandLine="nasm.exe -f win32 -g -o "$(OutDir)\$(InputName).obj" "$(InputPath)"
" + Outputs="$(OutDir)\$(InputName).obj" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCustomBuildTool" + CommandLine="nasm.exe -f win32 -o "$(OutDir)\$(InputName).obj" "$(InputPath)"
" + Outputs="$(OutDir)\$(InputName).obj" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug_Command|Win32" + > + <Tool + Name="VCCustomBuildTool" + CommandLine="nasm.exe -f win32 -g -o "$(OutDir)\$(InputName).obj" "$(InputPath)"
" + Outputs="$(OutDir)\$(InputName).obj" + /> + </FileConfiguration> + <FileConfiguration + Name="Release_Command|Win32" + > + <Tool + Name="VCCustomBuildTool" + CommandLine="nasm.exe -f win32 -o "$(OutDir)\$(InputName).obj" "$(InputPath)"
" + Outputs="$(OutDir)\$(InputName).obj" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\graphics\scaler\intern.h" + > + </File> + <File + RelativePath="..\..\graphics\scaler\scale2x.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\scale2x.h" + > + </File> + <File + RelativePath="..\..\graphics\scaler\scale3x.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\scale3x.h" + > + </File> + <File + RelativePath="..\..\graphics\scaler\scalebit.cpp" + > + </File> + <File + RelativePath="..\..\graphics\scaler\scalebit.h" + > + </File> + <File + RelativePath="..\..\graphics\scaler\thumbnail_intern.cpp" + > + </File> + </Filter> + <Filter + Name="fonts" + > + <File + RelativePath="..\..\graphics\fonts\consolefont.cpp" + > + </File> + <File + RelativePath="..\..\graphics\fonts\newfont.cpp" + > + </File> + <File + RelativePath="..\..\graphics\fonts\newfont_big.cpp" + > + </File> + <File + RelativePath="..\..\graphics\fonts\scummfont.cpp" + > + </File> + </Filter> + <Filter + Name="video" + > + <File + RelativePath="..\..\graphics\video\dxa_decoder.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\dxa_decoder.h" + > + </File> + <File + RelativePath="..\..\graphics\video\flic_decoder.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\flic_decoder.h" + > + </File> + <File + RelativePath="..\..\graphics\video\mpeg_player.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\mpeg_player.h" + > + </File> + <File + RelativePath="..\..\graphics\video\smk_decoder.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\smk_decoder.h" + > + </File> + <File + RelativePath="..\..\graphics\video\video_player.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\video_player.h" + > + </File> + <Filter + Name="coktelvideo" + > + <File + RelativePath="..\..\graphics\video\coktelvideo\coktelvideo.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\coktelvideo\coktelvideo.h" + > + </File> + <File + RelativePath="..\..\graphics\video\coktelvideo\indeo3.cpp" + > + </File> + <File + RelativePath="..\..\graphics\video\coktelvideo\indeo3.h" + > + </File> + </Filter> + </Filter> + </Filter> + <Filter + Name="engines" + > + <File + RelativePath="..\..\engines\advancedDetector.cpp" + > + </File> + <File + RelativePath="..\..\engines\advancedDetector.h" + > + </File> + <File + RelativePath="..\..\engines\dialogs.cpp" + > + </File> + <File + RelativePath="..\..\engines\dialogs.h" + > + </File> + <File + RelativePath="..\..\engines\engine.cpp" + > + </File> + <File + RelativePath="..\..\engines\engine.h" + > + </File> + <File + RelativePath="..\..\engines\game.cpp" + > + </File> + <File + RelativePath="..\..\engines\game.h" + > + </File> + <File + RelativePath="..\..\engines\metaengine.h" + > + </File> + </Filter> + <Filter + Name="TFMX" + > + <File + RelativePath="..\..\TFMX\README.txt" + > + </File> + <File + RelativePath="..\..\tfmx\tfmxdebug.cpp" + > + </File> + <File + RelativePath="..\..\tfmx\tfmxdebug.h" + > + </File> + <File + RelativePath="..\..\TFMX\tfmxplayer.cpp" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index 58d8db91fc..51fbecdb0d 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -40,6 +40,7 @@ MODULE_OBJS := \ player_v2a.o \ player_v2cms.o \ player_v3a.o \ + player_v4a.o \ resource_v2.o \ resource_v3.o \ resource_v4.o \ diff --git a/engines/scumm/palette.cpp b/engines/scumm/palette.cpp index a2cd4a0d4d..44249a8715 100644 --- a/engines/scumm/palette.cpp +++ b/engines/scumm/palette.cpp @@ -70,121 +70,80 @@ void ScummEngine::resetPalette() { else setEGAPalette(); } + } else if ((_game.platform == Common::kPlatformAmiga) && _game.version == 4) { + // if rendermode is set to EGA we use the full palette from the resources + // else we initialise and then lock down the first 16 colors. + if (_renderMode != Common::kRenderEGA) + setAmigaMIPalette(); } else setDirtyColors(0, 255); } -void ScummEngine::setC64Palette() { - setPalColor( 0, 0x00, 0x00, 0x00); - setPalColor( 1, 0xFD, 0xFE, 0xFC); - setPalColor( 2, 0xBE, 0x1A, 0x24); - setPalColor( 3, 0x30, 0xE6, 0xC6); - setPalColor( 4, 0xB4, 0x1A, 0xE2); - setPalColor( 5, 0x1F, 0xD2, 0x1E); - setPalColor( 6, 0x21, 0x1B, 0xAE); - setPalColor( 7, 0xDF, 0xF6, 0x0A); - setPalColor( 8, 0xB8, 0x41, 0x04); - setPalColor( 9, 0x6A, 0x33, 0x04); - setPalColor(10, 0xFE, 0x4A, 0x57); - setPalColor(11, 0x42, 0x45, 0x40); - setPalColor(12, 0x70, 0x74, 0x6F); - setPalColor(13, 0x59, 0xFE, 0x59); - setPalColor(14, 0x5F, 0x53, 0xFE); - setPalColor(15, 0xA4, 0xA7, 0xA2); +void ScummEngine::setHardcodedPaletteRGB(const byte *ptr, int numcolor, int index) { + for ( ; numcolor > 0; --numcolor, ++index, ptr += 3) + setPalColor( index, ptr[0], ptr[1], ptr[2]); +} +void ScummEngine::setC64Palette() { // Use 17 color table for v1 games to allow correct color for inventory and // sentence line. Original games used some kind of dynamic color table // remapping between rooms. - setPalColor(16, 255, 85, 255); + static const byte ctable[] = { + 0x00, 0x00, 0x00, 0xFD, 0xFE, 0xFC, 0xBE, 0x1A, 0x24, 0x30, 0xE6, 0xC6, + 0xB4, 0x1A, 0xE2, 0x1F, 0xD2, 0x1E, 0x21, 0x1B, 0xAE, 0xDF, 0xF6, 0x0A, + 0xB8, 0x41, 0x04, 0x6A, 0x33, 0x04, 0xFE, 0x4A, 0x57, 0x42, 0x45, 0x40, + 0x70, 0x74, 0x6F, 0x59, 0xFE, 0x59, 0x5F, 0x53, 0xFE, 0xA4, 0xA7, 0xA2, + + 0xFF, 0x55, 0xFF + }; + setHardcodedPaletteRGB(ctable, ARRAYSIZE(ctable) / 3); } void ScummEngine::setNESPalette() { - setPalColor(0x00,0x00,0x00,0x00); // 0x1D - setPalColor(0x01,0x00,0x24,0x92); - setPalColor(0x02,0x00,0x00,0xDB); - setPalColor(0x03,0x6D,0x49,0xDB); - setPalColor(0x04,0x92,0x00,0x6D); - setPalColor(0x05,0xB6,0x00,0x6D); - setPalColor(0x06,0xB6,0x24,0x00); - setPalColor(0x07,0x92,0x49,0x00); - setPalColor(0x08,0x6D,0x49,0x00); - setPalColor(0x09,0x24,0x49,0x00); - setPalColor(0x0A,0x00,0x6D,0x24); - setPalColor(0x0B,0x00,0x92,0x00); - setPalColor(0x0C,0x00,0x49,0x49); - setPalColor(0x0D,0x00,0x00,0x00); - setPalColor(0x0E,0x00,0x00,0x00); - setPalColor(0x0F,0x00,0x00,0x00); - - setPalColor(0x10,0xB6,0xB6,0xB6); - setPalColor(0x11,0x00,0x6D,0xDB); - setPalColor(0x12,0x00,0x49,0xFF); - setPalColor(0x13,0x92,0x00,0xFF); - setPalColor(0x14,0xB6,0x00,0xFF); - setPalColor(0x15,0xFF,0x00,0x92); - setPalColor(0x16,0xFF,0x00,0x00); - setPalColor(0x17,0xDB,0x6D,0x00); - setPalColor(0x18,0x92,0x6D,0x00); - setPalColor(0x19,0x24,0x92,0x00); - setPalColor(0x1A,0x00,0x92,0x00); - setPalColor(0x1B,0x00,0xB6,0x6D); - setPalColor(0x1C,0x00,0x92,0x92); - setPalColor(0x1D,0x6D,0x6D,0x6D); // 0x00 - setPalColor(0x1E,0x00,0x00,0x00); - setPalColor(0x1F,0x00,0x00,0x00); - - setPalColor(0x20,0xFF,0xFF,0xFF); - setPalColor(0x21,0x6D,0xB6,0xFF); - setPalColor(0x22,0x92,0x92,0xFF); - setPalColor(0x23,0xDB,0x6D,0xFF); - setPalColor(0x24,0xFF,0x00,0xFF); - setPalColor(0x25,0xFF,0x6D,0xFF); - setPalColor(0x26,0xFF,0x92,0x00); - setPalColor(0x27,0xFF,0xB6,0x00); - setPalColor(0x28,0xDB,0xDB,0x00); - setPalColor(0x29,0x6D,0xDB,0x00); - setPalColor(0x2A,0x00,0xFF,0x00); - setPalColor(0x2B,0x49,0xFF,0xDB); - setPalColor(0x2C,0x00,0xFF,0xFF); - setPalColor(0x2D,0x49,0x49,0x49); - setPalColor(0x2E,0x00,0x00,0x00); - setPalColor(0x2F,0x00,0x00,0x00); - - setPalColor(0x30,0xFF,0xFF,0xFF); - setPalColor(0x31,0xB6,0xDB,0xFF); - setPalColor(0x32,0xDB,0xB6,0xFF); - setPalColor(0x33,0xFF,0xB6,0xFF); - setPalColor(0x34,0xFF,0x92,0xFF); - setPalColor(0x35,0xFF,0xB6,0xB6); - setPalColor(0x36,0xFF,0xDB,0x92); - setPalColor(0x37,0xFF,0xFF,0x49); - setPalColor(0x38,0xFF,0xFF,0x6D); - setPalColor(0x39,0xB6,0xFF,0x49); - setPalColor(0x3A,0x92,0xFF,0x6D); - setPalColor(0x3B,0x49,0xFF,0xDB); - setPalColor(0x3C,0x92,0xDB,0xFF); - setPalColor(0x3D,0x92,0x92,0x92); - setPalColor(0x3E,0x00,0x00,0x00); - setPalColor(0x3F,0x00,0x00,0x00); + static const byte ctable[] = { + /* 0x1D */ + 0x00, 0x00, 0x00, 0x00, 0x24, 0x92, 0x00, 0x00, 0xDB, 0x6D, 0x49, 0xDB, + 0x92, 0x00, 0x6D, 0xB6, 0x00, 0x6D, 0xB6, 0x24, 0x00, 0x92, 0x49, 0x00, + 0x6D, 0x49, 0x00, 0x24, 0x49, 0x00, 0x00, 0x6D, 0x24, 0x00, 0x92, 0x00, + 0x00, 0x49, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xB6, 0xB6, 0xB6, 0x00, 0x6D, 0xDB, 0x00, 0x49, 0xFF, 0x92, 0x00, 0xFF, + 0xB6, 0x00, 0xFF, 0xFF, 0x00, 0x92, 0xFF, 0x00, 0x00, 0xDB, 0x6D, 0x00, + 0x92, 0x6D, 0x00, 0x24, 0x92, 0x00, 0x00, 0x92, 0x00, 0x00, 0xB6, 0x6D, + /* 0x00 */ + 0x00, 0x92, 0x92, 0x6D, 0x6D, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0x6D, 0xB6, 0xFF, 0x92, 0x92, 0xFF, 0xDB, 0x6D, 0xFF, + 0xFF, 0x00, 0xFF, 0xFF, 0x6D, 0xFF, 0xFF, 0x92, 0x00, 0xFF, 0xB6, 0x00, + 0xDB, 0xDB, 0x00, 0x6D, 0xDB, 0x00, 0x00, 0xFF, 0x00, 0x49, 0xFF, 0xDB, + 0x00, 0xFF, 0xFF, 0x49, 0x49, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xB6, 0xDB, 0xFF, 0xDB, 0xB6, 0xFF, 0xFF, 0xB6, 0xFF, + 0xFF, 0x92, 0xFF, 0xFF, 0xB6, 0xB6, 0xFF, 0xDB, 0x92, 0xFF, 0xFF, 0x49, + 0xFF, 0xFF, 0x6D, 0xB6, 0xFF, 0x49, 0x92, 0xFF, 0x6D, 0x49, 0xFF, 0xDB, + 0x92, 0xDB, 0xFF, 0x92, 0x92, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + setHardcodedPaletteRGB(ctable, ARRAYSIZE(ctable) / 3); } void ScummEngine::setAmigaPalette() { - setPalColor( 0, 0, 0, 0); - setPalColor( 1, 0, 0, 187); - setPalColor( 2, 0, 187, 0); - setPalColor( 3, 0, 187, 187); - setPalColor( 4, 187, 0, 0); - setPalColor( 5, 187, 0, 187); - setPalColor( 6, 187, 119, 0); - setPalColor( 7, 187, 187, 187); - setPalColor( 8, 119, 119, 119); - setPalColor( 9, 119, 119, 255); - setPalColor(10, 0, 255, 0); - setPalColor(11, 0, 255, 255); - setPalColor(12, 255, 136, 136); - setPalColor(13, 255, 0, 255); - setPalColor(14, 255, 255, 0); - setPalColor(15, 255, 255, 255); + static const byte ctable[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x00, 0xBB, 0x00, 0x00, 0xBB, 0xBB, + 0xBB, 0x00, 0x00, 0xBB, 0x00, 0xBB, 0xBB, 0x77, 0x00, 0xBB, 0xBB, 0xBB, + 0x77, 0x77, 0x77, 0x77, 0x77, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0x88, 0x88, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF + }; + setHardcodedPaletteRGB(ctable, ARRAYSIZE(ctable) / 3); +} + +void ScummEngine::setAmigaMIPalette() { + static const byte ctable[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x88, 0x22, 0x00, 0x66, 0x77, + 0xBB, 0x66, 0x66, 0xAA, 0x22, 0xAA, 0x88, 0x55, 0x22, 0x77, 0x77, 0x77, + 0x33, 0x33, 0x33, 0x22, 0x55, 0xDD, 0x22, 0xDD, 0x44, 0x00, 0xCC, 0xFF, + 0xFF, 0x99, 0x99, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0x77, 0xFF, 0xFF, 0xFF + }; + setHardcodedPaletteRGB(ctable, ARRAYSIZE(ctable) / 3); } void ScummEngine::setHercPalette() { @@ -214,50 +173,32 @@ void ScummEngine::setCGAPalette() { } void ScummEngine::setEGAPalette() { - setPalColor( 0, 0, 0, 0); - setPalColor( 1, 0, 0, 170); - setPalColor( 2, 0, 170, 0); - setPalColor( 3, 0, 170, 170); - setPalColor( 4, 170, 0, 0); - setPalColor( 5, 170, 0, 170); - setPalColor( 6, 170, 85, 0); - setPalColor( 7, 170, 170, 170); - setPalColor( 8, 85, 85, 85); - setPalColor( 9, 85, 85, 255); - setPalColor(10, 85, 255, 85); - setPalColor(11, 85, 255, 255); - setPalColor(12, 255, 85, 85); - setPalColor(13, 255, 85, 255); - setPalColor(14, 255, 255, 85); - setPalColor(15, 255, 255, 255); + static const byte ctable[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0x00, 0xAA, 0xAA, + 0xAA, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0xAA, 0x55, 0x00, 0xAA, 0xAA, 0xAA, + 0x55, 0x55, 0x55, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0x55, 0x55, 0xFF, 0xFF, + 0xFF, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0x55, 0xFF, 0xFF, 0xFF + }; + setHardcodedPaletteRGB(ctable, ARRAYSIZE(ctable) / 3); } void ScummEngine::setV1Palette() { - setPalColor( 0, 0, 0, 0); - setPalColor( 1, 255, 255, 255); - setPalColor( 2, 170, 0, 0); - setPalColor( 3, 0, 170, 170); - setPalColor( 4, 170, 0, 170); - setPalColor( 5, 0, 170, 0); - setPalColor( 6, 0, 0, 170); - setPalColor( 7, 255, 255, 85); - setPalColor( 8, 255, 85, 85); - setPalColor( 9, 170, 85, 0); - setPalColor(10, 255, 85, 85); - setPalColor(11, 85, 85, 85); - setPalColor(12, 170, 170, 170); - setPalColor(13, 85, 255, 85); - setPalColor(14, 85, 85, 255); + static const byte ctable[] = { + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xAA, 0x00, 0x00, 0x00, 0xAA, 0xAA, + 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0x00, 0x00, 0xAA, 0xFF, 0xFF, 0x55, + 0xFF, 0x55, 0x55, 0xAA, 0x55, 0x00, 0xFF, 0x55, 0x55, 0x55, 0x55, 0x55, + 0xAA, 0xAA, 0xAA, 0x55, 0xFF, 0x55, 0x55, 0x55, 0xFF, 0x55, 0x55, 0x55, + + 0xFF, 0x55, 0xFF + }; + setHardcodedPaletteRGB(ctable, ARRAYSIZE(ctable) / 3); if (_game.id == GID_ZAK) setPalColor(15, 170, 170, 170); - else - setPalColor(15, 85, 85, 85); - - setPalColor(16, 255, 85, 255); } void ScummEngine::setPaletteFromPtr(const byte *ptr, int numcolor) { + int firstIndex = 0; int i; byte *dest, r, g, b; @@ -277,7 +218,13 @@ void ScummEngine::setPaletteFromPtr(const byte *ptr, int numcolor) { dest = _currentPalette; - for (i = 0; i < numcolor; i++) { + if ((_game.platform == Common::kPlatformAmiga) && _game.version == 4 && _renderMode != Common::kRenderEGA) { + firstIndex = 16; + dest += 3 * 16; + ptr += 3 * 16; + } + + for (i = firstIndex; i < numcolor; i++) { r = *ptr++; g = *ptr++; b = *ptr++; @@ -302,7 +249,7 @@ void ScummEngine::setPaletteFromPtr(const byte *ptr, int numcolor) { memcpy(_darkenPalette, _currentPalette, 768); } - setDirtyColors(0, numcolor - 1); + setDirtyColors(firstIndex, numcolor - 1); } void ScummEngine::setDirtyColors(int min, int max) { diff --git a/engines/scumm/player_v4a.cpp b/engines/scumm/player_v4a.cpp new file mode 100644 index 0000000000..7c3aab0462 --- /dev/null +++ b/engines/scumm/player_v4a.cpp @@ -0,0 +1,186 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + * $URL$ + * $Id$ + * + */ + + +#include "engines/engine.h" +#include "scumm/player_v4a.h" +#include "scumm/scumm.h" + +#include "common/file.h" + +namespace Scumm { + +Player_V4A::Player_V4A(ScummEngine *scumm, Audio::Mixer *mixer) + : _vm(scumm), _mixer(mixer), _musicId(), _sfxSlots(), _tfmxPlay(0), _tfmxSfx(0), _musicHandle(), _sfxHandle() { + init(); +} + +bool Player_V4A::init() { + if (_vm->_game.id != GID_MONKEY_VGA) + error("player_v4a - unknown game"); + + Common::File fileMdat; + Common::File fileSample; + bool mdatExists = fileMdat.open("music.dat"); + bool sampleExists = fileSample.open("sample.dat"); + + if (mdatExists && sampleExists) { + Audio::Tfmx *play = new Audio::Tfmx(_mixer->getOutputRate(), true); + if (play->load(fileMdat, fileSample)) { + play->setSignalPtr(_signal); + _tfmxPlay = play; + } else + delete play; + + play = new Audio::Tfmx(_mixer->getOutputRate(), true); + fileMdat.seek(0); + fileSample.seek(0); + if (play->load(fileMdat, fileSample)) { + _tfmxSfx = play; + } else + delete play; + } + return _tfmxPlay != 0; +} + +Player_V4A::~Player_V4A() { + _mixer->stopHandle(_musicHandle); + _mixer->stopHandle(_sfxHandle); + delete _tfmxPlay; + delete _tfmxSfx; +} + +void Player_V4A::setMusicVolume(int vol) { + debug(5, "player_v4a: setMusicVolume %i", vol); +} + +void Player_V4A::stopAllSounds() { + debug(5, "player_v4a: stopAllSounds"); + if (_tfmxPlay) { + _tfmxPlay->stopSong(); + _signal[0] = 0; + } + _musicId = 0; + if (_tfmxSfx) + _tfmxSfx->stopSong(); + clearSfxSlots(); +} + +void Player_V4A::stopSound(int nr) { + debug(5, "player_v4a: stopSound %d", nr); + if (nr == 0) + return; + if (nr == _musicId) { + _musicId = 0; + _tfmxPlay->stopSong(); + _signal[0] = 0; + } else { + const int chan = getSfxChan(nr); + if (chan != -1) { + setSfxSlot(chan, 0); + _tfmxSfx->stopMacroEffect(chan); + } + } +} + +void Player_V4A::startSound(int nr) { + assert(_vm); + const byte *ptr = _vm->getResourceAddress(rtSound, nr); + assert(ptr); + + static const int8 monkeyCommands[52] = { + -1, -2, -3, -4, -5, -6, -7, -8, + -9, -10, -11, -12, -13, -14, 18, 17, + -17, -18, -19, -20, -21, -22, -23, -24, + -25, -26, -27, -28, -29, -30, -31, -32, + -33, 16, -35, 0, 1, 2, 3, 7, + 8, 10, 11, 4, 5, 14, 15, 12, + 6, 13, 9, 19 + }; + + const int val = ptr[9]; + if (val < 0 || val >= ARRAYSIZE(monkeyCommands)) { + warning("player_v4a: illegal Songnumber %i", val); + return; + } + + if (!_tfmxSfx || !_tfmxPlay) + return; + + int index = monkeyCommands[val]; + const byte type = ptr[6]; + if (index < 0) { + // SoundFX + index = -index - 1; + debug(3, "player_v4a: play %d: custom %i - %02X", nr, index, type); + + if (_tfmxSfx->getSongIndex() < 0) + _tfmxSfx->doSong(0x18); + const int chan = _tfmxSfx->doSfx((uint16)index); + if (chan >= 0 && chan < ARRAYSIZE(_sfxSlots)) + setSfxSlot(chan, nr, type); + else + warning("player_v4a: custom %i is not of required type", index); + + if (!_mixer->isSoundHandleActive(_sfxHandle)) + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, _tfmxSfx, -1, Audio::Mixer::kMaxChannelVolume, 0, false); + } else { + // Song + debug(3, "player_v4a: play %d: song %i - %02X", nr, index, type); + if (ptr[6] != 0x7F) + warning("player_v4a: Song has wrong type"); + + _tfmxPlay->doSong(index); + _signal[0] = 2; + _musicId = nr; + + if (!_mixer->isSoundHandleActive(_musicHandle)) + _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle, _tfmxPlay, -1, Audio::Mixer::kMaxChannelVolume, 0, false); + } +} + +int Player_V4A::getMusicTimer() const { + if (_musicId) { + // TODO: The titlesong is running with ~70 ticks per second and the scale seems to be based on that. + // Other songs dont and I have no clue if this scalevalue is anything close to correct for them. + // The Amiga-Game doesnt counts the ticks of the song, but has an own timer and I hope thespeed is constant through the game + const int magicScale = 357; // ~ 1000 * 25 * (10173 / 709379.0) + return (_mixer->getSoundElapsedTime(_musicHandle)) / magicScale; + } + return 0; +} + +int Player_V4A::getSoundStatus(int nr) const { + bool a = nr == _musicId; + bool b = _tfmxPlay->getSongIndex() >= 0; + int c = _signal[0]; + + debug(5, "player_v4a: getSoundStatus music=%d, active=%d, signal=%d", a, b, c); + if (nr == _musicId) + return _signal[0]; + return 0; +} + +} // End of namespace Scumm diff --git a/engines/scumm/player_v4a.h b/engines/scumm/player_v4a.h new file mode 100644 index 0000000000..3b454e9349 --- /dev/null +++ b/engines/scumm/player_v4a.h @@ -0,0 +1,96 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef SCUMM_PLAYER_V4A_H +#define SCUMM_PLAYER_V4A_H + +#include "common/scummsys.h" +#include "scumm/music.h" +#include "sound/mixer.h" +#include "sound/mods/tfmx.h" + +class Mixer; + +namespace Scumm { + +class ScummEngine; + +/** + * Scumm V4 Amiga sound/music driver. + */ +class Player_V4A : public MusicEngine { +public: + Player_V4A(ScummEngine *scumm, Audio::Mixer *mixer); + virtual ~Player_V4A(); + + virtual void setMusicVolume(int vol); + virtual void startSound(int sound); + virtual void stopSound(int sound); + virtual void stopAllSounds(); + virtual int getMusicTimer() const; + virtual int getSoundStatus(int sound) const; + +private: + ScummEngine *_vm; + + Audio::Tfmx *_tfmxPlay; + Audio::Tfmx *_tfmxSfx; + Audio::Mixer *_mixer; + Audio::SoundHandle _musicHandle; + Audio::SoundHandle _sfxHandle; + + int _musicId; + uint16 _signal[4]; + + struct SfxChan { + int id; + byte type; + } _sfxSlots[4]; + + int getSfxChan(int id) const { + for (int i = 0; i < ARRAYSIZE(_sfxSlots); ++i) + if (_sfxSlots[i].id == id) + return i; + return -1; + } + + void setSfxSlot(int channel, int id, byte type = 0) { + _sfxSlots[channel].id = id; + _sfxSlots[channel].type = type; + } + + void clearSfxSlots() { + for (int i = 0; i < ARRAYSIZE(_sfxSlots); ++i){ + _sfxSlots[i].id = 0; + _sfxSlots[i].type = 0; + } + } + + bool init(); +}; + +} // End of namespace Scumm + +#endif diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index dcbf95ef4b..6716fda3fd 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -55,6 +55,7 @@ #include "scumm/player_v2.h" #include "scumm/player_v2a.h" #include "scumm/player_v3a.h" +#include "scumm/player_v4a.h" #include "scumm/he/resource_he.h" #include "scumm/scumm_v0.h" #include "scumm/scumm_v8.h" @@ -494,7 +495,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) case Common::kRenderCGA: case Common::kRenderEGA: case Common::kRenderAmiga: - if ((_game.version >= 4 && !(_game.features & GF_16COLOR)) || (_game.features & GF_OLD256)) + if ((_game.version >= 4 && !(_game.features & GF_16COLOR) && !(_game.platform == Common::kPlatformAmiga && _renderMode == Common::kRenderEGA)) + || (_game.features & GF_OLD256)) _renderMode = Common::kRenderDefault; break; @@ -1669,7 +1671,7 @@ void ScummEngine::setupMusic(int midi) { } else if (_game.platform == Common::kPlatformPCEngine && _game.version == 3) { // TODO: Add support for music format } else if (_game.platform == Common::kPlatformAmiga && _game.version <= 4) { - // TODO: Add support for music format + _musicEngine = new Player_V4A(this, _mixer); } else if (_game.id == GID_MANIAC && _game.version == 1) { _musicEngine = new Player_V1(this, _mixer, midiDriver != MD_PCSPK); } else if (_game.version <= 2) { diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 9ac6f87f26..b74104ea3c 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -1017,9 +1017,11 @@ protected: const byte *getPalettePtr(int palindex, int room); + void setHardcodedPaletteRGB(const byte *ptr, int numcolor, int firstIndex = 0); void setC64Palette(); void setNESPalette(); void setAmigaPalette(); + void setAmigaMIPalette(); void setHercPalette(); void setCGAPalette(); void setEGAPalette(); diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index bc3ca00571..970b3970b6 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -440,26 +440,6 @@ void Sound::playSound(int soundID) { if (_vm->_game.id == GID_MONKEY_VGA || _vm->_game.id == GID_MONKEY_EGA || (_vm->_game.id == GID_MONKEY && _vm->_game.platform == Common::kPlatformMacintosh)) { - // Sound is currently not supported at all in the amiga versions of these games - if (_vm->_game.platform == Common::kPlatformAmiga) { - int track = -1; - if (soundID == 50) - track = 17; - else if (ptr[6] == 0x7F && ptr[7] == 0x00 && ptr[8] == 0x80) { - static const char tracks[16] = {13,14,10,3,4,9,16,5,1,8,2,15,6,7,11,12}; - if (ptr[9] == 0x0E) - track = 18; - else - track = tracks[ptr[9] - 0x23]; - } - if (track != -1) { - playCDTrack(track,((track < 5) || (track > 16)) ? 1 : -1,0,0); - stopCDTimer(); - _currentCDSound = soundID; - } - return; - } - // Works around the fact that in some places in MonkeyEGA/VGA, // the music is never explicitly stopped. // Rather it seems that starting a new music is supposed to diff --git a/sound/mods/paula.cpp b/sound/mods/paula.cpp index 545390ff93..c9866e51ab 100644 --- a/sound/mods/paula.cpp +++ b/sound/mods/paula.cpp @@ -27,19 +27,20 @@ namespace Audio { -Paula::Paula(bool stereo, int rate, int interruptFreq) : - _stereo(stereo), _rate(rate), _intFreq(interruptFreq) { +Paula::Paula(bool stereo, int rate, uint interruptFreq) : + _stereo(stereo), _rate(rate), _periodScale((kPalSystemClock / 2.0) / rate), _intFreq(interruptFreq) { clearVoices(); - _voice[0].panning = 63; - _voice[1].panning = 191; - _voice[2].panning = 191; - _voice[3].panning = 63; + _voice[0].panning = 191; + _voice[1].panning = 63; + _voice[2].panning = 63; + _voice[3].panning = 191; - if (_intFreq <= 0) + if (_intFreq == 0) _intFreq = _rate; - _curInt = _intFreq; + _curInt = 0; + _timerBase = 1; _playing = false; _end = true; } @@ -55,8 +56,10 @@ void Paula::clearVoice(byte voice) { _voice[voice].length = 0; _voice[voice].lengthRepeat = 0; _voice[voice].period = 0; + _voice[voice].periodRepeat = 0; _voice[voice].volume = 0; _voice[voice].offset = 0; + _voice[voice].dmaCount = 0; } int Paula::readBuffer(int16 *buffer, const int numSamples) { @@ -95,18 +98,17 @@ int Paula::readBufferIntern(int16 *buffer, const int numSamples) { // Handle 'interrupts'. This gives subclasses the chance to adjust the channel data // (e.g. insert new samples, do pitch bending, whatever). - if (_curInt == _intFreq) { + if (_curInt == 0) { + _curInt = _intFreq; interrupt(); - _curInt = 0; } // Compute how many samples to generate: at most the requested number of samples, // of course, but we may stop earlier when an 'interrupt' is expected. - const int nSamples = MIN(samples, _intFreq - _curInt); + const uint nSamples = MIN((uint)samples, _curInt); // Loop over the four channels of the emulated Paula chip for (int voice = 0; voice < NUM_VOICES; voice++) { - // No data, or paused -> skip channel if (!_voice[voice].data || (_voice[voice].period <= 0)) continue; @@ -115,8 +117,7 @@ int Paula::readBufferIntern(int16 *buffer, const int numSamples) { // the requested output sampling rate (typicall 44.1 kHz or 22.05 kHz) // as well as the "period" of the channel we are processing right now, // to compute the correct output 'rate'. - const double frequency = (7093789.2 / 2.0) / _voice[voice].period; - frac_t rate = doubleToFrac(frequency / _rate); + frac_t rate = doubleToFrac(_periodScale / _voice[voice].period); // Cap the volume _voice[voice].volume = MIN((byte) 0x40, _voice[voice].volume); @@ -126,6 +127,7 @@ int Paula::readBufferIntern(int16 *buffer, const int numSamples) { frac_t offset = _voice[voice].offset; frac_t sLen = intToFrac(_voice[voice].length); const int8 *data = _voice[voice].data; + int dmaCount = _voice[voice].dmaCount; int16 *p = buffer; int end = 0; int neededSamples = nSamples; @@ -141,21 +143,29 @@ int Paula::readBufferIntern(int16 *buffer, const int numSamples) { // If we have not yet generated enough samples, and looping is active: loop! if (neededSamples > 0 && _voice[voice].lengthRepeat > 2) { - // At this point we know that we have used up all samples in the buffer, so reset it. _voice[voice].data = data = _voice[voice].dataRepeat; _voice[voice].length = _voice[voice].lengthRepeat; sLen = intToFrac(_voice[voice].length); + // TODO: the value in offset shouldnt be dropped but scaled to new rate + + if (_voice[voice].period != _voice[voice].periodRepeat) { + _voice[voice].period = _voice[voice].periodRepeat; + rate = doubleToFrac(_periodScale / _voice[voice].period); + } // If the "rate" exceeds the sample rate, we would have to perform constant // wrap arounds. So, apply the first step of the euclidean algorithm to // achieve the same more efficiently: Take rate modulo sLen + // TODO: This messes up dmaCount if (sLen < rate) rate %= sLen; // Repeat as long as necessary. while (neededSamples > 0) { - offset = 0; + // TODO offset -= sLen, but only if same rate otherwise need to scale first + offset &= FRAC_LO_MASK; + dmaCount++; // Compute the number of samples to generate (see above) and mix 'em. end = MIN(neededSamples, (int)((sLen - offset + rate - 1) / rate)); @@ -166,10 +176,11 @@ int Paula::readBufferIntern(int16 *buffer, const int numSamples) { // Write back the cached data _voice[voice].offset = offset; + _voice[voice].dmaCount = dmaCount; } buffer += _stereo ? nSamples * 2 : nSamples; - _curInt += nSamples; + _curInt -= nSamples; samples -= nSamples; } return numSamples; diff --git a/sound/mods/paula.h b/sound/mods/paula.h index e3c6002451..fbc984f121 100644 --- a/sound/mods/paula.h +++ b/sound/mods/paula.h @@ -40,12 +40,27 @@ namespace Audio { class Paula : public AudioStream { public: static const int NUM_VOICES = 4; + enum { + kPalSystemClock = 7093790, + kNtscSystemClock = 7159090, + kPalCiaClock = kPalSystemClock / 10, + kNtscCiaClock = kNtscSystemClock / 10 + }; - Paula(bool stereo = false, int rate = 44100, int interruptFreq = 0); + Paula(bool stereo = false, int rate = 44100, uint interruptFreq = 0); ~Paula(); bool playing() const { return _playing; } - void setInterruptFreq(int freq) { _curInt = _intFreq = freq; } + void setTimerBaseValue( uint32 ticksPerSecond ) { _timerBase = ticksPerSecond; } + uint32 getTimerBaseValue() { return _timerBase; } + void setSingleInterrupt(uint sampleDelay) { assert(sampleDelay < _intFreq); _curInt = sampleDelay; } + void setSingleInterruptUnscaled(uint timerDelay) { + setSingleInterrupt((uint)(((double)timerDelay * getRate()) / _timerBase)); + } + void setInterruptFreq(uint sampleDelay) { _intFreq = sampleDelay; _curInt = 0; } + void setInterruptFreqUnscaled(uint timerDelay) { + setInterruptFreq((uint)(((double)timerDelay * getRate()) / _timerBase)); + } void clearVoice(byte voice); void clearVoices() { for (int i = 0; i < NUM_VOICES; ++i) clearVoice(i); } void startPlay(void) { _playing = true; } @@ -65,9 +80,11 @@ protected: uint32 length; uint32 lengthRepeat; int16 period; + int16 periodRepeat; byte volume; frac_t offset; byte panning; // For stereo mixing: 0 = far left, 255 = far right + int dmaCount; }; bool _end; @@ -90,9 +107,24 @@ protected: _voice[channel].panning = panning; } + void disableChannel(byte channel) { + assert(channel < NUM_VOICES); + _voice[channel].data = 0; + } + + void enableChannel(byte channel) { + assert(channel < NUM_VOICES); + Channel &ch = _voice[channel]; + ch.data = ch.dataRepeat; + ch.length = ch.lengthRepeat; + // actually first 2 bytes are dropped? + ch.offset = intToFrac(0); + ch.period = ch.periodRepeat; + } + void setChannelPeriod(byte channel, int16 period) { assert(channel < NUM_VOICES); - _voice[channel].period = period; + _voice[channel].periodRepeat = period; } void setChannelVolume(byte channel, byte volume) { @@ -100,6 +132,17 @@ protected: _voice[channel].volume = volume; } + void setChannelSampleStart(byte channel, const int8 *data) { + assert(channel < NUM_VOICES); + _voice[channel].dataRepeat = data; + } + + void setChannelSampleLen(byte channel, uint32 length) { + assert(channel < NUM_VOICES); + assert(length < 32768/2); + _voice[channel].lengthRepeat = 2 * length; + } + void setChannelData(uint8 channel, const int8 *data, const int8 *dataRepeat, uint32 length, uint32 lengthRepeat, int32 offset = 0) { assert(channel < NUM_VOICES); @@ -110,11 +153,14 @@ protected: assert(lengthRepeat < 32768); Channel &ch = _voice[channel]; - ch.data = data; + + ch.dataRepeat = data; + ch.lengthRepeat = length; + enableChannel(channel); + ch.offset = intToFrac(offset); + ch.dataRepeat = dataRepeat; - ch.length = length; ch.lengthRepeat = lengthRepeat; - ch.offset = intToFrac(offset); } void setChannelOffset(byte channel, frac_t offset) { @@ -128,13 +174,25 @@ protected: return _voice[channel].offset; } + int getChannelDmaCount(byte channel) { + assert(channel < NUM_VOICES); + return _voice[channel].dmaCount; + } + + void setChannelDmaCount(byte channel, int dmaVal = 0) { + assert(channel < NUM_VOICES); + _voice[channel].dmaCount = dmaVal; + } + private: Channel _voice[NUM_VOICES]; const bool _stereo; const int _rate; - int _intFreq; - int _curInt; + const double _periodScale; + uint _intFreq; + uint _curInt; + uint32 _timerBase; bool _playing; template<bool stereo> diff --git a/sound/mods/soundfx.cpp b/sound/mods/soundfx.cpp index 101d8a077d..3af8ca19c6 100644 --- a/sound/mods/soundfx.cpp +++ b/sound/mods/soundfx.cpp @@ -46,8 +46,7 @@ public: enum { NUM_CHANNELS = 4, - NUM_INSTRUMENTS = 15, - CIA_FREQ = 715909 + NUM_INSTRUMENTS = 15 }; SoundFx(int rate, bool stereo); @@ -75,12 +74,12 @@ protected: uint16 _curPos; uint8 _ordersTable[128]; uint8 *_patternData; - int _eventsFreq; uint16 _effects[NUM_CHANNELS]; }; SoundFx::SoundFx(int rate, bool stereo) : Paula(stereo, rate) { + setTimerBaseValue(kPalCiaClock); _ticks = 0; _delay = 0; memset(_instruments, 0, sizeof(_instruments)); @@ -89,7 +88,6 @@ SoundFx::SoundFx(int rate, bool stereo) _curPos = 0; memset(_ordersTable, 0, sizeof(_ordersTable)); _patternData = 0; - _eventsFreq = 0; memset(_effects, 0, sizeof(_effects)); } @@ -167,8 +165,7 @@ void SoundFx::play() { _curPos = 0; _curOrder = 0; _ticks = 0; - _eventsFreq = CIA_FREQ / _delay; - setInterruptFreq(getRate() / _eventsFreq); + setInterruptFreqUnscaled(_delay); startPaula(); } @@ -252,7 +249,7 @@ void SoundFx::handleTick() { } void SoundFx::disablePaulaChannel(uint8 channel) { - setChannelPeriod(channel, 0); + disableChannel(channel); } void SoundFx::setupPaulaChannel(uint8 channel, const int8 *data, uint16 len, uint16 repeatPos, uint16 repeatLen) { diff --git a/sound/mods/tfmx.cpp b/sound/mods/tfmx.cpp new file mode 100644 index 0000000000..c3d7288990 --- /dev/null +++ b/sound/mods/tfmx.cpp @@ -0,0 +1,996 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/scummsys.h" +#include "common/endian.h" +#include "common/stream.h" +#include "common/util.h" +#include "common/debug.h" + +#include "sound/mods/tfmx.h" +#ifdef _MSC_VER +#include "tfmx/tfmxdebug.h" +#endif +namespace Audio { + +const uint16 Tfmx::noteIntervalls[64] = { + 1710, 1614, 1524, 1438, 1357, 1281, 1209, 1141, 1077, 1017, 960, 908, + 856, 810, 764, 720, 680, 642, 606, 571, 539, 509, 480, 454, + 428, 404, 381, 360, 340, 320, 303, 286, 270, 254, 240, 227, + 214, 202, 191, 180, 170, 160, 151, 143, 135, 127, 120, 113, + 214, 202, 191, 180, 170, 160, 151, 143, 135, 127, 120, 113, + 214, 202, 191, 180 }; + +Tfmx::Tfmx(int rate, bool stereo) +: Paula(stereo, rate), _resource(), _playerCtx() { + _playerCtx.stopWithLastPattern = false; + + for (int i = 0; i < kNumVoices; ++i) + _channelCtx[i].paulaChannel = (byte)i; + + _playerCtx.song = -1; + _playerCtx.volume = 0x40; + _playerCtx.patternSkip = 6; + stopPatternChannels(); + stopMacroChannels(); + + setTimerBaseValue(kPalCiaClock); + setInterruptFreqUnscaled(kPalDefaultCiaVal); +} + +Tfmx::~Tfmx() { +} + +void Tfmx::interrupt() { + assert(!_end); + ++_playerCtx.tickCount; + for (int i = 0; i < kNumVoices; ++i) { + ChannelContext &channel = _channelCtx[i]; + if (channel.dmaIntCount) { + // wait for DMA Interupts to happen + int doneDma = getChannelDmaCount(channel.paulaChannel); + if (doneDma >= channel.dmaIntCount) { + channel.dmaIntCount = 0; + channel.macroRun = true; + } + } + + if (channel.sfxLockTime >= 0) + --channel.sfxLockTime; + else { + channel.sfxLocked = false; + channel.customMacroPrio = 0; + } + + // externally queued macros + if (channel.customMacro) { + const byte *const noteCmd = (const byte *)&channel.customMacro; + channel.sfxLocked = false; + noteCommand(noteCmd[0], noteCmd[1], (noteCmd[2] & 0xF0) | (uint8)i, noteCmd[3]); + channel.customMacro = 0; + channel.sfxLocked = (channel.customMacroPrio != 0); + } + + // apply timebased effects on Parameters + if (channel.macroSfxRun > 0) + effects(channel); + + // see if we have to run the macro-program + if (channel.macroRun) { + if (!channel.macroWait) { + macroRun(channel); + //assert( !channel.deferWait ); // we can remove this variable as it should be never true after macroRun? + } + else + --channel.macroWait; + } + + Paula::setChannelPeriod(channel.paulaChannel, channel.period); + if (channel.macroSfxRun >= 0) + channel.macroSfxRun = 1; + + // TODO: handling pending DMAOff? + } + + // Patterns are only processed each _playerCtx.timerCount + 1 tick + if (_playerCtx.song >= 0 && !_playerCtx.patternCount--) { + _playerCtx.patternCount = _playerCtx.patternSkip; + advancePatterns(); + } +} + +void Tfmx::effects(ChannelContext &channel) { + // addBegin + if (channel.addBeginLength) { + channel.sampleStart += channel.addBeginDelta; + Paula::setChannelSampleStart(channel.paulaChannel, _resource.getSamplePtr(channel.sampleStart)); + if (!(--channel.addBeginCount)) { + channel.addBeginCount = channel.addBeginLength; + channel.addBeginDelta = -channel.addBeginDelta; + } + } + + // vibrato + if (channel.vibLength) { + channel.vibValue += channel.vibDelta; + if (--channel.vibCount == 0) { + channel.vibCount = channel.vibLength; + channel.vibDelta = -channel.vibDelta; + } + if (!channel.portaDelta) { + // 16x16 bit multiplication, casts needed for the right results + channel.period = (uint16)(((uint32)channel.refPeriod * (uint16)((1 << 11) + channel.vibValue)) >> 11); + } + } + + // portamento + if (channel.portaDelta && --channel.portaCount == 0) { + channel.portaCount = channel.portaSkip; + + bool resetPorta = true; + const uint16 period = channel.refPeriod; + uint16 portaVal = channel.portaValue; + + if (period > portaVal) { + portaVal = ((uint32)portaVal * (uint16)((1 << 8) + channel.portaDelta)) >> 8; + resetPorta = (period <= portaVal); + + } else if (period < portaVal) { + portaVal = ((uint32)portaVal * (uint16)((1 << 8) - channel.portaDelta)) >> 8; + resetPorta = (period >= portaVal); + } + + if (resetPorta) { + channel.portaDelta = 0; + channel.portaValue = period & 0x7FF; + } else + channel.period = channel.portaValue = portaVal & 0x7FF; + } + + // envelope + if (channel.envSkip && !channel.envCount--) { + channel.envCount = channel.envSkip; + + const int8 endVol = channel.envEndVolume; + int8 volume = channel.volume; + bool resetEnv = true; + + if (endVol > volume) { + volume += channel.envDelta; + resetEnv = endVol <= volume; + } else { + volume -= channel.envDelta; + resetEnv = volume <= 0 || endVol >= volume; + } + + if (resetEnv) { + channel.envSkip = 0; + volume = endVol; + } + channel.volume = volume; + } + + // Fade + if (_playerCtx.fadeDelta && !(--_playerCtx.fadeCount)) { + _playerCtx.fadeCount = _playerCtx.fadeSkip; + + _playerCtx.volume += _playerCtx.fadeDelta; + if (_playerCtx.volume == _playerCtx.fadeEndVolume) + _playerCtx.fadeDelta = 0; + } + + // Volume + const uint8 finVol = _playerCtx.volume * channel.volume >> 6; + Paula::setChannelVolume(channel.paulaChannel, finVol); +} + +static void warnMacroUnimplemented(const byte *macroPtr, int level) { + if (level > 0) + return; + if (level == 0) + debug("Warning - Macro not supported:"); + else + debug("Warning - Macro not completely supported:"); +#ifdef _MSC_VER + displayMacroStep(macroPtr); +#endif +} + +void Tfmx::macroRun(ChannelContext &channel) { + bool deferWait = false; + for (;;) { + const byte *const macroPtr = (byte *)(_resource.getMacroPtr(channel.macroOffset) + channel.macroStep); + ++channel.macroStep; + + switch (macroPtr[0]) { + case 0x00: // Reset + DMA Off. Parameters: deferWait, addset, vol + clearEffects(channel); + // FT + case 0x13: // DMA Off. Parameters: deferWait, addset, vol + // TODO: implement PArameters + Paula::disableChannel(channel.paulaChannel); + channel.deferWait = deferWait = (macroPtr[1] != 0); + if (deferWait) { + // if set, then we expect a DMA On in the same tick. + channel.period = 4; + //Paula::setChannelPeriod(channel.paulaChannel, channel.period); + Paula::setChannelSampleLen(channel.paulaChannel, 1); + // in this state we then need to allow some commands that normally + // would halt the macroprogamm to continue instead. + // those commands are: Wait, WaitDMA, AddPrevNote, AddNote, SetNote, <unknown Cmd> + // DMA On is affected aswell + // TODO remember time disabled, remember pending dmaoff?. + } else { + //TODO ? + } + + if (macroPtr[2]) + channel.volume = macroPtr[3]; + else if (macroPtr[3]) + channel.volume = channel.relVol * 3 + macroPtr[3]; + else + continue; + Paula::setChannelVolume(channel.paulaChannel, channel.volume); + continue; + + case 0x01: // DMA On + // TODO: Parameter macroPtr[1] - en-/disable effects + if (macroPtr[1]) + debug("Tfmx: DMA On %i", (int8)macroPtr[1]); + channel.dmaIntCount = 0; + if (deferWait) { + // TODO + // there is actually a small delay in the player, but I think that + // only allows to clear DMA-State on real Hardware + } + Paula::setChannelPeriod(channel.paulaChannel, channel.period); + Paula::enableChannel(channel.paulaChannel); + channel.deferWait = deferWait = false; + continue; + + case 0x02: // SetBeginn. Parameters: SampleOffset(L) + channel.addBeginLength = 0; + channel.sampleStart = READ_BE_UINT32(macroPtr) & 0xFFFFFF; + Paula::setChannelSampleStart(channel.paulaChannel, _resource.getSamplePtr(channel.sampleStart)); + continue; + + case 0x03: // SetLength. Parameters: SampleLength(W) + channel.sampleLen = READ_BE_UINT16(¯oPtr[2]); + Paula::setChannelSampleLen(channel.paulaChannel, channel.sampleLen); + continue; + + case 0x04: // Wait. Parameters: Ticks to wait(W). + // TODO: some unkown Parameter? (macroPtr[1] & 1) + channel.macroWait = READ_BE_UINT16(¯oPtr[2]); + return; + + case 0x10: // Loop Key Up. Parameters: Loopcount, MacroStep(W) + if (channel.keyUp) + continue; + // FT + case 0x05: // Loop. Parameters: Loopcount, MacroStep(W) + if (channel.macroLoopCount != 0) { + if (channel.macroLoopCount == 0xFF) + channel.macroLoopCount = macroPtr[1]; + channel.macroStep = READ_BE_UINT16(¯oPtr[2]); + } + --channel.macroLoopCount; + continue; + + case 0x06: // Jump. Parameters: MacroIndex, MacroStep(W) + channel.macroIndex = macroPtr[1] & (kMaxMacroOffsets - 1); + channel.macroOffset = _macroOffset[macroPtr[1] & (kMaxMacroOffsets - 1)]; + channel.macroStep = READ_BE_UINT16(¯oPtr[2]); + channel.macroLoopCount = 0xFF; + continue; + + case 0x07: // Stop Macro + channel.macroRun = false; + --channel.macroStep; + return; + + case 0x08: // AddNote. Parameters: Note, Finetune(W) + setNoteMacro(channel, channel.note + macroPtr[1], READ_BE_UINT16(¯oPtr[2])); + break; + + case 0x09: // SetNote. Parameters: Note, Finetune(W) + setNoteMacro(channel, macroPtr[1], READ_BE_UINT16(¯oPtr[2])); + break; + + case 0x0A: // Clear Effects + clearEffects(channel); + continue; + + case 0x0B: // Portamento. Parameters: count, speed + channel.portaSkip = macroPtr[1]; + channel.portaCount = 1; + // if porta is already running, then keep using old value + if (!channel.portaDelta) + channel.portaValue = channel.refPeriod; + channel.portaDelta = READ_BE_UINT16(¯oPtr[2]); + continue; + + case 0x0C: // Vibrato. Parameters: Speed, intensity + channel.vibLength = macroPtr[1]; + channel.vibCount = macroPtr[1] / 2; + channel.vibDelta = macroPtr[3]; + if (!channel.portaDelta) { + channel.period = channel.refPeriod; + //Paula::setChannelPeriod(channel.paulaChannel, channel.period); + channel.vibValue = 0; + } + continue; + + case 0x0D: // Add Volume. Parameters: note, addNoteFlag, volume + if (macroPtr[2] == 0xFE) + setNoteMacro(channel, channel.note + macroPtr[1], 0); + channel.volume = channel.relVol * 3 + macroPtr[3]; + continue; + + case 0x0E: // Set Volume. Parameters: note, addNoteFlag, volume + if (macroPtr[2] == 0xFE) + setNoteMacro(channel, channel.note + macroPtr[1], 0); + channel.volume = macroPtr[3]; + continue; + + case 0x0F: // Envelope. Parameters: speed, count, endvol + channel.envDelta = macroPtr[1]; + channel.envCount = channel.envSkip = macroPtr[2]; + channel.envEndVolume = macroPtr[3]; + continue; + + case 0x11: // AddBegin. Parameters: times, Offset(W) + channel.addBeginLength = channel.addBeginCount = macroPtr[1]; + channel.addBeginDelta = (int16)READ_BE_UINT16(¯oPtr[2]); + channel.sampleStart += channel.addBeginDelta; + Paula::setChannelSampleStart(channel.paulaChannel, _resource.getSamplePtr(channel.sampleStart)); + warnMacroUnimplemented(macroPtr, 1); + continue; + + case 0x12: // AddLen. Parameters: added Length(W) + channel.sampleLen += (int16)READ_BE_UINT16(¯oPtr[2]); + Paula::setChannelSampleLen(channel.paulaChannel, channel.sampleLen); + continue; + + case 0x14: // Wait key up. Parameters: wait cycles + if (channel.keyUp || channel.macroLoopCount == 0) { + channel.macroLoopCount = 0xFF; + continue; + } else if (channel.macroLoopCount == 0xFF) + channel.macroLoopCount = macroPtr[3]; + --channel.macroLoopCount; + --channel.macroStep; + return; + + case 0x15: // Subroutine. Parameters: MacroIndex, Macrostep(W) + channel.macroReturnOffset = channel.macroOffset; + channel.macroReturnStep = channel.macroStep; + + channel.macroOffset = _macroOffset[macroPtr[1] & (kMaxMacroOffsets - 1)]; + channel.macroStep = READ_BE_UINT16(¯oPtr[2]); + // TODO: MI does some weird stuff there. Figure out which varioables need to be set + continue; + + case 0x16: // Return from Sub. + channel.macroOffset = channel.macroReturnOffset; + channel.macroStep = channel.macroReturnStep; + continue; + + case 0x17: // set Period. Parameters: Period(W) + channel.refPeriod = READ_BE_UINT16(¯oPtr[2]); + if (!channel.portaDelta) { + channel.period = channel.refPeriod; + //Paula::setChannelPeriod(channel.paulaChannel, channel.period); + } + continue; + + case 0x18: { // Sampleloop. Parameters: Offset from Samplestart(W) + // TODO: MI loads 24 bit, but thats useless? + const uint16 temp = /* ((int8)macroPtr[1] << 16) | */ READ_BE_UINT16(¯oPtr[2]); + if (macroPtr[1] || (temp & 1)) + warning("Tfmx: Problematic value for sampleloop: %i", (macroPtr[1] << 16) | temp); + channel.sampleStart += temp & 0xFFFE; + channel.sampleLen -= (temp / 2) /* & 0x7FFF */; + Paula::setChannelSampleStart(channel.paulaChannel, _resource.getSamplePtr(channel.sampleStart)); + Paula::setChannelSampleLen(channel.paulaChannel, channel.sampleLen); + continue; + } + case 0x19: // set one-shot Sample + channel.addBeginLength = 0; + channel.sampleStart = 0; + channel.sampleLen = 1; + Paula::setChannelSampleStart(channel.paulaChannel, _resource.getSamplePtr(0)); + Paula::setChannelSampleLen(channel.paulaChannel, 1); + continue; + + case 0x1A: // Wait on DMA. Parameters: Cycles-1(W) to wait + channel.dmaIntCount = READ_BE_UINT16(¯oPtr[2]) + 1; + channel.macroRun = false; + Paula::setChannelDmaCount(channel.paulaChannel); + break; + + case 0x1B: // Random play. Parameters: macro/speed/mode + warnMacroUnimplemented(macroPtr, 0); + continue; + + case 0x1C: // Branch on Note. Parameters: note/macrostep(W) + if (channel.note > macroPtr[1]) + channel.macroStep = READ_BE_UINT16(¯oPtr[2]); + continue; + + case 0x1D: // Branch on Volume. Parameters: volume/macrostep(W) + if (channel.volume > macroPtr[1]) + channel.macroStep = READ_BE_UINT16(¯oPtr[2]); + continue; + + case 0x1E: // Addvol+note. Parameters: note/CONST./volume + warnMacroUnimplemented(macroPtr, 0); + continue; + + case 0x1F: // AddPrevNote. Parameters: Note, Finetune(W) + setNoteMacro(channel, channel.prevNote + macroPtr[1], READ_BE_UINT16(¯oPtr[2])); + break; + + case 0x20: // Signal. Parameters: signalnumber/value + if (_playerCtx.signal) + _playerCtx.signal[macroPtr[1]] = READ_BE_UINT16(¯oPtr[2]); + continue; + + case 0x21: // Play macro. Parameters: macro/chan/detune + noteCommand(channel.note, (channel.relVol << 4) | macroPtr[1], macroPtr[2], macroPtr[3]); + continue; + #if defined(TFMX_NOT_IMPLEMENTED) + // used by Gem`X according to the docs + case 0x22: // SID setbeg. Parameters: sample-startadress + return true; + case 0x23: // SID setlen. Parameters: buflen/sourcelen + return true; + case 0x24: // SID op3 ofs. Parameters: offset + return true; + case 0x25: // SID op3 frq. Parameters: speed/amplitude + return true; + case 0x26: // SID op2 ofs. Parameters: offset + return true; + case 0x27: // SID op2 frq. Parameters: speed/amplitude + return true; + case 0x28: // ID op1. Parameters: speed/amplitude/TC + return true; + case 0x29: // SID stop. Parameters: flag (1=clear all) + return true; + // 30-34 used by Carribean Disaster + #endif + default: + warnMacroUnimplemented(macroPtr, 0); + } + if (!deferWait) + return; + } +} + +void Tfmx::advancePatterns() { +startPatterns: + int runningPatterns = 0; + + for (int i = 0; i < kNumChannels; ++i) { + const uint8 pattCmd = _patternCtx[i].command; + if (pattCmd < 0x90) { // execute Patternstep + ++runningPatterns; + if (_patternCtx[i].wait == 0) { + // issue all Steps for this tick + const bool pendingTrackstep = patternRun(_patternCtx[i]); + + if (pendingTrackstep) { + // we load the next Trackstep Command and then process all Channels again + trackRun(true); + goto startPatterns; + } + + } else + --_patternCtx[i].wait; + + } else if (pattCmd == 0xFE) { // Stop voice in pattern.expose + _patternCtx[i].command = 0xFF; + ChannelContext &channel = _channelCtx[_patternCtx[i].expose & (kNumVoices - 1)]; + if (!channel.sfxLocked) { + clearMacroProgramm(channel); + Paula::disableChannel(channel.paulaChannel); + } + } // else this pattern-Channel is stopped + } + if (_playerCtx.stopWithLastPattern && !runningPatterns) { + stopPaula(); + } +} + +static void warnPatternUnimplemented(const byte *patternPtr, int level) { + if (level > 0) + return; + if (level == 0) + debug("Warning - Pattern not supported:"); + else + debug("Warning - Pattern not completely supported:"); +#ifdef _MSC_VER + displayPatternstep(patternPtr); +#endif +} + +bool Tfmx::patternRun(PatternContext &pattern) { + for (;;) { + const byte *const patternPtr = (byte *)(_resource.getPatternPtr(pattern.offset) + pattern.step); + ++pattern.step; + const byte pattCmd = patternPtr[0]; + + if (pattCmd < 0xF0) { // Playnote + bool doWait = false; + byte noteCmd = pattCmd + pattern.expose; + byte param3 = patternPtr[3]; + if (pattCmd < 0xC0) { // Note + if (pattCmd >= 0x80) { // Wait + pattern.wait = param3; + param3 = 0; + doWait = true; + } + noteCmd &= 0x3F; + } // else Portamento + noteCommand(noteCmd, patternPtr[1], patternPtr[2], param3); + if (doWait) + return false; + + } else { // Patterncommand + switch (pattCmd & 0xF) { + case 0: // End Pattern + Next Trackstep + pattern.command = 0xFF; + --pattern.step; + return true; + + case 1: // Loop Pattern. Parameters: Loopcount, PatternStep(W) + if (pattern.loopCount != 0) { + if (pattern.loopCount == 0xFF) + pattern.loopCount = patternPtr[1]; + pattern.step = READ_BE_UINT16(&patternPtr[2]); + } + --pattern.loopCount; + continue; + + case 2: // Jump. Parameters: PatternIndex, PatternStep(W) + pattern.offset = _patternOffset[patternPtr[1]]; + pattern.step = READ_BE_UINT16(&patternPtr[2]); + continue; + + case 3: // Wait. Paramters: ticks to wait + pattern.wait = patternPtr[1]; + return false; + + case 14: // Stop custompattern + // TODO ? + warnPatternUnimplemented(patternPtr, 1); + // FT + case 4: // Stop this pattern + pattern.command = 0xFF; + --pattern.step; + // TODO: try figuring out if this was the last Channel? + return false; + + case 5: // Key Up Signal + if (!_channelCtx[patternPtr[2] & (kNumVoices - 1)].sfxLocked) + _channelCtx[patternPtr[2] & (kNumVoices - 1)].keyUp = true; + continue; + + case 6: // Vibrato + case 7: // Envelope + noteCommand(pattCmd, patternPtr[1], patternPtr[2], patternPtr[3]); + continue; + + case 8: // Subroutine + warnPatternUnimplemented(patternPtr, 0); + continue; + + case 9: // Return from Subroutine + warnPatternUnimplemented(patternPtr, 0); + continue; + + case 10: // fade master volume + _playerCtx.fadeCount = _playerCtx.fadeSkip = patternPtr[1]; + _playerCtx.fadeEndVolume = (int8)patternPtr[3]; + if (_playerCtx.fadeSkip) { + const int diff = _playerCtx.fadeEndVolume - _playerCtx.volume; + _playerCtx.fadeDelta = (diff != 0) ? ((diff > 0) ? 1 : -1) : 0; + } else { + _playerCtx.volume = _playerCtx.fadeEndVolume; + _playerCtx.fadeDelta = 0; + } + ++_trackCtx.posInd; + continue; + + case 11: { // play pattern. Parameters: patternCmd, channel, expose + PatternContext &target = _patternCtx[patternPtr[2] & (kNumChannels - 1)]; + + target.command = patternPtr[1]; + target.offset = _patternOffset[patternPtr[1] & (kMaxPatternOffsets - 1)]; + target.expose = patternPtr[3]; + target.step = 0; + target.wait = 0; + target.loopCount = 0xFF; + } + continue; + + case 12: // Lock + _channelCtx[patternPtr[2] & (kNumVoices - 1)].sfxLocked = (patternPtr[1] != 0); + _channelCtx[patternPtr[2] & (kNumVoices - 1)].sfxLockTime = patternPtr[3]; + continue; + + case 13: // Cue + if (_playerCtx.signal) + _playerCtx.signal[patternPtr[1]] = READ_BE_UINT16(&patternPtr[2]); + continue; + + case 15: // NOP + continue; + } + } + } +} + +bool Tfmx::trackRun(const bool incStep) { + assert(_playerCtx.song >= 0); + if (incStep) { + // TODO Optionally disable looping + if (_trackCtx.posInd == _trackCtx.stopInd) + _trackCtx.posInd = _trackCtx.startInd; + else + ++_trackCtx.posInd; + } + for (;;) { + const uint16 *const trackData = _resource.getTrackPtr(_trackCtx.posInd); + + if (trackData[0] != FROM_BE_16(0xEFFE)) { + // 8 commands for Patterns + for (int i = 0; i < 8; ++i) { + const uint patCmd = READ_BE_UINT16(&trackData[i]); + // First byte is pattern number + const uint patNum = (patCmd >> 8); + // if highest bit is set then keep previous pattern + if (patNum < 0x80) { + _patternCtx[i].step = 0; + _patternCtx[i].wait = 0; + _patternCtx[i].loopCount = 0xFF; + _patternCtx[i].offset = _patternOffset[patNum]; + } + _patternCtx[i].command = (uint8)patNum; + _patternCtx[i].expose = patCmd & 0xFF; + } + return true; + + } else { + // 16 byte Trackstep Command + switch (READ_BE_UINT16(&trackData[1])) { + case 0: // Stop Player. No Parameters + stopPaula(); + return false; + + case 1: // Branch/Loop section of tracksteps. Parameters: branch target, loopcount + if (_trackCtx.loopCount != 0) { + if (_trackCtx.loopCount < 0) + _trackCtx.loopCount = READ_BE_UINT16(&trackData[3]); + _trackCtx.posInd = READ_BE_UINT16(&trackData[2]); + continue; + } + --_trackCtx.loopCount; + break; + + case 2: { // Set Tempo. Parameters: tempo, divisor + _playerCtx.patternCount = _playerCtx.patternSkip = READ_BE_UINT16(&trackData[2]); // tempo + const uint16 temp = READ_BE_UINT16(&trackData[3]); // divisor + + if (!(temp & 0x8000) && (temp & 0x1FF)) + setInterruptFreqUnscaled(temp & 0x1FF); + break; + } + case 4: // Fade + _playerCtx.fadeCount = _playerCtx.fadeSkip = (uint8)READ_BE_UINT16(&trackData[2]); + _playerCtx.fadeEndVolume = (int8)READ_BE_UINT16(&trackData[3]); + + if (_playerCtx.fadeSkip) { + const int diff = _playerCtx.fadeEndVolume - _playerCtx.volume; + _playerCtx.fadeDelta = (diff != 0) ? ((diff > 0) ? 1 : -1) : 0; + } else { + _playerCtx.volume = _playerCtx.fadeEndVolume; + _playerCtx.fadeDelta = 0; + } + break; + + case 3: // Unknown, stops player aswell + default: + debug("Unknown Command: %02X", READ_BE_UINT16(&trackData[1])); + // MI-Player handles this by stopping the player, we just continue + } + } + + if (_trackCtx.posInd == _trackCtx.stopInd) { + warning("Tfmx: Reached invalid Song-Position"); + return false; + } + ++_trackCtx.posInd; + } +} + +void Tfmx::noteCommand(const uint8 note, const uint8 param1, const uint8 param2, const uint8 param3) { + ChannelContext &channel = _channelCtx[param2 & (kNumVoices - 1)]; + + if (note == 0xFC) { // Lock + channel.sfxLocked = (param1 != 0); + channel.sfxLockTime = param3; // only 1 byte read! + return; + } + if (channel.sfxLocked) + return; + + if (note < 0xC0) { // Play Note + channel.prevNote = channel.note; + channel.note = note; + channel.macroIndex = param1 & (kMaxMacroOffsets - 1); + channel.macroOffset = _macroOffset[param1 & (kMaxMacroOffsets - 1)]; + channel.relVol = (param2 >> 4) & 0xF; + channel.fineTune = (int8)param3; + + initMacroProgramm(channel); + channel.keyUp = false; // key down = playing a Note + + } else if (note < 0xF0) { // Portamento + channel.portaSkip = param1; + channel.portaCount = 1; + if (!channel.portaDelta) + channel.portaValue = channel.refPeriod; + channel.portaDelta = param3; + + channel.note = note & 0x3F; + channel.refPeriod = noteIntervalls[channel.note]; + } else switch (note & 0xF) { // Command + case 5: // Key Up Signal + channel.keyUp = true; + break; + case 6: // Vibratio + channel.vibLength = param1 & 0xFE; + channel.vibCount = param1 / 2; + channel.vibValue = 0; + break; + case 7: // Envelope + channel.envDelta = param1; + channel.envSkip = channel.envCount = (param2 >> 4) + 1; + channel.envEndVolume = param3; + break; + } +} + +bool Tfmx::load(Common::SeekableReadStream &musicData, Common::SeekableReadStream &sampleData) { + bool res; + + assert(0 == _resource._mdatData); + assert(0 == _resource._sampleData); + + // TODO: Sanity checks if we have a valid TFMX-Module + // TODO: check for Stream-Errors (other than using asserts) + + // 0x0000: 10 Bytes Header "TFMX-SONG " + // 0x000A: int16 ? + // 0x000C: int32 ? + musicData.read(_resource.header, 10); + _resource.headerFlags = musicData.readUint16BE(); + _resource.headerUnknown = musicData.readUint32BE(); + + // This might affect timing + // bool isPalModule = (_resource.headerFlags & 2) != 0; + + // 0x0010: 6*40 Textfield + musicData.read(_resource.textField, 6 * 40); + + /* 0x0100: Songstart x 32*/ + for (int i = 0; i < kNumSubsongs; ++i) + _subsong[i].songstart = musicData.readUint16BE(); + + /* 0x0140: Songend x 32*/ + for (int i = 0; i < kNumSubsongs; ++i) + _subsong[i].songend = musicData.readUint16BE(); + + /* 0x0180: Tempo x 32*/ + for (int i = 0; i < kNumSubsongs; ++i) + _subsong[i].tempo = musicData.readUint16BE(); + + /* 0x01c0: unused ? */ + musicData.skip(16); + + /* 0x01d0: trackstep, pattern data p, macro data p */ + uint32 offTrackstep = musicData.readUint32BE(); + uint32 offPatternP = musicData.readUint32BE(); + uint32 offMacroP = musicData.readUint32BE(); + _resource._sfxTableOffset = 0x200; + bool getSfxIndex = false; + + // This is how MI`s TFMX-Player tests for unpacked Modules. + if (offTrackstep == 0) { + offTrackstep = 0x600 + 0x200; + offPatternP = 0x200 + 0x200; + offMacroP = 0x400 + 0x200; + getSfxIndex = true; + _resource._sfxTableOffset = 0x5FC; + } + + _resource._trackstepOffset = offTrackstep; + + // Read in pattern starting offsets + musicData.seek(offPatternP); + for (int i = 0; i < kMaxPatternOffsets; ++i) + _patternOffset[i] = musicData.readUint32BE(); + + res = musicData.err(); + assert(!res); + + if (getSfxIndex) + _resource._sfxTableOffset = _patternOffset[127]; + + // Read in macro starting offsets + musicData.seek(offMacroP); + for (int i = 0; i < kMaxMacroOffsets; ++i) + _macroOffset[i] = musicData.readUint32BE(); + + res = musicData.err(); + assert(!res); + + // Read in whole mdat-file + int32 size = musicData.size(); + assert(size != -1); + // TODO: special routine if size = -1? + + _resource._mdatData = new byte[size]; + assert(_resource._mdatData); + _resource._mdatLen = size; + musicData.seek(0); + musicData.read(_resource._mdatData, size); + + res = musicData.err(); + assert(!res); + musicData.readByte(); + res = musicData.eos(); + assert(res); + + + // TODO: It would be possible to analyze the pointers and be able to + // seperate the file in trackstep, patterns and macro blocks + // Modules could do weird stuff like having those blocks mixed though. + // TODO: Analyze pointers if they are correct offsets, + // so that accesses can be unchecked later + + // Read in whole sample-file + size = sampleData.size(); + assert(size >= 4); + assert(size != -1); + // TODO: special routine if size = -1? + + _resource._sampleData = new byte[size]; + assert(_resource._sampleData); + _resource._sampleLen = size; + sampleData.seek(0); + sampleData.read(_resource._sampleData, size); + for (int i = 0; i < 4; ++i) + _resource._sampleData[i] = 0; + + res = sampleData.err(); + assert(!res); + sampleData.readByte(); + res = sampleData.eos(); + assert(res); + + return true; +} + + +void Tfmx::doMacro(int note, int macro, int relVol, int finetune, int channelNo) { + assert(0 <= macro && macro < kMaxMacroOffsets); + assert(0 <= note && note < 0xC0); + Common::StackLock lock(_mutex); + + channelNo &= (kNumVoices - 1); + ChannelContext &channel = _channelCtx[channelNo]; + unlockMacroChannel(channel); + + noteCommand((uint8)note, (uint8)macro, (uint8)(relVol << 4) | channelNo, (uint8)finetune); + startPaula(); +} + +void Tfmx::stopSong(bool stopAudio) { + Common::StackLock lock(_mutex); + _playerCtx.song = -1; + if (stopAudio) { + stopMacroChannels(); + stopPaula(); + } +} + +void Tfmx::doSong(int songPos, bool stopAudio) { + assert(0 <= songPos && songPos < kNumSubsongs); + Common::StackLock lock(_mutex); + + stopPatternChannels(); + if (stopAudio) { + stopMacroChannels(); + stopPaula(); + } + + _playerCtx.song = (int8)songPos; + + _trackCtx.loopCount = -1; + _trackCtx.startInd = _trackCtx.posInd = _subsong[songPos].songstart; + _trackCtx.stopInd = _subsong[songPos].songend; + + const bool palFlag = (_resource.headerFlags & 2) != 0; + const uint16 tempo = _subsong[songPos].tempo; + uint16 ciaIntervall; + if (tempo >= 0x10) { + ciaIntervall = (uint16)(kCiaBaseInterval / tempo); + _playerCtx.patternSkip = 0; + } else { + ciaIntervall = palFlag ? (uint16)kPalDefaultCiaVal : (uint16)kNtscDefaultCiaVal; + _playerCtx.patternSkip = tempo; + } + setInterruptFreqUnscaled(ciaIntervall); + + _playerCtx.patternCount = 0; + if (trackRun()) + startPaula(); +} + +int Tfmx::doSfx(uint16 sfxIndex, bool unlockChannel) { + assert(0 <= sfxIndex && sfxIndex < 128); + Common::StackLock lock(_mutex); + + const byte *sfxEntry = _resource.getSfxPtr(sfxIndex); + if (sfxEntry[0] == 0xFB) { + // custompattern + const uint8 patCmd = sfxEntry[2]; + const int8 patExp = (int8)sfxEntry[3]; + } else { + // custommacro + const byte channelNo = ((_playerCtx.song >= 0) ? sfxEntry[2] : sfxEntry[4]) & (kNumVoices - 1); + const byte priority = sfxEntry[5] & 0x7F; + + ChannelContext &channel = _channelCtx[channelNo]; + if (unlockChannel) + unlockMacroChannel(channel); + + const int16 sfxLocktime = channel.sfxLockTime; + if (priority >= channel.customMacroPrio || sfxLocktime < 0) { + if (sfxIndex != channel.customMacroIndex || sfxLocktime < 0 || (sfxEntry[5] < 0x80)) { + channel.customMacro = READ_UINT32(sfxEntry); // intentionally not "endian-correct" + channel.customMacroPrio = priority; + channel.customMacroIndex = (uint8)sfxIndex; + debug(3, "Tfmx: running Macro %08X on channel %i - priority: %02X", TO_BE_32(channel.customMacro), channelNo, priority); + return channelNo; + } + } + } + return -1; +} + +} diff --git a/sound/mods/tfmx.h b/sound/mods/tfmx.h new file mode 100644 index 0000000000..fccdf0aa01 --- /dev/null +++ b/sound/mods/tfmx.h @@ -0,0 +1,296 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef SOUND_MODS_TFMX_H +#define SOUND_MODS_TFMX_H + +#include "sound/mods/paula.h" + +namespace { +#ifndef NDEBUG +inline void boundaryCheck(const void *bufStart, size_t bufLen, const void *address, size_t accessLen = 1) { + assert(bufStart <= address && (const byte *)address + accessLen <= (const byte *)bufStart + bufLen); +} +#else +inline void boundaryCheck(const void *, size_t, void *, size_t = 1) {} +#endif +} + +namespace Audio { + +class Tfmx : public Paula { +public: + Tfmx(int rate, bool stereo); + virtual ~Tfmx(); + + void interrupt(); + void stopSong(bool stopAudio = true); + void doSong(int songPos, bool stopAudio = false); + int doSfx(uint16 sfxIndex, bool unlockChannel = false); + void doMacro(int note, int macro, int relVol = 0, int finetune = 0, int channelNo = 0); + bool load(Common::SeekableReadStream &musicData, Common::SeekableReadStream &sampleData); + int getTicks() const {return _playerCtx.tickCount;} + int getSongIndex() const {return _playerCtx.song;} + void setSignalPtr(uint16 *ptr) {_playerCtx.signal = ptr;} + void stopMacroEffect(int channel) { + assert(0 <= channel && channel < kNumVoices); + Common::StackLock lock(_mutex); + unlockMacroChannel(_channelCtx[channel]); + clearMacroProgramm(_channelCtx[channel]); + Paula::disableChannel(_channelCtx[channel].paulaChannel); + } + +// Note: everythings public so the debug-Routines work. +// private: + enum {kPalDefaultCiaVal = 11822, kNtscDefaultCiaVal = 14320, kCiaBaseInterval = 0x1B51F8}; + enum {kNumVoices = 4, kNumChannels = 8, kNumSubsongs = 32, kMaxPatternOffsets = 128, kMaxMacroOffsets = 128}; + + static const uint16 noteIntervalls[64]; + + struct Resource { + uint32 _trackstepOffset; //!< Offset in mdat + uint32 _sfxTableOffset; + + byte *_mdatData; //!< Currently the whole mdat-File + byte *_sampleData; //!< Currently the whole sample-File + + uint32 _mdatLen; + uint32 _sampleLen; + + byte header[10]; + uint16 headerFlags; + uint32 headerUnknown; + char textField[6 * 40]; + + const byte *getSfxPtr(uint16 index = 0) { + byte *sfxPtr = (byte *)(_mdatData + _sfxTableOffset + index * 8); + + boundaryCheck(_mdatData, _mdatLen, sfxPtr, 8); + return sfxPtr; + } + + const uint16 *getTrackPtr(uint16 trackstep = 0) { + uint16 *trackData = (uint16 *)(_mdatData + _trackstepOffset + 16 * trackstep); + + boundaryCheck(_mdatData, _mdatLen, trackData, 16); + return trackData; + } + + const uint32 *getPatternPtr(uint32 offset) { + uint32 *pattData = (uint32 *)(_mdatData + offset); + + boundaryCheck(_mdatData, _mdatLen, pattData, 4); + return pattData; + } + + const uint32 *getMacroPtr(uint32 offset) { + uint32 *macroData = (uint32 *)(_mdatData + offset); + + boundaryCheck(_mdatData, _mdatLen, macroData, 4); + return macroData; + } + + const int8 *getSamplePtr(const uint32 offset) { + int8 *sampleData = (int8 *)(_sampleData + offset); + + boundaryCheck(_sampleData, _sampleLen, sampleData, 2); + return sampleData; + } + Resource() : _mdatData(), _mdatLen(), _sampleData(), _sampleLen() {} + + ~Resource() { + delete[] _mdatData; + delete[] _sampleData; + } + } _resource; + + uint32 _patternOffset[kMaxPatternOffsets]; //!< Offset in mdat + uint32 _macroOffset[kMaxMacroOffsets]; //!< Offset in mdat + + struct Subsong { + uint16 songstart; //!< Index in Trackstep-Table + uint16 songend; //!< Last index in Trackstep-Table + uint16 tempo; + } _subsong[kNumSubsongs]; + + struct ChannelContext { + byte paulaChannel; + + byte macroIndex; + uint16 macroWait; + uint32 macroOffset; + uint32 macroReturnOffset; + uint16 macroStep; + uint16 macroReturnStep; + uint8 macroLoopCount; + bool macroRun; + int8 macroSfxRun; + + uint32 customMacro; + uint8 customMacroIndex; + uint8 customMacroPrio; + + bool sfxLocked; + int16 sfxLockTime; + bool keyUp; + + bool deferWait; + uint16 dmaIntCount; + + uint32 sampleStart; + uint16 sampleLen; + uint16 refPeriod; + uint16 period; + + int8 volume; + uint8 relVol; + uint8 note; + uint8 prevNote; + int16 fineTune; // always a signextended byte + + uint8 portaSkip; + uint8 portaCount; + uint16 portaDelta; + uint16 portaValue; + + uint8 envSkip; + uint8 envCount; + uint8 envDelta; + int8 envEndVolume; + + uint8 vibLength; + uint8 vibCount; + int16 vibValue; + int8 vibDelta; + + uint8 addBeginLength; + uint8 addBeginCount; + int32 addBeginDelta; + } _channelCtx[kNumVoices]; + + struct PatternContext { + uint32 offset; // patternStart, Offset from mdat + uint32 savedOffset; // for subroutine calls + uint16 step; // distance from patternStart + uint16 savedStep; + + uint8 command; + int8 expose; + uint8 loopCount; + uint8 wait; //!< how many ticks to wait before next Command + } _patternCtx[kNumChannels]; + + struct TrackStepContext { + uint16 startInd; + uint16 stopInd; + uint16 posInd; + int16 loopCount; + } _trackCtx; + + struct PlayerContext { + int8 song; //!< >= 0 if Song is running (means process Patterns) + + uint16 patternCount; + uint16 patternSkip; //!< skip that amount of CIA-Interrupts + + int8 volume; //!< Master Volume + + uint8 fadeSkip; + uint8 fadeCount; + int8 fadeEndVolume; + int8 fadeDelta; + + int tickCount; + + uint16 *signal; + + bool stopWithLastPattern; //!< hack to automatically stop the whole player if no Pattern is running + } _playerCtx; +private: + static void initMacroProgramm(ChannelContext &channel) { + channel.macroStep = 0; + channel.macroWait = 0; + channel.macroRun = true; + channel.macroSfxRun = 0; + channel.macroLoopCount = 0xFF; + channel.dmaIntCount = 0; + } + + static void clearEffects(ChannelContext &channel) { + channel.addBeginLength = 0; + channel.envSkip = 0; + channel.vibLength = 0; + channel.portaDelta = 0; + } + + static void clearMacroProgramm(ChannelContext &channel) { + channel.macroRun = false; + channel.macroSfxRun = 0; + channel.dmaIntCount = 0; + } + + static void unlockMacroChannel(ChannelContext &channel) { + channel.customMacro = 0; + channel.customMacroPrio = false; + channel.sfxLocked = false; + channel.sfxLockTime = -1; + } + + void stopPatternChannels() { + for (int i = 0; i < kNumChannels; ++i) { + _patternCtx[i].command = 0xFF; + _patternCtx[i].expose = 0; + } + } + + void stopMacroChannels() { + for (int i = 0; i < kNumVoices; ++i) { + clearEffects(_channelCtx[i]); + unlockMacroChannel(_channelCtx[i]); + clearMacroProgramm(_channelCtx[i]); + _channelCtx[i].note = 0; + _channelCtx[i].volume = 0; + } + } + + static void setNoteMacro(ChannelContext &channel, uint note, int fineTune) { + const uint16 noteInt = noteIntervalls[note & 0x3F]; + const uint16 finetune = (uint16)(fineTune + channel.fineTune + (1 << 8)); + channel.refPeriod = ((uint32)noteInt * finetune >> 8); + if (!channel.portaDelta) + channel.period = channel.refPeriod; + } + + void effects(ChannelContext &channel); + void macroRun(ChannelContext &channel); + void advancePatterns(); + bool patternRun(PatternContext &pattern); + bool trackRun(bool incStep = false); + void noteCommand(uint8 note, uint8 param1, uint8 param2, uint8 param3); +}; + +} + +#endif diff --git a/sound/module.mk b/sound/module.mk index dba9501a38..0c24e0cf0e 100644 --- a/sound/module.mk +++ b/sound/module.mk @@ -29,6 +29,7 @@ MODULE_OBJS := \ mods/paula.o \ mods/rjp1.o \ mods/soundfx.o \ + mods/tfmx.o \ softsynth/adlib.o \ softsynth/opl/dosbox.o \ softsynth/opl/mame.o \ diff --git a/tfmx/module.mk b/tfmx/module.mk new file mode 100644 index 0000000000..41d114bfb0 --- /dev/null +++ b/tfmx/module.mk @@ -0,0 +1,8 @@ +MODULE := tfmx + +MODULE_OBJS := \ + tfmxplayer.o \ + tfmxdebug.o + +# Include common rules +include $(srcdir)/rules.mk diff --git a/tfmx/tfmxdebug.cpp b/tfmx/tfmxdebug.cpp new file mode 100644 index 0000000000..95bad15a96 --- /dev/null +++ b/tfmx/tfmxdebug.cpp @@ -0,0 +1,200 @@ +#include "common/scummsys.h" +#include "common/endian.h" +#include "common/debug.h" +#include "common/stream.h" +#include "common/util.h" + +#include "sound/mods/tfmx.h" + +#include "tfmx/tfmxdebug.h" + + +const char *pattcmds[]={ + "End --Next track step--", + "Loop[count / step.w]", + "Cont[patternno./ step.w]", + "Wait[count 00-FF--------", + "Stop--Stop this pattern-", + "Kup^-Set key up/channel]", + "Vibr[speed / rate.b]", + "Enve[speed /endvolume.b]", + "GsPt[patternno./ step.w]", + "RoPt-Return old pattern-", + "Fade[speed /endvolume.b]", + "PPat[patt./track+transp]", + "Lock---------ch./time.b]", + "Cue [number.b/ value.w]", + "Stop-Stop custompattern-", + "NOP!-no operation-------" +}; + +const char *macrocmds[]={ + "DMAoff+Resetxx/xx/xx flag/addset/vol ", + "DMAon (start sample at selected begin) ", + "SetBegin xxxxxx sample-startadress", + "SetLen ..xxxx sample-length ", + "Wait ..xxxx count (VBI''s) ", + "Loop xx/xxxx count/step ", + "Cont xx/xxxx macro-number/step ", + "-------------STOP----------------------", + "AddNote xx/xxxx note/detune ", + "SetNote xx/xxxx note/detune ", + "Reset Vibrato-Portamento-Envelope ", + "Portamento xx/../xx count/speed ", + "Vibrato xx/../xx speed/intensity ", + "AddVolume ....xx volume 00-3F ", + "SetVolume ....xx volume 00-3F ", + "Envelope xx/xx/xx speed/count/endvol", + "Loop key up xx/xxxx count/step ", + "AddBegin xx/xxxx count/add to start", + "AddLen ..xxxx add to sample-len ", + "DMAoff stop sample but no clear ", + "Wait key up ....xx count (VBI''s) ", + "Go submacro xx/xxxx macro-number/step ", + "--------Return to old macro------------", + "Setperiod ..xxxx DMA period ", + "Sampleloop ..xxxx relative adress ", + "-------Set one shot sample-------------", + "Wait on DMA ..xxxx count (Wavecycles)", + "Random play xx/xx/xx macro/speed/mode ", + "Splitkey xx/xxxx key/macrostep ", + "Splitvolume xx/xxxx volume/macrostep ", + "Addvol+note xx/fe/xx note/CONST./volume", + "SetPrevNote xx/xxxx note/detune ", + "Signal xx/xxxx signalnumber/value", + "Play macro xx/.x/xx macro/chan/detune ", + "SID setbeg xxxxxx sample-startadress", + "SID setlen xx/xxxx buflen/sourcelen ", + "SID op3 ofs xxxxxx offset ", + "SID op3 frq xx/xxxx speed/amplitude ", + "SID op2 ofs xxxxxx offset ", + "SID op2 frq xx/xxxx speed/amplitude ", + "SID op1 xx/xx/xx speed/amplitude/TC", + "SID stop xx.... flag (1=clear all)" +}; + +const char *const trackstepFmt[] = { + "---Stop Player----", + "Loop step/count ", + "Tempo tempo/ciaDiv", + "Timeshare ?/? ", + "Fade start/end " +}; + +void displayPatternstep(const void *const vptr) { + const byte *const patData = (const byte *const)vptr; + + const byte command = patData[0]; + + if (command < 0xF0) { // Playnote + const byte flags = command >> 6; // 0-1 means note+detune, 2 means wait, 3 means portamento? + char *flagsSt[] = {"Note ", "Note ", "Wait ", "Porta"}; + debug("%s %02X%02X%02X%02X", flagsSt[flags], patData[0], patData[1], patData[2], patData[3]); + } else { + debug("%s %02X%02X%02X",pattcmds[command&0xF], patData[1], patData[2], patData[3]); + } + +} + +void displayTrackstep(const void *const vptr) { + const uint16 *const trackData = (const uint16 *const)vptr; + + if (trackData[0] == FROM_BE_16(0xEFFE)) { + // 16 byte Trackstep Command + const uint16 command = READ_BE_UINT16(&trackData[1]); + const uint16 param1 = READ_BE_UINT16(&trackData[2]); + const uint16 param2 = READ_BE_UINT16(&trackData[3]); + + + if (command >= ARRAYSIZE(trackstepFmt)) + debug("Unknown (%04X) : %04X %04X", command, param1, param2); + else + debug("%s: %04X %04X", trackstepFmt[command], param1, param2); + } else { + const byte *const ptr = (const byte *const)vptr; + // 8 commands for Patterns + debug("%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X", + ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], + ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]); + } +} + +void displayMacroStep(const void *const vptr, int chan, int index) { + const byte *const macroData = (const byte *const)vptr; + + if (macroData[0] < ARRAYSIZE(macrocmds)) + debug("%02X %02X %s %02X%02X%02X", chan, index, macrocmds[macroData[0]], macroData[1], macroData[2], macroData[3]); + else + debug("%02X %02X Unkown Macro #%02X %02X%02X%02X", chan, index, macroData[0], macroData[1], macroData[2], macroData[3]); +} + +void displayMacroStep(const void *const vptr) { + const byte *const macroData = (const byte *const)vptr; + + if (macroData[0] < ARRAYSIZE(macrocmds)) + debug("%s %02X%02X%02X", macrocmds[macroData[0]], macroData[1], macroData[2], macroData[3]); + else + debug("Unkown Macro #%02X %02X%02X%02X", macroData[0], macroData[1], macroData[2], macroData[3]); +} + +void dumpTracksteps(Audio::Tfmx &player, uint16 first, uint16 last) { + for ( ; first <= last; ++first) { + displayTrackstep(player._resource.getTrackPtr(first)); + } +} + +void dumpTrackstepsBySong(Audio::Tfmx &player, int song) { + debug("Song %02X: Pos %02X - %02X. Tempo: %02X", song, player._subsong[song].songstart, player._subsong[song].songend, player._subsong[song].tempo); + dumpTracksteps(player, player._subsong[song].songstart, player._subsong[song].songend); + debug(""); +} + +void dumpMacro(Audio::Tfmx &player, uint16 macroIndex, uint16 len, uint16 start) { + const uint32 * macroPtr = player._resource.getMacroPtr(player._macroOffset[macroIndex]); + bool untilMacroStop = (len == 0); + while (len--) { + displayMacroStep(macroPtr++); + } + while (untilMacroStop) { + untilMacroStop = *(const byte *)macroPtr != 7; + displayMacroStep(macroPtr++); + } +} + +void dumpPattern(Audio::Tfmx &player, uint16 pattIndex, uint16 len, uint16 start) { + const uint32 * pattPtr = player._resource.getPatternPtr(player._patternOffset[pattIndex]); + if (len == 0) + len = (player._patternOffset[pattIndex+1] - player._patternOffset[pattIndex])/4; + bool untilMacroStop = (len == 0); + while (len--) { + displayPatternstep(pattPtr++); + } + while (untilMacroStop) { + byte cmd = *(const byte *)pattPtr; + untilMacroStop = cmd != 0 && cmd != 4; + displayPatternstep(pattPtr++); + } +} + +void countAllMacros1(Audio::Tfmx &player, uint16 macroIndex, int *list) { + const uint32 * macroPtr = player._resource.getMacroPtr(player._macroOffset[macroIndex]); + bool untilMacroStop = true; + while (untilMacroStop) { + const int type = *(const byte *)macroPtr++; + untilMacroStop = type != 7; + list[type]++; + } +} + +void countAllMacros(Audio::Tfmx &player) { + int list[256] = {0}; + for (int i = 0; i < 128; ++i) + countAllMacros1(player, i, list); + byte fakeMacro[4] = {0}; + for (int i = 0; i < 256; ++i) { + fakeMacro[0] = (byte)i; + if (list[i] > 0) + displayMacroStep(fakeMacro); + } + +} diff --git a/tfmx/tfmxdebug.h b/tfmx/tfmxdebug.h new file mode 100644 index 0000000000..e849e561a9 --- /dev/null +++ b/tfmx/tfmxdebug.h @@ -0,0 +1,14 @@ +#ifndef TFMXDEBUG_H +#define TFMXDEBUG_H + +void displayTrackstep(const void *const vptr); +void displayPatternstep(const void *const vptr); +void displayMacroStep(const void *const vptr); +void displayMacroStep(const void *const vptr, int chan, int index); +void dumpTracksteps(Audio::Tfmx &player, uint16 first, uint16 last); +void dumpTrackstepsBySong(Audio::Tfmx &player, int song); +void dumpMacro(Audio::Tfmx &player, uint16 macroIndex, uint16 len = 0, uint16 start = 0); +void dumpPattern(Audio::Tfmx &player, uint16 pattIndex, uint16 len = 0, uint16 start = 0); +void countAllMacros(Audio::Tfmx &player); + +#endif // TFMXDEBUG_H
\ No newline at end of file diff --git a/tfmx/tfmxplayer.cpp b/tfmx/tfmxplayer.cpp new file mode 100644 index 0000000000..efc3ce68b1 --- /dev/null +++ b/tfmx/tfmxplayer.cpp @@ -0,0 +1,170 @@ +#include "common/scummsys.h" +#include "common/system.h" +#include "common/stream.h" +#include "common/file.h" +#include "common/fs.h" +#include "common/endian.h" +#include "common/debug.h" + +#include "sound/mixer.h" +#include "sound/mods/protracker.h" +#include "sound/mods/tfmx.h" + +#include "tfmx/tfmxdebug.h" + +#define FILEDIR "" + +using namespace Common; + +#define MUSICFILE "mdat.monkey" +#define SAMPLEFILE "smpl.monkey" + +Audio::Tfmx *loadTfmxfile(const char *mdatName, const char *sampleName) { + FSNode fileDir(FILEDIR); + FSNode musicNode = fileDir.getChild(mdatName); + FSNode sampleNode = fileDir.getChild(sampleName); + SeekableReadStream *musicIn = musicNode.createReadStream(); + if (0 == musicIn) { + debug("Couldnt load file %s", MUSICFILE); + return 0; + } + + SeekableReadStream *sampleIn = sampleNode.createReadStream(); + if (0 == sampleIn) { + debug("Couldnt load file %s", SAMPLEFILE); + delete musicIn; + return 0; + } + + Audio::Tfmx *player = new Audio::Tfmx(44100, true); + player->load(*musicIn, *sampleIn); + delete musicIn; + delete sampleIn; + + return player; +} + +void runFlac(int chan, int bits, int sr, const char *fileName); + +void tfmxmain(const int argc, const char *const argv[]) { + debug("Started Scumm&VM"); + debug("Sound celebrating utility for monkey melodies & Various Malfunctions"); + debug(""); + + //simplePlaybacktest(argc, argv); + + Audio::Tfmx *player = loadTfmxfile(MUSICFILE, SAMPLEFILE); + if (!player) { + debug("couldnt create TFMX-Player"); + return; + } + + int i = 1; + int playflag = 1; + bool hasCmd = false; + + + while (i < argc && argv[i][0] == '-') { + int param; + if (!strcmp("-m", argv[i])) { + if (i + 1 < argc) { + param = atoi(argv[++i]); + debug( "play Macro %02X", param); + dumpMacro(*player, param); + player->doMacro(0x1B, param); + hasCmd = true; + } + } else if (!strcmp("-s", argv[i])) { + if (i + 1 < argc) { + param = atoi(argv[++i]); + debug( "play Song %02X", param); + dumpTrackstepsBySong(*player, param); + player->doSong(param); + hasCmd = true; + } + } else if (!strcmp("-c", argv[i])) { + if (i + 1 < argc) { + param = atoi(argv[++i]); + debug( "play custom %02X", param); + if (player->getSongIndex() < 0) + player->doSong(0x18); + player->doSfx(param); + hasCmd = true; + } + } else if (!strcmp("-flac", argv[i])) { + playflag = 2; + } else if (!strcmp("-hack-patternstop", argv[i])) + player->_playerCtx.stopWithLastPattern = true; + ++i; + } + + if (!hasCmd) { + player->doSong(4); + dumpTrackstepsBySong(*player, 4); + } + + + + +#if 0 + int16 buf[2 * 1024]; + + while( true) + player->readBuffer(buf, ARRAYSIZE(buf)); +#endif + int maxsecs = 10 * 60; + if (playflag == 1) { + // get Mixer, assume this never fails + Audio::Mixer *mixer = g_system->getMixer(); + + Audio::SoundHandle soundH; + + mixer->playInputStream(Audio::Mixer::kMusicSoundType, &soundH, player); + while (mixer->isSoundHandleActive(soundH) && --maxsecs) + g_system->delayMillis(1000); +// player->AllOff(); + +// while (mixer->isSoundHandleActive(soundH)); + + mixer->stopHandle(soundH); + player = 0; + } + + if (playflag == 2) { + Common::FSNode file("out.raw"); + WriteStream *wav = file.createWriteStream(); + int16 buf[2 * 1024]; + int32 maxsamples = (maxsecs <= 0) ? 0 : maxsecs * 44100; + while (!player->endOfData() && maxsamples > 0) { + int read = player->readBuffer(buf, ARRAYSIZE(buf)); + wav->write(buf, read * 2); + maxsamples -= read/2; + } + delete wav; + + runFlac(2, 16, 44100, "out.raw"); + } + +#ifdef _MSC_VER + printf("\npress a key"); + getc(stdin); +#endif + + delete player; +} + +void runFlac( int chan, int bits, int sr, const char *fileName) { + const char *format = "flac --endian=" +#ifdef SCUMM_BIG_ENDIAN + "big" +#else + "little" +#endif + " --channels=%d -f --bps=%d --sample-rate=%d --sign=signed --force-raw-format %s"; + char cmd[1024]; + sprintf(cmd, format, chan, bits, sr, fileName); + debug(cmd); + system(cmd); +} + + |