Readd support for folder cover art; rudimentary EQ support

This commit is contained in:
Royce551 2022-12-30 23:46:33 -06:00
parent 1c7219669d
commit 90950df4ed
5 changed files with 144 additions and 6 deletions

View file

@ -1,6 +1,7 @@
using ATL;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
@ -21,7 +22,32 @@ namespace FRESHMusicPlayer.Backends
public string Album => ATLTrack.Album;
/// <inheritdoc/>
public byte[] CoverArt => ATLTrack.EmbeddedPictures.Count != 0 ? ATLTrack.EmbeddedPictures[0].PictureData : null;
public byte[] CoverArt
{
get
{
if (ATLTrack.EmbeddedPictures.Count != 0) return ATLTrack.EmbeddedPictures[0].PictureData;
if (!File.Exists(path)) return null;
else
{
foreach (var file in Directory.EnumerateFiles(Path.GetDirectoryName(path)))
{
if (Path.GetFileNameWithoutExtension(file).ToUpper() == "COVER" ||
Path.GetFileNameWithoutExtension(file).ToUpper() == "ARTWORK" ||
Path.GetFileNameWithoutExtension(file).ToUpper() == "FRONT" ||
Path.GetFileNameWithoutExtension(file).ToUpper() == "BACK" ||
Path.GetFileNameWithoutExtension(file).ToUpper() == "JACKET" ||
Path.GetFileNameWithoutExtension(file).ToUpper() == path)
{
if (Path.GetExtension(file) == ".png" || Path.GetExtension(file) == ".jpg" || Path.GetExtension(file) == ".jpeg")
return File.ReadAllBytes(file);
}
}
return null;
}
}
}
/// <inheritdoc/>
public string[] Genres => ATLTrack.Genre.Split(Settings.DisplayValueSeparator, '/');
@ -47,10 +73,16 @@ namespace FRESHMusicPlayer.Backends
/// <inheritdoc/>
public Track ATLTrack { get; set; }
private string path;
/// <summary>
/// Gets metadata for the supplied file path
/// </summary>
/// <param name="path">The file path to query metadata for</param>
public FileMetadataProvider(string path) => ATLTrack = new Track(path);
public FileMetadataProvider(string path)
{
this.path = path;
ATLTrack = new Track(path);
}
}
}

View file

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FRESHMusicPlayer.Backends
{
public interface ISupportEqualization
{
List<EqualizerBand> EqualizerBands { get; set; }
void UpdateEqualizer();
}
public class EqualizerBand
{
public float Frequency { get; set; }
public float Gain { get; set; }
public float Bandwidth { get; set; }
}
}

View file

@ -1,4 +1,5 @@
using NAudio.Wave;
using NAudio.Dsp;
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.Composition;
@ -10,7 +11,7 @@ using System.Threading.Tasks;
namespace FRESHMusicPlayer.Backends
{
[Export(typeof(IAudioBackend))]
class NAudioBackend : IAudioBackend
class NAudioBackend : IAudioBackend, ISupportEqualization
{
public WaveOutEvent OutputDevice;
@ -30,6 +31,16 @@ namespace FRESHMusicPlayer.Backends
}
public TimeSpan TotalTime => AudioFile.TotalTime;
public List<EqualizerBand> EqualizerBands
{
get => equalizer.Bands;
set => equalizer.Bands = value;
}
public void UpdateEqualizer() => equalizer?.Update();
private Equalizer equalizer;
public NAudioBackend()
{
if (OutputDevice is null)
@ -50,7 +61,8 @@ namespace FRESHMusicPlayer.Backends
await Task.Run(() =>
{
AudioFile = new AudioFileReader(file);
OutputDevice.Init(AudioFile);
equalizer = new Equalizer(AudioFile, new List<EqualizerBand>());
OutputDevice.Init(equalizer);
});
}
catch (ArgumentException)
@ -90,4 +102,71 @@ namespace FRESHMusicPlayer.Backends
OutputDevice.Pause();
}
}
public class Equalizer : ISampleProvider
{
private readonly ISampleProvider sourceProvider;
public List<EqualizerBand> Bands;
private BiQuadFilter[,] filters;
private readonly int channels;
private int bandCount;
private bool updated;
public Equalizer(ISampleProvider sourceProvider, List<EqualizerBand> bands)
{
this.sourceProvider = sourceProvider;
this.Bands = bands;
channels = sourceProvider.WaveFormat.Channels;
bandCount = bands.Count;
filters = new BiQuadFilter[channels, bands.Count];
CreateFilters();
}
private void CreateFilters()
{
for (int bandIndex = 0; bandIndex < bandCount; bandIndex++)
{
var band = Bands[bandIndex];
for (int n = 0; n < channels; n++)
{
if (filters[n, bandIndex] == null)
filters[n, bandIndex] = BiQuadFilter.PeakingEQ(sourceProvider.WaveFormat.SampleRate, band.Frequency, band.Bandwidth, band.Gain);
else
filters[n, bandIndex].SetPeakingEq(sourceProvider.WaveFormat.SampleRate, band.Frequency, band.Bandwidth, band.Gain);
}
}
}
public void Update()
{
updated = true;
bandCount = Bands.Count;
filters = new BiQuadFilter[channels, Bands.Count];
CreateFilters();
}
public WaveFormat WaveFormat => sourceProvider.WaveFormat;
public int Read(float[] buffer, int offset, int count)
{
int samplesRead = sourceProvider.Read(buffer, offset, count);
if (updated)
{
CreateFilters();
updated = false;
}
for (int n = 0; n < samplesRead; n++)
{
int ch = n % channels;
for (int band = 0; band < bandCount; band++)
{
buffer[offset + n] = filters[ch, band].Transform(buffer[offset + n]);
}
}
return samplesRead;
}
}
}

View file

@ -97,6 +97,10 @@ namespace FRESHMusicPlayer
}
QueueChanged?.Invoke(null, EventArgs.Empty);
}
/// <summary>
/// Adds a track to play after the currently playing track
/// </summary>
/// <param name="filePath">The track to add.</param>
public void PlayNext(string filePath)
{
queue.Insert(Position, filePath);

View file

@ -103,7 +103,7 @@ namespace FRESHMusicPlayer
Queue.Position -= 2;
await PlayAsync();
}
/// <summary>
/// Skips to the next track in the Queue. If there are no more tracks, the player will stop.
/// </summary>
@ -142,6 +142,7 @@ namespace FRESHMusicPlayer
/// <param name="path">The track to play</param>
public async Task PlayAsync(string path)
{
Queue.Clear();
Queue.Add(path);
await PlayAsync();
}