public override void Start() { _outputStream.Start(); _outputStream.Pause(false); _driver.FlushContextEvents(); }
static void WriteCallback(SoundIOOutStream stream, int frameCountMin, int frameCountMax) { double floatSampleRate = stream.SampleRate; double secondsPerFrame = 1.0 / floatSampleRate; SoundIOChannelAreas areas; SoundIoError err; int framesLeft = frameCountMax; while (true) { int frameCount = framesLeft; err = stream.BeginWrite(out areas, ref frameCount); if (err != SoundIoError.None) { throw new SoundIOException(string.Format("Unrecoverable stream error: {0}.", err.GetErrorMessage())); } if (areas == null || frameCount == 0) { break; } SoundIOChannelLayout layout = stream.Layout; double pitch = 440.0; double radiansPerSecond = pitch * 2.0 * Math.PI; for (int frame = 0; frame < frameCount; frame++) { double sample = Math.Sin((secondsOffset + frame * secondsPerFrame) * radiansPerSecond); for (int channel = 0; channel < layout.ChannelCount; channel += 1) { writeSample(areas[channel].Pointer, sample); areas[channel].AdvancePointer(); } } secondsOffset = (secondsOffset + secondsPerFrame * frameCount) % 1.0; err = stream.EndWrite(); if (err != SoundIoError.None) { Console.WriteLine("EndWrite failed with error: {0}.", err); if (err == SoundIoError.Underflow) { return; } throw new SoundIOException(string.Format("Unrecoverable stream error: {0}.", err.GetErrorMessage())); } framesLeft -= frameCount; if (framesLeft <= 0) { break; } } stream.Pause(wantPause); }
static void write_callback(SoundIOOutStream outstream, int frame_count_min, int frame_count_max) { double float_sample_rate = outstream.SampleRate; double seconds_per_frame = 1.0 / float_sample_rate; int frames_left = frame_count_max; int frame_count = 0; for (; ;) { frame_count = frames_left; var results = outstream.BeginWrite(ref frame_count); if (frame_count == 0) { break; } SoundIOChannelLayout layout = outstream.Layout; double pitch = 440.0; double radians_per_second = pitch * 2.0 * Math.PI; for (int frame = 0; frame < frame_count; frame += 1) { double sample = Math.Sin((seconds_offset + frame * seconds_per_frame) * radians_per_second); for (int channel = 0; channel < layout.ChannelCount; channel += 1) { var area = results.GetArea(channel); write_sample(area.Pointer, sample); area.Pointer += area.Step; } } seconds_offset = Math.IEEERemainder(seconds_offset + seconds_per_frame * frame_count, 1.0); outstream.EndWrite(); frames_left -= frame_count; if (frames_left <= 0) { break; } } outstream.Pause(want_pause); }
public static int Main(string[] args) { string exe = "SoundIOSine"; SoundIoBackend backend = SoundIoBackend.None; string deviceId = null; bool raw = false; string streamName = null; double latency = 0.0; int sampleRate = 0; SoundIoError err; SoundIODevice device = null; for (int i = 0; i < args.Length; i++) { string arg = args[i]; if (arg.StartsWith("--")) { if (arg.CompareTo("--raw") == 0) { raw = true; } else { i++; if (i >= args.Length) { return(Usage(exe)); } else if (arg.CompareTo("--backend") == 0) { backend = (SoundIoBackend)Enum.Parse(typeof(SoundIoBackend), args[i]); } else if (arg.CompareTo("--device") == 0) { deviceId = args[i]; } else if (arg.CompareTo("--name") == 0) { streamName = args[i]; } else if (arg.CompareTo("--latency") == 0) { latency = double.Parse(args[i]); } else if (arg.CompareTo("--sample-rate") == 0) { sampleRate = int.Parse(args[i]); } else { return(Usage(exe)); } } } else { return(Usage(exe)); } } SoundIO soundIo = new SoundIO(); err = (backend == SoundIoBackend.None) ? soundIo.Connect() : soundIo.ConnectBackend(backend); if (err != SoundIoError.None) { Console.Error.WriteLine("Unable to connect to backend: {0}.", err.GetErrorMessage()); return(1); } Console.WriteLine("Backend: {0}.", soundIo.CurrentBackend); soundIo.FlushEvents(); if (deviceId != null) { foreach (var dev in soundIo) { if (dev.Aim == SoundIoDeviceAim.Output && dev.Id.Equals(deviceId) && dev.IsRaw == raw) { device = dev; break; } } if (device == null) { Console.Error.WriteLine("Output device not found."); return(1); } device.AddRef(); // Enumerator cleans up itself on dispose } else { device = soundIo.GetDefaultOutputDevice(); } Console.WriteLine("Output device: {0}.", device.Name); if (device.ProbeError != SoundIoError.None) { Console.Error.WriteLine("Cannot probe device: {0}.", device.ProbeError.GetErrorMessage()); return(1); } SoundIOOutStream outstream = new SoundIOOutStream(device); outstream.OnWriteCallback = WriteCallback; outstream.OnUnderflowCallback = UnderflowCallback; if (streamName != null) { outstream.Name = streamName; } outstream.SoftwareLatency = latency; if (sampleRate != 0) { outstream.SampleRate = sampleRate; } if (device.SupportsFormat(SoundIoFormats.Float32NE)) { outstream.Format = SoundIoFormats.Float32NE; writeSample = WriteSampleFloat32NE; } else if (device.SupportsFormat(SoundIoFormats.Float64NE)) { outstream.Format = SoundIoFormats.Float64NE; writeSample = WriteSampleFloat64NE; } else if (device.SupportsFormat(SoundIoFormats.S32NE)) { outstream.Format = SoundIoFormats.S32NE; writeSample = WriteSampleS32NE; } else if (device.SupportsFormat(SoundIoFormats.S16NE)) { outstream.Format = SoundIoFormats.S16NE; writeSample = WriteSampleS16NE; } else { Console.Error.WriteLine("No suitable format available."); return(1); } err = outstream.Open(); if (err != SoundIoError.None) { Console.Error.WriteLine("Unable to open device: {0}.", err.GetErrorMessage()); return(1); } Console.WriteLine("Software latency: {0:N6}.", outstream.SoftwareLatency); Console.WriteLine( "\t'p' - pause\n" + "\t'u' - unpause\n" + "\t'P' - pause from within callback\n" + "\t'c' - clear buffer\n" + "\t'q' - quit\n"); if (outstream.LayoutError != SoundIoError.None) { Console.Error.WriteLine("Unable to set channel layout: {0}.", outstream.LayoutError.GetErrorMessage()); } err = outstream.Start(); if (err != SoundIoError.None) { Console.Error.WriteLine("Unable to start device {0}.", err.GetErrorMessage()); return(1); } while (true) { soundIo.FlushEvents(); int c = Console.Read(); if (c == 'p') { err = outstream.Pause(true); Console.Error.WriteLine("Pausing result: {0}.", err.GetErrorMessage()); } else if (c == 'P') { wantPause = true; } else if (c == 'u') { wantPause = false; err = outstream.Pause(false); Console.Error.WriteLine("Unpausing result: {0}.", err.GetErrorMessage()); } else if (c == 'c') { err = outstream.ClearBuffer(); Console.Error.WriteLine("Clear buffer result: {0}.", err.GetErrorMessage()); } else if (c == 'q') { break; } else if (c == '\r' || c == '\n') { // ignore } else { Console.Error.WriteLine("Unrecognized command: {0}.", (char)c); } } outstream.Dispose(); device.Release(); soundIo.Dispose(); return(0); }
public static void WriteCallback(SoundIOOutStream stream, int frameCountMin, int frameCountMax) { SoundIoError err; DateTime callbackTime = DateTime.Now; // loop to utilize as much as the frameCountMax as possible while (frameCountMax > 0) { int frameCount = frameCountMax; if ((err = stream.BeginWrite(out SoundIOChannelAreas areas, ref frameCount)) != SoundIoError.None) { Console.WriteLine("unrecoverable stream error: {0}", err.GetErrorMessage()); _fileDone = true; } if (frameCount == 0) { break; } var bufferCount = frameCount * stream.Layout.ChannelCount; // if buffer is done add silence based on latency to allow stream to complete through // audio path before stream is Disposed() if (_waveFile.Position >= _waveFile.Length) { if (_startSilence) { // windows latency is a little higher (using DateTime to determine the callback time delay) // and needs to be accoutned for... _latencySeconds -= (DateTime.Now - callbackTime).TotalMilliseconds / 1000.0; _silentSamplesRemaining = (int)((stream.SampleRate * stream.Layout.ChannelCount) * _latencySeconds); _silentSamplesRemaining -= _silentSamplesAlreadySent; _startSilence = false; } int silentBufferSize; if (_silentSamplesRemaining > bufferCount) { silentBufferSize = bufferCount; _silentSamplesRemaining -= bufferCount; } else { silentBufferSize = _silentSamplesRemaining; _silentSamplesRemaining = 0; } if (silentBufferSize > 0) { // create a new buffer initialized to 0 and copy to native buffer var silenceBuffer = new float[silentBufferSize]; stream.CopyTo(silenceBuffer, 0, areas, silentBufferSize); } if (_silentSamplesRemaining == 0) { _fileDone = true; stream.EndWrite(); stream.Pause(true); return; } // if the remaining audioBuffer will only partially fill the frameCount // copy the remaining amount and set the startSilence flag to allow // stream to play to the end. } else if (_waveFile.Position + (frameCount * _waveFile.WaveFormat.Channels) >= _waveFile.Length) { float[] audioBuffer = new float[bufferCount]; var actualSamplesRead = _sampleProvider.Read(audioBuffer, 0, bufferCount); stream.CopyTo(audioBuffer, 0, areas, bufferCount); _silentSamplesAlreadySent = bufferCount - actualSamplesRead; _latencySeconds = 0.0; _startSilence = true; } else { // copy audioBuffer data to native buffer and advance the bufferPos float[] audioBuffer = new float[bufferCount]; var actualSamplesRead = _sampleProvider.Read(audioBuffer, 0, bufferCount); stream.CopyTo(audioBuffer, 0, areas, actualSamplesRead); if (_waveFile.Position >= _waveFile.Length) { _latencySeconds = 0.0; _startSilence = true; } } if ((err = stream.EndWrite()) != SoundIoError.None) { if (err == SoundIoError.Underflow) { return; } Console.WriteLine("Unrecoverable stream error: {0}", err.GetErrorMessage()); _fileDone = true; } if (_startSilence) { // get actual latency in order to compute number of silent frames stream.GetLatency(out _latencySeconds); callbackTime = DateTime.Now; } // loop until frameCountMax is used up frameCountMax -= frameCount; } return; }