summaryrefslogtreecommitdiff
path: root/sid/sidplay-libs-2.1.0/libsidplay/src/config.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sid/sidplay-libs-2.1.0/libsidplay/src/config.cpp')
-rw-r--r--sid/sidplay-libs-2.1.0/libsidplay/src/config.cpp616
1 files changed, 616 insertions, 0 deletions
diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/config.cpp b/sid/sidplay-libs-2.1.0/libsidplay/src/config.cpp
new file mode 100644
index 00000000..0b4a71da
--- /dev/null
+++ b/sid/sidplay-libs-2.1.0/libsidplay/src/config.cpp
@@ -0,0 +1,616 @@
+/***************************************************************************
+ config.cpp - Library Configuration Code
+ -------------------
+ begin : Fri Jul 27 2001
+ copyright : (C) 2001 by Simon White
+ email : s_a_white@email.com
+ ***************************************************************************/
+/***************************************************************************
+ * *
+ * This program 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. *
+ * *
+ ***************************************************************************/
+/***************************************************************************
+ * $Log: config.cpp,v $
+ * Revision 1.29 2002/10/15 18:14:02 s_a_white
+ * Removed upper limit frequency limit check to allow for oversampling.
+ *
+ * Revision 1.28 2002/10/02 19:46:36 s_a_white
+ * RSID support & fix sid model forced operation.
+ *
+ * Revision 1.27 2002/09/09 18:09:06 s_a_white
+ * Added error message for psid specific flag set in strict real C64 mode.
+ *
+ * Revision 1.26 2002/08/10 22:35:56 s_a_white
+ * Small clock speed fix for when both clockSpeed and clockDefault are set
+ * to SID2_CLOCK_CORRECT.
+ *
+ * Revision 1.25 2002/07/17 19:25:28 s_a_white
+ * Temp fix to allow SID model to change for current builder.
+ *
+ * Revision 1.24 2002/04/14 21:46:50 s_a_white
+ * PlaySID reads fixed to come from RAM only.
+ *
+ * Revision 1.23 2002/03/11 18:01:30 s_a_white
+ * Prevent lockup if config call fails with existing and old configurations.
+ *
+ * Revision 1.22 2002/03/04 19:05:49 s_a_white
+ * Fix C++ use of nothrow.
+ *
+ * Revision 1.21 2002/03/03 22:01:58 s_a_white
+ * New clock speed & sid model interface.
+ *
+ * Revision 1.20 2002/02/18 21:59:10 s_a_white
+ * Added two new clock modes (FIXED). Seems to be a requirement for
+ * HVSC/sidplayw.
+ *
+ * Revision 1.19 2002/02/04 22:08:14 s_a_white
+ * Fixed main voice/sample gains.
+ *
+ * Revision 1.18 2002/01/29 21:50:33 s_a_white
+ * Auto switching to a better emulation mode. m_tuneInfo reloaded after a
+ * config. Initial code added to support more than two sids.
+ *
+ * Revision 1.17 2002/01/16 19:11:38 s_a_white
+ * Always release sid emulations now on a call to sidCreate until a better
+ * method is implemented for hardware emulations with locked sids.
+ *
+ * Revision 1.16 2002/01/16 08:23:45 s_a_white
+ * Force a clock speed when unknown.
+ *
+ * Revision 1.15 2002/01/15 19:12:54 s_a_white
+ * PSID2NG update.
+ *
+ * Revision 1.14 2002/01/14 23:18:56 s_a_white
+ * Make sure xsid releases the old sid emulation when there are errors gaining
+ * a new one.
+ *
+ * Revision 1.13 2001/12/20 20:15:23 s_a_white
+ * Fixed bad environment initialisation when switching to legacy modes.
+ *
+ * Revision 1.12 2001/12/13 08:28:08 s_a_white
+ * Added namespace support to fix problems with xsidplay.
+ *
+ * Revision 1.11 2001/12/11 19:24:15 s_a_white
+ * More GCC3 Fixes.
+ *
+ * Revision 1.10 2001/11/23 22:59:59 s_a_white
+ * Added new header
+ *
+ * Revision 1.9 2001/10/02 18:27:55 s_a_white
+ * Updated to use new sidbuilder classes.
+ *
+ * Revision 1.8 2001/09/20 20:33:54 s_a_white
+ * sid2 now gets correctly set to nullsid for a bad create call.
+ *
+ * Revision 1.7 2001/09/20 19:34:11 s_a_white
+ * Error checking added for the builder create calls.
+ *
+ * Revision 1.6 2001/09/17 19:02:38 s_a_white
+ * Now uses fixed point maths for sample output and rtc.
+ *
+ * Revision 1.5 2001/09/01 11:13:56 s_a_white
+ * Fixes sidplay1 environment modes.
+ *
+ * Revision 1.4 2001/08/20 18:24:50 s_a_white
+ * tuneInfo in the info structure now correctly has the sid revision setup.
+ *
+ * Revision 1.3 2001/08/12 18:22:45 s_a_white
+ * Fixed bug in Player::sidEmulation call.
+ *
+ * Revision 1.2 2001/07/27 12:51:40 s_a_white
+ * Removed warning.
+ *
+ * Revision 1.1 2001/07/27 12:12:23 s_a_white
+ * Initial release.
+ *
+ ***************************************************************************/
+
+#include "sid2types.h"
+#include "player.h"
+
+#ifdef HAVE_EXCEPTIONS
+# include <new>
+#endif
+
+SIDPLAY2_NAMESPACE_START
+
+// An instance of this structure is used to transport emulator settings
+// to and from the interface class.
+
+int Player::config (const sid2_config_t &cfg)
+{
+ if (m_running)
+ {
+ m_errorString = ERR_CONF_WHILST_ACTIVE;
+ goto Player_configure_error;
+ }
+
+ // Check for base sampling frequency
+ if (cfg.frequency < 4000)
+ { // Rev 1.6 (saw) - Added descriptive error
+ m_errorString = ERR_UNSUPPORTED_FREQ;
+ goto Player_configure_error;
+ }
+
+ // Check for legal precision
+ switch (cfg.precision)
+ {
+ case 8:
+ case 16:
+ case 24:
+ if (cfg.precision > SID2_MAX_PRECISION)
+ { // Rev 1.6 (saw) - Added descriptive error
+ m_errorString = ERR_UNSUPPORTED_PRECISION;
+ goto Player_configure_error;
+ }
+ break;
+
+ default:
+ // Rev 1.6 (saw) - Added descriptive error
+ m_errorString = ERR_UNSUPPORTED_PRECISION;
+ goto Player_configure_error;
+ }
+
+ // Only do these if we have a loaded tune
+ if (m_tune)
+ {
+ float64_t cpuFreq;
+ // Reset tune info
+ m_tune->getInfo(m_tuneInfo);
+
+ // External Setups
+ if (sidCreate (cfg.sidEmulation, cfg.sidModel, cfg.sidDefault) < 0)
+ {
+ m_errorString = cfg.sidEmulation->error ();
+ m_cfg.sidEmulation = NULL;
+ goto Player_configure_restore;
+ }
+ // Must be this order:
+ // Determine clock speed
+ cpuFreq = clockSpeed (cfg.clockSpeed, cfg.clockDefault,
+ cfg.clockForced);
+ // Fixed point conversion 16.16
+ m_samplePeriod = (event_clock_t) (cpuFreq /
+ (float64_t) cfg.frequency *
+ (1 << 16) * m_fastForwardFactor);
+ // Setup fake cia
+ sid6526.clock ((uint_least16_t)(cpuFreq / VIC_FREQ_PAL + 0.5));
+ if (m_tuneInfo.songSpeed == SIDTUNE_SPEED_CIA_1A ||
+ m_tuneInfo.clockSpeed == SIDTUNE_CLOCK_NTSC)
+ {
+ sid6526.clock ((uint_least16_t)(cpuFreq / VIC_FREQ_NTSC + 0.5));
+ }
+ // Configure, setup and install C64 environment/events
+ if (environment (cfg.environment) < 0)
+ goto Player_configure_restore;
+ // Start the real time clock event
+ rtc.clock (cpuFreq);
+ }
+ sidSamples (cfg.sidSamples);
+
+ // All parameters check out, so configure player.
+ m_info.channels = 1;
+ if (cfg.playback == sid2_stereo)
+ m_info.channels++;
+
+ m_sidAddress[0] = m_tuneInfo.sidChipBase1;
+ m_sidAddress[1] = m_tuneInfo.sidChipBase2;
+
+ // Only force dual sids if second wasn't detected
+ if (!m_sidAddress[1] && cfg.forceDualSids)
+ m_sidAddress[1] = 0xd500; // Assumed
+
+ m_leftVolume = cfg.leftVolume;
+ m_rightVolume = cfg.rightVolume;
+
+ if (cfg.playback != sid2_mono)
+ { // Try Spliting channels across 2 sids
+ if (!m_sidAddress[1])
+ {
+ m_sidAddress[1] = m_sidAddress[0];
+
+ // Mute Voices
+ sid[0]->voice (0, 0, true);
+ sid[0]->voice (2, 0, true);
+ sid[1]->voice (1, 0, true);
+ // 2 Voices scaled to unity from 4 (was !SID_VOL)
+ // m_leftVolume *= 2;
+ // m_rightVolume *= 2;
+ // 2 Voices scaled to unity from 3 (was SID_VOL)
+ // m_leftVolume *= 3;
+ // m_leftVolume /= 2;
+ // m_rightVolume *= 3;
+ // m_rightVolume /= 2;
+ }
+
+ if (cfg.playback == sid2_left)
+ xsid.mute (true);
+ }
+
+ // Setup the audio side, depending on the audio hardware
+ // and the information returned by sidtune
+ switch (cfg.precision)
+ {
+ case 8:
+ if (!m_sidAddress[1])
+ {
+ if (cfg.playback == sid2_stereo)
+ output = &Player::stereoOut8MonoIn;
+ else
+ output = &Player::monoOut8MonoIn;
+ }
+ else
+ {
+ switch (cfg.playback)
+ {
+ case sid2_stereo: // Stereo Hardware
+ output = &Player::stereoOut8StereoIn;
+ break;
+
+ case sid2_right: // Mono Hardware,
+ output = &Player::monoOut8StereoRIn;
+ break;
+
+ case sid2_left:
+ output = &Player::monoOut8MonoIn;
+ break;
+
+ case sid2_mono:
+ output = &Player::monoOut8StereoIn;
+ break;
+ }
+ }
+ break;
+
+ case 16:
+ if (!m_sidAddress[1])
+ {
+ if (cfg.playback == sid2_stereo)
+ output = &Player::stereoOut16MonoIn;
+ else
+ output = &Player::monoOut16MonoIn;
+ }
+ else
+ {
+ switch (cfg.playback)
+ {
+ case sid2_stereo: // Stereo Hardware
+ output = &Player::stereoOut16StereoIn;
+ break;
+
+ case sid2_right: // Mono Hardware,
+ output = &Player::monoOut16StereoRIn;
+ break;
+
+ case sid2_left:
+ output = &Player::monoOut16MonoIn;
+ break;
+
+ case sid2_mono:
+ output = &Player::monoOut16StereoIn;
+ break;
+ }
+ }
+ }
+
+ // Update Configuration
+ m_cfg = cfg;
+
+ if (m_cfg.optimisation > SID2_MAX_OPTIMISATION)
+ m_cfg.optimisation = SID2_MAX_OPTIMISATION;
+return 0;
+
+Player_configure_restore:
+ // Try restoring old configuration
+ if (&m_cfg != &cfg)
+ config (m_cfg);
+Player_configure_error:
+ return -1;
+}
+
+// Clock speed changes due to loading a new song
+float64_t Player::clockSpeed (sid2_clock_t userClock, sid2_clock_t defaultClock,
+ bool forced)
+{
+ float64_t cpuFreq = CLOCK_FREQ_PAL;
+
+ // Detect the Correct Song Speed
+ // Determine song speed when unknown
+ if (m_tuneInfo.clockSpeed == SIDTUNE_CLOCK_UNKNOWN)
+ {
+ switch (defaultClock)
+ {
+ case SID2_CLOCK_PAL:
+ m_tuneInfo.clockSpeed = SIDTUNE_CLOCK_PAL;
+ break;
+ case SID2_CLOCK_NTSC:
+ m_tuneInfo.clockSpeed = SIDTUNE_CLOCK_NTSC;
+ break;
+ case SID2_CLOCK_CORRECT:
+ // No default so base it on emulation clock
+ m_tuneInfo.clockSpeed = SIDTUNE_CLOCK_ANY;
+ }
+ }
+
+ // Since song will run correct at any clock speed
+ // set tune speed to the current emulation
+ if (m_tuneInfo.clockSpeed == SIDTUNE_CLOCK_ANY)
+ {
+ if (userClock == SID2_CLOCK_CORRECT)
+ userClock = defaultClock;
+
+ switch (userClock)
+ {
+ case SID2_CLOCK_NTSC:
+ m_tuneInfo.clockSpeed = SIDTUNE_CLOCK_NTSC;
+ break;
+ case SID2_CLOCK_PAL:
+ default:
+ m_tuneInfo.clockSpeed = SIDTUNE_CLOCK_PAL;
+ break;
+ }
+ }
+
+ if (userClock == SID2_CLOCK_CORRECT)
+ {
+ switch (m_tuneInfo.clockSpeed)
+ {
+ case SIDTUNE_CLOCK_NTSC:
+ userClock = SID2_CLOCK_NTSC;
+ break;
+ case SIDTUNE_CLOCK_PAL:
+ userClock = SID2_CLOCK_PAL;
+ break;
+ }
+ }
+
+ if (forced)
+ {
+ m_tuneInfo.clockSpeed = SIDTUNE_CLOCK_PAL;
+ if (userClock == SID2_CLOCK_NTSC)
+ m_tuneInfo.clockSpeed = SIDTUNE_CLOCK_NTSC;
+ }
+
+ if (m_tuneInfo.clockSpeed == SIDTUNE_CLOCK_PAL)
+ vic.chip (MOS6569);
+ else // if (tuneInfo.clockSpeed == SIDTUNE_CLOCK_NTSC)
+ vic.chip (MOS6567R8);
+
+ if (userClock == SID2_CLOCK_PAL)
+ {
+ cpuFreq = CLOCK_FREQ_PAL;
+ m_tuneInfo.speedString = TXT_PAL_VBI;
+ if (m_tuneInfo.songSpeed == SIDTUNE_SPEED_CIA_1A)
+ m_tuneInfo.speedString = TXT_PAL_CIA;
+ else if (m_tuneInfo.clockSpeed == SIDTUNE_CLOCK_NTSC)
+ m_tuneInfo.speedString = TXT_PAL_VBI_FIXED;
+ }
+ else // if (userClock == SID2_CLOCK_NTSC)
+ {
+ cpuFreq = CLOCK_FREQ_NTSC;
+ m_tuneInfo.speedString = TXT_NTSC_VBI;
+ if (m_tuneInfo.songSpeed == SIDTUNE_SPEED_CIA_1A)
+ m_tuneInfo.speedString = TXT_NTSC_CIA;
+ else if (m_tuneInfo.clockSpeed == SIDTUNE_CLOCK_PAL)
+ m_tuneInfo.speedString = TXT_NTSC_VBI_FIXED;
+ }
+ return cpuFreq;
+}
+
+int Player::environment (sid2_env_t env)
+{
+ switch (m_tuneInfo.compatibility)
+ {
+ case SIDTUNE_COMPATIBILITY_R64:
+ env = sid2_envR;
+ break;
+ case SIDTUNE_COMPATIBILITY_PSID:
+ if (env == sid2_envR)
+ env = sid2_envBS;
+ }
+
+ // Environment already set?
+ if (!(m_ram && (m_info.environment == env)))
+ { // Setup new player environment
+ m_info.environment = env;
+ if (m_ram)
+ {
+ if (m_ram == m_rom)
+ delete [] m_ram;
+ else
+ {
+ delete [] m_rom;
+ delete [] m_ram;
+ }
+ }
+
+#ifdef HAVE_EXCEPTIONS
+ m_ram = new(std::nothrow) uint8_t[0x10000];
+#else
+ m_ram = new uint8_t[0x10000];
+#endif
+
+ // Setup the access functions to the environment
+ // and the properties the memory has.
+ if (m_info.environment == sid2_envPS)
+ { // Playsid has no roms and SID exists in ram space
+ m_rom = m_ram;
+ m_readMemByte = &Player::readMemByte_player;
+ m_writeMemByte = &Player::writeMemByte_playsid;
+ m_readMemDataByte = &Player::readMemByte_plain;
+ }
+ else
+ {
+#ifdef HAVE_EXCEPTIONS
+ m_rom = new(std::nothrow) uint8_t[0x10000];
+#else
+ m_rom = new uint8_t[0x10000];
+#endif
+
+ switch (m_info.environment)
+ {
+ case sid2_envTP:
+ m_readMemByte = &Player::readMemByte_player;
+ m_writeMemByte = &Player::writeMemByte_sidplay;
+ m_readMemDataByte = &Player::readMemByte_sidplaytp;
+ break;
+
+ //case sid2_envTR:
+ case sid2_envBS:
+ m_readMemByte = &Player::readMemByte_player;
+ m_writeMemByte = &Player::writeMemByte_sidplay;
+ m_readMemDataByte = &Player::readMemByte_sidplaybs;
+ break;
+
+ case sid2_envR:
+ default: // <-- Just to please compiler
+ m_readMemByte = &Player::readMemByte_player;
+ m_writeMemByte = &Player::writeMemByte_sidplay;
+ m_readMemDataByte = &Player::readMemByte_sidplaybs;
+ break;
+ }
+ }
+ }
+
+ { // Have to reload the song into memory as
+ // everything has changed
+ int ret;
+ sid2_env_t old = m_info.environment;
+ m_info.environment = env;
+ ret = initialise ();
+ m_info.environment = old;
+ return ret;
+ }
+}
+
+// Integrate SID emulation from the builder class into
+// libsidplay2
+int Player::sidCreate (sidbuilder *builder, sid2_model_t userModel,
+ sid2_model_t defaultModel)
+{
+ sid[0] = xsid.emulation ();
+ /* @FIXME@ Removed as prevents SID
+ * Model being updated
+ ****************************************
+ // If we are already using the emulation
+ // then don't change
+ if (builder == sid[0]->builder ())
+ {
+ sid[0] = &xsid;
+ return 0;
+ }
+ ****************************************/
+
+ // Make xsid forget it's emulation
+ xsid.emulation (&nullsid);
+
+ { // Release old sids
+ for (int i = 0; i < SID2_MAX_SIDS; i++)
+ {
+ sidbuilder *b;
+ b = sid[i]->builder ();
+ if (b)
+ b->unlock (sid[i]);
+ }
+ }
+
+ if (!builder)
+ { // No sid
+ for (int i = 0; i < SID2_MAX_SIDS; i++)
+ sid[i] = &nullsid;
+ }
+ else
+ { // Detect the Correct SID model
+ // Determine model when unknown
+ if (m_tuneInfo.sidModel == SIDTUNE_SIDMODEL_UNKNOWN)
+ {
+ switch (defaultModel)
+ {
+ case SID2_MOS6581:
+ m_tuneInfo.sidModel = SIDTUNE_SIDMODEL_6581;
+ break;
+ case SID2_MOS8580:
+ m_tuneInfo.sidModel = SIDTUNE_SIDMODEL_8580;
+ break;
+ case SID2_MODEL_CORRECT:
+ // No default so base it on emulation clock
+ m_tuneInfo.sidModel = SIDTUNE_SIDMODEL_ANY;
+ }
+ }
+
+ // Since song will run correct on any sid model
+ // set it to the current emulation
+ if (m_tuneInfo.sidModel == SIDTUNE_SIDMODEL_ANY)
+ {
+ if (userModel == SID2_MODEL_CORRECT)
+ userModel = defaultModel;
+
+ switch (userModel)
+ {
+ case SID2_MOS8580:
+ m_tuneInfo.sidModel = SIDTUNE_SIDMODEL_8580;
+ break;
+ case SID2_MOS6581:
+ default:
+ m_tuneInfo.sidModel = SIDTUNE_SIDMODEL_6581;
+ break;
+ }
+ }
+
+ switch (userModel)
+ {
+ case SID2_MODEL_CORRECT:
+ switch (m_tuneInfo.sidModel)
+ {
+ case SIDTUNE_SIDMODEL_8580:
+ userModel = SID2_MOS8580;
+ break;
+ case SIDTUNE_SIDMODEL_6581:
+ userModel = SID2_MOS6581;
+ break;
+ }
+ break;
+ // Fixup tune information if model is forced
+ case SID2_MOS6581:
+ m_tuneInfo.sidModel = SIDTUNE_SIDMODEL_6581;
+ break;
+ case SID2_MOS8580:
+ m_tuneInfo.sidModel = SIDTUNE_SIDMODEL_8580;
+ break;
+ }
+
+ for (int i = 0; i < SID2_MAX_SIDS; i++)
+ { // Get first SID emulation
+ sid[i] = builder->lock (this, userModel);
+ if (!sid[i])
+ sid[i] = &nullsid;
+ if ((i == 0) && !*builder)
+ return -1;
+ }
+ }
+ xsid.emulation (sid[0]);
+ sid[0] = &xsid;
+ return 0;
+}
+
+void Player::sidSamples (bool enable)
+{
+ int_least8_t gain = 0;
+ xsid.sidSamples (enable);
+
+ // Now balance voices
+ if (!enable)
+ gain = -25;
+
+ xsid.gain (-100 - gain);
+ sid[0] = xsid.emulation ();
+ for (int i = 0; i < SID2_MAX_SIDS; i++)
+ sid[i]->gain (gain);
+ sid[0] = &xsid;
+}
+
+SIDPLAY2_NAMESPACE_STOP