daedalus/Source/HLEAudio/main.cpp
2021-12-11 12:55:43 +11:00

359 lines
8.7 KiB
C++

/****************************************************************************
* *
* Azimer's HLE Audio Plugin for Project64 Compatible N64 Emulators *
* http://www.apollo64.com/ *
* Copyright (C) 2000-2019 Azimer. All rights reserved. *
* *
* License: *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
* *
****************************************************************************/
#include "common.h"
#include "AudioSpec.h"
#include "SoundDriverInterface.h"
#include "SoundDriverFactory.h"
#include "audiohle.h"
//#include "rsp/rsp.h"
#include <string.h> // memcpy(), strcpy()
#include <stdio.h> // needed for configuration
#ifdef USE_PRINTF
#include <io.h>
#include <fcntl.h>
#include <ios>
using namespace std;
#endif
SoundDriverInterface *snd = NULL;
bool ai_delayed_carry; // Borrowed from MAME and Mupen64Plus
bool bBackendChanged = false;
void SetTimerResolution(void);
#ifdef USE_PRINTF
void RedirectIOToConsole();
#endif
HINSTANCE hInstance;
#ifdef __GNUC__
extern "C"
#endif
#ifdef _WIN32
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved // reserved
) {
UNREFERENCED_PARAMETER(lpvReserved);
UNREFERENCED_PARAMETER(fdwReason);
hInstance = hinstDLL;
return TRUE;
}
#endif
void DllAbout(HWND hParent) {
#if defined(_WIN32) || defined(_XBOX)
Configuration::AboutDialog(hParent);
#else
puts(PLUGIN_VERSION);
#endif
}
void DllConfig(HWND hParent)
{
#if defined(_WIN32) && !defined(_XBOX)
SoundDriverType currentDriver = Configuration::getDriver();
Configuration::ConfigDialog(hParent);
if (currentDriver != Configuration::getDriver())
{
bBackendChanged = true;
}
#else
fputs("To do: Implement saving configuration settings.\n", stderr);
#endif
}
void DllTest(HWND hParent) {
#if defined(_WIN32)
MessageBoxA(hParent, "Nothing to test yet... ", "Test Box", MB_OK);
#else
puts("DllTest");
#endif
}
// Initialization / Deinitalization Functions
// Note: We call CloseDLL just in case the audio plugin was already initialized...
AUDIO_INFO AudioInfo;
u32 Dacrate = 0;
//EXPORT Boolean CALL InitiateAudio(AUDIO_INFO Audio_Info) {
if (snd != NULL)
{
snd->AI_Shutdown();
delete snd;
}
#ifdef USE_PRINTF
RedirectIOToConsole();
DEBUG_OUTPUT("Logging to console enabled...\n");
#endif
Dacrate = 0;
//CloseDLL ();
if (Configuration::getResTimer() == true)
{
SetTimerResolution();
}
memcpy(&AudioInfo, &Audio_Info, sizeof(AUDIO_INFO));
DRAM = Audio_Info.RDRAM;
DMEM = Audio_Info.DMEM;
IMEM = Audio_Info.IMEM;
Configuration::LoadDefaults();
snd = SoundDriverFactory::CreateSoundDriver(Configuration::getDriver());
if (snd == NULL)
return FALSE;
snd->AI_Startup();
ai_delayed_carry = false;
return TRUE;
}
void CloseDLL(void) {
DEBUG_OUTPUT("Call: CloseDLL()\n");
if (snd != NULL)
{
snd->AI_Shutdown();
delete snd;
snd = NULL;
}
}
void GetDllInfo(PLUGIN_INFO * PluginInfo) {
PluginInfo->MemoryBswaped = TRUE;
PluginInfo->NormalMemory = FALSE;
safe_strcpy(PluginInfo->Name, 100, PLUGIN_VERSION);
PluginInfo->Type = PLUGIN_TYPE_AUDIO;
PluginInfo->Version = 0x0101; // Set this to retain backwards compatibility
}
void ProcessAList(void) {
if (snd == NULL)
return;
HLEStart ();
}
void RomOpen(void)
{
DEBUG_OUTPUT("Call: RomOpen()\n");
if (snd == NULL)
return;
//snd->AI_ResetAudio();
}
void RomClosed(void)
{
DEBUG_OUTPUT("Call: RomClosed()\n");
Dacrate = 0; // Forces a revisit to initialize audio
if (snd == NULL)
return;
if (bBackendChanged == true)
{
snd->AI_Shutdown();
delete snd;
snd = SoundDriverFactory::CreateSoundDriver(Configuration::getDriver());
snd->AI_Startup();
bBackendChanged = false;
}
else
{
snd->AI_ResetAudio();
}
}
void AiDacrateChanged(int SystemType) {
u32 Frequency, video_clock;
ai_delayed_carry = false;
DEBUG_OUTPUT("Call: AiDacrateChanged()\n");
if (snd == NULL)
return;
if (Dacrate == *AudioInfo.AI_DACRATE_REG)
return;
Dacrate = *AudioInfo.AI_DACRATE_REG & 0x00003FFF;
#ifdef _DEBUG
if (Dacrate != *AudioInfo.AI_DACRATE_REG)
MessageBoxA(
NULL,
"Unknown/reserved bits in AI_DACRATE_REG set.",
"Warning",
MB_ICONWARNING
);
#endif
switch (SystemType) {
default : assert(FALSE);
case SYSTEM_NTSC: video_clock = 48681812; break;
case SYSTEM_PAL : video_clock = 49656530; break;
case SYSTEM_MPAL: video_clock = 48628316; break;
}
Frequency = video_clock / (Dacrate + 1);
#if 1
if ((Frequency > 7000) && (Frequency < 9000))
Frequency = 8000;
else if ((Frequency > 10000) && (Frequency < 12000))
Frequency = 11025;
else if ((Frequency > 18000) && (Frequency < 20000))
Frequency = 19000;
else if ((Frequency > 21000) && (Frequency < 23000))
Frequency = 22050;
else if ((Frequency > 31000) && (Frequency < 33000))
Frequency = 32000;
else if ((Frequency > 43000) && (Frequency < 45000))
Frequency = 44100;
else if ((Frequency > 47000) && (Frequency < 49000))
Frequency = 48000;
else
DEBUG_OUTPUT("Unable to standardize Frequeny!\n");
#endif
DEBUG_OUTPUT("Frequency = %i\n", Frequency);
snd->AI_SetFrequency(Frequency);
}
void AiLenChanged(void)
{
u32 address = (*AudioInfo.AI_DRAM_ADDR_REG & 0x00FFFFF8);
u32 length = (*AudioInfo.AI_LEN_REG & 0x3FFF8);
if (snd == NULL)
return;
if (ai_delayed_carry)
address += 0x2000;
if (((address + length) & 0x1FFF) == 0)
ai_delayed_carry = true;
else
ai_delayed_carry = false;
snd->AI_LenChanged(AudioInfo.RDRAM + address, length);
}
u32 AiReadLength(void) {
if (snd == NULL)
return 0;
*AudioInfo.AI_LEN_REG = snd->AI_ReadLength();
return *AudioInfo.AI_LEN_REG;
}
void AiUpdate(Boolean Wait) {
static int intCount = 0;
if (snd == NULL)
{
#if defined(_WIN32) || defined(_XBOX)
Sleep(1);
#endif
return;
}
snd->AI_Update(Wait);
return;
}
int safe_strcpy(char* dst, size_t limit, const char* src)
{
#if defined(_MSC_VER) && !defined(_XBOX)
return strcpy_s(dst, limit, src);
#else
size_t bytes;
int failure;
if (dst == NULL || src == NULL)
return (failure = 22); /* EINVAL, from MSVC <errno.h> */
bytes = strlen(src) + 1; /* strlen("abc") + 1 == 4 bytes */
failure = 34; /* ERANGE, from MSVC <errno.h> */
if (bytes > limit)
bytes = limit;
else
failure = 0;
memcpy(dst, src, bytes);
dst[limit - 1] = '\0'; /* in case of ERANGE, may not be null-terminated */
return (failure);
#endif
}
#ifdef USE_PRINTF
static const WORD MAX_CONSOLE_LINES = 500;
void RedirectIOToConsole() {
#if !defined(_XBOX)
//int hConHandle;
//long lStdHandle;
//CONSOLE_SCREEN_BUFFER_INFO coninfo;
//FILE *fp;
// allocate a console for this app
FreeConsole();
if (!AllocConsole())
return;
freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
//// set the screen buffer to be big enough to let us scroll text
//GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
//coninfo.dwSize.Y = MAX_CONSOLE_LINES;
//SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
//// redirect unbuffered STDOUT to the console
//lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
//hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
//fp = _fdopen(hConHandle, "w");
//*stdout = *fp;
//setvbuf(stdout, NULL, _IONBF, 0);
//// redirect unbuffered STDIN to the console
//lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
//hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
//fp = _fdopen(hConHandle, "r");
//*stdin = *fp;
//setvbuf(stdin, NULL, _IONBF, 0);
//// redirect unbuffered STDERR to the console
//lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
//hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
//fp = _fdopen(hConHandle, "w");
//*stderr = *fp;
//setvbuf(stderr, NULL, _IONBF, 0);
//// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
//// point to console as well
//ios::sync_with_stdio();
#endif
}
#ifdef _WIN32
/*
Time resolution code borrowed from Project64-Audio
Will be set as an optional parameter
*/
void SetTimerResolution(void)
{
HMODULE hMod = GetModuleHandle("ntdll.dll");
if (hMod != NULL)
{
typedef LONG(NTAPI* tNtSetTimerResolution)(IN ULONG DesiredResolution, IN BOOLEAN SetResolution, OUT PULONG CurrentResolution);
tNtSetTimerResolution NtSetTimerResolution = (tNtSetTimerResolution)GetProcAddress(hMod, "NtSetTimerResolution");
ULONG CurrentResolution = 0;
NtSetTimerResolution(10000, TRUE, &CurrentResolution);
}
}
#endif
#endif