Refactor Mockingboard into a class (#1171)
Mockingboard or Phasor cards can be inserted into any slot. Change Config->Sound to that slots 4+5 to be individually selected for the 3 soundcard types. Add MockingboardCardManager class to manage multiple cards and mix the sound buffers.
This commit is contained in:
parent
4668718fb3
commit
71c67cf132
|
@ -91,6 +91,8 @@
|
|||
<ClInclude Include="source\Log.h" />
|
||||
<ClInclude Include="source\Memory.h" />
|
||||
<ClInclude Include="source\Mockingboard.h" />
|
||||
<ClInclude Include="source\MockingboardCardManager.h" />
|
||||
<ClInclude Include="source\MockingboardDefs.h" />
|
||||
<ClInclude Include="source\MouseInterface.h" />
|
||||
<ClInclude Include="source\NoSlotClock.h" />
|
||||
<ClInclude Include="source\NTSC.h" />
|
||||
|
@ -176,6 +178,7 @@
|
|||
<ClCompile Include="source\Disk2CardManager.cpp" />
|
||||
<ClCompile Include="source\FourPlay.cpp" />
|
||||
<ClCompile Include="source\FrameBase.cpp" />
|
||||
<ClCompile Include="source\MockingboardCardManager.cpp" />
|
||||
<ClCompile Include="source\RGBMonitor.cpp" />
|
||||
<ClCompile Include="source\SAM.cpp" />
|
||||
<ClCompile Include="source\Debugger\Debug.cpp" />
|
||||
|
|
|
@ -271,6 +271,9 @@
|
|||
<ClCompile Include="source\CopyProtectionDongles.cpp">
|
||||
<Filter>Source Files\Emulator</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\MockingboardCardManager.cpp">
|
||||
<Filter>Source Files\Emulator</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="source\CommonVICE\6510core.h">
|
||||
|
@ -615,6 +618,12 @@
|
|||
<ClInclude Include="source\CopyProtectionDongles.h">
|
||||
<Filter>Source Files\Emulator</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="source\MockingboardCardManager.h">
|
||||
<Filter>Source Files\Emulator</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="source\MockingboardDefs.h">
|
||||
<Filter>Source Files\Emulator</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="resource\Applewin.bmp">
|
||||
|
|
|
@ -168,10 +168,10 @@ BEGIN
|
|||
LTEXT "&Mockingboard:",IDC_STATIC,49,39,51,8
|
||||
CONTROL "Slider1",IDC_MB_VOLUME,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | WS_TABSTOP,59,47,25,60
|
||||
GROUPBOX "Sound Cards",IDC_STATIC,6,122,197,64
|
||||
CONTROL "Mockingboards (in slots 4 && 5)",IDC_MB_ENABLE,"Button",BS_AUTORADIOBUTTON,10,136,142,8
|
||||
CONTROL "Phasor (in slot 4)",IDC_PHASOR_ENABLE,"Button",BS_AUTORADIOBUTTON,10,149,92,10
|
||||
CONTROL "SAM/DAC (in slot 5)",IDC_SAM_ENABLE,"Button",BS_AUTORADIOBUTTON,10,162,95,10
|
||||
CONTROL "No sound cards",IDC_SOUNDCARD_DISABLE,"Button",BS_AUTORADIOBUTTON,10,175,78,10
|
||||
LTEXT "Slot &4:",IDC_STATIC,16,136,84,10
|
||||
COMBOBOX IDC_SOUNDCARD_SLOT4,45,134,100,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "Slot &5:",IDC_STATIC,16,152,82,10
|
||||
COMBOBOX IDC_SOUNDCARD_SLOT5,45,150,100,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
END
|
||||
|
||||
IDD_PROPPAGE_DISK DIALOGEX 0, 0, 210, 240
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#define IDR_APPLE2_PLUS_ROM 127
|
||||
#define IDR_APPLE2E_ROM 128
|
||||
#define IDR_APPLE2E_ENHANCED_ROM 129
|
||||
#define IDC_MB_ENABLE 130
|
||||
#define IDD_TFE_SETTINGS_DIALOG 131
|
||||
#define IDR_PRINTDRVR_FW 132
|
||||
#define IDD_PROPPAGE_ADVANCED 132
|
||||
|
@ -68,9 +67,8 @@
|
|||
#define IDC_PASTE_FROM_CLIPBOARD 1023
|
||||
#define IDC_SPIN_XTRIM 1026
|
||||
#define IDC_SPIN_YTRIM 1027
|
||||
#define IDC_PHASOR_ENABLE 1029
|
||||
#define IDC_SAM_ENABLE 1030
|
||||
#define IDC_SOUNDCARD_DISABLE 1031
|
||||
#define IDC_SOUNDCARD_SLOT4 1028
|
||||
#define IDC_SOUNDCARD_SLOT5 1029
|
||||
#define IDC_TFE_SETTINGS_ENABLE_T 1032
|
||||
#define IDC_TFE_SETTINGS_ENABLE 1033
|
||||
#define IDC_TFE_SETTINGS_INTERFACE_T 1034
|
||||
|
|
|
@ -29,6 +29,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
#include "StdAfx.h"
|
||||
|
||||
#include "6522.h"
|
||||
#include "CardManager.h"
|
||||
#include "Mockingboard.h"
|
||||
#include "Core.h"
|
||||
#include "CPU.h"
|
||||
#include "Memory.h"
|
||||
|
@ -115,8 +117,6 @@ USHORT SY6522::SetTimerSyncEvent(BYTE reg, USHORT timerLatch)
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
extern void MB_UpdateIRQ(void);
|
||||
|
||||
void SY6522::UpdateIFR(BYTE clr_ifr, BYTE set_ifr /*= 0*/)
|
||||
{
|
||||
m_regs.IFR &= ~clr_ifr;
|
||||
|
@ -127,7 +127,8 @@ void SY6522::UpdateIFR(BYTE clr_ifr, BYTE set_ifr /*= 0*/)
|
|||
else
|
||||
m_regs.IFR &= ~IFR_IRQ;
|
||||
|
||||
MB_UpdateIRQ();
|
||||
if (GetCardMgr().GetObj(m_slot)) // If called from MockingboardCard ctor, then CardManager::m_slot[slot] == NULL
|
||||
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(m_slot)).UpdateIRQ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class SY6522
|
||||
{
|
||||
public:
|
||||
SY6522(void)
|
||||
SY6522(UINT slot) : m_slot(slot)
|
||||
{
|
||||
for (UINT i = 0; i < kNumTimersPer6522; i++)
|
||||
m_syncEvent[i] = NULL;
|
||||
|
@ -140,4 +140,5 @@ private:
|
|||
bool m_timer2Active;
|
||||
|
||||
class SyncEvent* m_syncEvent[kNumTimersPer6522];
|
||||
UINT m_slot;
|
||||
};
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
* very high at all. And I speak as a Cyrix owner. :-)
|
||||
*/
|
||||
|
||||
libspectrum_signed_word** g_ppSoundBuffers; // Used to pass param to sound_ay_overlay()
|
||||
//libspectrum_signed_word** g_ppSoundBuffers; // Used to pass param to sound_ay_overlay() // Moved to class AY8913
|
||||
|
||||
/* configuration */
|
||||
//int sound_enabled = 0; /* Are we currently using the sound card */
|
||||
|
@ -69,7 +69,7 @@ libspectrum_signed_word** g_ppSoundBuffers; // Used to pass param to sound_ay_ov
|
|||
* given the number of port writes theoretically possible in a
|
||||
* 50th I think this should be plenty.
|
||||
*/
|
||||
//#define AY_CHANGE_MAX 8000 // [TC] Moved into AY8910.h
|
||||
//#define AY_CHANGE_MAX 8000 // [TC] Moved into class AY8910.h
|
||||
|
||||
///* frequency to generate sound at for hifi sound */
|
||||
//#define HIFI_FREQ 88200
|
||||
|
@ -78,14 +78,14 @@ libspectrum_signed_word** g_ppSoundBuffers; // Used to pass param to sound_ay_ov
|
|||
static SRC_STATE *src_state;
|
||||
#endif /* #ifdef HAVE_SAMPLERATE */
|
||||
|
||||
int sound_generator_framesiz;
|
||||
int sound_framesiz;
|
||||
//static int sound_generator_framesiz; // Moved to class AY8913
|
||||
//int sound_framesiz; // unused
|
||||
|
||||
static int sound_generator_freq;
|
||||
//static int sound_generator_freq; // Moved to class AY8913
|
||||
|
||||
static int sound_channels;
|
||||
//static int sound_channels; // unused
|
||||
|
||||
static unsigned int ay_tone_levels[16];
|
||||
//static unsigned int ay_tone_levels[16]; // Moved to class AY8913
|
||||
|
||||
//static libspectrum_signed_word *sound_buf, *tape_buf;
|
||||
//static float *convert_input_buffer, *convert_output_buffer;
|
||||
|
@ -108,10 +108,10 @@ static int rstereopos, rchan1pos, rchan2pos, rchan3pos;
|
|||
|
||||
|
||||
// Statics:
|
||||
double CAY8910::m_fCurrentCLK_AY8910 = 0.0;
|
||||
double AY8913::m_fCurrentCLK_AY8910 = 0.0;
|
||||
|
||||
|
||||
void CAY8910::init(void)
|
||||
void AY8913::init(void)
|
||||
{
|
||||
// Init the statics that were in sound_ay_overlay()
|
||||
rng = 1;
|
||||
|
@ -119,14 +119,14 @@ void CAY8910::init(void)
|
|||
env_first = 1; env_rev = 0; env_counter = 15;
|
||||
}
|
||||
|
||||
CAY8910::CAY8910(void)
|
||||
AY8913::AY8913(void)
|
||||
{
|
||||
init();
|
||||
m_fCurrentCLK_AY8910 = g_fCurrentCLK6502;
|
||||
};
|
||||
|
||||
|
||||
void CAY8910::sound_ay_init( void )
|
||||
void AY8913::sound_ay_init( void )
|
||||
{
|
||||
/* AY output doesn't match the claimed levels; these levels are based
|
||||
* on the measurements posted to comp.sys.sinclair in Dec 2001 by
|
||||
|
@ -155,7 +155,7 @@ void CAY8910::sound_ay_init( void )
|
|||
}
|
||||
|
||||
|
||||
void CAY8910::sound_init( const char *device )
|
||||
void AY8913::sound_init( const char *device )
|
||||
{
|
||||
// static int first_init = 1;
|
||||
// int f, ret;
|
||||
|
@ -202,7 +202,7 @@ void CAY8910::sound_init( const char *device )
|
|||
|
||||
sound_channels = ( sound_stereo ? 2 : 1 );
|
||||
#endif
|
||||
sound_channels = 3; // 3 mono channels: ABC
|
||||
// sound_channels = 3; // 3 mono channels: ABC
|
||||
|
||||
// hz = ( float ) machine_current->timings.processor_speed /
|
||||
// machine_current->timings.tstates_per_frame;
|
||||
|
@ -230,7 +230,7 @@ void CAY8910::sound_init( const char *device )
|
|||
#endif
|
||||
|
||||
// sound_framesiz = ( float ) settings_current.sound_freq / hz;
|
||||
sound_framesiz = sound_generator_freq / (int)hz;
|
||||
// sound_framesiz = sound_generator_freq / (int)hz;
|
||||
|
||||
#ifdef HAVE_SAMPLERATE
|
||||
if( settings_current.sound_hifi ) {
|
||||
|
@ -338,7 +338,7 @@ sound_unpause( void )
|
|||
#endif
|
||||
|
||||
|
||||
void CAY8910::sound_end( void )
|
||||
void AY8913::sound_end( void )
|
||||
{
|
||||
#if 0
|
||||
if( sound_enabled ) {
|
||||
|
@ -470,7 +470,7 @@ sound_write_buf_pstereo( libspectrum_signed_word * out, int c )
|
|||
#define HZ_COMMON_DENOMINATOR 50
|
||||
#include "Log.h"
|
||||
|
||||
void CAY8910::sound_ay_overlay( void )
|
||||
void AY8913::sound_ay_overlay( void )
|
||||
{
|
||||
int tone_level[3];
|
||||
int mixer, envshape;
|
||||
|
@ -511,9 +511,9 @@ void CAY8910::sound_ay_overlay( void )
|
|||
}
|
||||
#endif
|
||||
|
||||
libspectrum_signed_word* pBuf1 = g_ppSoundBuffers[0];
|
||||
libspectrum_signed_word* pBuf2 = g_ppSoundBuffers[1];
|
||||
libspectrum_signed_word* pBuf3 = g_ppSoundBuffers[2];
|
||||
libspectrum_signed_word* pBuf1 = ppSoundBuffers[0];
|
||||
libspectrum_signed_word* pBuf2 = ppSoundBuffers[1];
|
||||
libspectrum_signed_word* pBuf3 = ppSoundBuffers[2];
|
||||
|
||||
// for( f = 0, ptr = sound_buf; f < sound_generator_framesiz; f++ ) {
|
||||
for( f = 0; f < sound_generator_framesiz; f++ ) {
|
||||
|
@ -725,7 +725,7 @@ void CAY8910::sound_ay_overlay( void )
|
|||
}
|
||||
}
|
||||
|
||||
BYTE CAY8910::sound_ay_read( int reg )
|
||||
BYTE AY8913::sound_ay_read( int reg )
|
||||
{
|
||||
reg &= 15;
|
||||
|
||||
|
@ -773,7 +773,7 @@ BYTE CAY8910::sound_ay_read( int reg )
|
|||
/* don't make the change immediately; record it for later,
|
||||
* to be made by sound_frame() (via sound_ay_overlay()).
|
||||
*/
|
||||
void CAY8910::sound_ay_write( int reg, int val, libspectrum_dword now )
|
||||
void AY8913::sound_ay_write( int reg, int val, libspectrum_dword now )
|
||||
{
|
||||
if( ay_change_count < AY_CHANGE_MAX ) {
|
||||
ay_change[ ay_change_count ].tstates = now;
|
||||
|
@ -787,7 +787,7 @@ void CAY8910::sound_ay_write( int reg, int val, libspectrum_dword now )
|
|||
/* no need to call this initially, but should be called
|
||||
* on reset otherwise.
|
||||
*/
|
||||
void CAY8910::sound_ay_reset( void )
|
||||
void AY8913::sound_ay_reset( void )
|
||||
{
|
||||
int f;
|
||||
|
||||
|
@ -868,7 +868,7 @@ sound_resample( void )
|
|||
}
|
||||
#endif /* #ifdef HAVE_SAMPLERATE */
|
||||
|
||||
void CAY8910::sound_frame( void )
|
||||
void AY8913::sound_frame( void )
|
||||
{
|
||||
#if 0
|
||||
libspectrum_signed_word *ptr, *tptr;
|
||||
|
@ -1046,7 +1046,7 @@ sound_beeper( int is_tape, int on )
|
|||
#define SS_YAML_KEY_CHANGE "Change"
|
||||
#define SS_YAML_VALUE_CHANGE_FORMAT "%d, %d, 0x%1X, 0x%02X"
|
||||
|
||||
void CAY8910::SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const std::string& suffix)
|
||||
void AY8913::SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const std::string& suffix)
|
||||
{
|
||||
std::string unit = std::string(SS_YAML_KEY_AY8910) + suffix;
|
||||
YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", unit.c_str());
|
||||
|
@ -1101,7 +1101,7 @@ void CAY8910::SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const std::string& su
|
|||
}
|
||||
}
|
||||
|
||||
bool CAY8910::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, const std::string& suffix)
|
||||
bool AY8913::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, const std::string& suffix)
|
||||
{
|
||||
std::string unit = std::string(SS_YAML_KEY_AY8910) + suffix;
|
||||
if (!yamlLoadHelper.GetSubMap(unit))
|
||||
|
@ -1192,86 +1192,3 @@ bool CAY8910::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, const std::string& su
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// AY8910 interface
|
||||
|
||||
#include "CPU.h" // For g_nCumulativeCycles
|
||||
|
||||
static CAY8910 g_AY8910[MAX_8910];
|
||||
static unsigned __int64 g_uLastCumulativeCycles = 0;
|
||||
|
||||
BYTE AYReadReg(int chip, int r)
|
||||
{
|
||||
return g_AY8910[chip].sound_ay_read(r);
|
||||
}
|
||||
|
||||
void _AYWriteReg(int chip, int r, int v)
|
||||
{
|
||||
libspectrum_dword uOffset = (libspectrum_dword) (g_nCumulativeCycles - g_uLastCumulativeCycles);
|
||||
g_AY8910[chip].sound_ay_write(r, v, uOffset);
|
||||
}
|
||||
|
||||
void AY8910_reset(int chip)
|
||||
{
|
||||
// Don't reset the AY CLK, as this is a property of the card (MB/Phasor), not the AY chip
|
||||
g_AY8910[chip].sound_ay_reset(); // Calls: sound_ay_init();
|
||||
}
|
||||
|
||||
void AY8910UpdateSetCycles()
|
||||
{
|
||||
g_uLastCumulativeCycles = g_nCumulativeCycles;
|
||||
}
|
||||
|
||||
void AY8910Update(int chip, INT16** buffer, int nNumSamples)
|
||||
{
|
||||
AY8910UpdateSetCycles();
|
||||
|
||||
sound_generator_framesiz = nNumSamples;
|
||||
g_ppSoundBuffers = buffer;
|
||||
g_AY8910[chip].sound_frame();
|
||||
}
|
||||
|
||||
void AY8910_InitAll(int nClock, int nSampleRate)
|
||||
{
|
||||
for (UINT i=0; i<MAX_8910; i++)
|
||||
{
|
||||
g_AY8910[i].sound_init(NULL); // Inits mainly static members (except ay_tick_incr)
|
||||
g_AY8910[i].sound_ay_init();
|
||||
}
|
||||
}
|
||||
|
||||
void AY8910_InitClock(int nClock)
|
||||
{
|
||||
CAY8910::SetCLK( (double)nClock );
|
||||
for (UINT i=0; i<MAX_8910; i++)
|
||||
{
|
||||
g_AY8910[i].sound_init(NULL); // ay_tick_incr is dependent on AY_CLK
|
||||
}
|
||||
}
|
||||
|
||||
BYTE* AY8910_GetRegsPtr(UINT uChip)
|
||||
{
|
||||
if (uChip >= MAX_8910)
|
||||
return NULL;
|
||||
|
||||
return g_AY8910[uChip].GetAYRegsPtr();
|
||||
}
|
||||
|
||||
UINT AY8910_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, UINT uChip, const std::string& suffix)
|
||||
{
|
||||
if (uChip >= MAX_8910)
|
||||
return 0;
|
||||
|
||||
g_AY8910[uChip].SaveSnapshot(yamlSaveHelper, suffix);
|
||||
return 1;
|
||||
}
|
||||
|
||||
UINT AY8910_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT uChip, const std::string& suffix)
|
||||
{
|
||||
if (uChip >= MAX_8910)
|
||||
return 0;
|
||||
|
||||
return g_AY8910[uChip].LoadSnapshot(yamlLoadHelper, suffix) ? 1 : 0;
|
||||
}
|
||||
|
|
|
@ -1,26 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#define MAX_8910 4
|
||||
|
||||
BYTE AYReadReg(int chip, int r); // TC
|
||||
|
||||
//-------------------------------------
|
||||
// MAME interface
|
||||
|
||||
void _AYWriteReg(int chip, int r, int v);
|
||||
//void AY8910_write_ym(int chip, int addr, int data);
|
||||
void AY8910_reset(int chip);
|
||||
void AY8910Update(int chip, INT16** buffer, int nNumSamples);
|
||||
|
||||
void AY8910_InitAll(int nClock, int nSampleRate);
|
||||
void AY8910_InitClock(int nClock);
|
||||
BYTE* AY8910_GetRegsPtr(UINT uChip);
|
||||
|
||||
void AY8910UpdateSetCycles();
|
||||
|
||||
UINT AY8910_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, UINT uChip, const std::string& suffix);
|
||||
UINT AY8910_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT uChip, const std::string& suffix);
|
||||
|
||||
//-------------------------------------
|
||||
// FUSE stuff
|
||||
|
||||
|
@ -34,11 +13,11 @@ typedef SHORT libspectrum_signed_word;
|
|||
*/
|
||||
#define AY_CHANGE_MAX 8000
|
||||
|
||||
class CAY8910
|
||||
class AY8913
|
||||
{
|
||||
public:
|
||||
CAY8910();
|
||||
virtual ~CAY8910() {};
|
||||
AY8913(void);
|
||||
~AY8913(void) {};
|
||||
|
||||
void sound_ay_init( void );
|
||||
void sound_init( const char *device );
|
||||
|
@ -47,6 +26,8 @@ public:
|
|||
void sound_ay_reset( void );
|
||||
void sound_frame( void );
|
||||
BYTE* GetAYRegsPtr( void ) { return &sound_ay_registers[0]; }
|
||||
void SetFramesize(int frameSize) { sound_generator_framesiz = frameSize; }
|
||||
void SetSoundBuffers(INT16** buffers) { ppSoundBuffers = buffers; }
|
||||
static void SetCLK( double CLK ) { m_fCurrentCLK_AY8910 = CLK; }
|
||||
void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const std::string& suffix);
|
||||
bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, const std::string& suffix);
|
||||
|
@ -86,6 +67,12 @@ private:
|
|||
int noise_toggle;
|
||||
int env_first, env_rev, env_counter;
|
||||
|
||||
// Vars
|
||||
libspectrum_signed_word** ppSoundBuffers; // Used to pass param to sound_ay_overlay()
|
||||
int sound_generator_framesiz;
|
||||
int sound_generator_freq;
|
||||
unsigned int ay_tone_levels[16];
|
||||
|
||||
// Vars shared between all AY's
|
||||
static double m_fCurrentCLK_AY8910;
|
||||
};
|
||||
|
|
|
@ -441,7 +441,7 @@ static __forceinline bool IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn,
|
|||
CYC(7);
|
||||
#if defined(_DEBUG) && LOG_IRQ_TAKEN_AND_RTI
|
||||
std::string irq6522;
|
||||
MB_Get6522IrqDescription(irq6522);
|
||||
GetCardMgr().GetMockingboardCardMgr().Get6522IrqDescription(irq6522);
|
||||
const char* pSrc = (g_bmIRQ & 1) ? irq6522.c_str() :
|
||||
(g_bmIRQ & 2) ? "SPEECH" :
|
||||
(g_bmIRQ & 4) ? "SSC" :
|
||||
|
@ -614,7 +614,7 @@ DWORD CpuExecute(const DWORD uCycles, const bool bVideoUpdate)
|
|||
g_interruptInLastExecutionBatch = false;
|
||||
|
||||
#ifdef _DEBUG
|
||||
MB_CheckCumulativeCycles();
|
||||
GetCardMgr().GetMockingboardCardMgr().CheckCumulativeCycles();
|
||||
#endif
|
||||
|
||||
// uCycles:
|
||||
|
@ -625,7 +625,7 @@ DWORD CpuExecute(const DWORD uCycles, const bool bVideoUpdate)
|
|||
// Update 6522s (NB. Do this before updating g_nCumulativeCycles below)
|
||||
// . Ensures that 6522 regs are up-to-date for any potential save-state
|
||||
// . SyncEvent will trigger the 6522 TIMER1/2 underflow on the correct cycle
|
||||
MB_UpdateCycles(uExecutedCycles);
|
||||
GetCardMgr().GetMockingboardCardMgr().UpdateCycles(uExecutedCycles);
|
||||
|
||||
const UINT nRemainingCycles = uExecutedCycles - g_nCyclesExecuted;
|
||||
g_nCumulativeCycles += nRemainingCycles;
|
||||
|
|
|
@ -71,17 +71,11 @@ void DummyCard::InitializeIO(LPBYTE pCxRomPeripheral)
|
|||
{
|
||||
case CT_GenericClock:
|
||||
break; // nothing to do
|
||||
case CT_MockingboardC:
|
||||
case CT_Phasor:
|
||||
// only in slot 4
|
||||
if (m_slot == SLOT4)
|
||||
{
|
||||
MB_InitializeIO(pCxRomPeripheral, SLOT4, SLOT5);
|
||||
}
|
||||
break;
|
||||
case CT_Z80:
|
||||
Z80_InitializeIO(pCxRomPeripheral, m_slot);
|
||||
break;
|
||||
default:
|
||||
_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,13 +83,10 @@ void DummyCard::Update(const ULONG nExecutedCycles)
|
|||
{
|
||||
switch (QueryType())
|
||||
{
|
||||
case CT_MockingboardC:
|
||||
case CT_Phasor:
|
||||
// only in slot 4
|
||||
if (m_slot == SLOT4)
|
||||
{
|
||||
MB_PeriodicUpdate(nExecutedCycles);
|
||||
}
|
||||
case CT_Z80:
|
||||
break; // nothing to do
|
||||
default:
|
||||
_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -104,14 +95,10 @@ void DummyCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
|
|||
{
|
||||
switch (QueryType())
|
||||
{
|
||||
case CT_MockingboardC:
|
||||
MB_SaveSnapshot(yamlSaveHelper, m_slot);
|
||||
break;
|
||||
case CT_Phasor:
|
||||
Phasor_SaveSnapshot(yamlSaveHelper, m_slot);
|
||||
break;
|
||||
case CT_Z80:
|
||||
Z80_SaveSnapshot(yamlSaveHelper, m_slot);
|
||||
default:
|
||||
_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -120,12 +107,10 @@ bool DummyCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
|
|||
{
|
||||
switch (QueryType())
|
||||
{
|
||||
case CT_MockingboardC:
|
||||
return MB_LoadSnapshot(yamlLoadHelper, m_slot, version);
|
||||
case CT_Phasor:
|
||||
return Phasor_LoadSnapshot(yamlLoadHelper, m_slot, version);
|
||||
case CT_Z80:
|
||||
return Z80_LoadSnapshot(yamlLoadHelper, m_slot, version);
|
||||
default:
|
||||
_ASSERT(0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -150,7 +135,7 @@ std::string Card::GetCardName(const SS_CARDTYPE cardType)
|
|||
case CT_SSC:
|
||||
return CSuperSerialCard::GetSnapshotCardName();
|
||||
case CT_MockingboardC:
|
||||
return MB_GetSnapshotCardName();
|
||||
return MockingboardCard::GetSnapshotCardName();
|
||||
case CT_GenericPrinter:
|
||||
return ParallelPrinterCard::GetSnapshotCardName();
|
||||
case CT_GenericHDD:
|
||||
|
@ -162,7 +147,7 @@ std::string Card::GetCardName(const SS_CARDTYPE cardType)
|
|||
case CT_Z80:
|
||||
return Z80_GetSnapshotCardName();
|
||||
case CT_Phasor:
|
||||
return Phasor_GetSnapshotCardName();
|
||||
return MockingboardCard::GetSnapshotCardNamePhasor();
|
||||
case CT_Echo:
|
||||
return "Echo";
|
||||
case CT_SAM:
|
||||
|
@ -200,11 +185,11 @@ SS_CARDTYPE Card::GetCardType(const std::string & card)
|
|||
{
|
||||
return CT_Z80;
|
||||
}
|
||||
else if (card == MB_GetSnapshotCardName())
|
||||
else if (card == MockingboardCard::GetSnapshotCardName())
|
||||
{
|
||||
return CT_MockingboardC;
|
||||
}
|
||||
else if (card == Phasor_GetSnapshotCardName())
|
||||
else if (card == MockingboardCard::GetSnapshotCardNamePhasor())
|
||||
{
|
||||
return CT_Phasor;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
#include "Disk.h"
|
||||
#include "FourPlay.h"
|
||||
#include "Harddisk.h"
|
||||
#include "Mockingboard.h"
|
||||
#include "MouseInterface.h"
|
||||
#include "ParallelPrinter.h"
|
||||
#include "SAM.h"
|
||||
|
@ -65,7 +66,7 @@ void CardManager::InsertInternal(UINT slot, SS_CARDTYPE type)
|
|||
m_slot[slot] = m_pSSC = new CSuperSerialCard(slot);
|
||||
break;
|
||||
case CT_MockingboardC:
|
||||
m_slot[slot] = new DummyCard(type, slot);
|
||||
m_slot[slot] = new MockingboardCard(slot, type);
|
||||
break;
|
||||
case CT_GenericPrinter:
|
||||
_ASSERT(m_pParallelPrinterCard == NULL);
|
||||
|
@ -87,7 +88,7 @@ void CardManager::InsertInternal(UINT slot, SS_CARDTYPE type)
|
|||
m_slot[slot] = new DummyCard(type, slot);
|
||||
break;
|
||||
case CT_Phasor:
|
||||
m_slot[slot] = new DummyCard(type, slot);
|
||||
m_slot[slot] = new MockingboardCard(slot, type);
|
||||
break;
|
||||
case CT_Echo:
|
||||
m_slot[slot] = new DummyCard(type, slot);
|
||||
|
@ -237,6 +238,33 @@ void CardManager::InitializeIO(LPBYTE pCxRomPeripheral)
|
|||
}
|
||||
}
|
||||
|
||||
void CardManager::Destroy()
|
||||
{
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; ++i)
|
||||
{
|
||||
if (m_slot[i])
|
||||
{
|
||||
m_slot[i]->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
GetCardMgr().GetDisk2CardMgr().Destroy();
|
||||
GetCardMgr().GetMockingboardCardMgr().Destroy();
|
||||
}
|
||||
|
||||
void CardManager::Reset(const bool powerCycle)
|
||||
{
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; ++i)
|
||||
{
|
||||
if (m_slot[i])
|
||||
{
|
||||
m_slot[i]->Reset(powerCycle);
|
||||
}
|
||||
}
|
||||
|
||||
GetCardMgr().GetMockingboardCardMgr().Reset(powerCycle);
|
||||
}
|
||||
|
||||
void CardManager::Update(const ULONG nExecutedCycles)
|
||||
{
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; ++i)
|
||||
|
@ -246,6 +274,8 @@ void CardManager::Update(const ULONG nExecutedCycles)
|
|||
m_slot[i]->Update(nExecutedCycles);
|
||||
}
|
||||
}
|
||||
|
||||
GetCardMgr().GetMockingboardCardMgr().Update(nExecutedCycles);
|
||||
}
|
||||
|
||||
void CardManager::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
|
||||
|
@ -258,25 +288,3 @@ void CardManager::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardManager::Reset(const bool powerCycle)
|
||||
{
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; ++i)
|
||||
{
|
||||
if (m_slot[i])
|
||||
{
|
||||
m_slot[i]->Reset(powerCycle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardManager::Destroy()
|
||||
{
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; ++i)
|
||||
{
|
||||
if (m_slot[i])
|
||||
{
|
||||
m_slot[i]->Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "Card.h"
|
||||
#include "Disk2CardManager.h"
|
||||
#include "MockingboardCardManager.h"
|
||||
#include "Common.h"
|
||||
|
||||
class CardManager
|
||||
|
@ -51,6 +52,7 @@ public:
|
|||
//
|
||||
|
||||
Disk2CardManager& GetDisk2CardMgr(void) { return m_disk2CardMgr; }
|
||||
MockingboardCardManager& GetMockingboardCardMgr(void) { return m_mockingboardCardMgr; }
|
||||
class CMouseInterface* GetMouseCard(void) { return m_pMouseCard; }
|
||||
bool IsMouseCardInstalled(void) { return m_pMouseCard != NULL; }
|
||||
class CSuperSerialCard* GetSSC(void) { return m_pSSC; }
|
||||
|
@ -61,8 +63,8 @@ public:
|
|||
class LanguageCardUnit* GetLanguageCard(void) { return m_pLanguageCard; }
|
||||
|
||||
void InitializeIO(LPBYTE pCxRomPeripheral);
|
||||
void Destroy(void);
|
||||
void Reset(const bool powerCycle);
|
||||
void Destroy();
|
||||
void Update(const ULONG nExecutedCycles);
|
||||
void SaveSnapshot(YamlSaveHelper& yamlSaveHelper);
|
||||
|
||||
|
@ -75,6 +77,7 @@ private:
|
|||
Card* m_slot[NUM_SLOTS];
|
||||
Card* m_aux;
|
||||
Disk2CardManager m_disk2CardMgr;
|
||||
MockingboardCardManager m_mockingboardCardMgr;
|
||||
class CMouseInterface* m_pMouseCard;
|
||||
class CSuperSerialCard* m_pSSC;
|
||||
class LanguageCardUnit* m_pLanguageCard;
|
||||
|
|
|
@ -40,6 +40,13 @@ const TCHAR CPageSound::m_soundchoices[] = TEXT("Disabled\0")
|
|||
TEXT("Sound Card\0");
|
||||
|
||||
|
||||
const char CPageSound::m_soundCardChoices[] = "Mockingboard\0"
|
||||
"Phasor\0"
|
||||
"SAM\0"
|
||||
"Empty\0";
|
||||
|
||||
const char CPageSound::m_soundCardChoice_Unavailable[] = "Unavailable\0\0"; // doubly-null terminate
|
||||
|
||||
INT_PTR CALLBACK CPageSound::DlgProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
// Switch from static func to our instance
|
||||
|
@ -85,21 +92,25 @@ INT_PTR CPageSound::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPAR
|
|||
break;
|
||||
case IDC_MB_VOLUME:
|
||||
break;
|
||||
case IDC_MB_ENABLE:
|
||||
if (NewSoundcardConfigured(hWnd, wparam, CT_MockingboardC))
|
||||
InitOptions(hWnd); // re-init
|
||||
break;
|
||||
case IDC_PHASOR_ENABLE:
|
||||
if (NewSoundcardConfigured(hWnd, wparam, CT_Phasor))
|
||||
InitOptions(hWnd); // re-init
|
||||
break;
|
||||
case IDC_SAM_ENABLE:
|
||||
if (NewSoundcardConfigured(hWnd, wparam, CT_SAM))
|
||||
InitOptions(hWnd); // re-init
|
||||
break;
|
||||
case IDC_SOUNDCARD_DISABLE:
|
||||
if (NewSoundcardConfigured(hWnd, wparam, CT_Empty))
|
||||
InitOptions(hWnd); // re-init
|
||||
case IDC_SOUNDCARD_SLOT4:
|
||||
case IDC_SOUNDCARD_SLOT5:
|
||||
if (HIWORD(wparam) == CBN_SELCHANGE)
|
||||
{
|
||||
UINT slot = (LOWORD(wparam) == IDC_SOUNDCARD_SLOT4) ? SLOT4 : SLOT5;
|
||||
DWORD newChoiceItem = (DWORD)SendDlgItemMessage(hWnd, LOWORD(wparam), CB_GETCURSEL, 0, 0);
|
||||
|
||||
SS_CARDTYPE newCard = CT_Empty;
|
||||
switch (newChoiceItem)
|
||||
{
|
||||
case SC_MOCKINGBOARD: newCard = CT_MockingboardC; break;
|
||||
case SC_PHASOR: newCard = CT_Phasor; break;
|
||||
case SC_SAM: newCard = CT_SAM; break;
|
||||
case SC_EMPTY: newCard = CT_Empty; break;
|
||||
default: _ASSERT(0); break;
|
||||
}
|
||||
|
||||
m_PropertySheetHelper.GetConfigNew().m_Slot[slot] = newCard;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -116,12 +127,7 @@ INT_PTR CPageSound::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPAR
|
|||
SendDlgItemMessage(hWnd,IDC_MB_VOLUME,TBM_SETRANGE,1,MAKELONG(VOLUME_MIN,VOLUME_MAX));
|
||||
SendDlgItemMessage(hWnd,IDC_MB_VOLUME,TBM_SETPAGESIZE,0,10);
|
||||
SendDlgItemMessage(hWnd,IDC_MB_VOLUME,TBM_SETTICFREQ,10,0);
|
||||
SendDlgItemMessage(hWnd,IDC_MB_VOLUME,TBM_SETPOS,1,MB_GetVolume());
|
||||
|
||||
if (GetCardMgr().QuerySlot(SLOT5) == CT_SAM)
|
||||
m_NewCardType = CT_SAM;
|
||||
else
|
||||
m_NewCardType = MB_GetSoundcardType(); // Reinit 1st time page is activated (fires before PSN_SETACTIVE)
|
||||
SendDlgItemMessage(hWnd,IDC_MB_VOLUME,TBM_SETPOS,1, GetCardMgr().GetMockingboardCardMgr().GetVolume());
|
||||
|
||||
InitOptions(hWnd);
|
||||
|
||||
|
@ -145,95 +151,44 @@ void CPageSound::DlgOK(HWND hWnd)
|
|||
|
||||
// NB. Volume: 0=Loudest, VOLUME_MAX=Silence
|
||||
SpkrSetVolume(dwSpkrVolume, VOLUME_MAX);
|
||||
MB_SetVolume(dwMBVolume, VOLUME_MAX);
|
||||
GetCardMgr().GetMockingboardCardMgr().SetVolume(dwMBVolume, VOLUME_MAX);
|
||||
|
||||
REGSAVE(TEXT(REGVALUE_SPKR_VOLUME), SpkrGetVolume());
|
||||
REGSAVE(TEXT(REGVALUE_MB_VOLUME), MB_GetVolume());
|
||||
REGSAVE(TEXT(REGVALUE_MB_VOLUME), GetCardMgr().GetMockingboardCardMgr().GetVolume());
|
||||
|
||||
m_PropertySheetHelper.PostMsgAfterClose(hWnd, m_Page);
|
||||
}
|
||||
|
||||
CPageSound::SOUNDCARDCHOICE CPageSound::CardTypeToComboItem(SS_CARDTYPE card)
|
||||
{
|
||||
switch (card)
|
||||
{
|
||||
case CT_MockingboardC: return SC_MOCKINGBOARD;
|
||||
case CT_Phasor: return SC_PHASOR;
|
||||
case CT_SAM: return SC_SAM;
|
||||
case CT_Empty: return SC_EMPTY;
|
||||
default: _ASSERT(0); return SC_EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
void CPageSound::InitOptions(HWND hWnd)
|
||||
{
|
||||
// CheckRadioButton
|
||||
if(m_NewCardType == CT_MockingboardC)
|
||||
m_nCurrentIDCheckButton = IDC_MB_ENABLE;
|
||||
else if(m_NewCardType == CT_Phasor)
|
||||
m_nCurrentIDCheckButton = IDC_PHASOR_ENABLE;
|
||||
else if(m_NewCardType == CT_SAM)
|
||||
m_nCurrentIDCheckButton = IDC_SAM_ENABLE;
|
||||
const SS_CARDTYPE slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[4];
|
||||
const SS_CARDTYPE slot5 = m_PropertySheetHelper.GetConfigNew().m_Slot[5];
|
||||
|
||||
bool isSlot4SoundCard = slot4 == CT_MockingboardC || slot4 == CT_Phasor || slot4 == CT_SAM || slot4 == CT_Empty;
|
||||
bool isSlot5SoundCard = slot5 == CT_MockingboardC || slot5 == CT_Phasor || slot5 == CT_SAM || slot5 == CT_Empty;
|
||||
|
||||
if (isSlot4SoundCard)
|
||||
m_PropertySheetHelper.FillComboBox(hWnd, IDC_SOUNDCARD_SLOT4, m_soundCardChoices, (int)CardTypeToComboItem(slot4));
|
||||
else
|
||||
m_nCurrentIDCheckButton = IDC_SOUNDCARD_DISABLE;
|
||||
m_PropertySheetHelper.FillComboBox(hWnd, IDC_SOUNDCARD_SLOT4, m_soundCardChoice_Unavailable, 0);
|
||||
|
||||
CheckRadioButton(hWnd, IDC_MB_ENABLE, IDC_SOUNDCARD_DISABLE, m_nCurrentIDCheckButton);
|
||||
|
||||
//
|
||||
|
||||
const SS_CARDTYPE Slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[4];
|
||||
const SS_CARDTYPE Slot5 = m_PropertySheetHelper.GetConfigNew().m_Slot[5];
|
||||
|
||||
const bool bIsSlot4Empty = Slot4 == CT_Empty;
|
||||
const bool bIsSlot5Empty = Slot5 == CT_Empty;
|
||||
|
||||
// Phasor button
|
||||
{
|
||||
const BOOL bEnable = bIsSlot4Empty || Slot4 == CT_MockingboardC || Slot4 == CT_Phasor;
|
||||
EnableWindow(GetDlgItem(hWnd, IDC_PHASOR_ENABLE), bEnable); // Disable Phasor (slot 4)
|
||||
}
|
||||
|
||||
// Mockingboard button
|
||||
{
|
||||
const BOOL bEnable = (bIsSlot4Empty || Slot4 == CT_Phasor || Slot4 == CT_MockingboardC) &&
|
||||
(bIsSlot5Empty || Slot5 == CT_SAM || Slot5 == CT_MockingboardC);
|
||||
EnableWindow(GetDlgItem(hWnd, IDC_MB_ENABLE), bEnable); // Disable Mockingboard (slot 4 & 5)
|
||||
}
|
||||
|
||||
// SAM button
|
||||
{
|
||||
const BOOL bEnable = bIsSlot5Empty || Slot5 == CT_MockingboardC || Slot5 == CT_SAM;
|
||||
EnableWindow(GetDlgItem(hWnd, IDC_SAM_ENABLE), bEnable); // Disable SAM (slot 5)
|
||||
}
|
||||
|
||||
EnableWindow(GetDlgItem(hWnd, IDC_MB_VOLUME), (m_nCurrentIDCheckButton != IDC_SOUNDCARD_DISABLE) ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
bool CPageSound::NewSoundcardConfigured(HWND hWnd, WPARAM wparam, SS_CARDTYPE NewCardType)
|
||||
{
|
||||
if (HIWORD(wparam) != BN_CLICKED)
|
||||
return false;
|
||||
|
||||
if (LOWORD(wparam) == m_nCurrentIDCheckButton)
|
||||
return false;
|
||||
|
||||
m_NewCardType = NewCardType;
|
||||
|
||||
const SS_CARDTYPE Slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[4];
|
||||
const SS_CARDTYPE Slot5 = m_PropertySheetHelper.GetConfigNew().m_Slot[5];
|
||||
|
||||
if (NewCardType == CT_MockingboardC)
|
||||
{
|
||||
m_PropertySheetHelper.GetConfigNew().m_Slot[4] = CT_MockingboardC;
|
||||
m_PropertySheetHelper.GetConfigNew().m_Slot[5] = CT_MockingboardC;
|
||||
}
|
||||
else if (NewCardType == CT_Phasor)
|
||||
{
|
||||
m_PropertySheetHelper.GetConfigNew().m_Slot[4] = CT_Phasor;
|
||||
if ((Slot5 == CT_MockingboardC) || (Slot5 == CT_SAM))
|
||||
m_PropertySheetHelper.GetConfigNew().m_Slot[5] = CT_Empty;
|
||||
}
|
||||
else if (NewCardType == CT_SAM)
|
||||
{
|
||||
if ((Slot4 == CT_MockingboardC) || (Slot4 == CT_Phasor))
|
||||
m_PropertySheetHelper.GetConfigNew().m_Slot[4] = CT_Empty;
|
||||
m_PropertySheetHelper.GetConfigNew().m_Slot[5] = CT_SAM;
|
||||
}
|
||||
if (isSlot5SoundCard)
|
||||
m_PropertySheetHelper.FillComboBox(hWnd, IDC_SOUNDCARD_SLOT5, m_soundCardChoices, (int)CardTypeToComboItem(slot5));
|
||||
else
|
||||
{
|
||||
if ((Slot4 == CT_MockingboardC) || (Slot4 == CT_Phasor))
|
||||
m_PropertySheetHelper.GetConfigNew().m_Slot[4] = CT_Empty;
|
||||
if ((Slot5 == CT_MockingboardC) || (Slot5 == CT_SAM))
|
||||
m_PropertySheetHelper.GetConfigNew().m_Slot[5] = CT_Empty;
|
||||
}
|
||||
m_PropertySheetHelper.FillComboBox(hWnd, IDC_SOUNDCARD_SLOT5, m_soundCardChoice_Unavailable, 0);
|
||||
|
||||
return true;
|
||||
bool enableMBVolume = slot4 == CT_MockingboardC || slot5 == CT_MockingboardC || slot4 == CT_Phasor || slot5 == CT_Phasor;
|
||||
EnableWindow(GetDlgItem(hWnd, IDC_MB_VOLUME), enableMBVolume ? TRUE : FALSE);
|
||||
}
|
||||
|
|
|
@ -11,9 +11,7 @@ class CPageSound : private IPropertySheetPage
|
|||
public:
|
||||
CPageSound(CPropertySheetHelper& PropertySheetHelper) :
|
||||
m_Page(PG_SOUND),
|
||||
m_PropertySheetHelper(PropertySheetHelper),
|
||||
m_NewCardType(CT_Empty),
|
||||
m_nCurrentIDCheckButton(0)
|
||||
m_PropertySheetHelper(PropertySheetHelper)
|
||||
{
|
||||
CPageSound::ms_this = this;
|
||||
}
|
||||
|
@ -30,8 +28,10 @@ protected:
|
|||
virtual void DlgCANCEL(HWND hWnd){}
|
||||
|
||||
private:
|
||||
enum SOUNDCARDCHOICE { SC_MOCKINGBOARD = 0, SC_PHASOR, SC_SAM, SC_EMPTY, _SOUNDCARD_MAX_CHOICES, SC_UNAVAILABLE };
|
||||
|
||||
void InitOptions(HWND hWnd);
|
||||
bool NewSoundcardConfigured(HWND hWnd, WPARAM wparam, SS_CARDTYPE NewCardType);
|
||||
SOUNDCARDCHOICE CardTypeToComboItem(SS_CARDTYPE card);
|
||||
|
||||
static CPageSound* ms_this;
|
||||
|
||||
|
@ -41,7 +41,6 @@ private:
|
|||
static const UINT VOLUME_MIN = 0;
|
||||
static const UINT VOLUME_MAX = 59;
|
||||
static const TCHAR m_soundchoices[];
|
||||
|
||||
SS_CARDTYPE m_NewCardType;
|
||||
int m_nCurrentIDCheckButton;
|
||||
static const char m_soundCardChoices[];
|
||||
static const char m_soundCardChoice_Unavailable[];
|
||||
};
|
||||
|
|
|
@ -227,7 +227,7 @@ void SetCurrentCLK6502(void)
|
|||
//
|
||||
|
||||
SpkrReinitialize();
|
||||
MB_Reinitialize();
|
||||
GetCardMgr().GetMockingboardCardMgr().ReinitializeClock();
|
||||
}
|
||||
|
||||
void UseClockMultiplier(double clockMultiplier)
|
||||
|
|
|
@ -1954,7 +1954,13 @@ void DrawMemory ( int line, int iMemDump )
|
|||
SS_CARD_MOCKINGBOARD_v1 SS_MB;
|
||||
|
||||
if ((eDevice == DEV_SY6522) || (eDevice == DEV_AY8910))
|
||||
MB_GetSnapshot_v1(&SS_MB, 4+(nAddr>>1)); // Slot4 or Slot5
|
||||
{
|
||||
UINT slot = 4 + (nAddr >> 1); // Slot4 or Slot5
|
||||
if (GetCardMgr().GetMockingboardCardMgr().IsMockingboard(slot))
|
||||
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(slot)).GetSnapshot_v1(&SS_MB);
|
||||
else // No MB in this slot
|
||||
SS_MB.Hdr.UnitHdr.hdr.v2.Type = UT_Reserved;
|
||||
}
|
||||
|
||||
RECT rect = { 0 };
|
||||
rect.left = DISPLAY_MINIMEM_COLUMN;
|
||||
|
@ -2059,7 +2065,9 @@ void DrawMemory ( int line, int iMemDump )
|
|||
// else
|
||||
if (eDevice == DEV_SY6522)
|
||||
{
|
||||
sText = StrFormat( "%02X ", (unsigned)((BYTE*)&SS_MB.Unit[nAddr & 1].RegsSY6522)[iAddress] );
|
||||
if (SS_MB.Hdr.UnitHdr.hdr.v2.Type == UT_Card)
|
||||
{
|
||||
sText = StrFormat("%02X ", (unsigned)((BYTE*)&SS_MB.Unit[nAddr & 1].RegsSY6522)[iAddress]);
|
||||
if (SS_MB.Unit[nAddr & 1].bTimer1Active && (iAddress == 4 || iAddress == 5)) // T1C
|
||||
{
|
||||
DebuggerSetColorFG(DebuggerGetColor(FG_INFO_TITLE)); // if timer1 active then draw in white
|
||||
|
@ -2071,19 +2079,31 @@ void DrawMemory ( int line, int iMemDump )
|
|||
else
|
||||
{
|
||||
if (iCol & 1)
|
||||
DebuggerSetColorFG( DebuggerGetColor( iForeground ));
|
||||
DebuggerSetColorFG(DebuggerGetColor(iForeground));
|
||||
else
|
||||
DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS ));
|
||||
DebuggerSetColorFG(DebuggerGetColor(FG_INFO_ADDRESS));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sText = "-- "; // No MB card in this slot
|
||||
}
|
||||
}
|
||||
else
|
||||
if (eDevice == DEV_AY8910)
|
||||
{
|
||||
sText = StrFormat( "%02X ", (unsigned)SS_MB.Unit[nAddr & 1].RegsAY8910[iAddress] );
|
||||
if (SS_MB.Hdr.UnitHdr.hdr.v2.Type == UT_Card)
|
||||
{
|
||||
sText = StrFormat("%02X ", (unsigned)SS_MB.Unit[nAddr & 1].RegsAY8910[iAddress]);
|
||||
if (iCol & 1)
|
||||
DebuggerSetColorFG( DebuggerGetColor( iForeground ));
|
||||
DebuggerSetColorFG(DebuggerGetColor(iForeground));
|
||||
else
|
||||
DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS ));
|
||||
DebuggerSetColorFG(DebuggerGetColor(FG_INFO_ADDRESS));
|
||||
}
|
||||
else
|
||||
{
|
||||
sText = "-- "; // No MB card in this slot
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -106,15 +106,11 @@ void Disk2CardManager::LoadLastDiskImage(void)
|
|||
}
|
||||
}
|
||||
|
||||
// Called by CardManager::Destroy()
|
||||
void Disk2CardManager::Destroy(void)
|
||||
{
|
||||
for (UINT i = 0; i < NUM_SLOTS; i++)
|
||||
{
|
||||
if (GetCardMgr().QuerySlot(i) == CT_Disk2)
|
||||
{
|
||||
dynamic_cast<Disk2InterfaceCard&>(GetCardMgr().GetRef(i)).Destroy();
|
||||
}
|
||||
}
|
||||
// NB. All cards (including any Disk2 cards) have just been destroyed by CardManager
|
||||
// - so nothing to do
|
||||
}
|
||||
|
||||
bool Disk2CardManager::IsAnyFirmware13Sector(void)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,41 +1,147 @@
|
|||
#pragma once
|
||||
|
||||
#include "6522.h"
|
||||
#include "AY8910.h"
|
||||
#include "Card.h"
|
||||
#include "SoundCore.h"
|
||||
#include "SSI263.h"
|
||||
#include "SynchronousEventManager.h"
|
||||
|
||||
enum PHASOR_MODE {PH_Mockingboard=0, PH_UNDEF1, PH_UNDEF2, PH_UNDEF3, PH_UNDEF4, PH_Phasor/*=5*/, PH_UNDEF6, PH_EchoPlus/*=7*/};
|
||||
class MockingboardCard : public Card
|
||||
{
|
||||
public:
|
||||
MockingboardCard(UINT slot, SS_CARDTYPE type);
|
||||
virtual ~MockingboardCard(void);
|
||||
|
||||
void MB_Initialize();
|
||||
void MB_Reinitialize();
|
||||
void MB_Destroy();
|
||||
void MB_Reset(const bool powerCycle);
|
||||
void MB_InitializeForLoadingSnapshot(void);
|
||||
void MB_InitializeIO(LPBYTE pCxRomPeripheral, UINT uSlot4, UINT uSlot5);
|
||||
void MB_Mute();
|
||||
void MB_Unmute();
|
||||
virtual void InitializeIO(LPBYTE pCxRomPeripheral);
|
||||
virtual void Destroy();
|
||||
virtual void Reset(const bool powerCycle);
|
||||
virtual void Update(const ULONG executedCycles);
|
||||
virtual void SaveSnapshot(YamlSaveHelper& yamlSaveHelper);
|
||||
virtual bool LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version);
|
||||
|
||||
static BYTE __stdcall IORead(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
|
||||
static BYTE __stdcall IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
|
||||
static BYTE __stdcall PhasorIO(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles);
|
||||
|
||||
BYTE IOReadInternal(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles);
|
||||
BYTE IOWriteInternal(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
|
||||
BYTE PhasorIOInternal(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles);
|
||||
|
||||
void ReinitializeClock(void);
|
||||
void MuteControl(bool mute);
|
||||
void UpdateCycles(ULONG executedCycles);
|
||||
bool IsActive(void);
|
||||
void SetVolume(DWORD dwVolume, DWORD dwVolumeMax);
|
||||
void SetCumulativeCycles(void);
|
||||
UINT MB_Update(void);
|
||||
short** GetVoiceBuffers(void) { return m_ppAYVoiceBuffer; }
|
||||
int GetNumSamplesError(void) { return m_numSamplesError; }
|
||||
void SetNumSamplesError(int numSamplesError) { m_numSamplesError = numSamplesError; }
|
||||
#ifdef _DEBUG
|
||||
void MB_CheckCumulativeCycles(); // DEBUG
|
||||
void CheckCumulativeCycles(void);
|
||||
void Get6522IrqDescription(std::string& desc);
|
||||
#endif
|
||||
void MB_SetCumulativeCycles();
|
||||
void MB_PeriodicUpdate(UINT executedCycles);
|
||||
void MB_CheckIRQ();
|
||||
void MB_UpdateCycles(ULONG uExecutedCycles);
|
||||
SS_CARDTYPE MB_GetSoundcardType();
|
||||
bool MB_IsActive();
|
||||
DWORD MB_GetVolume();
|
||||
void MB_SetVolume(DWORD dwVolume, DWORD dwVolumeMax);
|
||||
void MB_Get6522IrqDescription(std::string& desc);
|
||||
void MB_OutputToRiff(void);
|
||||
|
||||
void MB_UpdateIRQ(void);
|
||||
UINT64 MB_GetLastCumulativeCycles(void);
|
||||
void MB_UpdateIFR(BYTE nDevice, BYTE clr_mask, BYTE set_mask);
|
||||
BYTE MB_GetPCR(BYTE nDevice);
|
||||
void UpdateIRQ(void);
|
||||
UINT64 GetLastCumulativeCycles(void);
|
||||
void UpdateIFR(BYTE nDevice, BYTE clr_mask, BYTE set_mask);
|
||||
BYTE GetPCR(BYTE nDevice);
|
||||
bool IsAnyTimer1Active(void);
|
||||
|
||||
void MB_GetSnapshot_v1(struct SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot); // For debugger
|
||||
const std::string& MB_GetSnapshotCardName(void);
|
||||
void MB_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const UINT uSlot);
|
||||
bool MB_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version);
|
||||
void GetSnapshot_v1(struct SS_CARD_MOCKINGBOARD_v1* const pSS);
|
||||
|
||||
const std::string& Phasor_GetSnapshotCardName(void);
|
||||
void Phasor_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const UINT uSlot);
|
||||
bool Phasor_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version);
|
||||
static std::string GetSnapshotCardName(void);
|
||||
static std::string GetSnapshotCardNamePhasor(void);
|
||||
|
||||
private:
|
||||
enum MockingboardUnitState_e { AY_NOP0, AY_NOP1, AY_INACTIVE, AY_READ, AY_NOP4, AY_NOP5, AY_WRITE, AY_LATCH };
|
||||
|
||||
struct MB_SUBUNIT
|
||||
{
|
||||
SY6522 sy6522;
|
||||
AY8913 ay8913[2]; // Phasor has 2x AY per 6522
|
||||
SSI263 ssi263;
|
||||
BYTE nAY8910Number;
|
||||
BYTE nAYCurrentRegister;
|
||||
MockingboardUnitState_e state; // Where a unit is a 6522+AY8910 pair
|
||||
MockingboardUnitState_e stateB; // Phasor: 6522 & 2nd AY8910
|
||||
|
||||
MB_SUBUNIT(UINT slot) : sy6522(slot), ssi263(slot)
|
||||
{
|
||||
nAY8910Number = 0;
|
||||
nAYCurrentRegister = 0;
|
||||
state = AY_NOP0;
|
||||
stateB = AY_NOP0;
|
||||
// sy6522 & ssi263 have already been default constructed
|
||||
}
|
||||
};
|
||||
|
||||
void WriteToORB(BYTE subunit);
|
||||
void AY8910_Write(BYTE subunit, BYTE ay, BYTE value);
|
||||
void UpdateIFRandIRQ(MB_SUBUNIT* pMB, BYTE clr_mask, BYTE set_mask);
|
||||
|
||||
void Phasor_SaveSnapshot(YamlSaveHelper& yamlSaveHelper);
|
||||
bool Phasor_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version);
|
||||
|
||||
static int MB_SyncEventCallback(int id, int /*cycles*/, ULONG uExecutedCycles);
|
||||
int MB_SyncEventCallbackInternal(int id, int /*cycles*/, ULONG uExecutedCycles);
|
||||
|
||||
//-------------------------------------
|
||||
// MAME interface
|
||||
BYTE AYReadReg(BYTE subunit, BYTE ay, int r);
|
||||
void _AYWriteReg(BYTE subunit, BYTE ay, int r, int v);
|
||||
void AY8910_reset(BYTE subunit, BYTE ay);
|
||||
void AY8910Update(BYTE subunit, BYTE ay, INT16** buffer, int nNumSamples);
|
||||
|
||||
void AY8910_InitAll(int nClock, int nSampleRate);
|
||||
void AY8910_InitClock(int nClock);
|
||||
BYTE* AY8910_GetRegsPtr(BYTE subunit, BYTE ay);
|
||||
|
||||
void AY8910UpdateSetCycles();
|
||||
|
||||
UINT AY8910_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, BYTE subunit, BYTE ay, const std::string& suffix);
|
||||
UINT AY8910_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, BYTE subunit, BYTE ay, const std::string& suffix);
|
||||
|
||||
UINT64 m_lastAYUpdateCycle;
|
||||
//-------------------------------------
|
||||
|
||||
static const UINT SY6522_DEVICE_A = 0;
|
||||
static const UINT SY6522_DEVICE_B = 1;
|
||||
|
||||
static const UINT AY8913_DEVICE_A = 0;
|
||||
static const UINT AY8913_DEVICE_B = 1; // Phasor only
|
||||
|
||||
// Chip offsets from card base:
|
||||
static const UINT SY6522A_Offset = 0x00;
|
||||
static const UINT SY6522B_Offset = 0x80;
|
||||
static const UINT SSI263B_Offset = 0x20;
|
||||
static const UINT SSI263A_Offset = 0x40;
|
||||
|
||||
// MB has 2x (1x SY6522 + 1x AY8913), Phasor has 2x (1x SY6522 + 2x AY8913)
|
||||
MB_SUBUNIT m_MBSubUnit[NUM_SUBUNITS_PER_MB];
|
||||
|
||||
static const UINT kNumSyncEvents = NUM_SY6522 * SY6522::kNumTimersPer6522;
|
||||
SyncEvent* m_syncEvent[kNumSyncEvents];
|
||||
|
||||
UINT64 m_lastCumulativeCycle;
|
||||
|
||||
static const DWORD SAMPLE_RATE = 44100; // Use a base freq so that DirectX (or sound h/w) doesn't have to up/down-sample
|
||||
|
||||
short* m_ppAYVoiceBuffer[NUM_VOICES];
|
||||
|
||||
UINT64 m_inActiveCycleCount;
|
||||
bool m_regAccessedFlag;
|
||||
bool m_isActive;
|
||||
|
||||
//
|
||||
|
||||
bool m_phasorEnable;
|
||||
PHASOR_MODE m_phasorMode;
|
||||
UINT m_phasorClockScaleFactor;
|
||||
|
||||
//
|
||||
|
||||
UINT64 m_lastMBUpdateCycle;
|
||||
int m_numSamplesError;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,445 @@
|
|||
/*
|
||||
AppleWin : An Apple //e emulator for Windows
|
||||
|
||||
Copyright (C) 1994-1996, Michael O'Brien
|
||||
Copyright (C) 1999-2001, Oliver Schmidt
|
||||
Copyright (C) 2002-2005, Tom Charlesworth
|
||||
Copyright (C) 2006-2022, Tom Charlesworth, Michael Pohoreski, Nick Westgate
|
||||
|
||||
AppleWin 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.
|
||||
|
||||
AppleWin 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 AppleWin; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* Description: Mockingboard/Phasor Card Manager
|
||||
*
|
||||
* Author: Various
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "MockingboardCardManager.h"
|
||||
#include "Core.h"
|
||||
#include "CardManager.h"
|
||||
#include "Mockingboard.h"
|
||||
#include "MockingboardDefs.h"
|
||||
#include "Riff.h"
|
||||
|
||||
//#define DBG_MB_UPDATE
|
||||
|
||||
bool MockingboardCardManager::IsMockingboard(UINT slot)
|
||||
{
|
||||
SS_CARDTYPE type = GetCardMgr().QuerySlot(slot);
|
||||
return type == CT_MockingboardC || type == CT_Phasor;
|
||||
}
|
||||
|
||||
void MockingboardCardManager::ReinitializeClock(void)
|
||||
{
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; i++)
|
||||
{
|
||||
if (IsMockingboard(i))
|
||||
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(i)).ReinitializeClock();
|
||||
}
|
||||
}
|
||||
|
||||
void MockingboardCardManager::InitializeForLoadingSnapshot(void)
|
||||
{
|
||||
if (g_bDisableDirectSound || g_bDisableDirectSoundMockingboard)
|
||||
return;
|
||||
|
||||
if (!m_mockingboardVoice.lpDSBvoice)
|
||||
return;
|
||||
|
||||
DSVoiceStop(&m_mockingboardVoice); // Reason: 'MB voice is playing' then loading a save-state where 'no MB present' (GH#609)
|
||||
}
|
||||
|
||||
void MockingboardCardManager::MuteControl(bool mute)
|
||||
{
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; i++)
|
||||
{
|
||||
if (IsMockingboard(i))
|
||||
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(i)).MuteControl(mute);
|
||||
}
|
||||
|
||||
if (mute)
|
||||
{
|
||||
if (m_mockingboardVoice.bActive && !m_mockingboardVoice.bMute)
|
||||
{
|
||||
m_mockingboardVoice.lpDSBvoice->SetVolume(DSBVOLUME_MIN);
|
||||
m_mockingboardVoice.bMute = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_mockingboardVoice.bActive && m_mockingboardVoice.bMute)
|
||||
{
|
||||
m_mockingboardVoice.lpDSBvoice->SetVolume(m_mockingboardVoice.nVolume);
|
||||
m_mockingboardVoice.bMute = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MockingboardCardManager::SetCumulativeCycles(void)
|
||||
{
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; i++)
|
||||
{
|
||||
if (IsMockingboard(i))
|
||||
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(i)).SetCumulativeCycles();
|
||||
}
|
||||
}
|
||||
|
||||
void MockingboardCardManager::UpdateCycles(ULONG executedCycles)
|
||||
{
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; i++)
|
||||
{
|
||||
if (IsMockingboard(i))
|
||||
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(i)).UpdateCycles(executedCycles);
|
||||
}
|
||||
}
|
||||
|
||||
bool MockingboardCardManager::IsActive(void)
|
||||
{
|
||||
if (!m_mockingboardVoice.bActive)
|
||||
return false;
|
||||
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; i++)
|
||||
{
|
||||
if (IsMockingboard(i))
|
||||
if (dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(i)).IsActive())
|
||||
return true; // if any card is true then the condition for active is true
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD MockingboardCardManager::GetVolume(void)
|
||||
{
|
||||
return m_userVolume;
|
||||
}
|
||||
|
||||
void MockingboardCardManager::SetVolume(DWORD volume, DWORD volumeMax)
|
||||
{
|
||||
m_userVolume = volume;
|
||||
|
||||
m_mockingboardVoice.dwUserVolume = volume;
|
||||
m_mockingboardVoice.nVolume = NewVolume(volume, volumeMax);
|
||||
|
||||
if (m_mockingboardVoice.bActive && !m_mockingboardVoice.bMute)
|
||||
m_mockingboardVoice.lpDSBvoice->SetVolume(m_mockingboardVoice.nVolume);
|
||||
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; i++)
|
||||
{
|
||||
if (IsMockingboard(i))
|
||||
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(i)).SetVolume(volume, volumeMax);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
void MockingboardCardManager::CheckCumulativeCycles(void)
|
||||
{
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; i++)
|
||||
{
|
||||
if (IsMockingboard(i))
|
||||
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(i)).CheckCumulativeCycles();
|
||||
}
|
||||
}
|
||||
|
||||
void MockingboardCardManager::Get6522IrqDescription(std::string& desc)
|
||||
{
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; i++)
|
||||
{
|
||||
if (IsMockingboard(i))
|
||||
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(i)).Get6522IrqDescription(desc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Called by CardManager::Destroy()
|
||||
void MockingboardCardManager::Destroy(void)
|
||||
{
|
||||
// NB. All cards (including any Mockingboard cards) have just been destroyed by CardManager
|
||||
|
||||
if (m_mockingboardVoice.lpDSBvoice && m_mockingboardVoice.bActive)
|
||||
DSVoiceStop(&m_mockingboardVoice);
|
||||
|
||||
DSReleaseSoundBuffer(&m_mockingboardVoice);
|
||||
}
|
||||
|
||||
// Called by ContinueExecution() at the end of every execution period (~1000 cycles or ~3 cycles when MODE_STEPPING)
|
||||
// NB. Required for FT's TEST LAB #1 player
|
||||
void MockingboardCardManager::Update(const ULONG executedCycles)
|
||||
{
|
||||
// NB. CardManager has just called each card's Update()
|
||||
|
||||
bool active = false;
|
||||
for (UINT i = SLOT0; i < NUM_SLOTS; i++)
|
||||
{
|
||||
if (IsMockingboard(i))
|
||||
active |= dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(i)).IsAnyTimer1Active();
|
||||
}
|
||||
|
||||
if (active)
|
||||
return;
|
||||
|
||||
// No 6522 TIMER1's are active, so periodically update AY8913's here...
|
||||
|
||||
const UINT kCyclesPerAudioFrame = 1000;
|
||||
m_cyclesThisAudioFrame += executedCycles;
|
||||
if (m_cyclesThisAudioFrame < kCyclesPerAudioFrame)
|
||||
return;
|
||||
|
||||
m_cyclesThisAudioFrame %= kCyclesPerAudioFrame;
|
||||
|
||||
UpdateSoundBuffer();
|
||||
}
|
||||
|
||||
// Called by:
|
||||
// . MB_SyncEventCallback() on a TIMER1 (not TIMER2) underflow - when IsAnyTimer1Active() == true
|
||||
// . Update() - when IsAnyTimer1Active() == false
|
||||
void MockingboardCardManager::UpdateSoundBuffer(void)
|
||||
{
|
||||
#ifdef LOG_PERF_TIMINGS
|
||||
extern UINT64 g_timeMB_NoTimer;
|
||||
extern UINT64 g_timeMB_Timer;
|
||||
PerfMarker perfMarker(!IsAnyTimer1Active() ? g_timeMB_NoTimer : g_timeMB_Timer);
|
||||
#endif
|
||||
|
||||
if (!m_mockingboardVoice.lpDSBvoice)
|
||||
{
|
||||
if (g_bDisableDirectSound || g_bDisableDirectSoundMockingboard)
|
||||
return;
|
||||
|
||||
if (!Init())
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_mockingboardVoice.bActive)
|
||||
{
|
||||
// Sound buffer may have been stopped by MB_InitializeForLoadingSnapshot().
|
||||
// NB. DSZeroVoiceBuffer() also zeros the sound buffer, so it's better than directly calling IDirectSoundBuffer::Play():
|
||||
// - without zeroing, then the previous sound buffer can be heard for a fraction of a second
|
||||
// - eg. when doing Mockingboard playback, then loading a save-state which is also doing Mockingboard playback
|
||||
DSZeroVoiceBuffer(&m_mockingboardVoice, SOUNDBUFFER_SIZE); // ... and Play()
|
||||
}
|
||||
|
||||
UINT numSamples = GenerateAllSoundData();
|
||||
if (numSamples)
|
||||
MixAllAndCopyToRingBuffer(numSamples);
|
||||
}
|
||||
|
||||
bool MockingboardCardManager::Init(void)
|
||||
{
|
||||
if (!g_bDSAvailable)
|
||||
return false;
|
||||
|
||||
const DWORD SAMPLE_RATE = 44100; // Use a base freq so that DirectX (or sound h/w) doesn't have to up/down-sample
|
||||
|
||||
HRESULT hr = DSGetSoundBuffer(&m_mockingboardVoice, DSBCAPS_CTRLVOLUME, SOUNDBUFFER_SIZE, SAMPLE_RATE, NUM_MB_CHANNELS, "MB");
|
||||
LogFileOutput("MBCardMgr: DSGetSoundBuffer(), hr=0x%08X\n", hr);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LogFileOutput("MBCardMgr: DSGetSoundBuffer failed (%08X)\n", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bRes = DSZeroVoiceBuffer(&m_mockingboardVoice, SOUNDBUFFER_SIZE); // ... and Play()
|
||||
LogFileOutput("MBCardMgr: DSZeroVoiceBuffer(), res=%d\n", bRes ? 1 : 0);
|
||||
if (!bRes)
|
||||
return false;
|
||||
|
||||
m_mockingboardVoice.bActive = true;
|
||||
|
||||
// Volume might've been setup from value in Registry
|
||||
if (!m_mockingboardVoice.nVolume)
|
||||
m_mockingboardVoice.nVolume = DSBVOLUME_MAX;
|
||||
|
||||
hr = m_mockingboardVoice.lpDSBvoice->SetVolume(m_mockingboardVoice.nVolume);
|
||||
LogFileOutput("MBCardMgr: SetVolume(), hr=0x%08X\n", hr);
|
||||
return true;
|
||||
}
|
||||
|
||||
UINT MockingboardCardManager::GenerateAllSoundData(void)
|
||||
{
|
||||
UINT nNumSamples = 0;
|
||||
|
||||
UINT numSamples0 = (UINT)-1;
|
||||
int numSamplesError0 = -1;
|
||||
|
||||
for (UINT slot = SLOT0; slot < NUM_SLOTS; slot++)
|
||||
{
|
||||
if (!IsMockingboard(slot))
|
||||
continue;
|
||||
|
||||
MockingboardCard& MB = dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(slot));
|
||||
|
||||
MB.SetNumSamplesError(m_numSamplesError);
|
||||
nNumSamples = MB.MB_Update();
|
||||
m_numSamplesError = MB.GetNumSamplesError();
|
||||
|
||||
#if 1 // debug
|
||||
if (numSamples0 == (UINT)-1)
|
||||
{
|
||||
numSamples0 = nNumSamples;
|
||||
numSamplesError0 = m_numSamplesError;
|
||||
}
|
||||
|
||||
_ASSERT(numSamples0 == nNumSamples);
|
||||
_ASSERT(numSamplesError0 == m_numSamplesError);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
DWORD dwCurrentPlayCursor, dwCurrentWriteCursor;
|
||||
HRESULT hr = m_mockingboardVoice.lpDSBvoice->GetCurrentPosition(&dwCurrentPlayCursor, &dwCurrentWriteCursor);
|
||||
if (FAILED(hr))
|
||||
return 0;
|
||||
|
||||
if (m_byteOffset == (DWORD)-1)
|
||||
{
|
||||
// First time in this func
|
||||
|
||||
m_byteOffset = dwCurrentWriteCursor;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check that our offset isn't between Play & Write positions
|
||||
|
||||
if (dwCurrentWriteCursor > dwCurrentPlayCursor)
|
||||
{
|
||||
// |-----PxxxxxW-----|
|
||||
if ((m_byteOffset > dwCurrentPlayCursor) && (m_byteOffset < dwCurrentWriteCursor))
|
||||
{
|
||||
#ifdef DBG_MB_UPDATE
|
||||
double fTicksSecs = (double)GetTickCount() / 1000.0;
|
||||
LogOutput("%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor - dwCurrentPlayCursor, dwByteOffset, nNumSamples);
|
||||
#endif
|
||||
m_byteOffset = dwCurrentWriteCursor;
|
||||
m_numSamplesError = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// |xxW----------Pxxx|
|
||||
if ((m_byteOffset > dwCurrentPlayCursor) || (m_byteOffset < dwCurrentWriteCursor))
|
||||
{
|
||||
#ifdef DBG_MB_UPDATE
|
||||
double fTicksSecs = (double)GetTickCount() / 1000.0;
|
||||
LogOutput("%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor - dwCurrentPlayCursor, dwByteOffset, nNumSamples);
|
||||
#endif
|
||||
m_byteOffset = dwCurrentWriteCursor;
|
||||
m_numSamplesError = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nBytesRemaining = m_byteOffset - dwCurrentPlayCursor;
|
||||
if (nBytesRemaining < 0)
|
||||
nBytesRemaining += SOUNDBUFFER_SIZE;
|
||||
|
||||
// Calc correction factor so that play-buffer doesn't under/overflow
|
||||
const int nErrorInc = SoundCore_GetErrorInc();
|
||||
if (nBytesRemaining < SOUNDBUFFER_SIZE / 4)
|
||||
m_numSamplesError += nErrorInc; // < 0.25 of buffer remaining
|
||||
else if (nBytesRemaining > SOUNDBUFFER_SIZE / 2)
|
||||
m_numSamplesError -= nErrorInc; // > 0.50 of buffer remaining
|
||||
else
|
||||
m_numSamplesError = 0; // Acceptable amount of data in buffer
|
||||
|
||||
#ifdef DBG_MB_UPDATE
|
||||
double fTicksSecs = (double)GetTickCount() / 1000.0;
|
||||
LogOutput("%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X, NSE=%08X, Interval=%f\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor - dwCurrentPlayCursor, dwByteOffset, nNumSamples, nNumSamplesError, updateInterval);
|
||||
#endif
|
||||
|
||||
return nNumSamples;
|
||||
}
|
||||
|
||||
void MockingboardCardManager::MixAllAndCopyToRingBuffer(UINT nNumSamples)
|
||||
{
|
||||
// const double fAttenuation = g_bPhasorEnable ? 2.0 / 3.0 : 1.0;
|
||||
const double fAttenuation = true ? 2.0 / 3.0 : 1.0;
|
||||
|
||||
short** slotAYVoiceBuffers[NUM_SLOTS] = {0};
|
||||
|
||||
for (UINT slot = SLOT0; slot < NUM_SLOTS; slot++)
|
||||
{
|
||||
if (IsMockingboard(slot))
|
||||
slotAYVoiceBuffers[slot] = dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(slot)).GetVoiceBuffers();
|
||||
}
|
||||
|
||||
for (UINT i = 0; i < nNumSamples; i++)
|
||||
{
|
||||
// Mockingboard stereo (all voices on an AY8910 wire-or'ed together)
|
||||
// L = Address.b7=0, R = Address.b7=1
|
||||
int nDataL = 0, nDataR = 0;
|
||||
|
||||
for (UINT slot = SLOT0; slot < NUM_SLOTS; slot++)
|
||||
{
|
||||
if (!slotAYVoiceBuffers[slot])
|
||||
continue;
|
||||
|
||||
for (UINT j = 0; j < NUM_VOICES_PER_AY8913; j++)
|
||||
{
|
||||
short** ppAYVoiceBuffer = slotAYVoiceBuffers[slot];
|
||||
|
||||
// Regular MB-C AY's
|
||||
nDataL += (int)((double)ppAYVoiceBuffer[0 * NUM_VOICES_PER_AY8913 + j][i] * fAttenuation);
|
||||
nDataR += (int)((double)ppAYVoiceBuffer[2 * NUM_VOICES_PER_AY8913 + j][i] * fAttenuation);
|
||||
|
||||
// Extra Phasor AY's
|
||||
nDataL += (int)((double)ppAYVoiceBuffer[1 * NUM_VOICES_PER_AY8913 + j][i] * fAttenuation);
|
||||
nDataR += (int)((double)ppAYVoiceBuffer[3 * NUM_VOICES_PER_AY8913 + j][i] * fAttenuation);
|
||||
}
|
||||
}
|
||||
|
||||
// Cap the superpositioned output
|
||||
if (nDataL < WAVE_DATA_MIN)
|
||||
nDataL = WAVE_DATA_MIN;
|
||||
else if (nDataL > WAVE_DATA_MAX)
|
||||
nDataL = WAVE_DATA_MAX;
|
||||
|
||||
if (nDataR < WAVE_DATA_MIN)
|
||||
nDataR = WAVE_DATA_MIN;
|
||||
else if (nDataR > WAVE_DATA_MAX)
|
||||
nDataR = WAVE_DATA_MAX;
|
||||
|
||||
m_mixBuffer[i * NUM_MB_CHANNELS + 0] = (short)nDataL; // L
|
||||
m_mixBuffer[i * NUM_MB_CHANNELS + 1] = (short)nDataR; // R
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
DWORD dwDSLockedBufferSize0, dwDSLockedBufferSize1;
|
||||
SHORT* pDSLockedBuffer0, * pDSLockedBuffer1;
|
||||
|
||||
HRESULT hr = DSGetLock(m_mockingboardVoice.lpDSBvoice,
|
||||
m_byteOffset, (DWORD)nNumSamples * sizeof(short) * NUM_MB_CHANNELS,
|
||||
&pDSLockedBuffer0, &dwDSLockedBufferSize0,
|
||||
&pDSLockedBuffer1, &dwDSLockedBufferSize1);
|
||||
if (FAILED(hr))
|
||||
return;
|
||||
|
||||
memcpy(pDSLockedBuffer0, &m_mixBuffer[0], dwDSLockedBufferSize0);
|
||||
if (pDSLockedBuffer1)
|
||||
memcpy(pDSLockedBuffer1, &m_mixBuffer[dwDSLockedBufferSize0 / sizeof(short)], dwDSLockedBufferSize1);
|
||||
|
||||
// Commit sound buffer
|
||||
hr = m_mockingboardVoice.lpDSBvoice->Unlock((void*)pDSLockedBuffer0, dwDSLockedBufferSize0,
|
||||
(void*)pDSLockedBuffer1, dwDSLockedBufferSize1);
|
||||
|
||||
m_byteOffset = (m_byteOffset + (DWORD)nNumSamples * sizeof(short) * NUM_MB_CHANNELS) % SOUNDBUFFER_SIZE;
|
||||
|
||||
if (m_outputToRiff)
|
||||
RiffPutSamples(&m_mixBuffer[0], nNumSamples);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
#pragma once
|
||||
|
||||
#include "Core.h"
|
||||
#include "SoundCore.h"
|
||||
|
||||
class MockingboardCardManager
|
||||
{
|
||||
public:
|
||||
MockingboardCardManager(void)
|
||||
{
|
||||
m_numSamplesError = 0;
|
||||
m_byteOffset = (DWORD)-1;
|
||||
m_cyclesThisAudioFrame = 0;
|
||||
m_userVolume = 0;
|
||||
m_outputToRiff = false;
|
||||
|
||||
// NB. Cmd line has already been processed
|
||||
LogFileOutput("MBCardMgr::ctor() g_bDisableDirectSound=%d, g_bDisableDirectSoundMockingboard=%d\n", g_bDisableDirectSound, g_bDisableDirectSoundMockingboard);
|
||||
}
|
||||
~MockingboardCardManager(void)
|
||||
{}
|
||||
|
||||
bool IsMockingboard(UINT slot);
|
||||
void ReinitializeClock(void);
|
||||
void InitializeForLoadingSnapshot(void);
|
||||
void MuteControl(bool mute);
|
||||
void SetCumulativeCycles(void);
|
||||
void UpdateCycles(ULONG executedCycles);
|
||||
bool IsActive(void);
|
||||
DWORD GetVolume(void);
|
||||
void SetVolume(DWORD volume, DWORD volumeMax);
|
||||
void OutputToRiff(void) { m_outputToRiff = true; }
|
||||
|
||||
void Destroy(void);
|
||||
void Reset(const bool powerCycle)
|
||||
{
|
||||
m_cyclesThisAudioFrame = 0;
|
||||
}
|
||||
void Update(const ULONG executedCycles);
|
||||
void UpdateSoundBuffer(void);
|
||||
|
||||
#ifdef _DEBUG
|
||||
void CheckCumulativeCycles(void);
|
||||
void Get6522IrqDescription(std::string& desc);
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool Init(void);
|
||||
UINT GenerateAllSoundData(void);
|
||||
void MixAllAndCopyToRingBuffer(UINT nNumSamples);
|
||||
|
||||
static const unsigned short NUM_MB_CHANNELS = 2;
|
||||
static const DWORD SOUNDBUFFER_SIZE = MAX_SAMPLES * sizeof(short) * NUM_MB_CHANNELS;
|
||||
|
||||
static const SHORT WAVE_DATA_MIN = (SHORT)0x8000;
|
||||
static const SHORT WAVE_DATA_MAX = (SHORT)0x7FFF;
|
||||
|
||||
short m_mixBuffer[SOUNDBUFFER_SIZE / sizeof(short)];
|
||||
VOICE m_mockingboardVoice;
|
||||
|
||||
//
|
||||
|
||||
int m_numSamplesError;
|
||||
DWORD m_byteOffset;
|
||||
UINT m_cyclesThisAudioFrame;
|
||||
DWORD m_userVolume; // GUI's slide volume
|
||||
bool m_outputToRiff;
|
||||
};
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
// PHASOR_MODE: Circular dependency for Mockingboard.h & SSI263.h - so put it here for now
|
||||
enum PHASOR_MODE { PH_Mockingboard = 0, PH_UNDEF1, PH_UNDEF2, PH_UNDEF3, PH_UNDEF4, PH_Phasor/*=5*/, PH_UNDEF6, PH_EchoPlus/*=7*/ };
|
||||
|
||||
const UINT NUM_SY6522 = 2;
|
||||
const UINT NUM_AY8913 = 4; // Phasor has 4, MB has 2
|
||||
const UINT NUM_SSI263 = 2;
|
||||
|
||||
const UINT NUM_SUBUNITS_PER_MB = NUM_SY6522;
|
||||
const UINT NUM_AY8913_PER_SUBUNIT = NUM_AY8913 / NUM_SUBUNITS_PER_MB;
|
||||
const UINT NUM_VOICES_PER_AY8913 = 3;
|
||||
const UINT NUM_VOICES = NUM_AY8913 * NUM_VOICES_PER_AY8913;
|
|
@ -29,6 +29,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
#include "StdAfx.h"
|
||||
|
||||
#include "6522.h"
|
||||
#include "CardManager.h"
|
||||
#include "Mockingboard.h"
|
||||
#include "Core.h"
|
||||
#include "CPU.h"
|
||||
#include "Log.h"
|
||||
|
@ -104,6 +106,23 @@ void SSI_Output(void)
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
UINT64 SSI263::GetLastCumulativeCycles(void)
|
||||
{
|
||||
return dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(m_slot)).GetLastCumulativeCycles();
|
||||
}
|
||||
|
||||
void SSI263::UpdateIFR(BYTE nDevice, BYTE clr_mask, BYTE set_mask)
|
||||
{
|
||||
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(m_slot)).UpdateIFR(nDevice, clr_mask, set_mask);
|
||||
}
|
||||
|
||||
BYTE SSI263::GetPCR(BYTE nDevice)
|
||||
{
|
||||
return dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(m_slot)).GetPCR(nDevice);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
BYTE SSI263::Read(ULONG nExecutedCycles)
|
||||
{
|
||||
// Regardless of register, just return inverted A/!R in bit7
|
||||
|
@ -292,7 +311,7 @@ void SSI263::Votrax_Write(BYTE value)
|
|||
m_isVotraxPhoneme = true;
|
||||
|
||||
// !A/R: Acknowledge receipt of phoneme data (signal goes from high to low)
|
||||
MB_UpdateIFR(m_device, SY6522::IxR_VOTRAX, 0);
|
||||
UpdateIFR(m_device, SY6522::IxR_VOTRAX, 0);
|
||||
|
||||
// NB. Don't set reg0.DUR, as SC01's phoneme duration doesn't change with pitch (empirically determined from MAME's SC01 emulation)
|
||||
//m_durationPhoneme = value; // Set reg0.DUR = I1:0 (inflection or pitch)
|
||||
|
@ -363,7 +382,7 @@ void SSI263::Play(unsigned int nPhoneme)
|
|||
m_currSampleMod4 = 0;
|
||||
|
||||
// Set m_lastUpdateCycle, otherwise UpdateAccurateLength() can immediately complete phoneme! (GH#1104)
|
||||
m_lastUpdateCycle = MB_GetLastCumulativeCycles();
|
||||
m_lastUpdateCycle = GetLastCumulativeCycles();
|
||||
}
|
||||
|
||||
void SSI263::Stop(void)
|
||||
|
@ -479,7 +498,7 @@ void SSI263::Update(void)
|
|||
// . NB. this is fine, since it's the steady state; and it's likely that no actual data will ever occur during this initial time.
|
||||
// This means that the '1st phoneme playback time' (in cycles) will be a bit longer for subsequent times.
|
||||
|
||||
m_lastUpdateCycle = MB_GetLastCumulativeCycles();
|
||||
m_lastUpdateCycle = GetLastCumulativeCycles();
|
||||
|
||||
nNumSamples = kMinBytesInBuffer / sizeof(short);
|
||||
memset(&m_mixBufferSSI263[0], 0, nNumSamples);
|
||||
|
@ -491,14 +510,14 @@ void SSI263::Update(void)
|
|||
const double kMinimumUpdateInterval = 500.0; // Arbitary (500 cycles = 21 samples)
|
||||
const double kMaximumUpdateInterval = (double)(0xFFFF + 2); // Max 6522 timer interval (1372 samples)
|
||||
|
||||
_ASSERT(MB_GetLastCumulativeCycles() >= m_lastUpdateCycle);
|
||||
updateInterval = (double)(MB_GetLastCumulativeCycles() - m_lastUpdateCycle);
|
||||
_ASSERT(GetLastCumulativeCycles() >= m_lastUpdateCycle);
|
||||
updateInterval = (double)(GetLastCumulativeCycles() - m_lastUpdateCycle);
|
||||
if (updateInterval < kMinimumUpdateInterval)
|
||||
return;
|
||||
if (updateInterval > kMaximumUpdateInterval)
|
||||
updateInterval = kMaximumUpdateInterval;
|
||||
|
||||
m_lastUpdateCycle = MB_GetLastCumulativeCycles();
|
||||
m_lastUpdateCycle = GetLastCumulativeCycles();
|
||||
|
||||
const double nIrqFreq = g_fCurrentCLK6502 / updateInterval + 0.5; // Round-up
|
||||
const int nNumSamplesPerPeriod = (int)((double)(SAMPLE_RATE_SSI263) / nIrqFreq); // Eg. For 60Hz this is 367
|
||||
|
@ -659,7 +678,7 @@ void SSI263::UpdateAccurateLength(void)
|
|||
if (m_lastUpdateCycle == 0)
|
||||
return;
|
||||
|
||||
double updateInterval = (double)(MB_GetLastCumulativeCycles() - m_lastUpdateCycle);
|
||||
double updateInterval = (double)(GetLastCumulativeCycles() - m_lastUpdateCycle);
|
||||
|
||||
const double nIrqFreq = g_fCurrentCLK6502 / updateInterval + 0.5; // Round-up
|
||||
const int nNumSamplesPerPeriod = (int)((double)(SAMPLE_RATE_SSI263) / nIrqFreq); // Eg. For 60Hz this is 367
|
||||
|
@ -717,9 +736,9 @@ void SSI263::SetSpeechIRQ(void)
|
|||
{
|
||||
if (m_cardMode == PH_Mockingboard)
|
||||
{
|
||||
if ((MB_GetPCR(m_device) & 1) == 0) // CA1 Latch/Input = 0 (Negative active edge)
|
||||
MB_UpdateIFR(m_device, 0, SY6522::IxR_SSI263);
|
||||
if (MB_GetPCR(m_device) == 0x0C) // CA2 Control = b#110 (Low output)
|
||||
if ((GetPCR(m_device) & 1) == 0) // CA1 Latch/Input = 0 (Negative active edge)
|
||||
UpdateIFR(m_device, 0, SY6522::IxR_SSI263);
|
||||
if (GetPCR(m_device) == 0x0C) // CA2 Control = b#110 (Low output)
|
||||
m_currentMode &= ~1; // Clear SSI263's D7 pin (cleared by 6522's PCR CA1/CA2 handshake)
|
||||
|
||||
// NB. Don't set CTL=1, as Mockingboard(SMS) speech doesn't work (it sets MODE_IRQ_DISABLED mode during ISR)
|
||||
|
@ -738,11 +757,11 @@ void SSI263::SetSpeechIRQ(void)
|
|||
|
||||
//
|
||||
|
||||
if (m_isVotraxPhoneme && MB_GetPCR(m_device) == 0xB0)
|
||||
if (m_isVotraxPhoneme && GetPCR(m_device) == 0xB0)
|
||||
{
|
||||
// !A/R: Time-out of old phoneme (signal goes from low to high)
|
||||
|
||||
MB_UpdateIFR(m_device, 0, SY6522::IxR_VOTRAX);
|
||||
UpdateIFR(m_device, 0, SY6522::IxR_VOTRAX);
|
||||
|
||||
m_isVotraxPhoneme = false;
|
||||
}
|
||||
|
@ -863,7 +882,7 @@ void SSI263::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
|
|||
yamlSaveHelper.SaveBool(SS_YAML_KEY_SSI263_ACTIVE_PHONEME, IsPhonemeActive());
|
||||
}
|
||||
|
||||
void SSI263::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT device, PHASOR_MODE mode, UINT version)
|
||||
void SSI263::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, PHASOR_MODE mode, UINT version)
|
||||
{
|
||||
if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_SSI263))
|
||||
throw std::runtime_error("Card: Expected key: " SS_YAML_KEY_SSI263);
|
||||
|
@ -891,5 +910,5 @@ void SSI263::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT device, PHASOR_MO
|
|||
if (IsPhonemeActive())
|
||||
UpdateIRQ(); // Pre: m_device, m_cardMode
|
||||
|
||||
m_lastUpdateCycle = MB_GetLastCumulativeCycles();
|
||||
m_lastUpdateCycle = GetLastCumulativeCycles();
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "Mockingboard.h" // enum PHASOR_MODE
|
||||
#include "MockingboardDefs.h"
|
||||
|
||||
class SSI263
|
||||
{
|
||||
public:
|
||||
SSI263(void)
|
||||
SSI263(UINT slot) : m_slot(slot)
|
||||
{
|
||||
m_device = -1; // undefined
|
||||
m_cardMode = PH_Mockingboard;
|
||||
|
@ -59,6 +59,9 @@ public:
|
|||
m_dbgStartTime = 0;
|
||||
}
|
||||
|
||||
void SetDevice(UINT device) { m_device = device; }
|
||||
void SetCardMode(PHASOR_MODE mode) { m_cardMode = mode; }
|
||||
|
||||
bool DSInit(void);
|
||||
void DSUninit(void);
|
||||
|
||||
|
@ -80,11 +83,8 @@ public:
|
|||
bool GetVotraxPhoneme(void) { return m_isVotraxPhoneme; }
|
||||
void SetVotraxPhoneme(bool value) { m_isVotraxPhoneme = value; }
|
||||
|
||||
void SetCardMode(PHASOR_MODE mode) { m_cardMode = mode; }
|
||||
void SetDevice(UINT device) { m_device = device; }
|
||||
|
||||
void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
|
||||
void LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT device, PHASOR_MODE mode, UINT version);
|
||||
void LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, PHASOR_MODE mode, UINT version);
|
||||
|
||||
private:
|
||||
void Play(unsigned int nPhoneme);
|
||||
|
@ -92,6 +92,10 @@ private:
|
|||
void UpdateIRQ(void);
|
||||
void UpdateAccurateLength(void);
|
||||
|
||||
UINT64 GetLastCumulativeCycles(void);
|
||||
void UpdateIFR(BYTE nDevice, BYTE clr_mask, BYTE set_mask);
|
||||
BYTE GetPCR(BYTE nDevice);
|
||||
|
||||
static const BYTE m_Votrax2SSI263[/*64*/];
|
||||
|
||||
static const unsigned short m_kNumChannels = 1;
|
||||
|
@ -101,6 +105,7 @@ private:
|
|||
|
||||
//
|
||||
|
||||
UINT m_slot;
|
||||
BYTE m_device; // SSI263 device# which is generating phoneme-complete IRQ (and only required whilst Mockingboard isn't a class)
|
||||
PHASOR_MODE m_cardMode;
|
||||
short* m_pPhonemeData00;
|
||||
|
|
|
@ -388,7 +388,7 @@ static void Snapshot_LoadState_v2(void)
|
|||
GetVideo().SetVidHD(false); // Set true later only if VidHDCard is instantiated
|
||||
GetVideo().VideoResetState();
|
||||
GetVideo().SetVideoRefreshRate(VR_60HZ); // Default to 60Hz as older save-states won't contain refresh rate
|
||||
MB_InitializeForLoadingSnapshot(); // GH#609
|
||||
GetCardMgr().GetMockingboardCardMgr().InitializeForLoadingSnapshot(); // GH#609
|
||||
#ifdef USE_SPEECH_API
|
||||
g_Speech.Reset();
|
||||
#endif
|
||||
|
@ -402,7 +402,7 @@ static void Snapshot_LoadState_v2(void)
|
|||
throw std::runtime_error("Unknown top-level scalar: " + scalar);
|
||||
}
|
||||
|
||||
MB_SetCumulativeCycles();
|
||||
GetCardMgr().GetMockingboardCardMgr().SetCumulativeCycles();
|
||||
frame.SetLoadedSaveStateFlag(true);
|
||||
|
||||
// NB. The following disparity should be resolved:
|
||||
|
|
|
@ -48,7 +48,7 @@ static LPDIRECTSOUND g_lpDS = NULL;
|
|||
|
||||
// Used for muting & fading:
|
||||
|
||||
static const UINT uMAX_VOICES = 6; // 4x SSI263 + spkr + mockingboard
|
||||
static const UINT uMAX_VOICES = NUM_SLOTS * 2 + 1 + 1; // 8x (2x SSI263) + spkr + MockingboardCardManager
|
||||
static UINT g_uNumVoices = 0;
|
||||
static VOICE* g_pVoices[uMAX_VOICES] = {NULL};
|
||||
|
||||
|
@ -58,6 +58,21 @@ static VOICE* g_pSpeakerVoice = NULL;
|
|||
|
||||
bool g_bDSAvailable = false;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// NB. Also similar is done by: MockingboardCardManager::Destroy()
|
||||
// - which is called from WM_DESTROY (when both restarting VM & exiting the app)
|
||||
|
||||
VOICE::~VOICE(void)
|
||||
{
|
||||
if (lpDSBvoice)
|
||||
{
|
||||
DSVoiceStop(this);
|
||||
DSReleaseSoundBuffer(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext)
|
||||
|
@ -540,8 +555,10 @@ bool DSInit()
|
|||
return false;
|
||||
}
|
||||
|
||||
hr = g_lpDS->SetCooperativeLevel(GetFrame().g_hFrameWindow, DSSCL_NORMAL);
|
||||
if(FAILED(hr))
|
||||
HWND hwnd = GetFrame().g_hFrameWindow;
|
||||
_ASSERT(hwnd);
|
||||
hr = g_lpDS->SetCooperativeLevel(hwnd, DSSCL_NORMAL);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
if(g_fh) fprintf(g_fh, "SetCooperativeLevel failed (%08X)\n",hr);
|
||||
return false;
|
||||
|
|
|
@ -30,6 +30,8 @@ struct VOICE
|
|||
bRecentlyActive = false;
|
||||
name = "";
|
||||
}
|
||||
|
||||
~VOICE(void);
|
||||
};
|
||||
|
||||
typedef VOICE* PVOICE;
|
||||
|
|
|
@ -211,7 +211,7 @@ void LoadConfiguration(bool loadImages)
|
|||
SpkrSetVolume(dwTmp, GetPropertySheet().GetVolumeMax());
|
||||
|
||||
if(REGLOAD(TEXT(REGVALUE_MB_VOLUME), &dwTmp))
|
||||
MB_SetVolume(dwTmp, GetPropertySheet().GetVolumeMax());
|
||||
GetCardMgr().GetMockingboardCardMgr().SetVolume(dwTmp, GetPropertySheet().GetVolumeMax());
|
||||
|
||||
if(REGLOAD(TEXT(REGVALUE_SAVE_STATE_ON_EXIT), &dwTmp))
|
||||
g_bSaveStateOnExit = dwTmp ? true : false;
|
||||
|
@ -528,7 +528,6 @@ void ResetMachineState()
|
|||
GetVideo().VideoResetState();
|
||||
KeybReset();
|
||||
JoyReset();
|
||||
MB_Reset(true);
|
||||
SpkrReset();
|
||||
SetActiveCpu(GetMainCpu());
|
||||
#ifdef USE_SPEECH_API
|
||||
|
@ -568,7 +567,6 @@ void CtrlReset()
|
|||
GetPravets().Reset();
|
||||
GetCardMgr().Reset(false);
|
||||
KeybReset();
|
||||
MB_Reset(false);
|
||||
#ifdef USE_SPEECH_API
|
||||
g_Speech.Reset();
|
||||
#endif
|
||||
|
|
|
@ -179,7 +179,7 @@ static void ContinueExecution(void)
|
|||
const bool bWasFullSpeed = g_bFullSpeed;
|
||||
g_bFullSpeed = (g_dwSpeed == SPEED_MAX) ||
|
||||
bScrollLock_FullSpeed ||
|
||||
(GetCardMgr().GetDisk2CardMgr().IsConditionForFullSpeed() && !Spkr_IsActive() && !MB_IsActive()) ||
|
||||
(GetCardMgr().GetDisk2CardMgr().IsConditionForFullSpeed() && !Spkr_IsActive() && !GetCardMgr().GetMockingboardCardMgr().IsActive()) ||
|
||||
IsDebugSteppingAtFullSpeed();
|
||||
|
||||
if (g_bFullSpeed)
|
||||
|
@ -188,7 +188,7 @@ static void ContinueExecution(void)
|
|||
GetFrame().VideoRedrawScreenDuringFullSpeed(0, true); // Init for full-speed mode
|
||||
|
||||
// Don't call Spkr_Mute() - will get speaker clicks
|
||||
MB_Mute();
|
||||
GetCardMgr().GetMockingboardCardMgr().MuteControl(true);
|
||||
SysClk_StopTimer();
|
||||
#ifdef USE_SPEECH_API
|
||||
g_Speech.Reset(); // TODO: Put this on a timer (in emulated cycles)... otherwise CATALOG cuts out
|
||||
|
@ -206,7 +206,7 @@ static void ContinueExecution(void)
|
|||
GetFrame().VideoRedrawScreenAfterFullSpeed(g_dwCyclesThisFrame);
|
||||
|
||||
// Don't call Spkr_Unmute()
|
||||
MB_Unmute();
|
||||
GetCardMgr().GetMockingboardCardMgr().MuteControl(false);
|
||||
SysClk_StartTimerUsec(nExecutionPeriodUsec);
|
||||
|
||||
// Switch to higher priority, eg. for audio (BUG #015394)
|
||||
|
@ -633,7 +633,7 @@ static void OneTimeInitialization(HINSTANCE passinstance)
|
|||
else if (!g_cmdLine.wavFileMockingboard.empty())
|
||||
{
|
||||
if (RiffInitWriteFile(g_cmdLine.wavFileMockingboard.c_str(), 44100, 2))
|
||||
MB_OutputToRiff();
|
||||
GetCardMgr().GetMockingboardCardMgr().OutputToRiff();
|
||||
}
|
||||
|
||||
// Initialize COM - so we can use CoCreateInstance
|
||||
|
@ -678,7 +678,7 @@ static void RepeatInitialization(void)
|
|||
// NB. g_OldAppleWinVersion needed by LoadConfiguration() -> Config_Load_Video()
|
||||
const bool bShowAboutDlg = CheckOldAppleWinVersion(); // Post: g_OldAppleWinVersion
|
||||
|
||||
// Load configuration from Registry
|
||||
// Load configuration from Registry (+ will insert cards)
|
||||
{
|
||||
bool loadImages = g_cmdLine.szSnapshotName == NULL; // don't load floppy/harddisk images if a snapshot is to be loaded later on
|
||||
LoadConfiguration(loadImages);
|
||||
|
|
|
@ -1054,14 +1054,11 @@ LRESULT Win32Frame::WndProc(
|
|||
if (!g_bRestart) // GH#564: Only save-state on shutdown (not on a restart)
|
||||
Snapshot_Shutdown();
|
||||
DebugDestroy();
|
||||
if (!g_bRestart) {
|
||||
GetCardMgr().Destroy();
|
||||
}
|
||||
CpuDestroy();
|
||||
MemDestroy();
|
||||
SpkrDestroy();
|
||||
Destroy();
|
||||
MB_Destroy();
|
||||
DeleteGdiObjects();
|
||||
DIMouse::DirectInputUninit(window); // NB. do before window is destroyed
|
||||
PostQuitMessage(0); // Post WM_QUIT message to the thread's message queue
|
||||
|
@ -1076,15 +1073,12 @@ LRESULT Win32Frame::WndProc(
|
|||
CreateGdiObjects();
|
||||
LogFileOutput("WM_CREATE: CreateGdiObjects()\n");
|
||||
|
||||
DSInit();
|
||||
DSInit(); // NB. Need g_hFrameWindow for IDirectSound::SetCooperativeLevel()
|
||||
LogFileOutput("WM_CREATE: DSInit()\n");
|
||||
|
||||
DIMouse::DirectInputInit(window);
|
||||
LogFileOutput("WM_CREATE: DIMouse::DirectInputInit()\n");
|
||||
|
||||
MB_Initialize();
|
||||
LogFileOutput("WM_CREATE: MB_Initialize()\n");
|
||||
|
||||
SpkrInitialize();
|
||||
LogFileOutput("WM_CREATE: SpkrInitialize()\n");
|
||||
|
||||
|
|
Loading…
Reference in New Issue