Ejemplo n.º 1
0
        private static string GetSectionLabel(TzxDataBlock tzxBlock)
        {
            string sectionLabel = null;

            switch (tzxBlock.Type)
            {
            case TzxDataBlockType.StandardSpeedDataBlock:
                StandardSpeedDataBlock dataBlock = (StandardSpeedDataBlock)tzxBlock;
                sectionLabel = GetSectionLabel(dataBlock.TapeDataBlock);
                break;

            case TzxDataBlockType.TurboSpeedDataBlock:
                dataBlock     = (StandardSpeedDataBlock)tzxBlock;
                sectionLabel  = GetSectionLabel(dataBlock.TapeDataBlock);
                sectionLabel += " [turbo speed]";
                break;

            case TzxDataBlockType.PureDataBlock:
                dataBlock     = (StandardSpeedDataBlock)tzxBlock;
                sectionLabel  = GetSectionLabel(dataBlock.TapeDataBlock);
                sectionLabel += " [no pilot/sync]";
                break;

            case TzxDataBlockType.PureTone:
                sectionLabel = "Pure tone";
                break;

            case TzxDataBlockType.PulseSequence:
                sectionLabel = "Pulse sequence";
                break;

            case TzxDataBlockType.DirectRecording:
                sectionLabel = "Direct recording";
                break;

            case TzxDataBlockType.PauseOrStopTheTape:
                sectionLabel = "Pause";
                break;

            case TzxDataBlockType.GroupStart:
                GroupStart groupStart = (GroupStart)tzxBlock;
                sectionLabel = groupStart.GroupName;
                break;
            }
            return(sectionLabel);
        }
Ejemplo n.º 2
0
        private static TzxDataBlock ReadTzxDataBlock(BinaryReader fileReader)
        {
            TzxDataBlock resultDataBlock = null;

            byte id = fileReader.ReadByte();

            TzxDataBlockType dataBlockType = TzxDataBlock.GetTZXDataBlockTypeFromID(id);

            switch (dataBlockType)
            {
            // ID 10 - Standard Speed Data Block
            case TzxDataBlockType.StandardSpeedDataBlock:
                resultDataBlock = new StandardSpeedDataBlock();
                ReadStandardSpeedDataBlock(fileReader, (StandardSpeedDataBlock)resultDataBlock);
                break;

            // ID 11 - Turbo Speed Data Block
            case TzxDataBlockType.TurboSpeedDataBlock:
                resultDataBlock = new TurboSpeedDataBlock();
                ReadTurboSpeedDataBlock(fileReader, (TurboSpeedDataBlock)resultDataBlock);
                break;

            // ID 12 - Pure Tone
            case TzxDataBlockType.PureTone:
                resultDataBlock = new PureTone();
                ReadPureTone(fileReader, (PureTone)resultDataBlock);
                break;

            // ID 13 - Pulse sequence
            case TzxDataBlockType.PulseSequence:
                resultDataBlock = new PulseSequence();
                ReadPulseSequence(fileReader, (PulseSequence)resultDataBlock);
                break;

            // ID 14 - Pure Data Block
            case TzxDataBlockType.PureDataBlock:
                resultDataBlock = new PureDataBlock();
                ReadPureDataBlock(fileReader, (PureDataBlock)resultDataBlock);
                break;

            // ID 15 - Direct Recording
            case TzxDataBlockType.DirectRecording:
                resultDataBlock = new DirectRecording();
                ReadDirectRecording(fileReader, (DirectRecording)resultDataBlock);
                break;

            // ID 20 - Pause (silence) or 'Stop the Tape' command
            case TzxDataBlockType.PauseOrStopTheTape:
                resultDataBlock = new PauseOrStopTheTape();
                ReadPauseOrStopTheTape(fileReader, (PauseOrStopTheTape)resultDataBlock);
                break;

            // ID 21 - Group start
            case TzxDataBlockType.GroupStart:
                resultDataBlock = new GroupStart();
                ReadGroupStart(fileReader, (GroupStart)resultDataBlock);
                break;

            // ID 22 - Group end
            case TzxDataBlockType.GroupEnd:
                resultDataBlock = new GroupEnd();
                break;

            // ID 30 - Text description
            case TzxDataBlockType.TextDescription:
                resultDataBlock = new TextDescription();
                ReadTextDescription(fileReader, (TextDescription)resultDataBlock);
                break;

            // ID 32 - Archive info
            case TzxDataBlockType.ArchiveInfo:
                resultDataBlock = new ArchiveInfo();
                ReadArchiveInfo(fileReader, (ArchiveInfo)resultDataBlock);
                break;

            default:
                throw new NotImplementedException("TZX data block ID " + id.ToString("X") + " is not yet implemented");
            }

            return(resultDataBlock);
        }
