Skip to content

Latest commit

 

History

History
817 lines (472 loc) · 20.7 KB

README.md

File metadata and controls

817 lines (472 loc) · 20.7 KB

Audio Playback

Welcome to Audio Playback, a dynamic and versatile tool crafted for seamless audio management using the Windows Multimedia API. This application is packed with features that make it an essential asset for developers and audio enthusiasts alike.

005

Key Features:

  • Simultaneous Playback: Unlock the full potential of the Windows Multimedia API by playing multiple audio files at the same time. This feature allows you to create rich, immersive audio experiences that captivate your audience.

  • Precision Volume Control: Tailor the volume levels of individual audio tracks with precision. This ensures that you achieve the perfect audio balance tailored to your unique requirements.

  • Looping and Overlapping: Effortlessly loop audio tracks and play overlapping sounds. This enables you to craft captivating and dynamic audio compositions that enhance your projects.

  • MCI Integration: Harness the power of the Media Control Interface (MCI) to interact with multimedia devices. This provides a standardized and platform-independent approach to controlling multimedia hardware, making your development process smoother.

  • User-Friendly Interface: Enjoy a clean and intuitive interface designed to simplify the management of audio playback operations. This makes it easy for users of all skill levels to navigate and utilize the application effectively.

With its robust functionality and seamless integration with the Windows Multimedia API, the Audio Playback application empowers you to create engaging multimedia applications effortlessly. Whether you’re a seasoned developer or an aspiring enthusiast, this tool is your gateway to unlocking the full potential of audio playback on the Windows platform.

Clone the repository now and embark on a transformative audio playback journey! Let's dive into the world of audio together!


Code Walkthrough

Welcome to this detailed walkthrough of the AudioPlayer structure and the Form1 class! We'll go through each line of code and explain its purpose. Let's dive in!

Index


Imports

Imports System.Runtime.InteropServices
Imports System.Text
Imports System.IO

These imports bring in necessary namespaces for:

  • System.Runtime.InteropServices: For interacting with unmanaged code.
  • System.Text: For using the StringBuilder class.
  • System.IO: For file input and output operations.

Index


AudioPlayer Structure

Public Structure AudioPlayer

This line defines a Structure named AudioPlayer. Structures in are value types that can contain data and methods.

DLL Import

<DllImport("winmm.dll", EntryPoint:="mciSendStringW")>
Private Shared Function mciSendStringW(<MarshalAs(UnmanagedType.LPWStr)> ByVal lpszCommand As String,
                                       <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszReturnString As StringBuilder,
                                       ByVal cchReturn As UInteger, ByVal hwndCallback As IntPtr) As Integer
End Function

This imports the mciSendStringW function from the winmm.dll library. This function sends a command string to the Media Control Interface (MCI) to control multimedia devices.

Index


Adding Sounds

Sounds Array

Private Sounds() As String

This declares an array named Sounds to store the names of sounds that have been added.

AddSound Method

Public Function AddSound(SoundName As String, FilePath As String) As Boolean

This method adds a sound to the player. It takes the name of the sound and the path to the sound file as parameters.

If Not String.IsNullOrWhiteSpace(SoundName) AndAlso IO.File.Exists(FilePath) Then

Checks if the sound name is not empty or whitespace and if the file exists.

Dim CommandOpen As String = $"open ""{FilePath}"" alias {SoundName}"

Creates a command string to open the sound file and assign it an alias.

The double quotes "" around {FilePath} are needed because file paths in commands can contain spaces. If a file path includes spaces, the command might not interpret it correctly unless it's enclosed in quotes. For example, C:\My Files\file.wav would be misinterpreted without quotes.

Enclosing the file path in double quotes ensures that the entire path is treated as a single string, even if it contains spaces. This way, the command parser correctly recognizes it as the full path to the file.

Here's a simple example:

  • Without quotes: open C:\My Files\file.wav alias SoundAlias would fail.
  • With quotes: open "C:\My Files\file.wav" alias SoundAlias works properly.
If Sounds Is Nothing Then

Checks if the Sounds array is uninitialized.

