コード例 #1
0
        public static void GetRMSScalingFactors(
            IBGCStream stream,
            double desiredLevel,
            out double scalingFactorL,
            out double scalingFactorR,
            Calibration.Source source = Calibration.Source.Custom)
        {
            GetAmplitudeFactors(
                dbSPLL: desiredLevel,
                dbSPLR: desiredLevel,
                factorL: out double levelFactorL,
                factorR: out double levelFactorR,
                source: source);

            double maxRMS = stream.GetChannelRMS().Where(x => !double.IsNaN(x)).Max();

            scalingFactorL = levelFactorL * (TARGET_RMS / maxRMS);
            scalingFactorR = levelFactorR * (TARGET_RMS / maxRMS);

            //Protect against some NaN Poisoning
            if (double.IsNaN(scalingFactorL) || double.IsInfinity(scalingFactorL))
            {
                scalingFactorL = 1.0;
            }

            if (double.IsNaN(scalingFactorR) || double.IsInfinity(scalingFactorR))
            {
                scalingFactorR = 1.0;
            }
        }
コード例 #2
0
        public NoiseVocoder(
            IBGCStream stream,
            double freqLowerBound            = 20.0,
            double freqUpperBound            = 16000.0,
            int bandCount                    = 22,
            int fftSize                      = 4096,
            int overlapRatio                 = 4,
            TransformRMSBehavior rmsBehavior = TransformRMSBehavior.Passthrough,
            Random randomizer                = null)
            : base(stream)
        {
            if (stream.Channels != 1)
            {
                throw new StreamCompositionException(
                          $"Noise Vocoder requires a mono input stream. Input stream has {stream.Channels} channels.");
            }

            this.fftSize      = fftSize;
            this.overlapRatio = overlapRatio;
            stepSize          = fftSize / overlapRatio;
            overlapSize       = fftSize - stepSize;

            inputBuffer        = new float[fftSize];
            noiseBuffer        = new double[fftSize];
            outputAccumulation = new double[fftSize];
            cachedSampleBuffer = new float[stepSize];

            noiseFFTBuffer  = new Complex64[fftSize];
            signalFFTBuffer = new Complex64[fftSize];

            amplitudeBuffers = new Complex64[bandCount][];
            noiseBandBuffers = new Complex64[bandCount][];

            for (int i = 0; i < bandCount; i++)
            {
                amplitudeBuffers[i] = new Complex64[fftSize];
                noiseBandBuffers[i] = new Complex64[fftSize];
            }

            initialized = false;

            noiseScalarA = Math.Sqrt(1.0 / 3.0);
            noiseScalarB = 2.0 * noiseScalarA;

            double[] windowTemplate = Windowing.GetHalfWindow64(Windowing.Function.BlackmanHarris, fftSize / 2);

            window = new double[fftSize];
            for (int i = 0; i < fftSize / 2; i++)
            {
                window[i] = windowTemplate[i];
                window[fftSize - i - 1] = windowTemplate[i];
            }

            this.randomizer  = randomizer ?? new Random(CustomRandom.Next());
            this.rmsBehavior = rmsBehavior;

            bandFrequencies = GetExponentialDistribution(freqLowerBound, freqUpperBound, bandCount).ToArray();

            outputFactor = 0.5 * Math.Sqrt(fftSize) / overlapRatio;
        }
コード例 #3
0
 public StreamChannelSplitter(IBGCStream stream, out IBGCStream splitStream)
     : base(stream)
 {
     Debug.Assert(stream.Channels == 2);
     this.splitStream = new InternalStreamSplit(this);
     splitStream      = this.splitStream;
 }
