Skip to content

Instantly share code, notes, and snippets.

@chutchinson
Last active February 21, 2020 23:43
Show Gist options
  • Save chutchinson/cc2f5596ac68747b6fd6f7286dfe5aae to your computer and use it in GitHub Desktop.
Save chutchinson/cc2f5596ac68747b6fd6f7286dfe5aae to your computer and use it in GitHub Desktop.
NAudio Opus
using Concentus.Structs;
using NAudio.Wave;
using System;
using System.Threading.Tasks;
namespace AudioGen
{
public class BufferedSampleProvider : ISampleProvider
{
private float[] Buffer { get; }
private int Position { get; set; }
public WaveFormat WaveFormat =>
WaveFormat.CreateIeeeFloatWaveFormat(48000, 1);
public BufferedSampleProvider(float[] buffer)
{
Buffer = buffer;
}
public int Read(float[] buffer, int offset, int count)
{
if (Position >= Buffer.Length)
{
return 0;
}
var slice = Buffer.AsSpan().Slice(Position, count);
slice.CopyTo(buffer);
Position += count;
return slice.Length;
}
}
class Program
{
static Task PlayAudioAsync(float[] buffer)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
var provider = new BufferedSampleProvider(buffer);
var wasapi = new WasapiOut();
wasapi.PlaybackStopped += (sender, e) =>
{
if (e.Exception != null)
{
taskCompletionSource.SetException(e.Exception);
return;
}
taskCompletionSource.SetResult(true);
};
wasapi.Init(provider);
wasapi.Play();
return taskCompletionSource.Task;
}
static async Task Main(string[] args)
{
var channels = 1;
var sampleRate = 48000;
var frequency = 440.0;
var frameSize = 960;
var buffer = new float[sampleRate];
var decodedBuffer = new float[sampleRate];
for (var i = 0; i < buffer.Length; i++)
{
var time = i / (float)buffer.Length;
var sample = Math.Sin(2.0 * Math.PI * frequency * time);
buffer[i] = (float)sample;
}
Console.WriteLine("Reference Tone");
await PlayAudioAsync(buffer);
Console.WriteLine("Opus Tone");
Console.ReadKey();
var offset = 0;
var packet = new byte[frameSize * sizeof(float)];
var encoder = OpusEncoder.Create(sampleRate, channels,
Concentus.Enums.OpusApplication.OPUS_APPLICATION_AUDIO);
encoder.Bitrate = 6144; // min
encoder.ForceMode = Concentus.Enums.OpusMode.MODE_AUTO;
encoder.SignalType = Concentus.Enums.OpusSignal.OPUS_SIGNAL_VOICE;
encoder.Complexity = 0;
var decoder = new OpusDecoder(sampleRate, channels);
var decodeOffset = 0;
while (offset < buffer.Length)
{
var packetSize = encoder.Encode(buffer, offset, frameSize, packet, 0, packet.Length);
var samplesDecoded = decoder.Decode(packet, 0, packetSize, decodedBuffer, decodeOffset, frameSize);
offset += frameSize;
decodeOffset += samplesDecoded;
}
await PlayAudioAsync(decodedBuffer);
Console.WriteLine("done");
Console.ReadKey();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment