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.
-
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!
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!
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.IOThese imports bring in necessary namespaces for:
System.Runtime.InteropServices: For interacting with unmanaged code.System.Text: For using theStringBuilderclass.System.IO: For file input and output operations.
Public Structure AudioPlayerThis line defines a Structure named AudioPlayer. Structures in are value types that can contain data and methods.
<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 FunctionThis 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.
Private Sounds() As StringThis declares an array named Sounds to store the names of sounds that have been added.
Public Function AddSound(SoundName As String, FilePath As String) As BooleanThis 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) ThenChecks 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 SoundAliaswould fail. - With quotes:
open "C:\My Files\file.wav" alias SoundAliasworks properly.
If Sounds Is Nothing ThenChecks if the Sounds array is uninitialized.
If SendMciCommand(CommandOpen, IntPtr.Zero) ThenSends the command to open the sound file.
ReDim Sounds(0)
Sounds(0) = SoundName
Return TrueInitializes the Sounds array with the new sound and returns True.
ElseIf Not Sounds.Contains(SoundName) ThenChecks if the sound is not already in the array.
Array.Resize(Sounds, Sounds.Length + 1)
Sounds(Sounds.Length - 1) = SoundName
Return TrueAdds the new sound to the Sounds array and returns True.
Debug.Print($"{SoundName} not added to sounds.")
Return FalsePrints a debug message and returns False if the sound could not be added.
Public Function SetVolume(SoundName As String, Level As Integer) As BooleanThis 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 ThenChecks 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 FalsePrints a debug message and returns False if the volume could not be set.
Public Function LoopSound(SoundName As String) As BooleanThis method loops a sound. It takes the sound name as a parameter.
If Sounds IsNot Nothing AndAlso Sounds.Contains(SoundName) ThenChecks 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 FalsePrints a debug message and returns False if the sound could not be looped.
Public Function PlaySound(SoundName As String) As BooleanThis method plays a sound. It takes the sound name as a parameter.
If Sounds IsNot Nothing AndAlso Sounds.Contains(SoundName) ThenChecks 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 FalsePrints a debug message and returns False if the sound could not be played.
Public Function PauseSound(SoundName As String) As BooleanThis method pauses a sound. It takes the sound name as a parameter.
If Sounds IsNot Nothing AndAlso Sounds.Contains(SoundName) ThenChecks 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 FalsePrints a debug message and returns False if the sound could not be paused.
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)
NextLoops through a set of suffixes (A to L) and adds each sound instance with a unique name.
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
NextLoops through the set of suffixes and plays the first sound instance that is not already playing.
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)
NextLoops through the set of suffixes and sets the volume for each sound instance.
Private Function SendMciCommand(command As String, hwndCallback As IntPtr) As BooleanThis 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 TryHere, 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.
Private Function GetStatus(SoundName As String, StatusType As String) As StringThis 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 IfChecks 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.EmptyIf an exception occurs, the error is printed, and an empty string is returned.
Public Function IsPlaying(SoundName As String) As BooleanThis 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.
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
Soundsarray is not empty: This prevents any errors that might occur ifSoundsisNothing(ornull) before attempting to loop through it. - Loops through each sound and sends a command to close it: This ensures that every sound in the
Soundsarray is properly closed using theSendMciCommandmethod. Sounds = Nothing: This line sets theSoundsarray toNothing(ornull). 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.
Public Class Form1This class defines a form in a Windows Forms application.
Private Player As AudioPlayerThis declares an instance of the AudioPlayer structure.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.LoadThis method handles the form's Load event.
Text = "Audio Playback - Code with Joe"Sets the form's title.
CreateSoundFiles()Calls the CreateSoundFiles method to create the necessary sound files from embedded resources.
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.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Player.PlayOverlapping("CashCollected")
End SubThis method handles the Click event for Button1. It plays an overlapping instance of the "CashCollected" sound.
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 SubThis method handles the Click event for Button2. It toggles between playing and pausing the "Music" sound and updates the button text accordingly.
Private Sub Form1_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
Player.CloseSounds()
End SubThis method handles the form's Closing event. It closes all sound files to release resources.
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 SubThis method creates sound files from embedded resources. It specifies the file paths and calls CreateFileFromResource to write the resource data to the file system.
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.
To add a resource file to your Visual Studio project, follow these steps:
- Add a New Resource File:
- From the Project menu, select
Add New Item.... - In the dialog that appears, choose
Resource Filefrom the list of templates. - Name your resource file (e.g.,
Resource1.resx) and clickAdd.
- From the Project menu, select
- Open the Resource Editor:
- Double-click the newly created
.resxfile to open the resource editor.
- Double-click the newly created
- 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.
- In the resource editor, click on the Green Plus Sign or right-click in the resource pane and select
-
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.
-
Accessing the Resource in Code:
- You can access the added resource in your code using the following syntax:
CreateFileFromResource(filePath, YourProjectNamespace.Resource1.YourResourceName)
- You can access the added resource in your code using the following syntax:
-
Save Changes:
- Don’t forget to save your changes to the
.resxfile.
- Don’t forget to save your changes to the
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.
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!






