Last active
January 12, 2024 12:51
-
-
Save trueroad/2b4214a3c033e90ee64f097a7dcccbc1 to your computer and use it in GitHub Desktop.
Find groups of equivalent SMFs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
""" | |
Find groups of equivalent SMFs. | |
https://gist.github.com/trueroad/2b4214a3c033e90ee64f097a7dcccbc1 | |
Copyright (C) 2023 Masamichi Hosoda. | |
All rights reserved. | |
Redistribution and use in source and binary forms, with or without | |
modification, are permitted provided that the following conditions | |
are met: | |
* Redistributions of source code must retain the above copyright notice, | |
this list of conditions and the following disclaimer. | |
* Redistributions in binary form must reproduce the above copyright notice, | |
this list of conditions and the following disclaimer in the documentation | |
and/or other materials provided with the distribution. | |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
ARE DISCLAIMED. | |
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
SUCH DAMAGE. | |
複数の SMF を入力として、等価 SMF のグループを見つける。 | |
等価というのは、 | |
ノートON/OFFのタイミング、チャンネル、ノート番号、ベロシティ | |
がまったく同じとし、それ以外のメッセージやメタイベント等は考慮しない。 | |
入力はコマンドライン引数に比較したい SMF のファイル名をすべて記述する。 | |
出力は標準出力に、 | |
グループ間に空行を入れつつ、 | |
グループ内は所属する SMF のノート数とファイル名をタブ区切りで 1 行ずつ、 | |
という形式となる。 | |
グループに所属しない SMF については出力しない。 | |
例: | |
group1-1.mid, group1-2.mid, group1-3.mid がそれぞれ等価でノート数 10、 | |
group2-1.mid, group2-2.mid それぞれ等価でノート数 5、 | |
different1.mid, different2.mid が等価でない場合は以下のようになる。 | |
``` | |
$ ./find_smf_groups.py group1-1.mid group1-2.mid group1-3.mid \ | |
group2-1.mid group2-2.mid \ | |
different1.mid different2.mid | |
10 group1-1.mid | |
10 group1-2.mid | |
10 group1-3.mid | |
5 group2-1.mid | |
5 group2-2.mid | |
$ | |
``` | |
""" | |
import sys | |
# https://gist.github.com/trueroad/52b7c4c98eec5fdf0ff3f62d64ec17bd | |
import smf_parse | |
def main() -> None: | |
"""Do main.""" | |
if len(sys.argv) < 3: | |
# 比較対象の SMF が 2 つ以上ないので終了 | |
return | |
# 入力ファイル名の一覧 | |
input_filenames: list[str] = sys.argv[1:] | |
# ファイル名とノートリストのタプルのリスト | |
sn_list: list[tuple[str, smf_parse.smf_notes]] = [] | |
# 入力ファイルを読み込んでリストに格納 | |
filename: str | |
sn: smf_parse.smf_notes | |
for filename in input_filenames: | |
sn = smf_parse.smf_notes() | |
sn.load(filename) | |
sn_list.append((filename, sn)) | |
# 既に等価 SMF グループに入っている SMF のインデックス格納用 | |
already_grouped: set[int] = set() | |
# 外側の判定ループ | |
i: int | |
for i in range(len(sn_list)): | |
if i in already_grouped: | |
# 既に等価 SMF グループに入っているインデックスはスキップ | |
continue | |
# 等価 SMF グループ開始フラグを未開始に初期化 | |
b_group_started: bool = False | |
# 内側の判定ループ | |
j: int | |
for j in range(len(sn_list)): | |
if i >= j: | |
# 内側外側で同じインデックス同士は比較せずにスキップ、 | |
# 内側外側が逆のインデックス組み合わせで比較するものもスキップ | |
continue | |
if j in already_grouped: | |
# 既に等価 SMF グループに入っているインデックスはスキップ | |
continue | |
if sn_list[i][1].get_notes() == sn_list[j][1].get_notes(): | |
# SMF 全ノートが一致! | |
if not b_group_started: | |
# まだ等価 SMF グループを開始していなかったので開始処理 | |
# 最初の SMF の情報を出力 | |
print(f'\n{len(sn_list[i][1].get_notes())}' | |
f'\t{sn_list[i][0]}') | |
# 等価 SMF グループ開始済フラグを立てる | |
b_group_started = True | |
# 2 番目以降の SMF の情報を出力 | |
print(f'{len(sn_list[j][1].get_notes())}\t{sn_list[j][0]}') | |
# このインデックスはグループ化されたので次以降はスキップ | |
already_grouped.add(i) | |
already_grouped.add(j) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment