HomePage Delphi Library

Adding Multimedia to Delphi Programs

Overview

Installing the Correct Drivers

The TMediaPlayer Component

Opening the TMediaPlayer at Runtime

Media Access Programs

A Closer Look at a Media Access Program

Defining the Window in Which a Movie Plays

Overview

You can easily add Multimedia features such as sounds, movies, and music to Delphi programs. This paper shows how to achieve these ends using the multimedia control that is built into the Delphi environment.

At the time of this writing, the new Windows 95 multimedia features have not been implemented for Delphi. As a result, the paper covers only those features included in the first 16 bit release of Delphi. Windows 95 specific features will be discussed during my talk, and additional programs and information will be available at the time. In particular, I find it very likely that WinG, double buffering, and DIBS will all be touched on in the talk.

When reading this paper, you can expect to encounter the following distinct sections:

How to use the built-in Delphi multimedia control to play WAVE, MIDI, and AVI files. This section of the paper will also discuss accessing CD-ROM files.

How to show an AVI file in a window on your form.

How to know when the user starts playing a file, when the user stops playing a file, when a file reaches the end, when the user pauses a file, and in general how to track runtime information about the state of the multimedia player.

Installing the Correct Drivers

Delphi can't play multimedia files for you unless you have the proper software and the proper drivers. Some multimedia tools, such as movies, do not require that you have any special hardware, although you can't hear the soundtrack to the films unless you have a sound card. Other multimedia features such as MIDI, WAV and CD files, all require special hardware. The little built-in speaker that has always come with PCs is not enough to exercise the real multimedia capabilities described in this paper. In particular, the SPEAKER.DRV file is not going to be any help in this regard.

As a rule, the drivers you need ship with the hardware that you have installed on your system. For instance, a Sound Blaster card comes with a set of disks that contain the drivers you need. You must install these drivers before attempting to run the programs described in this paper.

Don't forget the Microsoft Video for Windows Drivers, which are available for free from Microsoft. They can be found on Compuserve or the Internet.

If you have a sound card, but can't find the drivers you need, they are usually available from the manufacturer, or from CompuServe, the Internet, or some other on-line service. As a rule, companies don't charge for drivers.

When you are done installing the drivers, you can run the Drivers applet from the Control Panel to see the drivers that you have installed. You will also find a parallel set of entries in your SYSTEM.INI file. On my system these entries look like this: [drivers]

midimapper=midimap.drv

VIDC.CVID=iccvid.drv

VIDC.YVU9=indeov.drv

WaveMapper=msacm.drv

MSACM.msadpcm=msadpcm.acm

MSACM.imaadpcm=imaadpcm.acm

wave=sndsys.drv

midi=sndsys.drv

aux=sndsys.drv

Or like this:

[drivers32]

MSACM.msg711=msg711.acm

vidc.CVID=iccvid.dll

VIDC.IV31=ir32_32.dll

VIDC.IV32=ir32_32.dll

vidc.MSVC=msvidc32.dll

VIDC.MRLE=msrle32.dll

MSACM.imaadpcm=imaadp32.acm

MSACM.msadpcm=msadp32.acm

MSACM.msgsm610=msgsm32.acm

MSACM.trspch=tssoft32.acm

Ugh! What a mess. However, some knowledge can be gleaned from this listing. For instance, on my system, SNDSYS.DRV is used to play WAV and MIDI files. To improve the performance on my system, I might want to check whether that driver is up to date, and if I was having problems getting any sound from my system, I might want to check to see that the driver is the right one for my system.

The MIDI Mapper applet in the Control Panel can be used to customize the voices on your synthesizer so that they map to the right values. For instance, some MIDI hardware uses voice 1 as the sound for a piano, voice 2 for an electric piano, and so on. If you want to change which voices are mapped to which numbers, use the MIDI Mapper. Due to a lack of standardization, and also to some lack of foresight on the part of the people who set up the Windows MIDI services, there can be some frustrating work in store for you in this regard.

The TMediaPlayer Component

To get started writing a multimedia application, create a new project and select the multimedia control (TMediaPlayer) from the System page of the Component Palette. Drop the tool in the middle of a form, as shown in Figure 1.

Figure 1. The TMediaPlayer control resting in the middle of a standard form

After you have placed the control on a form, you will find that the Object Inspector contains a FileName field, as shown in Figure 2. Fill in this field with the name of an AVI, MIDI, or WAVE file. For instance, on my system I can write G:\AVI\CLOUDS.AVI to indicate the name of a video file located on my CD-ROM. The ellipses icon on the right side of the property editor pops up a dialog so that you can browse for files. After choosing a valid FileName, be sure the AutoOpen property is set to true. This property ensures that Delphi automatically opens the MULTIMEDIA services when you start your program.

