Example #1
0
        static int GetBufferSize(XtStream stream, int frames)
        {
            XtFormat format     = stream.GetFormat();
            int      sampleSize = XtAudio.GetSampleAttributes(format.mix.sample).size;

            return(frames * format.inputs * sampleSize);
        }
Example #2
0
        internal void StreamCallback(IntPtr stream, IntPtr input, IntPtr output,
            int frames, double time, ulong position, bool timeValid, ulong error, IntPtr u) {

            XtFormat format = GetFormat();
            bool interleaved = IsInterleaved();
            object inData = raw ? (object)input : input == IntPtr.Zero ? null : interleaved ? inputInterleaved : inputNonInterleaved;
            object outData = raw ? (object)output : output == IntPtr.Zero ? null : interleaved ? outputInterleaved : outputNonInterleaved;

            if (!raw && inData != null)
                if (interleaved)
                    CopyInterleavedBufferFromNative(format.mix.sample, input, (Array)inData, format.inputs, frames);
                else
                    CopyNonInterleavedBufferFromNative(format.mix.sample, input, (Array)inData, format.inputs, frames);

            try {
                streamCallback(this, inData, outData, frames, time, position, timeValid, error, user);
            } catch (Exception e) {
                if (XtAudio.trace != null)
                    XtAudio.trace(XtLevel.Fatal, string.Format("Exception caught in xrun callback: {0}.", e));
                Console.WriteLine(e);
                Console.WriteLine(e.StackTrace);
                Environment.FailFast("Exception caught in stream callback.", e);
            }

            if (!raw && outData != null)
                if (interleaved)
                    CopyInterleavedBufferToNative(format.mix.sample, (Array)outData, output, format.outputs, frames);
                else
                    CopyNonInterleavedBufferToNative(format.mix.sample, (Array)outData, output, format.outputs, frames);
        }
Example #3
0
        internal void OnCallback(XtStream stream, object input, object output, int frames,
                                 double time, ulong position, bool timeValid, ulong error, object user)
        {
            if (error != 0)
            {
                onError(() => "Stream callback error: " + XtPrint.ErrorToString(error));
                return;
            }

            XtFormat format      = stream.GetFormat();
            bool     interleaved = stream.IsInterleaved();

            OnCallback(format, interleaved, stream.IsRaw(), input, output, frames);
            processed += frames;
            if (processed < format.mix.rate * 3)
            {
                return;
            }

            processed = 0;
            XtLatency latency      = stream.GetLatency();
            string    formatString = "Stream {1}:{0}\tinput latency:{2}{0}\toutput latency:{3}{0}\t" +
                                     "buffer frames:{4}{0}\tcurrent frames:{5}{0}\ttime:{6}{0}\tposition:{7}{0}\ttimeValid:{8}{0}\tuser:{9}.";

            OnMessage(() => string.Format(formatString, Environment.NewLine, name, latency.input,
                                          latency.output, stream.GetFrames(), frames, time, position, timeValid, user));
        }
Example #4
0
        public static void Main(string[] args)
        {
            XtMix      mix            = new XtMix(48000, XtSample.Int16);
            XtFormat   inputFormat    = new XtFormat(mix, 2, 0, 0, 0);
            XtChannels inputChannels  = new XtChannels(2, 0, 0, 0);
            XtFormat   outputFormat   = new XtFormat(mix, 0, 0, 2, 0);
            XtChannels outputChannels = new XtChannels(0, 0, 2, 0);

            using (XtAudio audio = new XtAudio(null, IntPtr.Zero, null, null)) {
                XtService service = XtAudio.GetServiceBySetup(XtSetup.SystemAudio);
                using (XtDevice input = service.OpenDefaultDevice(false))
                    using (XtDevice output = service.OpenDefaultDevice(true)) {
                        if (input != null && input.SupportsFormat(inputFormat) &&
                            output != null && output.SupportsFormat(outputFormat))
                        {
                            using (XtStream stream = service.AggregateStream(
                                       new XtDevice[] { input, output },
                                       new XtChannels[] { inputChannels, outputChannels },
                                       new double[] { 30.0, 30.0 },
                                       2, mix, true, false, output, OnAggregate, XRun, "user-data")) {
                                stream.Start();
                                Console.WriteLine("Streaming aggregate, press any key to continue...");
                                Console.ReadLine();
                                stream.Stop();
                            }
                        }
                    }
            }
        }
Example #5
0
        public bool SupportsFormat(XtFormat format)
        {
            bool supports;

            XtNative.Format native = XtNative.Format.ToNative(format);
            XtNative.HandleError(XtNative.XtDeviceSupportsFormat(d, ref native, out supports));
            return(supports);
        }
Example #6
0
        public XtBuffer GetBuffer(XtFormat format)
        {
            XtBuffer buffer = new XtBuffer();

            XtNative.Format native = XtNative.Format.ToNative(format);
            XtNative.HandleError(XtNative.XtDeviceGetBuffer(d, ref native, buffer));
            return(buffer);
        }
Example #7
0
        public static void Main(string[] args)
        {
            XtFormat format;
            XtFormat int44100   = new XtFormat(new XtMix(44100, XtSample.Int32), 2, 0, 2, 0);
            XtFormat int48000   = new XtFormat(new XtMix(48000, XtSample.Int32), 2, 0, 2, 0);
            XtFormat float44100 = new XtFormat(new XtMix(44100, XtSample.Float32), 2, 0, 2, 0);
            XtFormat float48000 = new XtFormat(new XtMix(48000, XtSample.Float32), 2, 0, 2, 0);

            using (XtAudio audio = new XtAudio(null, IntPtr.Zero, null, null))
            {
                XtService service = XtAudio.GetServiceBySetup(XtSetup.ProAudio);
                if (service == null)
                {
                    return;
                }

                using (XtDevice device = service.OpenDefaultDevice(true))
                {
                    if (device == null)
                    {
                        return;
                    }

                    if (device.SupportsFormat(int44100))
                    {
                        format = int44100;
                    }
                    else if (device.SupportsFormat(int48000))
                    {
                        format = int48000;
                    }
                    else if (device.SupportsFormat(float44100))
                    {
                        format = float44100;
                    }
                    else if (device.SupportsFormat(float48000))
                    {
                        format = float48000;
                    }
                    else
                    {
                        return;
                    }

                    XtBuffer buffer = device.GetBuffer(format);
                    using (XtStream stream = device.OpenStream(format, true,
                                                               false, buffer.min, Callback, null, null))
                    {
                        stream.Start();
                        Console.WriteLine("Streaming full-duplex, press any key to continue...");
                        Console.ReadLine();
                        stream.Stop();
                    }
                }
            }
        }
Example #8
0
 internal XtSafeBuffer(XtStream stream, bool interleaved)
 {
     _stream      = stream;
     _interleaved = interleaved;
     _format      = stream.GetFormat();
     _inputs      = _format.channels.inputs;
     _outputs     = _format.channels.outputs;
     _attrs       = XtAudio.GetSampleAttributes(_format.mix.sample);
     _input       = CreateBuffer(_inputs);
     _output      = CreateBuffer(_outputs);
 }
