public Stream(Guid DeviceId, Audio.Stream.SampleHandler Callback, Channel[] Input, Channel[] Output) : base(Input, Output) { Log.Global.WriteLine(MessageType.Info, "Instantiating ASIO stream with {0} input channels and {1} output channels.", Input.Length, Output.Length); asio = new AsioObject(DeviceId); asio.Init(IntPtr.Zero); callback = Callback; buffer = asio.BufferSize.Preferred; ASIOBufferInfo[] infos = new ASIOBufferInfo[Input.Length + Output.Length]; for (int i = 0; i < Input.Length; ++i) { infos[i].isInput = ASIOBool.True; infos[i].channelNum = Input[i].Index; } for (int i = 0; i < Output.Length; ++i) { infos[Input.Length + i].isInput = ASIOBool.False; infos[Input.Length + i].channelNum = Output[i].Index; } ASIOCallbacks callbacks = new ASIOCallbacks() { bufferSwitch = OnBufferSwitch, sampleRateDidChange = OnSampleRateChange, asioMessage = OnAsioMessage, bufferSwitchTimeInfo = OnBufferSwitchTimeInfo }; asio.CreateBuffers(infos, buffer, callbacks); input = new Buffer[Input.Length]; for (int i = 0; i < Input.Length; ++i) input[i] = new Buffer(infos[i], Input[i].Type, buffer); output = new Buffer[Output.Length]; for (int i = 0; i < Output.Length; ++i) output[i] = new Buffer(infos[Input.Length + i], Output[i].Type, buffer); sampleRate = asio.SampleRate; asio.Start(); }
public LiveSimulation(Circuit.Schematic Simulate, Audio.Device Device, Audio.Channel[] Inputs, Audio.Channel[] Outputs) { try { InitializeComponent(); // Make a clone of the schematic so we can mess with it. Circuit.Schematic clone = Circuit.Schematic.Deserialize(Simulate.Serialize(), Log); clone.Elements.ItemAdded += OnElementAdded; clone.Elements.ItemRemoved += OnElementRemoved; Schematic = new SimulationSchematic(clone); Schematic.SelectionChanged += OnProbeSelected; // Build the circuit from the schematic. circuit = Schematic.Schematic.Build(Log); // Create the input and output controls. IEnumerable<Circuit.Component> components = circuit.Components; // Create audio input channels. for (int i = 0; i < Inputs.Length; ++i) InputChannels.Add(new InputChannel(i) { Name = Inputs[i].Name }); ComputerAlgebra.Expression speakers = 0; foreach (Circuit.Component i in components) { Circuit.Symbol S = i.Tag as Circuit.Symbol; if (S == null) continue; SymbolControl tag = (SymbolControl)S.Tag; if (tag == null) continue; // Create potentiometers. Circuit.IPotControl c = i as Circuit.IPotControl; if (c != null) { PotControl pot = new PotControl() { Width = 80, Height = 80, Opacity = 0.5, FontSize = 15, FontWeight = FontWeights.Bold, }; Schematic.overlays.Children.Add(pot); Canvas.SetLeft(pot, Canvas.GetLeft(tag) - pot.Width / 2 + tag.Width / 2); Canvas.SetTop(pot, Canvas.GetTop(tag) - pot.Height / 2 + tag.Height / 2); pot.Value = c.PotValue; pot.ValueChanged += x => { c.PotValue = x; UpdateSimulation(false); }; pot.MouseEnter += (o, e) => pot.Opacity = 0.95; pot.MouseLeave += (o, e) => pot.Opacity = 0.5; } // Create Buttons. Circuit.IButtonControl b = i as Circuit.IButtonControl; if (b != null) { Button button = new Button() { Width = tag.Width, Height = tag.Height, Opacity = 0.5, Background = Brushes.White, }; Schematic.overlays.Children.Add(button); Canvas.SetLeft(button, Canvas.GetLeft(tag)); Canvas.SetTop(button, Canvas.GetTop(tag)); button.Click += (o, e) => { // Click all the buttons in the group. foreach (Circuit.IButtonControl j in components.OfType<Circuit.IButtonControl>().Where(x => x.Group == b.Group)) j.Click(); UpdateSimulation(true); }; button.MouseEnter += (o, e) => button.Opacity = 0.95; button.MouseLeave += (o, e) => button.Opacity = 0.5; } Circuit.Speaker output = i as Circuit.Speaker; if (output != null) speakers += output.V; // Create input controls. Circuit.Input input = i as Circuit.Input; if (input != null) { tag.ShowText = false; ComboBox combo = new ComboBox() { Width = 80, Height = 24, Opacity = 0.5, IsEditable = true, SelectedValuePath = "Tag", }; foreach (InputChannel j in InputChannels) { combo.Items.Add(new ComboBoxItem() { Tag = j, Content = j.Name }); } Schematic.overlays.Children.Add(combo); Canvas.SetLeft(combo, Canvas.GetLeft(tag) - combo.Width / 2 + tag.Width / 2); Canvas.SetTop(combo, Canvas.GetTop(tag) - combo.Height / 2 + tag.Height / 2); ComputerAlgebra.Expression V = Circuit.Component.DependentVariable(input.Name, Circuit.Component.t); inputs[V] = new SignalChannel(0); combo.SelectionChanged += (o, e) => { if (combo.SelectedItem != null) { ComboBoxItem it = (ComboBoxItem)combo.SelectedItem; inputs[V] = new InputChannel(((InputChannel)it.Tag).Index); } }; combo.AddHandler(TextBox.KeyDownEvent, new KeyEventHandler((o, e) => { try { inputs[V] = new SignalChannel(Circuit.Quantity.Parse(combo.Text, Circuit.Units.V)); } catch (Exception) { // If there is an error in the expression, zero out the signal. inputs[V] = new SignalChannel(0); } })); if (combo.Items.Count > 0) combo.SelectedItem = combo.Items[0]; else combo.Text = "0 V"; combo.MouseEnter += (o, e) => combo.Opacity = 0.95; combo.MouseLeave += (o, e) => combo.Opacity = 0.5; } } // Create audio output channels. for (int i = 0; i < Outputs.Length; ++i) { OutputChannel c = new OutputChannel(i) { Name = Outputs[i].Name, Signal = speakers }; c.PropertyChanged += (o, e) => { if (e.PropertyName == "Signal") RebuildSolution(); }; OutputChannels.Add(c); } // Begin audio processing. if (Inputs.Any() || Outputs.Any()) stream = Device.Open(ProcessSamples, Inputs, Outputs); else stream = new NullStream(ProcessSamples); ContentRendered += (o, e) => RebuildSolution(); Closed += (s, e) => stream.Stop(); } catch (Exception Ex) { MessageBox.Show(Ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } }
private void RunSimulation(int Count, Audio.SampleBuffer[] In, Audio.SampleBuffer[] Out, double Rate) { try { // If the sample rate changed, we need to kill the simulation and let the foreground rebuild it. if (Rate != (double)simulation.SampleRate) { simulation = null; Dispatcher.InvokeAsync(() => RebuildSolution()); return; } List<double[]> ins = new List<double[]>(inputs.Count); foreach (Channel i in inputs.Values) { if (i is InputChannel) ins.Add(In[((InputChannel)i).Index].LockSamples(true, false)); else if (i is SignalChannel) ins.Add(((SignalChannel)i).Buffer(Count, simulation.Time, simulation.TimeStep)); } List<double[]> outs = new List<double[]>(probes.Count + Out.Length); foreach (Probe i in probes) outs.Add(i.AllocBuffer(Count)); for (int i = 0; i < Out.Length; ++i) outs.Add(Out[i].LockSamples(false, true)); // Process the samples! simulation.Run(Count, ins, outs); // Show the samples on the oscilloscope. long clock = Scope.Signals.Clock; foreach (Probe i in probes) i.Signal.AddSamples(clock, i.Buffer); } catch (Circuit.SimulationDiverged Ex) { // If the simulation diverged more than one second ago, reset it and hope it doesn't happen again. Log.WriteLine(MessageType.Error, "Error: " + Ex.Message); simulation = null; if ((double)Ex.At > Rate) Dispatcher.InvokeAsync(() => RebuildSolution()); foreach (Audio.SampleBuffer i in Out) i.Clear(); } catch (Exception Ex) { // If there was a more serious error, kill the simulation so the user can fix it. Log.WriteException(Ex); simulation = null; foreach (Audio.SampleBuffer i in Out) i.Clear(); } // Unlock sample buffers. foreach (Audio.SampleBuffer i in Out) i.Unlock(); foreach (Audio.SampleBuffer i in In) i.Unlock(); }
private void ProcessSamples(int Count, Audio.SampleBuffer[] In, Audio.SampleBuffer[] Out, double Rate) { // Apply input gain. for (int i = 0; i < In.Length; ++i) { Channel ch = InputChannels[i]; double peak = In[i].Amplify(inputGain * ch.V0dB); Dispatcher.InvokeAsync(() => ch.SignalStatus = MapSignalToBrush(peak)); } // Run the simulation. lock (sync) { if (simulation != null) RunSimulation(Count, In, Out, Rate); else foreach (Audio.SampleBuffer i in Out) i.Clear(); } // Apply output gain. for (int i = 0; i < Out.Length; ++i) { Channel ch = OutputChannels[i]; double peak = Out[i].Amplify(outputGain / ch.V0dB); Dispatcher.InvokeAsync(() => ch.SignalStatus = MapSignalToBrush(peak)); } // Tick oscilloscope. Scope.Signals.TickClock(Count, Rate); }
private static double AmplifySignal(Audio.SampleBuffer Signal, double Gain) { double peak = 0.0; using (Audio.SamplesLock samples = new Audio.SamplesLock(Signal, true, true)) { for (int i = 0; i < samples.Count; ++i) { double v = samples[i]; v *= Gain; peak = Math.Max(peak, Math.Abs(v)); samples[i] = v; } } return peak; }