If SendMciCommand(CommandOpen, IntPtr.Zero) Then

Sends the command to open the sound file.

ReDim Sounds(0)
Sounds(0) = SoundName
Return True

Initializes the Sounds array with the new sound and returns True.

ElseIf Not Sounds.Contains(SoundName) Then

Checks if the sound is not already in the array.

Array.Resize(Sounds, Sounds.Length + 1)
Sounds(Sounds.Length - 1) = SoundName
Return True

Adds the new sound to the Sounds array and returns True.

Debug.Print($"{SoundName} not added to sounds.")
Return False

Prints a debug message and returns False if the sound could not be added.

Index


Setting Volume

SetVolume Method

Public Function SetVolume(SoundName As String, Level As Integer) As Boolean

This method sets the volume of a sound. It takes the sound name and volume level (0 to 1000) as parameters.

If Sounds IsNot Nothing AndAlso
   Sounds.Contains(SoundName) AndAlso
   Level >= 0 AndAlso Level <= 1000 Then

Checks if the Sounds array is not empty, contains the sound, and the volume level is valid.

Dim CommandVolume As String = $"setaudio {SoundName} volume to {Level}"
Return SendMciCommand(CommandVolume, IntPtr.Zero)

Creates and sends the command to set the volume.

Debug.Print($"{SoundName} volume not set.")
Return False

Prints a debug message and returns False if the volume could not be set.

Index


Looping Sounds

LoopSound Method

Public Function LoopSound(SoundName As String) As Boolean

This method loops a sound. It takes the sound name as a parameter.

If Sounds IsNot Nothing AndAlso Sounds.Contains(SoundName) Then

Checks if the Sounds array is not empty and contains the sound.

Dim CommandSeekToStart As String = $"seek {SoundName} to start"
Dim CommandPlayRepeat As String = $"play {SoundName} repeat"
Return SendMciCommand(CommandSeekToStart, IntPtr.Zero) AndAlso
       SendMciCommand(CommandPlayRepeat, IntPtr.Zero)

Creates and sends commands to seek to the start of the sound and play it in a loop.

