このページは『[VC] IMAPI v1(その3)』記事のサンプルコードです。
誤っている箇所がありましたら、記事のコメント欄に連絡願います。
//-----------------------------------------------------------------------------
// main.cpp - IMAPAv1サンプル3 音楽CD作成
// 
// 2007/02/11 … VC2005用サンプル
//-----------------------------------------------------------------------------
#define WIN32_LEAN_AND_MEAN
#include <atlbase.h>
#include <atlfile.h>      // CAtlFile
#include <stdio.h>
#include <tchar.h>
#include <locale.h>       // _tsetlocale()
#include <conio.h>        // _getch()
#include <comdef.h>       // COM support.
#include <imapi.h>        // IMAPI support.
#include <imapierror.h>   // IMAPI error.
#include <string>
#include <vector>

typedef std::basic_string<TCHAR, std::char_traits<TCHAR>, std::allocator<TCHAR> >
    tstring;
typedef std::vector<tstring> FilePaths;

// IMAPI Interface Smart Pointers:
_COM_SMARTPTR_TYPEDEF(IDiscMaster           , __uuidof(IDiscMaster)           );
_COM_SMARTPTR_TYPEDEF(IEnumDiscMasterFormats, __uuidof(IEnumDiscMasterFormats));
_COM_SMARTPTR_TYPEDEF(IEnumDiscRecorders    , __uuidof(IEnumDiscRecorders)    );
_COM_SMARTPTR_TYPEDEF(IDiscRecorder         , __uuidof(IDiscRecorder)         );
_COM_SMARTPTR_TYPEDEF(IRedbookDiscMaster    , __uuidof(IRedbookDiscMaster)    );

// プロトタイプ
void CreateMusicDisc(IDiscMasterPtr& master, FilePaths& files);
bool ReadFileAndAddTrack(
        IRedbookDiscMasterPtr& redbook, tstring& trackfile, ULONG& nTime);
bool SelectDrive(IDiscMasterPtr& master);
void SetWriteSpeed(IDiscRecorderPtr& rec, long speed);

//-----------------------------------------------------------------------------
// エントリーポイント
//-----------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
    FilePaths   files;
    HRESULT hr;

    _tsetlocale( LC_ALL, _T("jpn") );

    hr = ::CoInitialize(NULL);
    ATLASSERT(SUCCEEDED(hr));

    for(int i=1; i<argc; i++)
    {
        if( ::GetFileAttributes( argv[i] ) == -1 )
            continue;
        files.push_back( tstring( argv[i] ) );
    }

    if( files.size() )
    {
        IDiscMasterPtr master;

        hr = master.CreateInstance( CLSID_MSDiscMasterObj );
        ATLASSERT(SUCCEEDED(hr));

        hr = master->Open();
        ATLASSERT(SUCCEEDED(hr));

        // 音楽CDの作成
        CreateMusicDisc( master, files );

        master->Close();

    }else{
        _tprintf_s(_T("waveファイルを指定してください\n"));
    }

    _tprintf_s(_T("...何かキーを押すと終了します"));
    _gettch();

    ::CoUninitialize();
    return 0;
}

