Supermodel/Src/Model3/SoundBoard.cpp
Nik Henson 5e247021be Changes relating to input system:
- Fixed bug with mapping of multiple assignments.
- Added new ! operator for input mappings, which lets the user specify that an input must not be active.
- Added option to print info about input system (such as settings and detected keyboards, mice and joysticks) during input configuration.
- Added new trigger input for lightgun games with a configurable option to automatically pull trigger when offscreen input is activated (this makes playing with the mouse easier as the gun can be reloaded with single mouse button, rather than having to press both
 buttons at the same time).
- Added -xinput command line option that switches to using XInput API rather than DirectInput for XBox 360 controllers (this allows the XBox 360 controller's two triggers to be read independently which works better for driving games when they are mapped to accele
rator and brake).
- Added initial version of force feedback implementation to DirectInputSystem (this still needs work).
2011-06-05 20:53:39 +00:00

381 lines
11 KiB
C++

/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski
**
** This file is part of Supermodel.
**
** Supermodel 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 3 of the License, or (at your option)
** any later version.
**
** Supermodel 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 Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* SoundBoard.cpp
*
* Model 3 sound board. Implementation of the CSoundBoard class. This class can
* only be instantiated once because it relies on global variables (the non-OOP
* 68K core).
*/
#include "Supermodel.h"
//TEMP: these need to be dynamically allocated in the memory pool
static INT16 leftBuffer[44100/60],rightBuffer[44100/60];
static FILE *soundFP;
/******************************************************************************
Global 68K Access Handlers
The 68K must interface with globally-accessible memory maps and access
handlers. Turbo68K uses the __cdecl calling convention. Note that this is not
explicitly defined for the Turbo68K functions themselves but in case Turbo68K
crashes, this may be the culprit.
******************************************************************************/
// Prototypes for access handlers
static UINT8 __cdecl UnknownRead8(UINT32);
static UINT16 __cdecl UnknownRead16(UINT32);
static UINT32 __cdecl UnknownRead32(UINT32);
static void __cdecl UnknownWrite8(UINT32, UINT8);
static void __cdecl UnknownWrite16(UINT32, UINT16);
static void __cdecl UnknownWrite32(UINT32, UINT32);
// Memory maps for 68K
#ifdef SUPERMODEL_SOUND
struct TURBO68K_FETCHREGION mapFetch[] =
{
{ 0x000000, 0x0FFFFF, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL }, // SCSP2 RAM
{ 0x600000, 0x67FFFF, NULL }, // program ROM
{ -1, -1, NULL }
};
struct TURBO68K_DATAREGION mapRead8[] =
{
{ 0x000000, 0x0FFFFF, NULL, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL, NULL }, // SCSP2 RAM
{ 0x600000, 0x67FFFF, NULL, NULL }, // program ROM
{ 0x800000, 0x9FFFFF, NULL, NULL }, // sample ROM (low 2 MB)
{ 0xA00000, 0xDFFFFF, NULL, NULL }, // sample ROM (bank)
{ 0xE00000, 0xFFFFFF, NULL, NULL }, // sample ROM (bank)
{ 0x100000, 0x10FFFF, NULL, SCSP_Master_r8 },
{ 0x300000, 0x30FFFF, NULL, SCSP_Slave_r8 },
{ 0x000000, 0xFFFFFF, NULL, UnknownRead8 },
{ -1, -1, NULL, NULL }
};
struct TURBO68K_DATAREGION mapRead16[] =
{
{ 0x000000, 0x0FFFFF, NULL, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL, NULL }, // SCSP2 RAM
{ 0x600000, 0x67FFFF, NULL, NULL }, // program ROM
{ 0x800000, 0x9FFFFF, NULL, NULL }, // sample ROM (low 2 MB)
{ 0xA00000, 0xDFFFFF, NULL, NULL }, // sample ROM (bank)
{ 0xE00000, 0xFFFFFF, NULL, NULL }, // sample ROM (bank)
{ 0x100000, 0x10FFFF, NULL, SCSP_Master_r16 },
{ 0x300000, 0x30FFFF, NULL, SCSP_Slave_r16 },
{ 0x000000, 0xFFFFFF, NULL, UnknownRead16 },
{ -1, -1, NULL, NULL }
};
struct TURBO68K_DATAREGION mapRead32[] =
{
{ 0x000000, 0x0FFFFF, NULL, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL, NULL }, // SCSP2 RAM
{ 0x600000, 0x67FFFF, NULL, NULL }, // program ROM
{ 0x800000, 0x9FFFFF, NULL, NULL }, // sample ROM (low 2 MB)
{ 0xA00000, 0xDFFFFF, NULL, NULL }, // sample ROM (bank)
{ 0xE00000, 0xFFFFFF, NULL, NULL }, // sample ROM (bank)
{ 0x100000, 0x10FFFF, NULL, SCSP_Master_r32 },
{ 0x300000, 0x30FFFF, NULL, SCSP_Slave_r32 },
{ 0x000000, 0xFFFFFF, NULL, UnknownRead32 },
{ -1, -1, NULL, NULL }
};
struct TURBO68K_DATAREGION mapWrite8[] =
{
{ 0x000000, 0x0FFFFF, NULL, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL, NULL }, // SCSP2 RAM
{ 0x100000, 0x10FFFF, NULL, SCSP_Master_w8 },
{ 0x300000, 0x30FFFF, NULL, SCSP_Slave_w8 },
{ 0x000000, 0xFFFFFF, NULL, UnknownWrite8 },
{ -1, -1, NULL, NULL }
};
struct TURBO68K_DATAREGION mapWrite16[] =
{
{ 0x000000, 0x0FFFFF, NULL, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL, NULL }, // SCSP2 RAM
{ 0x100000, 0x10FFFF, NULL, SCSP_Master_w16 },
{ 0x300000, 0x30FFFF, NULL, SCSP_Slave_w16 },
{ 0x000000, 0xFFFFFF, NULL, UnknownWrite16 },
{ -1, -1, NULL, NULL }
};
struct TURBO68K_DATAREGION mapWrite32[] =
{
{ 0x000000, 0x0FFFFF, NULL, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL, NULL }, // SCSP2 RAM
{ 0x100000, 0x10FFFF, NULL, SCSP_Master_w32 },
{ 0x300000, 0x30FFFF, NULL, SCSP_Slave_w32 },
{ 0x000000, 0xFFFFFF, NULL, UnknownWrite32 },
{ -1, -1, NULL, NULL }
};
#endif
static UINT8 __cdecl UnknownRead8(UINT32 addr)
{
printf("68K read from %06X (byte)\n", addr);
return 0;
}
static UINT16 __cdecl UnknownRead16(UINT32 addr)
{
printf("68K read from %06X (word)\n", addr);
return 0;
}
static UINT32 __cdecl UnknownRead32(UINT32 addr)
{
printf("68K read from %06X (longword)\n", addr);
return 0;
}
static void __cdecl UnknownWrite8(UINT32 addr, UINT8 data)
{
printf("68K wrote %06X=%02X\n", addr, data);
}
static void __cdecl UnknownWrite16(UINT32 addr, UINT16 data)
{
printf("68K wrote %06X=%04X\n", addr, data);
}
static void __cdecl UnknownWrite32(UINT32 addr, UINT32 data)
{
printf("68K wrote %06X=%08X\n", addr, data);
}
/******************************************************************************
Emulation Functions
******************************************************************************/
int irqLine = 0;
// SCSP callback for generating IRQs
void SCSP68KIRQCallback(int irqNum)
{
#ifdef SUPERMODEL_SOUND
//printf("IRQ: %d\n", irqNum);
irqLine = irqNum;
//Turbo68KInterrupt(irqNum, TURBO68K_AUTOVECTOR);
#endif
}
// SCSP callback for running the 68K
int SCSP68KRunCallback(int numCycles)
{
#ifdef SUPERMODEL_SOUND
for (int i = 0; i < numCycles; i++)
{
if (irqLine)
Turbo68KInterrupt(irqLine,TURBO68K_AUTOVECTOR);
Turbo68KRun(1);
}
return numCycles;
//Turbo68KRun(numCycles);
//return Turbo68KGetElapsedCycles();
#else
return numCycles;
#endif
}
void CSoundBoard::WriteMIDIPort(UINT8 data)
{
#ifdef SUPERMODEL_SOUND
SCSP_MidiIn(data);
#endif
}
void CSoundBoard::RunFrame(void)
{
#ifdef SUPERMODEL_SOUND
SCSP_Update();
// Output to binary file
INT16 s;
for (int i = 0; i < 44100/60; i++)
{
s = ((UINT16)leftBuffer[i]>>8) | ((leftBuffer[i]&0xFF)<<8);
fwrite(&s, sizeof(INT16), 1, soundFP); // left channel
s = ((UINT16)rightBuffer[i]>>8) | ((rightBuffer[i]&0xFF)<<8);
fwrite(&s, sizeof(INT16), 1, soundFP); // right channel
}
#endif
}
void CSoundBoard::Reset(void)
{
#ifdef SUPERMODEL_SOUND
memcpy(ram1, soundROM, 16); // copy 68K vector table
Turbo68KReset();
/*
printf("68K PC=%06X\n", Turbo68KReadPC());
for (int i = 0; i < 1000000; i++)
{
//printf("%06X\n", Turbo68KReadPC());
Turbo68KRun(1);
}
*/
#endif
DebugLog("Sound Board Reset\n");
}
/******************************************************************************
Configuration, Initialization, and Shutdown
******************************************************************************/
// Offsets of memory regions within sound board's pool
#define OFFSET_RAM1 0 // 1 MB SCSP1 RAM
#define OFFSET_RAM2 0x100000 // 1 MB SCSP2 RAM
#define MEMORY_POOL_SIZE (0x100000+0x100000)
BOOL CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr, CIRQ *ppcIRQObjectPtr, unsigned soundIRQBit)
{
#ifdef SUPERMODEL_SOUND
float memSizeMB = (float)MEMORY_POOL_SIZE/(float)0x100000;
// Attach IRQ controller
ppcIRQ = ppcIRQObjectPtr;
ppcSoundIRQBit = soundIRQBit;
// Receive sound ROMs
soundROM = soundROMPtr;
sampleROM = sampleROMPtr;
// Allocate all memory for RAM
memoryPool = new(std::nothrow) UINT8[MEMORY_POOL_SIZE];
if (NULL == memoryPool)
return ErrorLog("Insufficient memory for sound board (needs %1.1f MB).", memSizeMB);
memset(memoryPool, 0, MEMORY_POOL_SIZE);
// Set up memory pointers
ram1 = &memoryPool[OFFSET_RAM1];
ram2 = &memoryPool[OFFSET_RAM2];
// Initialize 68K core
mapFetch[0].ptr = mapRead8[0].ptr = mapRead16[0].ptr = mapRead32[0].ptr =
mapWrite8[0].ptr = mapWrite16[0].ptr = mapWrite32[0].ptr = (UINT32)ram1 - mapFetch[0].base;;
mapFetch[1].ptr = mapRead8[1].ptr = mapRead16[1].ptr = mapRead32[1].ptr =
mapWrite8[1].ptr = mapWrite16[1].ptr = mapWrite32[1].ptr = (UINT32)ram2 - mapFetch[1].base;
mapFetch[2].ptr = mapRead8[2].ptr = mapRead16[2].ptr = mapRead32[2].ptr = (UINT32)soundROM - mapFetch[2].base;
mapRead8[3].ptr = mapRead16[3].ptr = mapRead32[3].ptr = (UINT32)&sampleROM[0x000000] - mapRead8[3].base;
mapRead8[4].ptr = mapRead16[4].ptr = mapRead32[4].ptr = (UINT32)&sampleROM[0x200000] - mapRead8[4].base;
mapRead8[5].ptr = mapRead16[5].ptr = mapRead32[5].ptr = (UINT32)&sampleROM[0x600000] - mapRead8[5].base;
Turbo68KInit();
Turbo68KSetFetch(mapFetch, NULL);
Turbo68KSetReadByte(mapRead8, NULL);
Turbo68KSetReadWord(mapRead16, NULL);
Turbo68KSetReadLong(mapRead32, NULL);
Turbo68KSetWriteByte(mapWrite8, NULL);
Turbo68KSetWriteWord(mapWrite16, NULL);
Turbo68KSetWriteLong(mapWrite32, NULL);
// Initialize SCSPs
SCSP_SetBuffers(leftBuffer, rightBuffer, 44100/60);
SCSP_SetCB(SCSP68KRunCallback, SCSP68KIRQCallback, ppcIRQ, ppcSoundIRQBit);
SCSP_Init(2);
SCSP_SetRAM(0, ram1);
SCSP_SetRAM(1, ram2);
// Binary logging
soundFP = fopen("sound.bin","wb"); // delete existing file
fclose(soundFP);
soundFP = fopen("sound.bin","ab"); // append mode
#endif
return OKAY;
}
CSoundBoard::CSoundBoard(void)
{
memoryPool = NULL;
ram1 = NULL;
ram2 = NULL;
DebugLog("Built Sound Board\n");
}
static void Reverse16(UINT8 *buf, unsigned size)
{
unsigned i;
UINT8 tmp;
for (i = 0; i < size; i += 2)
{
tmp = buf[i+0];
buf[i+0] = buf[i+1];
buf[i+1] = tmp;
}
}
CSoundBoard::~CSoundBoard(void)
{
#ifdef SUPERMODEL_SOUND
// close binary log file
fclose(soundFP);
//#if 0
FILE *fp;
Reverse16(ram1, 0x100000);
Reverse16(ram2, 0x100000);
fp = fopen("scspRAM1", "wb");
if (NULL != fp)
{
fwrite(ram1, sizeof(UINT8), 0x100000, fp);
fclose(fp);
printf("dumped %s\n", "scspRAM1");
}
fp = fopen("scspRAM2", "wb");
if (NULL != fp)
{
fwrite(ram2, sizeof(UINT8), 0x100000, fp);
fclose(fp);
printf("dumped %s\n", "scspRAM2");
}
//#endif
SCSP_Deinit();
if (memoryPool != NULL)
{
delete [] memoryPool;
memoryPool = NULL;
}
ram1 = NULL;
ram2 = NULL;
#endif
DebugLog("Destroyed Sound Board\n");
}