需要和重新设计音量的配置方式。开始做实验

This commit is contained in:
2026-07-20 07:14:22 +08:00
parent b01fccbf4b
commit 813ffab782
10 changed files with 91 additions and 44 deletions
+11 -13
View File
@@ -66,10 +66,10 @@ class MidiImportConfig(PluginConfig):
default_program_value: int = MIDI_DEFAULT_PROGRAM_VALUE
default_volume_value: int = MIDI_DEFAULT_VOLUME_VALUE
default_tempo_value: int = mido.midifiles.midifiles.DEFAULT_TEMPO
default_midi_charset: str = "latin1"
default_lyric_encoding: str = "utf-8" # 默认歌词编码
midi_charset: str = "latin1"
string_encoding: str = "utf-8" # 默认歌词编码
"""
默认歌词编码,设定为空时不进行二次编码处理
默认字串编码,设定为空时不对原 Midi 中的字符串二次编码
"""
# 对照表,此处 None 值在下边 post init 函数中有处理
@@ -200,9 +200,7 @@ class MidiImport2MusicPlugin(MusicInputPluginBase):
if config is None:
config = MidiImportConfig()
return self.midifile_2_singlemusic(
mido.MidiFile(
file=bytes_buffer_in, clip=True, charset=config.default_midi_charset
),
mido.MidiFile(file=bytes_buffer_in, clip=True, charset=config.midi_charset),
config,
)
@@ -213,9 +211,7 @@ class MidiImport2MusicPlugin(MusicInputPluginBase):
if config is None:
config = MidiImportConfig()
return self.midifile_2_singlemusic(
mido.MidiFile(
filename=file_path, clip=True, charset=config.default_midi_charset
),
mido.MidiFile(filename=file_path, clip=True, charset=config.midi_charset),
config,
)
@@ -344,7 +340,9 @@ class MidiImport2MusicPlugin(MusicInputPluginBase):
midi_copyright_list.append(msg.text)
elif msg.type == "track_name":
# 检测轨道名称事件
midi_track_name_dict[track_no] = msg.name
midi_track_name_dict[track_no] = msg.name.encode("latin1").decode(
config.string_encoding
)
elif msg.type == "note_on" and msg.velocity != 0:
# 一个音符开始弹奏
@@ -428,9 +426,9 @@ class MidiImport2MusicPlugin(MusicInputPluginBase):
note_table_replacement=config.note_replacement_table,
lyric_line=(
_lyric.encode("latin1").decode(
config.default_lyric_encoding
config.string_encoding
)
if config.default_lyric_encoding
if config.string_encoding
else _lyric
),
)
@@ -498,7 +496,7 @@ class MidiImport2MusicPlugin(MusicInputPluginBase):
for track_properties, every_single_track in divided_tracks.items():
# [音轨编号, 通道编号, 乐器名称, 音量, 声相]
if track_properties[0] and (
track_name := midi_track_name_dict.get(track_properties[0])
track_name := midi_track_name_dict.get(track_properties[0], "无名音轨")
): # 音轨编号
every_single_track.name = track_name
if track_properties[2]: # 乐器名称
@@ -204,7 +204,7 @@ def midi_msgs_to_noteinfo(
return (
SingleNote(
note_pitch=note,
note_volume=velocity,
note_volume=velocity, # 需要重新设计
start_tick=(tk := int(start_time / float(play_speed) / 50000)),
keep_tick=round(duration / float(play_speed) / 50000),
mass_precision_time=round(
@@ -113,6 +113,16 @@ class MusicPreview:
if file.is_file():
self.res_raw_data[file.stem] = librosa.load(file, sr=None)
# print(
# file.stem,": { 'AVG':",
# np.average(np.absolute(self.res_raw_data[file.stem][0])),", 'MID' :",
# np.median(np.absolute(self.res_raw_data[file.stem][0])),", 'MAX' :",
# np.max(np.absolute(self.res_raw_data[file.stem][0])),", 'MIN' :",
# np.min(np.absolute(self.res_raw_data[file.stem][0])),", 'VAR' :",
# np.var(np.absolute(self.res_raw_data[file.stem][0])),"}",
# flush=True,
# )
def res_shift(
self,
sound_name: str,
@@ -121,24 +131,28 @@ class MusicPreview:
duration: int,
# rate: int
):
y_orig, sr_orig = self.res_raw_data[sound_name]
original_y, original_sample_rate = self.res_raw_data[sound_name]
if not percussive:
if self.mode == 1:
# 变调, 时域压扩, 重采样 mc方法
self.res_data[sound_name][pitch] = librosa.resample(
librosa.effects.time_stretch(
librosa.effects.pitch_shift(y_orig, sr=sr_orig, n_steps=pitch),
librosa.effects.pitch_shift(
original_y, sr=original_sample_rate, n_steps=pitch
),
rate=2 ** (pitch / 12),
),
orig_sr=sr_orig,
orig_sr=original_sample_rate,
target_sr=self.output_sample_rate,
fix=False,
)
elif self.mode == 0:
# 重采样, 变调
self.res_data[sound_name][pitch] = librosa.resample(
librosa.effects.pitch_shift(y_orig, sr=sr_orig, n_steps=pitch),
orig_sr=sr_orig,
librosa.effects.pitch_shift(
original_y, sr=original_sample_rate, n_steps=pitch
),
orig_sr=original_sample_rate,
target_sr=self.output_sample_rate,
fix=False,
)
@@ -146,16 +160,18 @@ class MusicPreview:
# 变调, 时域压扩, 重采样 MIDI-FFT
if self.overlay_mode_c == 2:
rate = duration / 20 / (len(y_orig[0]) / sr_orig)
rate = duration / 20 / (len(original_y[0]) / original_sample_rate)
else:
rate = duration / 20 / (len(y_orig) / sr_orig)
rate = duration / 20 / (len(original_y) / original_sample_rate)
rate = rate if rate != 0 else 1
self.res_data[sound_name][pitch] = librosa.resample(
librosa.effects.time_stretch(
librosa.effects.pitch_shift(y_orig, sr=sr_orig, n_steps=pitch),
librosa.effects.pitch_shift(
original_y, sr=original_sample_rate, n_steps=pitch
),
rate=rate,
),
orig_sr=sr_orig,
orig_sr=original_sample_rate,
target_sr=self.output_sample_rate,
fix=False,
)
@@ -163,38 +179,41 @@ class MusicPreview:
# 变调, 时域压扩, 重采样 MIDI-cut
if self.overlay_mode_c == 2:
deal = librosa.effects.pitch_shift(
y_orig, sr=sr_orig, n_steps=pitch
original_y, sr=original_sample_rate, n_steps=pitch
)[
...,
: (
int(duration / 20 * sr_orig)
if duration / 20 * sr_orig > len(y_orig[0])
else len(y_orig[0])
int(duration / 20 * original_sample_rate)
if duration / 20 * original_sample_rate > len(original_y[0])
else len(original_y[0])
),
]
else:
deal = librosa.effects.pitch_shift(
y_orig, sr=sr_orig, n_steps=pitch
original_y, sr=original_sample_rate, n_steps=pitch
)[
: (
int(duration / 20 * sr_orig)
if duration / 20 * sr_orig > len(y_orig)
else len(y_orig)
int(duration / 20 * original_sample_rate)
if duration / 20 * original_sample_rate > len(original_y)
else len(original_y)
)
]
self.res_data[sound_name][pitch] = librosa.resample(
deal, orig_sr=sr_orig, target_sr=self.output_sample_rate, fix=False
deal,
orig_sr=original_sample_rate,
target_sr=self.output_sample_rate,
fix=False,
)
else:
# if self.mode == 1:
# 重采样, 不变调
# print(">>", sound_name, pitch)
self.res_data[sound_name][pitch] = librosa.resample(
y_orig,
orig_sr=sr_orig,
original_y,
orig_sr=original_sample_rate,
target_sr=self.output_sample_rate,
fix=False, # 尽管这样不变调,但是也不应将 pitch 与打击乐器联系在一起
) # 已经在下面重新用 0 取代了打击乐器的 pitch
) # 已经在下面重新用 0 取代了打击乐器的 pitch
"""elif self.mode == 0:
# 重采样, 不变调, 衰弱
self.cache_dict[raw_name] = librosa_resample(
@@ -354,20 +373,18 @@ class MusicPreview:
if not note.percussive:
overlay(
self.res_data[note.instrument][accurate_pitch]
* note.volume
/ (note.position.sound_distance + 0.5)
/ 127,
* (1 - (note.position.sound_distance / 48)),
note.start_tick,
)
# 上述参数的原顺序应为
# x * (音量 / 127) * (1 / (距离 + 0.5))
# 乘法优先是为了提高计算精度,小的数的除法优先同理
# 下面是后来的注释
# 这种方式是错误的 —— 金羿 20260720
else:
overlay(
self.res_data[note.instrument][accurate_pitch]
* note.volume
/ (note.position.sound_distance + 0.5)
/ 127,
* (1 - (note.position.sound_distance / 48)),
note.start_tick,
)
+35 -3
View File
@@ -409,6 +409,7 @@ MC_PITCHED_INSTRUMENT_LIST: List[str] = [
MC_INSTRUMENT_BLOCKS_TABLE: Dict[str, Tuple[str, ...]] = {
"note.bass": ("planks",),
"note.bassattack": ("planks",), # 无法找到此音效
"note.snare": ("sand",),
"note.hat": ("glass",),
"note.bd": ("stone",),
@@ -424,12 +425,11 @@ MC_INSTRUMENT_BLOCKS_TABLE: Dict[str, Tuple[str, ...]] = {
"note.bit": ("emerald_block",),
"note.banjo": ("hay_block",),
"note.pling": ("glowstone",),
"note.bassattack": ("stone",), # 无法找到此音效
"note.harp": ("dirt",),
"note.trumpet": ("waxed_copper",),
"note.trumpet_exposed": ("waxed_exposed_copper",),
"note.trumpet_weathered": ("waxed_weathered_copper",),
"note.trumpet_oxidized": ("waxed_oxidized_copper",),
"note.harp": ("dirt",),
# 呃……
"firework.blast": ("sandstone",),
"firework.twinkle": ("red_sandstone",),
@@ -438,6 +438,38 @@ MC_INSTRUMENT_BLOCKS_TABLE: Dict[str, Tuple[str, ...]] = {
}
"""MC乐器对音符盒下垫方块对照表"""
MC_INSTRUMENT_VOLUME_BALANCE_TABLE: Dict[str, float] = {
"note.bass": 0.18975738,
"note.bassattack": 0.19250469,
"note.snare": 0.09636449,
"note.hat": 0.041303635,
"note.bd": 0.25398168,
"note.bell": 0.03190162,
"note.flute": 0.050610494,
"note.chime": 0.011847978,
"note.guitar": 0.03356794,
"note.xylophone": 0.025973769,
"note.iron_xylophone": 0.044438824,
"note.cow_bell": 0.09123069,
"note.didgeridoo": 0.06332747,
"note.bit": 0.028824601,
"note.banjo": 0.02944984,
"note.pling": 0.11315284,
"note.trumpet": 0.069420114,
"note.trumpet_exposed": 0.083734825,
"note.trumpet_oxidized": 0.047252066,
"note.trumpet_weathered": 0.06659823,
"note.harp": 0.12101666,
# 嗯……
"fire.ignite": 0.004931174,
"firework.blast": 0.015445901,
"firework.twinkle": 0.032410737,
"mob.cat.meow-2": 0.0675417,
"mob.cat.meow-4": 0.05923138,
"mob.zombie.wood": 0.14135803,
}
MC_EILLES_RT261_INSTRUMENT_REPLACE_TABLE: Dict[str, str] = {
"note.trumpet": "note.flute",
"note.trumpet_exposed": "note.flute",
@@ -505,7 +537,7 @@ MM_INSTRUMENT_RANGE_TABLE: Dict[str, Tuple[Tuple[int, int], int]] = {
}
"""
不同乐器的音域偏离对照表
元组里的是范围,后面的整数是中央 C 所在
元组里的是范围,后面的整数是游戏里的默认采样音高
"""
MM_INSTRUMENT_DEVIATION_TABLE: Dict[str, int] = {