我需要以编程方式从 midi 文件中删除一个通道(通道 10,因此是打击乐通道)。有很多音乐程序允许您编辑 midi 文件,但我希望我可以通过脚本来执行此操作以节省一些时间。
我对此很陌生,我在网上找到的唯一可能对我有帮助的东西似乎是 ffmpeg。但我真的不明白该怎么做。
总结一下:
- ffmpeg 可以编辑 midi 文件吗?
- 如果是,ffmpeg 是编写 midi 操作脚本的最佳工具吗?
- 您有一些可以展示的工作代码吗?
谢谢!
答案1
FFmpeg 是为音频和视频文件(如.mp3
和 )制作的.mp4
。这些文件的结构与 MIDI 文件非常不同。虽然可能有人添加了 MIDI 支持,但我对此表示怀疑。
幸运的是,MIDI 文件并不难理解:
MIDI 文件由块组成,每个块以四个 ASCII 字母开头(总共占用四个字节),后跟一个四字节值。该值是块的大小。
第一个块总是以 ASCII 字母开头MThd
,告诉您这是标题,接下来的四个字节编码大小。如果您跳过大小值告诉您的字节数,您应该到达下一个块,即一个轨道。如果一切正确,您应该读到 ASCII 字母MTrk
,后面跟着四个字节的大小。跳过此站点应该会带您到下一个轨道。计算您跳过的轨道数,直到到达第十个轨道。您可以通过删除此轨道中原本会跳过的字节(包括MTrk
删除的字节)来删除它。
这可能会删除您的打击乐音轨,如果不行,您可以尝试删除其他音轨。如果这不起作用,那么事情就会变得有点复杂。
例外情况:
- 这个 MIDI 文件可能在单个音轨中嵌入了整首歌曲,这里事情会变得稍微复杂一些。
更复杂的情况:在音轨中,还存储了每个音符的音轨编号,要读取这些音符,您需要制作(或找到)一个完整的 MIDI 解释器。要删除这些音符,您需要过滤掉具有该特定音轨编号的音符。
答案2
如果你不介意用 Python,那么这个图书馆用于处理 MIDI 的 Mido。它允许您像 SP4CEBAR 的答案一样在更高级别上迭代音轨。
以下函数检查每条“消息”并检查是否存在频道属性以及该频道值是否与您要删除的频道匹配。
你可以使用它来开始:
import mido
def remove_channel_from_midi(input_path, output_path, channel_to_remove):
try:
# Load the MIDI file
midi_file = mido.MidiFile(input_path)
# Create a new MIDI file to store the modified data
new_midi_file = mido.MidiFile()
for msg in midi_file:
# Check if the message is on the channel to be removed
if hasattr(msg, 'channel') and msg.channel == channel_to_remove:
continue # Skip this message
new_midi_file.tracks.append([msg]) # Add the message to the new file
# Save the modified MIDI file
new_midi_file.save(output_path)
print(f"Channel {channel_to_remove} removed and saved to {output_path}")
except Exception as e:
print(f"An error occurred: {e}")
# Example usage:
input_midi_path = "input.mid"
output_midi_path = "output.mid"
remove_channel_from_midi(input_midi_path, output_midi_path, channel_to_remove=10)