summaryrefslogtreecommitdiff
path: root/libsidplay2/sidplay-libs-2.1.0/libsidplay/src/xsid/xsid.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libsidplay2/sidplay-libs-2.1.0/libsidplay/src/xsid/xsid.cpp')
-rw-r--r--libsidplay2/sidplay-libs-2.1.0/libsidplay/src/xsid/xsid.cpp598
1 files changed, 0 insertions, 598 deletions
diff --git a/libsidplay2/sidplay-libs-2.1.0/libsidplay/src/xsid/xsid.cpp b/libsidplay2/sidplay-libs-2.1.0/libsidplay/src/xsid/xsid.cpp
deleted file mode 100644
index 29b5c909..00000000
--- a/libsidplay2/sidplay-libs-2.1.0/libsidplay/src/xsid/xsid.cpp
+++ /dev/null
@@ -1,598 +0,0 @@
-/***************************************************************************
- xsid.cpp - Support for Playsids Extended
- Registers
- -------------------
- begin : Tue Jun 20 2000
- copyright : (C) 2000 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: xsid.cpp,v $
- * Revision 1.20 2002/07/17 21:19:54 s_a_white
- * Minor non sid sample mode fixes.
- *
- * Revision 1.19 2002/02/21 20:26:13 s_a_white
- * Nolonger default to Galway Mode when Noise samples init incorrectly. Fixes
- * VARIOUS/S-Z/Zyron/Bouncy_Balls.sid (HVSC).
- *
- * Revision 1.18 2002/02/17 16:34:39 s_a_white
- * New reset interface
- *
- * Revision 1.17 2002/01/28 19:31:42 s_a_white
- * PSID sample improvements.
- *
- * Revision 1.16 2001/10/02 18:03:03 s_a_white
- * Support updated sidbuilder class interface.
- *
- * Revision 1.15 2001/09/17 18:36:41 s_a_white
- * Changed object construction to prevent multiple resets.
- *
- * Revision 1.14 2001/07/14 12:59:53 s_a_white
- * XSID effeciency increased. Now uses new component classes and event
- * generation.
- *
- * Revision 1.13 2001/03/25 19:51:23 s_a_white
- * Performance update.
- *
- * Revision 1.12 2001/03/19 23:40:19 s_a_white
- * Removed repeat definition of state for debug mode.
- *
- * Revision 1.11 2001/03/09 22:27:13 s_a_white
- * Speed optimisation update.
- *
- * Revision 1.10 2001/03/01 23:45:58 s_a_white
- * Combined both through sid and non-through sid modes. Can be selected
- * at runtime now.
- *
- * Revision 1.9 2001/02/21 21:46:34 s_a_white
- * 0x1d = 0 now fixed. Limit checking on sid volume. This helps us determine
- * even better what the sample offset should be (fixes Skate and Die).
- *
- * Revision 1.8 2001/02/07 21:02:30 s_a_white
- * Supported for delaying samples for frame simulation. New alogarithm to
- * better guess original tunes volume when playing samples.
- *
- * Revision 1.7 2000/12/12 22:51:01 s_a_white
- * Bug Fix #122033.
- *
- ***************************************************************************/
-
-#include <string.h>
-#include <stdio.h>
-#include "sidendian.h"
-#include "xsid.h"
-
-
-// Convert from 4 bit resolution to 8 bits
-/* Rev 2.0.5 (saw) - Removed for a more non-linear equivalent
- which better models the SIDS master volume register
-const int8_t XSID::sampleConvertTable[16] =
-{
- '\x80', '\x91', '\xa2', '\xb3', '\xc4', '\xd5', '\xe6', '\xf7',
- '\x08', '\x19', '\x2a', '\x3b', '\x4c', '\x5d', '\x6e', '\x7f'
-};
-*/
-const int8_t XSID::sampleConvertTable[16] =
-{
- '\x80', '\x94', '\xa9', '\xbc', '\xce', '\xe1', '\xf2', '\x03',
- '\x1b', '\x2a', '\x3b', '\x49', '\x58', '\x66', '\x73', '\x7f'
-};
-
-const char *XSID::credit =
-{
- "xSID (Extended SID) Engine:\0"
- "\tCopyright (C) 2000 Simon White <sidplay2@email.com>\0"
-};
-
-
-channel::channel (const char * const name, EventContext *context, XSID *xsid)
-:m_name(name),
- m_context(*context),
- m_xsid(*xsid),
- sampleEvent(this),
- galwayEvent(this)
-{
- memset (reg, 0, sizeof (reg));
- active = true;
- reset ();
-}
-
-void channel::reset ()
-{
- galVolume = 0; // This is left to free run until reset
- mode = FM_NONE;
- free ();
-}
-
-void channel::free ()
-{
- active = false;
- cycleCount = 0;
- sampleLimit = 0;
- // Set XSID to stopped state
- reg[convertAddr (0x1d)] = 0;
- silence ();
-}
-
-inline int8_t channel::output ()
-{
- outputs++;
- return sample;
-}
-
-void channel::checkForInit ()
-{ // Check to see mode of operation
- // See xsid documentation
- switch (reg[convertAddr (0x1d)])
- {
- case 0xFF:
- case 0xFE:
- case 0xFC:
- sampleInit ();
- break;
- case 0xFD:
- if (!active)
- return;
- free (); // Stop
- // Calculate the sample offset
- m_xsid.sampleOffsetCalc ();
- break;
- case 0x00:
- break;
- default:
- galwayInit ();
- }
-}
-
-void channel::sampleInit ()
-{
- uint8_t *r;
- if (active && (mode == FM_GALWAY))
- return;
-
-#ifdef XSID_DEBUG
- printf ("XSID [%s]: Sample Init\n", m_name);
- if (active && (mode == FM_HUELS))
- printf ("XSID [%s]: Stopping Playing Sample\n", m_name);
-#endif
-
- // Check all important parameters are legal
- r = &reg[convertAddr (0x1d)];
- volShift = (uint_least8_t) (0 - (int8_t) r[0]) >> 1;
- r[0] = 0;
- // Use endian_16 as can't g
- r = &reg[convertAddr (0x1e)];
- address = endian_16 (r[1], r[0]);
- r = &reg[convertAddr (0x3d)];
- samEndAddr = endian_16 (r[1], r[0]);
- if (samEndAddr <= address) return;
- samScale = reg[convertAddr (0x5f)];
- r = &reg[convertAddr (0x5d)];
- samPeriod = endian_16 (r[1], r[0]) >> samScale;
- if (!samPeriod)
- { // Stop this channel
- reg[convertAddr (0x1d)] = 0xfd;
- checkForInit ();
- return;
- }
-
- // Load the other parameters
- samNibble = 0;
- samRepeat = reg[convertAddr (0x3f)];
- samOrder = reg[convertAddr (0x7d)];
- r = &reg[convertAddr (0x7e)];
- samRepeatAddr = endian_16 (r[1], r[0]);
- cycleCount = samPeriod;
-
- // Support Galway Samples, but that
- // mode it setup only when as Galway
- // Noise sequence begins
- if (mode == FM_NONE)
- mode = FM_HUELS;
-
- active = true;
- cycles = 0;
- outputs = 0;
-
- sampleLimit = 8 >> volShift;
- sample = sampleCalculate ();
-
- // Calculate the sample offset
- m_xsid.sampleOffsetCalc ();
-
-#ifdef XSID_DEBUG
-# if XSID_DEBUG > 1
- printf ("XSID [%s]: Sample Start Address: 0x%04x\n", m_name, address);
- printf ("XSID [%s]: Sample End Address: 0x%04x\n", m_name, samEndAddr);
- printf ("XSID [%s]: Sample Repeat Address: 0x%04x\n", m_name, samRepeatAddr);
- printf ("XSID [%s]: Sample Period: %u\n", m_name, samPeriod);
- printf ("XSID [%s]: Sample Repeat: %u\n", m_name, samRepeat);
- printf ("XSID [%s]: Sample Order: %u\n", m_name, samOrder);
-# endif
- printf ("XSID [%s]: Sample Start\n", m_name);
-#endif // XSID_DEBUG
-
- // Schedule a sample update
- m_context.schedule (&m_xsid, 0);
- m_context.schedule (&sampleEvent, cycleCount);
-}
-
-void channel::sampleClock ()
-{
- cycleCount = samPeriod;
- if (address >= samEndAddr)
- {
- if (samRepeat != 0xFF)
- {
- if (samRepeat)
- samRepeat--;
- else
- samRepeatAddr = address;
- }
-
- address = samRepeatAddr;
- if (address >= samEndAddr)
- { // The sequence has completed
- uint8_t &status = reg[convertAddr (0x1d)];
- if (!status)
- status = 0xfd;
- if (status != 0xfd)
- active = false;
-#ifdef XSID_DEBUG
- printf ("XSID [%s]: Sample Stop (%lu Cycles, %lu Outputs)\n",
- m_name, cycles, outputs);
- if (status != 0xfd)
- printf ("XSID [%s]: Starting Delayed Sequence\n", m_name);
-#endif
- checkForInit ();
- return;
- }
- }
-
- // We have reached the required sample
- // So now we need to extract the right nibble
- sample = sampleCalculate ();
- cycles += cycleCount;
- // Schedule a sample update
- m_context.schedule (&sampleEvent, cycleCount);
- m_context.schedule (&m_xsid, 0);
-}
-
-int8_t channel::sampleCalculate ()
-{
- uint_least8_t tempSample = m_xsid.readMemByte (address);
- if (samOrder == SO_LOWHIGH)
- {
- if (samScale == 0)
- {
- if (samNibble != 0)
- tempSample >>= 4;
- }
- // AND 15 further below.
- }
- else // if (samOrder == SO_HIGHLOW)
- {
- if (samScale == 0)
- {
- if (samNibble == 0)
- tempSample >>= 4;
- }
- else // if (samScale != 0)
- tempSample >>= 4;
- // AND 15 further below.
- }
-
- // Move to next address
- address += samNibble;
- samNibble ^= 1;
- return (int8_t) ((tempSample & 0x0f) - 0x08) >> volShift;
-}
-
-void channel::galwayInit()
-{
- uint8_t *r;
- if (active)
- return;
-
-#ifdef XSID_DEBUG
- printf ("XSID [%s]: Galway Init\n", m_name);
-#endif
-
- // Check all important parameters are legal
- r = &reg[convertAddr (0x1d)];
- galTones = r[0];
- r[0] = 0;
- galInitLength = reg[convertAddr (0x3d)];
- if (!galInitLength) return;
- galLoopWait = reg[convertAddr (0x3f)];
- if (!galLoopWait) return;
- galNullWait = reg[convertAddr (0x5d)];
- if (!galNullWait) return;
-
- // Load the other parameters
- r = &reg[convertAddr(0x1e)];
- address = endian_16 (r[1], r[0]);
- volShift = reg[convertAddr (0x3e)] & 0x0f;
- mode = FM_GALWAY;
- active = true;
- cycles = 0;
- outputs = 0;
-
- sampleLimit = 8;
- sample = (int8_t) galVolume - 8;
- galwayTonePeriod ();
-
- // Calculate the sample offset
- m_xsid.sampleOffsetCalc ();
-
-#ifdef XSID_DEBUG
- printf ("XSID [%s]: Galway Start\n", m_name);
-#endif
-
- // Schedule a sample update
- m_context.schedule (&m_xsid, 0);
- m_context.schedule (&galwayEvent, cycleCount);
-}
-
-void channel::galwayClock ()
-{
- if (--galLength)
- cycleCount = samPeriod;
- else if (galTones == 0xff)
- { // The sequence has completed
- uint8_t &status = reg[convertAddr (0x1d)];
- if (!status)
- status = 0xfd;
- if (status != 0xfd)
- active = false;
-#ifdef XSID_DEBUG
- printf ("XSID [%s]: Galway Stop (%lu Cycles, %lu Outputs)\n",
- m_name, cycles, outputs);
- if (status != 0xfd)
- printf ("XSID [%s]: Starting Delayed Sequence\n", m_name);
-#endif
- checkForInit ();
- return;
- }
- else
- galwayTonePeriod ();
-
- // See Galway Example...
- galVolume += volShift;
- galVolume &= 0x0f;
- sample = (int8_t) galVolume - 8;
- cycles += cycleCount;
- m_context.schedule (&galwayEvent, cycleCount);
- m_context.schedule (&m_xsid, 0);
-}
-
-void channel::galwayTonePeriod ()
-{ // Calculate the number of cycles over which sample should last
- galLength = galInitLength;
- samPeriod = m_xsid.readMemByte (address + galTones);
- samPeriod *= galLoopWait;
- samPeriod += galNullWait;
- cycleCount = samPeriod;
-#if XSID_DEBUG > 2
- printf ("XSID [%s]: Galway Settings\n", m_name);
- printf ("XSID [%s]: Length %u, LoopWait %u, NullWait %u\n",
- m_name, galLength, galLoopWait, galNullWait);
- printf ("XSID [%s]: Tones %u, Data %u\n",
- m_name, galTones, m_xsid.readMemByte (address + galTones));
-#endif
- galTones--;
-}
-
-void channel::silence ()
-{
- sample = 0;
- m_context.cancel (&sampleEvent);
- m_context.cancel (&galwayEvent);
- m_context.schedule (&m_xsid, 0);
-}
-
-
-XSID::XSID (EventContext *context)
-:sidemu(NULL),
- Event("xSID"),
- ch4("CH4", context, this),
- ch5("CH5", context, this),
- muted(false),
- suppressed(false),
- wasRunning(false)
-{
- sidSamples (true);
-}
-
-void XSID::reset (uint8_t)
-{
- ch4.reset ();
- ch5.reset ();
- suppressed = false;
- wasRunning = false;
-}
-
-void XSID::event (void)
-{
- if (ch4 || ch5)
- {
- setSidData0x18 ();
- wasRunning = true;
- }
- else if (wasRunning)
- {
- recallSidData0x18 ();
- wasRunning = false;
- }
-}
-
-// Use Suppress to delay the samples and start them later
-// Effectivly allows running samples in a frame based mode.
-void XSID::suppress (bool enable)
-{
- // @FIXME@: Mute Temporary Hack
- suppressed = enable;
- if (!suppressed)
- { // Get the channels running
-#if XSID_DEBUG
- printf ("XSID: Un-suppressing\n");
-#endif
- ch4.checkForInit ();
- ch5.checkForInit ();
- }
-#if XSID_DEBUG
- else
- printf ("XSID: Suppressing\n");
-#endif
-}
-
-// By muting samples they will start and play the at the
-// appropriate time but no sound is produced. Un-muting
-// will cause sound output from the current play position.
-void XSID::mute (bool enable)
-{
- if (!muted && enable && wasRunning)
- recallSidData0x18 ();
- muted = enable;
-}
-
-void XSID::write (uint_least16_t addr, uint8_t data)
-{
- channel *ch;
- uint8_t tempAddr;
-
- // Make sure address is legal
- if ((addr & 0xfe8c) ^ 0x000c)
- return;
-
- ch = &ch4;
- if (addr & 0x0100)
- ch = &ch5;
-
- tempAddr = (uint8_t) addr;
- ch->write (tempAddr, data);
-#if XSID_DEBUG > 1
- printf ("XSID: Addr 0x%02x, Data 0x%02x\n", tempAddr, data);
-#endif
-
- if (tempAddr == 0x1d)
- {
- if (suppressed)
- {
-#if XSID_DEBUG
- printf ("XSID: Initialise Suppressed\n");
-#endif
- return;
- }
- ch->checkForInit ();
- }
-}
-
-int8_t XSID::sampleOutput (void)
-{
- int8_t sample;
- sample = ch4.output ();
- sample += ch5.output ();
- // Automatically compensated for by C64 code
- //return (sample >> 1);
- return sample;
-}
-
-void XSID::setSidData0x18 (void)
-{
- if (!_sidSamples || muted)
- return;
-
- uint8_t data = (sidData0x18 & 0xf0);
- data |= ((sampleOffset + sampleOutput ()) & 0x0f);
-
-#ifdef XSID_DEBUG
- if ((sampleOffset + sampleOutput ()) > 0x0f)
- {
- printf ("XSID: Sample Wrapped [offset %u, sample %d]\n",
- sampleOffset, sampleOutput ());
- }
-# if XSID_DEBUG > 1
- printf ("XSID: Writing Sample to SID Volume [0x%02x]\n", data);
-# endif
-#endif // XSID_DEBUG
-
- writeMemByte (data);
-}
-
-void XSID::recallSidData0x18 (void)
-{ // Rev 2.0.5 (saw) - Changed to recall volume differently depending on mode
- // Normally after samples volume should be restored to half volume,
- // however, Galway Tunes sound horrible and seem to require setting back to
- // the original volume. Setting back to the original volume for normal
- // samples can have nasty pulsing effects
- if (ch4.isGalway ())
- {
- if (_sidSamples && !muted)
- writeMemByte (sidData0x18);
- }
- else
- setSidData0x18 ();
-}
-
-void XSID::sampleOffsetCalc (void)
-{
- // Try to determine a sensible offset between voice
- // and sample volumes.
- uint_least8_t lower = ch4.limit () + ch5.limit ();
- uint_least8_t upper;
-
- // Both channels seem to be off. Keep current offset!
- if (!lower)
- return;
-
- sampleOffset = sidData0x18 & 0x0f;
-
- // Is possible to compensate for both channels
- // set to 4 bits here, but should never happen.
- if (lower > 8)
- lower >>= 1;
- upper = 0x0f - lower + 1;
-
- // Check against limits
- if (sampleOffset < lower)
- sampleOffset = lower;
- else if (sampleOffset > upper)
- sampleOffset = upper;
-
-#ifdef XSID_DEBUG
- printf ("XSID: Sample Offset %d based on channel(s) ", sampleOffset);
- if (ch4)
- printf ("4 ");
- if (ch5)
- printf ("5");
- printf ("\n");
-#endif // XSID_DEBUG
-}
-
-bool XSID::storeSidData0x18 (uint8_t data)
-{
- sidData0x18 = data;
- if (ch4 || ch5)
- { // Force volume to be changed at next clock
- sampleOffsetCalc ();
- if (_sidSamples)
- {
-#if XSID_DEBUG
- printf ("XSID: SID Volume Changed Externally (Corrected).\n");
-#endif
- return true;
- }
- }
- writeMemByte (sidData0x18);
- return false;
-}