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; } }
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; }
public StreamChannelSplitter(IBGCStream stream, out IBGCStream splitStream) : base(stream) { Debug.Assert(stream.Channels == 2); this.splitStream = new InternalStreamSplit(this); splitStream = this.splitStream; }
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)); }
public static IBGCStream Center( this IBGCStream stream, int preDelaySamples, int postDelaySamples) { return(new StreamCenterer(stream, preDelaySamples, postDelaySamples)); }
public bool RemoveStream(IBGCStream stream) { bool success = streams.Remove(stream); UpdateStats(); return(success); }
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); }
private void StartFillBufferTask() { int fillBufferIndex = (bufferIndex + 1) % buffers.Length; IBGCStream fillStream = stream; fillBufferTask = Task.Run(() => FillBuffer(fillStream, buffers[fillBufferIndex])); }
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); }
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(); } } }
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; }
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]; }
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); }
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(); } } }
/// <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); }
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); }
public static IBGCStream MultiConvolve( this IBGCStream stream, IBGCStream filter, bool recalculateRMS = false) { return(new MultiConvolutionFilter(stream, filter, recalculateRMS)); }
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(); }
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)); }
public static IBGCStream PhaseVocode( this IBGCStream stream, double speed, TransformRMSBehavior rmsBehavior = TransformRMSBehavior.Passthrough) { return(new PhaseVocoder(stream, speed, rmsBehavior)); }
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; }
public static IBGCStream Convolve( this IBGCStream stream, double[] filter, TransformRMSBehavior transformRMSBehavior = TransformRMSBehavior.Passthrough) { return(new ConvolutionFilter(stream, filter, transformRMSBehavior)); }
public static IBGCStream MultiConvolve( this IBGCStream stream, float[] filter1, float[] filter2, TransformRMSBehavior transformRMSBehavior = TransformRMSBehavior.Passthrough) { return(new MultiConvolutionFilter(stream, filter1, filter2, transformRMSBehavior)); }
public static IBGCStream Truncate( this IBGCStream stream, int totalChannelSamples, int offset = 0, TransformRMSBehavior transformRMSBehavior = TransformRMSBehavior.Passthrough) { return(new StreamTruncator(stream, totalChannelSamples, offset, transformRMSBehavior)); }
public static IBGCStream Truncate( this IBGCStream stream, double totalDuration, int offset = 0, TransformRMSBehavior transformRMSBehavior = TransformRMSBehavior.Passthrough) { return(new StreamTruncator(stream, totalDuration, offset, transformRMSBehavior)); }
/// <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)); }
/// <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)); }
/// <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)); }
public StreamRepeater(IBGCStream stream) : base(stream) { if (stream.ChannelSamples == int.MaxValue) { throw new StreamCompositionException("Cannot apply a StreamRepeater to an infinite stream."); } }
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)); }