Example #9
0
        static void OnAggregate(XtStream stream, object input, object output, int frames, double time,
                                ulong position, bool timeValid, ulong error, object user)
        {
            XtFormat     format = stream.GetFormat();
            XtAttributes attrs  = XtAudio.GetSampleAttributes(format.mix.sample);

            if (frames > 0)
            {
                Buffer.BlockCopy((Array)input, 0, (Array)output, 0, frames * format.inputs * attrs.size);
            }
        }
Example #10
0
            public XtFormat FromNative()
            {
                XtFormat result = new XtFormat();

                result.mix.rate   = rate;
                result.mix.sample = sample;
                result.inputs     = inputs;
                result.inMask     = inMask;
                result.outputs    = outputs;
                result.outMask    = outMask;
                return(result);
            }
Example #11
0
            public static Format ToNative(XtFormat format)
            {
                Format result = new Format();

                result.rate    = format.mix.rate;
                result.sample  = format.mix.sample;
                result.inputs  = format.inputs;
                result.inMask  = format.inMask;
                result.outputs = format.outputs;
                result.outMask = format.outMask;
                return(result);
            }
Example #12
0
        public XtStream OpenStream(XtFormat format, bool interleaved, bool raw, double bufferSize,
                                   XtStreamCallback streamCallback, XtXRunCallback xRunCallback, object user)
        {
            IntPtr   s;
            XtStream stream = new XtStream(raw, streamCallback, xRunCallback, user);

            XtNative.Format native = XtNative.Format.ToNative(format);
            XtNative.HandleError(XtNative.XtDeviceOpenStream(d, ref native, interleaved,
                                                             bufferSize, stream.streamCallbackPtr, stream.xRunCallbackPtr, IntPtr.Zero, out s));
            stream.Init(s);
            return(stream);
        }
Example #13
0
        static unsafe void RenderNonInterleavedRaw(XtStream stream, object input, object output,
                                                   int frames, double time, ulong position, bool timeValid, ulong error, object user)
        {
            XtFormat format = stream.GetFormat();

            for (int f = 0; f < frames; f++)
            {
                float sine = NextSine(format.mix.rate);
                for (int c = 0; c < format.outputs; c++)
                {
                    ((float **)(IntPtr)output)[c][f] = sine;
                }
            }
        }
Example #14
0
        static void RenderInterleaved(XtStream stream, object input, object output,
                                      int frames, double time, ulong position, bool timeValid, ulong error, object user)
        {
            XtFormat format = stream.GetFormat();

            for (int f = 0; f < frames; f++)
            {
                float sine = NextSine(format.mix.rate);
                for (int c = 0; c < format.outputs; c++)
                {
                    ((float[])output)[f * format.outputs + c] = sine;
                }
            }
        }
Example #15
0
 internal void Init(IntPtr s) {
     this.s = s;
     if (!IsRaw()) {
         int frames = GetFrames();
         XtFormat format = GetFormat();
         if (IsInterleaved()) {
             inputInterleaved = CreateInterleavedBuffer(format.mix.sample, format.inputs, frames);
             outputInterleaved = CreateInterleavedBuffer(format.mix.sample, format.outputs, frames);
         } else {
             inputNonInterleaved = CreateNonInterleavedBuffer(format.mix.sample, format.inputs, frames);
             outputNonInterleaved = CreateNonInterleavedBuffer(format.mix.sample, format.outputs, frames);
         }
     }
 }
Example #16
0
 static void CaptureNonInterleaved(XtStream stream, object input, object output,
                                   int frames, double time, ulong position, bool timeValid, ulong error, object user)
 {
     if (frames > 0)
     {
         Context  ctx        = (Context)user;
         XtFormat format     = stream.GetFormat();
         int      channels   = format.inputs;
         int      sampleSize = XtAudio.GetSampleAttributes(format.mix.sample).size;
         for (int f = 0; f < frames; f++)
         {
             for (int c = 0; c < channels; c++)
             {
                 // Don't do this.
                 ctx.recording.Write(((byte[][])input)[c], f * sampleSize, sampleSize);
             }
         }
     }
 }
Example #17
0
 static unsafe void CaptureNonInterleavedRaw(XtStream stream, object input, object output,
                                             int frames, double time, ulong position, bool timeValid, ulong error, object user)
 {
     if (frames > 0)
     {
         Context  ctx        = (Context)user;
         XtFormat format     = stream.GetFormat();
         int      channels   = format.inputs;
         int      sampleSize = XtAudio.GetSampleAttributes(format.mix.sample).size;
         for (int f = 0; f < frames; f++)
         {
             for (int c = 0; c < channels; c++)
             {
                 IntPtr source = new IntPtr(&(((byte **)(IntPtr)input)[c][f * sampleSize]));
                 Marshal.Copy(source, ctx.intermediate, 0, sampleSize);
                 // Don't do this.
                 ctx.recording.Write(ctx.intermediate, 0, sampleSize);
             }
         }
     }
 }
Example #18
0
        XtFormat?GetFormat(bool output)
        {
            if (_sample.SelectedItem == null ||
                _rate.SelectedItem == null ||
                _channelCount.SelectedItem == null)
            {
                return(null);
            }
            XtFormat result = new XtFormat();

            result.mix.rate   = (int)_rate.SelectedItem;
            result.mix.sample = (XtSample)_sample.SelectedItem;
            if (output)
            {
                result.channels.outputs = (int)_channelCount.SelectedItem;
            }
            else
            {
                result.channels.inputs = (int)_channelCount.SelectedItem;
            }
            return(result);
        }
Example #19
0
 internal override void OnCallback(XtFormat format, bool interleaved,
                                   bool raw, object input, object output, int frames)
 {
     if (frames == 0)
     {
         return;
     }
     if (!raw && !interleaved)
     {
         Utility.Interleave((Array)input, interleavedBuffer, format.mix.sample, format.inputs, frames);
     }
     else if (raw && !interleaved)
     {
         Utility.Interleave((IntPtr)input, interleavedBuffer, format.mix.sample, format.inputs, frames);
     }
     else if (raw && interleaved)
     {
         Utility.Copy((IntPtr)input, interleavedBuffer, format.mix.sample, format.inputs, frames);
     }
     Buffer.BlockCopy(interleaved && !raw ? (Array)input : interleavedBuffer, 0, block, 0, frames * frameSize);
     stream.Write(block, 0, frames * frameSize);
 }
Example #20
0
        private XtFormat GetFormat(bool output)
        {
            if (sample.SelectedItem == null ||
                rate.SelectedItem == null ||
                channelCount.SelectedItem == null)
            {
                return(null);
            }

            XtFormat result = new XtFormat();

            result.mix.rate   = (int)rate.SelectedItem;
            result.mix.sample = (XtSample)sample.SelectedItem;
            if (output)
            {
                result.outputs = (int)channelCount.SelectedItem;
            }
            else
            {
                result.inputs = (int)channelCount.SelectedItem;
            }
            return(result);
        }
