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:
TomCh 2023-01-28 18:15:28 +00:00 committed by GitHub
parent 4668718fb3
commit 71c67cf132
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 1439 additions and 1251 deletions

View File

@ -91,6 +91,8 @@
<ClInclude Include="source\Log.h" /> <ClInclude Include="source\Log.h" />
<ClInclude Include="source\Memory.h" /> <ClInclude Include="source\Memory.h" />
<ClInclude Include="source\Mockingboard.h" /> <ClInclude Include="source\Mockingboard.h" />
<ClInclude Include="source\MockingboardCardManager.h" />
<ClInclude Include="source\MockingboardDefs.h" />
<ClInclude Include="source\MouseInterface.h" /> <ClInclude Include="source\MouseInterface.h" />
<ClInclude Include="source\NoSlotClock.h" /> <ClInclude Include="source\NoSlotClock.h" />
<ClInclude Include="source\NTSC.h" /> <ClInclude Include="source\NTSC.h" />
@ -176,6 +178,7 @@
<ClCompile Include="source\Disk2CardManager.cpp" /> <ClCompile Include="source\Disk2CardManager.cpp" />
<ClCompile Include="source\FourPlay.cpp" /> <ClCompile Include="source\FourPlay.cpp" />
<ClCompile Include="source\FrameBase.cpp" /> <ClCompile Include="source\FrameBase.cpp" />
<ClCompile Include="source\MockingboardCardManager.cpp" />
<ClCompile Include="source\RGBMonitor.cpp" /> <ClCompile Include="source\RGBMonitor.cpp" />
<ClCompile Include="source\SAM.cpp" /> <ClCompile Include="source\SAM.cpp" />
<ClCompile Include="source\Debugger\Debug.cpp" /> <ClCompile Include="source\Debugger\Debug.cpp" />

View File

@ -271,6 +271,9 @@
<ClCompile Include="source\CopyProtectionDongles.cpp"> <ClCompile Include="source\CopyProtectionDongles.cpp">
<Filter>Source Files\Emulator</Filter> <Filter>Source Files\Emulator</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="source\MockingboardCardManager.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="source\CommonVICE\6510core.h"> <ClInclude Include="source\CommonVICE\6510core.h">
@ -615,6 +618,12 @@
<ClInclude Include="source\CopyProtectionDongles.h"> <ClInclude Include="source\CopyProtectionDongles.h">
<Filter>Source Files\Emulator</Filter> <Filter>Source Files\Emulator</Filter>
</ClInclude> </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>
<ItemGroup> <ItemGroup>
<Image Include="resource\Applewin.bmp"> <Image Include="resource\Applewin.bmp">

View File

@ -168,10 +168,10 @@ BEGIN
LTEXT "&Mockingboard:",IDC_STATIC,49,39,51,8 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 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 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 LTEXT "Slot &4:",IDC_STATIC,16,136,84,10
CONTROL "Phasor (in slot 4)",IDC_PHASOR_ENABLE,"Button",BS_AUTORADIOBUTTON,10,149,92,10 COMBOBOX IDC_SOUNDCARD_SLOT4,45,134,100,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "SAM/DAC (in slot 5)",IDC_SAM_ENABLE,"Button",BS_AUTORADIOBUTTON,10,162,95,10 LTEXT "Slot &5:",IDC_STATIC,16,152,82,10
CONTROL "No sound cards",IDC_SOUNDCARD_DISABLE,"Button",BS_AUTORADIOBUTTON,10,175,78,10 COMBOBOX IDC_SOUNDCARD_SLOT5,45,150,100,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
END END
IDD_PROPPAGE_DISK DIALOGEX 0, 0, 210, 240 IDD_PROPPAGE_DISK DIALOGEX 0, 0, 210, 240

View File

@ -30,7 +30,6 @@
#define IDR_APPLE2_PLUS_ROM 127 #define IDR_APPLE2_PLUS_ROM 127
#define IDR_APPLE2E_ROM 128 #define IDR_APPLE2E_ROM 128
#define IDR_APPLE2E_ENHANCED_ROM 129 #define IDR_APPLE2E_ENHANCED_ROM 129
#define IDC_MB_ENABLE 130
#define IDD_TFE_SETTINGS_DIALOG 131 #define IDD_TFE_SETTINGS_DIALOG 131
#define IDR_PRINTDRVR_FW 132 #define IDR_PRINTDRVR_FW 132
#define IDD_PROPPAGE_ADVANCED 132 #define IDD_PROPPAGE_ADVANCED 132
@ -68,9 +67,8 @@
#define IDC_PASTE_FROM_CLIPBOARD 1023 #define IDC_PASTE_FROM_CLIPBOARD 1023
#define IDC_SPIN_XTRIM 1026 #define IDC_SPIN_XTRIM 1026
#define IDC_SPIN_YTRIM 1027 #define IDC_SPIN_YTRIM 1027
#define IDC_PHASOR_ENABLE 1029 #define IDC_SOUNDCARD_SLOT4 1028
#define IDC_SAM_ENABLE 1030 #define IDC_SOUNDCARD_SLOT5 1029
#define IDC_SOUNDCARD_DISABLE 1031
#define IDC_TFE_SETTINGS_ENABLE_T 1032 #define IDC_TFE_SETTINGS_ENABLE_T 1032
#define IDC_TFE_SETTINGS_ENABLE 1033 #define IDC_TFE_SETTINGS_ENABLE 1033
#define IDC_TFE_SETTINGS_INTERFACE_T 1034 #define IDC_TFE_SETTINGS_INTERFACE_T 1034

View File

