C#で書いた.NET Framework/Mono用のthbgm.dat処理ライブラリ、東方シリーズ音楽抜き出し機のコアライブラリです。

§1 機能概要

主な機能一覧。

  • thbgm.datからのリニアPCMストリーム、WAVEストリームの作成
  • 曲目ファイルの読み込み機能
  • thbgm.datからの作品情報の自動判別

本ライブラリには、以下の作品に関する曲目データが含まれています。

thbgm.datと同様のフォーマットを持つ音楽ファイルであれば、東方シリーズ以外にも対応出来ます。 なお、本ライブラリには抜き出したストリームにフェードアウト等のエフェクトを施す機能は含まれていません。

§2 ダウンロード

東方シリーズ音楽抜き出し機 version 1.4以降に含まれているものを使ってください。

§3 使い方

§3.1 作品情報の取得とストリームの作成

基本的な使い方。

using System;
using System.IO;

using Smdn.Formats.Thbgm;

class Sample {
  static void Main(string[] args)
  {
    // 東方永夜抄の作品情報を取得
    ProductInfo product = ProductInfo.Th08;

    // 作品のタイトルを表示
    Console.WriteLine(product.Title);

    // 1トラック目のタイトルを取得
    Console.WriteLine(product.Tracks[0].Title);

    // ループ部分を3回リピートした1トラック目のストリームを取得
    using (BgmStream stream = product.Tracks[0].GetStream(@"C:\Program Files\東方永夜抄\thbgm.dat", 3)) {
      // ...
    }
  }
}

音楽ファイルから作品情報を自動的に判別して取得するにはProductInfo.FindMatchedProductを使います。

static void Main(string[] args)
{
  ProductInfo product = ProductInfo.FindMatchedProduct(@"C:\Program Files\東方永夜抄\thbgm.dat");

  if (product == null) {
    // ファイルが見つからないか、音楽ファイルに対応する作品情報が見つからなかった
    Console.Error.WriteLine("not found");
    return;
  }

  Console.WriteLine(product.Title);
  Console.WriteLine(product.Tracks[0].Title);

  // 1トラック目のストリームを取得(音楽ファイルのパスは指定しなくてもよい)
  using (BgmStream stream = product.Tracks[0].GetStream(3)) {
    // ...
  }
}

曲目ファイルを読み込む場合はProductInfo.LoadFromを使います。

static void Main(string[] args)
{
  // ライブラリに組み込まれている作品情報をリストに追加
  List<ProductInfo> products = new List<ProductInfo>(ProductInfo.EmbeddedProducts);

  // 曲目ファイルを読み込んでリストに追加
  products.Add(ProductInfo.LoadFrom(@"C:\Users\user\th97.txt"));
  products.Add(ProductInfo.LoadFrom(@"C:\Users\user\th98.txt"));
  products.Add(ProductInfo.LoadFrom(@"C:\Users\user\th99.txt"));

  // 対応する作品情報を取得する
  ProductInfo product = ProductInfo.FindMatchedProduct(@"C:\Users\user\th99\thbgm.dat", products);

  Console.WriteLine(product.Title);
}

§3.2 WAVEストリームの作成

TrackInfo.GetStreamメソッドが返すBgmStreamはRIFF WAVEヘッダを含まないリニアPCMのデータストリームです。 WAVEストリームを作成するにはWaveStream.CreateFromを使います。 WaveStreamはBgmStreamをラップし、Readメソッドが呼ばれる際に必要に応じてRIFF WAVEヘッダを返します。

static void Main(string[] args)
{
  TrackInfo track = ProductInfo.FindMatchedProduct(@"C:\Program Files\東方永夜抄\thbgm.dat").Tracks[13];

  using (WaveStream stream = WaveStream.CreateFrom(track.GetStream(1))) {
    using (SoundPlayer player = new SoundPlayer(stream)) {
      player.PlaySync();
    }
  }
}

また、RIFF WAVEヘッダだけが必要な場合は、WaveStream.CreateRiffWaveHeaderFromを使います。 以下の例は抜き出したリニアPCMのストリームをWAVEファイルとして保存する例です。