Example #21
0
        internal override unsafe void OnCallback(XtFormat format, bool interleaved,
                                                 bool raw, object input, object output, int frames)
        {
            int sampleSize = XtAudio.GetSampleAttributes(format.mix.sample).size;

            if (!raw)
            {
                if (interleaved)
                {
                    Buffer.BlockCopy((Array)input, 0, (Array)output, 0, frames * format.inputs * sampleSize);
                }
                else
                {
                    for (int i = 0; i < format.inputs; i++)
                    {
                        Buffer.BlockCopy((Array)(((Array)input).GetValue(i)), 0, (Array)(((Array)output).GetValue(i)), 0, frames * sampleSize);
                    }
                }
            }
            else
            {
                if (interleaved)
                {
                    Utility.MemCpy((IntPtr)output, (IntPtr)input, new IntPtr(frames * format.inputs * sampleSize));
                }
                else
                {
                    for (int i = 0; i < format.inputs; i++)
                    {
                        Utility.MemCpy(
                            new IntPtr(((void **)(((IntPtr)output).ToPointer()))[i]),
                            new IntPtr(((void **)(((IntPtr)input).ToPointer()))[i]),
                            new IntPtr(frames * sampleSize));
                    }
                }
            }
        }
Example #22
0
        private void FormatOrDeviceChanged()
        {
            if (sample.SelectedItem != null)
            {
                var attrs = XtAudio.GetSampleAttributes((XtSample)sample.SelectedItem);
                attributes.Text = XtPrint.AttributesToString(attrs);
            }

            XtFormat inputFormat = GetFormat(false);
            XtDevice inputDevice = this.inputDevice.SelectedItem == null ?
                                   null : ((DeviceView)(this.inputDevice.SelectedItem)).device;
            bool inputSupported = inputDevice == null ? false : inputDevice.SupportsFormat(inputFormat);

            inputFormatSupported.Text = inputSupported.ToString();
            XtBuffer inputBuffer = !inputSupported ? null : inputDevice.GetBuffer(inputFormat);

            inputBufferSizes.Text = !inputSupported ? "N/A" : string.Format("{0} / {1} / {2}",
                                                                            inputBuffer.min.ToString("N1"), inputBuffer.current.ToString("N1"), inputBuffer.max.ToString("N1"));
            inputMix.Text         = inputDevice == null || inputDevice.GetMix() == null ? "N/A" : inputDevice.GetMix().ToString();
            inputInterleaved.Text = inputDevice == null
                ? "N/A"
                : inputDevice.SupportsAccess(true) && inputDevice.SupportsAccess(false)
                ? "Both"
                : inputDevice.SupportsAccess(false)
                ? "False"
                : "True";
            List <ChannelView> inputViews = new List <ChannelView>();

            if (inputDevice != null)
            {
                inputViews = (from i in Enumerable.Range(0, inputDevice.GetChannelCount(false))
                              select new ChannelView {
                    index = i, name = (1 + i) + ": " + inputDevice.GetChannelName(false, i)
                })
                             .ToList();
            }
            inputChannels.DataSource = null;
            inputChannels.DataSource = inputViews;
            inputChannels.SelectedItems.Clear();

            XtFormat outputFormat = GetFormat(true);
            XtDevice outputDevice = this.outputDevice.SelectedItem == null ?
                                    null : ((DeviceView)(this.outputDevice.SelectedItem)).device;
            bool outputSupported = outputDevice == null ? false : outputDevice.SupportsFormat(outputFormat);

            outputFormatSupported.Text = outputSupported.ToString();
            XtBuffer outputBuffer = !outputSupported ? null : outputDevice.GetBuffer(outputFormat);

            outputBufferSizes.Text = !outputSupported ? "N/A" : string.Format("{0} / {1} / {2}",
                                                                              outputBuffer.min.ToString("N1"), outputBuffer.current.ToString("N1"), outputBuffer.max.ToString("N1"));
            outputMix.Text         = outputDevice == null || outputDevice.GetMix() == null ? "N/A" : outputDevice.GetMix().ToString();
            outputInterleaved.Text = outputDevice == null
                ? "N/A"
                : outputDevice.SupportsAccess(true) && outputDevice.SupportsAccess(false)
                ? "Both"
                : outputDevice.SupportsAccess(false)
                ? "False"
                : "True";
            List <ChannelView> outputViews = new List <ChannelView>();

            if (outputDevice != null)
            {
                outputViews = (from i in Enumerable.Range(0, outputDevice.GetChannelCount(true))
                               select new ChannelView {
                    index = i, name = (1 + i) + ": " + outputDevice.GetChannelName(true, i)
                })
                              .ToList();
            }
            outputChannels.DataSource = null;
            outputChannels.DataSource = outputViews;
            outputChannels.SelectedItems.Clear();

            bufferSize.Minimum = 1;
            bufferSize.Maximum = 5000;
            bufferSize.Value   = 1000;
            if (outputBuffer != null)
            {
                bufferSize.Minimum       = (int)Math.Floor(outputBuffer.min);
                bufferSize.Maximum       = (int)Math.Ceiling(outputBuffer.max);
                bufferSize.Value         = (int)Math.Ceiling(outputBuffer.current);
                bufferSize.TickFrequency = (bufferSize.Maximum - bufferSize.Minimum) / 10;
            }
        }
