
The interface for accessing and playing CDs should look very similiar to what you are used to on your home system. It should allow you to scan, play, stop, pause, and reverse. The IMMAudioCD class works only on discs that contain CD_DA tracks.
The application must ensure that the appropriate compact disc is in the CD drive. For example, a CD player application might simply update its track and time displays if a new disc is inserted and verified. If you try to open an IMMAudioCD object and there is not an audio CD in the CD-ROM drive, then the application sends a message that the medium is not valid. A CD-drive can only be accessed by one player at a time. An example of designing a user interface with a player panel containing a CD player device follows.
class CD : public IMultiCellCanvas,
public ICommandHandler,
public IObserver,
public ISliderArmHandler,
public ISelectHandler
{
//**************************************************************************
// Class: CD *
// *
// Purpose: Provide a CD player. *
// It is a subclass of IMultiCell *
// *
//**************************************************************************
public:
CD( unsigned long windowid,
IWindow* parent,
IWindow* owner);
protected:
virtual bool
command ( ICommandEvent& event ),
selected( IControlEvent& event ),
moving ( IControlEvent& event );
virtual IObserver
&dispatchNotificationEvent(const INotificationEvent&);
private:
IMMAudioCD
cdPlayer;
IMMPlayerPanel
baseButtons;
IAnimatedButton
trackF,
trackB,
scanF,
scanB,
eject;
ICircularSlider
volume;
IStaticText
name,
readout;
IRadioButton
doorOpen,
doorClosed;
IMMAmpMixer
*pAmpMixer;
};
class MainWindow : public IFrameWindow
{
//**************************************************************************
// Class: MainWindow *
// *
// Purpose: Main Window for C++ MltMedia sample application. *
// It is a subclass of IFrameWindow *
// *
//**************************************************************************
public:
MainWindow( unsigned long windowId );
~MainWindow();
private:
ISetCanvas
clientCanvas;
CD*
cd;
};
/*---------------------------------------------------------
| MainWindow::MainWindow
------------------------------------------------------------
MainWindow::MainWindow( unsigned long windowId)
: IFrameWindow("Audio CD Example",windowId),
clientCanvas(CLIENTCANVASID,this,this)
{
cd = new CD ( CD_ID, &clientCanvas, this);
setBackgroundColor(IColor(IColor::kPaleGray));
IFont("Helv",8).setWindowFont(this);
sizeTo(ISize(600, 300));
setClient(cd);
clientCanvas.setDeckOrientation(ISetCanvas::vertical);
show();
setFocus();
}
MainWindow::~MainWindow()
{
if (cd)
delete cd;
}
CD::CD(
unsigned long windowid,
IWindow* parent,
IWindow* owner)
: IMultiCellCanvas(windowid,parent,owner),
readout (READOUTID, this,this),
name (CDNAMEID, this, this),
baseButtons (BASEBUTTONID, this,this, IMMDevice::audioCD),
trackF (TRACKFID,&baseButtons,&baseButtons,IRectangle(),
IWindow::visible | IAnimatedButton::animateWhenLatched),
trackB (TRACKBID,&baseButtons,&baseButtons,IRectangle(),
IWindow::visible | IAnimatedButton::animateWhenLatched),
scanF (SCANFID,&baseButtons,this,IRectangle(),
ICustomButton::autoLatch |
ICustomButton::latchable |
IWindow::visible | IAnimatedButton::animateWhenLatched),
scanB (SCANBID,&baseButtons,this,IRectangle(),
ICustomButton::autoLatch |
ICustomButton::latchable |
IWindow::visible | IAnimatedButton::animateWhenLatched),
eject (EJECTID,this,this,IRectangle(),
ICustomButton::autoLatch |
IWindow::visible | IAnimatedButton::animateWhenLatched),
volume (VOLID, this, this, IRectangle(),
ICircularSlider::defaultStyle() | ICircularSlider::proportionalTicks),
doorOpen (OPENBTN, this, this, IRectangle(), IRadioButton::defaultStyle() |
IControl::group),
doorClosed(CLOSEDBTN, this, this),
cdPlayer(),
pAmpMixer( 0 )
{
// Allow the CD to play without a connector.
cdPlayer.enableConnector(IMMDevice::cdStream);
//Add the additional button to the player panel.
baseButtons.setPlayableDevice(&cdPlayer);
baseButtons.addToCell(&trackB , 7, 1, 1, 1);
baseButtons.addToCell(&trackF , 8, 1, 1, 1);
baseButtons.addToCell(&scanB , 10, 1, 1, 1);
baseButtons.addToCell(&scanF , 11, 1, 1, 1);
//Put the bitmaps on the buttons.
trackB.setBitmaps(IAnimatedButton::trackReverse);
trackF.setBitmaps(IAnimatedButton::trackAdvance);
scanB.setBitmaps(IAnimatedButton::scanBackward);
scanF.setBitmaps(IAnimatedButton::scanForward);
eject.setBitmaps(IAnimatedButton::eject);
//Put text on the buttons. The \n cause the text to be on a new line.
trackB.setText("Track\nReverse");
trackF.setText("Track\nAdvance");
scanB.setText("Scan\nBackward");
scanF.setText("Scan\nForward");
eject.setText("Eject");
doorOpen.setText("Open door");
doorClosed.setText("Close door (if possible)");
doorOpen.select();
//Set up the title
name.setText("CD Player");
//Set up the display
readout.setText("TRACK 00 MIN:SEC 00:00");
readout.setLimit(24);
volume.setArmRange (IRange(0,100));
volume.setRotationIncrement(10);
volume.setText ("Volume");
volume.setValue( 100 );
cdPlayer.setVolume( 100 );
pAmpMixer = new IMMAmpMixer( cdPlayer.connectedDeviceId( IMMDevice::cdStream ) );
pAmpMixer->enableMonitoring();
pAmpMixer->setCloseOnDestroy( false );
//Add the controls to the multicell
addToCell (&name, 2, 1, 4, 1);
addToCell (&readout, 2, 3, 4, 1);
addToCell (&doorOpen, 2, 5, 4, 1);
addToCell (&doorClosed, 2, 6, 4, 1);
addToCell (&volume, 4, 7);
addToCell (&baseButtons, 4, 9);
addToCell (&eject, 2, 9);
setColumnWidth ( 5, 0, true );
ISelectHandler::handleEventsFor(this);
ICommandHandler::handleEventsFor(this);
IObserver::handleNotificationsFor(cdPlayer);
ISliderArmHandler::handleEventsFor(&volume);
}
bool CD::command( ICommandEvent& evt )
{
bool
rv = false;
switch ( evt.commandId() )
{
case TRACKBID:
cdPlayer.trackBackward();
rv=true;
break;
case TRACKFID:
cdPlayer.trackForward();
rv=true;
break;
case SCANFID:
if (scanF.isLatched())
cdPlayer.startScanningForward();
else
cdPlayer.stop();
rv=true;
break;
case SCANBID:
if (scanB.isLatched())
cdPlayer.startScanningBackward();
else
cdPlayer.stop();
rv=true;
break;
case EJECTID:
if (cdPlayer.isMediaPresent())
cdPlayer.openDoor();
else
{
cdPlayer.closeDoor();
if (cdPlayer.isMediaPresent())
eject.unlatch();
}
rv = true;
break;
}
return rv;
}
bool CD::selected( IControlEvent& evt )
{
bool
rv = false;
switch(evt.controlId())
{
case OPENBTN:
// enable open cd
cdPlayer.openDoor();
rv = true;
break;
case CLOSEDBTN:
// close cd
cdPlayer.closeDoor();
rv = true;
break;
}
return rv;
}
IObserver& CD::dispatchNotificationEvent(const INotificationEvent& event)
{
if (event.notificationId() == IMMAudioCD::positionTimerId)
{
IMMTrackMinSecFrameTime* time = (IMMTrackMinSecFrameTime*)(event.eventData().asUnsignedLong());
readout.setText(IString("TRACK ") +
IString(time->track()).rightJustify(2,'0') +
IString(" MIN:SEC ") +
IString(time->minutes()).rightJustify(2,'0') +
IString(":") +
IString(time->seconds()).rightJustify(2,'0'));
}
else if (event.notificationId() == IMMAudioCD::trackStartedId)
{
IMMTrackMinSecFrameTime* time = (IMMTrackMinSecFrameTime*)(event.eventData().asUnsignedLong());
readout.setText(IString("TRACK ") +
IString(time->track()).rightJustify(2,'0') +
IString(" MIN:SEC ") +
IString(time->minutes()).rightJustify(2,'0') +
IString(":") +
IString(time->seconds()).rightJustify(2,'0'));
}
return *this;
}
/*-------------------------------------------------------------
| CD::moving |
--------------------------------------------------------------*/
bool CD::moving(IControlEvent& evt)
{
bool
result = false;
ICircularSlider
*pSld = (ICircularSlider*)( evt.controlWindow() );
short
val = pSld->value();
switch( evt.controlId() )
{
case VOLID:
pAmpMixer->setVolume( val );
result = true;
break;
}
return result;
}
The following figure shows an audio CD example. Note that the track information is displayed on the top part of the interface. The open and closed radio buttons control the CD door.
A sequencer device plays a MIDI file by sending commands to a synthesizer where the commands are converted to the sounds of a specific musical instrument. The sequencer uses the timing commands to sequence the playing of the music.
Music devices with a sequencer, such as a Casio keyboard or a drum machine (a machine that reproduces percussion sounds), can record what is being played and can play what has been recorded previously. This recording is called a sequence. This sequence of music notes is stored in the MIDI format.
A sequencer is personal computer software that allows you to record, edit, and arrange multiple tracks of MIDI data. Most sequencers let you edit the messages in a sequence and link different sequences stored in memory. This finished sequence, ready for playback, is called a song. If you do not want to manipulate songs already recorded with a sequencer, you can also create original songs. A sequencer lets you record any style of music you want.
The MIDI sequencer device plays a MIDI song by sending commands from a MIDI file to a synthesizer where the commands are converted to the sounds of specific instruments. The IMMSequencer class is the base class for handling a MIDI sequencer device, and it supports the MIDI standard. Thus, the sequencer controls the characteristics of the MIDI information. In addition to allowing you to load MIDI files, the IMMSequencer class inherits all of the main functions, such as play, stop, pause, and record.
You can use the following command to create a MIDI sequencer object:
#include// Define the header file IMMSequencer midiPlayer; // Define the object midiPlayer(true) // Pass true to the device constructors so // the devices are opened and no additional // functions calls are made before using the // device.
The waveform audio device allows an application to play or record digital audio using files or application memory. Waveform audio devices require some form of input, that is, a file. The file contains the actual sound or waveform. The device can be opened with or without a file. If it is opened without a file, then a file is typically loaded later.
This device can use files or memory buffers. Buffering data improves performance of multimedia applications that perform numerous file input and output operations when accessing media devices. Applications that are performance-sensitive (that is, slow machines) can optimize file input and performance by buffering their data. If the data is already in the memory buffer, the operating system can transfer the record to the application's area without reading the sector from disk.
An object instantiated from IMMWaveAudio is capable of performing many tasks with a sound file. It can edit, play back, and record to name a few. In addition, the object inherits up the chain for the functions of play, stop, pause, and setFormat, plus cut, copy, and paste to, and from a memory buffer.
You can use the following command to create a waveform audio device object:
#include// Define the header file IMMWaveAudio wavePlayer; // Define the object wavePlayer(true) // Pass true to the device constructors so // the devices are opened and no additional // functions calls are made before using // the device.
![]()
Creating Master Devices
Creating Audio Devices
Creating Video Devices
Adding Animated Buttons and
Circular Sliders
![]()
IAnimatedButton
ICircularSlider
ICommandHandler
IMMAudioCD
IMMPlayerPanel
IMMRecordable
IMMSequencer
IMMWaveAudio
IMultiCellCanvas
IObserver
ISelectHandler
ISliderArmHandler
IStaticText