本篇是创建游戏内核(21)【OO改良版】的续篇,关于该内核的细节说明请参阅创建游戏内核(22)。
接口:
//======================================================================================
// This class encapsulates mp3 playing.
//======================================================================================
typedef class MP3
{
public:
    MP3();
    ~MP3();
    BOOL init();
    void shutdown();
    BOOL render_file(const char* filename);
    BOOL play();
    BOOL stop();
    BOOL pause();
    BOOL is_playing();
private:
    IGraphBuilder*      m_graph_builder;
    IMediaControl*      m_media_control;
    IMediaEvent*        m_media_event;
} *MP3_PTR;
实现:
//------------------------------------------------------------------------------
// Constructor, zero member data.
//------------------------------------------------------------------------------
MP3::MP3()
{
    memset(this, 0, sizeof(*this));
}
//------------------------------------------------------------------------------
// Destructor, release resource.
//------------------------------------------------------------------------------
MP3::~MP3()
{
    shutdown();
}
//------------------------------------------------------------------------------
// Release all resource which used to play mp3.
//------------------------------------------------------------------------------
void MP3::shutdown()
{
    release_com(m_media_event);
    release_com(m_media_control);
    release_com(m_graph_builder);
    CoUninitialize();
}
//------------------------------------------------------------------------------
// Create graph builder, query interface for medial control and medial event.
//------------------------------------------------------------------------------
BOOL MP3::init()
{
    // shutdown prior initialized system
    shutdown();
    // initialize com
    CoInitialize(NULL);
    // create graph builder object and media controls
    if(FAILED(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, 
                               (void**)&m_graph_builder)))
    {
        return FALSE;
    }
    m_graph_builder->QueryInterface(IID_IMediaControl, (void**) &m_media_control);
    m_graph_builder->QueryInterface(IID_IMediaEvent,   (void**) &m_media_event);
    return TRUE;
}
//------------------------------------------------------------------------------
// Builds a filter graph that renders the specified file.
//------------------------------------------------------------------------------
BOOL MP3::render_file(const char* filename)
{
    // error checking
    if(m_graph_builder == NULL || m_media_control == NULL)
        return FALSE;
    // stop the current song
    m_media_control->Stop();
    // convert filename to wide-character string
    WCHAR _w_filename[MAX_PATH];
    mbstowcs(_w_filename, filename, MAX_PATH);
    // builds a filter graph that renders the specified file
    if(FAILED(m_graph_builder->RenderFile(_w_filename, NULL)))
        return FALSE;
    return TRUE;
}
//------------------------------------------------------------------------------
// Play mp3.
//------------------------------------------------------------------------------
BOOL MP3::play()
{
    // error checking
    if(m_media_control == NULL)
        return FALSE;
    // Runs all the filters in the filter graph. 
    // While the graph is running, data moves through the graph and is rendered.
    if(FAILED(m_media_control->Run()))
        return FALSE;
    return TRUE;
}
//------------------------------------------------------------------------------
// Stop playing mp3.
//------------------------------------------------------------------------------
BOOL MP3::stop()
{
    // error checking
    if(m_media_control == NULL)
        return FALSE;
    // stops all the filters in the graph
    if(FAILED(m_media_control->Stop()))
        return FALSE;
    return TRUE;
}
//------------------------------------------------------------------------------
// Pause playing mp3.
//------------------------------------------------------------------------------
BOOL MP3::pause()
{
    // error checking
    if(m_media_control == NULL)
        return FALSE;
    // pause all the filters in the filter graph
    if(FAILED(m_media_control->Pause()))
        return FALSE;
    return TRUE;
}
//------------------------------------------------------------------------------
// Ascertain whether mp3 has completed playing.
//------------------------------------------------------------------------------
BOOL MP3::is_playing()
{
    // error checking
    if(m_media_event == NULL)
        return FALSE;
    // get event and handle it
    long _event, _param1, _param2;
    // retrieves the next event notification from the event queue
    m_media_event->GetEvent(&_event, &_param1, &_param2, 1);
    if(_event == EC_COMPLETE)
    {
        // free resources associated with the paramters of an event
        m_media_event->FreeEventParams(_event, _param1, _param2);
        return TRUE;
    }
    m_media_event->FreeEventParams(_event, _param1, _param2);
    return FALSE;
}
测试代码:
/*****************************************************************************
PURPOSE:
    Test for class MP3.
*****************************************************************************/
#include "core_common.h"
#include "core_framework.h"
#include "core_sound.h"
class APP : public FRAMEWORK
{
public:
    BOOL init()
    {
        m_mp3.init();
        if(m_mp3.render_file("song.mp3"))
            m_mp3.play();
        while(m_mp3.is_playing())
            ;
        
        return TRUE;
    }
    BOOL frame()
    {
        return TRUE;
    }
    BOOL shutdown()
    {
        return TRUE;
    }
private:
    MP3 m_mp3;    
};
int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
    APP app;
    if(! build_window(inst, "mp3_class", "mp3_test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480))
        return -1;
    
    app.run();
    return 0;
}