@ -29,6 +29,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h" #include "StdAfx.h"
#include "6522.h" #include "6522.h"
#include "CardManager.h"
#include "Mockingboard.h"
#include "Core.h" #include "Core.h"
#include "CPU.h" #include "CPU.h"
#include "Memory.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*/) void SY6522::UpdateIFR(BYTE clr_ifr, BYTE set_ifr /*= 0*/)
{ {
m_regs.IFR &= ~clr_ifr; m_regs.IFR &= ~clr_ifr;
@ -127,7 +127,8 @@ void SY6522::UpdateIFR(BYTE clr_ifr, BYTE set_ifr /*= 0*/)
else else
m_regs.IFR &= ~IFR_IRQ; 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();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -3,7 +3,7 @@
class SY6522 class SY6522
{ {
public: public:
SY6522(void) SY6522(UINT slot) : m_slot(slot)
{ {
for (UINT i = 0; i < kNumTimersPer6522; i++) for (UINT i = 0; i < kNumTimersPer6522; i++)
m_syncEvent[i] = NULL; m_syncEvent[i] = NULL;
@ -140,4 +140,5 @@ private:
bool m_timer2Active; bool m_timer2Active;
class SyncEvent* m_syncEvent[kNumTimersPer6522]; class SyncEvent* m_syncEvent[kNumTimersPer6522];
UINT m_slot;
}; };

View File

@ -42,7 +42,7 @@
* very high at all. And I speak as a Cyrix owner. :-) * 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 */ /* configuration */
//int sound_enabled = 0; /* Are we currently using the sound card */ //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 * given the number of port writes theoretically possible in a
* 50th I think this should be plenty. * 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 */ ///* frequency to generate sound at for hifi sound */
//#define HIFI_FREQ 88200 //#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; static SRC_STATE *src_state;
#endif /* #ifdef HAVE_SAMPLERATE */ #endif /* #ifdef HAVE_SAMPLERATE */
int sound_generator_framesiz; //static int sound_generator_framesiz; // Moved to class AY8913
int sound_framesiz; //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 libspectrum_signed_word *sound_buf, *tape_buf;
//static float *convert_input_buffer, *convert_output_buffer; //static float *convert_input_buffer, *convert_output_buffer;
@ -108,10 +108,10 @@ static int rstereopos, rchan1pos, rchan2pos, rchan3pos;
// Statics: // 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() // Init the statics that were in sound_ay_overlay()
rng = 1; rng = 1;
@ -119,14 +119,14 @@ void CAY8910::init(void)
env_first = 1; env_rev = 0; env_counter = 15; env_first = 1; env_rev = 0; env_counter = 15;
} }
CAY8910::CAY8910(void) AY8913::AY8913(void)
{ {
init(); init();
m_fCurrentCLK_AY8910 = g_fCurrentCLK6502; 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 /* AY output doesn't match the claimed levels; these levels are based
* on the measurements posted to comp.sys.sinclair in Dec 2001 by * 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; // static int first_init = 1;
// int f, ret; // int f, ret;
@ -202,7 +202,7 @@ void CAY8910::sound_init( const char *device )
sound_channels = ( sound_stereo ? 2 : 1 ); sound_channels = ( sound_stereo ? 2 : 1 );
#endif #endif
sound_channels = 3; // 3 mono channels: ABC // sound_channels = 3; // 3 mono channels: ABC
// hz = ( float ) machine_current->timings.processor_speed / // hz = ( float ) machine_current->timings.processor_speed /
// machine_current->timings.tstates_per_frame; // machine_current->timings.tstates_per_frame;
@ -230,7 +230,7 @@ void CAY8910::sound_init( const char *device )
#endif #endif
// sound_framesiz = ( float ) settings_current.sound_freq / hz; // 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 #ifdef HAVE_SAMPLERATE
if( settings_current.sound_hifi ) { if( settings_current.sound_hifi ) {
@ -338,7 +338,7 @@ sound_unpause( void )
#endif #endif
void CAY8910::sound_end( void ) void AY8913::sound_end( void )
{ {
#if 0 #if 0
if( sound_enabled ) { if( sound_enabled ) {
@ -470,7 +470,7 @@ sound_write_buf_pstereo( libspectrum_signed_word * out, int c )
#define HZ_COMMON_DENOMINATOR 50 #define HZ_COMMON_DENOMINATOR 50
#include "Log.h" #include "Log.h"
void CAY8910::sound_ay_overlay( void ) void AY8913::sound_ay_overlay( void )
{ {
int tone_level[3]; int tone_level[3];
int mixer, envshape; int mixer, envshape;
@ -511,9 +511,9 @@ void CAY8910::sound_ay_overlay( void )
} }
#endif #endif
libspectrum_signed_word* pBuf1 = g_ppSoundBuffers[0]; libspectrum_signed_word* pBuf1 = ppSoundBuffers[0];
libspectrum_signed_word* pBuf2 = g_ppSoundBuffers[1]; libspectrum_signed_word* pBuf2 = ppSoundBuffers[1];
libspectrum_signed_word* pBuf3 = g_ppSoundBuffers[2]; libspectrum_signed_word* pBuf3 = ppSoundBuffers[2];
// for( f = 0, ptr = sound_buf; f < sound_generator_framesiz; f++ ) { // for( f = 0, ptr = sound_buf; f < sound_generator_framesiz; f++ ) {
for( f = 0; 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; reg &= 15;
@ -773,7 +773,7 @@ BYTE CAY8910::sound_ay_read( int reg )
/* don't make the change immediately; record it for later, /* don't make the change immediately; record it for later,
* to be made by sound_frame() (via sound_ay_overlay()). * 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 ) { if( ay_change_count < AY_CHANGE_MAX ) {
ay_change[ ay_change_count ].tstates = now; 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 /* no need to call this initially, but should be called
* on reset otherwise. * on reset otherwise.
*/ */
void CAY8910::sound_ay_reset( void ) void AY8913::sound_ay_reset( void )
{ {
int f; int f;
@ -868,7 +868,7 @@ sound_resample( void )
} }
#endif /* #ifdef HAVE_SAMPLERATE */ #endif /* #ifdef HAVE_SAMPLERATE */
void CAY8910::sound_frame( void ) void AY8913::sound_frame( void )
{ {
#if 0 #if 0
libspectrum_signed_word *ptr, *tptr; 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_KEY_CHANGE "Change"
#define SS_YAML_VALUE_CHANGE_FORMAT "%d, %d, 0x%1X, 0x%02X" #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; std::string unit = std::string(SS_YAML_KEY_AY8910) + suffix;
YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", unit.c_str()); 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; std::string unit = std::string(SS_YAML_KEY_AY8910) + suffix;
if (!yamlLoadHelper.GetSubMap(unit)) if (!yamlLoadHelper.GetSubMap(unit))
@ -1192,86 +1192,3 @@ bool CAY8910::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, const std::string& su
return true; 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;
}

View File

@ -1,26 +1,5 @@
#pragma once #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 // FUSE stuff
@ -34,11 +13,11 @@ typedef SHORT libspectrum_signed_word;
*/ */
#define AY_CHANGE_MAX 8000 #define AY_CHANGE_MAX 8000
class CAY8910 class AY8913
{ {
public: public:
CAY8910(); AY8913(void);
virtual ~CAY8910() {}; ~AY8913(void) {};
void sound_ay_init( void ); void sound_ay_init( void );
void sound_init( const char *device ); void sound_init( const char *device );
@ -47,6 +26,8 @@ public:
void sound_ay_reset( void ); void sound_ay_reset( void );
void sound_frame( void ); void sound_frame( void );
BYTE* GetAYRegsPtr( void ) { return &sound_ay_registers[0]; } 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; } static void SetCLK( double CLK ) { m_fCurrentCLK_AY8910 = CLK; }
void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const std::string& suffix); void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const std::string& suffix);
bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, const std::string& suffix); bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, const std::string& suffix);
@ -86,6 +67,12 @@ private:
int noise_toggle; int noise_toggle;
int env_first, env_rev, env_counter; 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 // Vars shared between all AY's
static double m_fCurrentCLK_AY8910; static double m_fCurrentCLK_AY8910;
}; };