//-----------------------------------------------------------------------------
// 音楽CDの作成
//-----------------------------------------------------------------------------
void CreateMusicDisc(
    IDiscMasterPtr& master,
    FilePaths& files)
{
    IRedbookDiscMasterPtr redbook;
    IStoragePtr root;
    HRESULT hr;

    // Redbookフォーマットを指定
    hr = master->SetActiveDiscMasterFormat(
            IID_IRedbookDiscMaster, reinterpret_cast<void**>(&redbook) );
    ATLASSERT(SUCCEEDED(hr));

    // 使用するレコーダーを指定
    if( !SelectDrive( master ) ){
        _tprintf_s(_T("Error! レコーダーの指定に失敗\n"));
        return;
    }

    // waveファイルの読み取り&トラックの追加
    for(int i=0; i<(int)files.size(); i++)
    {
        _tprintf_s(_T("Add \"%s\" ... "), files[i].c_str());
        ULONG nTime;
        if( ReadFileAndAddTrack( redbook, files[i], nTime ) )
            _tprintf_s(_T("%02d:%02d\n"), nTime/60, nTime%60);
        else
            _tprintf_s(_T("NG!\n"));
        Sleep(100);
    }

    long track, used, blocks;
    hr = redbook->GetTotalAudioTracks( &track );
    ATLASSERT(SUCCEEDED(hr));
    hr = redbook->GetUsedAudioBlocks( &used );
    ATLASSERT(SUCCEEDED(hr));
    hr = redbook->GetTotalAudioBlocks( &blocks );
    ATLASSERT(SUCCEEDED(hr));
    _tprintf_s(_T("Total tracks=%d. Used blocks(%d/%d)\n"), track, used, blocks);

    while( track )
    {
        _tprintf_s(_T("Are you record disk? (y/n):"));
        _TINT ch = _gettch();
        _tprintf_s(_T("%c\n"), ch);
        if( ch == _T('y') )
        {
            // ライティング開始
            _tprintf_s(_T("メディアに記録中...\n"));
            hr = master->RecordDisc( false, true );
            ATLASSERT(SUCCEEDED(hr));

            _tprintf_s(_T("処理完了!\n"));
            break;

        }else
        if( ch == _T('n') )
            break;
    }
}

//-----------------------------------------------------------------------------
// 使用するレコーダーを選択
// このサンプルでは、最初に検索されたドライブを使用する
//-----------------------------------------------------------------------------
bool SelectDrive(IDiscMasterPtr& master)
{
    IEnumDiscRecordersPtr recs;
    IDiscRecorderPtr      rec;
    ULONG   cFetched;
    HRESULT hr;

    hr = master->EnumDiscRecorders( &recs );
    ATLASSERT(SUCCEEDED(hr));

    if( recs->Next( 1, &rec, &cFetched ) != S_OK )
        return false;

    // TODO : メディアのチェック

    // 使用するレコーダーの指定
    // メディアが挿入されていないとエラーが発生するので注意
    hr = master->SetActiveDiscRecorder( rec );
    if( FAILED(hr) )
    {
        if(hr == EVENT_E_INVALID_EVENT_CLASS_PARTITION){
            _tprintf_s(_T("Error! EVENT_E_INVALID_EVENT_CLASS_PARTITION\n"));
        }else
        {    // その他エラー
            ATLASSERT(SUCCEEDED(hr));
        }
        return false;
    }

    // 書き込み速度の調整 (x2)
    SetWriteSpeed( rec, 2 );

    return true;
}

//-----------------------------------------------------------------------------
// 書き込み速度の設定
//-----------------------------------------------------------------------------
void SetWriteSpeed(
    IDiscRecorderPtr& rec,
    long speed)
{
    IPropertyStoragePtr prop;
    PROPSPEC iPropSpec;
    PROPVARIANT iPropVariant;
    HRESULT hr;

    hr = rec->GetRecorderProperties( &prop );
    ATLASSERT(SUCCEEDED(hr));

    iPropSpec.ulKind = PRSPEC_LPWSTR;
    iPropSpec.lpwstr = L"WriteSpeed";
    hr = prop->ReadMultiple (1, &iPropSpec, &iPropVariant);
    ATLASSERT(SUCCEEDED(hr));

    // 新しい書き込みスピード値
    iPropVariant.lVal = speed;
    hr = prop->WriteMultiple( 1,
        &iPropSpec, &iPropVariant, iPropVariant.vt );
    ATLASSERT(SUCCEEDED(hr));
    rec->SetRecorderProperties( prop );
}