Example #23
0
        internal override unsafe void OnCallback(XtFormat format, bool interleaved,
                                                 bool raw, object input, object output, int frames)
        {
            for (int f = 0; f < frames; f++)
            {
                int    ival;
                double val = Math.Sin(phase * 2.0 * Math.PI);
                phase += Frequency / format.mix.rate;
                if (phase >= 1.0)
                {
                    phase = -1.0;
                }

                if (!raw)
                {
                    if (interleaved)
                    {
                        for (int c = 0; c < format.outputs; c++)
                        {
                            int pos = f * format.outputs + c;
                            switch (format.mix.sample)
                            {
                            case XtSample.UInt8:
                                ((byte[])output)[pos] = (byte)((val * 0.5 + 0.5) * byte.MaxValue);
                                break;

                            case XtSample.Int16:
                                ((short[])output)[pos] = (short)(val * short.MaxValue);
                                break;

                            case XtSample.Int24:
                                ival = (int)(val * int.MaxValue);
                                ((byte[])output)[pos * 3]     = (byte)((ival & 0x0000FF00) >> 8);
                                ((byte[])output)[pos * 3 + 1] = (byte)((ival & 0x00FF0000) >> 16);
                                ((byte[])output)[pos * 3 + 2] = (byte)((ival & 0xFF000000) >> 24);
                                break;

                            case XtSample.Int32:
                                ((int[])output)[pos] = (int)(val * int.MaxValue);
                                break;

                            case XtSample.Float32:
                                ((float[])output)[pos] = (float)val;
                                break;

                            default:
                                break;
                            }
                        }
                    }
                    else
                    {
                        for (int c = 0; c < format.outputs; c++)
                        {
                            switch (format.mix.sample)
                            {
                            case XtSample.UInt8:
                                ((byte[][])output)[c][f] = (byte)((val * 0.5 + 0.5) * byte.MaxValue);
                                break;

                            case XtSample.Int16:
                                ((short[][])output)[c][f] = (short)(val * short.MaxValue);
                                break;

                            case XtSample.Int24:
                                ival = (int)(val * int.MaxValue);
                                ((byte[][])output)[c][f * 3]     = (byte)((ival & 0x0000FF00) >> 8);
                                ((byte[][])output)[c][f * 3 + 1] = (byte)((ival & 0x00FF0000) >> 16);
                                ((byte[][])output)[c][f * 3 + 2] = (byte)((ival & 0xFF000000) >> 24);
                                break;

                            case XtSample.Int32:
                                ((int[][])output)[c][f] = (int)(val * int.MaxValue);
                                break;

                            case XtSample.Float32:
                                ((float[][])output)[c][f] = (float)val;
                                break;

                            default:
                                break;
                            }
                        }
                    }
                }
                else
                {
                    if (interleaved)
                    {
                        for (int c = 0; c < format.outputs; c++)
                        {
                            int pos = f * format.outputs + c;
                            switch (format.mix.sample)
                            {
                            case XtSample.UInt8:
                                ((byte *)(IntPtr)output)[pos] = (byte)((val * 0.5 + 0.5) * byte.MaxValue);
                                break;

                            case XtSample.Int16:
                                ((short *)(IntPtr)output)[pos] = (short)(val * short.MaxValue);
                                break;

                            case XtSample.Int24:
                                ival = (int)(val * int.MaxValue);
                                ((byte *)(IntPtr)output)[pos * 3]     = (byte)((ival & 0x0000FF00) >> 8);
                                ((byte *)(IntPtr)output)[pos * 3 + 1] = (byte)((ival & 0x00FF0000) >> 16);
                                ((byte *)(IntPtr)output)[pos * 3 + 2] = (byte)((ival & 0xFF000000) >> 24);
                                break;

                            case XtSample.Int32:
                                ((int *)(IntPtr)output)[pos] = (int)(val * int.MaxValue);
                                break;

                            case XtSample.Float32:
                                ((float *)(IntPtr)output)[pos] = (float)val;
                                break;

                            default:
                                break;
                            }
                        }
                    }
                    else
                    {
                        for (int c = 0; c < format.outputs; c++)
                        {
                            switch (format.mix.sample)
                            {
                            case XtSample.UInt8:
                                ((byte **)(IntPtr)output)[c][f] = (byte)((val * 0.5 + 0.5) * byte.MaxValue);
                                break;

                            case XtSample.Int16:
                                ((short **)(IntPtr)output)[c][f] = (short)(val * short.MaxValue);
                                break;

                            case XtSample.Int24:
                                ival = (int)(val * int.MaxValue);
                                ((byte **)(IntPtr)output)[c][f * 3]     = (byte)((ival & 0x0000FF00) >> 8);
                                ((byte **)(IntPtr)output)[c][f * 3 + 1] = (byte)((ival & 0x00FF0000) >> 16);
                                ((byte **)(IntPtr)output)[c][f * 3 + 2] = (byte)((ival & 0xFF000000) >> 24);
                                break;

                            case XtSample.Int32:
                                ((int **)(IntPtr)output)[c][f] = (int)(val * int.MaxValue);
                                break;

                            case XtSample.Float32:
                                ((float **)(IntPtr)output)[c][f] = (float)val;
                                break;

                            default:
                                break;
                            }
                        }
                    }
                }
            }
        }
Example #24
0
        public static void Main(String[] args)
        {
            using (XtAudio audio = new XtAudio(null, IntPtr.Zero, null, null)) {
                XtService service = XtAudio.GetServiceBySetup(XtSetup.ConsumerAudio);
                XtFormat  format  = new XtFormat(new XtMix(44100, XtSample.Float32), 0, 0, 2, 0);
                using (XtDevice device = service.OpenDefaultDevice(true)) {
                    if (device == null)
                    {
                        Console.WriteLine("No default device found.");
                        return;
                    }

                    if (!device.SupportsFormat(format))
                    {
                        Console.WriteLine("Format not supported.");
                        return;
                    }

                    XtBuffer buffer = device.GetBuffer(format);

                    using (XtStream stream = device.OpenStream(format, true, false,
                                                               buffer.current, RenderInterleaved, XRun, "user-data")) {
                        stream.Start();
                        Console.WriteLine("Rendering interleaved...");
                        ReadLine();
                        stream.Stop();
                    }

                    using (XtStream stream = device.OpenStream(format, true, true,
                                                               buffer.current, RenderInterleavedRaw, XRun, "user-data")) {
                        stream.Start();
                        Console.WriteLine("Rendering interleaved, raw buffers...");
                        ReadLine();
                        stream.Stop();
                    }

                    using (XtStream stream = device.OpenStream(format, false, false,
                                                               buffer.current, RenderNonInterleaved, XRun, "user-data")) {
                        stream.Start();
                        Console.WriteLine("Rendering non-interleaved...");
                        ReadLine();
                        stream.Stop();
                    }

                    using (XtStream stream = device.OpenStream(format, false, true,
                                                               buffer.current, RenderNonInterleavedRaw, XRun, "user-data")) {
                        stream.Start();
                        Console.WriteLine("Rendering non-interleaved, raw buffers...");
                        ReadLine();
                        stream.Stop();
                    }

                    XtFormat sendTo0 = new XtFormat(new XtMix(44100, XtSample.Float32), 0, 0, 1, 1L << 0);
                    using (XtStream stream = device.OpenStream(sendTo0, true, false,
                                                               buffer.current, RenderInterleaved, XRun, "user-data")) {
                        stream.Start();
                        Console.WriteLine("Rendering channel mask, channel 0...");
                        ReadLine();
                        stream.Stop();
                    }

                    XtFormat sendTo1 = new XtFormat(new XtMix(44100, XtSample.Float32), 0, 0, 1, 1L << 1);
                    using (XtStream stream = device.OpenStream(sendTo1, true, false, buffer.current,
                                                               RenderInterleaved, XRun, "user-data")) {
                        stream.Start();
                        Console.WriteLine("Rendering channel mask, channel 1...");
                        ReadLine();
                        stream.Stop();
                    }
                }
            }
        }
Example #25
0
 internal void Init(XtFormat format, int maxFrames)
 {
     frameSize         = format.inputs * XtAudio.GetSampleAttributes(format.mix.sample).size;
     block             = new byte[maxFrames * frameSize];
     interleavedBuffer = Utility.CreateInterleavedBuffer(format.mix.sample, format.inputs, maxFrames);
 }
Example #26
0
        public static void Main(string[] args)
        {
            using (XtAudio audio = new XtAudio(null, IntPtr.Zero, null, null)) {
                XtService service = XtAudio.GetServiceBySetup(XtSetup.ConsumerAudio);
                XtFormat  format  = new XtFormat(new XtMix(44100, XtSample.Int24), 2, 0, 0, 0);
                using (XtDevice device = service.OpenDefaultDevice(false)) {
                    if (device == null)
                    {
                        Console.WriteLine("No default device found.");
                        return;
                    }

                    if (!device.SupportsFormat(format))
                    {
                        Console.WriteLine("Format not supported.");
                        return;
                    }

                    Context  context = new Context();
                    XtBuffer buffer  = device.GetBuffer(format);

                    using (FileStream recording = new FileStream(
                               "xt-audio-interleaved.raw", FileMode.Create, FileAccess.Write))
                        using (XtStream stream = device.OpenStream(format, true, false,
                                                                   buffer.current, CaptureInterleaved, XRun, context)) {
                            context.recording    = recording;
                            context.intermediate = new byte[GetBufferSize(stream, stream.GetFrames())];
                            stream.Start();
                            Console.WriteLine("Capturing interleaved...");
                            ReadLine();
                            stream.Stop();
                        }

                    using (FileStream recording = new FileStream(
                               "xt-audio-interleaved-raw.raw", FileMode.Create, FileAccess.Write))
                        using (XtStream stream = device.OpenStream(format, true, true,
                                                                   buffer.current, CaptureInterleavedRaw, XRun, context)) {
                            context.recording    = recording;
                            context.intermediate = new byte[GetBufferSize(stream, stream.GetFrames())];
                            stream.Start();
                            Console.WriteLine("Capturing interleaved, raw buffers...");
                            ReadLine();
                            stream.Stop();
                        }

                    using (FileStream recording = new FileStream(
                               "xt-audio-non-interleaved.raw", FileMode.Create, FileAccess.Write))
                        using (XtStream stream = device.OpenStream(format, false, false,
                                                                   buffer.current, CaptureNonInterleaved, XRun, context)) {
                            context.recording    = recording;
                            context.intermediate = new byte[GetBufferSize(stream, stream.GetFrames())];
                            stream.Start();
                            Console.WriteLine("Capturing non-interleaved...");
                            ReadLine();
                            stream.Stop();
                        }

                    using (FileStream recording = new FileStream(
                               "xt-audio-non-interleaved-raw.raw", FileMode.Create, FileAccess.Write))
                        using (XtStream stream = device.OpenStream(format, false, true,
                                                                   buffer.current, CaptureNonInterleavedRaw, XRun, context)) {
                            context.recording    = recording;
                            context.intermediate = new byte[GetBufferSize(stream, stream.GetFrames())];
                            stream.Start();
                            Console.WriteLine("Capturing non-interleaved, raw buffers...");
                            ReadLine();
                            stream.Stop();
                        }
                }
            }
        }
Example #27
0
 internal abstract void OnCallback(XtFormat format, bool interleaved,
                                   bool raw, object input, object output, int frames);
Example #28
0
        internal override unsafe void OnCallback(XtFormat format, bool interleaved,
                                                 bool raw, object input, object output, int frames)
        {
            for (int f = 0; f < frames; f++)
            {
                bool pulseReceived = false;
                bool sendPulse     = framesProcessed == pulseSend + format.mix.rate;
                if (sendPulse)
                {
                    pulseSend = framesProcessed;
                }
                byte  byteValue  = sendPulse ? byte.MaxValue : (byte)0;
                short shortValue = sendPulse ? short.MaxValue : (short)0;
                int   intValue   = sendPulse ? int.MaxValue : (int)0;
                float floatValue = sendPulse ? 1.0f : 0.0f;

                if (!raw)
                {
                    if (!interleaved)
                    {
                        switch (format.mix.sample)
                        {
                        case XtSample.UInt8:
                            ((byte[][])output)[0][f] = byteValue;
                            pulseReceived            = ((byte[][])input)[0][f] < 64 || ((byte[][])input)[0][f] > 192;
                            break;

                        case XtSample.Int16:
                            ((short[][])output)[0][f] = shortValue;
                            pulseReceived             = Math.Abs(((short[][])input)[0][f]) > short.MaxValue / 2;
                            break;

                        case XtSample.Int24:
                            ((byte[][])output)[0][f * 3] = byteValue;
                            pulseReceived = Math.Abs(((byte[][])input)[0][f * 3]) > byte.MaxValue / 2;
                            break;

                        case XtSample.Int32:
                            ((int[][])output)[0][f] = intValue;
                            pulseReceived           = Math.Abs(((int[][])input)[0][f]) > int.MaxValue / 2;
                            break;

                        case XtSample.Float32:
                            ((float[][])output)[0][f] = floatValue;
                            pulseReceived             = Math.Abs(((float[][])input)[0][f]) > 0.5;
                            break;
                        }
                    }
                    else
                    {
                        switch (format.mix.sample)
                        {
                        case XtSample.UInt8:
                            ((byte[])output)[f * format.outputs] = byteValue;
                            pulseReceived = ((byte[])input)[f * format.inputs] < 64 || ((byte[])input)[f * format.inputs] > 192;
                            break;

                        case XtSample.Int16:
                            ((short[])output)[f * format.outputs] = shortValue;
                            pulseReceived = Math.Abs(((short[])input)[f * format.inputs]) > short.MaxValue / 2;
                            break;

                        case XtSample.Int24:
                            ((byte[])output)[f * format.outputs * 3] = byteValue;
                            pulseReceived = Math.Abs(((byte[])input)[f * format.inputs * 3]) > byte.MaxValue / 2;
                            break;

                        case XtSample.Int32:
                            ((int[])output)[f * format.outputs] = intValue;
                            pulseReceived = Math.Abs(((int[])input)[f * format.inputs]) > int.MaxValue / 2;
                            break;

                        case XtSample.Float32:
                            ((float[])output)[f * format.outputs] = floatValue;
                            pulseReceived = Math.Abs(((float[])input)[f * format.inputs]) > 0.5;
                            break;
                        }
                    }
                }
                else
                {
                    if (!interleaved)
                    {
                        switch (format.mix.sample)
                        {
                        case XtSample.UInt8:
                            ((byte **)(IntPtr)output)[0][f] = byteValue;
                            pulseReceived = ((byte **)(IntPtr)input)[0][f] < 64 || ((byte **)(IntPtr)input)[0][f] > 192;
                            break;

                        case XtSample.Int16:
                            ((short **)(IntPtr)output)[0][f] = shortValue;
                            pulseReceived = Math.Abs(((short **)(IntPtr)input)[0][f]) > short.MaxValue / 2;
                            break;

                        case XtSample.Int24:
                            ((byte **)(IntPtr)output)[0][f * 3] = byteValue;
                            pulseReceived = Math.Abs(((byte **)(IntPtr)input)[0][f * 3]) > byte.MaxValue / 2;
                            break;

                        case XtSample.Int32:
                            ((int **)(IntPtr)output)[0][f] = intValue;
                            pulseReceived = Math.Abs(((int **)(IntPtr)input)[0][f]) > int.MaxValue / 2;
                            break;

                        case XtSample.Float32:
                            ((float **)(IntPtr)output)[0][f] = floatValue;
                            pulseReceived = Math.Abs(((float **)(IntPtr)input)[0][f]) > 0.5;
                            break;
                        }
                    }
                    else
                    {
                        switch (format.mix.sample)
                        {
                        case XtSample.UInt8:
                            ((byte *)(IntPtr)output)[f * format.outputs] = byteValue;
                            pulseReceived = ((byte *)(IntPtr)input)[f * format.inputs] < 64 || ((byte *)(IntPtr)input)[f * format.inputs] > 192;
                            break;

                        case XtSample.Int16:
                            ((short *)(IntPtr)output)[f * format.outputs] = shortValue;
                            pulseReceived = Math.Abs(((short *)(IntPtr)input)[f * format.inputs]) > short.MaxValue / 2;
                            break;

                        case XtSample.Int24:
                            ((byte *)(IntPtr)output)[f * format.outputs * 3] = byteValue;
                            pulseReceived = Math.Abs(((byte *)(IntPtr)input)[f * format.inputs * 3]) > byte.MaxValue / 2;
                            break;

                        case XtSample.Int32:
                            ((int *)(IntPtr)output)[f * format.outputs] = intValue;
                            pulseReceived = Math.Abs(((int *)(IntPtr)input)[f * format.inputs]) > int.MaxValue / 2;
                            break;

                        case XtSample.Float32:
                            ((float *)(IntPtr)output)[f * format.outputs] = floatValue;
                            pulseReceived = Math.Abs(((float *)(IntPtr)input)[f * format.inputs]) > 0.5;
                            break;
                        }
                    }
                }

                if (pulseReceived)
                {
                    onMessage(() => string.Format(
                                  "Pulse received after {0} frames ({1} ms).",
                                  framesProcessed - pulseSend,
                                  (framesProcessed - pulseSend) * 1000.0 / format.mix.rate));
                }

                framesProcessed++;
            }
        }
