このページは『[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