View File

@ -441,7 +441,7 @@ static __forceinline bool IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn,
CYC(7); CYC(7);
#if defined(_DEBUG) && LOG_IRQ_TAKEN_AND_RTI #if defined(_DEBUG) && LOG_IRQ_TAKEN_AND_RTI
std::string irq6522; std::string irq6522;
MB_Get6522IrqDescription(irq6522); GetCardMgr().GetMockingboardCardMgr().Get6522IrqDescription(irq6522);
const char* pSrc = (g_bmIRQ & 1) ? irq6522.c_str() : const char* pSrc = (g_bmIRQ & 1) ? irq6522.c_str() :
(g_bmIRQ & 2) ? "SPEECH" : (g_bmIRQ & 2) ? "SPEECH" :
(g_bmIRQ & 4) ? "SSC" : (g_bmIRQ & 4) ? "SSC" :
@ -614,7 +614,7 @@ DWORD CpuExecute(const DWORD uCycles, const bool bVideoUpdate)
g_interruptInLastExecutionBatch = false; g_interruptInLastExecutionBatch = false;
#ifdef _DEBUG #ifdef _DEBUG
MB_CheckCumulativeCycles(); GetCardMgr().GetMockingboardCardMgr().CheckCumulativeCycles();
#endif #endif
// uCycles: // uCycles:
@ -625,7 +625,7 @@ DWORD CpuExecute(const DWORD uCycles, const bool bVideoUpdate)
// Update 6522s (NB. Do this before updating g_nCumulativeCycles below) // Update 6522s (NB. Do this before updating g_nCumulativeCycles below)
// . Ensures that 6522 regs are up-to-date for any potential save-state // . 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 // . 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; const UINT nRemainingCycles = uExecutedCycles - g_nCyclesExecuted;
g_nCumulativeCycles += nRemainingCycles; g_nCumulativeCycles += nRemainingCycles;

View File

@ -71,17 +71,11 @@ void DummyCard::InitializeIO(LPBYTE pCxRomPeripheral)
{ {
case CT_GenericClock: case CT_GenericClock:
break; // nothing to do 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: case CT_Z80:
Z80_InitializeIO(pCxRomPeripheral, m_slot); Z80_InitializeIO(pCxRomPeripheral, m_slot);
break; break;
default:
_ASSERT(0);
} }
} }
@ -89,13 +83,10 @@ void DummyCard::Update(const ULONG nExecutedCycles)
{ {
switch (QueryType()) switch (QueryType())
{ {
case CT_MockingboardC: case CT_Z80:
case CT_Phasor: break; // nothing to do
// only in slot 4 default:
if (m_slot == SLOT4) _ASSERT(0);
{
MB_PeriodicUpdate(nExecutedCycles);
}
break; break;
} }
} }
@ -104,14 +95,10 @@ void DummyCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
{ {
switch (QueryType()) switch (QueryType())
{ {
case CT_MockingboardC:
MB_SaveSnapshot(yamlSaveHelper, m_slot);
break;
case CT_Phasor:
Phasor_SaveSnapshot(yamlSaveHelper, m_slot);
break;
case CT_Z80: case CT_Z80:
Z80_SaveSnapshot(yamlSaveHelper, m_slot); Z80_SaveSnapshot(yamlSaveHelper, m_slot);
default:
_ASSERT(0);
break; break;
} }
} }
@ -120,12 +107,10 @@ bool DummyCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
{ {
switch (QueryType()) 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: case CT_Z80:
return Z80_LoadSnapshot(yamlLoadHelper, m_slot, version); return Z80_LoadSnapshot(yamlLoadHelper, m_slot, version);
default:
_ASSERT(0);
} }
return false; return false;
} }
@ -150,7 +135,7 @@ std::string Card::GetCardName(const SS_CARDTYPE cardType)
case CT_SSC: case CT_SSC:
return CSuperSerialCard::GetSnapshotCardName(); return CSuperSerialCard::GetSnapshotCardName();
case CT_MockingboardC: case CT_MockingboardC:
return MB_GetSnapshotCardName(); return MockingboardCard::GetSnapshotCardName();
case CT_GenericPrinter: case CT_GenericPrinter:
return ParallelPrinterCard::GetSnapshotCardName(); return ParallelPrinterCard::GetSnapshotCardName();
case CT_GenericHDD: case CT_GenericHDD:
@ -162,7 +147,7 @@ std::string Card::GetCardName(const SS_CARDTYPE cardType)
case CT_Z80: case CT_Z80:
return Z80_GetSnapshotCardName(); return Z80_GetSnapshotCardName();
case CT_Phasor: case CT_Phasor:
return Phasor_GetSnapshotCardName(); return MockingboardCard::GetSnapshotCardNamePhasor();
case CT_Echo: case CT_Echo:
return "Echo"; return "Echo";
case CT_SAM: case CT_SAM:
@ -200,11 +185,11 @@ SS_CARDTYPE Card::GetCardType(const std::string & card)
{ {
return CT_Z80; return CT_Z80;
} }
else if (card == MB_GetSnapshotCardName()) else if (card == MockingboardCard::GetSnapshotCardName())
{ {
return CT_MockingboardC; return CT_MockingboardC;
} }
else if (card == Phasor_GetSnapshotCardName()) else if (card == MockingboardCard::GetSnapshotCardNamePhasor())
{ {
return CT_Phasor; return CT_Phasor;
} }

View File