Figure 2. The TMediaPlayer component as seen through the Object Inspector

After completing these simple steps, you are ready to run the program. When it's launched, click on the green button at the left of the TMediaPlayer to start the movie or sound file that you selected. If you get an error, there are three probable sources:

You entered an invalid filename.

You don't have multimedia set up correctly on your system. This means you either don't have the right hardware, or you have not installed the right drivers. Driver configuration occurs in the Control Panel.

You have AutoOpen set to true, but have left the FileName property blank. This produces the dreaded error message This command requires a parameter. Please supply one.

An example program is available on disk as MEDIA1.DPR. By default, it plays CHIMES.WAV, a file that ships with every copy of Windows. If you have deleted this file, or if you do not store it in a subdirectory called C:\WINDOWS, you need to change the FileName property of this program.

If you experiment with the MEDIA1 program for awhile, you find that you can play AVI, MIDI, and WAVE files simply by specifying the name of a file. This flexibility is the result of the control's capability to parse the filename, detect the file type from the extension, and apportion the act of actually playing the file to the appropriate internal routine.

Opening the TMediaPlayer at Runtime

If you place a TMediaPlayer component on a window, select a file, set AutoOpen to true, and run the program, you will find that the media player starts out in operational mode. That is, most most of its buttons lit up and ready for use. If you close the program, set the AutoOpen property to False, and restart the program, the media player will not be open when you first run the program. This can be useful under some circumstances, because it costs time and resources to open up the Windows multimedia drivers.

It takes only a few simple steps to gain control over the opening and closing of the TMediaPlayer. To get started, place a button on the form and name it Open. Double-click the button to create an OnClick method, and fill it in as follows: procedure TForm1.Button1Click(Sender: TObject);

begin

MediaPlayer.Open;

end;

When you run the program, you see a bar containing the universal symbols for playing a tape, CD, or video device. Click once on the button to open the appropriate MCI device. Wait a few moments for the buttons on the TMediaPlayer to change color, and then click once more on the green arrow at the left of the control. The file you specified in the FileName section now plays for you.

Media Access Programs

Many programmers will want to give their users a simple way of playing the widest possible range of files. This means they will want to give the user access to the hard disk or CD-ROM, and allow them to select and play a wide range of individual files. This type of application is sometimes called a media access program.

To create a media access application, start by dropping a TMediaPlayer and a button on a form. Name the button BSelectFile, and give it Select File as a caption. Choose the OpenDialog from the Dialogs palette in the Component Palette, and place this control on the form. When you are done, your form should look like the one shown in Figure 3. This might be a good time to save this program under the name ACCESS.

Figure 3. The main form for the ACCESS program.

Now create a BSelectFileClick method that looks like this: procedure TForm1.BSelectFileClick(Sender: TObject);

begin

MediaPlayer1.Close;

if OpenDialog1.Execute then begin

MediaPlayer1.FileName := OpenDialog1.FileName;

MediaPlayer1.Open;

end;

end;

The code shown here is going to be executed every time the user presses the Select File button. It has four purposes:

The first step is to close any MCI devices that might be currently open by calling MediaPlayer1.Close. When you first open the program, this line won't serve a useful purpose, but after you have opened a file and wish to open a second one, you find that it helps clear the way. It is never an error to call Close on a TMediaPlayer.

The second step is to execute the OpenDialog. This allows users to roam at will through the hard drive and any available CD-ROMs. If they find a file they wish to play, they can press the OK button to select it. To aid in this process, set the Filter propert of the TOpenDialog to: Media Files | *.avi;*.wav;*.mid.

The third step only executes if the user selects a file. If the user chooses Cancel from the OpenDialog, nothing happens. If the user picks OK, the code assigns the filename selected by the user to the MCI control.

When an appropriate filename has been designated, the only step left is to open (or reopen) the MCI device by calling MediaPlayer1.Open. Now the user is free to click on the green arrow to play the file.

Besides the Filter property, another field of OpenDialog that you might want to tweak is called InitialDir. You can use this to designate the drive or directory that you want users to see first when they open the dialog. In my case, I prefer to enter the drive designating my CD-ROM:

g:

This allows the user to start his search for files on the drive most likely to contain a hit. Because I do not specify a particular directory, the user can select a directory and return to it over and over until he or she has seen all the files of interest in that location.

A Closer Look at a Media Access Program

I have shown you one very simple media access program called ACCESS, which nearly anyone can put together. However, there are occasions when you want a more in-depth look at what occurs when a multimedia file is being played. The next section of this paper describes a program called ACCESS2, which gives you all the information you need to gain full control over MCI multimedia capabilities.

Before plunging into this explanation, let me make two points:

Although many programmers will find it useful, the information presented in this section is not essential to all multimedia programmers.

Other readers might wish for even more control over multimedia files than is shown in this section. These readers should be aware that you can get down to a lower level of file control by entirely circumventing the TMediaPlayer and dealing directly with a set of low-level Windows commands found in the MMSYSTEM.PAS unit that ships with Delphi. You can also use the MCI commands described in Delphi Programming Unleashed.

With these two caveats fresh in your mind, you are now ready to learn about some of the more subtle aspects of TMediaPlayer.

You have probably noticed that the Events palette for the TMediaPlayer contains special capabilities that you can add to your program. These functions come in two categories:

The first are the OnClick events that occur when the user presses part of the control. For instance, when the user presses the green play arrow on the TMediaPlayer, an OnClick message is sent to your program. Accompanying the OnClick message a parameter called Button which defines the button that has been clicked. Button is of type TMPBtnType.

The second are the OnNotify events containing the mm_MciNotify messages that are sent to your window when a file starts or stops playing, or when an error occurs.

I am going to describe the first set of events in the next few paragraphs, and then move on to the second set.

There are eight major events generated by a direct click on the control, all of which are captured in the TMPBtnType. These events, passed to you in the Button parameter of an OnClick event, are as follows:

btPlay Occurs when the user presses the green play arrow.

btStop Occurs when the user presses the red square stop button.

btBack Occurs when the user presses the blue "back one frame" button.

btStep Occurs when the user presses the blue "forward one frame" button.

btNext Occurs when the user presses the blue fast-forward button.

btPrev Occurs when the user presses the blue rewind button.

btPause Occurs when the user presses the yellow pause button.

btRecord Occurs when the user presses the round red record button.

If you want to see what it's like to capture one of these events, first place four edit controls on your form. Each of these edit controls will be used eventually, although they do not all play a role in the first parts of the program I am going to describe. Create an OnClick event for the TMediaPlayer, and fill it in so that it looks like this: procedure TForm1.MediaPlayer1Click(Sender: TObject;

Button: TMpBtnType;

var DoDefault: Boolean);

begin

if Button = btPlay then

Edit1.Text := 'Playing';

end;

When you understand how this system works, it should take you only a moment to be able to display an appropriate line of text whenever the user selects the TMediaPlayer. For instance, here is a method that can be called whenever the user presses a media player button: procedure TForm1.MediaPlayer1Click(Sender: TObject;

Button: TMPBtnType;

var DoDefault: Boolean);

begin

case Button of

btPlay: Edit1.Text := 'Playing';

btPause: Edit1.Text := 'Paused';

btStop: Edit1.Text := 'Stop';

btNext: Edit1.Text := 'Next';

btPrev: Edit1.Text := 'Prev';

btStep: Edit1.Text := 'Step';

btBack: Edit1.Text := 'Back';

btRecord: Edit1.Text := 'Record';

btEject: Edit1.Text := 'Eject';

end;

end;

To find out whether a piece has stopped playing, or whether an error has occurred, you can take a look at OnNotify messages. When working directly with the operating system, these messages come in four flavors: mci_Notify_Successful: Sent when a command is completed

mci_Notify_Superseded: Command aborted by another function

mci_Notify_Aborted : Current function is aborted

mci_Notify_Failure : An error occurred

Delphi does not send these messages to you directly, but instead converts them into constants such as nvSuccessful, nvAborted, and so on. This system is adopted to provide consistency with other portions of the Delphi environment.

It's a bit tricky to understand exactly when each of these messages are sent by the Windows MCI device driver. As a rule, you get messages in these cases:

An nvSuccessful message when a piece finishes successfully.

An nvSuperseded message might come if the system has been paused, and the user then presses the play button.

An nvAborted message might come if the user presses the stop button, or causes the device to be closed.

Here is a function that responds to OnNotify messages by displaying a short descriptive string in an edit control: procedure TForm1.MediaPlayer1Notify(Sender: TObject);

var

S: String;

begin

case MediaPlayer1.NotifyValue of

nvSuccessful: begin

Inc(Total);

