示例#1
0
        /// <summary>
        /// Initializes this upmixer by creating the obligatory reference channels and the extra channels that are
        /// used by the <see cref="source"/>.
        /// </summary>
        void Init()
        {
            ReferenceChannel[] layout = ChannelPrototype.GetStandardMatrix(8);
            output = new ChannelData[layout.Length];
            for (int channel = 0; channel < layout.Length; ++channel)
            {
                output[channel].target = layout[channel];
            }
            output[0].lastSamples = new float[0]; // To skip null check in GenerateSamples

            layout = ChannelPrototype.GetStandardMatrix(source.Channels);
            List <ReferenceChannel> missing = new List <ReferenceChannel>();

            for (int channel = 0; channel < layout.Length; ++channel)
            {
                if (!output.Has(entry => entry.target == layout[channel]))
                {
                    missing.Add(layout[channel]);
                }
            }

            int offset = output.Length, news = missing.Count;

            Array.Resize(ref output, offset + news);
            for (int channel = 0; channel < news; ++channel)
            {
                output[channel + offset] = new ChannelData(missing[channel]);
            }
        }
示例#2
0
        /// <summary>
        /// Render new object samples for the next timeslot
        /// </summary>
        void RenderNextTimeslot()
        {
            float[] input = new float[QuadratureMirrorFilterBank.subbands * stream.ChannelCount];
            stream.DecodeBlock(input, 0, input.LongLength);
            Source?.ReadBlock(input, 0, input.LongLength);
            WaveformUtils.InterlacedToMultichannel(input, inputData);

            ReferenceChannel[] matrix  = ChannelPrototype.GetStandardMatrix(stream.ChannelCount);
            EnhancedAC3Decoder decoder = (EnhancedAC3Decoder)stream;

            // Object-based rendering
            if (HasObjects = decoder.Extensions.HasObjects)
            {
                decoder.Extensions.OAMD.UpdateSources(decoder.LastFetchStart / stream.ChannelCount, objects);

                float[][] sources = new float[JointObjectCodingTables.inputMatrix.Length][];
                for (int i = 0; i < sources.Length; ++i)
                {
                    for (int j = 0; j < matrix.Length; ++j)
                    {
                        if (JointObjectCodingTables.inputMatrix[i] == matrix[j])
                        {
                            sources[i] = inputData[j];
                            break;
                        }
                    }
                }

                for (int i = 0; i < matrix.Length; ++i)
                {
                    if (matrix[i] == ReferenceChannel.ScreenLFE)
                    {
                        lfeTimeslot = inputData[i];
                    }
                }

                timeslotResult = applier.Apply(sources, decoder.Extensions.JOC);
            }
            // Channel-based rendering or fallback to it when OAMD or JOC can't be decoded correctly
            else
            {
                for (int i = 0; i < matrix.Length; ++i)
                {
                    timeslotResult[i]   = inputData[i];
                    objects[i].Position = channelPositions[(int)matrix[i]] * Listener.EnvironmentSize;
                    if (ChannelPrototype.Mapping[(int)matrix[i]].LFE)   // LFE is handled elsewhere
                    {
                        objects[i].Position = default;
                        Array.Clear(timeslotResult[i], 0, timeslotResult[i].Length);
                    }
                }
                for (int i = matrix.Length; i < timeslotResult.Length; ++i)
                {
                    objects[i].Position = default;
                    Array.Clear(timeslotResult[i], 0, timeslotResult[i].Length);
                }
            }
        }
示例#3
0
 public SpatializedChannel(ReferenceChannel source, Cavernizer master, int updateRate)
 {
     Channel = ChannelPrototype.Mapping[(int)source];
     filter  = new Filters.Cavernize(AudioListener3D.Current.SampleRate, 250);
     filter.PresetOutput(updateRate);
     Output = new float[updateRate];
     CreateSource(master, true);
     CreateSource(master, false);
 }
示例#4
0
文件: Renderer.cs 项目: VoidXH/Cavern
 /// <summary>
 /// Set up the renderer for a number of standard channels.
 /// </summary>
 protected void SetupChannels(int count)
 {
     ReferenceChannel[] matrix = ChannelPrototype.GetStandardMatrix(count);
     for (int channel = 0; channel < count; ++channel)
     {
         Source source = new StreamMasterSource(reader, channel)
         {
             Position = channelPositions[(int)matrix[channel]] * Listener.EnvironmentSize
         };
         objects.Add(source);
     }
     FinishSetup(count);
 }
示例#5
0
        void ProcessImpulse(object sender, RoutedEventArgs e)
        {
            if (browser.ShowDialog().Value)
            {
                AudioReader reader  = AudioReader.Open(browser.FileName);
                float[]     impulse = reader.Read();
                float       gain    = 1;
                if (keepGain.IsChecked.Value)
                {
                    gain = WaveformUtils.GetPeak(impulse);
                }

                if (commonEQ.IsChecked.Value)
                {
                    ProcessCommon(reader, ref impulse);
                }
                else
                {
                    ProcessPerChannel(reader, ref impulse);
                }

                if (keepGain.IsChecked.Value)
                {
                    WaveformUtils.Gain(impulse, gain / WaveformUtils.GetPeak(impulse));
                }

                BitDepth bits = reader.Bits;
                if (forceFloat.IsChecked.Value)
                {
                    bits = BitDepth.Float32;
                }

                int targetLen = QMath.Base2Ceil((int)reader.Length);
                if (separateExport.IsChecked.Value)
                {
                    ReferenceChannel[] channels = ChannelPrototype.GetStandardMatrix(reader.ChannelCount);
                    for (int ch = 0; ch < reader.ChannelCount; ++ch)
                    {
                        string exportName  = Path.GetFileName(browser.FileName);
                        int    idx         = exportName.LastIndexOf('.');
                        string channelName = ChannelPrototype.Mapping[(int)channels[ch]].Name;
                        exporter.FileName = $"{exportName[..idx]} - {channelName}{exportName[idx..]}";
示例#6
0
        /// <summary>
        /// Set the object properties from metadata.
        /// </summary>
        /// <param name="timecode">Samples since the beginning of the audio frame</param>
        /// <param name="sources">The sources used for rendering this track</param>
        public void UpdateSources(int timecode, IReadOnlyList <Source> sources)
        {
            timecode -= offset;
            int element = 0;

            for (int i = elements.Length - 1; i >= 0; --i)
            {
                if (elements[i].MinOffset < 0)
                {
                    continue;
                }
                if (elements[i].MinOffset <= timecode)
                {
                    element = i;
                    break;
                }
            }

            elements[element].UpdateSources(timecode, sources);
            int checkedBed         = 0;
            int checkedBedInstance = 0;

            for (int i = 0; i < beds; ++i)
            {
                while (!bedAssignment[checkedBedInstance][checkedBed])
                {
                    if (++checkedBed == (int)NonStandardBedChannel.Max)
                    {
                        ++checkedBedInstance;
                    }
                }
                ChannelPrototype prototype = ChannelPrototype.Mapping[(int)bedChannels[checkedBed]];
                sources[i].Position = new Vector3(prototype.X, prototype.Y, 0).PlaceInCube() * Listener.EnvironmentSize;
                sources[i].LFE      = prototype.LFE;
            }
        }
示例#7
0
        /// <summary>
        /// Generate the next <paramref name="samples"/> samples to be retrieved with <see cref="RetrieveSamples(ReferenceChannel)"/>.
        /// </summary>
        public void GenerateSamples(int samples)
        {
            // Preparations
            ReferenceChannel[] layout = ChannelPrototype.GetStandardMatrix(source.Channels);
            if (output[0].lastSamples.Length != samples)
            {
                for (int channel = 0; channel < output.Length; ++channel)
                {
                    output[channel].lastSamples = null;
                }

                cache = new float[source.Channels][];
                for (int channel = 0; channel < source.Channels; ++channel)
                {
                    cache[channel] = new float[samples];
                    int channelId = GetChannelId(layout[channel]);
                    if (channelId != -1)
                    {
                        output[channelId].lastSamples = cache[channel]; // Cache linked with output, no need to copy
                    }
                }

                for (int channel = 0; channel < output.Length; ++channel)
                {
                    if (output[channel].lastSamples == null)
                    {
                        output[channel].lastSamples = new float[samples];
                    }
                }
            }
            for (int channel = 0; channel < output.Length; ++channel)
            {
                output[channel].writtenTo = false;
            }

            // Fetch samples
            source.GetData(cache, timeSamples);
            if (timeSamples >= source.Samples)
            {
                if (loop)
                {
                    timeSamples %= source.Samples;
                }
                else
                {
                    timeSamples = 0;
                    OnPlaybackFinished();
                }
            }
            timeSamples += samples;
            for (int channel = 0; channel < source.Channels; ++channel)
            {
                output[GetChannelId(layout[channel])].writtenTo = true;
            }

            // Create missing channels via matrix if asked for
            if (matrixUpmix)
            {
                if (output[0].writtenTo && output[1].writtenTo) // Left and right channels available
                {
                    if (!output[2].writtenTo)                   // Create discrete middle channel
                    {
                        float[] left = output[0].lastSamples, right = output[1].lastSamples, center = output[2].lastSamples;
                        for (int offset = 0; offset < samples; ++offset)
                        {
                            center[offset] = (left[offset] + right[offset]) * .5f;
                        }
                        output[2].writtenTo = true;
                    }
                    if (!output[6].writtenTo)   // Matrix mix for sides
                    {
                        float[] leftFront = output[0].lastSamples, rightFront = output[1].lastSamples,
                        leftSide = output[6].lastSamples, rightSide = output[7].lastSamples;
                        for (int offset = 0; offset < samples; ++offset)
                        {
                            leftSide[offset]  = (leftFront[offset] - rightFront[offset]) * .5f;
                            rightSide[offset] = -leftSide[offset];
                        }
                        output[6].writtenTo = output[7].writtenTo = true;
                    }
                    if (!output[4].writtenTo)        // Extend sides to rears...
                    {
                        bool rearsAvailable = false; // ...but only if there are rears in the system
                        for (int channel = 0; channel < Listener.Channels.Length; ++channel)
                        {
                            float currentY = Listener.Channels[channel].Y;
                            if (currentY < -135 || currentY > 135)
                            {
                                rearsAvailable = true;
                                break;
                            }
                        }
                        if (rearsAvailable)
                        {
                            float[] leftSide = output[6].lastSamples, rightSide = output[7].lastSamples,
                            leftRear = output[4].lastSamples, rightRear = output[5].lastSamples;
                            for (int offset = 0; offset < samples; ++offset)
                            {
                                leftRear[offset]  = leftSide[offset] *= .5f;
                                rightRear[offset] = rightSide[offset] *= .5f;
                            }
                            output[4].writtenTo = output[5].writtenTo = true;
                        }
                    }
                }
            }
        }
示例#8
0
        /// <summary>
        /// Read the next <paramref name="samples"/> and update the objects.
        /// </summary>
        /// <param name="samples">Samples per channel</param>
        public override void Update(int samples)
        {
            if (lfeResult.Length != samples)
            {
                timeslotResult = new float[finalResult.Length][];
                for (int obj = 0; obj < finalResult.Length; ++obj)
                {
                    finalResult[obj] = new float[samples];
                }
                lfeTimeslot = new float[samples];
                lfeResult   = new float[samples];
            }
            if (inputData.Length != stream.ChannelCount)
            {
                inputData = new float[stream.ChannelCount][];
                for (int channel = 0; channel < inputData.Length; ++channel)
                {
                    inputData[channel] = new float[QuadratureMirrorFilterBank.subbands];
                }
            }

            int pointer = 0;

            while (pointer < samples)
            {
                if (timeslotPosition == 0)
                {
                    RenderNextTimeslot();
                }
                int next = Math.Min(samples - pointer, QuadratureMirrorFilterBank.subbands - timeslotPosition);
                for (int obj = 0; obj < finalResult.Length; ++obj)
                {
                    for (int i = 0; i < next; ++i)
                    {
                        finalResult[obj][pointer + i] = timeslotResult[obj][timeslotPosition + i];
                    }
                }
                for (int i = 0; i < next; ++i)
                {
                    lfeResult[pointer + i] = lfeTimeslot[timeslotPosition + i];
                }
                pointer          += next;
                timeslotPosition += next;
                if (timeslotPosition == QuadratureMirrorFilterBank.subbands)
                {
                    timeslotPosition = 0;
                }
            }

            int lfe = ((EnhancedAC3Decoder)stream).Extensions.OAMD.GetLFEPosition();

            if (lfe != -1)
            {
                for (int obj = 0; obj < lfe; ++obj)
                {
                    objectSamples[obj] = finalResult[obj];
                }
                ReferenceChannel[] matrix = ChannelPrototype.GetStandardMatrix(stream.ChannelCount);
                for (int i = 0; i < matrix.Length; ++i)
                {
                    if (matrix[i] == ReferenceChannel.ScreenLFE)
                    {
                        objectSamples[lfe] = lfeResult;
                        break;
                    }
                }
                for (int obj = lfe + 1; obj < objectSamples.Length; ++obj)
                {
                    objectSamples[obj] = finalResult[obj - 1];
                }
            }
            else
            {
                for (int obj = 0; obj < objectSamples.Length; ++obj)
                {
                    objectSamples[obj] = finalResult[obj];
                }
            }
        }
示例#9
0
文件: Renderer.cs 项目: VoidXH/Cavern
 /// <summary>
 /// Get the bed channels.
 /// </summary>
 public virtual ReferenceChannel[] GetChannels() => ChannelPrototype.GetStandardMatrix(stream.ChannelCount);
示例#10
0
 /// <summary>
 /// Loads a standard layout of the channel count of the imported file to a list of channels.
 /// </summary>
 void SetStandardLayout(ListBox holder) =>
 holder.ItemsSource = (ReferenceChannel[])ChannelPrototype.GetStandardMatrix(reader.ChannelCount).Clone();