Example #1
0
        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;
 }