Example #1
0
        public static Timestamp ConvertTimeToStreamPos(Timestamp where, int rate, bool isStereo)
        {
            var result = new Timestamp(where.ConvertToFramerate(rate * (isStereo ? 2 : 1)));

            // When the Stream is a stereo stream, we have to assure
            // that the sample position is an even number.
            if (isStereo && (result.TotalNumberOfFrames & 1) != 0)
            {
                result = result.AddFrames(-1); // We cut off one sample here.
            }
            // Since Timestamp allows sub-frame-precision it might lead to odd behaviors
            // when we would just return result.
            //
            // An example is when converting the timestamp 500ms to a 11025 Hz based
            // stream. It would have an internal frame counter of 5512.5. Now when
            // doing calculations at frame precision, this might lead to unexpected
            // results: The frame difference between a timestamp 1000ms and the above
            // mentioned timestamp (both with 11025 as framerate) would be 5512,
            // instead of 5513, which is what a frame-precision based code would expect.
            //
            // By creating a new Timestamp with the given parameters, we create a
            // Timestamp with frame-precision, which just drops a sub-frame-precision
            // information (i.e. rounds down).
            return(new Timestamp(result.Seconds, result.NumberOfFrames, result.Framerate));
        }
Example #2
0
            public void DecodeFrame(Stream frame, int sectorCount)
            {
                // A frame is essentially an MPEG-1 intra frame

                var bits = new BitStream(frame, BitStreamType.SixteenBits, true, true);

                bits.Skip(16); // unknown
                bits.Skip(16); // 0x3800
                ushort scale   = (ushort)bits.GetBits(16);
                ushort version = (ushort)bits.GetBits(16);

                if (version != 2 && version != 3)
                {
                    throw new InvalidOperationException("Unknown PSX stream frame version");
                }

                // Initalize default v3 DC here
                _lastDC[0] = _lastDC[1] = _lastDC[2] = 0;

                for (int mbX = 0; mbX < _macroBlocksW; mbX++)
                {
                    for (int mbY = 0; mbY < _macroBlocksH; mbY++)
                    {
                        DecodeMacroBlock(bits, mbX, mbY, scale, version);
                    }
                }

                // Output data onto the frame
                YUVToRGBManager.Convert420(_surface, LuminanceScale.ScaleFull, _yBuffer, _cbBuffer, _crBuffer, _surface.Width, _surface.Height, _macroBlocksW * 16, _macroBlocksW * 8);

                _curFrame++;

                // Increase the time by the amount of sectors we read
                // One may notice that this is still not the most precise
                // method since a frame takes up the time its sectors took
                // up instead of the amount of time it takes the next frame
                // to be read from the sectors. The actual frame rate should
                // be constant instead of variable, so the slight difference
                // in a frame's showing time is negligible (1/150 of a second).
                _nextFrameStartTime = _nextFrameStartTime.AddFrames(sectorCount);
            }
Example #3
0
        public static Timestamp ConvertTimeToStreamPos(Timestamp where, int rate, bool isStereo)
        {
            var result = new Timestamp(where.ConvertToFramerate(rate * (isStereo ? 2 : 1)));

            // When the Stream is a stereo stream, we have to assure
            // that the sample position is an even number.
            if (isStereo && (result.TotalNumberOfFrames & 1) != 0)
                result = result.AddFrames(-1); // We cut off one sample here.

            // Since Timestamp allows sub-frame-precision it might lead to odd behaviors
            // when we would just return result.
            //
            // An example is when converting the timestamp 500ms to a 11025 Hz based
            // stream. It would have an internal frame counter of 5512.5. Now when
            // doing calculations at frame precision, this might lead to unexpected
            // results: The frame difference between a timestamp 1000ms and the above
            // mentioned timestamp (both with 11025 as framerate) would be 5512,
            // instead of 5513, which is what a frame-precision based code would expect.
            //
            // By creating a new Timestamp with the given parameters, we create a
            // Timestamp with frame-precision, which just drops a sub-frame-precision
            // information (i.e. rounds down).
            return new Timestamp(result.Seconds, result.NumberOfFrames, result.Framerate);
        }
