Blind Geeks dot org
Basic Audio Programming
Part I: Playing Audio
DISCLAIMER:
This lesson series is intended for experienced
computer programming professionals.
Please read the following before continuing.
√ It is assumed
that student has successfully completed 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 instructing the student in
programming in these languages. This is
a series in Audio Programming.
Introduction:
For
about 5 years, I have been planning on doing an audio programming tutorial
since audio is my real love (don’t tell my wife please).
When
I was only 10 years old, I decided to become a radio announcer when I grew
up. I still haven’t grown up but when I
was 11 years old, I pieced together a “studio” from two old record players, a
1955 RCA amplifier, a reel to reel deck which my blind mother got for listening
to book from the school for the blind and a 1945 RCA microphone that the radio
station a mile away from my home threw in their dumpster one night.
I
lived in a town named Three Rivers in
At
age 15, I became a professional radio announcer when I was hired at WAOP-FM in
By
the age of 20, I was one of
By
age 25, I had left the radio business all together
but still had music and radio in my blood.
Later,
computers became a way that I could mix my passion for music, radio and
computers into one. While in college, I
developed a radio music rotation system in IBM Basic that we used at the radio
station I worked at, WABB-AM. Then in
1988, I had helped a friend of mine develop a music rotation system (play list)
for professional radio written in Pascal.
In 1990, that system was used by more than 35 radio stations in the
In
2005, I went to work for an audio software company where I helped develop
modifications to an application called The
Singulator.
My
passion for audio continued after leaving this position and continues today. I take great joy in offering this series on
Audio Programming. I hope you enjoy it
as much as I enjoyed doing it.
1.
The History of
Digital Audio.
In 1981, the concept of
automating audio playback at a radio station consisted of two to four reel to
reel decks for music playback, two to four machines called Cart Carousels
for commercial (spots) and
jingle/promotion playback and a main “brain” which was very simplistic compared
to even the computers of the mid-1980’s.
This entire system took up
the entire wall of a radio station control room. The programming of this monster was done
solely in a sequence of numbers which were actual decimal. After the “programmer” typed in these numbers
and pressed the ENTER key, the computer translated these numbers into binary.
These numbers were generated
by a computer company based on the sequence of the playback device and were
sent to the radio station in a folder each time a new reel tape was sent. This usually happened once per week.
The “programmer” was actually
a radio station employee who did not really write any code at all but merely
input these numbers into the computer.
I became one of these
programmers after working at the radio station for a few months. The AM station, WOAM-AM was automated using
this computer from sunrise to sunset then the FM Station,
WAOP-FM used the automation system from 7pm to 6am.
I learned how to program the
automation system to play the music sequentially or to play certain cuts from a
reel tape.
At the end of each song on
the reel tape was an inaudible tone that the computer detected and interpreted
to trigger the start of the next reel deck or cart deck, depending on whether
music would be played next or if it were time for a commercial or jingle to
play. These were called Events. If you do any type of programming today, you
recognize this word from programming.
In 1983, when I worked at a
small town radio station that had a 3,000 watt FM and a small 250 watt AM
station in
That was when I yearned for a
way to develop a way to automate a station myself. In the 1990s, I started developing a system
which used a series of CD decks but technology moved faster than I could.
By 1997, radio stations began
using personal computers for on-air playback using a system called Audio Vault
which played Wave files stored on the computer’s hard drive. With smaller hard drives and speed issues back
then, the bigger and faster hard drives called SCSI (pronounced Scuzzy) were
very expensive so only bigger radio stations could afford these systems. To give you an example, the average 4 minute
song took up about 45 megabytes of disk space.
The biggest hard drive that they had back then was about 60 gig in size, so about 150 songs could fit on one hard drive. Usually, the system had 1 to 3 SCSI drives
chained to a single controller. The more
expensive systems had up to 6 hard drives.
Around the year 2000, the
MPEG-2 Layer III audio format (MP3) became popular but it took a year or so for
radio stations to adopt this format due to radio and music industry audio
“experts” complaining that the quality of the MP3 format was not good enough
for on-air use.
The radio station owners and
management won this argument because the MP3 format was much cheaper to use in
systems than the current WAVE format and less expensive systems could be put
into place instead of the expensive SCSI systems. With the MP3 format, more files could be stored
and played on IDE hard drives with no performance issues and they were much
cheaper.
In about 1998, CD burners
became popular and consumers began buying them and dubbing their old records
and tapes onto the computer then burning them to CD. The format used at the time was Wave but that
changed when MP3 became popular. Shortly
after, CD burners allowed you to store up to 100 songs in MP3 format on a CD
and play back on consumer CD decks.
In 1999, online music sharing
sites such as Napster, allowed computer users to connect to one another and
share their MP3 files. When the record
industry made Napster go under, ten more such sites sprung up overnight. Now, there are pay subscription services such
as iTunes, BearShare and others that either allow you to pay a monthly subscription fee or pay a small
fee per download. The MP3 file format is
still the favored after 10 years even though formats such as Ogg have become popular over the years.
For the purposes of this
series, we will be using the Wave and MP3 formats. All music files including with the examples
projects have been recorded in low quality formats to avoid prosecution from
various organizations. You are free to
record and use your own music files to use in these examples.
We are going to introduce
audio technology in this series from the past to the present in that
order. We will begin with Windows
Application Audio programming then go to Web Application Audio Programming then
end with an advanced audio application.
We start by showing how to play audio in this part of the series.
Section 1: Windows
Application Audio Programming
2.
Low-Level MCI
Audio.
MCI stands for Media Control
Interface and is founded on the C++ language but we will use C# to demonstrate
playing Wave files and Visual Basic (Using Visual Studio 2010) to do our
demonstration of playing MP3 files in this chapter.
In this chapter, we will
write a small Windows application in C# to demonstrate playing wave files using
the low-level MCI technology. We will
then write a pretty sophisticated Visual Basic application that is a mock Radio
Station DJ program to demonstrate playing MP3 files with the high-level mciSendString command.
If you do not have Visual
Studio 2010, this code should work in Visual Studio 2008 as well.
Low-Level MCI Playback
Technology
The native digital audio
format is the raw or Wave data format.
When audio CDs are ripped, the audio is taken from the CD and placed
into this Wave format. It is a very high
quality format but takes up much disk space.
The Windows operating system
uses the wave format for its Windows Sounds.
So does many computer games even today.
MCI was founded using the
Visual C++ language and many of the existing MCI code is done in C++. However, over the years, developers have
translated the C++ definitions and code to C#, VB and even Java. But, as time goes by and the technology is
replaced by newer technology, it is getting harder to find sample code or any
help from forums or even from Microsoft.
Microsoft officially no longer supports the MCI technology as they
replaced it with DirectX.
In 2005, I helped develop and
support upgrades to a C++ application called Singulator that was written using
low-level MCI. That program was
originally written in 1998 and has now faded and is no longer supported by the
company full-time. I haven’t worked with
this company since 2008 but my name is still listed on the web page for support
contact. This is an example of how the
MCI technology has lost ground to the point where companies no longer support
their MCI products.
This is caused mostly by the
Wave format no longer being used and the audio system overhaul that Microsoft
did when they developed
During the development of the
sample project for this chapter, I had issues with Windows Vista. Unfortunately, I did not discover this until
I was almost finished with the project.
So, this made me have to re-think a few areas of the demonstration
project. One method, in particular, for
getting the song length caused run-time errors under
There are two ways to play
audio in MCI.
1.
Low-Level process
using WaveOut methods.
2.
High-Level
process using the mciSendString method.
The low-level WaveOut process can only natively play wave files. It is possible to play other audio formats
but you must first build methods to decode the audio from that format and place
it into the wave format before calling the methods to play the audio. With newer technologies available that allow
you to do the same thing with less work, using low-level MCI to play other
formats just doesn’t seem feasible unless you needed to process the audio in
some way.
For the purposes of this
first demonstration, we are going to write a very simple application that loads
and plays a wave file. The application
will be simple but once you see how much code it takes to do this, it may not
seem so simple after all. That is why we
won’t be spending much time on low-level MCI audio.
Project Setup & Visuals
1.
Start Visual
Studio 2010.
2.
Create a new C#
Windows Forms Project named BGLowLevelMCI.
3.
When the project
loads, open Solution Explorer and rename Form1.cs to Main.cs.
4.
When prompted to
rename all references, activate the Yes button.
5.
Open Main.cs in Design View.
Just a note
about visuals here. We are about to design our player form. I’ve already designed it for you but will
instruct you on making some visual improvements to the normal bland Windows
form.
I like to make buttons larger
than the default and make them stand out with color. Just because you may be blind or visually
impaired does not mean that, with a little sighted assistance, you cannot make
your forms more visually pleasing.
The form we are about to
create will have a shaded label with a black background and a yellow foreground
color. This resembles the 1980’s
cassette deck LED displays. This label
will be used to display the song playback status.
It will have a menu strip so
that we can assign meaningful shortcut keys to the player buttons.
And, finally, it will have
four very large, colored buttons: Load
Song, Play Song, Pause Song and Stop Song.
I use a blue (Navy) background and white foreground color for the Load
Song button but for the rest of the buttons, I use colors that a sighted person
would see on a traffic stop light. Green
for Play, Yellow for pause and Red for Stop.
After we get the layout done,
we will play with these colors a little in our code to make the buttons look
differently when they are activated.
This way, the visual person can easily tell the status of the player by
looking at the coloring of the buttons.
1.
Resize Main.cs in designer mode to ().
2.
Add an Open File
Dialog control named ofdOpenWave with the following
properties:
|
Property |
Value |
|
Filter |
Wave Audio (*.wav)|*.wav |
|
Title |
Open Wave Audio File |
3.
Drop a label
control named lblSongStatus onto the form with the
following properties:
|
Property |
Value |
|
Backcolor |
Black |
|
Forecolor |
Yellow |
|
TextAlign |
Center |
|
Text |
|
|
Size |
|
|
Location |
|
The
text property above is blank and is not a typo.
4.
Add a button
control named btnLoad with the following properties:
|
Property |
Value |
|
Backcolor |
Navy |
|
Forecolor |
White |
|
Text |
Load Song |
|
Font |
|
|
Size |
|
|
Location |
|
|
Enabled |
True |
5.
Add a button
control named btnPlay with the following properties:
|
Property |
Value |
|
Backcolor |
DarkGreen |
|
Forecolor |
DarkGray |
|
Text |
Play Song |
|
Font |
|
|
Size |
|
|
Location |
|
|
Enabled |
False |
6.
Add a button
control named btnPause with the following properties:
|
Property |
Value |
|
Backcolor |
Gold |
|
Forecolor |
DarkGray |
|
Text |
Pause Song |
|
Font |
|
|
Size |
|
|
Location |
|
|
Enabled |
False |
7.
Add a button
control named btnStop with the following properties:
|
Property |
Value |
|
Backcolor |
DarkRed |
|
Forecolor |
DarkGray |
|
Text |
Stop Song |
|
Font |
|
|
Size |
|
|
Location |
|
|
Enabled |
False |
8.
Add a menustrip control named mnuMain.
9.
Add menu items to
mnuMain with the following properties:
|
Menu Item |
Parent Item |
Property |
Value |
|
mnuFile |
|
Text |
&File |
|
mnuExit |
mnuFile |
Text |
E&xit |
|
mnuAction |
|
Text |
&Action |
|
mnuLoadSong |
mnuAction |
Text |
Load Song |
|
mnuLoadSong |
mnuAction |
ShortcutKeys |
F2 |
|
mnuPlaySong |
mnuAction |
Text |
Play Song |
|
mnuPlaySong |
mnuAction |
ShortcutKeys |
F3 |
|
mnuPauseSong |
mnuAction |
Text |
Pause Song |
|
mnuPauseSong |
mnuAction |
ShortcutKeys |
F4 |
|
mnuStopSong |
mnuAction |
Text |
Stop Song |
|
mnuStopSong |
mnuAction |
ShortcutKeys |
F5 |
10. Save your work.
You may have noticed that we
set the default state of all but the Load button to enabled = false. It is good practice not to allow the user to
click buttons when the action of those buttons could cause errors. Naturally, if the user tried to play, stop or
pause a song which hasn’t been loaded yet, it may cause a run-time error unless
there is validation in the click event handling code. So, by disabling the buttons when no click
actions should be allowed, we reduce the risk of errors.
Before we add any audio
coding, we are going to make the buttons and menu items activate the way they
should. So, later, all we have to do is
add the audio functionality. This also simplifies
the process of debugging.
1.
Open Visual
Studio 2010.
2.
Open the BGLowLevelMCI project.
3.
Create Click
Event Handlers for btnLoad, btnPlay,
btnPause and btnStop. (In C#, this is done from the properties
window or by double-clicking on the button in the designer.
4.
Create Click
Event Handlers for mnuExit, mnuLoadSong,
mnuPlaySong, mnuPauseSong
and mnuStopSong. (Hint: If the code in the menu click
event handler is the same as the button click event handler, you may enter the
button’s handler as the menu item’s handler in the properties window. In VB, you would add the control to the
Handles clause of the event handler.
Example: <function signature
here> Handles btnPlay.Click, mnuPlaySong.Click.
5.
Create the
following private void functions but do not add code yet: LoadSong(), PlaySong(), PauseSong(), StopSong() and CloseSong().
6.
Save Your Work.
We are now going to add some
code that will help us avoid run-time errors and add some visual effect to the
program.
When the program begins, only
one button should be available to the user: btnLoad. The rest should be disabled. This includes the menu items as well. If we tried to play a song before it is
loaded, we’d get a run-time error. So,
we will simply disable the Play button until a song is loaded. The same is true of the Pause and Stop
buttons.
1. Add a form load event handler to the form.
2. In the load event handler, type the following code:
btnPlay.Enabled = false;
mnuPlaySong.Enabled = false;
btnPause.Enabled = false;
mnuPauseSong.Enabled = false;
btnStop.Enabled = false;
mnuStopSong.Enabled = false;
btnLoad.Enabled = true;
mnuLoadSong.Enabled = true;
The
code above disables all buttons and menu items except for btnLoad
and mnuLoadSong.
3. In the function LoadSong,
type the following code:
DialogResult res = ofdOpenWave.ShowDialog();
if (res != DialogResult.OK)
{
return;
}
// load
wave file
strWaveFile = ofdOpenWave.FileName;
4. Put a comment on the next line of code that says //Load Audio File Here.
5. Skip about three lines before adding the next section
of code. When we are ready to add the
audio code, we will add it here.
6. Type the following code next:
// Set buttons
lblStatus.Text = ofdOpenWave.FileName
+ " Loaded.";
btnPlay.Enabled = true;
mnuPlaySong.Enabled = true;
btnPlay.ForeColor = Color.White;
btnPlay.BackColor
= Color.DarkGreen;
btnPause.Enabled = false;
mnuPauseSong.Enabled = false;
btnPause.BackColor = Color.Gold;
btnPause.ForeColor = Color.DarkGray;
btnStop.Enabled = false;
mnuStopSong.Enabled
= false;
btnStop.BackColor = Color.DarkRed;
btnStop.ForeColor = Color.DarkGray;
7. Save Your Work.
In the code above, we
activated the Open File Dialog control to allow the user to select the file
they wished to load. If the user clicks Cancel, the file
dialog is closed and no file is loaded.
But, if the user selects a file and clicks OK, the button states and colors are changed.
The colors of btnLoad never change but the other buttons do change in color
as described in this table.
|
Control |
BackColor |
ForeColor |
Condition |
|
btnPlay |
DarkGreen |
DarkGray |
Disabled – No Song Loaded |
|
btnPlay |
Green |
White |
Enabled |
|
btnPlay |
Lime (Light Green) |
Navy (Dark Blue) |
Song Playing |
|
btnPause |
Gold |
DarkGray |
Disabled |
|
btnPause |
Gold |
Black |
Enabled – Song Playing |
|
btnPause |
Yellow |
Navy |
Song Paused |
|
btnStop |
DarkRed |
DarkGray |
Disabled. |
|
btnStop |
DarkRed |
White |
Enabled. Song Playing. |
|
btnStop |
Red |
White |
Song Stopped but still
loaded. |
The colors as they change
depending on the state of the Player application resemble the buttons used on
1980’s cart machines, which were tape machines used for commercials at radio
stations.
1. Add the following code to the PlaySong()
function
//Add Audio Code Here
// Set
Button States
btnPlay.BackColor = Color.Lime;
btnPlay.ForeColor = Color.Navy;
btnPlay.Enabled = false;
mnuPlaySong.Enabled = false;
btnPause.Enabled = true;
mnuPauseSong.Enabled = true;
btnPause.ForeColor =
Color.Black;
btnPause.BackColor = Color.Gold;
btnStop.Enabled = true;
mnuStopSong.Enabled = true;
btnStop.ForeColor = Color.White;
btnStop.BackColor = Color.DarkRed;
lblStatus.Text = strWaveFile + " Now
Playing...";
We
just added a comment and space for the audio code then the next section of the
code sets the states and colors of the buttons and menu items.
2. Add the following code to the function named PauseSong():
if (btnPause.BackColor
== Color.Gold)
{
//
Add Audio Code Here
//
Set Button States
btnPlay.BackColor = Color.DarkGreen;
btnPlay.ForeColor = Color.DarkGray;
btnPlay.Enabled
= false;
mnuPlaySong.Enabled = false;
btnPause.Enabled = true;
mnuPauseSong.Enabled = true;
btnPause.ForeColor = Color.Navy;
btnPause.BackColor = Color.Yellow;
btnStop.Enabled = false;
mnuStopSong.Enabled = false;
btnStop.ForeColor = Color.DarkGray;
btnStop.BackColor = Color.DarkRed;
lblStatus.Text = strWaveFile + " Paused...";
}
else
{
// Unpause
//Add Audio Code Here
//
Set Button States
btnPlay.BackColor = Color.Lime;
btnPlay.ForeColor = Color.Navy;
btnPlay.Enabled = false;
mnuPlaySong.Enabled = false;
btnPause.Enabled = true;
mnuPauseSong.Enabled = true;
btnPause.ForeColor = Color.Black;
btnPause.BackColor = Color.Gold;
btnStop.Enabled = true;
mnuStopSong.Enabled = true;
btnStop.ForeColor = Color.White;
btnStop.BackColor = Color.DarkRed;
lblStatus.Text = strWaveFile + " Now Playing...";
}
In the code above, we checked
to see if the button is disabled. If so,
we change its state to enabled and set the colors accordingly. If the button is enabled
and in Paused state as defined by its background color, we set the button
states to “unpause” the song.
3. Add the following code to the function named StopSong():
// Add Audio Code Here
// Set
Button States
btnPlay.BackColor = Color.DarkGreen;
btnPlay.ForeColor = Color.White;
btnPlay.Enabled = true;
mnuPlaySong.Enabled = true;
btnPause.Enabled = false;
mnuPauseSong.Enabled = false;
btnPause.ForeColor = Color.DarkGray;
btnPause.BackColor = Color.Gold;
btnStop.Enabled = false;
mnuStopSong.Enabled = false;
btnStop.ForeColor = Color.DarkGray;
btnStop.BackColor = Color.Red;
lblStatus.Text = strWaveFile + " Stopped...";
In the code above, we left a
few spaces for our audio code and then set the button states so that the song
is in “Stopped” mode.
4. Now, add a call to the appropriate function in each of
the button’s click event handler. Do the
same for the menu items. Example: in btnPlay click
event handler, you would call PlaySong().
5. Save Your Work.
6. Compile Your Project to make sure there are no
errors. If there are errors, fix them.
7. Test Your Work.
Make use of the Messagebox.Show or Console.Writeline method to ensure that the button states
and colors are changing when they should.
Adding The Audio Code
I’m not going to go in-depth
into the low-level MCI library. The
purpose of this section is to show you what the code looks like and to show you
how to load, play, pause and stop audio files using this technology.
We will be using three
classes that can be found on the Microsoft web site and then calling methods
from these classes in our program.
These three classes are very
complicated and are out of the scope of this lesson. Since this technology is so old and there are
easier alternatives, I do not see the need to teach these techniques in greater
detail.
You may, however, look at
these classes and learn from it independently, if you wish.
These classes include data
structures for the Wave format as well as the methods we will be using in our
program.
1.
Download the
chapter solution project from the web site.
2.
Unzip the
project.
3.
Open Visual
Studio 2010.
4.
Open the BGLowLevelMCI project.
5.
Open Solution
Explorer.
6.
Select the BGLowLevelMCI project in Solution Explorer and bring
up the context menu.
7.
Add an Existing
Item to the project.
8.
Add these files
from the solution project you downloaded from the web site: WaveOut.cs, WaveNative.cs, WaveStream.cs.
9.
Build the
solution to make sure there are no errors.
As stated above, we are not
going to spend time on the complicated code inside these three classes but will
show you how to use these classes to load, play, pause and stop audio. You may investigate this code on your own, if
it interests you.
1. Add a function named CloseSong()
and add the following code to it:
StopSong();
lblStatus.Text = "";
2. Add the following definitions to the top of your form
class:
private string strWaveFile
= "";
private WaveLib.WaveStream audioStream;
private WaveLib.WaveOutPlayer waveOutPlayer;
private WaveLib.WaveFormat waveFormat;
private WaveLib.WaveNative waveNative;
private long wavePosition = 0;
3. Add the following code to LoadSong()
before the code that sets the button states:
// load wave file
strWaveFile = ofdOpenWave.FileName;
try
{
WaveLib.WaveStream
waveStream = new WaveLib.WaveStream(strWaveFile);
if
(waveStream.Length <= 0)
throw
new Exception("Invalid WAV file");
waveFormat = waveStream.Format;
if
(waveFormat.wFormatTag != (short)WaveLib.WaveFormats.Pcm
&& waveFormat.wFormatTag != (short)WaveLib.WaveFormats.Float)
throw new Exception("Only PCM Wave files are
supported");
audioStream = waveStream;
}
catch(Exception e)
{
CloseSong();
MessageBox.Show(e.Message);
return;
}
wavePosition = 0;
The code above opens a Try…Catch
block to trap any errors that occur, opens and loads the selected wave file.
4. Add a function called FillWaveBuffer(). Add the following code to this function:
byte[] b = new byte[size];
if (audioStream != null)
{
int pos = 0;
while
(pos < size)
{
int toget = size - pos;
int got = audioStream.Read(b,
pos, toget);
if
(got < toget)
audioStream.Position
= 0; // loop if the file ends
pos += got;
}
}
else
{
for (int i = 0; i < b.Length; i++)
b[i]
= 0;
}
System.Runtime.InteropServices.Marshal.Copy(b, 0, data, size);
This function loads the wave
data from the file into memory.
5. Add the following code to the beginning of PlaySong():
//Add Audio Code Here
StopSong();
if (audioStream != null)
{
audioStream.Position = 0;
wavePosition = 0;
waveOutPlayer = new WaveLib.WaveOutPlayer(-1, waveFormat,
16384, 3, new WaveLib.BufferFillEventHandler(FillWaveBuffer));
}
The code above calls StopSong() to stop and close any currently playing songs,
sets the position of the play head to zero (beginning of the song) then starts
playback from the memory buffer.
6. Add the following code to StopSong
before the code where the button states are set:
// Add Audio Code Here
if (waveOutPlayer != null)
{
try
{
waveOutPlayer.Dispose();
}
finally
{
waveOutPlayer = null;
}
if (btnStop.Enabled == true)
{
wavePosition
= 0;
}
}
This code disposes of the
player object, effectively stopping and closing the wave file/buffer then sets
the variable we use for the playback head position to zero.
7. Modify the PauseSong() code
so that it looks like the following:
if (btnPause.BackColor
== Color.Gold)
{
// Add Audio Code Here
waveOutPlayer.Pause();
// Set Button States
btnPlay.BackColor
= Color.DarkGreen;
btnPlay.ForeColor
= Color.DarkGray;
btnPlay.Enabled
= false;
mnuPlaySong.Enabled
= false;
btnPause.Enabled
= true;
mnuPauseSong.Enabled
= true;
btnPause.ForeColor
= Color.Navy;
btnPause.BackColor
= Color.Yellow;
btnStop.Enabled
= false;
mnuStopSong.Enabled
= false;
btnStop.ForeColor
= Color.DarkGray;
btnStop.BackColor
= Color.DarkRed;
lblStatus.Text
= strWaveFile + " Paused...";
}
else
{
// Unpause
//Add Audio Code Here
waveOutPlayer.Resume();
// Set Button States
btnPlay.BackColor
= Color.Lime;
btnPlay.ForeColor
= Color.Navy;
btnPlay.Enabled
= false;
mnuPlaySong.Enabled
= false;
btnPause.Enabled
= true;
mnuPauseSong.Enabled
= true;
btnPause.ForeColor
= Color.Black;
btnPause.BackColor
= Color.Gold;
btnStop.Enabled
= true;
mnuStopSong.Enabled
= true;
btnStop.ForeColor
= Color.White;
btnStop.BackColor
= Color.DarkRed;
lblStatus.Text
= strWaveFile + " Now
Playing...";
}
8. Save Your Work.
9. Build the project to ensure you have no errors. If so, fix the errors.
10. Test the project.
Load a wave, play and test the pause and stop functionality.
While this small application
may seem cool to you now, it only plays wave files and no one really uses wave
files anymore, except for very small sound effects in gaming.
In the next chapter, we are
going to use high-level MCI to play MP3 files.
On Your Own
In this chapter, I tried to
keep the code simple but in reality, low-level MCI audio technology is very
complicated and there are areas of it that even I do not understand due to poor
documentation and lack of audio engineering education. The Founder of AIPL, Ken Levy, whom I work
with on Singulator has a 4-year engineering degree in audio
engineering and many years of experience working with audio from the bit
level. In contrast, compared to him, I
seem like a beginner. When I asked him
to teach me to build an audio limiting module, he stated that he couldn’t
possibly teach me enough engineering in several months to get the job done. That can only be obtained by going to college
and studying the engineering.
Likewise, I’ve only touched
the surface on low-level MCI in this chapter.
If you are interested in learning more, I have listed a few references
at the end of this chapter.
Some things you can research
to add to our demonstration program include:
1.
Mechanism to stop
the audio when the play head is at the end of the buffer. Currently, the song repeats. This can be accomplished by obtaining the
length in seconds and using a timer, obtain the length of the song in bytes and
stopping the audio after it has processed that number of bytes or using the MCI
event-triggered MM_WOM_DONE approach,
2.
Displaying the
song’s progress visually in either a progress bar, a
time counter or both.
3.
Jumping to a
specific user-defined position in the song.
4.
Obtaining and Adjusting the sound volume.
5.
Displaying the
amplitude of the audio in the form of a visual VU meter(s).
6.
Adjust the audio
balance (called panning).
7.
Add a visual
effect to the buttons where the currently activated button “blinks”. This can be accomplished using a Timer
control and changing the colors in the Tick event handler.
Next, we will learn more MCI
audio by using the high-level mciSendString approach.
Reference:
Programming Windows fifth edition by Charles Petzold(1998)