Example #29
0
        internal override unsafe void OnCallback(XtFormat format, bool interleaved,
                                                 bool raw, object input, object output, int frames)
        {
            Array.Clear(aggregateChannel, 0, frames);
            for (int f = 0; f < frames; f++)
            {
                for (int c = 0; c < format.inputs; c++)
                {
                    if (!raw && !interleaved)
                    {
                        switch (format.mix.sample)
                        {
                        case XtSample.UInt8:
                            aggregateChannel[f] += (((((byte[][])input)[c][f]) * 2.0) - 1.0) / byte.MaxValue;
                            break;

                        case XtSample.Int16:
                            aggregateChannel[f] += (((short[][])input)[c][f]) / (double)short.MaxValue;
                            break;

                        case XtSample.Int24:
                            int value = (int)(
                                ((byte[][])input)[c][f * 3] << 8 |
                                    ((byte[][])input)[c][f * 3 + 1] << 16 |
                                    ((byte[][])input)[c][f * 3 + 2] << 24);
                            aggregateChannel[f] += value / (double)int.MaxValue;
                            break;

                        case XtSample.Int32:
                            aggregateChannel[f] += (((int[][])input)[c][f]) / (double)int.MaxValue;
                            break;

                        case XtSample.Float32:
                            aggregateChannel[f] += ((float[][])input)[c][f];
                            break;
                        }
                    }
                    else if (!raw && interleaved)
                    {
                        switch (format.mix.sample)
                        {
                        case XtSample.UInt8:
                            aggregateChannel[f] += (((((byte[])input)[f * format.inputs + c]) * 2.0) - 1.0) / byte.MaxValue;
                            break;

                        case XtSample.Int16:
                            aggregateChannel[f] += (((short[])input)[f * format.inputs + c]) / (double)short.MaxValue;
                            break;

                        case XtSample.Int24:
                            int value = (int)(
                                ((byte[])input)[(f * format.inputs + c) * 3] << 8 |
                                    ((byte[])input)[(f * format.inputs + c) * 3 + 1] << 16 |
                                    ((byte[])input)[(f * format.inputs + c) * 3 + 2] << 24);
                            aggregateChannel[f] += value / (double)int.MaxValue;
                            break;

                        case XtSample.Int32:
                            aggregateChannel[f] += (((int[])input)[f * format.inputs + c]) / (double)int.MaxValue;
                            break;

                        case XtSample.Float32:
                            aggregateChannel[f] += ((float[])input)[f * format.inputs + c];
                            break;
                        }
                    }
                    else if (raw && !interleaved)
                    {
                        switch (format.mix.sample)
                        {
                        case XtSample.UInt8:
                            aggregateChannel[f] += (((((byte **)(IntPtr)input)[c][f]) * 2.0) - 1.0) / byte.MaxValue;
                            break;

                        case XtSample.Int16:
                            aggregateChannel[f] += (((short **)(IntPtr)input)[c][f]) / (double)short.MaxValue;
                            break;

                        case XtSample.Int24:
                            int value = (int)(
                                ((byte **)(IntPtr)input)[c][f * 3] << 8 |
                                    ((byte **)(IntPtr)input)[c][f * 3 + 1] << 16 |
                                    ((byte **)(IntPtr)input)[c][f * 3 + 2] << 24);
                            aggregateChannel[f] += value / (double)int.MaxValue;
                            break;

                        case XtSample.Int32:
                            aggregateChannel[f] += (((int **)(IntPtr)input)[c][f]) / (double)int.MaxValue;
                            break;

                        case XtSample.Float32:
                            aggregateChannel[f] += ((float **)(IntPtr)input)[c][f];
                            break;
                        }
                    }
                    else
                    {
                        switch (format.mix.sample)
                        {
                        case XtSample.UInt8:
                            aggregateChannel[f] += (((((byte *)(IntPtr)input)[f * format.inputs + c]) * 2.0) - 1.0) / byte.MaxValue;
                            break;

                        case XtSample.Int16:
                            aggregateChannel[f] += (((short *)(IntPtr)input)[f * format.inputs + c]) / (double)short.MaxValue;
                            break;

                        case XtSample.Int24:
                            int value = (int)(
                                ((byte *)(IntPtr)input)[(f * format.inputs + c) * 3] << 8 |
                                    ((byte *)(IntPtr)input)[(f * format.inputs + c) * 3 + 1] << 16 |
                                    ((byte *)(IntPtr)input)[(f * format.inputs + c) * 3 + 2] << 24);
                            aggregateChannel[f] += value / (double)int.MaxValue;
                            break;

                        case XtSample.Int32:
                            aggregateChannel[f] += (((int *)(IntPtr)input)[f * format.inputs + c]) / (double)int.MaxValue;
                            break;

                        case XtSample.Float32:
                            aggregateChannel[f] += ((float *)(IntPtr)input)[f * format.inputs + c];
                            break;
                        }
                    }
                }
                attenuate            = Math.Min(attenuate, 1.0 / Math.Abs(aggregateChannel[f]));
                aggregateChannel[f] *= attenuate;
                for (int c = 0; c < format.outputs; c++)
                {
                    if (!raw && !interleaved)
                    {
                        switch (format.mix.sample)
                        {
                        case XtSample.UInt8:
                            ((byte[][])output)[c][f] = (byte)(((aggregateChannel[f] + 1.0) * 0.5) * byte.MaxValue);
                            break;

                        case XtSample.Int16:
                            ((short[][])output)[c][f] = (short)(aggregateChannel[f] * (double)short.MaxValue);
                            break;

                        case XtSample.Int24:
                            int value = (int)(aggregateChannel[f] * (double)int.MaxValue);
                            ((byte[][])output)[c][f * 3]     = (byte)((value & 0x0000FF00) >> 8);
                            ((byte[][])output)[c][f * 3 + 1] = (byte)((value & 0x00FF0000) >> 16);
                            ((byte[][])output)[c][f * 3 + 2] = (byte)((value & 0xFF000000) >> 24);
                            break;

                        case XtSample.Int32:
                            ((int[][])output)[c][f] = (int)(aggregateChannel[f] * (double)int.MaxValue);
                            break;

                        case XtSample.Float32:
                            ((float[][])output)[c][f] = (float)aggregateChannel[f];
                            break;
                        }
                    }
                    else if (!raw && interleaved)
                    {
                        switch (format.mix.sample)
                        {
                        case XtSample.UInt8:
                            ((byte[])output)[f * format.outputs + c] = (byte)(((aggregateChannel[f] + 1.0) * 0.5) * byte.MaxValue);
                            break;

                        case XtSample.Int16:
                            ((short[])output)[f * format.outputs + c] = (short)(aggregateChannel[f] * (double)short.MaxValue);
                            break;

                        case XtSample.Int24:
                            int value = (int)(aggregateChannel[f] * (double)int.MaxValue);
                            ((byte[])output)[(f * format.outputs + c) * 3]     = (byte)((value & 0x0000FF00) >> 8);
                            ((byte[])output)[(f * format.outputs + c) * 3 + 1] = (byte)((value & 0x00FF0000) >> 16);
                            ((byte[])output)[(f * format.outputs + c) * 3 + 2] = (byte)((value & 0xFF000000) >> 24);
                            break;

                        case XtSample.Int32:
                            ((int[])output)[f * format.outputs + c] = (int)(aggregateChannel[f] * (double)int.MaxValue);
                            break;

                        case XtSample.Float32:
                            ((float[])output)[f * format.outputs + c] = (float)aggregateChannel[f];
                            break;
                        }
                    }
                    else if (raw && !interleaved)
                    {
                        switch (format.mix.sample)
                        {
                        case XtSample.UInt8:
                            ((byte **)(IntPtr)output)[c][f] = (byte)(((aggregateChannel[f] + 1.0) * 0.5) * byte.MaxValue);
                            break;

                        case XtSample.Int16:
                            ((short **)(IntPtr)output)[c][f] = (short)(aggregateChannel[f] * (double)short.MaxValue);
                            break;

                        case XtSample.Int24:
                            int value = (int)(aggregateChannel[f] * (double)int.MaxValue);
                            ((byte **)(IntPtr)output)[c][f * 3]     = (byte)((value & 0x0000FF00) >> 8);
                            ((byte **)(IntPtr)output)[c][f * 3 + 1] = (byte)((value & 0x00FF0000) >> 16);
                            ((byte **)(IntPtr)output)[c][f * 3 + 2] = (byte)((value & 0xFF000000) >> 24);
                            break;

                        case XtSample.Int32:
                            ((int **)(IntPtr)output)[c][f] = (int)(aggregateChannel[f] * (double)int.MaxValue);
                            break;

                        case XtSample.Float32:
                            ((float **)(IntPtr)output)[c][f] = (float)aggregateChannel[f];
                            break;
                        }
                    }
                    else
                    {
                        switch (format.mix.sample)
                        {
                        case XtSample.UInt8:
                            ((byte *)(IntPtr)output)[f * format.outputs + c] = (byte)(((aggregateChannel[f] + 1.0) * 0.5) * byte.MaxValue);
                            break;

                        case XtSample.Int16:
                            ((short *)(IntPtr)output)[f * format.outputs + c] = (short)(aggregateChannel[f] * (double)short.MaxValue);
                            break;

                        case XtSample.Int24:
                            int value = (int)(aggregateChannel[f] * (double)int.MaxValue);
                            ((byte *)(IntPtr)output)[(f * format.outputs + c) * 3]     = (byte)((value & 0x0000FF00) >> 8);
                            ((byte *)(IntPtr)output)[(f * format.outputs + c) * 3 + 1] = (byte)((value & 0x00FF0000) >> 16);
                            ((byte *)(IntPtr)output)[(f * format.outputs + c) * 3 + 2] = (byte)((value & 0xFF000000) >> 24);
                            break;

                        case XtSample.Int32:
                            ((int *)(IntPtr)output)[f * format.outputs + c] = (int)(aggregateChannel[f] * (double)int.MaxValue);
                            break;

                        case XtSample.Float32:
                            ((float *)(IntPtr)output)[f * format.outputs + c] = (float)aggregateChannel[f];
                            break;
                        }
                    }
                }
            }
        }
