Example #1
0
        public static SidTuneBase load(ref byte[] dataBuf)
        {
            // File format check
            if (dataBuf.Length < 4)
            {
                return(null);
            }

            UInt32 magic = sidendian.endian_big32(dataBuf);

            if ((magic != PSID_ID) &&
                (magic != RSID_ID))
            {
                return(null);
            }

            psidHeader pHeader = new psidHeader();

            readHeader(dataBuf, ref pHeader);

            PSID tune = new PSID();

            tune.tryLoad(ref pHeader);

            return(tune);
        }
Example #2
0
        private static void readHeader(byte[] dataBuf, ref psidHeader hdr)
        {
            // Due to security concerns, input must be at least as long as version 1
            // header plus 16-bit C64 load address. That is the area which will be
            // accessed.
            if (dataBuf.Length < (psid_headerSize + 2))
            {
                throw new loadError(ERR_TRUNCATED);
            }

            // Read v1 fields
            hdr.id      = sidendian.endian_big32(new Ptr <byte>(dataBuf, 0));
            hdr.version = sidendian.endian_big16(new Ptr <byte>(dataBuf, 4));
            hdr.data    = sidendian.endian_big16(new Ptr <byte>(dataBuf, 6));
            hdr.load    = sidendian.endian_big16(new Ptr <byte>(dataBuf, 8));
            hdr.init    = sidendian.endian_big16(new Ptr <byte>(dataBuf, 10));
            hdr.play    = sidendian.endian_big16(new Ptr <byte>(dataBuf, 12));
            hdr.songs   = sidendian.endian_big16(new Ptr <byte>(dataBuf, 14));
            hdr.start   = sidendian.endian_big16(new Ptr <byte>(dataBuf, 16));
            hdr.speed   = sidendian.endian_big32(new Ptr <byte>(dataBuf, 18));
            mem.memcpy(ref hdr.name, new Ptr <byte>(dataBuf, 22), PSID_MAXSTRLEN);
            mem.memcpy(ref hdr.author, new Ptr <byte>(dataBuf, 54), PSID_MAXSTRLEN);
            mem.memcpy(ref hdr.released, new Ptr <byte>(dataBuf, 86), PSID_MAXSTRLEN);

            if (hdr.version >= 2)
            {
                if (dataBuf.Length < (psidv2_headerSize + 2))
                {
                    throw new loadError(ERR_TRUNCATED);
                }

                // Read v2/3/4 fields
                hdr.flags          = sidendian.endian_big16(new Ptr <byte>(dataBuf, 118));
                hdr.relocStartPage = dataBuf[120];
                hdr.relocPages     = dataBuf[121];
                hdr.sidChipBase2   = dataBuf[122];
                hdr.sidChipBase3   = dataBuf[123];
            }
        }
Example #3
0
        private void tryLoad(ref psidHeader pHeader)
        {
            SidTuneInfo.compatibility_t compatibility = SidTuneInfo.compatibility_t.COMPATIBILITY_C64;

            // Require a valid ID and version number.
            if (pHeader.id == PSID_ID)
            {
                switch (pHeader.version)
                {
                case 1:
                    compatibility = SidTuneInfo.compatibility_t.COMPATIBILITY_PSID;
                    break;

                case 2:
                case 3:
                case 4:
                    break;

                default:
                    throw new loadError(TXT_UNKNOWN_PSID);
                }
                info.m_formatString = TXT_FORMAT_PSID;
            }
            else if (pHeader.id == RSID_ID)
            {
                switch (pHeader.version)
                {
                case 2:
                case 3:
                case 4:
                    break;

                default:
                    throw new loadError(TXT_UNKNOWN_RSID);
                }
                info.m_formatString = TXT_FORMAT_RSID;
                compatibility       = SidTuneInfo.compatibility_t.COMPATIBILITY_R64;
            }

            fileOffset            = pHeader.data;
            info.m_loadAddr       = pHeader.load;
            info.m_initAddr       = pHeader.init;
            info.m_playAddr       = pHeader.play;
            info.m_songs          = pHeader.songs;
            info.m_startSong      = pHeader.start;
            info.m_compatibility  = compatibility;
            info.m_relocPages     = 0;
            info.m_relocStartPage = 0;

            UInt32 speed = pHeader.speed;

            SidTuneInfo.clock_t clock = SidTuneInfo.clock_t.CLOCK_UNKNOWN;

            bool musPlayer = false;

            if (pHeader.version >= 2)
            {
                UInt16 flags = pHeader.flags;

                // Check clock
                if ((flags & (UInt16)Psid.PSID_MUS) != 0)
                {   // MUS tunes run at any speed
                    clock     = SidTuneInfo.clock_t.CLOCK_ANY;
                    musPlayer = true;
                }
                else
                {
                    switch ((flags & (UInt16)Psid.PSID_CLOCK))
                    {
                    case (UInt16)Psid_Clock.PSID_CLOCK_ANY:
                        clock = SidTuneInfo.clock_t.CLOCK_ANY;
                        break;

                    case (UInt16)Psid_Clock.PSID_CLOCK_PAL:
                        clock = SidTuneInfo.clock_t.CLOCK_PAL;
                        break;

                    case (UInt16)Psid_Clock.PSID_CLOCK_NTSC:
                        clock = SidTuneInfo.clock_t.CLOCK_NTSC;
                        break;

                    default:
                        break;
                    }
                }

                // These flags are only available for the appropriate
                // file formats
                switch (compatibility)
                {
                case SidTuneInfo.compatibility_t.COMPATIBILITY_C64:
                    if ((flags & (UInt16)Psid.PSID_SPECIFIC) != 0)
                    {
                        info.m_compatibility = SidTuneInfo.compatibility_t.COMPATIBILITY_PSID;
                    }
                    break;

                case SidTuneInfo.compatibility_t.COMPATIBILITY_R64:
                    if ((flags & (UInt16)Psid.PSID_BASIC) != 0)
                    {
                        info.m_compatibility = SidTuneInfo.compatibility_t.COMPATIBILITY_BASIC;
                    }
                    break;

                default:
                    break;
                }

                info.m_clockSpeed = clock;

                info.m_sidModels[0] = getSidModel((UInt16)(flags >> 4));

                info.m_relocStartPage = pHeader.relocStartPage;
                info.m_relocPages     = pHeader.relocPages;

                if (pHeader.version >= 3)
                {
                    if (validateAddress(pHeader.sidChipBase2))
                    {
                        info.m_sidChipAddresses.Add((UInt16)(0xd000 | (pHeader.sidChipBase2 << 4)));

                        info.m_sidModels.Add(getSidModel((UInt16)(flags >> 6)));
                    }

                    if (pHeader.version >= 4)
                    {
                        if (pHeader.sidChipBase3 != pHeader.sidChipBase2 &&
                            validateAddress(pHeader.sidChipBase3))
                        {
                            info.m_sidChipAddresses.Add((UInt16)(0xd000 | (pHeader.sidChipBase3 << 4)));

                            info.m_sidModels.Add((SidTuneInfo.model_t)(getSidModel((UInt16)(flags >> 8))));
                        }
                    }
                }
            }

            // Check reserved fields to force real c64 compliance
            // as required by the RSID specification
            if (compatibility == SidTuneInfo.compatibility_t.COMPATIBILITY_R64)
            {
                if ((info.m_loadAddr != 0) ||
                    (info.m_playAddr != 0) ||
                    (speed != 0))
                {
                    throw new loadError(ERR_INVALID);
                }

                // Real C64 tunes appear as CIA
                speed = 0xffffffff;// ~0;
            }

            // Create the speed/clock setting table.
            convertOldStyleSpeedToTables(speed, (Int64)clock);

            // Copy info strings.
            info.m_infoString.Add(Encoding.ASCII.GetString(pHeader.name, 0, PSID_MAXSTRLEN));
            info.m_infoString.Add(Encoding.ASCII.GetString(pHeader.author, 0, PSID_MAXSTRLEN));
            info.m_infoString.Add(Encoding.ASCII.GetString(pHeader.released, 0, PSID_MAXSTRLEN));

            if (musPlayer)
            {
                throw new loadError("Compute!'s Sidplayer MUS data is not supported yet"); // TODO
            }
        }