コード例 #4
0
        public static BiQuadFilter LowShelfFilter(
            IBGCStream stream,
            double criticalFrequency,
            double dbGain,
            TransformRMSBehavior rmsBehavior = TransformRMSBehavior.Recalculate)
        {
            double k          = Math.Tan(Math.PI * criticalFrequency / stream.SamplingRate);
            double gainFactor = Math.Pow(10.0, Math.Abs(dbGain) / 20.0);

            double norm, a0, a1, a2, b1, b2;

            if (dbGain >= 0.0)
            {
                //Boost
                norm = 1.0 / (1.0 + Math.Sqrt(2.0) * k + k * k);
                a0   = (1.0 + Math.Sqrt(2.0 * gainFactor) * k + gainFactor * k * k) * norm;
                a1   = 2.0 * (gainFactor * k * k - 1.0) * norm;
                a2   = (1.0 - Math.Sqrt(2.0 * gainFactor) * k + gainFactor * k * k) * norm;
                b1   = 2.0 * (k * k - 1.0) * norm;
                b2   = (1.0 - Math.Sqrt(2.0) * k + k * k) * norm;
            }
            else
            {
                //Cut
                norm = 1.0 / (1.0 + Math.Sqrt(2.0 * gainFactor) * k + gainFactor * k * k);
                a0   = (1.0 + Math.Sqrt(2.0) * k + k * k) * norm;
                a1   = 2.0 * (k * k - 1.0) * norm;
                a2   = (1.0 - Math.Sqrt(2.0) * k + k * k) * norm;
                b1   = 2.0 * (gainFactor * k * k - 1.0) * norm;
                b2   = (1.0 - Math.Sqrt(2.0 * gainFactor) * k + gainFactor * k * k) * norm;
            }

            return(new BiQuadFilter(stream, a0, a1, a2, b1, b2, rmsBehavior));
        }
コード例 #5
0
 public static IBGCStream Center(
     this IBGCStream stream,
     int preDelaySamples,
     int postDelaySamples)
 {
     return(new StreamCenterer(stream, preDelaySamples, postDelaySamples));
 }
コード例 #6
0
        public bool RemoveStream(IBGCStream stream)
        {
            bool success = streams.Remove(stream);

            UpdateStats();
            return(success);
        }
コード例 #7
0
    private Fanfare(
        double noteDuration,
        double endSustain,
        double[] frequencies)
    {
        double totalDuration = noteDuration * 4 + endSustain;
        int    totalSamples  = (int)Math.Floor(SamplingRate * totalDuration);

        StreamAdder fanfareStream = new StreamAdder();

        for (int i = 0; i < frequencies.Length; i++)
        {
            double startingTime = i * noteDuration;

            IBGCStream noteStream =
                GetNote(frequencies[i], totalDuration - startingTime)
                .Center((int)(startingTime * SamplingRate), 0);

            fanfareStream.AddStream(noteStream);
        }

        stream = fanfareStream
                 .Spatialize(0.0)
                 .Normalize(Level);
    }
コード例 #8
0
        private void StartFillBufferTask()
        {
            int        fillBufferIndex = (bufferIndex + 1) % buffers.Length;
            IBGCStream fillStream      = stream;

            fillBufferTask = Task.Run(() => FillBuffer(fillStream, buffers[fillBufferIndex]));
        }
コード例 #9
0
        public ContinuousFilter(
            IBGCStream stream,
            IBGCEnvelopeStream filterEnvelope,
            FilterType filterType,
            double freqLB,
            double freqUB,
            double qFactor = double.NaN)
            : base(stream)
        {
            UnityEngine.Debug.Assert(stream.Channels == 1);

            this.filterType = filterType;

            if (double.IsNaN(qFactor))
            {
                Q = Math.Sqrt(0.5);
            }
            else
            {
                Q = qFactor;
            }

            this.filterEnvelope = filterEnvelope;

            this.freqLB = freqLB;
            this.freqUB = freqUB;
            freqMid     = Math.PI * (this.freqUB + this.freqLB) / (2.0 * stream.SamplingRate);
            freqFactor  = Math.PI * (this.freqUB - this.freqLB) / (2.0 * stream.SamplingRate);
        }
コード例 #10
0
        void OnAudioFilterRead(float[] data, int numchannels)
        {
            if (currentState == SoundState.Playing && stream != null)
            {
                if (numchannels != stream.Channels)
                {
                    Debug.LogError($"Stream/Player channel mismatch: {stream.Channels}, {numchannels}");

                    switch (numchannels)
                    {
                    case 1:
                        //Down-channel
                        stream = stream.IsolateChannel(0);
                        break;

                    case 2:
                        //Up-channel
                        stream = stream.UpChannel();
                        break;

                    default:
                        Debug.LogError($"Completely unexpected Player channel count: {numchannels}");
                        break;
                    }
                }

                int readSamples = stream.Read(data, 0, data.Length);

                if (readSamples < data.Length)
                {
                    currentState = SoundState.Stopped;
                    playbackEndedNotifier?.Invoke();
                }
            }
        }