static void Main(string[] args)
{
  TrackInfo track = ProductInfo.FindMatchedProduct(@"C:\Program Files\東方永夜抄\thbgm.dat").Tracks[13];

  using (BgmStream inStream = track.GetStream(1)) {
    using (FileStream outStream = File.OpenWrite(string.Format(@"C:\Users\user\{0}.wav", track.Title))) {
      var writer = new BinaryWriter(outStream);

      // RIFF WAVEヘッダを書き込む
      writer.Write(WaveStream.CreateRiffWaveHeaderFrom(inStream));

      // PCMデータを書き込む
      var buffer = new byte[track.StreamFormat.BytesPerSecond];

      for (;;) {
        var read = inStream.Read(buffer, 0, buffer.Length);

        writer.Write(buffer, 0, read);

        if (read <= 0)
          break;
      }

      writer.Flush();
    }
  }
}

§4 曲目ファイルのフォーマット

曲目ファイルは作品に関する情報を含むヘッダ部分と曲ごとの情報を含む部分に分かれます。 書式は次のとおりです。

@で始まる行
音楽ファイル(thbgm.dat)のパス(インストーラのデフォルト設定でインストールされる場所)を表します。 相対パスを指定した場合は%PROGRAMFILES%からの相対パスとして解釈されます。 カンマ以降(パスの後ろ)は製品名を表します。
#=ProductInfoで始まる行
作品に関する情報を表します。 これらの情報はSmdn.Formats.Thbgm独自の拡張情報で、いずれも省略可能です。 東方シリーズ音楽抜き出し機ではこれらの情報を使ってタグ付けを行います。 現在以下のエントリが定義されています。
Creator,hoge
作品の原作者名を表します。
ReleaseDate,yyyy-MM-dd
作品の頒布年月日を表します。
製品略称
製品名の略称を表します。
Prefix,thXX
ファイルのプレフィックスなどに使われる略称を表します。 (例:th08)
ShortName,東方○○○
サブタイトル部分を除いた略称を表します。 (例:東方永夜抄)
AbbreviatedShortName,○○○
シリーズ名を省略した略称を表します。 (例:永夜抄)
ShortestName,
一文字形式の略称を表します。 (例:)
BgmSourceLength,xxxx
音楽ファイルのサイズをバイト単位で表します。 作品情報の自動判別の際に使用されます。
BgmSourceHash,MD5Sum,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
音楽ファイルのMD5ハッシュ値を表します。 音楽ファイルの妥当性検証(現時点では未実装)の際に使用されます。
BgmSourceIdentificationHash,MD5Sum,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
音楽ファイルの末尾4MBytesのMD5ハッシュ値を表します。 作品情報の自動判別の際、BgmSourceLengthだけで判別できない場合に使用されます。
THxxBGMProductGuid,XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
THxxBGMのフェードアウト設定・アプリケーション設定で使用されるGUID値を表します。 東方シリーズ音楽抜き出し機ではTHxxBGMの設定ファイルをインポートする際にこの情報が使用されます。
上記以外のシャープ記号(#)で始まる行
すべてコメントとして扱われます。
上記以外の行
曲ごとの情報を表します。 音楽ファイル上での開始位置(バイト単位)、イントロ部の長さ[Bytes]、ループ部の長さ[Bytes]および曲名の順に記述します。 行頭に「%ファイル名」を付けると、音楽ファイルに個別のwavファイルを指定することができます。

§4.1 曲目ファイルの文字コード

曲目ファイルの文字コードにはShift_JISかBOM付きのUTF-8の使用を推奨します。 本ライブラリでは、読み込み時に文字コードの指定がない場合は文字コードの判別を試みます。 文字コードの判別手順は次のとおりです。

  • BOMがある場合
    • BOMの指定に従って、UTF-8/16BE/16LE/32BE/32LEのいずれかで読み込む
  • BOMが無い場合
    • 曲目ファイル内に"東方", "上海", "曲データ"のいずれかの文字列がある場合
      • それらの文字列からShift_JISかUTF-8かを判別して読み込む
    • いずれの文字列もない場合
      • システムデフォルトの文字コードでエンコードされているものとして読み込む

従って、自動判別で対応している文字コードは次の通りとなります。 これ以外の文字コード(EUC-JP等)の自動判別には現時点では対応していません。

  • Shift_JIS
  • Unicode (UTF-8/16BE/16LE/32BE/32LE)
  • システムデフォルトの文字コード (日本語WindowsではShift_JIS)

§4.2 曲目ファイルの記述例

以下は東方永夜抄製品版の曲目ファイルの例です。

すべての項目を記述した曲目ファイルの例
#「東方永夜抄 ~ Imperishable Night.」 製品版曲データ
#デフォルトのパスと製品名
@東方永夜抄\thbgm.dat,東方永夜抄 ~ Imperishable Night.
#原作者名
#=ProductInfo,Creator,上海アリス幻樂団
#製品略称
#=ProductInfo,Prefix,th08
#=ProductInfo,ShortName,東方永夜抄
#=ProductInfo,AbbreviatedShortName,永夜抄
#=ProductInfo,ShortestName,永
#頒布年月日
#=ProductInfo,ReleaseDate,2004-08-15
#thbgm.datのサイズ(バイト単位)
#=ProductInfo,BgmSourceLength,449961024
#thbgm.datのハッシュ値(MD5)
#=ProductInfo,BgmSourceHash,MD5Sum,38d3aeac961e93014643b064dcb30e3f
#thbgm.datの識別用ハッシュ値(末尾4MBのハッシュ)
#=ProductInfo,BgmSourceIdentificationHash,MD5Sum,6198ac09d529be7bc285459ca490dc93
#THxxBGM製品識別用GUID
#=ProductInfo,THxxBGMProductGuid,881949A4-B453-A741-E8CD-72D1A5741E0F
#曲データ
#開始位置[Bytes]、イントロ部の長さ[Bytes]、ループ部の長さ[Bytes]、曲名
#位置・長さは16進値として記述する
00000010,000f1ac0,00b2ed40,永夜抄 ~ Eastern Night.
00c20810,000aae00,01563b00,幻視の夜 ~ Ghostly Eyes
0222f110,002a8000,00a78000,蠢々秋月 ~ Mooned Insect
02f4f110,00077400,018b5c00,夜雀の歌声 ~ Night Bird
0487c110,0044d680,00be3a80,もう歌しか聞こえない
058ad210,0029d200,00ceae00,懐かしき東方の血 ~ Old World
06835210,0048a600,00eb8400,プレインエイジア
07b77c10,00165200,00ea2e00,永夜の報い ~ Imperishable Night.
08b7fc10,0023acc0,0195d340,少女綺想曲 ~ Dream Battle
0a717c10,001bbc40,013963c0,恋色マスタースパーク
0bc69c10,0011f000,01c3b900,シンデレラケージ ~ Kagome-Kagome
0d9c4510,00082200,013b5c00,狂気の瞳 ~ Invisible Full Moon
0edfc310,00197000,00cf4500,ヴォヤージュ1969
0fc87810,0012d180,01ccb280,千年幻想郷 ~ History of the Moon
12847810,0065ea00,017e8600,竹取飛翔 ~ Lunatic Princess
11a7fc10,00bc9500,001fe700,ヴォヤージュ1970
16763f10,000d7600,019e0700,エクステンドアッシュ ~ 蓬莱人
1821bc10,00145800,01c77f00,月まで届け、不死の煙
1468e810,002f2200,00c26000,月見草
155a6a10,00347e00,00e75700,Eternal Dream ~ 幽玄の槭樹
19fd9310,0010e200,00c36700,東方妖怪小町

省略可能な項目を省略し、最低限必要な項目のみを記述した場合は次のようになります。

最低限必要な項目のみを記述した曲目ファイルの例
@東方永夜抄\thbgm.dat,東方永夜抄 ~ Imperishable Night.
00000010,000f1ac0,00b2ed40,
00c20810,000aae00,01563b00,
0222f110,002a8000,00a78000,
02f4f110,00077400,018b5c00,
0487c110,0044d680,00be3a80,
058ad210,0029d200,00ceae00,
06835210,0048a600,00eb8400,
07b77c10,00165200,00ea2e00,
08b7fc10,0023acc0,0195d340,
0a717c10,001bbc40,013963c0,
0bc69c10,0011f000,01c3b900,
0d9c4510,00082200,013b5c00,
0edfc310,00197000,00cf4500,
0fc87810,0012d180,01ccb280,
12847810,0065ea00,017e8600,
11a7fc10,00bc9500,001fe700,
16763f10,000d7600,019e0700,
1821bc10,00145800,01c77f00,
1468e810,002f2200,00c26000,
155a6a10,00347e00,00e75700,
19fd9310,0010e200,00c36700,

§4.3 トラック毎に音声ファイルを指定する場合の記述例

音声データが個別のwavファイルに分かれている東方紅魔郷の場合や、サウンドトラックCDからリッピングしたwavファイルを音楽ファイルとして使いたい場合は、曲ごとの情報の行の先頭に「%ファイル名」を記述します。 (東方蓄音機互換の機能)

東方紅魔郷など個別のwavファイルからの抜き出しを行う曲目ファイルの例
#「東方紅魔郷 ~ the Embodiment of Scarlet Devil.」 製品版曲データ
#デフォルトのパスと製品名
@東方紅魔郷\bgm\th06_01.wav,東方紅魔郷 ~ the Embodiment of Scarlet Devil.
#曲データ
#ファイル名、開始位置[Bytes]、イントロ部の長さ[Bytes]、ループ部の長さ[Bytes]、曲名
#位置・長さは16進値として記述する
%th06_01.wav,0000002C,001C0E20,008EF1E0,赤より紅い夢
%th06_02.wav,0000002C,00384840,00B237C0,ほおずきみたいに紅い魂
%th06_03.wav,0000002C,000A14C0,008DAB40,妖魔夜行
%th06_04.wav,0000002C,0013FC80,00D90380,ルーネイトエルフ
%th06_05.wav,0000002C,0010A000,00E16000,おてんば恋娘
%th06_06.wav,0000002C,007B9400,00FF6C00,上海紅茶館 ~ Chinese Tea
%th06_07.wav,0000002C,0043F400,00DBCC00,明治十七年の上海アリス
%th06_08.wav,0000002C,00298200,011EF920,ヴワル魔法図書館
%th06_09.wav,0000002C,00732240,00EE4224,ラクトガール ~ 少女密室
%th06_10.wav,0000002C,006C9A00,017F4C80,メイドと血の懐中時計
%th06_11.wav,0000002C,00290CC0,00D47340,月時計 ~ ルナ・ダイアル
%th06_12.wav,0000002C,0009FFC0,009513A0,ツェペシュの幼き末裔
%th06_13.wav,0000002C,0099C400,0121BC90,亡き王女の為のセプテット
%th06_14.wav,0000002C,006E9E00,013C2200,魔法少女達の百年祭
%th06_15.wav,0000002C,00111400,01486C00,U.N.オーエンは彼女なのか?
%th06_16.wav,0000002C,001C7C20,007EC3E0,紅より儚い永遠
%th06_17.wav,0000002C,0017DB30,010E24D0,紅楼 ~ Eastern Dream...

なお、現在の仕様では指定されたwavファイルのフォーマットに関わらず、常にステレオ・16ビット・サンプリングレート44100Hzのフォーマットであるものとして読み込まれます。

§5 その他

現在対応していない作品の曲目ファイルを募集しています。 提供していただける方はご連絡ください。

§6 変更履歴

version 1.6.1
文字コードの自動判別処理を改善
version 1.4
東方シリーズ音楽抜き出し機本体から分離し、ライブラリ化
曲目ファイルのフォーマットを拡張し、製品情報などを含められるようにした

§7 動作状況

以下の環境で動作することを確認済みです。

  • .NET Framework 4.0
  • .NET Framework 3.5
  • Mono 3.2
  • Mono 2.4

§8 謝辞

本ライブラリに含まれる曲目ファイルのうち、下記の曲目ファイルはNautilusさんにご提供頂きました。 お礼申し上げます。

  • 東方文花帖
  • 東方風神録 Web体験版
  • 東方地霊殿 製品版および体験版
  • 東方星蓮船 製品版および体験版
  • 黄昏酒場