public AudioSampleBuffer Update(Spread <AudioSampleBuffer> inputs, Spread <int> outputMap) { var arrayInputs = inputs?.ToList(); var arrayMap = outputMap?.ToArray(); HasChanges = !AudioEngine.SequenceEquals(Inputs, arrayInputs) || !AudioEngine.ArrayEquals(OutputMap, arrayMap); Inputs = arrayInputs; OutputMap = arrayMap; if (HasChanges || HotSwapped) { AudioEngine.Log($"AudioMixer: configuration changed"); if (IsValid()) { processor = new AudioMixerProcessor(Inputs, OutputMap); output = processor.Build(); } else { output?.Dispose(); output = null; } HotSwapped = false; } return(output); }
private void BuildOversampling() { AudioEngine.Log($"AudioSampleLoop: {state} oversampling enabled {oversampling}"); decimators = new Decimator[outputChannels]; oversampleBuffer = new float[oversampling * outputChannels]; oversampleBuffer2 = new float[oversampling]; for (int i = 0; i < outputChannels; i++) { decimators[i] = new Decimator(oversampling, oversampling); } }
public Decimator(int oversample, int quality, float cutoff = 0.9f) { AudioEngine.Log($"Decimator: New Decimator created size={oversample * quality}"); Oversample = oversample; this.quality = quality; this.cutoff = cutoff; kernel = new float[oversample * quality]; inBuffer = new float[oversample * quality]; BoxcarLowpassIR(kernel, cutoff * 0.5f / oversample); BlackmanHarrisWindow(kernel); }
public void Swapped(object newInstance) { try { var s = RuntimeReflectionExtensions.GetRuntimeField(newInstance.GetType(), "HotSwapped"); s.SetValue(newInstance, true); } catch (Exception e) { AudioEngine.Log(e.Message); } }
public AudioSampleBuffer Update( bool reset, AudioSampleBuffer input, Func <IFrameClock, TState> create, Func <TState, AudioSampleAccessor, TState> update, int outputChannels = 1, int oversample = 1) { if (reset || state == null) { state = create(sampleClock); AudioEngine.Log($"AudioSampleLoop: Created {state}"); } hasChanges = reset != this.reset || input != this.input || outputChannels != this.outputChannels || oversample != oversampling; this.reset = reset; this.input = input; createFunc = create; updateFunc = update; this.outputChannels = outputChannels; oversampling = oversample; if (hasChanges || reset || HotSwapped) { AudioEngine.Log( $"AudioSampleLoop({state}) configuration changed outChannels={outputChannels}, oversampling={oversample}"); if (IsValid()) { processor = new AudioSampleLoopProcessor(state, input, sampleClock, update, outputChannels, oversample); output = processor.Build(); } else { output?.Dispose(); output = null; } HotSwapped = false; } processor.updateFunc = update; return(output); }
public IWavePlayer Create(int latency) { var asioOut = new AsioOut(driverName); AudioEngine.Log($"{asioOut.DriverInputChannelCount}"); AudioEngine.Log($"{asioOut.DriverOutputChannelCount}"); AudioEngine.Log($"{asioOut.PlaybackLatency}"); AudioEngine.Log($"{asioOut.NumberOfInputChannels}"); AudioEngine.Log($"{asioOut.NumberOfOutputChannels}"); AudioEngine.Log($"{asioOut.ChannelOffset}"); AudioEngine.Log($"{asioOut.InputChannelOffset}"); // AudioEngine.Log($"{asioOut.}"); // AudioEngine.Log($"{asioOut.}"); return(asioOut); }
public Spread <AudioSampleBuffer> Update(AudioSampleBuffer input, Spread <int> channelMap) { var arrayMap = channelMap?.ToArray(); hasChanges = input != this.input || !AudioEngine.ArrayEquals(this.channelMap, arrayMap); this.input = input; this.channelMap = arrayMap; if (hasChanges) { AudioEngine.Log($"AudioSplitter configuration changed!"); if (IsValid()) { var outputsBefore = outputs?.Length ?? 0; Build(); // Send nulls to update connected pins var fillOutputs = outputsBefore - (outputs?.Length ?? 0); if (fillOutputs > 0) { var builder = output.ToBuilder(); for (int i = 0; i < fillOutputs; i++) { builder.Add(null); } output = builder.ToSpread(); } } else { foreach (var buffer in outputs) { buffer.Dispose(); } // Send nulls to update connected pins var results = outputs.Select(o => (AudioSampleBuffer)null); return(results.ToSpread()); } } return(output); }
public AudioSampleBuffer Build() { BuildOutputMap(); multiplexer = new MultiplexingSampleProvider(inputs, outputMap.Length); for (int i = 0; i < outputMap.Length; i++) { var input = outputMap[i]; multiplexer.ConnectInputToOutput(input, i); AudioEngine.Log($" ch: {input} ==> {i}"); } return(new AudioSampleBuffer(multiplexer.WaveFormat) { Processor = this }); }
public AudioSampleHistoryBuffer(float bufferTime) { size = (int)(bufferTime * WaveOutput.InternalFormat.SampleRate); AudioEngine.Log($"AudioSampleHistoryBuffer: Create buffer for {bufferTime}s -> {size} samples"); buffer = new float[size]; }
public void Dispose() { AudioEngine.Log($"AudioSampleBuffer({GetHashCode()}): Disposed "); Processor = null; }
public AudioSampleBuffer(WaveFormat format) { AudioEngine.Log($"AudioSampleBuffer({GetHashCode()}): Created {format}"); WaveFormat = format; }
public void Update(WaveOutputDevice device, AudioSampleBuffer input, out string status, out WaveFormat waveFormat, out int latency, out float cpuUsage, out int bufferUnderRuns, int sampleRate = 44100, int driverLatency = 200, int internalLatency = 300, int bufferSize = 512, bool reset = false) { bool hasDeviceChanged = device?.Value != Device?.Value || sampleRate != SampleRate || driverLatency != DriverLatency || bufferSize != BufferSize || reset; Device = device; Input = input; SampleRate = sampleRate; InternalLatency = internalLatency; DriverLatency = driverLatency; BufferSize = bufferSize; if (hasDeviceChanged) { processor?.Dispose(); processor = null; if (waveOut != null) { AudioEngine.Log("Stopping WaveOut..."); waveOut.Stop(); waveOut.Dispose(); } } if (processor == null) { processor = new AudioThread.AudioThreadProcessor(BufferSize); } processor.EnsureThreadIsRunning(); processor.RequestedLatency = InternalLatency; if (hasDeviceChanged) { InternalFormat = WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, 2); SingleChannelFormat = WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, 1); processor.WaveFormat = InternalFormat; if (device != null) { AudioEngine.Log( $"WaveOutput: Configuration changed, device={device.Value}, sampleRate={sampleRate}, latency={InternalLatency} {HotSwapped} "); try { waveOut = ((IWaveOutputFactory)device.Tag).Create(DriverLatency); var wave16 = new SampleToWaveProvider16(processor); waveOut.Init(wave16); waveOut.Play(); AudioEngine.Log("WaveOutput: Started"); OutputFormat = wave16.WaveFormat; } catch (Exception e) { AudioEngine.Log(e); waveOut = null; } } } processor.Input = Input; status = waveOut != null?waveOut.PlaybackState.ToString() : "Uninitialized"; waveFormat = OutputFormat; latency = processor.Latency; cpuUsage = processor.CpuUsage; bufferUnderRuns = processor.BufferUnderRuns; }
public AudioSampleBuffer Update(WaveInputDevice device, out string status, out WaveFormat waveFormat, out int latency, out float cpuUsage, out int bufferUnderRuns, int driverLatency = 150, int internalLatency = 8, int bufferSize = 512, bool reset = false) { bool hasDeviceChanged = Device?.Value != device?.Value || DriverLatency != driverLatency || BufferSize != bufferSize || reset; Device = device; DriverLatency = driverLatency; InternalLatency = internalLatency; BufferSize = bufferSize; if (hasDeviceChanged) { processor?.Dispose(); processor = null; if (waveIn != null) { AudioEngine.Log("Stopping WaveIn..."); waveIn.StopRecording(); waveIn.Dispose(); } } if (processor == null) { processor = new AudioThread.AudioThreadProcessor(bufferSize); } processor.EnsureThreadIsRunning(); processor.RequestedLatency = internalLatency; if (hasDeviceChanged) { if (device != null) { AudioEngine.Log( $"WaveInput: Configuration changed, device={device.Value}, requested latency={DriverLatency}"); try { waveIn = ((IWaveInputFactory)device.Tag).Create(DriverLatency); bufferedWave = new BufferedWaveProvider(waveIn.WaveFormat); bufferedWave.DiscardOnBufferOverflow = true; sampleProvider = new WaveToSampleProvider(bufferedWave); OutputFormat = sampleProvider.WaveFormat; processor.WaveFormat = OutputFormat; processor.Input = sampleProvider; waveIn.DataAvailable += (s, a) => { bufferedWave.AddSamples(a.Buffer, 0, a.BytesRecorded); }; waveIn.StartRecording(); AudioEngine.Log("WaveInput: Started"); output = new AudioSampleBuffer(OutputFormat) { Processor = processor }; } catch (Exception e) { AudioEngine.Log(e); waveIn = null; } } } status = waveIn != null ? "Recording" : "Uninitialized"; waveFormat = OutputFormat; latency = processor.Latency; cpuUsage = processor.CpuUsage; bufferUnderRuns = processor.BufferUnderRuns; return(output); }
private void RunInThread() { float[] buffer = new float[bufferSize]; var stopWatch = Stopwatch.StartNew(); var clock = Stopwatch.StartNew(); var lastElapsed = 0.0; AudioEngine.Log($"Starting AudioThread {GetHashCode()}..."); try { while (Running) { if (playBuffer.IsValid && Input != null) { if (playBuffer.BufferedDuration.Milliseconds < RequestedLatency) { try { stopWatch.Stop(); var idleTime = stopWatch.ElapsedTicks; stopWatch.Restart(); while (playBuffer.BufferedDuration.Milliseconds < RequestedLatency) { Input?.Read(buffer, 0, buffer.Length); playBuffer.AddSamples(buffer, 0, buffer.Length); } Latency = playBuffer.BufferedDuration.Milliseconds; stopWatch.Stop(); var calcTime = stopWatch.ElapsedTicks; stopWatch.Restart(); CpuUsage = (float)calcTime / (idleTime + calcTime); } catch (Exception e) { AudioEngine.Log(e); } } else { if (RunWithoutOutput) { var elapsed = clock.Elapsed.TotalSeconds; var delta = elapsed - lastElapsed; lastElapsed = elapsed; playBuffer.Advance(TimeSpan.FromSeconds(delta)); Thread.Sleep(RequestedLatency); } } } else { Thread.Sleep(100); } } } catch (Exception e) { AudioEngine.Log(e); } AudioEngine.Log($"AudioThread {GetHashCode()} terminated"); }