Example #4
0
        void PreProcess()
        {
            var block = new Block();

            // Scan through the file and collect all blocks
            while (true)
            {
                block.Code   = _br.ReadByte();
                block.Length = 0;

                // If we hit EOS here we found the end of the VOC file.
                // According to http://wiki.multimedia.cx/index.php?title=Creative_Voice
                // there is no need for an "Terminator" block to be present.
                // In case we hit a "Terminator" block we also break here.
                if (IsAtEndOfStream || block.Code == 0)
                {
                    break;
                }
                // We will allow invalid block numbers as terminators. This is needed,
                // since some games ship broken VOC files. The following occasions are
                // known:
                // - 128 is used as terminator in Simon 1 Amiga CD32
                // - Full Throttle contains a VOC file with an incorrect block length
                //   resulting in a sample (127) to be read as block code.
                if (block.Code > 9)
                {
                    throw new NotSupportedException(string.Format("VocStream.PreProcess: Caught {0} as terminator", block.Code));
                }

                block.Length  = _stream.ReadByte();
                block.Length |= _stream.ReadByte() << 8;
                block.Length |= _stream.ReadByte() << 16;

                // Premature end of stream => error!
                if (IsAtEndOfStream)
                {
                    throw new InvalidOperationException("VocStream.PreProcess: Reading failed");
                }

                int skip = 0;

                switch (block.Code)
                {
                // Sound data
                case 1:
                // Sound data (New format)
                case 9:
                    if (block.Code == 1)
                    {
                        if (block.Length < 2)
                        {
                            throw new InvalidOperationException(string.Format("Invalid sound data block length {0} in VOC file", block.Length));
                        }

                        // Read header data
                        int freqDiv = _stream.ReadByte();
                        // Prevent division through 0
                        if (freqDiv == 256)
                        {
                            throw new InvalidOperationException("Invalid frequency divisor 256 in VOC file");
                        }
                        block.Rate = GetSampleRateFromVOCRate(freqDiv);

                        int codec = _stream.ReadByte();
                        // We only support 8bit PCM
                        if (codec != 0)
                        {
                            throw new NotSupportedException(string.Format("Unhandled codec {0} in VOC file", codec));
                        }

                        block.Samples = skip = block.Length - 2;
                        block.Offset  = (int)_stream.Position;

                        // Check the last block if there is any
                        if (_blocks.Count > 0)
                        {
                            int lastBlock = _blocks.Count;
                            --lastBlock;
                            // When we have found a block 8 as predecessor
                            // we need to use its settings
                            if (_blocks[lastBlock].Code == 8)
                            {
                                block.Rate = _blocks[lastBlock].Rate;
                                // Remove the block since we don't need it anymore
                                _blocks.RemoveAt(lastBlock);
                            }
                        }
                    }
                    else
                    {
                        if (block.Length < 12)
                        {
                            throw new InvalidOperationException(string.Format("Invalid sound data (wew format) block length {0} in VOC file", block.Length));
                        }

                        block.Rate = _br.ReadInt32();
                        int bitsPerSample = _stream.ReadByte();
                        // We only support 8bit PCM
                        if (bitsPerSample != 8)
                        {
                            throw new NotSupportedException(string.Format("Unhandled bits per sample {0} in VOC file", bitsPerSample));
                        }
                        int channels = _stream.ReadByte();
                        // We only support mono
                        if (channels != 1)
                        {
                            throw new NotSupportedException(string.Format("Unhandled channel count {0} in VOC file", channels));
                        }
                        int codec = _br.ReadInt16();
                        // We only support 8bit PCM
                        if (codec != 0)
                        {
                            throw new NotSupportedException(string.Format("Unhandled codec {0} in VOC file", codec));
                        }
                        /*uint32 reserved = */
                        _br.ReadInt32();
                        block.Offset  = (int)_stream.Position;
                        block.Samples = skip = block.Length - 12;
                    }

                    // Check whether we found a new highest rate
                    if (_rate < block.Rate)
                    {
                        _rate = block.Rate;
                    }
                    break;

                // Silence
                case 3:
                {
                    if (block.Length != 3)
                    {
                        throw new InvalidOperationException(string.Format("Invalid silence block length {0} in VOC file", block.Length));
                    }

                    block.Offset = 0;

                    block.Samples = _br.ReadInt16() + 1;
                    int freqDiv = _stream.ReadByte();
                    // Prevent division through 0
                    if (freqDiv == 256)
                    {
                        throw new InvalidOperationException("Invalid frequency divisor 256 in VOC file");
                    }
                    block.Rate = GetSampleRateFromVOCRate(freqDiv);
                }
                break;

                // Repeat start
                case 6:
                    if (block.Length != 2)
                    {
                        throw new InvalidOperationException(string.Format("Invalid repeat start block length {0} in VOC file", block.Length));
                    }

                    block.Count = _br.ReadInt16() + 1;
                    break;

                // Repeat end
                case 7:
                    break;

                // Extra info
                case 8:
                {
                    if (block.Length != 4)
                    {
                        return;
                    }

                    int freqDiv = _br.ReadInt16();
                    // Prevent division through 0
                    if (freqDiv == 65536)
                    {
                        throw new InvalidOperationException("Invalid frequency divisor 65536 in VOC file");
                    }

                    int codec = _stream.ReadByte();
                    // We only support RAW 8bit PCM.
                    if (codec != 0)
                    {
                        throw new NotSupportedException(string.Format("Unhandled codec {0} in VOC file", codec));
                    }

                    int channels = _stream.ReadByte() + 1;
                    // We only support mono sound right now
                    if (channels != 1)
                    {
                        throw new NotSupportedException(string.Format("Unhandled channel count {0} in VOC file", channels));
                    }

                    block.Offset  = 0;
                    block.Samples = 0;
                    block.Rate    = (int)(256000000L / (65536L - freqDiv));
                }
                break;

                default:
                    //                        Console.Error.WriteLine("Unhandled code {0} in VOC file (len {1})", block.Code, block.Length);
                    // Skip the whole block and try to use the next one.
                    skip = block.Length;
                    break;
                }

                // Premature end of stream => error!
                if (IsAtEndOfStream)
                {
                    throw new InvalidOperationException("VocStream::preProcess: Reading failed");
                }

                // Skip the rest of the block
                if (skip != 0)
                {
                    _stream.Seek(skip, SeekOrigin.Current);
                }

                _blocks.Add(block);
            }

            // Since we determined the sample rate we need for playback now, we will
            // initialize the play length.
            _length = new Timestamp(0, _rate);

            // Calculate the total play time and do some more sanity checks
            foreach (var i in _blocks)
            {
                // Check whether we found a block 8 which survived, this is not
                // allowed to happen!
                if (i.Code == 8)
                {
                    throw new InvalidOperationException("VOC file contains unused block 8");
                }
                // For now only use blocks with actual samples
                if (i.Code != 1 && i.Code != 9)
                {
                    continue;
                }

                // Check the sample rate
                if (i.Rate != _rate)
                {
                    throw new InvalidOperationException(string.Format("VOC file contains chunks with different sample rates ({0} != {1})", _rate, i.Rate));
                }

                _length = _length.AddFrames(i.Samples);
            }

            // Set the current block to the first block in the stream
            Rewind();
        }