コード例 #11
0
        public NoiseGateFilter(
            IBGCStream stream,
            double openThreshold             = -26.0,
            double closeThreshold            = -32.0,
            double attackDuration            = 0.025,
            double holdDuration              = 0.200,
            double releaseDuration           = 0.150,
            TransformRMSBehavior rmsBehavior = TransformRMSBehavior.Passthrough)
            : base(stream)
        {
            this.openThreshold  = Math.Pow(10.0, openThreshold / 20.0);
            this.closeThreshold = Math.Pow(10.0, closeThreshold / 20.0);

            attackRate  = (float)(1.0 / (attackDuration * SamplingRate));
            releaseRate = (float)(1.0 / (releaseDuration * SamplingRate));

            double thresholdDiff  = this.openThreshold - this.closeThreshold;
            double minDecayPeriod = (1.0 / 75.0) * SamplingRate;

            decayRate         = thresholdDiff / minDecayPeriod;
            this.holdDuration = holdDuration;

            isOpen      = false;
            attenuation = 0;
            level       = 0;
            heldTime    = 0;

            inverseSampleRate = 1.0 / SamplingRate;

            this.rmsBehavior = rmsBehavior;
        }
コード例 #12
0
        public SinglePassPhaseReencoder(
            IBGCStream stream,
            double leftTimeShift,
            double rightTimeShift)
            : base(stream)
        {
            if (stream.ChannelSamples == int.MaxValue)
            {
                throw new StreamCompositionException("Cannot Single-Pass Phase Reencode an infinite stream. " +
                                                     "Truncate first or use a Frame-based Reencoder.");
            }

            if (stream.Channels > 2)
            {
                throw new StreamCompositionException("Cannot Single-Pass Phase Reencode a stream with more than " +
                                                     "2 channels.");
            }

            Channels = 2;

            this.leftTimeShift  = leftTimeShift;
            this.rightTimeShift = rightTimeShift;

            Samples = new float[TotalSamples];
        }
コード例 #13
0
        public override int Read(float[] data, int offset, int count)
        {
            int remainingSamples = count;

            while (remainingSamples > 0)
            {
                if (CurrentClipIndex >= streams.Count)
                {
                    //Hit the end
                    break;
                }

                IBGCStream stream = streams[CurrentClipIndex];

                int readSamples = stream.Read(data, offset, remainingSamples);

                remainingSamples -= readSamples;
                offset           += readSamples;
                Position         += readSamples / Channels;

                if (readSamples <= 0)
                {
                    CurrentClipIndex++;

                    if (CurrentClipIndex < streams.Count)
                    {
                        //Reset on advancing allows a concatenator to hold multiple
                        //copies of the same clip
                        streams[CurrentClipIndex].Reset();
                    }
                }
            }

            return(count - remainingSamples);
        }
コード例 #14
0
        public override void Seek(int position)
        {
            Position         = position;
            CurrentClipIndex = streams.Count;

            for (int i = 0; i < streams.Count; i++)
            {
                IBGCStream clip = streams[i];
                if (position > 0)
                {
                    //Seek
                    if (position > clip.ChannelSamples)
                    {
                        clip.Seek(clip.ChannelSamples);
                        position -= clip.ChannelSamples;
                    }
                    else
                    {
                        clip.Seek(position);
                        position         = 0;
                        CurrentClipIndex = i;
                    }
                }
                else
                {
                    clip.Reset();
                }
            }
        }
コード例 #15
0
        /// <summary>
        /// Slowest Backup Alternative for calculating RMS
        /// </summary>
        public static IEnumerable <double> CalculateRMS(this IBGCStream stream)
        {
            double[] rms = new double[stream.Channels];
            int      readSamples;

            const int BUFFER_SIZE = 512;

            float[] buffer = new float[BUFFER_SIZE];

            stream.Reset();
            do
            {
                readSamples = stream.Read(buffer, 0, BUFFER_SIZE);

                for (int i = 0; i < readSamples; i++)
                {
                    rms[i % stream.Channels] += buffer[i] * buffer[i];
                }
            }while (readSamples > 0);

            stream.Reset();

            for (int i = 0; i < stream.Channels; i++)
            {
                rms[i] = Math.Sqrt(rms[i] / stream.ChannelSamples);
            }

            return(rms);
        }
