Apollo64/source/Audio.cpp
Azimer 94c848737e Misc Updates
Misc Updates from another repo
2023-07-31 10:51:50 -05:00

417 lines
No EOL
12 KiB
C++

/**************************************************************************
* *
* Copyright (C) 2000, Eclipse Productions *
* *
* Offical Source code of the Apollo Project. DO NOT DISTRIBUTE! Any *
* unauthorized distribution of these files in any way, shape, or form *
* is a direct infringement on the copyrights entitled to Eclipse *
* Productions and you will be prosecuted to the fullest extent of *
* the law. Have a nice day... ^_^ *
* *
*************************************************************************/
/**************************************************************************
*
* Revision History:
* Date: Comment:
* -----------------------------------------------------------------------
* 06-24-00 Initial Version (Andrew)
*
**************************************************************************/
/**************************************************************************
*
* Notes:
*
* -Designed to have the Audio interrupt fire at about the same time it
* would as if we were going at 60FPS. Also correctly emulates everything
* except for the LEN register, which I will have to verify. -KAH
*
**************************************************************************/
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h> // For status window
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <math.h>
#include "WinMain.h"
#include "EmuMain.h"
#include "resource.h"
#include "audiodll.h"
void ScheduleEvent (u32, u32, u32, void *);
#define AI_DMA_EVENT 0x5
#define AID_DMA_EVENT 0x7
extern u8* rdram;
extern u8* idmem;
extern u8* MI;
extern u8* AI;
// ****************** Testing Audio Stuff *****************
static u32 Frequency = 0;
static u32 Length = 0;
static u32 Status = 0;
static double CountsPerByte;
static u32 SecondBuff = 0;
static u32 CurrentCount;
static u32 CurrentLength;
static u32 IntScheduled = 0;
extern u32 VsyncTiming; // Need this so I can time things to VSync...
void AiInterrupt () {
if (SecondBuff != 0) {
IntScheduled = (u32)((double)SecondBuff * CountsPerByte);
ScheduleEvent (AID_DMA_EVENT, IntScheduled, 0, NULL);
} else {
Status &= ~0x40000000;
}
CurrentCount = MmuRegs[9];
CurrentLength = SecondBuff;
SecondBuff = 0;
Status &= 0x7FFFFFFF;
}
void AiCallBack () {
if (SecondBuff == 0)
Status &= 0x7FFFFFFF;
}
u32 GetLength () {
double AiCounts = CountsPerByte * CurrentLength;
AiCounts = AiCounts - (double)(MmuRegs[9] - CurrentCount);
if (AiCounts < 0)
return 0;
return (u32)(AiCounts/CountsPerByte);
//return 0;
}
u32 GetStatus () {
return Status;
//return 0;
}
void SetLength (u32 data) {
u32 CountCycles;
// Set Status to FULL for a few COUNT cycles
if (CurrentLength == 0) {
CurrentLength = data;
CurrentCount = MmuRegs[9];
IntScheduled = (u32)((double)data * CountsPerByte);
ScheduleEvent (AID_DMA_EVENT, IntScheduled, 0, NULL);
} else {
SecondBuff = data;
Status |= 0x80000000;
// ScheduleEvent (AI_DMA_EVENT, 20, 0, NULL);
}
Status |= 0x40000000;
((DWORD *)AI)[1] = data;
snddll.AiLenChanged ();
}
void SetFrequency (u32 data) {
u32 CountsPerSecond;
Frequency = data;
Frequency = (Frequency * 4); // This makes it Bytes Per Second...
CountsPerSecond = 789000.0 * (float)60.0; // This will only work with NTSC...
CountsPerByte = (double)CountsPerSecond / (double)Frequency;
}
// ****************** Interfacing for the Controller plugin ****************************
AUDIODLL snddll;
void SignalAiDone(void);
static bool LoadFunctions () {
snddll.CloseDLL = (void (__cdecl*)( void )) GetProcAddress(snddll.hinstLibAudio, "CloseDLL");
snddll.DllAbout = (void (__cdecl*)( HWND )) GetProcAddress(snddll.hinstLibAudio, "DllAbout");
snddll.DllConfig = (void (__cdecl*)( HWND )) GetProcAddress(snddll.hinstLibAudio, "DllConfig");
snddll.DllTest = (void (__cdecl*)( HWND )) GetProcAddress(snddll.hinstLibAudio, "DllTest");
snddll.ProcessAList = (void (__cdecl*)( void )) GetProcAddress(snddll.hinstLibAudio, "ProcessAList");
snddll.RomClosed = (void (__cdecl*)( void )) GetProcAddress(snddll.hinstLibAudio, "RomClosed");
snddll.InitiateAudio = (BOOL (__cdecl*)( AUDIO_INFO )) GetProcAddress(snddll.hinstLibAudio, "InitiateAudio");
snddll.GetDllInfo = (void (__cdecl*)( PLUGIN_INFO * )) GetProcAddress(snddll.hinstLibAudio, "GetDllInfo");
snddll.AiDacrateChanged = (void (__cdecl*)( int )) GetProcAddress(snddll.hinstLibAudio, "AiDacrateChanged");
snddll.AiLenChanged = (void (__cdecl*)( void )) GetProcAddress(snddll.hinstLibAudio, "AiLenChanged");
snddll.AiReadLength = (DWORD (__cdecl*)( void )) GetProcAddress(snddll.hinstLibAudio, "AiReadLength");
snddll.AiUpdate = (void (__cdecl*)( BOOL )) GetProcAddress(snddll.hinstLibAudio, "AiUpdate");
return true;
}
void CloseAudioPlugin () {
if(snddll.CloseDLL)
snddll.CloseDLL();
if(snddll.hinstLibAudio)
FreeLibrary(snddll.hinstLibAudio);
ZeroMemory (&snddll, sizeof(AUDIODLL));
}
BOOL LoadAudioPlugin (char *libname) {
PLUGIN_INFO Plugin_Info;
ZeroMemory (&Plugin_Info, sizeof(Plugin_Info));
if (libname == NULL) {
return FALSE;
}
if (snddll.hinstLibAudio != NULL)
snddll.Close ();
snddll.hinstLibAudio = LoadLibrary(libname);
if (snddll.hinstLibAudio == NULL) {
Debug (0, "Could not load %s because it couldn't be found!", libname);
snddll.Close();
return FALSE;
}
snddll.GetDllInfo = (void (__cdecl*)(PLUGIN_INFO *)) GetProcAddress(snddll.hinstLibAudio, "GetDllInfo");
if(!snddll.GetDllInfo) {
Debug (0, "%s does not conform to the plugin spec.", libname);
return FALSE;//This isn't a plugin dll, so don't bother.
}
snddll.GetDllInfo(&Plugin_Info);
if(Plugin_Info.Type == PLUGIN_TYPE_AUDIO) {
if(Plugin_Info.Version > PLUGIN_SND_VERSION) {
Debug (0, "%s is not compatable with Apollo. %X != %X", libname, Plugin_Info.Version, PLUGIN_INP_VERSION);
snddll.Close();
return FALSE;
}
if (LoadFunctions () == false) {
snddll.Close();
return FALSE;
}
} else {
//Here we insert Audio code, controller code, etc.
Debug (0, "%s dll isn't an Audio plugin!", libname);
snddll.Close();
return FALSE;
}
return TRUE;
}
AUDIO_INFO SndInfo; // make it stay just in case the evil plugin doesn't store a local copy
u32 DummyReg;
static u32 FakeReg;
void InitSNDPlugin () {
ZeroMemory (&SndInfo, sizeof(AUDIO_INFO));
SndInfo.hwnd = GhWnd;
SndInfo.hinst = GhInst;
SndInfo.MemoryBswaped = TRUE;
SndInfo.HEADER = RomMemory;
SndInfo.RDRAM = rdram;
SndInfo.DMEM = idmem;
SndInfo.IMEM = (idmem+0x1000);
SndInfo.AI_DRAM_ADDR_REG = (u32 *)(AI+0x00);
SndInfo.AI_LEN_REG = (u32 *)(AI+0x04);
SndInfo.AI_CONTROL_REG = (u32 *)(AI+0x08);
SndInfo.AI_STATUS_REG = (u32 *)&FakeReg;//(AI+0x0C);
SndInfo.AI_DACRATE_REG = (u32 *)(AI+0x10);
SndInfo.AI_BITRATE_REG = (u32 *)(AI+0x14);
SndInfo.MI_INTR_REG = (u32 *)&FakeReg;//(MI+0x08);
SndInfo.CheckInterrupts = SignalAiDone;
if (snddll.InitiateAudio (SndInfo) == FALSE) {
CloseAudioPlugin ();
Debug (0, "Plugin Initialization Failed.");
}
}
void SignalAiDone(void) {
//*SndInfo.AI_STATUS_REG |= 0x80000001;
//ScheduleEvent (AI_DMA_EVENT, 200, 0, NULL);
//if ((((u32*)MI)[3] & (((u32*)MI)[2])) & AI_INTERRUPT)
//((u32*)MI)[3] |= AI_INTERRUPT;
//((u32*)MI)[2] |= AI_INTERRUPT;
//InterruptNeeded |= AI_INTERRUPT;
//Debug (0, "Audio Interrupt");
}
// ******************** END AUDIO STUFF **********************
/*
u32 AI_second_delay = 0;
//#define ENABLEWAVE // Enabled wave logging
#ifdef ENABLEWAVE
bool Logging = false;
FILE* audio = NULL;
bool MemoryBswaped = true;
#define FREQ 44100
#define BPS 16
#define SEGMENTS 4
#define LOCK_SIZE (FREQ / 60) // Always 8bit mono (For the time being...)
static WAVEFORMATEX wfx;
struct WAVEFILEFORMAT {
char riff[4];
DWORD filesize;
char wavefmt[8];
DWORD fmtlength;
WAVEFORMAT wfx;
WORD bps;
char data[4];
DWORD datasize;
} wave;
void Soundmemcpy(void * dest, const void * src, size_t count);
void CloseWave () {
wave.filesize = ftell (audio);
fseek (audio, 0, SEEK_SET);
fwrite (&wave, 1, sizeof(WAVEFILEFORMAT), audio);
fclose (audio);
}
void LogWave (void *sndptr, DWORD sndlen, u32 freq) {
unsigned char buffer[262144];
if (audio == NULL) {
audio = fopen("C:\\audio.wav","wb");
if (audio == NULL) {
Logging = false;
return;
}
ZeroMemory (&wfx, sizeof(WAVEFORMATEX));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = freq;//22050;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
atexit (CloseWave);
strcpy ((char *)wave.riff, "RIFF ");
strcpy ((char *)wave.wavefmt, "WAVEfmt ");
strcpy ((char *)wave.data, "data ");
memcpy (&wave.wfx, &wfx, sizeof(WAVEFORMAT));
wave.fmtlength = sizeof(WAVEFORMAT)+2;
wave.bps = wfx.wBitsPerSample;
wave.filesize = 0;
wave.datasize = 0;
fwrite (&wave, 1, sizeof(WAVEFILEFORMAT), audio);
//MessageBox (NULL, "This should only come up once", "AUDIO", MB_OK);
Debug (0, "Logging Audio...");
}
Soundmemcpy (buffer, sndptr, sndlen);
fwrite(buffer, 1, sndlen, audio);
wave.datasize += sndlen;
}
#endif
void SignalAI(void) {
extern u8* AI;
extern u32 AiInterrupt;
extern u32 CountInterrupt, VsyncInterrupt, VsyncTime;
u32 dacRate = 49152000/(((u32*)AI)[4]+1); //NTSC conversion
float seconds = ((float)((u32*)AI)[1]/dacRate)/2;//div2 because of it being stereo
if (((u32*)AI)[5]==15) seconds /=2;
//Debug(0,"status%08X len%X rate%i freq%u seconds%2.2f, counter%X",((u32*)AI)[3],((u32*)AI)[1],((u32*)AI)[5]+1,dacRate,seconds,(u32)(seconds*625000*60));
#ifdef ENABLEWAVE
if (Logging == true)
LogWave (returnMemPointer(((u32*)AI)[0]), ((u32*)AI)[1], dacRate);
#endif
//fwrite(returnMemPointer(((u32*)AI)[0]),((u32*)AI)[1],1,audio);
//fclose(audio);
if (((u32*)AI)[3] & 1) {
AI_second_delay = (u32)(seconds*625000*60);
}
AiInterrupt = instructions + (u32)(seconds*625000*60);
VsyncTime = MIN(MIN(CountInterrupt,AiInterrupt),VsyncInterrupt);
}
void SignalAiDone(void) {
extern u8* AI;
extern u32 AiInterrupt;
if (((u32*)AI)[3] & 1) {//second sound in queue...unset full status, set interrupt, and redo AiInterrupt
((u32*)AI)[3] = 0x40000000;
InterruptNeeded |= AI_INTERRUPT;
AiInterrupt = AI_second_delay + instructions;
} else {//only one sound in queue...unset busy
((u32*)AI)[3] = 0;
AiInterrupt = -1;
((u32*)AI)[1] = 0;
((u32*)AI)[0] = 0;
}
}
#ifdef ENABLEWAVE
void Soundmemcpy(void * dest, const void * src, size_t count) {
if (MemoryBswaped) {
_asm {
mov edi, dest
mov ecx, src
mov edx, 0
push ebx
push edi
memcpyloop1:
mov ax, word ptr [ecx + edx]
mov bx, word ptr [ecx + edx + 2]
mov word ptr [edi + edx + 2],ax
mov word ptr [edi + edx],bx
add edx, 4
mov ax, word ptr [ecx + edx]
mov bx, word ptr [ecx + edx + 2]
mov word ptr [edi + edx + 2],ax
mov word ptr [edi + edx],bx
add edx, 4
cmp edx, count
jb memcpyloop1
pop edi
pop ebx
}
} else {
_asm {
mov edi, dest
mov ecx, src
mov edx, 0
memcpyloop2:
mov ax, word ptr [ecx + edx]
xchg ah,al
mov word ptr [edi + edx],ax
add edx, 2
mov ax, word ptr [ecx + edx]
xchg ah,al
mov word ptr [edi + edx],ax
add edx, 2
mov ax, word ptr [ecx + edx]
xchg ah,al
mov word ptr [edi + edx],ax
add edx, 2
mov ax, word ptr [ecx + edx]
xchg ah,al
mov word ptr [edi + edx],ax
add edx, 2
cmp edx, count
jb memcpyloop2
}
}
}
#endif
*/