static int GetBufferSize(XtStream stream, int frames) { XtFormat format = stream.GetFormat(); int sampleSize = XtAudio.GetSampleAttributes(format.mix.sample).size; return(frames * format.inputs * sampleSize); }
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); }
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)); }
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(); } } } } }
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); }
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); }
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(); } } } }
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); }
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); } }
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); }
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); }
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); }
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; } } }
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; } } }
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); } } }
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); } } } }
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); } } } }
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); }
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); }
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); }
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)); } } } }
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; } }
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; } } } } } }
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(); } } } }
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); }
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(); } } } }
internal abstract void OnCallback(XtFormat format, bool interleaved, bool raw, object input, object output, int frames);
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++; } }
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; } } } } }
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); } }