예제 #1
0
파일: ADX.cs 프로젝트: MetLob/tinke
        /// <summary>
        /// Decode the standard format.
        /// Copied from: "http://en.wikipedia.org/wiki/ADX_(file_format)"
        /// </summary>
        /// <param name="buffer">buffer is where the decoded samples will be put</param>
        /// <param name="samples_needed">samples_needed states how many sample 'sets' (one sample from every channel) need to be decoded to fill the buffer</param>
        /// <param name="looping_enabled">looping_enabled is a boolean flag to control use of the built-in loop</param>
        /// <returns>Returns the number of sample 'sets' in the buffer that could not be filled (EOS)</returns>
        public override byte[] Decode(byte[] encoded, bool looping_enabled)
        {
            BitReader bit_reader = new BitReader(encoded, true);
            List<byte> bufferOut = new List<byte>();

            Initialize_Decode();

            // Param:
            uint samples_needed = adx_header.total_samples;

            uint samples_per_block = (uint)((adx_header.block_size - 2) * 8 / adx_header.sample_bitdepth);
            short[] scale = new short[adx_header.channel_count];

            if (looping_enabled && adx_header.loop_enabled == 0)
                looping_enabled = false;

            if (looping_enabled)    // Mine
                sample_index = adx_header.loop_begin_sample_index;

            // Loop until the requested number of samples are decoded, or the end of file is reached
            while (samples_needed > 0 && sample_index < adx_header.total_samples)
            {
                // Calculate the number of samples that are left to be decoded in the current block
                uint sample_offset = sample_index % samples_per_block;
                uint samples_can_get = samples_per_block - sample_offset;

                // Clamp the samples we can get during this run if they won't fit in the buffer
                if (samples_can_get > samples_needed)
                    samples_can_get = samples_needed;

                // Clamp the number of samples to be acquired if the stream isn't long enough or the loop trigger is nearby
                if (looping_enabled && sample_index + samples_can_get > adx_header.loop_end_sample_index)
                    samples_can_get = adx_header.loop_end_sample_index - sample_index;
                else if (sample_index + samples_can_get > adx_header.total_samples)
                    samples_can_get = adx_header.total_samples - sample_index;

                // Calculate the bit address of the start of the frame that sample_index resides in and record that location
                ulong started_at = (ulong)(adx_header.copyright_offset + 4 +
                    sample_index / samples_per_block * adx_header.block_size * adx_header.channel_count) * 8;

                // Read the scale values from the start of each block in this frame
                for (uint i = 0; i < adx_header.channel_count; ++i)
                {
                    bit_reader.Seek((int)(started_at + adx_header.block_size * i * 8));
                    scale[i] = bit_reader.Read_Short();
                }

                // Pre-calculate the stop value for sample_offset
                uint sample_endoffset = sample_offset + samples_can_get;

                // Save the bitstream address of the first sample immediately after the scale in the first block of the frame
                started_at += 16;
                while (sample_offset < sample_endoffset)
                {
                    for (uint i = 0; i < adx_header.channel_count; ++i)
                    {
                        // Predict the next sample
                        double sample_prediction = coefficient[0] * past_samples[i * 2 + 0] + coefficient[1] * past_samples[i * 2 + 1];

                        // Seek to the sample offset, read and sign extend it to a 32bit integer
                        bit_reader.Seek((int)((int)started_at + adx_header.sample_bitdepth * sample_offset + adx_header.block_size * 8 * i));
                        int sample_error = 0;
                        if (adx_header.sample_bitdepth == 4)
                            sample_error = bit_reader.Read_4Bits();

                        // Scale the error correction value
                        sample_error *= scale[i];

                        // Calculate the sample by combining the prediction with the error correction
                        int sample = sample_error + (int)sample_prediction;

                        // Update the past samples with the newer sample
                        past_samples[i * 2 + 1] = past_samples[i * 2 + 0];
                        past_samples[i * 2 + 0] = sample;

                        // Clamp the decoded sample to the valid range for a 16bit integer
                        if (sample > 32767)
                            sample = 32767;
                        else if (sample < -32768)
                            sample = -32768;

                        bufferOut.AddRange(BitConverter.GetBytes((short)sample));
                    }

                    ++sample_offset;  // We've decoded one sample from every block, advance block offset by 1
                    ++sample_index;   // This also means we're one sample further into the stream
                    --samples_needed; // And so there is one less set of samples that need to be decoded
                }

                // Check if we hit the loop end marker, if we did we need to jump to the loop start
                if (looping_enabled && sample_index == adx_header.loop_end_sample_index)
                    //sample_index = adx_header.loop_begin_sample_index;
                    break;
            }

            //return samples_needed;
            return bufferOut.ToArray();
        }