Imports System.IO
Imports NAudio.Wave
Imports NAudio.Wave.SampleProviders
Imports System.Threading.Tasks

Public Class frmMusic
    ' Define fields for audio processing
    Private ReadOnly projectDir As String = GetProjectDirectory()
    Private ReadOnly musicFolder As String = Path.Combine(projectDir, "Data", "Music")
    Private ReadOnly IconsFolder As String = Path.Combine(projectDir, "Data", "Icons")

    Private waveOut As WaveOutEvent
    Private audioFileReader As AudioFileReader
    Private sampleChannel As SampleChannel

    ' Properties to return volume and gain levels
    Public Property AudioFile As String
    Public Property VolumeLevel As Integer
    Public Property GainLevel As Integer

    ' Fields for the moving line
    Private playbackTimer As New Timer()
    Private currentPosition As Double = 0
    Private totalDuration As Double = 0
    Private ReadOnly darkGreenPen As New Pen(Color.DarkGreen, 2)

    Private isPlaying As Boolean = False
    Private isRepeating As Boolean = False
    Private Function GetProjectDirectory() As String
        Dim dir As DirectoryInfo = New DirectoryInfo(Application.StartupPath)
        For i As Integer = 1 To 4
            If dir.Parent IsNot Nothing Then
                dir = dir.Parent
            End If
        Next
        Return dir.FullName
    End Function
    Private Sub frmMusic_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        btnPlayPause.Image = Image.FromFile(Path.Combine(IconsFolder, "Play.png"))

        ' Disable the "new row" at the bottom and allow a vertical scrollbar
        dgSound.AllowUserToAddRows = False
        dgSound.ScrollBars = ScrollBars.Vertical

        ' Initialize DataGridView columns
        dgSound.Columns.Clear()
        dgSound.Columns.Add("Filename", "Filename")
        dgSound.Columns.Add("Length", "Length")
        dgSound.Columns.Add("Type", "Type")

        ' Calculate the total available width for columns (account for vertical scrollbar width)
        Dim scrollbarWidth As Integer = SystemInformation.VerticalScrollBarWidth
        Dim availableWidth As Integer = dgSound.ClientSize.Width - scrollbarWidth

        ' Set column widths based on desired percentages
        dgSound.Columns("Filename").Width = CInt(availableWidth * 0.6)
        dgSound.Columns("Length").Width = CInt(availableWidth * 0.2)
        dgSound.Columns("Type").Width = CInt(availableWidth * 0.2)
        dgSound.RowTemplate.Height = 20
        dgSound.AllowUserToResizeRows = False

        ' Load music files into DataGridView
        LoadMusicFiles()

        ' Set up other controls
        TBVolume.Minimum = 0
        TBVolume.Maximum = 100
        TBVolume.Value = 50

        TBGain.Minimum = 0
        TBGain.Maximum = 30
        TBGain.Value = 10

        UpdateVolumeLabel()
        UpdateGainLabel()

        DrawCenterLine() ' Initialize with a center line

        playbackTimer.Interval = 500 ' Update every 500ms
        AddHandler playbackTimer.Tick, AddressOf PlaybackTimer_Tick

    End Sub
    Private Sub btnPlay_Click(sender As Object, e As EventArgs)
        ' Implement play functionality
    End Sub

    Private Sub btnPause_Click(sender As Object, e As EventArgs)
        ' Implement pause functionality
    End Sub

    Private Sub btnStop_Click(sender As Object, e As EventArgs)
        ' Implement stop functionality
    End Sub

    Private Sub LoadMusicFiles()
        Dim allowedExtensions As String() = {".mp3", ".wav"}
        dgSound.Rows.Clear()

        If Directory.Exists(musicFolder) Then
            Dim musicFiles = Directory.GetFiles(musicFolder)
            For Each file In musicFiles
                If allowedExtensions.Contains(Path.GetExtension(file).ToLower()) Then
                    Dim fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file)
                    Dim fileType = Path.GetExtension(file).Replace(".", "").ToUpper()

                    Using reader As New AudioFileReader(file)
                        Dim duration As String = $"{reader.TotalTime.Minutes:D2}:{reader.TotalTime.Seconds:D2}"
                        dgSound.Rows.Add(fileNameWithoutExtension, duration, fileType)
                    End Using
                End If
            Next
        Else
            MessageBox.Show("Music folder doesn't exist.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End If
    End Sub

    Private Sub dgSound_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles dgSound.CellClick
        If e.RowIndex >= 0 AndAlso e.RowIndex < dgSound.Rows.Count Then
            Dim selectedRow = dgSound.Rows(e.RowIndex)
            Dim fileNameWithoutExtension = selectedRow.Cells("Filename").Value.ToString()
            Dim fileType = selectedRow.Cells("Type").Value.ToString().ToLower()

            ' Call the method with the correct parameters
            LoadAndPlayAudio(fileNameWithoutExtension, fileType)
        End If
    End Sub

    Private Sub LoadAndPlayAudio(selectedFileName As String, fileType As String)
        playbackTimer.Stop()

        Try
            ' Ensure previous audio resources are disposed of safely
            If waveOut IsNot Nothing Then
                RemoveHandler waveOut.PlaybackStopped, AddressOf WaveOut_PlaybackStopped
                waveOut.Stop()
                waveOut.Dispose()
                waveOut = Nothing
            End If

            If audioFileReader IsNot Nothing Then
                audioFileReader.Dispose()
                audioFileReader = Nothing
            End If

            ' Construct the complete file path
            Dim completeFilePath As String = Path.Combine(musicFolder, selectedFileName & "." & fileType)

            If File.Exists(completeFilePath) Then
                audioFileReader = New AudioFileReader(completeFilePath)
                sampleChannel = New SampleChannel(audioFileReader, True)

                ' Apply gain
                Dim gainMultiplier As Single = TBGain.Value / 10.0F
                sampleChannel.Volume = gainMultiplier

                ' Initialize and start playback
                waveOut = New WaveOutEvent()
                waveOut.Init(New SampleToWaveProvider(sampleChannel))
                waveOut.Volume = TBVolume.Value / 100.0F

                totalDuration = audioFileReader.TotalTime.TotalSeconds
                currentPosition = 0 ' Reset

                ' Draw initial waveform
                DrawWaveform(completeFilePath, gainMultiplier)
                AudioFile = selectedFileName & "." & fileType

                AddHandler waveOut.PlaybackStopped, AddressOf WaveOut_PlaybackStopped

                waveOut.Play()
                playbackTimer.Start()
            Else
                MessageBox.Show("Selected audio file not found.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
                DrawCenterLine()
            End If
        Catch ex As Exception
            MessageBox.Show($"Error loading audio: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub
    ' Ensure only one version of this method exists
    Private Sub WaveOut_PlaybackStopped(sender As Object, e As StoppedEventArgs)
        If Not Me.IsDisposed AndAlso audioFileReader IsNot Nothing Then
            ' Check if track finished playing
            If Math.Abs(audioFileReader.CurrentTime.TotalSeconds - audioFileReader.TotalTime.TotalSeconds) < 0.1 Then
                currentPosition = totalDuration
                playbackTimer.Stop()
            End If

            ' Handle repeating logic
            If isRepeating AndAlso waveOut IsNot Nothing Then
                audioFileReader.CurrentTime = TimeSpan.Zero
                waveOut.Play()
            End If
        End If
    End Sub
    Private Sub TBVolume_Scroll(sender As Object, e As EventArgs) Handles TBVolume.Scroll
        If waveOut IsNot Nothing Then
            waveOut.Volume = TBVolume.Value / 100.0F
        End If
        UpdateVolumeLabel()
    End Sub

    Private Sub TBGain_Scroll(sender As Object, e As EventArgs) Handles TBGain.Scroll
        If sampleChannel IsNot Nothing Then
            Dim gainMultiplier As Single = TBGain.Value / 10.0F
            sampleChannel.Volume = gainMultiplier
            DrawWaveform(Path.Combine(musicFolder, AudioFile), gainMultiplier)
        End If
        UpdateGainLabel()
    End Sub

    Private Sub UpdateVolumeLabel()
        lblVolume.Text = "Volume: " & TBVolume.Value
    End Sub

    Private Sub UpdateGainLabel()
        lblGain.Text = "Gain: " & TBGain.Value
    End Sub

    Private Async Sub DrawWaveform(filePath As String, gainMultiplier As Single)
        If Not Me.IsHandleCreated OrElse picWav.IsDisposed OrElse picWav.Width = 0 OrElse picWav.Height = 0 Then Exit Sub

        Await Task.Run(Sub()
                           Try
                               Using reader As New AudioFileReader(filePath)
                                   Dim buffer As Single() = New Single(16383) {}
                                   Dim allSamples As New List(Of Single)()
                                   Dim samplesRead As Integer

                                   Do
                                       samplesRead = reader.Read(buffer, 0, buffer.Length)
                                       allSamples.AddRange(buffer.Take(samplesRead))
                                   Loop While samplesRead > 0

                                   Dim bmp As New Bitmap(picWav.Width, picWav.Height)
                                   Using g As Graphics = Graphics.FromImage(bmp)
                                       g.Clear(Color.Black)
                                       Dim midY As Integer = picWav.Height \ 2
                                       Dim samplesPerPixel As Integer = Math.Max(1, allSamples.Count \ (picWav.Width * reader.WaveFormat.Channels))

                                       For x As Integer = 0 To picWav.Width - 1
                                           Dim startIndex As Integer = x * samplesPerPixel * reader.WaveFormat.Channels
                                           Dim maxAmplitude As Single = allSamples.Skip(startIndex).Take(samplesPerPixel).Max(Function(s) Math.Abs(s))
                                           maxAmplitude *= gainMultiplier
                                           maxAmplitude = Math.Min(maxAmplitude, 1.0F)

                                           Dim amplitudeHeight As Integer = CInt(maxAmplitude * picWav.Height / 2)
                                           g.DrawLine(Pens.White, x, midY - amplitudeHeight, x, midY + amplitudeHeight)
                                       Next
                                   End Using

                                   If Me.IsHandleCreated Then
                                       Me.Invoke(Sub()
                                                     If Not picWav.IsDisposed Then
                                                         picWav.Image?.Dispose()
                                                         picWav.Image = bmp
                                                     End If
                                                 End Sub)
                                   End If
                               End Using
                           Catch ex As Exception
                               Console.WriteLine($"Drawing waveform error: {ex.Message}")
                           End Try
                       End Sub)
    End Sub


    Private Sub DrawCenterLine()
        If picWav.Width = 0 OrElse picWav.Height = 0 Then Exit Sub

        Dim bmp As New Bitmap(picWav.Width, picWav.Height)
        Using g As Graphics = Graphics.FromImage(bmp)
            g.Clear(Color.Black)
            Dim midY As Integer = picWav.Height / 2
            g.DrawLine(Pens.White, 0, midY, picWav.Width, midY)
        End Using
        picWav.Image = bmp
    End Sub

    Private Sub frmMusic_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
        ' Stop timer and clean up resources
        playbackTimer.Stop()
        RemoveHandler playbackTimer.Tick, AddressOf PlaybackTimer_Tick

        Try
            If waveOut IsNot Nothing Then
                RemoveHandler waveOut.PlaybackStopped, AddressOf WaveOut_PlaybackStopped
                waveOut.Stop()
                waveOut.Dispose()
                waveOut = Nothing
            End If

            If audioFileReader IsNot Nothing Then
                audioFileReader.Dispose()
                audioFileReader = Nothing
            End If
        Catch ex As Exception
            Console.WriteLine($"Error during form closing: {ex.Message}")
        End Try
    End Sub
    Private Sub UpdateTimerLabel()
        If audioFileReader IsNot Nothing Then
            Dim elapsed As TimeSpan = audioFileReader.CurrentTime
            Dim total As TimeSpan = audioFileReader.TotalTime
            lblTimer.Text = String.Format("{0:D2}:{1:D2} / {2:D2}:{3:D2}", elapsed.Minutes, elapsed.Seconds, total.Minutes, total.Seconds)
        Else
            lblTimer.Text = "00:00 / 00:00"
        End If
    End Sub

    Private Sub PlaybackTimer_Tick(sender As Object, e As EventArgs)
        If audioFileReader IsNot Nothing AndAlso waveOut IsNot Nothing AndAlso waveOut.PlaybackState = PlaybackState.Playing Then
            currentPosition = audioFileReader.CurrentTime.TotalSeconds
            UpdateTimerLabel()

            ' Ensure the form and controls are still valid
            If Me.IsHandleCreated Then
                Me.Invoke(Sub() DrawWaveform(Path.Combine(musicFolder, AudioFile), TBGain.Value / 10.0F))
            End If
        End If
    End Sub
    Private Sub picWav_MouseDown(sender As Object, e As MouseEventArgs) Handles picWav.MouseDown
        ' Ensure audio is loaded and playing
        If audioFileReader Is Nothing OrElse waveOut Is Nothing Then Exit Sub

        ' Calculate the new position based on the click
        Dim newPositionRatio As Double = e.X / picWav.Width
        newPositionRatio = Math.Max(0, Math.Min(newPositionRatio, 1)) ' Clamp between 0 and 1
        currentPosition = totalDuration * newPositionRatio

        ' Set the audio playback position
        audioFileReader.CurrentTime = TimeSpan.FromSeconds(currentPosition)

        ' Redraw the waveform with the new position
        If Not String.IsNullOrEmpty(AudioFile) Then
            DrawWaveform(Path.Combine(musicFolder, AudioFile), TBGain.Value / 10.0F)
        End If

        ' Ensure the playback timer continues
        playbackTimer.Start()

        ' Restart playback from the new position
        If waveOut.PlaybackState <> PlaybackState.Playing Then
            waveOut.Play()
        End If
    End Sub

    Private Sub btnStop_MouseEnter(sender As Object, e As EventArgs) Handles btnStop.MouseEnter, btnPlayPause.MouseEnter, btnRepeat.MouseEnter
        Dim btn As PictureBox = CType(sender, PictureBox)
        btn.BackColor = Color.LightGray
        If btn Is btnRepeat And isRepeating Then Exit Sub

        btn.BorderStyle = BorderStyle.FixedSingle
    End Sub

    Private Sub frmMusic_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
        btnStop.BackColor = DefaultBackColor
        btnStop.BorderStyle = BorderStyle.None
        If isRepeating = False Then
            btnRepeat.BackColor = DefaultBackColor
            btnRepeat.BorderStyle = BorderStyle.None
        Else
            btnRepeat.BackColor = Color.LightGreen
        End If
        btnPlayPause.BackColor = DefaultBackColor
        btnPlayPause.BorderStyle = BorderStyle.None
    End Sub

    Private Sub btnRepeat_Click(sender As Object, e As EventArgs) Handles btnRepeat.Click
        If isRepeating Then
            isRepeating = False
            btnRepeat.BackColor = Color.LightGray
            btnRepeat.BorderStyle = BorderStyle.FixedSingle
        Else
            isRepeating = True
            btnRepeat.BackColor = Color.LightGreen
            btnRepeat.BorderStyle = BorderStyle.Fixed3D
        End If
    End Sub

    Private Sub btnPlayPause_Click(sender As Object, e As EventArgs) Handles btnPlayPause.Click
        If isPlaying Then
            isPlaying = False
            btnPlayPause.Image = Image.FromFile(Path.Combine(IconsFolder, "Play.png"))
        Else
            isPlaying = True
            btnPlayPause.Image = Image.FromFile(Path.Combine(IconsFolder, "Pause.png"))
        End If
    End Sub
End Class

Hi there! as you can see, i've added the code to animate the buttons on mouseover, mouseleave and click. Can you add the code to make them play, stop, pause, repeat the playing music