-
Notifications
You must be signed in to change notification settings - Fork 17
NAudio decoder
wo80 edited this page May 3, 2021
·
4 revisions
The decoder was tested on the .NET 5.0 platform using the NAudio.Core
and NAudio.WinMM
NuGet packages.
namespace AcoustID.Examples
{
using NAudio.Wave;
using System;
using System.Buffers;
using System.IO;
/// <summary>
/// Decode using the NAudio library.
/// </summary>
public class NAudioDecoder : AudioDecoder
{
string file;
public NAudioDecoder(string file)
{
this.file = file;
Initialize();
}
public override bool Decode(IAudioConsumer consumer, int maxLength)
{
using (var reader = OpenWaveStream(file))
{
if (reader.WaveFormat.BitsPerSample != 16)
{
return false;
}
int remaining, length, size;
var buffer = ArrayPool<byte>.Shared.Rent(2 * BUFFER_SIZE);
var data = ArrayPool<short>.Shared.Rent(BUFFER_SIZE);
// Samples to read to get maxLength seconds of audio
remaining = maxLength * this.Format.Channels * this.sampleRate;
// Bytes to read
length = 2 * Math.Min(remaining, BUFFER_SIZE);
while ((size = reader.Read(buffer, 0, length)) > 0)
{
Buffer.BlockCopy(buffer, 0, data, 0, size);
consumer.Consume(data, size / 2);
remaining -= size / 2;
if (remaining <= 0)
{
break;
}
length = 2 * Math.Min(remaining, BUFFER_SIZE);
}
ArrayPool<byte>.Shared.Return(buffer);
ArrayPool<short>.Shared.Return(data);
return true;
}
}
private bool Initialize()
{
using (var reader = OpenWaveStream(file))
{
var format = reader.WaveFormat;
this.sampleRate = format.SampleRate;
this.channels = format.Channels;
this.Format = new AudioProperties(format.SampleRate, format.BitsPerSample,
format.Channels, (int)reader.TotalTime.TotalSeconds);
return format.BitsPerSample != 16;
}
}
private WaveStream OpenWaveStream(string file)
{
var extension = Path.GetExtension(file).ToLowerInvariant();
if (extension.Equals(".mp3"))
{
return new Mp3FileReader(file);
}
// Try open as WAV (will throw an exception, if not supported).
return new WaveFileReader(file);
}
}
Additional code:
/// <summary>
/// Interface for audio decoders.
/// </summary>
public interface IAudioDecoder : IDecoder, IDisposable
{
AudioProperties Format { get; }
}
/// <summary>
/// Abstract base class for audio decoders
/// </summary>
public abstract class AudioDecoder : IAudioDecoder
{
protected static readonly int BUFFER_SIZE = 2 * 192000;
protected int sampleRate;
protected int channels;
public int SampleRate
{
get { return sampleRate; }
}
public int Channels
{
get { return channels; }
}
~AudioDecoder() => Dispose(false);
public AudioProperties Format { get; protected set; }
public abstract bool Decode(IAudioConsumer consumer, int maxLength);
public virtual void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
}
}
}