mirror of
https://github.com/jayfunc/BetterLyrics.git
synced 2026-01-12 19:24:55 +08:00
add spectrum
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
<Identity
|
||||
Name="37412.BetterLyrics"
|
||||
Publisher="CN=E1428B0E-DC1D-4EA4-ACB1-4556569D5BA9"
|
||||
Version="1.0.78.0" />
|
||||
Version="1.0.79.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="ca4a4830-fc19-40d9-b823-53e2bff3d816" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.3.2" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4654" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250606001" />
|
||||
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
|
||||
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
|
||||
<PackageReference Include="Nito.AsyncEx.Tasks" Version="5.1.2" />
|
||||
<PackageReference Include="NTextCat" Version="0.3.65" />
|
||||
|
||||
@@ -116,6 +116,14 @@
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
|
||||
<controls:SettingsExpander
|
||||
x:Uid="SettingsPageSpectrumLayer"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="{x:Bind LyricsBackgroundSettings.IsSpectrumOverlayEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsBackgroundSettings.IsSpectrumOverlayEnabled, Mode=TwoWay}" />
|
||||
</controls:SettingsExpander>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
@@ -281,7 +281,7 @@
|
||||
</ListView.ItemsPanel>
|
||||
<ListView.Items>
|
||||
|
||||
<ListViewItem IsSelected="True" Tag="General">
|
||||
<ListViewItem Tag="General">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<FontIcon
|
||||
FontFamily="{StaticResource IconFontFamily}"
|
||||
|
||||
@@ -122,8 +122,15 @@
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- 播放源列表 -->
|
||||
<ListView
|
||||
x:Name="MediaSourceProvidersListView"
|
||||
VerticalAlignment="Top"
|
||||
AllowDrop="True"
|
||||
CanDragItems="True"
|
||||
CanReorderItems="True"
|
||||
DragItemsCompleted="MediaSourceProvidersListView_DragItemsCompleted"
|
||||
ItemsSource="{x:Bind ViewModel.AppSettings.MediaSourceProvidersInfo, Mode=OneWay}"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
||||
ScrollViewer.HorizontalScrollMode="Enabled"
|
||||
@@ -138,6 +145,10 @@
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:MediaSourceProviderInfo">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<FontIcon
|
||||
FontFamily="Segoe UI Symbol"
|
||||
FontSize="12"
|
||||
Glyph="⠿" />
|
||||
<ImageIcon Height="16" Source="{Binding Provider, Converter={StaticResource MediaSourceProviderToLogoUriConverter}, Mode=OneWay}" />
|
||||
<TextBlock
|
||||
MaxWidth="200"
|
||||
@@ -162,6 +173,7 @@
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</Grid>
|
||||
|
||||
<StackPanel
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Center"
|
||||
|
||||
@@ -41,5 +41,11 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
// <20><> LyricsSearchProvidersInfo <20><><EFBFBD><EFBFBD> CollectionChanged <20>¼<EFBFBD>
|
||||
ViewModel.SelectedMediaSourceProvider?.LyricsSearchProvidersInfo?.Refresh();
|
||||
}
|
||||
|
||||
private void MediaSourceProvidersListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
|
||||
{
|
||||
// <20><> MediaSourceProvidersInfo <20><><EFBFBD><EFBFBD> CollectionChanged <20>¼<EFBFBD>
|
||||
ViewModel.AppSettings.MediaSourceProvidersInfo?.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using NAudio.Dsp;
|
||||
using NAudio.Wave;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public class SpectrumAnalyzer : IDisposable
|
||||
{
|
||||
private WasapiLoopbackCapture _capture;
|
||||
|
||||
private int _sampleRate = 48000;
|
||||
private readonly int _fftLength = 2048;
|
||||
|
||||
private readonly float[] _fftLeftBuffer;
|
||||
private readonly float[] _fftRightBuffer;
|
||||
|
||||
private readonly Complex[] _fftLeftData;
|
||||
private readonly Complex[] _fftRightData;
|
||||
|
||||
private float[] _spectrumLeftData;
|
||||
private float[] _spectrumRightData;
|
||||
private float[] _spectrumData;
|
||||
|
||||
private bool _disposed = false;
|
||||
|
||||
private double[] _hammingWindow;
|
||||
|
||||
private float[] _currentSpectrum;
|
||||
public float[] SmoothSpectrum { get; private set; }
|
||||
|
||||
public int BarCount { get; set; } = 32;
|
||||
public int Sensitivity { get; set; } = 10;
|
||||
public float SmoothingFactor { get; set; } = 0.95f;
|
||||
public bool IsCapturing { get; private set; } = false;
|
||||
|
||||
public SpectrumAnalyzer()
|
||||
{
|
||||
_fftLeftBuffer = new float[_fftLength];
|
||||
_fftLeftData = new Complex[_fftLength];
|
||||
_fftRightBuffer = new float[_fftLength];
|
||||
_fftRightData = new Complex[_fftLength];
|
||||
_hammingWindow = new double[_fftLength];
|
||||
//汉明窗
|
||||
for (int i = 0; i < _fftLength; i++)
|
||||
{
|
||||
_hammingWindow[i] = 0.54 - 0.46 * Math.Cos((2 * Math.PI * i) / (_fftLength - 1));
|
||||
}
|
||||
}
|
||||
|
||||
public void StartCapture()
|
||||
{
|
||||
_currentSpectrum = new float[BarCount];
|
||||
SmoothSpectrum = new float[BarCount];
|
||||
|
||||
try
|
||||
{
|
||||
_capture = new WasapiLoopbackCapture();
|
||||
_sampleRate = _capture.WaveFormat.SampleRate;
|
||||
_spectrumLeftData = new float[(int)(24000.0f / _sampleRate * _fftLength) / 2];
|
||||
_spectrumRightData = new float[(int)(24000.0f / _sampleRate * _fftLength) / 2];
|
||||
_spectrumData = new float[(int)(24000.0f / _sampleRate * _fftLength)];
|
||||
_capture.DataAvailable += OnDataAvailable;
|
||||
_capture.RecordingStopped += OnRecordingStopped;
|
||||
_capture.StartRecording();
|
||||
|
||||
IsCapturing = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void StopCapture()
|
||||
{
|
||||
_capture?.DataAvailable -= OnDataAvailable;
|
||||
_capture?.RecordingStopped -= OnRecordingStopped;
|
||||
_capture?.StopRecording();
|
||||
|
||||
IsCapturing = false;
|
||||
}
|
||||
|
||||
private void OnDataAvailable(object? sender, WaveInEventArgs e)
|
||||
{
|
||||
if (_disposed || e.BytesRecorded == 0) return;
|
||||
// 将字节转换为浮点数
|
||||
int samples = e.BytesRecorded / 8;
|
||||
if (samples < _fftLength) return;
|
||||
for (int i = 0; i < _fftLength; i++)
|
||||
{
|
||||
_fftLeftBuffer[i] = BitConverter.ToSingle(e.Buffer, i * 8);
|
||||
_fftRightBuffer[i] = BitConverter.ToSingle(e.Buffer, i * 8 + 4);
|
||||
}
|
||||
for (int i = 0; i < _fftLength; i++)
|
||||
{
|
||||
_fftLeftData[i].X = _fftLeftBuffer[i] * (float)_hammingWindow[i]; // Real part
|
||||
_fftLeftData[i].Y = 0; // Imaginary part
|
||||
_fftRightData[i].X = _fftRightBuffer[i] * (float)_hammingWindow[i];
|
||||
_fftRightData[i].Y = 0;
|
||||
}
|
||||
|
||||
// FFT
|
||||
FastFourierTransform.FFT(true, (int)Math.Log(_fftLength, 2), _fftLeftData);
|
||||
FastFourierTransform.FFT(true, (int)Math.Log(_fftLength, 2), _fftRightData);
|
||||
for (int i = 0; i < _spectrumLeftData.Length; i++)
|
||||
{
|
||||
float real = (float)_fftLeftData[i].X;
|
||||
float imaginary = (float)_fftLeftData[i].Y;
|
||||
float magnitude = (float)Math.Sqrt(real * real + imaginary * imaginary);
|
||||
float frequency = i * _sampleRate / _fftLength;
|
||||
float compensationFactor = GetCompensationFactor(frequency);
|
||||
_spectrumLeftData[i] = magnitude * compensationFactor;
|
||||
_spectrumRightData[i] = (float)Math.Sqrt((float)_fftRightData[i].X * (float)_fftRightData[i].X + (float)_fftRightData[i].Y * (float)_fftRightData[i].Y) * compensationFactor;
|
||||
for (int j = 0; j < _spectrumLeftData.Length; j++)
|
||||
{
|
||||
_spectrumData[j] = _spectrumLeftData[_spectrumLeftData.Length - 1 - j];
|
||||
}
|
||||
Array.Copy(_spectrumRightData, 0, _spectrumData, _spectrumLeftData.Length, _spectrumRightData.Length);
|
||||
}
|
||||
|
||||
for (int i = 0; i < BarCount; i++)
|
||||
{
|
||||
int index = (int)((float)i / BarCount * _spectrumData.Length);
|
||||
if (index < _spectrumData.Length)
|
||||
{
|
||||
_currentSpectrum[i] = _spectrumData[index] * 250f * Sensitivity;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void UpdateSmoothSpectrum()
|
||||
{
|
||||
for (int i = 0; i < BarCount; i++)
|
||||
{
|
||||
SmoothSpectrum[i] = SmoothSpectrum[i] * SmoothingFactor +
|
||||
_currentSpectrum[i] * (1 - SmoothingFactor);
|
||||
}
|
||||
}
|
||||
|
||||
private float GetCompensationFactor(float freq)
|
||||
{
|
||||
// 补偿曲线
|
||||
float[] frequencies = { 20, 50, 100, 200, 500, 1000, 2000, 4000, 8000, 16000, 20000 };
|
||||
float[] gains = { 0.5f, 0.3f, 0.4f, 0.6f, 0.8f, 1.0f, 1.2f, 1.3f, 1.1f, 0.9f, 0.8f };
|
||||
if (freq <= frequencies[0])
|
||||
{
|
||||
return gains[0];
|
||||
}
|
||||
if (freq >= frequencies[frequencies.Length - 1])
|
||||
{
|
||||
return gains[gains.Length - 1];
|
||||
}
|
||||
int i = 0;
|
||||
while (freq > frequencies[i + 1])
|
||||
{
|
||||
i++;
|
||||
}
|
||||
// 线性插值
|
||||
float x1 = frequencies[i];
|
||||
float y1 = gains[i];
|
||||
float x2 = frequencies[i + 1];
|
||||
float y2 = gains[i + 1];
|
||||
return y1 + (freq - x1) * ((y2 - y1) / (x2 - x1));
|
||||
}
|
||||
|
||||
private void OnRecordingStopped(object? sender, StoppedEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_capture?.Dispose();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,8 @@ namespace BetterLyrics.WinUI3.Models.Settings
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsFluidOverlayEnabled { get; set; } = false;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int FluidOverlayOpacity { get; set; } = 100;
|
||||
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsSpectrumOverlayEnabled { get; set; } = false;
|
||||
|
||||
public LyricsBackgroundSettings() { }
|
||||
|
||||
public object Clone()
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
<Grid>
|
||||
<canvas:CanvasAnimatedControl
|
||||
x:Name="LyricsCanvas"
|
||||
Draw="LyricsCanvas_Draw"
|
||||
CreateResources="LyricsCanvas_CreateResources"
|
||||
Draw="LyricsCanvas_Draw"
|
||||
Update="LyricsCanvas_Update" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -1150,6 +1150,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
|
||||
<data name="SettingsPageSongInfoRight.Content" xml:space="preserve">
|
||||
<value>Right</value>
|
||||
</data>
|
||||
<data name="SettingsPageSpectrumLayer.Header" xml:space="preserve">
|
||||
<value>Spectrum layer</value>
|
||||
</data>
|
||||
<data name="SettingsPageSpeed.Header" xml:space="preserve">
|
||||
<value>Motion rate</value>
|
||||
</data>
|
||||
|
||||
@@ -156,6 +156,9 @@
|
||||
<data name="FailToStartLXMusicServer" xml:space="preserve">
|
||||
<value>LX Music Serverに接続できない場合は、設定に移動してください。リンクが正しく入力されているかどうかを確認するための高度なオプションに移動してください</value>
|
||||
</data>
|
||||
<data name="FullscreenMode" xml:space="preserve">
|
||||
<value>フルスクリーンモード</value>
|
||||
</data>
|
||||
<data name="HostWindowClickThroughButton.Content" xml:space="preserve">
|
||||
<value>ロック</value>
|
||||
</data>
|
||||
@@ -436,6 +439,9 @@
|
||||
<data name="MusicGalleryPageTitle" xml:space="preserve">
|
||||
<value>音楽ギャラリー - BetterLyrics</value>
|
||||
</data>
|
||||
<data name="NarrowMode" xml:space="preserve">
|
||||
<value>狭い</value>
|
||||
</data>
|
||||
<data name="PictureInPictureMode" xml:space="preserve">
|
||||
<value>ピクチャーインピクチャーモード</value>
|
||||
</data>
|
||||
@@ -715,9 +721,6 @@
|
||||
<data name="SettingsPageFullscreenMode.Text" xml:space="preserve">
|
||||
<value>フルスクリーンモード</value>
|
||||
</data>
|
||||
<data name="FullscreenMode" xml:space="preserve">
|
||||
<value>フルスクリーンモード</value>
|
||||
</data>
|
||||
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
|
||||
<value>音楽が再生されていないときに、自動的に歌詞ウィンドウを非表示/表示します</value>
|
||||
</data>
|
||||
@@ -1147,6 +1150,9 @@
|
||||
<data name="SettingsPageSongInfoRight.Content" xml:space="preserve">
|
||||
<value>右</value>
|
||||
</data>
|
||||
<data name="SettingsPageSpectrumLayer.Header" xml:space="preserve">
|
||||
<value>スペクトラムレイヤー</value>
|
||||
</data>
|
||||
<data name="SettingsPageSpeed.Header" xml:space="preserve">
|
||||
<value>モーション</value>
|
||||
</data>
|
||||
@@ -1240,7 +1246,4 @@
|
||||
<data name="TryRunMultipleInstance" xml:space="preserve">
|
||||
<value>BetterLyrics はすでに実行されています</value>
|
||||
</data>
|
||||
<data name="NarrowMode" xml:space="preserve">
|
||||
<value>狭い</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -156,6 +156,9 @@
|
||||
<data name="FailToStartLXMusicServer" xml:space="preserve">
|
||||
<value>LX Music Server에 연결할 수 없습니다. 설정으로 이동하십시오 - 고급 옵션이 링크가 올바르게 입력되었는지 확인하십시오.</value>
|
||||
</data>
|
||||
<data name="FullscreenMode" xml:space="preserve">
|
||||
<value>전체화면 모드</value>
|
||||
</data>
|
||||
<data name="HostWindowClickThroughButton.Content" xml:space="preserve">
|
||||
<value>잠금</value>
|
||||
</data>
|
||||
@@ -436,6 +439,9 @@
|
||||
<data name="MusicGalleryPageTitle" xml:space="preserve">
|
||||
<value>음악 갤러리 - BetterLyrics</value>
|
||||
</data>
|
||||
<data name="NarrowMode" xml:space="preserve">
|
||||
<value>협폭 조명</value>
|
||||
</data>
|
||||
<data name="PictureInPictureMode" xml:space="preserve">
|
||||
<value>사진 인당 모드</value>
|
||||
</data>
|
||||
@@ -715,9 +721,6 @@
|
||||
<data name="SettingsPageFullscreenMode.Text" xml:space="preserve">
|
||||
<value>전체화면 모드</value>
|
||||
</data>
|
||||
<data name="FullscreenMode" xml:space="preserve">
|
||||
<value>전체화면 모드</value>
|
||||
</data>
|
||||
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
|
||||
<value>음악이 재생되지 않을 때 자동으로 가사 창 숨기기/표시</value>
|
||||
</data>
|
||||
@@ -1147,6 +1150,9 @@
|
||||
<data name="SettingsPageSongInfoRight.Content" xml:space="preserve">
|
||||
<value>오른쪽</value>
|
||||
</data>
|
||||
<data name="SettingsPageSpectrumLayer.Header" xml:space="preserve">
|
||||
<value>스펙트럼 레이어</value>
|
||||
</data>
|
||||
<data name="SettingsPageSpeed.Header" xml:space="preserve">
|
||||
<value>모션</value>
|
||||
</data>
|
||||
@@ -1240,7 +1246,4 @@
|
||||
<data name="TryRunMultipleInstance" xml:space="preserve">
|
||||
<value>BetterLyrics 가 이미 실행 중입니다</value>
|
||||
</data>
|
||||
<data name="NarrowMode" xml:space="preserve">
|
||||
<value>협폭 조명</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -156,6 +156,9 @@
|
||||
<data name="FailToStartLXMusicServer" xml:space="preserve">
|
||||
<value>无法连接到 LX 音乐服务器,请转到设置 - 高级选项以检查是否正确输入链接</value>
|
||||
</data>
|
||||
<data name="FullscreenMode" xml:space="preserve">
|
||||
<value>全屏模式</value>
|
||||
</data>
|
||||
<data name="HostWindowClickThroughButton.Content" xml:space="preserve">
|
||||
<value>锁定</value>
|
||||
</data>
|
||||
@@ -436,6 +439,9 @@
|
||||
<data name="MusicGalleryPageTitle" xml:space="preserve">
|
||||
<value>音乐库 - BetterLyrics</value>
|
||||
</data>
|
||||
<data name="NarrowMode" xml:space="preserve">
|
||||
<value>窄屏模式</value>
|
||||
</data>
|
||||
<data name="PictureInPictureMode" xml:space="preserve">
|
||||
<value>画中画模式</value>
|
||||
</data>
|
||||
@@ -715,9 +721,6 @@
|
||||
<data name="SettingsPageFullscreenMode.Text" xml:space="preserve">
|
||||
<value>全屏模式</value>
|
||||
</data>
|
||||
<data name="FullscreenMode" xml:space="preserve">
|
||||
<value>全屏模式</value>
|
||||
</data>
|
||||
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
|
||||
<value>音乐未播放/播放时自动隐藏/显示歌词窗口</value>
|
||||
</data>
|
||||
@@ -1147,6 +1150,9 @@
|
||||
<data name="SettingsPageSongInfoRight.Content" xml:space="preserve">
|
||||
<value>靠右</value>
|
||||
</data>
|
||||
<data name="SettingsPageSpectrumLayer.Header" xml:space="preserve">
|
||||
<value>频谱层</value>
|
||||
</data>
|
||||
<data name="SettingsPageSpeed.Header" xml:space="preserve">
|
||||
<value>运动速率</value>
|
||||
</data>
|
||||
@@ -1240,7 +1246,4 @@
|
||||
<data name="TryRunMultipleInstance" xml:space="preserve">
|
||||
<value>BetterLyrics 已经在运行</value>
|
||||
</data>
|
||||
<data name="NarrowMode" xml:space="preserve">
|
||||
<value>窄屏模式</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -156,6 +156,9 @@
|
||||
<data name="FailToStartLXMusicServer" xml:space="preserve">
|
||||
<value>無法連接到 LX 音樂服務器,請轉到設置 - 高級選項以檢查是否正確輸入鏈接</value>
|
||||
</data>
|
||||
<data name="FullscreenMode" xml:space="preserve">
|
||||
<value>全螢幕模式</value>
|
||||
</data>
|
||||
<data name="HostWindowClickThroughButton.Content" xml:space="preserve">
|
||||
<value>鎖定</value>
|
||||
</data>
|
||||
@@ -436,6 +439,9 @@
|
||||
<data name="MusicGalleryPageTitle" xml:space="preserve">
|
||||
<value>音樂庫 - BetterLyrics</value>
|
||||
</data>
|
||||
<data name="NarrowMode" xml:space="preserve">
|
||||
<value>窄螢幕模式</value>
|
||||
</data>
|
||||
<data name="PictureInPictureMode" xml:space="preserve">
|
||||
<value>畫中畫模式</value>
|
||||
</data>
|
||||
@@ -715,9 +721,6 @@
|
||||
<data name="SettingsPageFullscreenMode.Text" xml:space="preserve">
|
||||
<value>全螢幕模式</value>
|
||||
</data>
|
||||
<data name="FullscreenMode" xml:space="preserve">
|
||||
<value>全螢幕模式</value>
|
||||
</data>
|
||||
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
|
||||
<value>音樂未播放/播放時自動隱藏/顯示歌詞視窗</value>
|
||||
</data>
|
||||
@@ -1147,6 +1150,9 @@
|
||||
<data name="SettingsPageSongInfoRight.Content" xml:space="preserve">
|
||||
<value>靠右</value>
|
||||
</data>
|
||||
<data name="SettingsPageSpectrumLayer.Header" xml:space="preserve">
|
||||
<value>光譜層</value>
|
||||
</data>
|
||||
<data name="SettingsPageSpeed.Header" xml:space="preserve">
|
||||
<value>動作速率</value>
|
||||
</data>
|
||||
@@ -1240,7 +1246,4 @@
|
||||
<data name="TryRunMultipleInstance" xml:space="preserve">
|
||||
<value>BetterLyrics 已經在運作</value>
|
||||
</data>
|
||||
<data name="NarrowMode" xml:space="preserve">
|
||||
<value>窄螢幕模式</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,4 +1,5 @@
|
||||
using CommunityToolkit.WinUI;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.Graphics.Canvas.Effects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Hqub.Lastfm;
|
||||
using Microsoft.Graphics.Canvas;
|
||||
using Microsoft.Graphics.Canvas.Brushes;
|
||||
using Microsoft.Graphics.Canvas.Effects;
|
||||
@@ -49,6 +50,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
}
|
||||
DrawAlbumArtBackground(control, combinedDs);
|
||||
DrawFluidBackground(control, combinedDs);
|
||||
DrawSpectrum(control, combinedDs);
|
||||
|
||||
combinedDs.DrawImage(blurredLyrics);
|
||||
|
||||
@@ -100,6 +102,76 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawSpectrum(ICanvasAnimatedControl control, CanvasDrawingSession ds)
|
||||
{
|
||||
if (_spectrumAnalyzer != null && _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.IsSpectrumOverlayEnabled)
|
||||
{
|
||||
var points = new Vector2[_spectrumAnalyzer.BarCount];
|
||||
float pointSpacing = 0;
|
||||
|
||||
if (_spectrumAnalyzer.BarCount > 1)
|
||||
{
|
||||
pointSpacing = (float)_canvasWidth / (_spectrumAnalyzer.BarCount - 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _spectrumAnalyzer.BarCount; i++)
|
||||
{
|
||||
float x = i * pointSpacing;
|
||||
float amplitude = _spectrumAnalyzer.SmoothSpectrum.Average() * 10 + _spectrumAnalyzer.SmoothSpectrum[i] * 0.5f;
|
||||
float y = (float)_canvasHeight - amplitude;
|
||||
points[i] = new Vector2(x, y);
|
||||
}
|
||||
|
||||
// 用于填充的闭合路径
|
||||
using var pathBuilder = new CanvasPathBuilder(ds);
|
||||
pathBuilder.BeginFigure(points[0]);
|
||||
|
||||
if (_spectrumAnalyzer.BarCount > 2)
|
||||
{
|
||||
for (int i = 0; i < _spectrumAnalyzer.BarCount - 1; i++)
|
||||
{
|
||||
Vector2 p0 = points[Math.Max(i - 1, 0)];
|
||||
Vector2 p1 = points[i];
|
||||
Vector2 p2 = points[i + 1];
|
||||
Vector2 p3 = points[Math.Min(i + 2, _spectrumAnalyzer.BarCount - 1)];
|
||||
|
||||
Vector2 cp1 = p1 + (p2 - p0) / 6.0f;
|
||||
Vector2 cp2 = p2 - (p3 - p1) / 6.0f;
|
||||
|
||||
pathBuilder.AddCubicBezier(cp1, cp2, p2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pathBuilder.AddLine(points[1]);
|
||||
}
|
||||
|
||||
pathBuilder.AddLine(new Vector2(points[_spectrumAnalyzer.BarCount - 1].X, (float)_canvasHeight));
|
||||
pathBuilder.AddLine(new Vector2(points[0].X, (float)_canvasHeight));
|
||||
pathBuilder.EndFigure(CanvasFigureLoop.Closed);
|
||||
|
||||
using var geometry = CanvasGeometry.CreatePath(pathBuilder);
|
||||
var gradientStops = new CanvasGradientStop[]
|
||||
{
|
||||
new() { Position = 0.0f, Color = _albumArtAccentColorTransition.Value },
|
||||
new() { Position = 1.0f, Color = Colors.Transparent }
|
||||
};
|
||||
|
||||
using var gradientBrush = new CanvasLinearGradientBrush(ds, gradientStops);
|
||||
gradientBrush.StartPoint = new Vector2((float)_canvasWidth / 2, (float)_canvasHeight);
|
||||
gradientBrush.EndPoint = new Vector2((float)_canvasWidth / 2, points.Select(p => p.Y).Min());
|
||||
|
||||
// 使用渐变画刷填充
|
||||
ds.FillGeometry(geometry, gradientBrush);
|
||||
|
||||
// 绘制轮廓线
|
||||
// var lineColor = Colors.SkyBlue;
|
||||
// float strokeWidth = 2f;
|
||||
// session.DrawGeometry(geometry, lineColor, strokeWidth);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawFluidBackground(ICanvasAnimatedControl control, CanvasDrawingSession ds)
|
||||
{
|
||||
if (_effect != null && _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.IsFluidOverlayEnabled)
|
||||
|
||||
@@ -85,6 +85,13 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_isAlbumArtSizeChanged = true;
|
||||
}
|
||||
}
|
||||
else if (message.Sender is LyricsBackgroundSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsBackgroundSettings.IsSpectrumOverlayEnabled))
|
||||
{
|
||||
_isSpectrumOverlayEnabledChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<Color> message)
|
||||
|
||||
@@ -54,6 +54,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
private bool _isSongInfoFontSizeChanged = false;
|
||||
private bool _isAlbumArtSizeChanged = false;
|
||||
|
||||
private bool _isSpectrumOverlayEnabledChanged = true;
|
||||
|
||||
public void Update(ICanvasAnimatedControl control, CanvasAnimatedUpdateEventArgs args)
|
||||
{
|
||||
_elapsedTime = args.Timing.ElapsedTime;
|
||||
@@ -101,6 +103,25 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_rotateAngle += _coverRotateBaseSpeed * _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.CoverOverlaySpeed / 100.0;
|
||||
_rotateAngle %= Math.PI * 2;
|
||||
|
||||
if (_isSpectrumOverlayEnabledChanged)
|
||||
{
|
||||
if (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.IsSpectrumOverlayEnabled)
|
||||
{
|
||||
_spectrumAnalyzer?.StartCapture();
|
||||
}
|
||||
else
|
||||
{
|
||||
_spectrumAnalyzer?.StopCapture();
|
||||
}
|
||||
|
||||
_isSpectrumOverlayEnabledChanged = false;
|
||||
}
|
||||
|
||||
if (_spectrumAnalyzer?.IsCapturing == true)
|
||||
{
|
||||
_spectrumAnalyzer?.UpdateSmoothSpectrum();
|
||||
}
|
||||
|
||||
//if (_isCanvasWidthChanged)
|
||||
//{
|
||||
// if (_canvasWidth < 500)
|
||||
|
||||
@@ -172,6 +172,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial ElementTheme ThemeTypeSent { get; set; }
|
||||
|
||||
private SpectrumAnalyzer? _spectrumAnalyzer;
|
||||
|
||||
public LyricsRendererViewModel(
|
||||
ISettingsService settingsService,
|
||||
IMediaSessionsService mediaSessionsService,
|
||||
@@ -181,7 +183,6 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_settingsService = settingsService;
|
||||
_mediaSessionsService = mediaSessionsService;
|
||||
_liveStatesService = liveStatesService;
|
||||
|
||||
_lastFMService = lastFMService;
|
||||
|
||||
_logger = Ioc.Default.GetRequiredService<ILogger<LyricsRendererViewModel>>();
|
||||
@@ -191,7 +192,6 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_titleTextFormat.HorizontalAlignment = _artistTextFormat.HorizontalAlignment = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.SongInfoAlignmentType.ToCanvasHorizontalAlignment();
|
||||
UpdateSongInfoFontSize();
|
||||
|
||||
|
||||
_timelineSyncThreshold = 0;
|
||||
|
||||
_mediaSessionsService.IsPlayingChanged += MediaSessionsService_IsPlayingChanged;
|
||||
@@ -203,6 +203,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
IsPlaying = _mediaSessionsService.IsPlaying;
|
||||
|
||||
UpdateColorConfig();
|
||||
|
||||
_spectrumAnalyzer = new SpectrumAnalyzer();
|
||||
}
|
||||
|
||||
private void MediaSessionsService_LyricsChanged(object? sender, LyricsChangedEventArgs e)
|
||||
|
||||
Reference in New Issue
Block a user