Ejemplo n.º 3
0
        public static TzxFile ReadTzxFile(Stream inputStream, string fileName)
        {
            TzxFile resultFile = new TzxFile(fileName);

            using (BinaryReader fileReader = new BinaryReader(inputStream, Encoding.GetEncoding("ISO-8859-1")))
            {
                string signature = Encoding.GetEncoding("ISO-8859-1").GetString(fileReader.ReadBytes(7));
                if (signature != "ZXTape!")
                {
                    throw new InvalidDataException("The signature of the file does not match the standard TZX file format");
                }
                else
                {
                    resultFile.Signature = signature;
                }

                resultFile.EndOfTextFileMarker = fileReader.ReadByte();
                resultFile.MajorRevisionNumber = fileReader.ReadByte();
                resultFile.MinorRevisionNumber = fileReader.ReadByte();

                TapeSection currentGroupSection = null;

                while (fileReader.PeekChar() >= 0)
                {
                    TzxDataBlock tzxBlock = ReadTzxDataBlock(fileReader);
                    resultFile.DataBlocks.Add(tzxBlock);

                    switch (tzxBlock.Type)
                    {
                    case TzxDataBlockType.StandardSpeedDataBlock:
                    case TzxDataBlockType.TurboSpeedDataBlock:
                    case TzxDataBlockType.PureTone:
                    case TzxDataBlockType.PulseSequence:
                    case TzxDataBlockType.PureDataBlock:
                    case TzxDataBlockType.DirectRecording:
                        TapeSection section = new TapeSection(tzxBlock);
                        if (currentGroupSection == null)
                        {
                            resultFile.Sections.Add(section);
                        }
                        else
                        {
                            foreach (TapeSoundSequence soundSequence in section.SoundSequences)
                            {
                                currentGroupSection.SoundSequences.Add(soundSequence);
                            }
                        }
                        break;

                    case TzxDataBlockType.PauseOrStopTheTape:
                        PauseOrStopTheTape pauseBlock = (PauseOrStopTheTape)tzxBlock;
                        if (pauseBlock.PauseInMs > 0)
                        {
                            section = new TapeSection(tzxBlock);
                            if (currentGroupSection == null)
                            {
                                resultFile.Sections.Add(section);
                            }
                            else
                            {
                                foreach (TapeSoundSequence soundSequence in section.SoundSequences)
                                {
                                    currentGroupSection.SoundSequences.Add(soundSequence);
                                }
                            }
                        }
                        break;

                    case TzxDataBlockType.TextDescription:
                        TextDescription descriptionBlock = (TextDescription)tzxBlock;
                        resultFile.Description += descriptionBlock.Text;
                        break;

                    case TzxDataBlockType.ArchiveInfo:
                        ArchiveInfo archiveInfo = (ArchiveInfo)tzxBlock;
                        resultFile.Description += archiveInfo.ToString();
                        break;

                    case TzxDataBlockType.GroupStart:
                        currentGroupSection = new TapeSection(tzxBlock);
                        break;

                    case TzxDataBlockType.GroupEnd:
                        foreach (TapeSoundSequence soundSequence in currentGroupSection.SoundSequences)
                        {
                            currentGroupSection.Duration += soundSequence.Duration;
                        }
                        resultFile.Sections.Add(currentGroupSection);
                        currentGroupSection = null;
                        break;
                    }
                }
            }
            TapeSection       lastSection       = resultFile.Sections[resultFile.Sections.Count - 1];
            TapeSoundSequence lastSoundSequence = lastSection.SoundSequences[lastSection.SoundSequences.Count - 1];

            if (lastSoundSequence.GetType() != typeof(PauseSequence))
            {
                lastSection.SoundSequences.Add(new PauseSequence("End of tape", 1));
            }

            foreach (TapeSection section in resultFile.Sections)
            {
                resultFile.Duration += section.Duration;
            }

            return(resultFile);
        }
Ejemplo n.º 4
0
        public TapeSection(TzxDataBlock tzxBlock)
        {
            switch (tzxBlock.Type)
            {
            // ID 10 - Standard Speed Data Block
            // PILOT tone :
            // - number of pulses : 8063 header (flag<128), 3223 data (flag>=128)
            // - pulse length : 2168
            // First SYNC pulse :
            // - pulse length : 667
            // Second SYNC pulse :
            // - pulse length : 735
            // DATA :
            // - length of ZERO bit pulse : 855
            // - length of ONE bit pulse : 1710
            // Pause after this block (ms.) {1000}
            case TzxDataBlockType.StandardSpeedDataBlock:
                StandardSpeedDataBlock standardDataBlock = (StandardSpeedDataBlock)tzxBlock;
                // PILOT tone
                if (standardDataBlock.TapeDataBlock.Flag < 128)
                {
                    _soundSequences.Add(new ToneSequence("Pilot tone", 8063, 2168));
                }
                else
                {
                    _soundSequences.Add(new ToneSequence("Pilot tone", 3223, 2168));
                }
                // First and Second SYNC pulse
                _soundSequences.Add(new PulsesSequence("Sync pulses", new ushort[] { 667, 735 }));
                // DATA
                _soundSequences.Add(new DataSequence("Data", standardDataBlock.TapeDataBlock.TapeData, 855, 1710, 8));
                // Pause
                if (standardDataBlock.PauseInMs > 0)
                {
                    _soundSequences.Add(new PauseSequence("Pause", standardDataBlock.PauseInMs));
                }
                break;

            // ID 11 - Turbo Speed Data Block
            // PILOT tone :
            // - number of pulses
            // - pulse length
            // First SYNC pulse :
            // - pulse length
            // Second SYNC pulse :
            // - pulse length
            // DATA :
            // - length of ZERO bit pulse
            // - length of ONE bit pulse
            // Pause after this block (ms.)
            case TzxDataBlockType.TurboSpeedDataBlock:
                TurboSpeedDataBlock turboDataBlock = (TurboSpeedDataBlock)tzxBlock;
                // PILOT tone
                _soundSequences.Add(new ToneSequence("Pilot tone", turboDataBlock.PilotTonePulseCount, turboDataBlock.PilotTonePulseLength));
                // First and Second SYNC pulse
                _soundSequences.Add(new PulsesSequence("Sync pulses", new ushort[] { turboDataBlock.FirstSyncPulseLength, turboDataBlock.SecondSyncPulseLength }));
                // DATA
                _soundSequences.Add(new DataSequence("Data", turboDataBlock.TapeDataBlock.TapeData, turboDataBlock.ZeroBitPulseLength, turboDataBlock.OneBitPulseLength, turboDataBlock.UsedBitsOfTheLastByte));
                // Pause
                if (turboDataBlock.PauseInMs > 0)
                {
                    _soundSequences.Add(new PauseSequence("Pause", turboDataBlock.PauseInMs));
                }
                break;

            // ID 12 - Pure Tone
            // Length of one pulse in T-states
            // Number of pulses
            case TzxDataBlockType.PureTone:
                PureTone toneBlock = (PureTone)tzxBlock;
                _soundSequences.Add(new ToneSequence("Pure tone", toneBlock.PulseCount, toneBlock.LengthOfOnePulse));
                break;

            // ID 13 - Pulse sequence
            // Number of pulses
            // Table of pulses' lengths
            case TzxDataBlockType.PulseSequence:
                PulseSequence pulseBlock = (PulseSequence)tzxBlock;
                _soundSequences.Add(new PulsesSequence("Pulse sequence", pulseBlock.PulsesLengths));
                break;

            // ID 14 - Pure Data Block
            // DATA : Length of ZERO bit pulse / Length of ONE bit pulse
            // Pause after this block (ms.)
            case TzxDataBlockType.PureDataBlock:
                PureDataBlock dataBlock = (PureDataBlock)tzxBlock;
                // DATA
                _soundSequences.Add(new DataSequence("Pure data", dataBlock.TapeDataBlock.TapeData, dataBlock.ZeroBitPulseLength, dataBlock.OneBitPulseLength, dataBlock.UsedBitsOfTheLastByte));
                // Pause
                if (dataBlock.PauseInMs > 0)
                {
                    _soundSequences.Add(new PauseSequence("Pause", dataBlock.PauseInMs));
                }
                break;

            // ID 15 - Direct Recording
            // Number of T-states per sample (bit of data). When creating a 'Direct recording' block please stick to the standard sampling frequencies of 22050 or 44100 Hz. This will ensure correct playback when using PC's soundcards.
            // Pause after this block in milliseconds (ms.)
            case TzxDataBlockType.DirectRecording:
                DirectRecording samplesBlock = (DirectRecording)tzxBlock;
                _soundSequences.Add(new SamplesSequence("Samples", samplesBlock.BitStream, samplesBlock.TStatesPerSample, samplesBlock.UsedBitsOfTheLastByte));
                if (samplesBlock.PauseInMs > 0)
                {
                    _soundSequences.Add(new PauseSequence("Pause", samplesBlock.PauseInMs));
                }
                break;

            // ID 20 - Pause (silence) or 'Stop the Tape' command
            // Pause duration (ms.)
            // This will make a silence (low amplitude level (0)) for a given time in milliseconds. If the value is 0 then the emulator or utility should (in effect) STOP THE TAPE, i.e. should not continue loading until the user or emulator requests it.
            case TzxDataBlockType.PauseOrStopTheTape:
                PauseOrStopTheTape pauseBlock = (PauseOrStopTheTape)tzxBlock;
                if (pauseBlock.PauseInMs > 0)
                {
                    _soundSequences.Add(new PauseSequence("Pause", pauseBlock.PauseInMs));
                }
                break;

            case TzxDataBlockType.GroupStart:
            case TzxDataBlockType.GroupEnd:
            case TzxDataBlockType.TextDescription:
            case TzxDataBlockType.ArchiveInfo:
                // Documentation only, ignore these blocks at runtime
                break;

            default:
                throw new NotSupportedException("Tzx file block type " + tzxBlock.Type.ToString() + " is not yet supported");
            }

            ComputeDuration();

            Label = GetSectionLabel(tzxBlock) + " [" + Math.Round(Duration / 1000f) + " sec]";
        }
        public TapeSection(TzxDataBlock tzxBlock)
        {
            switch (tzxBlock.Type)
            {
                // ID 10 - Standard Speed Data Block
                // PILOT tone :
                // - number of pulses : 8063 header (flag<128), 3223 data (flag>=128)
                // - pulse length : 2168
                // First SYNC pulse :
                // - pulse length : 667
                // Second SYNC pulse :
                // - pulse length : 735
                // DATA :
                // - length of ZERO bit pulse : 855
                // - length of ONE bit pulse : 1710
                // Pause after this block (ms.) {1000}
                case TzxDataBlockType.StandardSpeedDataBlock:
                    StandardSpeedDataBlock standardDataBlock = (StandardSpeedDataBlock)tzxBlock;
                    // PILOT tone
                    if (standardDataBlock.TapeDataBlock.Flag < 128)
                    {
                        _soundSequences.Add(new ToneSequence("Pilot tone", 8063, 2168));
                    }
                    else
                    {
                        _soundSequences.Add(new ToneSequence("Pilot tone", 3223, 2168));
                    }
                    // First and Second SYNC pulse
                    _soundSequences.Add(new PulsesSequence("Sync pulses", new ushort[] { 667, 735 }));
                    // DATA
                    _soundSequences.Add(new DataSequence("Data", standardDataBlock.TapeDataBlock.TapeData, 855, 1710, 8));
                    // Pause
                    if (standardDataBlock.PauseInMs > 0)
                    {
                        _soundSequences.Add(new PauseSequence("Pause", standardDataBlock.PauseInMs));
                    }
                    break;
                // ID 11 - Turbo Speed Data Block
                // PILOT tone :
                // - number of pulses
                // - pulse length
                // First SYNC pulse :
                // - pulse length
                // Second SYNC pulse :
                // - pulse length
                // DATA :
                // - length of ZERO bit pulse
                // - length of ONE bit pulse
                // Pause after this block (ms.)
                case TzxDataBlockType.TurboSpeedDataBlock:
                    TurboSpeedDataBlock turboDataBlock = (TurboSpeedDataBlock)tzxBlock;
                    // PILOT tone
                    _soundSequences.Add(new ToneSequence("Pilot tone", turboDataBlock.PilotTonePulseCount, turboDataBlock.PilotTonePulseLength));
                    // First and Second SYNC pulse
                    _soundSequences.Add(new PulsesSequence("Sync pulses", new ushort[] { turboDataBlock.FirstSyncPulseLength, turboDataBlock.SecondSyncPulseLength }));
                    // DATA
                    _soundSequences.Add(new DataSequence("Data", turboDataBlock.TapeDataBlock.TapeData, turboDataBlock.ZeroBitPulseLength, turboDataBlock.OneBitPulseLength, turboDataBlock.UsedBitsOfTheLastByte));
                    // Pause
                    if (turboDataBlock.PauseInMs > 0)
                    {
                        _soundSequences.Add(new PauseSequence("Pause", turboDataBlock.PauseInMs));
                    }
                    break;
                // ID 12 - Pure Tone
                // Length of one pulse in T-states
                // Number of pulses
                case TzxDataBlockType.PureTone:
                    PureTone toneBlock = (PureTone)tzxBlock;
                    _soundSequences.Add(new ToneSequence("Pure tone", toneBlock.PulseCount, toneBlock.LengthOfOnePulse));
                    break;
                // ID 13 - Pulse sequence
                // Number of pulses
                // Table of pulses' lengths
                case TzxDataBlockType.PulseSequence:
                    PulseSequence pulseBlock = (PulseSequence)tzxBlock;
                    _soundSequences.Add(new PulsesSequence("Pulse sequence", pulseBlock.PulsesLengths));
                    break;
                // ID 14 - Pure Data Block
                // DATA : Length of ZERO bit pulse / Length of ONE bit pulse
                // Pause after this block (ms.)
                case TzxDataBlockType.PureDataBlock:
                    PureDataBlock dataBlock = (PureDataBlock)tzxBlock;
                    // DATA
                    _soundSequences.Add(new DataSequence("Pure data", dataBlock.TapeDataBlock.TapeData, dataBlock.ZeroBitPulseLength, dataBlock.OneBitPulseLength, dataBlock.UsedBitsOfTheLastByte));
                    // Pause
                    if (dataBlock.PauseInMs > 0)
                    {
                        _soundSequences.Add(new PauseSequence("Pause", dataBlock.PauseInMs));
                    }
                    break;
                // ID 15 - Direct Recording
                // Number of T-states per sample (bit of data). When creating a 'Direct recording' block please stick to the standard sampling frequencies of 22050 or 44100 Hz. This will ensure correct playback when using PC's soundcards.
                // Pause after this block in milliseconds (ms.)
                case TzxDataBlockType.DirectRecording:
                    DirectRecording samplesBlock = (DirectRecording)tzxBlock;
                    _soundSequences.Add(new SamplesSequence("Samples", samplesBlock.BitStream, samplesBlock.TStatesPerSample, samplesBlock.UsedBitsOfTheLastByte));
                    if (samplesBlock.PauseInMs > 0)
                    {
                        _soundSequences.Add(new PauseSequence("Pause", samplesBlock.PauseInMs));
                    }
                    break;
                // ID 20 - Pause (silence) or 'Stop the Tape' command
                // Pause duration (ms.)
                // This will make a silence (low amplitude level (0)) for a given time in milliseconds. If the value is 0 then the emulator or utility should (in effect) STOP THE TAPE, i.e. should not continue loading until the user or emulator requests it.
                case TzxDataBlockType.PauseOrStopTheTape:
                    PauseOrStopTheTape pauseBlock = (PauseOrStopTheTape)tzxBlock;
                    if (pauseBlock.PauseInMs > 0)
                    {
                        _soundSequences.Add(new PauseSequence("Pause", pauseBlock.PauseInMs));
                    }
                    break;
                case TzxDataBlockType.GroupStart:
                case TzxDataBlockType.GroupEnd:
                case TzxDataBlockType.TextDescription:
                case TzxDataBlockType.ArchiveInfo:
                    // Documentation only, ignore these blocks at runtime
                    break;
                default:
                    throw new NotSupportedException("Tzx file block type " + tzxBlock.Type.ToString() + " is not yet supported");
            }

            ComputeDuration();

            Label = GetSectionLabel(tzxBlock) + " [" + Math.Round(Duration / 1000f) + " sec]";
        }
 private static string GetSectionLabel(TzxDataBlock tzxBlock)
 {
     string sectionLabel = null;
     switch (tzxBlock.Type)
     {
         case TzxDataBlockType.StandardSpeedDataBlock:
             StandardSpeedDataBlock dataBlock = (StandardSpeedDataBlock)tzxBlock;
             sectionLabel = GetSectionLabel(dataBlock.TapeDataBlock);
             break;
         case TzxDataBlockType.TurboSpeedDataBlock:
             dataBlock = (StandardSpeedDataBlock)tzxBlock;
             sectionLabel = GetSectionLabel(dataBlock.TapeDataBlock);
             sectionLabel += " [turbo speed]";
             break;
         case TzxDataBlockType.PureDataBlock:
             dataBlock = (StandardSpeedDataBlock)tzxBlock;
             sectionLabel = GetSectionLabel(dataBlock.TapeDataBlock);
             sectionLabel += " [no pilot/sync]";
             break;
         case TzxDataBlockType.PureTone:
             sectionLabel = "Pure tone";
             break;
         case TzxDataBlockType.PulseSequence:
             sectionLabel = "Pulse sequence";
             break;
         case TzxDataBlockType.DirectRecording:
             sectionLabel = "Direct recording";
             break;
         case TzxDataBlockType.PauseOrStopTheTape:
             sectionLabel = "Pause";
             break;
         case TzxDataBlockType.GroupStart:
             GroupStart groupStart = (GroupStart)tzxBlock;
             sectionLabel = groupStart.GroupName;
             break;
     }
     return sectionLabel;
 }