S := 'mci_Notify_Successful' + IntToStr(Total);

end;

nvSuperseded: S := 'mci_Notify_Superseded';

nvAborted: S := 'mci_Notify_Aborted';

nvFailure: S := 'mci_Notify_Failure';

else

S := 'Unknown notify message';

end;

Edit2.Text := S;

if (MediaPlayer1.NotifyValue = nvSuccessful) and

(MediaPlayer1.Mode = mpStopped) then

Edit1.Text := 'File finished playing';

end;

This function is called automatically every time a significant event occurs that affects the MCI device. You never explicitly call this function yourself. Instead, you just set it up and wait for the function to be called by the system.

The heart of the MediaPlayer1Notify method is a case statement that hinges on the current state of the NotifyValue field of a TMediaPlayer. For instance, if the NotifyValue field is set to mci_Notify_Successful, a string specifying that fact is displayed in an edit control. Once again, you don't have to do anything to change the state of the NotifyValue field. It will be changed for you automatically by the system. All you need to do is respond to an OnNotify event and then check the NotifyValue field.

To be sure that a file has finished playing, you can wait for the reception of an mci_Notify_Successful message, and then check to see the current mode.

The current mode of an MCI device is specified in the Mode property of a TMediaPlayer. Here is a listing of the common values designated in this field: mci_Mode_Not_Ready

mci_Mode_Stop

mci_Mode_Play

mci_Mode_Record

mci_Mode_Seek

mci_Mode_Pause

mci_Mode_Open

Each of these modes is self-explanatory. If the Mode field is set to mci_Mode_Stop, the device is stopped. If it's set to mci_Mode_Play, the device is playing. Once again, Delphi does not send you these constants directly, but instead passes corresponding identifiers such as mpStopped, mpPlaying, and so on. The developers substituted these constants for the Microsoft defineid constants because they followed the style used by the rest of the Delphi objects.

If your application receives an mci_Notify_Successful message, and if the Mode field of the device is set to mci_Mode_Stop, you can be certain that the current file has finished playing. That is why the OnNotify method shown earlier checks for such a condition:

if (MediaPlayer1.NotifyValue = nvSuccessful) and

(MediaPlayer1.Mode = mpStopped) then

Edit1.Text := 'File finished playing';

The ACCESS2 program also contains the following method, which can be used to track the current state of the media player:

procedure TForm1.SetMode;

begin

case MediaPlayer1.Mode of

mpNotReady: Edit3.Text := 'mci_Mode_Not_Ready';

mpStopped: Edit3.Text := 'mci_Mode_Stop';

mpPlaying: Edit3.Text := 'mci_Mode_Play';

mpRecording: Edit3.Text := 'mci_Mode_Record';

mpSeeking: Edit3.Text := 'mci_Mode_Seek';

mpPaused: Edit3.Text := 'mci_Mode_Pause';

mpOpen: Edit3.Text := 'mci_Mode_Open';

else begin

Edit1.Text := 'Device Inactive';

Edit2.Text := 'No special messages';

Edit3.Text := 'Unknown';

Edit4.Text := 'No file selected';

end;

end;

end;

This routine gets called in response to an event generated by a TTimer that is placed on the form. To create a timer, simply select it from the System page of the Component Palette, drop it on a form, and create an OnTimer event handler. The method needs to do nothing more than call the SetMode procedure. The Interval property of a TTimer component defines how often OnTimer events are generated. If you leave Interval at the default 1000 millisecond level, SetMode is called once every second, thereby ensuring that the user is kept reasonably well informed of the current state of the TMediaPlayer.

With the other code from this paper, you will find the complete source code for the ACCESS2 program.

Defining the Window in which a Movie Plays

Sometimes you want an AVI file to play in a separate window, and sometimes you want it to play in a window that is part of your form. If you want a movie to be shown on your form, use the TMediaPlayer.Display property. For instance, you might drop a TPanel on the form and assign the Display property to it: MediaPlayer1.Display := Panel1;

To further customize the view, you can use the DisplayRect property to define the rectangle in which you want the movie to play. For instance, if you want the movie to stretch to fit the entire surface of the panel, you write the following: MediaPlayer1.DisplayRect := Rect(0, 0, Panel1.Width, Panel1.Height);

An example of this technique is found in the WINDAVI program found on disk.

Clearly, Delphi offers a simple and powerful way to create multimedia applications. When writing your own multimedia programs, use this paper as a starting point, and use your imagination as a guide.

Hosted by www.Geocities.ws

1