//-----------------------------------------------------------------------------
// Waveファイル読み取り&トラック追加
//-----------------------------------------------------------------------------
bool ReadFileAndAddTrack(
    IRedbookDiscMasterPtr& redbook,
    tstring& trackfile,
    ULONG& nTime)
{
    CAtlFile file;
    DWORD nRead;
    long track;
    HRESULT hr;

    // 現在のトラック数をチェック
    // (追加できるトラック数は99個まで)
    hr = redbook->GetTotalAudioTracks( &track );
    ATLASSERT(SUCCEEDED(hr));
    if(track == 99)
        return false;

    // ファイル読み取りオープン
    hr = file.Create( trackfile.c_str(), GENERIC_READ, 0, OPEN_EXISTING );
    if( FAILED(hr) )
        return false;

    // riffチャンク読み取り
    struct RIFFChunk{
        char riff[4];
        unsigned long    length;
        char wave[4];
    } riffChunk;

    hr = file.Read( &riffChunk, sizeof( riffChunk ), nRead );
    if( FAILED(hr) )
        return false;
    if( nRead != sizeof( riffChunk ) )
        return false;
    if( _strnicmp( riffChunk.riff, "riff", 4 ) != 0 )
        return false;
    if( _strnicmp( riffChunk.wave, "wave", 4 ) != 0 )
        return false;

    // fmtチャンク読み取り
    struct FormatChunk{
        char fmt_[4];
        unsigned int length;
        unsigned short reserved;
        unsigned short channels;
        unsigned long  sampleRate;
        unsigned long  bytesPerSecond;
        unsigned short bytesPerSample;
        unsigned short bitsPerSample;
    } formatChunk;

    hr = file.Read( &formatChunk, sizeof( formatChunk ), nRead );
    if( FAILED(hr) )
        return false;
    if( nRead != sizeof( formatChunk ) )
        return false;
    if( _strnicmp( formatChunk.fmt_, "fmt", 3 ) != 0 )
        return false;
    if( formatChunk.channels != 0x02 )
        return false;    // チャンネル: ステレオのみ
    if( formatChunk.sampleRate != 44100 )
        return false;    // サンプリングレート: 44.1kHzのみ
    if( formatChunk.length > 0x10 )
    {   // Skip 
        DWORD len = formatChunk.length - 0x10;
        BYTE* b = (BYTE*) malloc( len );
        hr = file.Read( b, len, nRead );
        free( b );
        if( FAILED(hr) )
            return false;
        if( nRead != len )
            return false;
    }

    // dataチャンク読み取り開始
    struct DataChunk{
        char data[4];
        unsigned long length;
    } dataChunk;

    while( true )
    {
        hr = file.Read( &dataChunk, sizeof( dataChunk ), nRead );
        if( FAILED(hr) )
            return false;
        if( nRead != sizeof( dataChunk ) )
            return false;
        if( _strnicmp( dataChunk.data, "data", 4 ) == 0 )
            break;  // ok

        // Skip this chunk
        unsigned long i = 0;
        while( i < dataChunk.length )
        {
            BYTE buffer[16];
            DWORD nToRead = 16;
            if( nToRead > ( dataChunk.length - i ) )
                nToRead = ( dataChunk.length - i );

            hr = file.Read( buffer, nToRead, nRead );
            if( FAILED(hr) )
                return false;
            if( nRead != nToRead )
                return false;
            i += nRead;
        }
    }

    // フレーム数(1フレーム = 2352byte)
    long nBlocks = dataChunk.length / 2352;
    if( dataChunk.length % 2352 )
        nBlocks++;

    // 新しいオーディオトラックの作成
    hr = redbook->CreateAudioTrack( nBlocks );
    ATLASSERT(SUCCEEDED(hr));

    for( int i=0; i<nBlocks; i++ )
    {
        byte blocks[2352] = {0};
        DWORD nToRead = 2352;
        if( i == ( nBlocks - 1 ) )
            nToRead = dataChunk.length % 2352;

        hr = file.Read( blocks, nToRead, nRead );
        if( FAILED(hr) )
            return false;
        if( nRead != nToRead )
            return false;

        // 1フレームづつ書き込む
        // ( 44.1 KHz、16-bitステレオ RAWオーディオサンプル形式)
        hr = redbook->AddAudioTrackBlocks( blocks, 2352 );
        ATLASSERT(SUCCEEDED(hr));
    }

    // オーディオトラックのクローズ
    hr = redbook->CloseAudioTrack();
    ATLASSERT(SUCCEEDED(hr));

    nTime = dataChunk.length / formatChunk.bytesPerSecond;

    return true;
}
今日のジャンク.txt