@ -36,6 +36,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Disk.h" #include "Disk.h"
#include "FourPlay.h" #include "FourPlay.h"
#include "Harddisk.h" #include "Harddisk.h"
#include "Mockingboard.h"
#include "MouseInterface.h" #include "MouseInterface.h"
#include "ParallelPrinter.h" #include "ParallelPrinter.h"
#include "SAM.h" #include "SAM.h"
@ -65,7 +66,7 @@ void CardManager::InsertInternal(UINT slot, SS_CARDTYPE type)
m_slot[slot] = m_pSSC = new CSuperSerialCard(slot); m_slot[slot] = m_pSSC = new CSuperSerialCard(slot);
break; break;
case CT_MockingboardC: case CT_MockingboardC:
m_slot[slot] = new DummyCard(type, slot); m_slot[slot] = new MockingboardCard(slot, type);
break; break;
case CT_GenericPrinter: case CT_GenericPrinter:
_ASSERT(m_pParallelPrinterCard == NULL); _ASSERT(m_pParallelPrinterCard == NULL);
@ -87,7 +88,7 @@ void CardManager::InsertInternal(UINT slot, SS_CARDTYPE type)
m_slot[slot] = new DummyCard(type, slot); m_slot[slot] = new DummyCard(type, slot);
break; break;
case CT_Phasor: case CT_Phasor:
m_slot[slot] = new DummyCard(type, slot); m_slot[slot] = new MockingboardCard(slot, type);
break; break;
case CT_Echo: case CT_Echo:
m_slot[slot] = new DummyCard(type, slot); 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) void CardManager::Update(const ULONG nExecutedCycles)
{ {
for (UINT i = SLOT0; i < NUM_SLOTS; ++i) for (UINT i = SLOT0; i < NUM_SLOTS; ++i)
@ -246,6 +274,8 @@ void CardManager::Update(const ULONG nExecutedCycles)
m_slot[i]->Update(nExecutedCycles); m_slot[i]->Update(nExecutedCycles);
} }
} }
GetCardMgr().GetMockingboardCardMgr().Update(nExecutedCycles);
} }
void CardManager::SaveSnapshot(YamlSaveHelper& yamlSaveHelper) 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();
}
}
}

View File

@ -2,6 +2,7 @@
#include "Card.h" #include "Card.h"
#include "Disk2CardManager.h" #include "Disk2CardManager.h"
#include "MockingboardCardManager.h"
#include "Common.h" #include "Common.h"
class CardManager class CardManager
@ -51,6 +52,7 @@ public:
// //
Disk2CardManager& GetDisk2CardMgr(void) { return m_disk2CardMgr; } Disk2CardManager& GetDisk2CardMgr(void) { return m_disk2CardMgr; }
MockingboardCardManager& GetMockingboardCardMgr(void) { return m_mockingboardCardMgr; }
class CMouseInterface* GetMouseCard(void) { return m_pMouseCard; } class CMouseInterface* GetMouseCard(void) { return m_pMouseCard; }
bool IsMouseCardInstalled(void) { return m_pMouseCard != NULL; } bool IsMouseCardInstalled(void) { return m_pMouseCard != NULL; }
class CSuperSerialCard* GetSSC(void) { return m_pSSC; } class CSuperSerialCard* GetSSC(void) { return m_pSSC; }
@ -61,8 +63,8 @@ public:
class LanguageCardUnit* GetLanguageCard(void) { return m_pLanguageCard; } class LanguageCardUnit* GetLanguageCard(void) { return m_pLanguageCard; }
void InitializeIO(LPBYTE pCxRomPeripheral); void InitializeIO(LPBYTE pCxRomPeripheral);
void Destroy(void);
void Reset(const bool powerCycle); void Reset(const bool powerCycle);
void Destroy();
void Update(const ULONG nExecutedCycles); void Update(const ULONG nExecutedCycles);
void SaveSnapshot(YamlSaveHelper& yamlSaveHelper); void SaveSnapshot(YamlSaveHelper& yamlSaveHelper);
@ -75,6 +77,7 @@ private:
Card* m_slot[NUM_SLOTS]; Card* m_slot[NUM_SLOTS];
Card* m_aux; Card* m_aux;
Disk2CardManager m_disk2CardMgr; Disk2CardManager m_disk2CardMgr;
MockingboardCardManager m_mockingboardCardMgr;
class CMouseInterface* m_pMouseCard; class CMouseInterface* m_pMouseCard;
class CSuperSerialCard* m_pSSC; class CSuperSerialCard* m_pSSC;
class LanguageCardUnit* m_pLanguageCard; class LanguageCardUnit* m_pLanguageCard;

View File