Debug.Print(Debug.Print($"{SoundName} not looping.")
Return False

Prints a debug message and returns False if the sound could not be looped.

Index


Playing Sounds

PlaySound Method

Public Function PlaySound(SoundName As String) As Boolean

This method plays a sound. It takes the sound name as a parameter.

If Sounds IsNot Nothing AndAlso Sounds.Contains(SoundName) Then

Checks if the Sounds array is not empty and contains the sound.

Dim CommandSeekToStart As String = $"seek {SoundName} to start"
Dim CommandPlay As String = $"play {SoundName} notify"
Return SendMciCommand(CommandSeekToStart, IntPtr.Zero) AndAlso
 SendMciCommand(CommandPlay, IntPtr.Zero)

Creates and sends commands to seek to the start of the sound and play it.

Debug.Print($"{SoundName} not playing.")
Return False

Prints a debug message and returns False if the sound could not be played.

Index


Pausing Sounds

PauseSound Method

Public Function PauseSound(SoundName As String) As Boolean

This method pauses a sound. It takes the sound name as a parameter.

If Sounds IsNot Nothing AndAlso Sounds.Contains(SoundName) Then

Checks if the Sounds array is not empty and contains the sound.

Dim CommandPause As String = $"pause {SoundName} notify"
Return SendMciCommand(CommandPause, IntPtr.Zero)

Creates and sends the command to pause the sound.

Debug.Print($"{SoundName} not paused.")
Return False

Prints a debug message and returns False if the sound could not be paused.

Index

Index


Managing Overlapping Sounds

AddOverlapping Method

Public Sub AddOverlapping(SoundName As String, FilePath As String)

This method adds multiple overlapping instances of a sound. It takes the sound name and file path as parameters.

For Each Suffix As String In {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"}
    AddSound(SoundName & Suffix, FilePath)
Next

Loops through a set of suffixes (A to L) and adds each sound instance with a unique name.

Index

PlayOverlapping Method

Public Sub PlayOverlapping(SoundName As String)

This method plays one instance of an overlapping sound. It takes the sound name as a parameter.

For Each Suffix As String In {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"}
    If Not IsPlaying(SoundName & Suffix) Then
        PlaySound(SoundName & Suffix)
        Exit Sub
    End If
Next

Loops through the set of suffixes and plays the first sound instance that is not already playing.

Index

SetVolumeOverlapping Method

Public Sub SetVolumeOverlapping(SoundName As String, Level As Integer)

This method sets the volume for all instances of an overlapping sound. It takes the sound name and volume level as parameters.

For Each Suffix As String In {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"}
    SetVolume(SoundName & Suffix, Level)
Next

Loops through the set of suffixes and sets the volume for each sound instance.

Index


Sending MCI Commands

SendMciCommand Method

Private Function SendMciCommand(command As String, hwndCallback As IntPtr) As Boolean

This method sends an MCI command. It takes the command string and a window handle for the callback as parameters.

Dim ReturnString As New StringBuilder(128)
Try
    Return mciSendStringW(command, ReturnString, 0, hwndCallback) = 0
Catch ex As Exception
    Debug.Print($"Error sending MCI command: {command} | {ex.Message}")
    Return False
End Try

Here, the mciSendStringW function is called with the command string. If the function returns 0, it means the command was successfully sent. If an exception occurs, the error is printed, and the method returns False.

Index


Getting Sound Status

GetStatus Method

Private Function GetStatus(SoundName As String, StatusType As String) As String

This method gets the status of a sound. It takes the sound name and the status type (e.g., "mode") as parameters and returns the status as a string.

If Sounds IsNot Nothing AndAlso Sounds.Contains(SoundName) Then
    Dim CommandStatus As String = $"status {SoundName} {StatusType}"
    Dim StatusReturn As New StringBuilder(128)
    mciSendStringW(CommandStatus, StatusReturn, 128, IntPtr.Zero)
    Return StatusReturn.ToString.Trim.ToLower
End If

Checks if the Sounds array is not empty and contains the sound. Creates and sends the command to get the status, stores the result in StatusReturn, and returns the status as a trimmed, lowercase string.

Catch ex As Exception
    Debug.Print($"Error getting status: {SoundName} | {ex.Message}")
End Try
Return String.Empty

If an exception occurs, the error is printed, and an empty string is returned.

IsPlaying Method

Public Function IsPlaying(SoundName As String) As Boolean

This method checks if a sound is playing. It takes the sound name as a parameter and returns a Boolean.

Return GetStatus(SoundName, "mode") = "playing"

Uses the GetStatus method to check if the sound is currently playing.

Index


Closing Sounds

CloseSounds Method

Public Sub CloseSounds()

    If Sounds IsNot Nothing Then

        For Each Sound In Sounds

            Dim CommandClose As String = $"close {Sound}"

            SendMciCommand(CommandClose, IntPtr.Zero)

        Next

        Sounds = Nothing

    End If

End Sub
  • Checks if the Sounds array is not empty: This prevents any errors that might occur if Sounds is Nothing (or null) before attempting to loop through it.
  • Loops through each sound and sends a command to close it: This ensures that every sound in the Sounds array is properly closed using the SendMciCommand method.
  • Sounds = Nothing: This line sets the Sounds array to Nothing (or null). This effectively clears the reference to the array, making sure that all resources associated with the sounds are released, and it prevents further usage of the array without reinitialization.

By setting Sounds to Nothing, you are cleaning up and ensuring there are no lingering references to the sounds array, which can help with garbage collection and resource management in your application.

Index


Form Class and Event Handlers

Form1 Class

Public Class Form1

This class defines a form in a Windows Forms application.

Player Declaration

Private Player As AudioPlayer

This declares an instance of the AudioPlayer structure.

Form Load Event

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

This method handles the form's Load event.

Text = "Audio Playback - Code with Joe"

Sets the form's title.

CreateSoundFiles Method

CreateSoundFiles()

Calls the CreateSoundFiles method to create the necessary sound files from embedded resources.

Adding and Setting Up Sounds

Dim FilePath As String = Path.Combine(Application.StartupPath, "level.mp3")
Player.AddSound("Music", FilePath)
Player.SetVolume("Music", 600)
FilePath = Path.Combine(Application.StartupPath, "CashCollected.mp3")
Player.AddOverlapping("CashCollected", FilePath)
Player.SetVolumeOverlapping("CashCollected", 900)
Player.LoopSound("Music")
Debug.Print($"Running... {Now}")

Sets up the sound files by specifying their file paths, adding them to the player, setting their volume, and starting to loop the "Music" sound. It prints a debug message indicating the form is running.

Button1 Click Event

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Player.PlayOverlapping("CashCollected")
End Sub

This method handles the Click event for Button1. It plays an overlapping instance of the "CashCollected" sound.

Button2 Click Event

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If Player.IsPlaying("Music") = True Then
    Player.PauseSound("Music")
    Button2.Text = "Play Loop"
Else
    Player.LoopSound("Music")
    Button2.Text = "Pause Loop"
End If
End Sub

This method handles the Click event for Button2. It toggles between playing and pausing the "Music" sound and updates the button text accordingly.

Form Closing Event

Private Sub Form1_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
Player.CloseSounds()
End Sub

This method handles the form's Closing event. It closes all sound files to release resources.

Index


Creating Sound Files

CreateSoundFiles Method

Private Sub CreateSoundFiles()
    Dim FilePath As String = Path.Combine(Application.StartupPath, "level.mp3")
    CreateFileFromResource(FilePath, My.Resources.level)
    FilePath = Path.Combine(Application.StartupPath, "CashCollected.mp3")
    CreateFileFromResource(FilePath, My.Resources.CashCollected)
End Sub

This method creates sound files from embedded resources. It specifies the file paths and calls CreateFileFromResource to write the resource data to the file system.

CreateFileFromResource Method

Private Sub CreateFileFromResource(filepath As String, resource As Byte())

    Try

        If Not IO.File.Exists(filepath) Then

            IO.File.WriteAllBytes(filepath, resource)

        End If

    Catch ex As Exception

        Debug.Print($"Error creating file: {ex.Message}")

    End Try

End Sub

This method writes resource data to a file if it does not already exist. It handles exceptions by printing an error message.

Index


Adding Resources

To add a resource file to your Visual Studio project, follow these steps:

  1. Add a New Resource File:
    • From the Project menu, select Add New Item....
    • In the dialog that appears, choose Resource File from the list of templates.
    • Name your resource file (e.g., Resource1.resx) and click Add.

010

006

  1. Open the Resource Editor:
    • Double-click the newly created .resx file to open the resource editor.

009

  1. Add Existing Files:
    • In the resource editor, click on the Green Plus Sign or right-click in the resource pane and select Add Resource.
    • Choose Add Existing File... from the context menu.
    • Navigate to the location of the MP3 file (or any other resource file) you want to add, select it, and click Open.

011

  1. Verify the Addition:

    • Ensure that your MP3 file appears in the list of resources in the resource editor. It should now be accessible via the Resource class in your code.
  2. Accessing the Resource in Code:

    • You can access the added resource in your code using the following syntax:
      CreateFileFromResource(filePath, YourProjectNamespace.Resource1.YourResourceName)
  3. Save Changes:

    • Don’t forget to save your changes to the .resx file.

012

By following these steps, you can easily add any existing MP3 file or other resources to your Visual Studio project and utilize them within your Audio Playback application.

Index


Related Projects

If you're interested in exploring a similar project, check out Audio Playback C#, which is a port of this project. You can find the C# version in its repository: Audio Playback C# Repository.

For more information about the original project, visit the Audio Playback Repository.

Happy coding!

013


Index

Adding Sounds

Setting Volume

Looping Sounds

Playing Sounds

Pausing Sounds

Managing Overlapping Sounds

Sending MCI Commands

Getting Sound Status

Closing Sounds

Form Class and Event Handlers

Creating Sound Files

Adding Resources