VB.net开发的音乐播放器,支持歌词显示歌词同步,点一下歌词直接跳转

断了今生、忘了曾经 提交于 2020-02-21 04:24:59
Imports System.IO

Public Class Form1
    Public RND As New Random
    Public g As BufferedGraphics
    Public g2 As BufferedGraphics
    Public fonts20 As New Font("微软雅黑", 20)
    Public fonts11 As New Font("微软雅黑", 11)
    Public 居中画字样式 As StringFormat
    Public 播放器 As 歌曲
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        g = BufferedGraphicsManager.Current.Allocate(PictureBox1.CreateGraphics, PictureBox1.DisplayRectangle)
        g2 = BufferedGraphicsManager.Current.Allocate(PictureBox2.CreateGraphics, PictureBox2.DisplayRectangle)
        读取音乐文件并且刷新listview1()

        居中画字样式 = New StringFormat()
        居中画字样式.LineAlignment = StringAlignment.Center
        居中画字样式.Alignment = StringAlignment.Center



        Dim 集合 As New List(Of String)
        '第一种方法,可以获得索引,推荐
        For I = 0 To 集合.Count - 1
            Debug.Print(集合(I))
        Next
        '第二种方法,方便快速但是没索引或者需要另外定义变量
        For Each I In 集合
            Debug.Print(I)
        Next
    End Sub

    Public Sub 读取音乐文件并且刷新listview1()
        ListView1.BeginUpdate()
        ListView1.Items.Clear()
        '    Dim files As String() = Directory.GetFiles("C:\Users\panwei\Desktop\Music")
        Dim files As String() = Directory.GetFiles(Application.StartupPath)
        For Each file As String In files
            If Path.GetExtension(file) = ".flac" OrElse Path.GetExtension(file) = ".mp3" Then
                Dim music = New 歌曲(file)
                Dim t As ListViewItem = New ListViewItem({music.歌曲名, music.歌曲类型, music.歌曲长度_秒, Int(music.是否有歌词)})
                t.Tag = file
                t.BackColor = Color.FromArgb(RND.Next(200, 255), RND.Next(200, 255), RND.Next(200, 255))
                ListView1.Items.Add(t)
                music.close()
            End If
        Next
        ListView1.EndUpdate()
    End Sub


    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        If 播放器 IsNot Nothing Then
            '绘制进度条和进度条歌词
            g.Graphics.Clear(Color.Black)
            g.Graphics.FillRectangle(Brushes.Green, New RectangleF(0, 0, 播放器.当前播放时间_百分比 * PictureBox1.Width, PictureBox1.Height))
            g.Graphics.DrawString(播放器.当前播放时间_时分格式 & "/" & 播放器.歌曲长度_时分格式, fonts20, Brushes.Gold, 0, 0)
            For I = 1 To 播放器.歌词.Count - 2
                If 播放器.歌词(I + 1).歌词时间_秒 > 播放器.当前播放时间_秒 Then
                    g.Graphics.DrawString(播放器.歌词(I).歌词文本, fonts20, Brushes.Gold, New Rectangle(Point.Empty, PictureBox1.Size), 居中画字样式)
                    Exit For
                End If
            Next
            g.Render()

            '绘制歌词
            g2.Graphics.Clear(Color.Black)
            g2.Graphics.DrawString("当前歌曲没有歌词", Me.Font, Brushes.Red, 0, 0)
            Dim 当前歌词 As Boolean = False
            For I = 0 To 播放器.歌词.Count - 2
                If 播放器.歌词(I + 1).歌词时间_秒 > 播放器.当前播放时间_秒 And 当前歌词 = False Then
                    Dim se = 播放器.歌词(I).颜色
                    Dim se2 = Color.FromArgb(se.R - 100, se.G - 100, se.B - 100)
                    Dim 当前歌词长度 = 播放器.歌词(I + 1).歌词时间_秒 - 播放器.歌词(I).歌词时间_秒
                    Dim 这句歌词现在播放到 = 播放器.当前播放时间_秒 - 播放器.歌词(I).歌词时间_秒
                    g2.Graphics.FillRectangle(New SolidBrush(se2), New Rectangle((I Mod 3) * (PictureBox2.Width / 3), Int(I / 3) * 当前绘制高度, (PictureBox2.Width / 3) * (这句歌词现在播放到 / 当前歌词长度), 当前绘制高度))
                    g2.Graphics.DrawString(播放器.歌词(I).歌词文本, fonts11, Brushes.Red, New Rectangle((I Mod 3) * (PictureBox2.Width / 3), Int(I / 3) * 当前绘制高度, (PictureBox2.Width / 3), 当前绘制高度), 居中画字样式)
                    当前歌词 = True
                Else
                    g2.Graphics.FillRectangle(New SolidBrush(播放器.歌词(I).颜色), New Rectangle((I Mod 3) * (PictureBox2.Width / 3), Int(I / 3) * 当前绘制高度, (PictureBox2.Width / 3), 当前绘制高度))

                    Dim str = 播放器.歌词(I).歌词文本
                    If 显示当前歌词时间.Checked = True Then
                        str += vbCrLf & 播放器.歌词(I).歌词时间_分秒格式
                    End If

                    g2.Graphics.DrawString(str, Me.Font, Brushes.Black, New Rectangle((I Mod 3) * (PictureBox2.Width / 3), Int(I / 3) * 当前绘制高度, (PictureBox2.Width / 3), 当前绘制高度), 居中画字样式)
                End If
            Next
            g2.Render()
        End If
    End Sub
    Public 当前绘制高度 As Integer = 35


    Private Sub 进度条弹起(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseUp
        If 播放器 IsNot Nothing Then
            播放器.当前播放时间_百分比 = e.X / PictureBox1.Width
        End If
    End Sub

    Private Sub PictureBox2_MouseUp(sender As Object, e As MouseEventArgs) Handles PictureBox2.MouseUp

        Dim X As Integer = Int(e.X / (PictureBox2.Width / 3))
        Dim Y As Integer = Int(e.Y / 当前绘制高度)
        Dim INDEX = X + Y * 3
        If INDEX < 播放器.歌词.Count Then
            播放器.当前播放时间_秒 = 播放器.歌词(INDEX).歌词时间_秒
            播放器.播放音乐()
        End If
    End Sub

    Private Sub ListView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListView1.SelectedIndexChanged

        If ListView1.SelectedItems.Count >= 1 Then
                If 播放器 IsNot Nothing Then
                    播放器.close()
                    播放器 = Nothing
                End If
                播放器 = New 歌曲(ListView1.SelectedItems(0).Tag)
                播放器.播放音乐()

                If 播放器.是否有歌词 = True Then
                    当前绘制高度 = PictureBox2.Height / (播放器.歌词.Count / 3 + 1)

                End If

            End If

    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Try
            If ListView1.SelectedItems.Count >= 1 Then
                If ListView1.SelectedItems(0).Index >= 1 Then
                    Dim ID = ListView1.SelectedItems(0).Index - 1
                    ListView1.SelectedItems.Clear()
                    ListView1.Items(ID).Selected = True
                    ListView1.Focus()
                End If

            End If

        Catch ex As Exception

        End Try
    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        'Try
        If ListView1.SelectedItems.Count >= 1 Then
            If ListView1.SelectedItems(0).Index < ListView1.Items.Count - 1 Then
                Dim ID = ListView1.SelectedItems(0).Index + 1
                ListView1.SelectedItems.Clear()
                ListView1.Items(ID).Selected = True
                ListView1.Focus()
            End If

        End If

        '  Catch ex As Exception

        ' End Try
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Try

            If 播放器.播放状态 = 歌曲.播放.停止 Or 播放器.播放状态 = 歌曲.播放.暂停 Then
                Button1.Text = "暂停"
                播放器.播放状态 = 歌曲.播放.播放
            ElseIf 播放器.播放状态 = 歌曲.播放.播放 Then
                Button1.Text = "播放"
                播放器.播放状态 = 歌曲.播放.暂停

            End If

        Catch ex As Exception

        End Try
    End Sub
End Class


 

Imports System.IO
Imports NAudio
Imports NAudio.Wave

Public Class 歌曲
    Private 随机数 As Random
    Private 文件流 As WaveStream
    Private 播放组件 As IWavePlayer
    Public 路径 As String
    Public 路径_lrc As String
    Public 是否有歌词 As Boolean = False
    Public 歌曲名 As String
    Public 歌曲类型 As String
    Public 歌词 As New List(Of 单条歌词)
    Public 歌曲长度_秒 As Double
    Public Sub close()
        播放组件.Dispose()
        文件流.Dispose()
    End Sub
    Public Sub New(歌曲路径 As String)
        文件流 = New MediaFoundationReader(歌曲路径)
        播放组件 = New WaveOut()
        播放组件.Init(文件流)
        歌曲长度_秒 = TimeSpan转秒(文件流.TotalTime)
        路径 = 歌曲路径
        歌曲名 = Path.GetFileNameWithoutExtension(路径)
        歌曲类型 = Path.GetExtension(路径)
        随机数 = New Random
        解析歌词()

    End Sub

    Private Sub 解析歌词()
        Dim 路径_lrc = $"{ Path.GetDirectoryName(路径)}\{Path.GetFileNameWithoutExtension(路径)}.lrc"
        If System.IO.File.Exists(路径_lrc) = False Then
            是否有歌词 = False
            Exit Sub
        End If
        是否有歌词 = True
        Dim STR = IO.File.ReadAllText(路径_lrc)
        Dim arr = Split(STR, vbLf)
        For Each ss In arr
            '  Try
            If InStr(ss, "[") > 0 And InStr(ss, "]") > 0 And InStr(ss, ":") > 0 Then
                    Dim 时间 = Split(ss, "]")(0)
                    Dim 歌词_ = Split(ss, "]")(1)
                    If 歌词_.Length >= 1 Then
                        歌词.Add(New 单条歌词(时间, 歌词_, Color.FromArgb(随机数.Next(200, 255), 随机数.Next(200, 255), 随机数.Next(200, 255))))
                    End If
                End If
            '  Catch ex As Exception

            ' End Try
        Next
    End Sub



    Public Structure 单条歌词
        Public 歌词文本 As String
        Public 歌词时间_秒 As Double
        Public 歌词时间_分秒格式 As String
        Public 颜色 As Color

        Sub New(歌词时间 As String, 歌词_文本 As String, colors As Color)
            歌词文本 = 歌词_文本
            Dim str = 歌词时间
            str = str.Replace("[", "")
            str = str.Replace("]", "")
            Try
                Dim 分 = Split(str, ":")(0)
                Dim 秒 = Double.Parse(Split(str, ":")(1))
                歌词时间_秒 = 秒 + 分 * 60
                歌词时间_分秒格式 = $"{分}:{Int(秒)}"
                颜色 = colors
            Catch ex As Exception

            End Try

        End Sub
    End Structure
    Public Sub 播放音乐()
        播放组件.Play()
    End Sub
    Public Sub 暂停音乐()
        播放组件.Pause()
    End Sub
    Public Sub 停止音乐()
        播放组件.Stop()
        当前播放时间_百分比 = 0
    End Sub

    Public Property 当前播放时间_百分比() As Double
        Get
            Return 当前播放时间_秒 / 歌曲长度_秒
        End Get
        Set(ByVal value As Double)
            文件流.Position = value * 文件流.Length
        End Set
    End Property
    Public Shared Function TimeSpan转秒(T As TimeSpan) As Double
        Return T.Minutes * 60 + T.Seconds + T.Milliseconds / 1000
    End Function
    Public Shared Function 秒转时分格式(s As Double) As String
        Return Strings.Right("0" & Int(s / 60), 2) & ":" & Strings.Right("0" & Int(s Mod 60), 2)
    End Function

    Public ReadOnly Property 当前播放时间_时分格式() As String
        Get
            Return 秒转时分格式(TimeSpan转秒(文件流.CurrentTime))
        End Get
    End Property
    Public ReadOnly Property 歌曲长度_时分格式() As String
        Get
            Return 秒转时分格式(歌曲长度_秒)
        End Get
    End Property


    Public Property 当前播放时间_秒() As Double
        Get
            Return TimeSpan转秒(文件流.CurrentTime)
        End Get
        Set(ByVal value As Double)
            文件流.Position = (value / 歌曲长度_秒) * 文件流.Length
        End Set
    End Property

    Public Property 播放状态() As 播放
        Get
            If 播放组件.PlaybackState = PlaybackState.Playing Then Return 播放.播放
            If 播放组件.PlaybackState = PlaybackState.Paused Then Return 播放.暂停
            If 播放组件.PlaybackState = PlaybackState.Stopped Then Return 播放.停止
        End Get
        Set(ByVal value As 播放)
            If value = 播放.播放 Then 播放音乐()
            If value = 播放.暂停 Then 暂停音乐()
            If value = 播放.停止 Then 停止音乐()
        End Set
    End Property

    Public Enum 播放
        停止 = 0
        播放 = 1
        暂停 = 2
    End Enum


End Class

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!