@ -40,6 +40,13 @@ const TCHAR CPageSound::m_soundchoices[] = TEXT("Disabled\0")
TEXT("Sound Card\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) INT_PTR CALLBACK CPageSound::DlgProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
{ {
// Switch from static func to our instance // Switch from static func to our instance
@ -85,21 +92,25 @@ INT_PTR CPageSound::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPAR
break; break;
case IDC_MB_VOLUME: case IDC_MB_VOLUME:
break; break;
case IDC_MB_ENABLE: case IDC_SOUNDCARD_SLOT4:
if (NewSoundcardConfigured(hWnd, wparam, CT_MockingboardC)) case IDC_SOUNDCARD_SLOT5:
InitOptions(hWnd); // re-init if (HIWORD(wparam) == CBN_SELCHANGE)
break; {
case IDC_PHASOR_ENABLE: UINT slot = (LOWORD(wparam) == IDC_SOUNDCARD_SLOT4) ? SLOT4 : SLOT5;
if (NewSoundcardConfigured(hWnd, wparam, CT_Phasor)) DWORD newChoiceItem = (DWORD)SendDlgItemMessage(hWnd, LOWORD(wparam), CB_GETCURSEL, 0, 0);
InitOptions(hWnd); // re-init
break; SS_CARDTYPE newCard = CT_Empty;
case IDC_SAM_ENABLE: switch (newChoiceItem)
if (NewSoundcardConfigured(hWnd, wparam, CT_SAM)) {
InitOptions(hWnd); // re-init case SC_MOCKINGBOARD: newCard = CT_MockingboardC; break;
break; case SC_PHASOR: newCard = CT_Phasor; break;
case IDC_SOUNDCARD_DISABLE: case SC_SAM: newCard = CT_SAM; break;
if (NewSoundcardConfigured(hWnd, wparam, CT_Empty)) case SC_EMPTY: newCard = CT_Empty; break;
InitOptions(hWnd); // re-init default: _ASSERT(0); break;
}
m_PropertySheetHelper.GetConfigNew().m_Slot[slot] = newCard;
}
break; break;
} }
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_SETRANGE,1,MAKELONG(VOLUME_MIN,VOLUME_MAX));
SendDlgItemMessage(hWnd,IDC_MB_VOLUME,TBM_SETPAGESIZE,0,10); SendDlgItemMessage(hWnd,IDC_MB_VOLUME,TBM_SETPAGESIZE,0,10);
SendDlgItemMessage(hWnd,IDC_MB_VOLUME,TBM_SETTICFREQ,10,0); SendDlgItemMessage(hWnd,IDC_MB_VOLUME,TBM_SETTICFREQ,10,0);
SendDlgItemMessage(hWnd,IDC_MB_VOLUME,TBM_SETPOS,1,MB_GetVolume()); SendDlgItemMessage(hWnd,IDC_MB_VOLUME,TBM_SETPOS,1, GetCardMgr().GetMockingboardCardMgr().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)
InitOptions(hWnd); InitOptions(hWnd);
@ -145,95 +151,44 @@ void CPageSound::DlgOK(HWND hWnd)
// NB. Volume: 0=Loudest, VOLUME_MAX=Silence // NB. Volume: 0=Loudest, VOLUME_MAX=Silence
SpkrSetVolume(dwSpkrVolume, VOLUME_MAX); SpkrSetVolume(dwSpkrVolume, VOLUME_MAX);
MB_SetVolume(dwMBVolume, VOLUME_MAX); GetCardMgr().GetMockingboardCardMgr().SetVolume(dwMBVolume, VOLUME_MAX);
REGSAVE(TEXT(REGVALUE_SPKR_VOLUME), SpkrGetVolume()); 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); 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) void CPageSound::InitOptions(HWND hWnd)
{ {
// CheckRadioButton const SS_CARDTYPE slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[4];
if(m_NewCardType == CT_MockingboardC) const SS_CARDTYPE slot5 = m_PropertySheetHelper.GetConfigNew().m_Slot[5];
m_nCurrentIDCheckButton = IDC_MB_ENABLE;
else if(m_NewCardType == CT_Phasor) bool isSlot4SoundCard = slot4 == CT_MockingboardC || slot4 == CT_Phasor || slot4 == CT_SAM || slot4 == CT_Empty;
m_nCurrentIDCheckButton = IDC_PHASOR_ENABLE; bool isSlot5SoundCard = slot5 == CT_MockingboardC || slot5 == CT_Phasor || slot5 == CT_SAM || slot5 == CT_Empty;
else if(m_NewCardType == CT_SAM)
m_nCurrentIDCheckButton = IDC_SAM_ENABLE; if (isSlot4SoundCard)
m_PropertySheetHelper.FillComboBox(hWnd, IDC_SOUNDCARD_SLOT4, m_soundCardChoices, (int)CardTypeToComboItem(slot4));
else 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); if (isSlot5SoundCard)
m_PropertySheetHelper.FillComboBox(hWnd, IDC_SOUNDCARD_SLOT5, m_soundCardChoices, (int)CardTypeToComboItem(slot5));
//
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;
}
else else
{ m_PropertySheetHelper.FillComboBox(hWnd, IDC_SOUNDCARD_SLOT5, m_soundCardChoice_Unavailable, 0);
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;
}
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);
} }

View File

@ -11,9 +11,7 @@ class CPageSound : private IPropertySheetPage
public: public:
CPageSound(CPropertySheetHelper& PropertySheetHelper) : CPageSound(CPropertySheetHelper& PropertySheetHelper) :
m_Page(PG_SOUND), m_Page(PG_SOUND),
m_PropertySheetHelper(PropertySheetHelper), m_PropertySheetHelper(PropertySheetHelper)
m_NewCardType(CT_Empty),
m_nCurrentIDCheckButton(0)
{ {
CPageSound::ms_this = this; CPageSound::ms_this = this;
} }
@ -30,8 +28,10 @@ protected:
virtual void DlgCANCEL(HWND hWnd){} virtual void DlgCANCEL(HWND hWnd){}
private: private:
enum SOUNDCARDCHOICE { SC_MOCKINGBOARD = 0, SC_PHASOR, SC_SAM, SC_EMPTY, _SOUNDCARD_MAX_CHOICES, SC_UNAVAILABLE };
void InitOptions(HWND hWnd); void InitOptions(HWND hWnd);
bool NewSoundcardConfigured(HWND hWnd, WPARAM wparam, SS_CARDTYPE NewCardType); SOUNDCARDCHOICE CardTypeToComboItem(SS_CARDTYPE card);
static CPageSound* ms_this; static CPageSound* ms_this;
@ -41,7 +41,6 @@ private:
static const UINT VOLUME_MIN = 0; static const UINT VOLUME_MIN = 0;
static const UINT VOLUME_MAX = 59; static const UINT VOLUME_MAX = 59;
static const TCHAR m_soundchoices[]; static const TCHAR m_soundchoices[];
static const char m_soundCardChoices[];
SS_CARDTYPE m_NewCardType; static const char m_soundCardChoice_Unavailable[];
int m_nCurrentIDCheckButton;
}; };

View File

@ -227,7 +227,7 @@ void SetCurrentCLK6502(void)
// //
SpkrReinitialize(); SpkrReinitialize();
MB_Reinitialize(); GetCardMgr().GetMockingboardCardMgr().ReinitializeClock();
} }
void UseClockMultiplier(double clockMultiplier) void UseClockMultiplier(double clockMultiplier)

View File