Example #5
0
        void PreProcess()
        {
            var block = new Block();

            // Scan through the file and collect all blocks
            while (true)
            {
                block.Code = _br.ReadByte();
                block.Length = 0;

                // If we hit EOS here we found the end of the VOC file.
                // According to http://wiki.multimedia.cx/index.php?title=Creative_Voice
                // there is no need for an "Terminator" block to be present.
                // In case we hit a "Terminator" block we also break here.
                if (IsAtEndOfStream || block.Code == 0)
                    break;
                // We will allow invalid block numbers as terminators. This is needed,
                // since some games ship broken VOC files. The following occasions are
                // known:
                // - 128 is used as terminator in Simon 1 Amiga CD32
                // - Full Throttle contains a VOC file with an incorrect block length
                //   resulting in a sample (127) to be read as block code.
                if (block.Code > 9)
                {
                    throw new NotSupportedException(string.Format("VocStream.PreProcess: Caught {0} as terminator", block.Code));
                }

                block.Length = _stream.ReadByte();
                block.Length |= _stream.ReadByte() << 8;
                block.Length |= _stream.ReadByte() << 16;

                // Premature end of stream => error!
                if (IsAtEndOfStream)
                {
                    throw new InvalidOperationException("VocStream.PreProcess: Reading failed");
                }

                int skip = 0;

                switch (block.Code)
                {
                    // Sound data
                    case 1:
                    // Sound data (New format)
                    case 9:
                        if (block.Code == 1)
                        {
                            if (block.Length < 2)
                            {
                                throw new InvalidOperationException(string.Format("Invalid sound data block length {0} in VOC file", block.Length));
                            }

                            // Read header data
                            int freqDiv = _stream.ReadByte();
                            // Prevent division through 0
                            if (freqDiv == 256)
                            {
                                throw new InvalidOperationException("Invalid frequency divisor 256 in VOC file");
                            }
                            block.Rate = GetSampleRateFromVOCRate(freqDiv);

                            int codec = _stream.ReadByte();
                            // We only support 8bit PCM
                            if (codec != 0)
                            {
                                throw new NotSupportedException(string.Format("Unhandled codec {0} in VOC file", codec));
                            }

                            block.Samples = skip = block.Length - 2;
                            block.Offset = (int)_stream.Position;

                            // Check the last block if there is any
                            if (_blocks.Count > 0)
                            {
                                int lastBlock = _blocks.Count;
                                --lastBlock;
                                // When we have found a block 8 as predecessor
                                // we need to use its settings
                                if (_blocks[lastBlock].Code == 8)
                                {
                                    block.Rate = _blocks[lastBlock].Rate;
                                    // Remove the block since we don't need it anymore
                                    _blocks.RemoveAt(lastBlock);
                                }
                            }
                        }
                        else
                        {
                            if (block.Length < 12)
                            {
                                throw new InvalidOperationException(string.Format("Invalid sound data (wew format) block length {0} in VOC file", block.Length));
                            }

                            block.Rate = _br.ReadInt32();
                            int bitsPerSample = _stream.ReadByte();
                            // We only support 8bit PCM
                            if (bitsPerSample != 8)
                            {
                                throw new NotSupportedException(string.Format("Unhandled bits per sample {0} in VOC file", bitsPerSample));
                            }
                            int channels = _stream.ReadByte();
                            // We only support mono
                            if (channels != 1)
                            {
                                throw new NotSupportedException(string.Format("Unhandled channel count {0} in VOC file", channels));
                            }
                            int codec = _br.ReadInt16();
                            // We only support 8bit PCM
                            if (codec != 0)
                            {
                                throw new NotSupportedException(string.Format("Unhandled codec {0} in VOC file", codec));
                            }
                            /*uint32 reserved = */
                            _br.ReadInt32();
                            block.Offset = (int)_stream.Position;
                            block.Samples = skip = block.Length - 12;
                        }

                        // Check whether we found a new highest rate
                        if (_rate < block.Rate)
                            _rate = block.Rate;
                        break;

                    // Silence
                    case 3:
                        {
                            if (block.Length != 3)
                            {
                                throw new InvalidOperationException(string.Format("Invalid silence block length {0} in VOC file", block.Length));
                            }

                            block.Offset = 0;

                            block.Samples = _br.ReadInt16() + 1;
                            int freqDiv = _stream.ReadByte();
                            // Prevent division through 0
                            if (freqDiv == 256)
                            {
                                throw new InvalidOperationException("Invalid frequency divisor 256 in VOC file");
                            }
                            block.Rate = GetSampleRateFromVOCRate(freqDiv);
                        }
                        break;

                    // Repeat start
                    case 6:
                        if (block.Length != 2)
                        {
                            throw new InvalidOperationException(string.Format("Invalid repeat start block length {0} in VOC file", block.Length));
                        }

                        block.Count = _br.ReadInt16() + 1;
                        break;

                    // Repeat end
                    case 7:
                        break;

                    // Extra info
                    case 8:
                        {
                            if (block.Length != 4)
                                return;

                            int freqDiv = _br.ReadInt16();
                            // Prevent division through 0
                            if (freqDiv == 65536)
                            {
                                throw new InvalidOperationException("Invalid frequency divisor 65536 in VOC file");
                            }

                            int codec = _stream.ReadByte();
                            // We only support RAW 8bit PCM.
                            if (codec != 0)
                            {
                                throw new NotSupportedException(string.Format("Unhandled codec {0} in VOC file", codec));
                            }

                            int channels = _stream.ReadByte() + 1;
                            // We only support mono sound right now
                            if (channels != 1)
                            {
                                throw new NotSupportedException(string.Format("Unhandled channel count {0} in VOC file", channels));
                            }

                            block.Offset = 0;
                            block.Samples = 0;
                            block.Rate = (int)(256000000L / (65536L - freqDiv));
                        }
                        break;

                    default:
                        //                        Console.Error.WriteLine("Unhandled code {0} in VOC file (len {1})", block.Code, block.Length);
                        // Skip the whole block and try to use the next one.
                        skip = block.Length;
                        break;
                }

                // Premature end of stream => error!
                if (IsAtEndOfStream)
                {
                    throw new InvalidOperationException("VocStream::preProcess: Reading failed");
                }

                // Skip the rest of the block
                if (skip != 0)
                    _stream.Seek(skip, SeekOrigin.Current);

                _blocks.Add(block);
            }

            // Since we determined the sample rate we need for playback now, we will
            // initialize the play length.
            _length = new Timestamp(0, _rate);

            // Calculate the total play time and do some more sanity checks
            foreach (var i in _blocks)
            {
                // Check whether we found a block 8 which survived, this is not
                // allowed to happen!
                if (i.Code == 8)
                {
                    throw new InvalidOperationException("VOC file contains unused block 8");
                }
                // For now only use blocks with actual samples
                if (i.Code != 1 && i.Code != 9)
                    continue;

                // Check the sample rate
                if (i.Rate != _rate)
                {
                    throw new InvalidOperationException(string.Format("VOC file contains chunks with different sample rates ({0} != {1})", _rate, i.Rate));
                }

                _length = _length.AddFrames(i.Samples);
            }

            // Set the current block to the first block in the stream
            Rewind();
        }