コード例 #16
0
        public CarlileShuffler(
            IBGCStream stream,
            double freqLowerBound            = 20.0,
            double freqUpperBound            = 16000.0,
            int bandCount                    = 22,
            TransformRMSBehavior rmsBehavior = TransformRMSBehavior.Passthrough,
            Random randomizer                = null)
            : base(stream)
        {
            if (stream.Channels != 1)
            {
                throw new StreamCompositionException(
                          $"Carlile Shuffler requires a mono input stream. Input stream has {stream.Channels} channels.");
            }

            if (stream.ChannelSamples == int.MaxValue)
            {
                throw new StreamCompositionException(
                          $"Carlile Shuffler cannot be performed on a stream of infinite duration. Try truncating first.");
            }

            this.randomizer  = randomizer ?? new Random(CustomRandom.Next());
            this.rmsBehavior = rmsBehavior;

            frequencyDistribution = GetExponentialDistribution(freqLowerBound, freqUpperBound, bandCount);
        }
コード例 #17
0
 public static IBGCStream MultiConvolve(
     this IBGCStream stream,
     IBGCStream filter,
     bool recalculateRMS = false)
 {
     return(new MultiConvolutionFilter(stream, filter, recalculateRMS));
 }
コード例 #18
0
        public void SetStream(IBGCStream stream, bool disposeWhenComplete = false)
        {
            if (disposeStream && this.stream != null && !ReferenceEquals(stream, this.stream))
            {
                this.stream.Dispose();
            }

            if (stream != null)
            {
                int numChannels = stream.Channels;
                if (numChannels != 1 && numChannels != 2)
                {
                    Debug.LogError($"Completely unexpected stream channel count: {numChannels}");
                    if (disposeWhenComplete)
                    {
                        stream.Dispose();
                    }
                    stream = null;
                    disposeWhenComplete = false;
                }
            }

            this.stream   = stream;
            disposeStream = disposeWhenComplete;
            currentState  = SoundState.Stopped;
            ClearBuffers();
            WarmUpBuffers();
        }
コード例 #19
0
ファイル: BiQuadFilter.cs プロジェクト: TheArbalist/BGC_Tools
        public static BiQuadFilter HighShelfFilter(
            IBGCStream stream,
            double criticalFrequency,
            double dbGain)
        {
            double k          = Math.Tan(Math.PI * criticalFrequency / stream.SamplingRate);
            double gainFactor = Math.Pow(10.0, Math.Abs(dbGain) / 20.0);

            double norm, a0, a1, a2, b1, b2;

            if (dbGain >= 0.0)
            {
                //Boost
                norm = 1.0 / (1.0 + Math.Sqrt(2.0) * k + k * k);
                a0   = (gainFactor + Math.Sqrt(2.0 * gainFactor) * k + k * k) * norm;
                a1   = 2.0 * (k * k - gainFactor) * norm;
                a2   = (gainFactor - Math.Sqrt(2.0 * gainFactor) * k + k * k) * norm;
                b1   = 2.0 * (k * k - 1.0) * norm;
                b2   = (1.0 - Math.Sqrt(2.0) * k + k * k) * norm;
            }
            else
            {
                //Cut
                norm = 1.0 / (gainFactor + Math.Sqrt(2.0 * gainFactor) * k + k * k);
                a0   = (1.0 + Math.Sqrt(2.0) * k + k * k) * norm;
                a1   = 2.0 * (k * k - 1.0) * norm;
                a2   = (1.0 - Math.Sqrt(2.0) * k + k * k) * norm;
                b1   = 2.0 * (k * k - gainFactor) * norm;
                b2   = (gainFactor - Math.Sqrt(2.0 * gainFactor) * k + k * k) * norm;
            }

            return(new BiQuadFilter(stream, a0, a1, a2, b1, b2));
        }
コード例 #20
0
 public static IBGCStream PhaseVocode(
     this IBGCStream stream,
     double speed,
     TransformRMSBehavior rmsBehavior = TransformRMSBehavior.Passthrough)
 {
     return(new PhaseVocoder(stream, speed, rmsBehavior));
 }
コード例 #21
0
        public ExpanderFilter(
            IBGCStream stream,
            double ratio                     = 2.0,
            double threshold                 = -40.0,
            double attackDuration            = 0.010,
            double releaseDuration           = 0.050,
            double outputGain                = 0.0,
            TransformRMSBehavior rmsBehavior = TransformRMSBehavior.Passthrough)
            : base(stream)
        {
            this.threshold = threshold;

            attackGain  = (float)Math.Exp(-1.0 / (SamplingRate * attackDuration));
            releaseGain = (float)Math.Exp(-1.0 / (SamplingRate * releaseDuration));

            this.outputGain = (float)Math.Pow(10.0, outputGain / 20.0);

            slope = 1.0 - ratio;

            lastGain       = 0f;
            runningAverage = 0f;

            rmscoef = (float)Math.Pow(2, -100.0 / SamplingRate);

            this.rmsBehavior = rmsBehavior;
        }
コード例 #22
0
 public static IBGCStream Convolve(
     this IBGCStream stream,
     double[] filter,
     TransformRMSBehavior transformRMSBehavior = TransformRMSBehavior.Passthrough)
 {
     return(new ConvolutionFilter(stream, filter, transformRMSBehavior));
 }
コード例 #23
0
 public static IBGCStream MultiConvolve(
     this IBGCStream stream,
     float[] filter1,
     float[] filter2,
     TransformRMSBehavior transformRMSBehavior = TransformRMSBehavior.Passthrough)
 {
     return(new MultiConvolutionFilter(stream, filter1, filter2, transformRMSBehavior));
 }
コード例 #24
0
 public static IBGCStream Truncate(
     this IBGCStream stream,
     int totalChannelSamples,
     int offset = 0,
     TransformRMSBehavior transformRMSBehavior = TransformRMSBehavior.Passthrough)
 {
     return(new StreamTruncator(stream, totalChannelSamples, offset, transformRMSBehavior));
 }
コード例 #25
0
 public static IBGCStream Truncate(
     this IBGCStream stream,
     double totalDuration,
     int offset = 0,
     TransformRMSBehavior transformRMSBehavior = TransformRMSBehavior.Passthrough)
 {
     return(new StreamTruncator(stream, totalDuration, offset, transformRMSBehavior));
 }
コード例 #26
0
 /// <summary>
 /// Returns of stream padded by <paramref name="prependSamples"/> and <paramref name="appendSamples"/>
 /// </summary>
 public static IBGCStream PadBy(
     this IBGCStream stream,
     int prependSamples,
     int appendSamples,
     TransformRMSBehavior rmsBehavior = TransformRMSBehavior.Passthrough)
 {
     return(new StreamPadder(stream, prependSamples, appendSamples, rmsBehavior));
 }
コード例 #27
0
 /// <summary>
 /// Returns of stream padded by <paramref name="prependDuration"/> and <paramref name="appendDuration"/>
 /// </summary>
 public static IBGCStream PadBy(
     this IBGCStream stream,
     double prependDuration,
     double appendDuration,
     TransformRMSBehavior rmsBehavior = TransformRMSBehavior.Passthrough)
 {
     return(new StreamPadder(stream, prependDuration, appendDuration, rmsBehavior));
 }
コード例 #28
0
 /// <summary>
 /// Returns of stream <paramref name="duration"/> in duration, with the stream placed accordingly
 /// </summary>
 public static IBGCStream PadTo(
     this IBGCStream stream,
     double duration,
     StreamPadder.StimulusPlacement placement,
     TransformRMSBehavior rmsBehavior = TransformRMSBehavior.Passthrough)
 {
     return(new StreamPadder(stream, duration, placement, rmsBehavior));
 }
コード例 #29
0
 public StreamRepeater(IBGCStream stream)
     : base(stream)
 {
     if (stream.ChannelSamples == int.MaxValue)
     {
         throw new StreamCompositionException("Cannot apply a StreamRepeater to an infinite stream.");
     }
 }
コード例 #30
0
        protected override IBGCStream ApplyEffect(IBGCStream input)
        {
            using DisposableWaveProvider irFileReader = AudioTools.GetWaveProvider(reverbIRF.FilePath);

            IBGCStream filter = irFileReader.ToBGCStream().StereoStreamScaler(1.0 / reverbIRF.Gain).SafeCache();

            return(input.EnsureMono().MultiConvolve(filter));
        }