Example #30
0
        private void OnStart(object sender, EventArgs ea)
        {
            try {
                StreamType type                  = (StreamType)streamType.SelectedItem;
                bool       input                 = type == StreamType.Capture || type == StreamType.Duplex || type == StreamType.Latency;
                bool       output                = type == StreamType.Render || type == StreamType.Duplex || type == StreamType.Latency;
                XtDevice   inputDevice           = ((DeviceView)this.inputDevice.SelectedItem).device;
                XtDevice   outputDevice          = ((DeviceView)this.outputDevice.SelectedItem).device;
                XtDevice   secondaryInputDevice  = ((DeviceView)this.secondaryInput.SelectedItem).device;
                XtDevice   secondaryOutputDevice = ((DeviceView)this.secondaryOutput.SelectedItem).device;

                if (input && inputDevice == null)
                {
                    MessageBox.Show(this,
                                    "Select an input device.",
                                    "Invalid input device.");
                    return;
                }

                if (output && outputDevice == null)
                {
                    MessageBox.Show(this,
                                    "Select an output device.",
                                    "Invalid output device.");
                    return;
                }

                if (type == StreamType.Duplex && outputDevice != inputDevice)
                {
                    MessageBox.Show(this,
                                    "For duplex operation, input and output device must be the same.",
                                    "Invalid duplex device.");
                    return;
                }

                if (type == StreamType.Aggregate &&
                    (inputDevice == null && secondaryInputDevice == null ||
                     outputDevice == null && secondaryOutputDevice == null))
                {
                    MessageBox.Show(this,
                                    "For aggregate operation, select at least 1 input and 1 output device.",
                                    "Invalid aggregate device.");
                    return;
                }

                XRunCallback xRunCallback = new XRunCallback(AddMessage);

                XtFormat inputFormat = GetFormat(false);
                inputFormat.inputs = (int)channelCount.SelectedItem;
                if (input && inputChannels.SelectedItems.Count > 0 && inputChannels.SelectedItems.Count != inputFormat.inputs)
                {
                    MessageBox.Show(this,
                                    "Selected either 0 input channels or a number equal to the selected format's channels.",
                                    "Invalid input channel mask.");
                    return;
                }
                for (int c = 0; c < inputChannels.SelectedItems.Count; c++)
                {
                    inputFormat.inMask |= (1UL << ((ChannelView)inputChannels.SelectedItems[c]).index);
                }

                XtFormat outputFormat = GetFormat(true);
                if (output && outputChannels.SelectedItems.Count > 0 && outputChannels.SelectedItems.Count != outputFormat.outputs)
                {
                    MessageBox.Show(this,
                                    "Selected either 0 output channels or a number equal to the selected format's channels.",
                                    "Invalid output channel mask.");
                    return;
                }
                for (int c = 0; c < outputChannels.SelectedItems.Count; c++)
                {
                    outputFormat.outMask |= (1UL << ((ChannelView)outputChannels.SelectedItems[c]).index);
                }

                if (type == StreamType.Capture)
                {
                    captureFile = new FileStream("xt-audio.raw", FileMode.Create, FileAccess.Write);
                    CaptureCallback callback = new CaptureCallback(OnStreamError, AddMessage, captureFile);
                    inputStream = inputDevice.OpenStream(inputFormat, streamInterleaved.Checked, streamRaw.Checked,
                                                         bufferSize.Value, callback.OnCallback, xRunCallback.OnCallback, "capture-user-data");
                    callback.Init(inputStream.GetFormat(), inputStream.GetFrames());
                    inputStream.Start();
                }
                else if (type == StreamType.Render)
                {
                    RenderCallback callback = new RenderCallback(OnStreamError, AddMessage);
                    outputStream = outputDevice.OpenStream(outputFormat, streamInterleaved.Checked, streamRaw.Checked,
                                                           bufferSize.Value, callback.OnCallback, xRunCallback.OnCallback, "render-user-data");
                    outputStream.Start();
                }
                else if (type == StreamType.Duplex)
                {
                    XtFormat duplexFormat = inputFormat;
                    duplexFormat.outputs = outputFormat.outputs;
                    duplexFormat.outMask = outputFormat.outMask;
                    FullDuplexCallback callback = new FullDuplexCallback(OnStreamError, AddMessage);
                    outputStream = outputDevice.OpenStream(duplexFormat, streamInterleaved.Checked, streamRaw.Checked,
                                                           bufferSize.Value, callback.OnCallback, xRunCallback.OnCallback, "duplex-user-data");
                    outputStream.Start();
                }
                else if (type == StreamType.Aggregate)
                {
                    List <XtDevice>   devices     = new List <XtDevice>();
                    List <double>     bufferSizes = new List <double>();
                    List <XtChannels> channels    = new List <XtChannels>();
                    if (inputDevice != null)
                    {
                        devices.Add(inputDevice);
                        bufferSizes.Add(bufferSize.Value);
                        channels.Add(new XtChannels(inputFormat.inputs, inputFormat.inMask, 0, 0));
                    }
                    if (outputDevice != null)
                    {
                        devices.Add(outputDevice);
                        bufferSizes.Add(bufferSize.Value);
                        channels.Add(new XtChannels(0, 0, outputFormat.outputs, outputFormat.outMask));
                    }
                    if (secondaryInputDevice != null)
                    {
                        devices.Add(secondaryInputDevice);
                        bufferSizes.Add(bufferSize.Value);
                        channels.Add(new XtChannels(inputFormat.inputs, inputFormat.inMask, 0, 0));
                    }
                    if (secondaryOutputDevice != null)
                    {
                        devices.Add(secondaryOutputDevice);
                        bufferSizes.Add(bufferSize.Value);
                        channels.Add(new XtChannels(0, 0, outputFormat.outputs, outputFormat.outMask));
                    }

                    XtDevice[]   devicesArray     = devices.ToArray();
                    double[]     bufferSizesArray = bufferSizes.ToArray();
                    XtChannels[] channelsArray    = channels.ToArray();
                    XtDevice     master           = outputMaster.Checked ?
                                                    (outputDevice != null ? outputDevice :
                                                     secondaryOutputDevice != null ? secondaryOutputDevice :
                                                     inputDevice != null ? inputDevice : secondaryInputDevice) :
                                                    (inputDevice != null ? inputDevice :
                                                     secondaryInputDevice != null ? secondaryInputDevice :
                                                     outputDevice != null ? outputDevice : secondaryOutputDevice);

                    AggregateCallback streamCallback = new AggregateCallback(OnStreamError, AddMessage);
                    outputStream = ((XtService)service.SelectedItem).AggregateStream(devicesArray, channelsArray,
                                                                                     bufferSizesArray, devicesArray.Length, outputFormat.mix, streamInterleaved.Checked, streamRaw.Checked,
                                                                                     master, streamCallback.OnCallback, xRunCallback.OnCallback, "aggregate-user-data");
                    streamCallback.Init(outputStream.GetFrames());
                    outputStream.Start();
                }
                else if (inputDevice == outputDevice)
                {
                    XtFormat duplexFormat = inputFormat;
                    duplexFormat.outputs = outputFormat.outputs;
                    duplexFormat.outMask = outputFormat.outMask;
                    LatencyCallback callback = new LatencyCallback(OnStreamError, AddMessage);
                    outputStream = outputDevice.OpenStream(duplexFormat, streamInterleaved.Checked, streamRaw.Checked,
                                                           bufferSize.Value, callback.OnCallback, xRunCallback.OnCallback, "latency-user-data");
                    outputStream.Start();
                }
                else
                {
                    XtDevice[]   devices     = new XtDevice[] { inputDevice, outputDevice };
                    double[]     bufferSizes = new double[] { bufferSize.Value, bufferSize.Value };
                    XtChannels[] channels    = new XtChannels[] {
                        new XtChannels(inputFormat.inputs, inputFormat.inMask, 0, 0),
                        new XtChannels(0, 0, outputFormat.outputs, outputFormat.outMask)
                    };
                    XtDevice        master   = outputMaster.Checked ? outputDevice : inputDevice;
                    LatencyCallback callback = new LatencyCallback(OnStreamError, AddMessage);
                    outputStream = ((XtService)service.SelectedItem).AggregateStream(devices, channels,
                                                                                     bufferSizes, devices.Length, outputFormat.mix, streamInterleaved.Checked, streamRaw.Checked,
                                                                                     master, callback.OnCallback, xRunCallback.OnCallback, "latency-user-data");
                    outputStream.Start();
                }

                stop.Enabled              = true;
                panel.Enabled             = false;
                start.Enabled             = false;
                streamRaw.Enabled         = false;
                bufferSize.Enabled        = false;
                streamType.Enabled        = false;
                outputMaster.Enabled      = false;
                secondaryInput.Enabled    = false;
                secondaryOutput.Enabled   = false;
                streamInterleaved.Enabled = false;
            } catch (XtException e) {
                Stop();
                MessageBox.Show(this, e.ToString(), "Failed to start stream.", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }