Blind Geeks dot org
Basic Audio Programming
Part I: Playing Audio
Chapter 2: High-Level MCI Audio
DISCLAIMER:
This lesson series is intended for experienced
computer programming professionals.
Please read the following before continuing.
√ It is assumed
that student has had courses or lessons in at least one computer language.
√ While languages
such as Visual Basic, C#, Flex and Actionscript are
demonstrated in this series, this is not a series intructing
the student in programming in these languages.
This is a series in Audio Programming.
√
Part 1 – The Visuals.
In Chapter 1, we learned how to use MCI to play low-level audio (wave files). In this chapter, we use MCI again but a higher level method called mciSendString. mciSendString is a very powerful but under-documented MCI technology. And, some of it no longer works under Windows Vista and Windows 7, so you have to test your project thoroughly before releasing it.
Unlike the MCI low-level approach from Chapter 1, mciSendString can play MP3 files or even video files (*.avi). We won’t be dealing with video in this series but MCI does have that capability.
Basically, when you call the mciSendString method, you give it a command like open “c:\mySong.mp3” type mpegvideo alias mySong
In the command above, even though we are not playing a video but an MP3 file, we must specify type mpegvideo if we are playing an MP3 file. The file name must be surrounded by quotes as well, which can be tricky in Visual Basic. I will show you how to do this once we start programming.
In this chapter, we will build a pretty sophisticated D.J. package using MCI and mciSendString.
I will show you how to build a user control, which will be our playback “deck” and then to build an application where we use four different instances of this deck control.
1.
Open Visual Studio
2010.
2.
Create a new Visual
Basic Windows Forms Control Library project named BGMCI_Deck.
3.
Open Solution
Explorer.
4.
Rename
UserControl1.vb to BGMCI_Deck.vb.
5.
When prompted to
rename all references, activate the Yes button.
6.
Open BGMCI_Deck in the designer.
7.
Open the Properties
Window.
8.
Set the size property
for BGMCI_Deck to 484, 187.
9.
Save your work.
To make it easier for us to do this chapter, I have created
a form with all of the controls we will be using in this chapter. This form is on the web site named
BGAudioChap2_Start.zip. Download and
unzip this file then load it in a separate instance of Visual Studio. When it is loaded, open the form and use Control+A, Control+C to copy all
of the controls to the clipboard. Then,
navigate to the form we created in the steps above and press Control+V to paste all of the controls that I created for
you into our new user control form.
Visual Components
I’ve prepared a user interface for the playback deck we
will be using in this chapter that resembles a radio station “cart machine”
which looks similar to an 8-track tape player of the 1970’s. Cart machines were used in the radio industry
from the 1960’s through the 1990’s.
These were used primarily for playing commercials but some radio
stations that could afford the $5 per tape cost used them for music as well.
Several years ago, I hired an artist to create images of
radio equipment for one of my applications intended for the radio
industry. Among the images was one which
resembled the cart tape used in radio. I’ve
provided this image for the playback deck for this chapter. The tape image appears when a song is loaded
and disappears when there is no song loaded on the deck. This is done by using a Picture Box control.
Later, in this series, I will be using a Flash animation as
the playback deck and the application will communicate with the Flash SWF
Object through ActiveX communications to tell the SWF object when to begin the
animation, pass song information and when to stop.
Control Functionality
Just as we did in chapter 1, we will now add the control
functionality before we put in the code to do the audio.
Adding code to a user control is no different than adding
code to a normal Windows form. Simply
open the form in code view.
|
Procedure
Name |
|
LoadSong |
|
PlaySong |
|
StopSong |
|
PauseSong |
|
DisplayStatus |
|
CloseSong |
Dim strFile
As String = ""
Dim res As DialogResult
res = ofdLoadSong.ShowDialog()
If res = Windows.Forms.DialogResult.OK
Then
' load
song
If InStr(ofdLoadSong.FileName,
".wav") > 0 Then
' wave
file
bWaveFile = True
Else
' mp3
file
bWaveFile = False
End If
strFile = ofdLoadSong.FileName
Else
Exit Sub
End If
btnPlay.Enabled
= True
btnPlay.BackColor
= Color.Green
btnPlay.ForeColor
= Color.White
btnPause.Enabled
= False
btnStop.Enabled
= False
scrVolume.Value
= scrVolume.Minimum
scrVolume.Refresh()
imgCart.Visible
= True
lblSongStatus.Text
= "Loaded."
lblRemTitle.Visible
= True
lblLenTitle.Visible
= True
lblSongInfo.Visible
= True
scrVolume.Enabled
= True
If btnPlay.Enabled Then
btnPlay.Enabled
= False
btnPlay.ForeColor
= Color.LightSteelBlue
btnPlay.BackColor
= Color.Lime
btnPause.Enabled
= True
btnPause.ForeColor
= Color.Black
btnPause.BackColor
= Color.Gold
btnStop.Enabled
= True
btnStop.ForeColor
= Color.White
btnStop.BackColor
= Color.DarkRed
lblSongStatus.Text
= "Playing."
End If
If btnStop.Enabled Then
btnPlay.Enabled
= True
btnPlay.ForeColor
= Color.White
btnPlay.BackColor
= Color.DarkGreen
btnPause.Enabled = False
btnStop.Enabled
= False
btnStop.BackColor
= Color.Red
lblPosition.Text
= " 0:00"
lblSongStatus.Text
= "Stopped."
End If
If btnPause.BackColor = Color.Gold Then
' Pause
btnPlay.Enabled
= False
btnPlay.ForeColor
= Color.White
btnPlay.BackColor
= Color.DarkGreen
btnPause.Enabled
= True
btnPause.BackColor
= Color.Yellow
btnPause.ForeColor
= Color.Navy
btnStop.Enabled
= True
lblSongStatus.Text
= "Paused."
Else
' Resume
btnPlay.Enabled
= False
btnPlay.ForeColor
= Color.Black
btnPlay.BackColor
= Color.Lime
btnPause.Enabled
= True
btnPause.ForeColor
= Color.Black
btnPause.BackColor
= Color.Gold
btnStop.Enabled
= True
lblSongStatus.Text
= "Playing."
End If
StopSong()
btnPlay.Enabled
= False
btnPause.Enabled
= False
btnStop.Enabled
= False
btnLoad.Enabled
= True
imgCart.Visible = False
lblSongStatus.Text
= ""
lblLength.Text
= ""
lblPosition.Text
= ""
lblRemTitle.Visible
= False
lblLenTitle.Visible
= False
lblSongInfo.Text
= ""
lblSongInfo.Visible
= False
scrVolume.Enabled = False
scrVolume.Value
= scrVolume.Maximum
scrVolume.Enabled
= False
Part 2, Section 1
– Simple Audio Playback Functionality
The first thing we need to do to get the audio
functionality integrated into our project is to declare the Win32 MCI API.
Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpszCommand As String, ByVal lpszReturnString As String, ByVal
cchReturn As Integer, ByVal
hwndCallback As Integer) As Integer
MCI’s native programming language is C++. So, to use the MCI methods in languages such
as Visual Basic and C#, we need to declare these functions providing the DLL
name they are embedded in and the correct parameters for the method. That is what we are doing in line 3 above.
Now, we need to add a private variable and a public
property to use as an ‘Alias’ to identify the song to the MCI API.
The beginning of the class now looks like this:
Public Class BGMCI_Deck
Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpszCommand As String, ByVal lpszReturnString As String, ByVal
cchReturn As Integer, ByVal
hwndCallback As Integer) As Integer
Private bWaveFile As Boolean = False
' === Audio Code
===
Private strAlias As String = ""
' Properties
' === Audio Code
===
Public Property songAlias() As String
Get
songAlias = strAlias
End Get
Set(ByVal value As String)
strAlias = value
End Set
End Property
Now that we have some data elements to hold the song
information to send to the API, we can add some actual functionality.
We will build functionality to:
Load Song
We will now add code to the end of the LoadSong
procedure.
' === Audio
Code ===
' if running
control in debugger set Alias
If strAlias =
"" Then
strAlias = "Song"
End If
' close open
streams
mciSendString("close " & strAlias,
Nothing, 0, 0)
' open new
file
mciSendString("open " & Chr(34)
& strFile & Chr(34)
& " type mpegvideo alias " & strAlias, "", 0, 0)
The code above does the following.
To open and close Wave or MP3 files, we use the mciSendString function which is part of the MCI API. You could also use this function to load
videos but we will only work with audio in this series.
mciSendString()
is a very powerful function but sadly, it was poorly documented and replaced by
other technologies. The parameter
strings need to be formatted exactly or you may get an error. Debugging such errors is very time-consuming
due to the poor documentation on its use and error codes and the fact that this
technology is now considered obsolete.
Some of the features offered with mciSendString()
that once worked flawlessly under operating systems prior to Windows Vista now
either give obscure errors or just appear not to function at all. Once such feature is the
song length parameter. I spent
literally hours trying to resolve this before determining that this feature was
not supported in Vista and later operating systems.
Getting the song’s ID3 tag is also mot supported under
newer versions of Windows. I had to use
a tag class I had previously developed for another application.
Notice in the code we just entered that we send the “open”
command to the API using the mciSendString
function. This only opens the audio
file. It does not play the audio.
Lets examine the command we are sending to the API.
open “filename.mp3” type mpegvideo
alias Song
The above line represents the command we send in the first
parameter of mciSendString. Notice that I placed double quotes around the
file name of the audio file. THIS IS
REQUIRED. In VB, this is either done
like this:
“open “ & chr(34) & “filename.mp3” & chr(34)
Or, like this:
“open “”filename.mp3”””
The type keyword
is required for all file type except wave audio. The command for a wave file can be:
Open “”filename.wav”” alias WaveSong
As previously discussed, the alias keyword can be used to refer to an audio file instead of
referring to it by the path but is not required. The following are examples of using the close command using an alias and using
the path.
Open “”c:\music\wavefile.wav”” alias WaveSong
Close WaveSong
Open “”c:\music\wavefile.wav””
Close “”c:\music\wavefile.wav””
To play the audio, we will need to issue the play command
to the API, which we will do as part of the PlaySong
procedure. But, for now, we can test
that the song was opened by adding the following lines of code after the last
line we just entered:
If mciSendString("play " & strAlias,
"", 0, 0) <> 0 Then
MessageBox.Show("Error
Playing Song...")
Application.Exit()
End If
Now, save the project and press F5 to
test it. In Visual Studio 2010, the user control test
container will appear. Navigate to the
load song button and select an MP3 file.
After you activate the OK button of the Open File dialog, the audio
should begin playing.
After you’ve tested to be sure it works properly, close the
user control test container, return to code view and remove (or comment) the
lines that play the audio.
Close Song
I’ve already shown you the code that closes a song that has
previously been opened. This command was
sent to mciSendString() prior to opening the song in LoadSong. We will use this command in the CloseSong procedure.
'
=== Audio Code ===
mciSendString("close " & strAlias,
Nothing, 0, 0)
Play Song
As we’ve already seen the command to play a song, there
isn’t much to discuss here other than that it is always proper coding practice
to place the mciSendString call inside of a Try…Catch
block.
Try
If mciSendString("play " & strAlias,
"", 0, 0) <> 0 Then
MessageBox.Show("Error Playing Song...")
Application.Exit()
End If
Catch ex As Exception
MessageBox.Show("Error Playing Song.")
Application.Exit()
End Try
One thing that you will notice is that after the song plays
and you click Play again, nothing appears to happen.
Normally, there is an event that you would look for that
tells you when the file has finished playing.
This event no longer works in MCI with operating systems after Windows
XP.
Instead, later in this chapter, we will obtain the song
length information and use a Timer object to know when the song has finished
and set the buttons accordingly.
In most cases, you will want the play head of the player to
start at the beginning of the song but there are some instances where you might
wish to start a song at some other point.
For example, if there is a large amount of silence at the beginning of
the file, you may want to start the song at one second into the file which is
the standard silence for CD cuts. In
this instance, the play command will look like this:
Play Song From 1000
The above command plays the file referred to by the alias
Song starting from 1000 milliseconds (1 second) into the file. The following command plays a song until its
30 second location:
Play Song To 30000
The following command plays a song from 1 second into the
file and ends 30 seconds into the file, playing for exactly 29 seconds:
Play Song From 1000 To
30000
Real_World Application of this? In Radio, it is
called cue-points. Radio software these
days can detect the when the audio begins and when it fades inside an audio
file. Back when I was a professional in
radio in the 1980s, we used to “cue up” a vinyl record. We will not get as sophisticated as that in
this series. However, if you listen to
the beginning and ending of the song then note when the audio begins and when
it ends, you can save that information to an XML file so that you can have your
application perform cross-fading. In the
days of vinyl records and magnetic tapes, the radio station (usually the
Program Director) would type this information on a label which was physically
placed on the record or tape for the announcer to see.
Stop Song
To stop audio that is currently playing, you issue the stop
command but it does not close the audio file.
It simply stops the audio from playing.
The interesting thing is that the stop command actually acts like a
pause command, in which it stops the audio and leaves the audio play head at
the last place it was. To make it
function like a real stop command, we then issue a seek command and tell it to go to position 0 (remember, positions
by default are in milliseconds).
' === audio Code ===
mciSendString("stop
" & strAlias, "", 0, 0)
'Seek to position 0
mciSendString("seek
" & strAlias & " to 0",
"", 0, 0)
If you were using the cue points method I suggested above,
the seek point would be where the audio starts in the song. For example, the audio starts at 0.2 seconds
into the file. The seek command would
be:
Seek Song to 200
We will play with this a little before the end of the
chapter.
Pause Song
You can probably guess how to create the pause and resume
functionality based on what I said in the Stop Song section. You would be correct. You simply use the stop command without using
the seek command afterwards. You would
then send a play command to resume the audio playback.
' == Audio Code ==
mciSendString("stop
" & strAlias, "", 0, 0)
' == Audio code ==
mciSendString("play
" & strAlias, "", 0, 0)
If all you wanted from this chapter was how to load, play,
pause and stop audio files; you are not interested in distributing this
application to other people; are not concerned about obtaining and using song
information such as artist, title and song length and are not interested in
learning how to control the volume of the audio or allowing the user to place
the play head as the song plays, feel free to skip ahead to Section 3 where we
build the application that uses this control.
However, if you want to build a professional application
that has some pretty sophisticated features, keep reading on.
Part 2, Section 2
– Intermediate Audio Playback Functionality
In this section, we are going to obtain and display
information about the song as well as some intermediate features such as
controlling the volume of the play back deck and adding tracking features to
the deck to allow the user to specify where the play back head goes.
Obtaining & Displaying Song Playback Status
To obtain the song playback status information (mode), we
use the status command of the mciSendString function.
The command is as follows:
Status Song mode
Unlike the playback commands we used in section 1, this
command requires the name of a buffer to place the status information
into. So, we pass mciSendString() the name of
a string variable instead of Null as the second parameter. The VB call looks like this:
mciSendStatus(“status
Song mode”,strMode,128,0)
The first parameter is the status command. The second parameter is the name of the
string variable to place the information into.
This must be a space-filled variable.
The third parameter is the length of the buffer and the fourth variable
is a call-back function. We place a zero
in this parameter if there is no callback function.
To implement this command, we will use a timer control that
is already part of the project named tmStatus.
DisplayStatus()
Dim strMode As String = Space(128)
mciSendString("status
" & strAlias & " mode", strMode, 128, 0)
lblSongStatus.Text = strMode.Trim
Select
Case Microsoft.VisualBasic.Left(strMode.Trim(), 7)
Case "stopped"
If btnPause.Enabled Or
btnStop.Enabled = False Then
lblSongStatus.Text = "Stopped."
StopSong()
Exit Sub
Else
lblSongStatus.Text = "Paused."
End If
Case "playing"
lblSongStatus.Text = "Playing."
Case Else
lblSongStatus.Text = "Loaded..."
End
Select
' == Song Status ==
tmStatus.Enabled = True
tmStatus.Start()
' == Song
Status ==
tmStatus.Enabled = False
tmStatus.Stop()
' == Song Status ==
tmStatus.Enabled = True
tmStatus.Start()
' == Song Status ==
tmStatus.Enabled = False
tmStatus.Stop()
The code above does the following:
This code handles when a song is at the end of the file by
calling StopSong, which places the playback head at
the beginning and sets the button states correctly.
Test the application to make sure it works properly and
that the song can be played again after it is over.
Obtaining & Displaying Song Time Information
When I first began this series, I had started on this
chapter first and had begun using status mode command to retrieve the song length. It worked very well in Windows XP but when I
was about to finish the work, I tested it on Vista and was horrified by the
problems I discovered and the fact that status is useless for anything except
playback mode.
So, I had to find other ways to obtain and use song
information. In 2004, I developed two
modules in VB for getting the header and ID3 tag information from MP3
files. It was originally written in VB6
and I converted it to VB.NET.
It wasn’t until I had the Blind Geeks moderator, Jeff Durham, go through this chapter that we discovered that the
code did not work in all instances. It
worked great for MP3 files that had a constant bit rate (CBR) but didn’t work
for variable bit rate (VBR). So, we had
to abandon the use of this code.
Instead of spending the time required to modify the code I
had written, I found an open source library named UltraID3Lib. I’ve included this library in the start
project downloaded from the web site. We
are going to use this library to obtain MP3 Song information.
Imports ID3Tag =
HundredMilesSoftware.UltraID3Lib
' ===
Song Time Info
Private intRemaining = 0 'MilliSeconds Remaining
Private intSongLength = 0
Private MP3ID3Tag As ID3Tag.UltraID3
If
MP3ID3Tag.FirstMPEGFrameInfo.VBRInfo.WasFound Then
Return
MP3ID3Tag.FirstMPEGFrameInfo.Duration.TotalSeconds * 1000
Else
Return MP3ID3Tag.Duration.TotalSeconds
* 1000
End If
Dim retVal As String = ""
Dim intSeconds As Integer = 0
Dim intMinutes As Integer = 0
Dim intHours As Integer = 0
Dim intMilli As Integer = 0
intHours = (intMilliseconds
/ 1000) / 60 / 24 ' To get Hours
intMinutes = (intMilliseconds
/ 1000) / 60 'To get Minutes
intSeconds = Int(Str(intMilliseconds / 1000).Trim)
Dim iSecs As Integer = intSeconds Mod
60
Dim iMins As Integer = Int(Str(intSeconds
/ 60).Trim)
retVal = IIf(iMins < 10, " " & iMins,
iMins) & ":" & IIf(iSecs < 10, "0" & iSecs,
iSecs)
Return Microsoft.VisualBasic.Left(retVal, 5)
' === Song Time Info ===
MP3ID3Tag = New
ID3Tag.UltraID3
MP3ID3Tag.Read(strFile)
In the code above, we instantiate a new MP3ID3Tag object which will hold all of
the information about the MP3 file such as bit rate, frequency, duration,
genre, etc. We then open the MP3 file
and load the information into MP3ID3Tag.
' === Song Time Info ===
Dim strLength As String = Space(128)
strLength = GetSongLength()
intSongLength = Int(strLength)
intRemaining = intSongLength
' display initial values
lblLength.Text = GetTimeFormat(strLength).Trim
lblPosition.Text = lblLength.Text
In the code above, we create a string buffer and assign it
value of the space character (“ “), which is how we
prepare it to use with the mp3Info module.
We then call the method GetSongLength() and assign the return value to strLength. We
convert this value to type integer and assign it to int
variables we will use as counters.
Now, we display these values.
' == Song Time Info ===
tmRemaining.Enabled = True
tmRemaining.Start()
' === Song Time Info ===
tmRemaining.Stop()
tmRemaining.Enabled = False
' === Song Time Info ===
tmRemaining.Start()
tmRemaining.Enabled
= True
' === Song Time Info ===
tmRemaining.Stop()
tmRemaining.Enabled = False
intRemaining = intSongLength
lblPosition.Text = GetTimeFormat(intRemaining)
'
=== Song Time Info ===
If intRemaining > 0 Then
intRemaining -= 1000
lblPosition.Text = GetTimeFormat(intRemaining)
Else
intRemaining = 0
lblPosition.Text = " 0:00"
End If
Obtaining & Displaying Song ID3 Tag Information
lblSongInfo.Text
= MP3ID3Tag.Artist & " --- " & MP3ID3Tag.Title
lblLength.Text
= GetTimeFormat(GetSongLength()).Trim
intSongLength
= Int(GetSongLength())
'
=== Song ID3 Tag ===
DisplayID3TagInfo(strFile)
Controlling The Volume Using A
Scrollbar
The TAB key does work in this application and the TAB key
does land on the scroll bar for the volume.
You must use the left/right arrows to change the value of the volume
scroll bar, not the up/down keys. It is
possible that JAWS will not speak when you land on the volume scroll bar. I combat this in our main application that we
will build later in this chapter by creating a menu strip then placing a menu
item for Volume on the menu strip, assigning a shortcut (F7) to the volume menu
item then setting the volume scroll bar focus in the click event handler for
the menu item. I will demonstrate this
before finishing this section.
Note: The volume
scroll bar is verticle. Due to this, the keys used to adjust volume
are reversed. The LEFT arrow key turns
the volume high and the RIGHT arrow key lowers the volume.
Now, let’s make the volume scroll bar work.
Dim intValue As UInteger = IIf(scrVolume.Value < 0, scrVolume.Value
* -1, 0)
If intValue = 100 Then
intValue = 0
End If
If intValue > 0 Then
mciSendString("setaudio " & strAlias
& " volume to " & Str(intValue).Trim, Nothing, 255, 0)
Else
mciSendString("setaudio " & strAlias
& " volume to 0", Nothing, 255, 0)
End If
If JAWS does not speak when it lands on the volume scroll
bar, do the following:
scrVolume.Focus()
Before going on to Part 2 of this chapter, you will need to
delete the menu strip so it does not conflict with the menu strip that will be
built in Part 2.
Tracking & Setting The Playhead Using The Click Event of A Scrollbar
In professional audio software, the user is given the
ability to track and set the play head’s position. There are better looking controls for doing
this but the goal in this series is to create an accessible application that
has powerful features so we will use the horizontal scroll bar control for
getting and setting the play head’s position.
When the song loads, we will set the minimum, maximum and
value properties of the scroll bar.
While the song is playing, we will adjust the value and when the song
stops, we will reset the value to zero.
'
=== Song Tracking ===
scrSongProgress.Minimum = 0
scrSongProgress.Value = 0
scrSongProgress.Maximum = intSongLength
'
=== Song Tracking ===
If scrSongProgress.Value < scrSongProgress.Maximum
Then
Try
scrSongProgress.Value += 1000
Catch ex As
Exception
scrSongProgress.Value = scrSongProgress.Maximum
End Try
Else
scrSongProgress.Value = scrSongProgress.Maximum
End If
Add the following code to StopSong() (at the bottom of
the IF block):
'=== Song Tracking ===
scrSongProgress.Value = 0
Now, to allow the user to specify the position of the play
head, we use the scroll event handler of scrSongProgress.
Add the following code to this event handler after creating
it:
'
=== Set Song Position ===
If InStr(lblSongStatus.Text, "Play") > -1 Then
mciSendString("play
" & strAlias & " from " & scrSongProgress.Value, "", 0, 0)
intRemaining = intSongLength
- scrSongProgress.Value
Else
scrSongProgress.Value
= 0
intRemaining = intSongLength
scrSongProgress.Refresh()
End If
For the most part, we are finished with the user control
piece.
We now need to prepare it to be used from an application.
In the next section, we will use the DLL for this control
which we just built (located in bin\release folder) in Release mode.
Part 3 – Putting
It All Together
The first thing we will do is build the main application
project that will serve as our DJ application.
|
Property Name |
Value |
|
Size |
1048, 488 |
|
BackColor |
Navy |
|
ForeColor |
White |
|
Text |
Blind Geeks Basic Audio Programming MCI DJ System |
Addng The
BGMCI_Deck
Control
|
Deck: |
Location: |
|
Deck1 |
16, 61 |
|
Deck2 |
532, 61 |
|
Deck3 |
16, 251 |
|
Deck4 |
532, 251 |
|
Property |
Value |
|
BackColor |
Control |
|
ForeColor |
ControlText |
|
Size |
484, 185 |
Now, your solution should compile and run but if you
attempt to load audio files into two of the decks, the decks will only play the
last audio file loaded. Ooops.
To resolve this, we need to add some code.
We need to add a public write-only property to BGMCI_Deck.vb. Yje property will look like this:
Public WriteOnly Property DeckTitle() As String
Set(ByVal value As String)
lblDeck.Text = value
End Set
End Property
This property sets the label text of the deck label.
Now, add the following code to the Load Event handler of BGMCI_DJ.frmMain.vb:
Deck1.songAlias =
"Deck1"
Deck1.deckTitle =
"Deck #1"
Deck2.songAlias =
"Deck2"
Deck2.deckTitle =
"Deck #2"
Deck3.songAlias =
"Deck3"
Deck3.deckTitle =
"Deck #3"
Deck4.songAlias =
"Deck4"
Deck4.deckTitle =
"Deck #4"
Save your work.
The code above set the default values for the properties DeckTitle and SongLias.
Now, if you were to compile and run the program, the
problem mentioned above is resolved.
Building The Menu & Shortcuts
A trick I picked up in 2004 when in MCSD training was the
use of menu items to assign shortcut keys to buttons and other controls,
outside of the Alt+ key strokes.
Basically, you will set a menu item group then assign
shortcuts to menu items underneath for whatever control or function/procedure
you want executed. Then, before
releasing the application, you set the visible property for that menu item
group to false.
For the functionality we want added to our applications, we
don’t need to set the menu item group visible property to false. But, this is an
technique you can use in your applications.
We will be working with frmMain.vb
in the designer now.
|
Menu Strip Item
Name |
Text Property |
|
mnuFile |
&File |
|
mnuDeck1 |
Deck &1 |
|
mnuDeck2 |
Deck &2 |
|
mnuDeck3 |
Deck &3 |
|
mnuDeck4 |
Deck &4 |
|
mnuMixer |
&Mixer |
|
Menu Item Name |
Text Property |
Shortcut Deck1 |
Shortcut Deck2 |
Shortcut Deck3 |
Shortcut Deck4 |
|
mnuLoadDeck# |
Load |
F2 |
Shift+F2 |
Cntrl+F2 |
Alt+F2 |
|
mnuPlayDeck# |
Play |
F3 |
Shift+F3 |
Cntrl+F3 |
Alt+F3 |
|
mnuPauseDeck# |
Pause |
F4 |
Shift+F4 |
Cntrl+F4 |
Alt+F4 |
|
mnuStopDeck# |
Stop |
F5 |
Shift+F5 |
Cntrl+F5 |
Alt+F5 |
|
mnuEjectDeck# |
Eject |
F6 |
Shift+F6 |
Cntrl+F6 |
Alt+F6 |
Private Sub mnuLoadDeck#_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles mnuLoadDeck#.Click
Deck#.LoadSong()
End Sub
Private Sub mnuPlayDeck#_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles mnuPlayDeck#.Click
Deck#.PlaySong()
End Sub
Private Sub mnuPauseDeck#_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles mnuPauseDeck#.Click
Deck#.PauseSong()
End Sub
Private Sub mnuStopDeck#_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles mnuStopDeck#.Click
Deck#.StopSong()
End Sub
Private Sub mnuEjectDeck#_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles mnuEjectDeck#.Click
Deck#.CloseSong()
End Sub
'
Close all open playback devices
Deck1.CloseSong()
Deck2.CloseSong()
Deck3.CloseSong()
Deck4.CloseSong()
Application.Exit()
We’ve come to the end of Chapter 2 of the Basic Audio Programming
course. I will be adding an addendum to
this chapter later, as time permits which will include the following advanced
topics:
In Chapter 3 of the Basic Audio course, we will be learning
basic audio programming with Windows Media.
Chapter 3 won’t be as comprehensive as the last two chapters have been.