bms_utils/
bms.rs

1pub(crate) mod lex;
2pub(crate) mod parse;
3pub(crate) mod token;
4pub use token::Channel;
5
6/// ファイルを解析したままのBMS
7///
8/// ランダム要素を確定していない。
9/// [`RawBms::make_bms`]で疑似乱数生成器を指定してBMSを生成する
10#[derive(Debug, Clone, PartialEq, Default)]
11pub struct RawBms {
12    raw_bms: BmsBlock,
13    all_wav_files: HashSet<String>,
14}
15
16#[derive(Debug, Clone, PartialEq, Default)]
17pub(crate) struct BmsBlock(Vec<BmsElement>);
18#[derive(Debug, Clone, PartialEq)]
19pub(crate) enum BmsElement {
20    Command(token::Command),
21    Random(BmsRandomBlock),
22    Switch(BmsSwitchBlock),
23}
24#[derive(Debug, Clone, PartialEq)]
25pub(crate) struct BmsRandomBlock(RandomValue, Vec<BmsRandomElement>);
26#[derive(Debug, Clone, PartialEq)]
27pub(crate) enum BmsRandomElement {
28    Block(BmsBlock),
29    IfBlock(BmsIfBlock),
30}
31#[derive(Debug, Clone, Default, PartialEq)]
32pub(crate) struct BmsIfBlock {
33    pub(crate) r#if: Vec<(u128, BmsBlock)>,
34    pub(crate) r#else: Option<BmsBlock>,
35}
36#[derive(Debug, Clone, PartialEq)]
37pub(crate) struct BmsSwitchBlock(
38    RandomValue,
39    Vec<BmsCaseBlock>,
40    std::collections::HashSet<u128>,
41);
42#[derive(Debug, Clone, PartialEq)]
43pub(crate) struct BmsCaseBlock(SwitchLabel, BmsBlock, bool);
44#[derive(Debug, Clone, PartialEq)]
45pub(crate) enum RandomValue {
46    Max(u128),
47    Set(u128),
48}
49#[derive(Debug, Clone, PartialEq)]
50pub(crate) enum SwitchLabel {
51    Case(u128),
52    Default,
53}
54impl BmsBlock {
55    pub(crate) fn get_token_vec<'a, Rng: rand::RngCore>(
56        &'a self,
57        output: &mut Vec<&'a token::Command>,
58        rng: &mut Rng,
59    ) {
60        for e in &self.0 {
61            e.get_token_vec(output, rng);
62        }
63    }
64}
65impl BmsElement {
66    fn get_token_vec<'a, Rng: rand::RngCore>(
67        &'a self,
68        output: &mut Vec<&'a token::Command>,
69        rng: &mut Rng,
70    ) {
71        match self {
72            BmsElement::Command(c) => {
73                output.push(c);
74            }
75            BmsElement::Random(rb) => {
76                rb.get_token_vec(output, rng);
77            }
78            BmsElement::Switch(sb) => {
79                sb.get_token_vec(output, rng);
80            }
81        }
82    }
83}
84impl BmsRandomBlock {
85    fn get_token_vec<'a, Rng: rand::RngCore>(
86        &'a self,
87        output: &mut Vec<&'a token::Command>,
88        rng: &mut Rng,
89    ) {
90        use rand::Rng;
91        let n = match self.0 {
92            RandomValue::Max(n) => rng.random_range(1..=n),
93            RandomValue::Set(n) => n,
94        };
95        for e in &self.1 {
96            e.get_token_vec(output, rng, n);
97        }
98    }
99}
100impl BmsRandomElement {
101    fn get_token_vec<'a, Rng: rand::RngCore>(
102        &'a self,
103        output: &mut Vec<&'a token::Command>,
104        rng: &mut Rng,
105        n: u128,
106    ) {
107        match self {
108            BmsRandomElement::Block(b) => {
109                b.get_token_vec(output, rng);
110            }
111            BmsRandomElement::IfBlock(ib) => {
112                ib.get_token_vec(output, rng, n);
113            }
114        }
115    }
116}
117impl BmsIfBlock {
118    fn get_token_vec<'a, Rng: rand::RngCore>(
119        &'a self,
120        output: &mut Vec<&'a token::Command>,
121        rng: &mut Rng,
122        n: u128,
123    ) {
124        for (i, b) in &self.r#if {
125            if *i == n {
126                b.get_token_vec(output, rng);
127                return;
128            }
129        }
130        if let Some(b) = &self.r#else {
131            b.get_token_vec(output, rng);
132        }
133    }
134}
135impl BmsSwitchBlock {
136    fn get_token_vec<'a, Rng: rand::RngCore>(
137        &'a self,
138        output: &mut Vec<&'a token::Command>,
139        rng: &mut Rng,
140    ) {
141        use rand::Rng;
142        let n = match self.0 {
143            RandomValue::Max(n) => rng.random_range(1..=n),
144            RandomValue::Set(n) => n,
145        };
146        let mut flag = false;
147        for e in &self.1 {
148            if match &e.0 {
149                SwitchLabel::Case(i) => *i == n,
150                SwitchLabel::Default => !self.2.contains(&n),
151            } {
152                flag = true;
153            }
154            if flag {
155                e.1.get_token_vec(output, rng);
156            }
157            if flag && e.2 {
158                return;
159            }
160        }
161    }
162}
163
164use std::collections::{HashMap, HashSet};
165impl RawBms {
166    pub fn parse(source: &str) -> RawBms {
167        use token::*;
168        use winnow::prelude::*;
169        let token_stream = lex::lex(source);
170        let all_wav_files = token_stream
171            .iter()
172            .filter_map(|t| {
173                if let Token::Command(Command::Wav(_, file)) = t {
174                    Some(file.clone())
175                }
176                else {
177                    None
178                }
179            })
180            .collect::<HashSet<_>>();
181        RawBms {
182            raw_bms: parse::block
183                .parse_next(&mut token_stream.as_slice())
184                .unwrap(),
185            all_wav_files,
186        }
187    }
188    pub fn all_wav_files(&self) -> &HashSet<String> {
189        &self.all_wav_files
190    }
191    #[allow(deprecated)]
192    pub fn make_bms(&self, mut rng: impl rand::RngCore) -> Bms<'_> {
193        use token::Command::*;
194        let mut commands = vec![];
195        self.raw_bms.get_token_vec(&mut commands, &mut rng);
196
197        let base62 = commands.iter().any(|c| matches!(c, Base62));
198
199        let mut bms = Bms {
200            main_data: Vec::with_capacity(1000),
201            ..Default::default()
202        };
203
204        let convert_channel_vec = |ch_vec: &[Channel]| {
205            ch_vec
206                .iter()
207                .map(|ch| ch.to_base_36_or_62(base62))
208                .collect::<Vec<_>>()
209        };
210        for c in commands {
211            match c {
212                MainData(measure, data) => {
213                    if bms.main_data.len() <= *measure {
214                        bms.main_data
215                            .resize_with(measure + 1, Default::default);
216                    }
217                    let measure = &mut bms.main_data[*measure];
218                    use token::MainDataValue::*;
219                    #[rustfmt::skip]
220                    match data {
221                        Bgm(data) =>
222                            measure.bgm.push(convert_channel_vec(data)),
223                        Length(n) =>
224                            measure.length = *n,
225                        Bga(data) =>
226                            measure.bga.push(convert_channel_vec(data)),
227                        Bpm(data) =>
228                            measure.bpm.push(data),
229                        BgaPoor(data) =>
230                            measure.bga_poor.push(convert_channel_vec(data)),
231                        BgaLayer(data) =>
232                            measure.bga_layer.push(convert_channel_vec(data)),
233                        ExBpm(data) =>
234                            measure.ex_bpm.push(convert_channel_vec(data)),
235                        Stop(data) =>
236                            measure.stop.push(convert_channel_vec(data)),
237                        BgaLayer2(data) =>
238                            measure.bga_layer2.push(convert_channel_vec(data)),
239                        ExRank(data) =>
240                            measure.ex_rank.push(convert_channel_vec(data)),
241                        BgaAlpha(data) =>
242                            measure.bga_alpha.push(data),
243                        BgaLayerAlpha(data) =>
244                            measure.bga_layer_alpha.push(data),
245                        BgaLayer2Alpha(data) =>
246                            measure.bga_layer2_alpha.push(data),
247                        BgaPoorAlpha(data) =>
248                            measure.bga_poor_alpha.push(data),
249                        Note(ch, data) =>
250                            measure.notes.entry(*ch).or_default().push(convert_channel_vec(data)),
251                        InvisibleNote(ch, data) =>
252                            measure.invisible_notes.entry(*ch).or_default().push(convert_channel_vec(data)),
253                        LongNote(ch, data) =>
254                            measure.long_notes.entry(*ch).or_default().push(convert_channel_vec(data)),
255                        Text(data) =>
256                            measure.text.push(convert_channel_vec(data)),
257                        BgaArgb(data) =>
258                            measure.bga_argb.push(convert_channel_vec(data)),
259                        BgaLayerArgb(data) =>
260                            measure.bga_layer_argb.push(convert_channel_vec(data)),
261                        BgaLayer2Argb(data) =>
262                            measure.bga_layer2_argb.push(convert_channel_vec(data)),
263                        BgaPoorArgb(data) =>
264                            measure.bga_poor_argb.push(convert_channel_vec(data)),
265                        SwitchBga(data) =>
266                            measure.switch_bga.push(convert_channel_vec(data)),
267                        Option(data) =>
268                            measure.option.push(convert_channel_vec(data)),
269                        Landmine(ch, data) =>
270                            measure.landmine.entry(*ch).or_default().push(data),
271                        Scroll(data) =>
272                            measure.scroll.push(convert_channel_vec(data)),
273                        Speed(data) =>
274                            measure.speed.push(convert_channel_vec(data)),
275                        Other(ch, data) =>
276                            measure.other.push((*ch, data)),
277                    };
278                }
279                Player(n) => {
280                    bms.player = Some(match n {
281                        1 => PlayType::SinglePlay,
282                        2 => PlayType::CouplePlay,
283                        3 => PlayType::DoublePlay,
284                        4 => PlayType::BattlePlay,
285                        _ => unreachable!(),
286                    });
287                }
288                Rank(n) => bms.rank = Some(*n),
289                DefExRank(n) => bms.def_ex_rank = Some(*n),
290                ExRank(ch, n) => {
291                    bms.ex_rank.insert(ch.to_base_36_or_62(base62), *n);
292                }
293                Total(n) => bms.total = Some(*n),
294                VolumeWav(n) => bms.volume_wav = Some(*n),
295                StageFile(s) => bms.stage_file = Some(s),
296                Banner(s) => bms.banner = Some(s),
297                BackBmp(s) => bms.back_bmp = Some(s),
298                CharacterFile(s) => bms.character_file = Some(s),
299                PlayLevel(n) => bms.play_level = Some(*n),
300                Difficulty(n) => bms.difficulty = Some(*n),
301                Title(s) => bms.title = Some(s),
302                SubTitle(s) => bms.sub_title.push(s),
303                Artist(s) => bms.artist = Some(s),
304                SubArtist(s) => bms.sub_artist.push(s),
305                Maker(s) => bms.maker = Some(s),
306                Genre(s) => bms.genre = Some(s),
307                Comment(s) => bms.comment.push(s),
308                Text(ch, s) => {
309                    bms.text.insert(ch.to_base_36_or_62(base62), s);
310                }
311                PathWav(s) => bms.path_wav = Some(s),
312                Bpm(n) => bms.bpm = Some(*n),
313                ExBpm(ch, n) => {
314                    bms.ex_bpm.insert(ch.to_base_36_or_62(base62), *n);
315                }
316                BaseBpm(n) => bms.base_bpm = Some(*n),
317                Stop(ch, n) => {
318                    bms.stop.insert(ch.to_base_36_or_62(base62), *n);
319                }
320                Stp(x, y, z) => bms.stp.push((*x, *y, *z)),
321                LnMode(n) => bms.ln_mode = Some(*n),
322                LnType(n) => bms.ln_type = Some(*n),
323                LnObject(ch) => {
324                    bms.ln_object.insert(ch.to_base_36_or_62(base62));
325                }
326                OctFp => bms.oct_fp = true,
327                Option(opt) => bms.option.push(opt),
328                ChangeOption(ch, opt) => {
329                    bms.change_option.insert(ch.to_base_36_or_62(base62), opt);
330                }
331                Wav(ch, s) => {
332                    bms.wav.insert(ch.to_base_36_or_62(base62), s);
333                }
334                WavCommand(opt, ch, v) => {
335                    bms.wav_command.push((
336                        *opt,
337                        ch.to_base_36_or_62(base62),
338                        *v,
339                    ));
340                }
341                ExWav(ch, opt, s) => {
342                    bms.ex_wav.insert(ch.to_base_36_or_62(base62), (opt, s));
343                }
344                Cdda(n) => bms.cdda = Some(*n),
345                MidiFile(s) => bms.midi_file = Some(s),
346                Bmp(ch, s) => {
347                    bms.bmp.insert(ch.to_base_36_or_62(base62), s);
348                }
349                ExBmp(ch, argb, s) => {
350                    bms.ex_bmp.insert(ch.to_base_36_or_62(base62), (argb, s));
351                }
352                Bga(ch, bmp, pos) => {
353                    bms.bga.insert(
354                        ch.to_base_36_or_62(base62),
355                        (bmp.to_base_36_or_62(base62), pos),
356                    );
357                }
358                AtBga(ch, bmp, pos) => {
359                    bms.at_bga.insert(
360                        ch.to_base_36_or_62(base62),
361                        (bmp.to_base_36_or_62(base62), pos),
362                    );
363                }
364                PoorBga(n) => bms.poor_bga = Some(*n),
365                SwitchBga(ch, fr, time, line, r#loop, argb, data) => {
366                    bms.switch_bga.insert(
367                        ch.to_base_36_or_62(base62),
368                        (*fr, *time, line.to_base_36(), *r#loop, argb, data),
369                    );
370                }
371                Argb(ch, argb) => {
372                    bms.argb.insert(ch.to_base_36_or_62(base62), argb);
373                }
374                VideoFile(s) => bms.video_file = Some(s),
375                VideoFps(n) => bms.video_fps = Some(*n),
376                VideoColors(n) => bms.video_colors = Some(*n),
377                VideoDelay(n) => bms.video_delay = Some(*n),
378                Movie(s) => bms.movie = Some(s),
379                Seek(ch, n) => {
380                    bms.seek.insert(ch.to_base_36_or_62(base62), *n);
381                }
382                ExCharacter(sprite_num, bmp, trim_rect, offset, abs_pos) => {
383                    bms.ex_character = Some(super::bms::ExCharacter {
384                        sprite_num: *sprite_num,
385                        bmp: *bmp,
386                        trim_rect,
387                        offset: offset.as_ref(),
388                        abs_pos: abs_pos.as_ref(),
389                    });
390                }
391                Url(s) => bms.url = Some(s),
392                Email(s) => bms.email = Some(s),
393                Scroll(ch, n) => {
394                    bms.scroll.insert(ch.to_base_36_or_62(base62), *n);
395                }
396                Speed(ch, n) => {
397                    bms.speed.insert(ch.to_base_36_or_62(base62), *n);
398                }
399                Preview(s) => bms.preview = Some(s),
400                Other(command, value) => {
401                    bms.other.push((command, value));
402                }
403                _ => (),
404            }
405        }
406        bms
407    }
408}
409
410/// ランダムを考慮したBMS
411#[derive(Default, Debug, PartialEq)]
412pub struct Bms<'a> {
413    /// メインデータ
414    ///
415    /// mmmcc:chchch...
416    ///
417    /// mmm : 小節数 [0-9]
418    ///
419    /// cc : チャンネル [0-9, A-Z, a-z]
420    ///
421    /// chchch.. : メインのデータで、2文字一組として扱う [0-9, A-Z, a-z]
422    pub main_data: Vec<MainData<'a>>,
423    /// 判定幅
424    ///
425    /// 2を基本とするのが主流だが、その幅は実装依存
426    pub rank: Option<i32>,
427    /// より細かい判定幅
428    ///
429    /// 100をRank2と同じとするのが主流だが、
430    /// Rankの1に相当する数が実装依存
431    pub def_ex_rank: Option<f64>,
432    /// ゲージ増加の総数
433    ///
434    /// 全て最良判定のときのゲージの増加量
435    pub total: Option<f64>,
436    /// 譜面全体の音量
437    pub volume_wav: Option<f64>,
438    /// ロード画面に表示する画像
439    pub stage_file: Option<&'a str>,
440    /// 選曲画面やリザルト画面に表示する横長の画像
441    pub banner: Option<&'a str>,
442    /// ステージファイルに重ねる画像
443    ///
444    /// 選曲後カバー等の調整をする画面で、
445    /// ステージファイルにタイトルの代わりに重ねる
446    pub back_bmp: Option<&'a str>,
447    /// レベル
448    pub play_level: Option<i32>,
449    /// 難易度
450    ///
451    /// 主流な名付けは
452    ///
453    /// 1 : EASY, BEGINNER, LIGHT ...
454    ///
455    /// 2 : NORMAL, STANDARD ...
456    ///
457    /// 3 : HARD, HYPER ...
458    ///
459    /// 4 : EX, ANOTHER ...
460    ///
461    /// 5 : BLACK_ANOTHER, INSANE, 発狂 ...
462    pub difficulty: Option<i32>,
463    /// タイトル
464    pub title: Option<&'a str>,
465    /// サブタイトル
466    pub sub_title: Vec<&'a str>,
467    /// アーティスト
468    pub artist: Option<&'a str>,
469    /// サブアーティスト
470    pub sub_artist: Vec<&'a str>,
471    /// ジャンル名
472    pub genre: Option<&'a str>,
473    /// 基本BPM
474    ///
475    /// 曲選択時の表示や曲の最初のBPMとして使う
476    pub bpm: Option<f64>,
477    /// BPM変化用
478    ///
479    /// BPM変化時に256以上の値を指定したいとき、
480    /// 08チャンネルでidを指定する
481    pub ex_bpm: HashMap<usize, f64>,
482    /// 停止
483    ///
484    /// 譜面を停止するときに09チャンネルでidを指定する
485    pub stop: HashMap<usize, f64>,
486    /// LNの判定方法
487    ///
488    /// 1 : LN, 始点判定が基準で、最後まで押し切らないとPOOR
489    ///
490    /// 2 : CN, 始点判定と終点判定がある
491    ///
492    /// 3 : HCN, CHの判定に、押している間16分ごとに判定を追加したもの
493    pub ln_mode: Option<i32>,
494    /// LNの指定方法
495    ///
496    /// 1 : 主流の指定方法
497    ///
498    /// メインデータの0以外のidをLNの始点終点の繰り返しとして解析
499    ///
500    /// 2 : 非推奨な指定方法
501    ///
502    /// メインデータの0以外のidが続く部分をLNとして解析
503    ///
504    /// 例
505    ///
506    /// 1 : 0011000000002200
507    ///
508    /// 2 : 0011111111220000
509    pub ln_type: Option<i32>,
510    /// LNの音を鳴らす終点idの指定
511    ///
512    /// LNTYPE 1 で終点として使うと、音が鳴るようになる
513    pub ln_object: HashSet<usize>,
514    /// 音声ファイル
515    ///
516    /// 詳細はメインデータ等に記載
517    pub wav: HashMap<usize, &'a str>,
518    /// 画像ファイル
519    ///
520    /// 詳細はメインデータ等に記載
521    pub bmp: HashMap<usize, &'a str>,
522    /// BMS制作者のホームページ
523    pub url: Option<&'a str>,
524    /// BMS制作者のEメール
525    pub email: Option<&'a str>,
526    /// 譜面速度
527    pub scroll: HashMap<usize, f64>,
528    /// 譜面速度
529    ///
530    /// SCROLLと違って線形補間がされる
531    pub speed: HashMap<usize, f64>,
532    /// 曲選択時に流れる音声
533    ///
534    /// ここで指定されていなければ、
535    /// previewと名前が付いた音声ファイルを流すのが主流
536    pub preview: Option<&'a str>,
537
538    // 以降あまり使われないコマンド
539    /// メインデータで指定可能な判定幅の設定
540    ///
541    /// 値はDefExRankと同じ扱いをすることが主流だが、DefExRankと同じように判定幅が実装依存
542    pub ex_rank: HashMap<usize, f64>,
543    pub character_file: Option<&'a str>,
544    /// 譜面制作者
545    pub maker: Option<&'a str>,
546    /// 曲選択時に表示するコメント
547    pub comment: Vec<&'a str>,
548    /// プレイ中に表示するテキスト
549    pub text: HashMap<usize, &'a str>,
550    /// 音声ファイルを読み込むときに参照するフォルダ
551    pub path_wav: Option<&'a str>,
552    /// 譜面の停止
553    ///
554    /// (小節数, 1000等分した小節内の位置, 停止ms)
555    ///
556    /// 位置が一致するコマンドが複数あったら停止時間は合計時間を参照する
557    pub stp: Vec<(usize, u32, f64)>,
558    /// オクターブモード / フットペダルモード
559    pub oct_fp: bool,
560    /// オプション適用
561    pub option: Vec<&'a str>,
562    /// オプション適用(譜面内で動的変更)
563    ///
564    /// チャンネルは"A6"
565    pub change_option: HashMap<usize, &'a str>,
566    /// WAVを加工する
567    ///
568    /// (ID, index, value)
569    ///
570    /// ID: 0.ピッチ 1.ボリューム 2.再生時間
571    ///
572    /// index: WAVコマンドのindex
573    ///
574    /// value: 0.基準は60で、1を半音と対応 1.パーセントで解釈 2.ミリ秒(0で変更なし)
575    pub wav_command: Vec<(i32, usize, f64)>,
576    pub ex_wav: HashMap<usize, (&'a [Option<f64>; 3], &'a str)>,
577    pub cdda: Option<u32>,
578    pub midi_file: Option<&'a str>,
579    pub ex_bmp: HashMap<usize, (&'a [u8; 4], &'a str)>,
580    pub bga: HashMap<usize, (usize, &'a [[f64; 2]; 3])>,
581    pub at_bga: HashMap<usize, (usize, &'a [[f64; 2]; 3])>,
582    pub poor_bga: Option<i32>,
583    pub argb: HashMap<usize, &'a [u8; 4]>,
584    pub video_file: Option<&'a str>,
585    pub video_fps: Option<f64>,
586    pub video_colors: Option<u32>,
587    pub video_delay: Option<u32>,
588    pub movie: Option<&'a str>,
589    pub ex_character: Option<ExCharacter<'a>>,
590
591    // 以降非推奨のコマンド
592    /// プレイ方法
593    ///
594    /// 主にメインデータから解析するのが主流
595    #[deprecated]
596    pub player: Option<PlayType>,
597    /// スクロール速度の基準BPM
598    ///
599    /// オプション側で基準とするBPMを最大、最小、最長、最初のBPMに合わせられるようにするべき
600    #[deprecated]
601    pub base_bpm: Option<f64>,
602    /// キーを押したときに表示するBGA
603    ///
604    /// 試験的に追加された
605    #[deprecated]
606    pub switch_bga:
607        HashMap<usize, (f64, f64, usize, bool, &'a [u8; 4], &'a [Channel])>,
608    /// ビデオの再生位置を調整
609    ///
610    /// 提案されたプレイヤーで削除済み
611    #[deprecated]
612    pub seek: HashMap<usize, f64>,
613
614    /// その他のコマンド
615    pub other: Vec<(&'a str, &'a str)>,
616}
617
618/// 一小節ごとのメインデータ
619///
620/// 同じ小節、同じチャンネルが複数行定義された場合に対応
621///
622/// bgmとoptionのみ複数行に対応している場合が多い
623#[derive(Debug, PartialEq)]
624pub struct MainData<'a> {
625    /// BGM
626    pub bgm: Vec<Vec<usize>>,
627    /// 一小節の長さ
628    ///
629    /// 1が基準
630    pub length: f64,
631    /// BPM
632    ///
633    /// 1から255まで
634    pub bpm: Vec<&'a [Option<f64>]>,
635    /// BGA
636    pub bga: Vec<Vec<usize>>,
637    /// POOR BGA
638    pub bga_poor: Vec<Vec<usize>>,
639    /// BGA LAYER
640    pub bga_layer: Vec<Vec<usize>>,
641    /// EXBPM
642    pub ex_bpm: Vec<Vec<usize>>,
643    /// 停止
644    pub stop: Vec<Vec<usize>>,
645    /// BGA LAYER2
646    pub bga_layer2: Vec<Vec<usize>>,
647    /// BGA不透明度
648    pub bga_alpha: Vec<&'a [u8]>,
649    /// BGA LAYER不透明度
650    pub bga_layer_alpha: Vec<&'a [u8]>,
651    /// BGA LAYER2不透明度
652    pub bga_layer2_alpha: Vec<&'a [u8]>,
653    /// POOR BGA不透明度
654    pub bga_poor_alpha: Vec<&'a [u8]>,
655    /// ノーツ
656    ///
657    /// チャンネルを36進数で解釈した値をキーにした`HashMap`
658    pub notes: HashMap<usize, Vec<Vec<usize>>>,
659    /// 不可視ノーツ
660    ///
661    /// チャンネルを36進数で解釈した値をキーにした`HashMap`
662    pub invisible_notes: HashMap<usize, Vec<Vec<usize>>>,
663    /// ロングノーツ
664    ///
665    /// チャンネルを36進数で解釈した値をキーにした`HashMap`
666    pub long_notes: HashMap<usize, Vec<Vec<usize>>>,
667    /// テキスト
668    pub text: Vec<Vec<usize>>,
669    /// EXRANK
670    pub ex_rank: Vec<Vec<usize>>,
671    /// BGA aRGB
672    pub bga_argb: Vec<Vec<usize>>,
673    /// BGA LAYER aRGB
674    pub bga_layer_argb: Vec<Vec<usize>>,
675    /// BGA LAYER2 aRGB
676    pub bga_layer2_argb: Vec<Vec<usize>>,
677    /// POOR BGA aRGB
678    pub bga_poor_argb: Vec<Vec<usize>>,
679    /// SWBGA
680    pub switch_bga: Vec<Vec<usize>>,
681    /// オプション
682    pub option: Vec<Vec<usize>>,
683    /// 地雷
684    pub landmine: HashMap<usize, Vec<&'a [f64]>>,
685    /// スクロール速度
686    pub scroll: Vec<Vec<usize>>,
687    /// ノーツ速度
688    pub speed: Vec<Vec<usize>>,
689
690    /// その他
691    pub other: Vec<(usize, &'a str)>,
692}
693impl Default for MainData<'_> {
694    fn default() -> Self {
695        MainData {
696            bgm: vec![],
697            length: 1.0,
698            bpm: vec![],
699            bga: vec![],
700            bga_poor: vec![],
701            bga_layer: vec![],
702            ex_bpm: vec![],
703            stop: vec![],
704            bga_layer2: vec![],
705            bga_alpha: vec![],
706            bga_layer_alpha: vec![],
707            bga_layer2_alpha: vec![],
708            bga_poor_alpha: vec![],
709            notes: HashMap::new(),
710            invisible_notes: HashMap::new(),
711            long_notes: HashMap::new(),
712            text: vec![],
713            ex_rank: vec![],
714            bga_argb: vec![],
715            bga_layer_argb: vec![],
716            bga_layer2_argb: vec![],
717            bga_poor_argb: vec![],
718            switch_bga: vec![],
719            option: vec![],
720            landmine: HashMap::new(),
721            scroll: vec![],
722            speed: vec![],
723            other: vec![],
724        }
725    }
726}
727
728/// Extended-Characterファイル
729#[derive(Debug, PartialEq)]
730pub struct ExCharacter<'a> {
731    pub sprite_num: u32,
732    pub bmp: usize,
733    pub trim_rect: &'a [[f64; 2]; 2],
734    pub offset: Option<&'a [f64; 2]>,
735    pub abs_pos: Option<&'a [f64; 2]>,
736}
737
738/// プレイ方式
739#[derive(Debug, PartialEq)]
740pub enum PlayType {
741    SinglePlay,
742    CouplePlay,
743    DoublePlay,
744    BattlePlay,
745}