パッケージ com.lmt.lib.bms

クラス BmsLoader


  • public final class BmsLoader
    extends Object
    外部データからBMSコンテンツを生成するローダーです。

    BMSライブラリは、「外部データ」からBMSコンテンツを読み込む機能を提供します。ここで言う「外部データ」とは、 BMSで記述されたテキストデータのことを指します。外部データはファイル等の何らかの形式で記録されていることを 想定しており、Java言語のInputStreamで読み取ることができるもの全てを指します。

    外部データの記述形式について
    外部データは上述の通り、BMSで記述されたテキストデータです。一般的には「BMSファイル」のことを指します。 BMSライブラリで読み取り可能な記述形式は一般的なBMSの仕様を取り込んでいますが、一部独自の機能を盛り込んでいます。 詳細については以下を参照してください。

    BMS宣言
    BMSの1行目において、";?bms "で始まるコメントを検出した場合、1行目をBMS宣言として解析しようとします。 BMS宣言の構文に誤りがある場合、BMS宣言は通常のコメントとして認識されるようになり、BMS宣言の無いBMSコンテンツとして 読み込まれます。BMS宣言の記述例は以下の通りです。

     ;?bms encoding="UTF-8" rule="BM"

    メタ情報
    BMSの中で「ヘッダ」と呼ばれる宣言をメタ情報として解析します。メタ情報は"#"または"%"で始まる 行が該当します。ただし、BMS仕様で規定されていない名称のメタ情報はBMSコンテンツの情報としては読み込まれません。 それらの行は無視されるか、解析エラーとして報告されます。
    メタ情報はBMSのどこで宣言されていても問題無く読み込むことができます(チャンネルを記述した後でもOK)。 ただし、一般的にはメタ情報を全て宣言した後でチャンネルを記述することがほとんどのようです。
    メタ情報の記述例は以下の通りです。

     #GENRE J-POP
     #TITLE My Love Song
     #BPM 120
     %URL http://www.lm-t.com/
     %MYMETA 00AA00GG00ZZ

    チャンネル
    数字3文字+36進数2文字+":"で始まる行は「チャンネル」として解析します。最初の数字は小節番号、 続く36進数はチャンネル番号を表し、":"の後の記述は当該小節・チャンネルのデータを表します。 チャンネルデータの記述形式はBMS仕様によって定められているため、仕様に違反する記述をした場合、当該チャンネルは 解析エラーとして報告されます。
    一般的にチャンネルは小節番号の若い順で記述されますが、小節番号は前後しても構いません。ただし、BMSの可読性が 著しく低下するので小節番号順に記述することが推奨されます。
    チャンネルの記述例は以下の通りです。

     01002:1.5
     0880A:00AB00CD00EF00GH
     123ZZ:String data channel

    エラーハンドリングについて
    通常、BMSの読み込みにおいてエラー行を検出した場合はその行を無視し、読み込みを続行することがほとんどです。 アプリケーションによっては、特定のエラーを検出した場合例外的に読み込みを中止し、読み込みエラーとして扱いたい ケースがあります。そのような場合はsetHandler(BmsLoadHandler)でハンドラを登録し、発生したエラーに応じて 読み込みの続行・中止を選択することが できます。発生したエラーを蓄積し、エラーをユーザーに報告するようなケースも エラーハンドリングを行うことで解決できます。詳細はBmsLoadHandlerを参照してください。

    拡張したBMSコンテンツオブジェクトを読み込みたい場合
    アプリケーションによっては拡張したBMSコンテンツオブジェクト(BmsContent)を読み込みたいケースが存在します。 BmsLoaderでは読み込み時に、生成するBMSコンテンツオブジェクトを決定することができるようになっています。 setHandler(BmsLoadHandler)で設定したハンドラのBmsLoadHandler.createContent(BmsSpec)を オーバーライドすることによりアプリケーションで独自拡張したBMSコンテンツオブジェクトを返すことができます。

    BOM付きUTF-8で記録されたBMSの読み込みについて
    外部データにBOM(Byte Order Mark)が付与された場合でも正常に読み込むことはできますが、現バージョンのBMSライブラリで 読み込めるのはリトルエンディアンの場合のみです。ビッグエンディアンで記録された外部データはサポートしていません。

    関連項目:
    BmsLoadHandler, BmsScriptError
    • フィールドの詳細

      • DEFAULT_HANDLER

        public static final BmsLoadHandler DEFAULT_HANDLER
        BMSローダのデフォルトハンドラです。具体的な振る舞いはBmsLoadHandlerを参照してください。
    • コンストラクタの詳細

      • BmsLoader

        public BmsLoader()
        BmsLoaderオブジェクトを構築します。
    • メソッドの詳細

      • setSpec

        public final BmsLoader setSpec​(BmsSpec spec)
        読み込み対象BMSのBMS仕様を設定します。

        ローダーは設定されたBMS仕様に従ってBMSの構文を解析します。

        パラメータ:
        spec - BMS仕様
        戻り値:
        このオブジェクトのインスタンス
      • setHandler

        public final BmsLoader setHandler​(BmsLoadHandler handler)
        BMS読み込みハンドラを設定します。

        デフォルトではDEFAULT_HANDLERが設定されています。BMS読み込み時の振る舞いを変えたい場合は 実装をカスタマイズしたBmsLoadHandlerオブジェクトを設定してください。

        nullを設定することは出来ません。nullにした状態でload(java.io.File)メソッドを呼び出すと例外がスローされます。

        パラメータ:
        handler - BMS読み込みハンドラ
        戻り値:
        このオブジェクトのインスタンス
      • setSyntaxErrorEnable

        public final BmsLoader setSyntaxErrorEnable​(boolean isEnable)
        構文エラーの有効状態を設定します。

        BMSでは、メタ情報・チャンネル定義以外の記述は全て無視される仕様になっています。BMS内での不要・不正な記述を 防ぐために、メタ情報・チャンネル定義と認識されない全ての記述を構文エラーとしたい場合に当メソッドを使用します。

        構文エラーを有効にした状態でメタ情報・チャンネル定義以外の記述を検出すると、BMS読み込みハンドラにて解析エラーを 通知するようになります。通知メソッドから解析中止が返されるとBMS解析はエラーとなります。

        この設定は、複数行コメントが終了しない状態でBMSの読み込みが終了した場合(BmsErrorType.COMMENT_NOT_CLOSED)、 およびsetHandler(BmsLoadHandler)で設定したハンドラのBmsLoadHandler.testContent(BmsContent) が検査失敗を返した場合(BmsErrorType.TEST_CONTENT)にも適用されます。

        デフォルトでは構文エラーは「無効」になっています。

        パラメータ:
        isEnable - 構文エラーの有効状態
        戻り値:
        このオブジェクトのインスタンス
      • setFixSpecViolation

        public final BmsLoader setFixSpecViolation​(boolean isFix)
        BMSライブラリの定める仕様に違反した値を自動的に仕様範囲内に丸め込むかどうかを設定します。

        この設定を有効にすることで訂正される値とは、「初期BPM」「小節長」「BPM変更用のBPM」「譜面停止時間」を指します。 それぞれの値の許容範囲はBmsSpecを参照してください。

        この設定のデフォルト値は false です。BMSライブラリ仕様の違反を検出するとローダーに設定されたBmsLoadHandler に対してエラー通知を行います。その際のエラー種別はBmsErrorType.SPEC_VIOLATIONとなります。

        通常、BMSライブラリの仕様違反となる値は非常に極端な値となっており、値を訂正したとしても当該楽曲の再生には 大きな影響がない場合がほとんどですが、値の使い方次第では楽曲の構成を大きく崩してしまう可能性があります。そのような ケースが許容されない場合には仕様違反の訂正は行わず、当該楽曲の読み込みはエラーとして扱うべきです。

        この設定を有効にして読み込まれたBMSは定義上とは異なるデータとして読み込まれますので、BmsContent.generateHash() が生成する値にも影響を及ぼします。

        デフォルトではこの設定は「有効」になっています。

        パラメータ:
        isFix - 仕様違反訂正の有効状態
        戻り値:
        このオブジェクトのインスタンス
      • setAllowRedefine

        public final BmsLoader setAllowRedefine​(boolean isAllow)
        メタ情報・重複不可チャンネルの再定義を検出した場合のデータ上書きを許可するかどうかを設定します。

        データ上書きを許可すると、先に定義されたメタ情報、または同じ小節の重複不可チャンネルデータを上書きするようになります。 メタ情報は単体メタ情報(BmsUnit.SINGLE)と定義済みの索引付きメタ情報(BmsUnit.INDEXED)が対象です。 重複不可チャンネルでは、例えば以下のような定義を行った場合に上の行の定義は完全に上書きされ、 存在しなかったものとして処理されます。

         #003XY:11001100  ;上書きされ、無かったことになる
         #003XY:22002222  ;上書きされ、無かったことになる
         #003XY:00330033  ;この行のみが有効になる

        この設定は値型・配列型チャンネルの両方に適用されます。

        再定義が不許可の状態でメタ情報・重複不可チャンネルの再定義が検出された場合、再定義された行はエラーとして処理され、 BMSコンテンツ読み込みハンドラのBmsLoadHandler.parseError(BmsScriptError)が呼び出されます。 エラーはBmsErrorType.REDEFINEとして通知されます。

        パラメータ:
        isAllow - 再定義の許可有無
        戻り値:
        このオブジェクトのインスタンス
      • setIgnoreUnknownMeta

        public final BmsLoader setIgnoreUnknownMeta​(boolean isIgnore)
        不明なメタ情報を無視するかどうかを設定します。

        無視すると、BMS解析はエラーにならず不明メタ情報を読み飛ばして解析を続行するようになります。

        具体的には、setHandler(BmsLoadHandler)で設定したハンドラのBmsLoadHandler.parseError(BmsScriptError)BmsErrorType.UNKNOWN_METAのエラーが一切通知されなくなります。

        デフォルトではこの設定は「有効」になっています。

        パラメータ:
        isIgnore - 不明メタ情報を無視するかどうか
        戻り値:
        このオブジェクトのインスタンス
      • setIgnoreUnknownChannel

        public final BmsLoader setIgnoreUnknownChannel​(boolean isIgnore)
        不明なチャンネルを無視するかどうかを設定します。

        無視すると、BMS解析はエラーにならず不明チャンネルを読み飛ばして解析を続行するようになります。

        具体的には、setHandler(BmsLoadHandler)で設定したハンドラのBmsLoadHandler.parseError(BmsScriptError)BmsErrorType.UNKNOWN_CHANNELのエラーが一切通知されなくなります。

        デフォルトではこの設定は「有効」になっています。

        パラメータ:
        isIgnore - 不明チャンネルを無視するかどうか
        戻り値:
        このオブジェクトのインスタンス
      • setIgnoreWrongData

        public final BmsLoader setIgnoreWrongData​(boolean isIgnore)
        不正なデータを無視するかどうかを設定します。

        無視すると、BMS解析はエラーにならず不正データ定義のあったメタ情報・チャンネルを読み飛ばして解析を 続行するようになります。

        具体的には、setHandler(BmsLoadHandler)で設定したハンドラのBmsLoadHandler.parseError(BmsScriptError)BmsErrorType.WRONG_DATAのエラーが一切通知されなくなります。

        デフォルトではこの設定は「有効」になっています。

        パラメータ:
        isIgnore - 不正データを無視するかどうか
        戻り値:
        このオブジェクトのインスタンス
      • setSkipReadTimeline

        public final BmsLoader setSkipReadTimeline​(boolean isSkip)
        タイムラインの読み込みをスキップするかどうかを設定します。

        この設定を有効にするとタイムラインの定義を読み飛ばすようになり、BMSコンテンツに小節データとノートが 含まれなくなります。つまり、BMSコンテンツに取り込まれるのはBMS宣言とメタ情報のみなることを意味します。

        読み込み対象のBMSに含まれるメタ情報のみを参照したい場合は、この設定を有効にすることで 読み込み処理のパフォーマンス向上が期待できます。

        タイムラインの読み込みをスキップする場合、タイムライン(チャンネル定義)の行の小節番号とチャンネル番号定義の 書式が正しければ、誤った値(BmsErrorType.WRONG_DATAになる状態)を定義していたとしてもスキップされます。 ただし、小節番号、チャンネル番号のいずれかが誤った書式で定義されていた場合、その行はスキップされず 構文エラー(BmsErrorType.SYNTAX)として扱われます。

        デフォルトではこの設定は「無効」になっています。

        パラメータ:
        isSkip - タイムラインの読み込みをスキップするかどうか
        戻り値:
        このオブジェクトのインスタンス
      • load

        public final BmsContent load​(File bms)
                              throws BmsException
        BMSコンテンツを読み込みます。

        BMSコンテンツは指定されたファイルから読み込みます。

        読み込み処理の詳細はload(String)を参照してください。

        パラメータ:
        bms - BMSファイル
        戻り値:
        BMSコンテンツ
        例外:
        BmsException - bmsがnull: Cause NullPointerException
        BmsException - load(String)を参照
      • load

        public final BmsContent load​(Path bms)
                              throws BmsException
        BMSコンテンツを読み込みます。

        BMSコンテンツは指定されたパスが示すファイルから読み込みます。

        読み込み処理の詳細はload(String)を参照してください。

        パラメータ:
        bms - BMSファイルのパス
        戻り値:
        BMSコンテンツ
        例外:
        BmsException - bmsがnull: Cause NullPointerException
        BmsException - load(String)を参照
      • load

        public final BmsContent load​(InputStream bms)
                              throws BmsException
        BMSコンテンツを読み込みます。

        BMSコンテンツは指定された入力ストリームから読み込みます。

        読み込み処理の詳細はload(String)を参照してください。

        パラメータ:
        bms - BMSの入力ストリーム
        戻り値:
        BMSコンテンツ
        例外:
        BmsException - bmsがnull: Cause NullPointerException
        BmsException - load(String)を参照
      • load

        public final BmsContent load​(byte[] bms)
                              throws BmsException
        BMSコンテンツを読み込みます。

        BMSコンテンツは指定されたバイト配列から読み込みます。

        読み込み処理の詳細はload(String)を参照してください。

        パラメータ:
        bms - BMSのバイト配列
        戻り値:
        BMSコンテンツ
        例外:
        BmsException - bmsがnull: Cause NullPointerException
        BmsException - load(String)を参照
      • load

        public final BmsContent load​(Reader bms)
                              throws BmsException
        BMSコンテンツを読み込みます。

        File / Path / InputStream / byte[]が入力となる場合、 BmsLoaderでは最初に先頭行のBMS宣言を解析します。BMS宣言が存在し、encoding要素が存在する場合はその設定値から 使用する文字セットを解決します。以後の読み込みは当該文字セットを用いて文字列をデコードし、BMS解析を行います。 ただし、入力にBOM(Byte Order Mark)が付いている場合はUTF-8で入力をデコードし、encoding要素は "UTF-8" に設定・上書きします。

        上記の条件に該当しない場合は全てBmsSpec.getStandardCharset()で取得できる文字セットを用いて BMSをデコードし、解析を行います。

        BMS宣言は左から順に解析し、その順番でBMSコンテンツにセットされます。また、BMS解析の動作仕様は概ね以下の通りです。

        • 行頭の半角スペースおよびタブは無視されます。
        • 半角スペースおよびタブのみの行は空行として読み飛ばします。
        • 改行コードは<CR>, <LF>, <CR><LF>を自動認識します。
        • 先頭行において、";bms? "で始まる場合はBMS宣言として認識されます。
        • ";"、"*"、または"//"で始まる行はコメント行として認識されます。(単一行コメント)
        • "/*"で始まる行は複数行コメントの開始行として認識されます。以降、行末に"* /"が出現するまでの 行は全てコメントとして認識されます。
        • 複数行コメントが閉じられずにBMS解析が終了した場合、エラーハンドラにてBmsErrorType.COMMENT_NOT_CLOSED が通知されます。
        • "#"または"%"で始まり、1文字目がアルファベットで始まる行をメタ情報の定義と見なします。
        • "#"に続き3文字の半角数字で始まり、次に2文字の半角英数字、更にその次が":"で始まる行をチャンネルデータの定義と見なします。
        • 以上のパターンに該当しない行は構文エラーとし、エラーハンドラにてBmsErrorType.SYNTAXが通知されます。

        メタ情報解析について

        • メタ情報の値は、文字列の右側の半角空白文字は消去されます。
        • 索引付きメタ情報は、名称の末端文字2文字を36進数値と見なしてその値をインデックス値とし、残りの文字を名称として扱います。
        • 索引付きメタ情報のインデックス値が36進数値でない場合、エラーハンドラにてBmsErrorType.UNKNOWN_METAが通知されます。
        • BMS仕様に規定されていない名称を検出した場合、エラーハンドラにてBmsErrorType.UNKNOWN_METAが通知されます。
        • メタ情報の値がBMS仕様に規定されたデータ型の記述書式に適合しない場合、エラーハンドラにてBmsErrorType.WRONG_DATAが通知されます。

        チャンネル解析について

        • チャンネル番号がBMS仕様に未定義の場合、エラーハンドラにてBmsErrorType.UNKNOWN_CHANNELが通知されます。
        • 以下のケースを検出した場合、エラーハンドラにてBmsErrorType.WRONG_DATAが通知されます。
          • チャンネルに定義されたデータの記述書式がBMS仕様に違反している場合。
          • データ重複許可チャンネルの同小節番号内にてBmsSpec.CHINDEX_MAX+1個を超えるデータ定義を検出した場合。
          • 配列型チャンネルデータの配列要素数が当該小節の刻み総数より多い場合。
          • 配列型チャンネルデータの配列要素数が0。
        パラメータ:
        bms - BMSのReader
        戻り値:
        BMSコンテンツ
        例外:
        BmsException - bmsがnull: Cause NullPointerException
        BmsException - BMS仕様が設定されていない: Cause IllegalStateException
        BmsException - ハンドラが設定されていない: Cause IllegalStateException
        BmsLoadException - ハンドラ(BmsLoadHandler.parseError(com.lmt.lib.bms.BmsScriptError))がfalseを返した
      • load

        public final BmsContent load​(String bms)
                              throws BmsException
        BMSコンテンツを読み込みます。

        BmsLoaderでは、最初に先頭行のBMS宣言を解析します。BMS宣言が存在し、encoding要素が存在する場合はその設定値から 使用する文字セットを解決します。

        パラメータ:
        bms - BMSの文字列
        戻り値:
        BMSコンテンツ
        例外:
        BmsException - bmsがnull: Cause NullPointerException
        BmsException - BMS仕様が設定されていない: Cause IllegalStateException
        BmsException - BMS読み込みハンドラが設定されていない: Cause IllegalStateException
        BmsException - ハンドラが設定されていない: Cause IllegalStateException
        BmsException - BMS宣言にてencoding指定時、指定の文字セットが未知: Cause Exception
        BmsLoadException - ハンドラ(BmsLoadHandler.parseError(com.lmt.lib.bms.BmsScriptError))がfalseを返した