@ -1954,7 +1954,13 @@ void DrawMemory ( int line, int iMemDump )
SS_CARD_MOCKINGBOARD_v1 SS_MB; SS_CARD_MOCKINGBOARD_v1 SS_MB;
if ((eDevice == DEV_SY6522) || (eDevice == DEV_AY8910)) 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 rect = { 0 };
rect.left = DISPLAY_MINIMEM_COLUMN; rect.left = DISPLAY_MINIMEM_COLUMN;
@ -2059,31 +2065,45 @@ void DrawMemory ( int line, int iMemDump )
// else // else
if (eDevice == DEV_SY6522) 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)
if (SS_MB.Unit[nAddr & 1].bTimer1Active && (iAddress == 4 || iAddress == 5)) // T1C
{ {
DebuggerSetColorFG(DebuggerGetColor(FG_INFO_TITLE)); // if timer1 active then draw in white sText = StrFormat("%02X ", (unsigned)((BYTE*)&SS_MB.Unit[nAddr & 1].RegsSY6522)[iAddress]);
} if (SS_MB.Unit[nAddr & 1].bTimer1Active && (iAddress == 4 || iAddress == 5)) // T1C
else if (SS_MB.Unit[nAddr & 1].bTimer2Active && (iAddress == 8 || iAddress == 9)) // T2C {
{ DebuggerSetColorFG(DebuggerGetColor(FG_INFO_TITLE)); // if timer1 active then draw in white
DebuggerSetColorFG(DebuggerGetColor(FG_INFO_TITLE)); // if timer2 active then draw in white }
else if (SS_MB.Unit[nAddr & 1].bTimer2Active && (iAddress == 8 || iAddress == 9)) // T2C
{
DebuggerSetColorFG(DebuggerGetColor(FG_INFO_TITLE)); // if timer2 active then draw in white
}
else
{
if (iCol & 1)
DebuggerSetColorFG(DebuggerGetColor(iForeground));
else
DebuggerSetColorFG(DebuggerGetColor(FG_INFO_ADDRESS));
}
} }
else else
{ {
if (iCol & 1) sText = "-- "; // No MB card in this slot
DebuggerSetColorFG( DebuggerGetColor( iForeground ));
else
DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS ));
} }
} }
else else
if (eDevice == DEV_AY8910) 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)
if (iCol & 1) {
DebuggerSetColorFG( DebuggerGetColor( iForeground )); sText = StrFormat("%02X ", (unsigned)SS_MB.Unit[nAddr & 1].RegsAY8910[iAddress]);
if (iCol & 1)
DebuggerSetColorFG(DebuggerGetColor(iForeground));
else
DebuggerSetColorFG(DebuggerGetColor(FG_INFO_ADDRESS));
}
else else
DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS )); {
sText = "-- "; // No MB card in this slot
}
} }
else else
{ {

View File

@ -106,15 +106,11 @@ void Disk2CardManager::LoadLastDiskImage(void)
} }
} }
// Called by CardManager::Destroy()
void Disk2CardManager::Destroy(void) void Disk2CardManager::Destroy(void)
{ {
for (UINT i = 0; i < NUM_SLOTS; i++) // NB. All cards (including any Disk2 cards) have just been destroyed by CardManager
{ // - so nothing to do
if (GetCardMgr().QuerySlot(i) == CT_Disk2)
{
dynamic_cast<Disk2InterfaceCard&>(GetCardMgr().GetRef(i)).Destroy();
}
}
} }
bool Disk2CardManager::IsAnyFirmware13Sector(void) bool Disk2CardManager::IsAnyFirmware13Sector(void)

File diff suppressed because it is too large Load Diff

View File

@ -1,41 +1,147 @@
#pragma once #pragma once
#include "6522.h"
#include "AY8910.h"
#include "Card.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(); virtual void InitializeIO(LPBYTE pCxRomPeripheral);
void MB_Reinitialize(); virtual void Destroy();
void MB_Destroy(); virtual void Reset(const bool powerCycle);
void MB_Reset(const bool powerCycle); virtual void Update(const ULONG executedCycles);
void MB_InitializeForLoadingSnapshot(void); virtual void SaveSnapshot(YamlSaveHelper& yamlSaveHelper);
void MB_InitializeIO(LPBYTE pCxRomPeripheral, UINT uSlot4, UINT uSlot5); virtual bool LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version);
void MB_Mute();
void MB_Unmute(); 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 #ifdef _DEBUG
void MB_CheckCumulativeCycles(); // DEBUG void CheckCumulativeCycles(void);
void Get6522IrqDescription(std::string& desc);
#endif #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); void UpdateIRQ(void);
UINT64 MB_GetLastCumulativeCycles(void); UINT64 GetLastCumulativeCycles(void);
void MB_UpdateIFR(BYTE nDevice, BYTE clr_mask, BYTE set_mask); void UpdateIFR(BYTE nDevice, BYTE clr_mask, BYTE set_mask);
BYTE MB_GetPCR(BYTE nDevice); BYTE GetPCR(BYTE nDevice);
bool IsAnyTimer1Active(void);
void MB_GetSnapshot_v1(struct SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot); // For debugger void GetSnapshot_v1(struct SS_CARD_MOCKINGBOARD_v1* const pSS);
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);
const std::string& Phasor_GetSnapshotCardName(void); static std::string GetSnapshotCardName(void);
void Phasor_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const UINT uSlot); static std::string GetSnapshotCardNamePhasor(void);
bool Phasor_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version);
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;
};

View File

@ -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);
}

View File

@ -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;
};

13
source/MockingboardDefs.h Normal file
View File

@ -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;

View File

@ -29,6 +29,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h" #include "StdAfx.h"
#include "6522.h" #include "6522.h"
#include "CardManager.h"
#include "Mockingboard.h"
#include "Core.h" #include "Core.h"
#include "CPU.h" #include "CPU.h"
#include "Log.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) BYTE SSI263::Read(ULONG nExecutedCycles)
{ {
// Regardless of register, just return inverted A/!R in bit7 // Regardless of register, just return inverted A/!R in bit7
@ -292,7 +311,7 @@ void SSI263::Votrax_Write(BYTE value)
m_isVotraxPhoneme = true; m_isVotraxPhoneme = true;
// !A/R: Acknowledge receipt of phoneme data (signal goes from high to low) // !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) // 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) //m_durationPhoneme = value; // Set reg0.DUR = I1:0 (inflection or pitch)
@ -363,7 +382,7 @@ void SSI263::Play(unsigned int nPhoneme)
m_currSampleMod4 = 0; m_currSampleMod4 = 0;
// Set m_lastUpdateCycle, otherwise UpdateAccurateLength() can immediately complete phoneme! (GH#1104) // Set m_lastUpdateCycle, otherwise UpdateAccurateLength() can immediately complete phoneme! (GH#1104)
m_lastUpdateCycle = MB_GetLastCumulativeCycles(); m_lastUpdateCycle = GetLastCumulativeCycles();
} }
void SSI263::Stop(void) 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. // . 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. // 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); nNumSamples = kMinBytesInBuffer / sizeof(short);
memset(&m_mixBufferSSI263[0], 0, nNumSamples); 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 kMinimumUpdateInterval = 500.0; // Arbitary (500 cycles = 21 samples)
const double kMaximumUpdateInterval = (double)(0xFFFF + 2); // Max 6522 timer interval (1372 samples) const double kMaximumUpdateInterval = (double)(0xFFFF + 2); // Max 6522 timer interval (1372 samples)
_ASSERT(MB_GetLastCumulativeCycles() >= m_lastUpdateCycle); _ASSERT(GetLastCumulativeCycles() >= m_lastUpdateCycle);
updateInterval = (double)(MB_GetLastCumulativeCycles() - m_lastUpdateCycle); updateInterval = (double)(GetLastCumulativeCycles() - m_lastUpdateCycle);
if (updateInterval < kMinimumUpdateInterval) if (updateInterval < kMinimumUpdateInterval)
return; return;
if (updateInterval > kMaximumUpdateInterval) if (updateInterval > kMaximumUpdateInterval)
updateInterval = kMaximumUpdateInterval; updateInterval = kMaximumUpdateInterval;
m_lastUpdateCycle = MB_GetLastCumulativeCycles(); m_lastUpdateCycle = GetLastCumulativeCycles();
const double nIrqFreq = g_fCurrentCLK6502 / updateInterval + 0.5; // Round-up 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 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) if (m_lastUpdateCycle == 0)
return; 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 double nIrqFreq = g_fCurrentCLK6502 / updateInterval + 0.5; // Round-up
const int nNumSamplesPerPeriod = (int)((double)(SAMPLE_RATE_SSI263) / nIrqFreq); // Eg. For 60Hz this is 367 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 (m_cardMode == PH_Mockingboard)
{ {
if ((MB_GetPCR(m_device) & 1) == 0) // CA1 Latch/Input = 0 (Negative active edge) if ((GetPCR(m_device) & 1) == 0) // CA1 Latch/Input = 0 (Negative active edge)
MB_UpdateIFR(m_device, 0, SY6522::IxR_SSI263); UpdateIFR(m_device, 0, SY6522::IxR_SSI263);
if (MB_GetPCR(m_device) == 0x0C) // CA2 Control = b#110 (Low output) 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) 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) // 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) // !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; m_isVotraxPhoneme = false;
} }
@ -863,7 +882,7 @@ void SSI263::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
yamlSaveHelper.SaveBool(SS_YAML_KEY_SSI263_ACTIVE_PHONEME, IsPhonemeActive()); 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)) if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_SSI263))
throw std::runtime_error("Card: Expected key: " 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()) if (IsPhonemeActive())
UpdateIRQ(); // Pre: m_device, m_cardMode UpdateIRQ(); // Pre: m_device, m_cardMode
m_lastUpdateCycle = MB_GetLastCumulativeCycles(); m_lastUpdateCycle = GetLastCumulativeCycles();
} }

View File

@ -1,11 +1,11 @@
#pragma once #pragma once
#include "Mockingboard.h" // enum PHASOR_MODE #include "MockingboardDefs.h"
class SSI263 class SSI263
{ {
public: public:
SSI263(void) SSI263(UINT slot) : m_slot(slot)
{ {
m_device = -1; // undefined m_device = -1; // undefined
m_cardMode = PH_Mockingboard; m_cardMode = PH_Mockingboard;
@ -59,6 +59,9 @@ public:
m_dbgStartTime = 0; m_dbgStartTime = 0;
} }
void SetDevice(UINT device) { m_device = device; }
void SetCardMode(PHASOR_MODE mode) { m_cardMode = mode; }
bool DSInit(void); bool DSInit(void);
void DSUninit(void); void DSUninit(void);
@ -80,11 +83,8 @@ public:
bool GetVotraxPhoneme(void) { return m_isVotraxPhoneme; } bool GetVotraxPhoneme(void) { return m_isVotraxPhoneme; }
void SetVotraxPhoneme(bool value) { m_isVotraxPhoneme = value; } 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 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: private:
void Play(unsigned int nPhoneme); void Play(unsigned int nPhoneme);
@ -92,6 +92,10 @@ private:
void UpdateIRQ(void); void UpdateIRQ(void);
void UpdateAccurateLength(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 BYTE m_Votrax2SSI263[/*64*/];
static const unsigned short m_kNumChannels = 1; 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) BYTE m_device; // SSI263 device# which is generating phoneme-complete IRQ (and only required whilst Mockingboard isn't a class)
PHASOR_MODE m_cardMode; PHASOR_MODE m_cardMode;
short* m_pPhonemeData00; short* m_pPhonemeData00;

View File

@ -388,7 +388,7 @@ static void Snapshot_LoadState_v2(void)
GetVideo().SetVidHD(false); // Set true later only if VidHDCard is instantiated GetVideo().SetVidHD(false); // Set true later only if VidHDCard is instantiated
GetVideo().VideoResetState(); GetVideo().VideoResetState();
GetVideo().SetVideoRefreshRate(VR_60HZ); // Default to 60Hz as older save-states won't contain refresh rate 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 #ifdef USE_SPEECH_API
g_Speech.Reset(); g_Speech.Reset();
#endif #endif
@ -402,7 +402,7 @@ static void Snapshot_LoadState_v2(void)
throw std::runtime_error("Unknown top-level scalar: " + scalar); throw std::runtime_error("Unknown top-level scalar: " + scalar);
} }
MB_SetCumulativeCycles(); GetCardMgr().GetMockingboardCardMgr().SetCumulativeCycles();
frame.SetLoadedSaveStateFlag(true); frame.SetLoadedSaveStateFlag(true);
// NB. The following disparity should be resolved: // NB. The following disparity should be resolved:

View File

@ -48,7 +48,7 @@ static LPDIRECTSOUND g_lpDS = NULL;
// Used for muting & fading: // 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 UINT g_uNumVoices = 0;
static VOICE* g_pVoices[uMAX_VOICES] = {NULL}; static VOICE* g_pVoices[uMAX_VOICES] = {NULL};
@ -58,6 +58,21 @@ static VOICE* g_pSpeakerVoice = NULL;
bool g_bDSAvailable = false; 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) static BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext)
@ -540,8 +555,10 @@ bool DSInit()
return false; return false;
} }
hr = g_lpDS->SetCooperativeLevel(GetFrame().g_hFrameWindow, DSSCL_NORMAL); HWND hwnd = GetFrame().g_hFrameWindow;
if(FAILED(hr)) _ASSERT(hwnd);
hr = g_lpDS->SetCooperativeLevel(hwnd, DSSCL_NORMAL);
if (FAILED(hr))
{ {
if(g_fh) fprintf(g_fh, "SetCooperativeLevel failed (%08X)\n",hr); if(g_fh) fprintf(g_fh, "SetCooperativeLevel failed (%08X)\n",hr);
return false; return false;

View File

@ -30,6 +30,8 @@ struct VOICE
bRecentlyActive = false; bRecentlyActive = false;
name = ""; name = "";
} }
~VOICE(void);
}; };
typedef VOICE* PVOICE; typedef VOICE* PVOICE;

View File

@ -211,7 +211,7 @@ void LoadConfiguration(bool loadImages)
SpkrSetVolume(dwTmp, GetPropertySheet().GetVolumeMax()); SpkrSetVolume(dwTmp, GetPropertySheet().GetVolumeMax());
if(REGLOAD(TEXT(REGVALUE_MB_VOLUME), &dwTmp)) 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)) if(REGLOAD(TEXT(REGVALUE_SAVE_STATE_ON_EXIT), &dwTmp))
g_bSaveStateOnExit = dwTmp ? true : false; g_bSaveStateOnExit = dwTmp ? true : false;
@ -528,7 +528,6 @@ void ResetMachineState()
GetVideo().VideoResetState(); GetVideo().VideoResetState();
KeybReset(); KeybReset();
JoyReset(); JoyReset();
MB_Reset(true);
SpkrReset(); SpkrReset();
SetActiveCpu(GetMainCpu()); SetActiveCpu(GetMainCpu());
#ifdef USE_SPEECH_API #ifdef USE_SPEECH_API
@ -568,7 +567,6 @@ void CtrlReset()
GetPravets().Reset(); GetPravets().Reset();
GetCardMgr().Reset(false); GetCardMgr().Reset(false);
KeybReset(); KeybReset();
MB_Reset(false);
#ifdef USE_SPEECH_API #ifdef USE_SPEECH_API
g_Speech.Reset(); g_Speech.Reset();
#endif #endif

View File

@ -179,7 +179,7 @@ static void ContinueExecution(void)
const bool bWasFullSpeed = g_bFullSpeed; const bool bWasFullSpeed = g_bFullSpeed;
g_bFullSpeed = (g_dwSpeed == SPEED_MAX) || g_bFullSpeed = (g_dwSpeed == SPEED_MAX) ||
bScrollLock_FullSpeed || bScrollLock_FullSpeed ||
(GetCardMgr().GetDisk2CardMgr().IsConditionForFullSpeed() && !Spkr_IsActive() && !MB_IsActive()) || (GetCardMgr().GetDisk2CardMgr().IsConditionForFullSpeed() && !Spkr_IsActive() && !GetCardMgr().GetMockingboardCardMgr().IsActive()) ||
IsDebugSteppingAtFullSpeed(); IsDebugSteppingAtFullSpeed();
if (g_bFullSpeed) if (g_bFullSpeed)
@ -188,7 +188,7 @@ static void ContinueExecution(void)
GetFrame().VideoRedrawScreenDuringFullSpeed(0, true); // Init for full-speed mode GetFrame().VideoRedrawScreenDuringFullSpeed(0, true); // Init for full-speed mode
// Don't call Spkr_Mute() - will get speaker clicks // Don't call Spkr_Mute() - will get speaker clicks
MB_Mute(); GetCardMgr().GetMockingboardCardMgr().MuteControl(true);
SysClk_StopTimer(); SysClk_StopTimer();
#ifdef USE_SPEECH_API #ifdef USE_SPEECH_API
g_Speech.Reset(); // TODO: Put this on a timer (in emulated cycles)... otherwise CATALOG cuts out 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); GetFrame().VideoRedrawScreenAfterFullSpeed(g_dwCyclesThisFrame);
// Don't call Spkr_Unmute() // Don't call Spkr_Unmute()
MB_Unmute(); GetCardMgr().GetMockingboardCardMgr().MuteControl(false);
SysClk_StartTimerUsec(nExecutionPeriodUsec); SysClk_StartTimerUsec(nExecutionPeriodUsec);
// Switch to higher priority, eg. for audio (BUG #015394) // Switch to higher priority, eg. for audio (BUG #015394)
@ -633,7 +633,7 @@ static void OneTimeInitialization(HINSTANCE passinstance)
else if (!g_cmdLine.wavFileMockingboard.empty()) else if (!g_cmdLine.wavFileMockingboard.empty())
{ {
if (RiffInitWriteFile(g_cmdLine.wavFileMockingboard.c_str(), 44100, 2)) if (RiffInitWriteFile(g_cmdLine.wavFileMockingboard.c_str(), 44100, 2))
MB_OutputToRiff(); GetCardMgr().GetMockingboardCardMgr().OutputToRiff();
} }
// Initialize COM - so we can use CoCreateInstance // Initialize COM - so we can use CoCreateInstance
@ -678,7 +678,7 @@ static void RepeatInitialization(void)
// NB. g_OldAppleWinVersion needed by LoadConfiguration() -> Config_Load_Video() // NB. g_OldAppleWinVersion needed by LoadConfiguration() -> Config_Load_Video()
const bool bShowAboutDlg = CheckOldAppleWinVersion(); // Post: g_OldAppleWinVersion 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 bool loadImages = g_cmdLine.szSnapshotName == NULL; // don't load floppy/harddisk images if a snapshot is to be loaded later on
LoadConfiguration(loadImages); LoadConfiguration(loadImages);

View File

@ -1054,14 +1054,11 @@ LRESULT Win32Frame::WndProc(
if (!g_bRestart) // GH#564: Only save-state on shutdown (not on a restart) if (!g_bRestart) // GH#564: Only save-state on shutdown (not on a restart)
Snapshot_Shutdown(); Snapshot_Shutdown();
DebugDestroy(); DebugDestroy();
if (!g_bRestart) { GetCardMgr().Destroy();
GetCardMgr().Destroy();
}
CpuDestroy(); CpuDestroy();
MemDestroy(); MemDestroy();
SpkrDestroy(); SpkrDestroy();
Destroy(); Destroy();
MB_Destroy();
DeleteGdiObjects(); DeleteGdiObjects();
DIMouse::DirectInputUninit(window); // NB. do before window is destroyed DIMouse::DirectInputUninit(window); // NB. do before window is destroyed
PostQuitMessage(0); // Post WM_QUIT message to the thread's message queue PostQuitMessage(0); // Post WM_QUIT message to the thread's message queue
@ -1076,15 +1073,12 @@ LRESULT Win32Frame::WndProc(
CreateGdiObjects(); CreateGdiObjects();
LogFileOutput("WM_CREATE: CreateGdiObjects()\n"); LogFileOutput("WM_CREATE: CreateGdiObjects()\n");
DSInit(); DSInit(); // NB. Need g_hFrameWindow for IDirectSound::SetCooperativeLevel()
LogFileOutput("WM_CREATE: DSInit()\n"); LogFileOutput("WM_CREATE: DSInit()\n");
DIMouse::DirectInputInit(window); DIMouse::DirectInputInit(window);
LogFileOutput("WM_CREATE: DIMouse::DirectInputInit()\n"); LogFileOutput("WM_CREATE: DIMouse::DirectInputInit()\n");
MB_Initialize();
LogFileOutput("WM_CREATE: MB_Initialize()\n");
SpkrInitialize(); SpkrInitialize();
LogFileOutput("WM_CREATE: SpkrInitialize()\n"); LogFileOutput("WM_CREATE: SpkrInitialize()\n");