如题
具体一点来说,一个midi音乐里面是一堆音符,那么我想让这个midi音乐倒过来播放,但不是把波形倒放,而仅仅只是把所有的音符倒过来依次播放
假设现在有一个midi音乐,它里面只有一个音符,那么倒放前和倒放后是一样的
如果有一个低音区音符,一个高音区音符(顺序同我描述),则倒放后应该是高音区音符在前,低音区音符在后,但是每个音符自身的音色不变
因为我没有电脑,所以我需要这款软件能够独立的在手机上运行(而不是像网页开发者工具一样,要么得用电脑;要么就得在手机上连接电脑,然后在电脑上搞,像这样子一搞,说白了就是不要搞的除了用电脑就还得用电脑)
7 回答
手机上能实现的办法是你找到某些DAW(基本都要付费),软件提供直接的“反转”功能。你选择所有音符,导航到“编辑”菜单,选择“反转活动 MIDI 事件”。我不知道移动端有没有这种功能(大概率没有)。
或者你自己在手机山搞个编译器部署环境,然后写个类似下面这种的脚本(需要调用mido库)
import mido
# 加载 MIDI 文件
mid = mido.MidiFile('input.mid')
# 计算总长度
total_length = sum(msg.time for msg in mid)
# 创建新的 MIDI 文件
out_mid = mido.MidiFile()
out_track = mido.MidiTrack()
out_mid.tracks.append(out_track)
# 收集音符事件及其绝对时间
events = []
current_time = 0
for msg in mid:
current_time += msg.time
if msg.type in ['note_on', 'note_off']:
events.append((current_time, msg))
# 反转事件时间
reversed_events = []
for time, msg in events:
new_time = total_length - time
reversed_events.append((new_time, msg))
# 按新的时间排序事件
reversed_events.sort(key=lambda x: x[0])
# 重建消息并更新时间
last_time = 0
for time, msg in reversed_events:
delta_time = time - last_time
msg.time = delta_time
out_track.append(msg)
last_time = time
# 保存反转后的 MIDI 文件
out_mid.save('output.mid')
@农药君
https://github.com/mido/mido/issues/189https://github.com/mido/mido/issues/189
https://mido.readthedocs.io/en/1.1.24/midi_files.html
关于时间属性
时间属性有多种不同的使用方式:
在轨道内,它是以刻度为单位的增量时间。这必须是一个整数。
在 play() 生成的消息中,它是以秒为单位的增量时间(自上次生成消息以来经过的时间)
(仅对实现者重要)在某些方法中,它用于以滴答声或秒为单位的绝对时间
你把事件的事件属性想办法整成整数倍的刻度
@农药君
我修正了最好的门神给出的python代码,请过目。
import mido
mid = mido.MidiFile('input.mid')
total_length = sum(msg.time for msg in mid if not msg.is_meta)
out_mid = mido.MidiFile()
out_track = mido.MidiTrack()
out_mid.tracks.append(out_track)
events = []
current_time = 0
for msg in mid:
current_time += msg.time
if not msg.is_meta and msg.type in ['note_on', 'note_off']:
events.append((current_time, msg))
reversed_events = []
for time, msg in events:
new_time = int(total_length - time)
reversed_events.append((new_time, msg))
reversed_events.sort(key=lambda x: x[0])
last_time = 0
for time, msg in reversed_events:
delta_time = int(time - last_time)
new_msg = msg.copy(time=delta_time)
out_track.append(new_msg)
last_time = time
out_mid.save('output.mid')
修正后,应该可以避免报错。
@最好的门神 不是,你这个报错了啊
Traceback (most recent call last):
File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 31, in
start(fakepyfile,mainpyfile)
File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 30, in start
exec(open(mainpyfile).read(), __main__.__dict__)
File "", line 40, in
File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/mido/midifiles/midifiles.py", line 458, in save
self._save(file)
File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/mido/midifiles/midifiles.py", line 471, in _save
write_track(outfile, track)
File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/mido/midifiles/midifiles.py", line 244, in write_track
raise ValueError('message time must be int in MIDI file')
ValueError: message time must be int in MIDI file
[Program finished]
省流:打回重做(把midi触发的音符信号全部倒过来重新写过)
你描述的这个东西,就算有电脑,他也得手动一个一个的生抠过去。
这不就讲废话。
您的回答
登录以回答这儿是 MidiShow 问答区,欢迎您请教或帮大家解决关于音乐创作、MIDI 应用、MIDI 技术等音乐相关的问题。
问答区积分规则如下:
- 提问、回答或自问自答积分均不变
- 问题被赞成 : +10
- 问题被反对 : 提问者 -2,点击反对者不扣分
- 回答被赞成 : +10
- 回答被反对 : 回答者 -2,点击反对者 -1
- 提问者选出满意回答 :回答者 +15 ,提问者 +2
参与问答前请阅读:问答区玩法规则