diff --git a/Fingerprinter/Audio/AudioDecoder.cs b/Fingerprinter/Audio/AudioDecoder.cs index 7612b43..842e3fb 100644 --- a/Fingerprinter/Audio/AudioDecoder.cs +++ b/Fingerprinter/Audio/AudioDecoder.cs @@ -18,38 +18,6 @@ public abstract class AudioDecoder : IAudioDecoder protected int sampleRate; protected int channels; - protected int sourceSampleRate; - protected int sourceBitDepth; - protected int sourceChannels; - protected int duration; - - protected bool ready; - - public int SourceSampleRate - { - get { return sourceSampleRate; } - } - - public int SourceBitDepth - { - get { return sourceBitDepth; } - } - - public int SourceChannels - { - get { return sourceChannels; } - } - - public int Duration - { - get { return duration; } - } - - public bool Ready - { - get { return ready; } - } - public int SampleRate { get { return sampleRate; } @@ -60,7 +28,7 @@ public int Channels get { return channels; } } - public abstract void Load(string file); + public AudioProperties Format { get; protected set; } public abstract bool Decode(IAudioConsumer consumer, int maxLength); diff --git a/Fingerprinter/Audio/AudioProperties.cs b/Fingerprinter/Audio/AudioProperties.cs new file mode 100644 index 0000000..30b2c73 --- /dev/null +++ b/Fingerprinter/Audio/AudioProperties.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fingerprinter.Audio +{ + public class AudioProperties + { + /// + /// Gets the sample rate of the audio source. + /// + public int SampleRate { get; private set; } + + /// + /// Gets the sample rate of the audio source (must be 16 bits per sample). + /// + public int BitDepth { get; private set; } + + /// + /// Gets the number of channels. + /// + public int Channels { get; private set; } + + /// + /// Gets the duration of the audio source (in seconds). + /// + public int Duration { get; private set; } + + public AudioProperties() + : this(0, 0, 0, 0) + { + } + + public AudioProperties(int sampleRate, int bitDepth, int channels, int duration) + { + this.SampleRate = sampleRate; + this.BitDepth = bitDepth; + this.Channels = channels; + this.Duration = duration; + } + } +} diff --git a/Fingerprinter/Audio/IAudioDecoder.cs b/Fingerprinter/Audio/IAudioDecoder.cs index 8c023a9..f19e1eb 100644 --- a/Fingerprinter/Audio/IAudioDecoder.cs +++ b/Fingerprinter/Audio/IAudioDecoder.cs @@ -14,16 +14,6 @@ namespace Fingerprinter.Audio /// public interface IAudioDecoder : IDecoder, IDisposable { - int SourceSampleRate { get; } - int SourceBitDepth { get; } - int SourceChannels { get; } - - int Duration { get; } - bool Ready { get; } - - /// - /// Load an audio file. - /// - void Load(string file); + AudioProperties Format { get; } } } diff --git a/Fingerprinter/Audio/NAudioDecoder.cs b/Fingerprinter/Audio/NAudioDecoder.cs index 6b8582f..6fe0c87 100644 --- a/Fingerprinter/Audio/NAudioDecoder.cs +++ b/Fingerprinter/Audio/NAudioDecoder.cs @@ -12,53 +12,32 @@ namespace Fingerprinter.Audio using NAudio.Wave; /// - /// Decode using the NAudio library. Great audio library, but the MP3 decoder is kinda slow. + /// Decode using the NAudio library.. /// public class NAudioDecoder : AudioDecoder { WaveStream reader; - string extension; - - public override void Load(string file) - { - // Dispose on every new load - Dispose(false); - - ready = false; - - extension = Path.GetExtension(file).ToLowerInvariant(); + string file; - if (extension.Equals(".wav")) - { - reader = new WaveFileReader(file); - } - else - { - reader = new Mp3FileReader(file); - } - - var format = reader.WaveFormat; - - this.sampleRate = format.SampleRate; - this.channels = format.Channels; + public NAudioDecoder(string file) + { + this.file = file; - this.sourceSampleRate = format.SampleRate; - this.sourceBitDepth = format.BitsPerSample; - this.sourceChannels = format.Channels; - this.duration = (int)reader.TotalTime.TotalSeconds; - this.ready = (format.BitsPerSample == 16); + // Open the WaveStream and keep it open until Dispose() is called. This might lock + // the file. A better approach would be to open the stream only when needed. + Initialize(); } public override bool Decode(IAudioConsumer consumer, int maxLength) { - if (!ready) return false; + if (reader == null) return false; int remaining, length, size; byte[] buffer = new byte[2 * BUFFER_SIZE]; short[] data = new short[BUFFER_SIZE]; // Samples to read to get maxLength seconds of audio - remaining = maxLength * this.sourceChannels * this.sampleRate; + remaining = maxLength * this.Format.Channels * this.sampleRate; // Bytes to read length = 2 * Math.Min(remaining, BUFFER_SIZE); @@ -81,6 +60,33 @@ public override bool Decode(IAudioConsumer consumer, int maxLength) return true; } + private void Initialize() + { + var extension = Path.GetExtension(file).ToLowerInvariant(); + + if (extension.Equals(".wav")) + { + reader = new WaveFileReader(file); + } + else + { + reader = new Mp3FileReader(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); + + if (format.BitsPerSample != 16) + { + Dispose(true); + } + } + #region IDisposable implementation private bool hasDisposed = false; @@ -99,6 +105,7 @@ public void Dispose(bool disposing) { reader.Close(); reader.Dispose(); + reader = null; } } diff --git a/Fingerprinter/Fingerprinter.csproj b/Fingerprinter/Fingerprinter.csproj index a5eac2f..8a0f0e2 100644 --- a/Fingerprinter/Fingerprinter.csproj +++ b/Fingerprinter/Fingerprinter.csproj @@ -36,9 +36,9 @@ 4 - - False - ..\packages\NAudio.1.7.2\lib\net35\NAudio.dll + + ..\packages\NAudio.1.7.3\lib\net35\NAudio.dll + True @@ -46,6 +46,7 @@ + diff --git a/Fingerprinter/MainForm.cs b/Fingerprinter/MainForm.cs index cf53ac7..aa778aa 100644 --- a/Fingerprinter/MainForm.cs +++ b/Fingerprinter/MainForm.cs @@ -1,14 +1,14 @@ -using System; +using AcoustID; +using AcoustID.Web; +using Fingerprinter.Audio; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; +using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; -using AcoustID; -using AcoustID.Web; -using Fingerprinter.Audio; -using System.Threading; namespace Fingerprinter { @@ -24,9 +24,6 @@ public MainForm() private void MainForm_Load(object sender, EventArgs e) { Fpcalc.Path = @"D:\Projects\AcoustId\extern\fpcalc.exe"; - - decoder = new NAudioDecoder(); - //decoder = new BassDecoder(); } private void btnOpen_Click(object sender, EventArgs e) @@ -36,26 +33,32 @@ private void btnOpen_Click(object sender, EventArgs e) if (dlg.ShowDialog() == DialogResult.OK) { - lbFile.Text = dlg.FileName; + if (decoder != null) + { + decoder.Dispose(); + } - ResetAll(); + try + { + decoder = new NAudioDecoder(dlg.FileName); + //decoder = new BassDecoder(); - decoder.Load(dlg.FileName); + lbFile.Text = dlg.FileName; - int bits = decoder.SourceBitDepth; - int channels = decoder.SourceChannels; + ResetAll(); + + int bits = decoder.Format.BitDepth; + int channels = decoder.Format.Channels; - if (decoder.Ready) - { lbAudio.Text = String.Format("{0}Hz, {1}bit{2}, {3}", - decoder.SourceSampleRate, bits, bits != 16 ? " (not supported)" : "", + decoder.Format.SampleRate, bits, bits != 16 ? " (not supported)" : "", channels == 2 ? "stereo" : (channels == 1 ? "mono" : "multi-channel")); - lbDuration.Text = decoder.Duration.ToString(); + lbDuration.Text = decoder.Format.Duration.ToString(); btnFingerPrint.Enabled = true; } - else + catch { lbAudio.Text = "Failed to load audio"; lbDuration.Text = String.Empty; @@ -244,7 +247,7 @@ private void ProcessFile(string file) { if (File.Exists(file)) { - if (decoder.Ready) + if (decoder != null) { //btnOpen.Enabled = false; btnFingerPrint.Enabled = false; diff --git a/Fingerprinter/packages.config b/Fingerprinter/packages.config index 1e2c8b7..b19b834 100644 --- a/Fingerprinter/packages.config +++ b/Fingerprinter/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file