简体   繁体   English

确定 MIDI 文件的时分

[英]Determining time division of a MIDI file

I am working on a script in Python to parse MIDI files (yes I know MIDI parsing libraries exist for Python but for my use case it's easiest if i make it from scratch).我正在用 Python 编写一个脚本来解析 MIDI 文件(是的,我知道 Python 存在 MIDI 解析库,但对于我的用例,如果我从头开始制作它是最简单的)。

The one thing I'm having a problem with is the time division.我遇到的一件事是时间划分。 the last two bytes of the header specifies the time division, but I'm having trouble determining if a file's time division is noted in ticks per beat or frames per second.标题的最后两个字节指定了时分,但我无法确定文件的时分是以每节拍的滴答声还是每秒帧数来表示的。 After doing some reading, it seems that the top bit of the top byte indicates which of the two the time division is noted in. What I am confused about is if the top bit of a byte is the first bit of a byte or the last bit of a byte, as well as how to read the MIDI time division entirely.经过一些阅读后,似乎顶部字节的顶部位表示时分记在两个中的哪一个。 我感到困惑的是字节的顶部位是字节的第一位还是最后一位一个字节的位,以及如何完全读取 MIDI 时分。

EDIT: for example, a header of a MIDI file I have is the following:编辑:例如,我拥有的 MIDI 文件的标题如下:

4d54 6864 0000 0006 0000 0001 0078

0078 are the two bytes that denote the time sig, but I am confused as how to interpret it.

Edit 2:编辑2:

def openmidi(file):
    tmbr = []
    f = open(file, "rb")#opening the midi in binary mode
    loopfile = True
    while loopfile == True:
        cb = f.read(1)
        if cb != b'':#checking if there are still bytes left to read
            tmbr.append(cb)
        else:
            loopfile = False
    return tmbr

def byteread(num):#will read and return the specified number of bytes
    global bytecounter
    bytehold = b''
    for i in range(0, num):#reads specified number of bytes
        bytehold+=midibytearray[i+bytecounter]#number of increment plus the read position
    bytecounter+=num#after reading is done read position is incremented by the number of bytes read.
    return bytehold#after looping is done the specified bytes are returned.

def timetype(deltatimebytes):#used to determine if the time division is in ticks per beat or frames per second.
    if str(deltatimebytes).replace("b'","").replace("'","")[0:2] == "00":
        return True#if true the time division is in ticks per beat.
    else:
        return False#the time division is in frames per second.


global bytecounter
bytecounter = 0 #keeps track of what position in the file is being read.

midibytearray = openmidi("C:\\Users\\gabep\\Desktop\\Electrorchestrion\\Midis\\BONEY M.Rasputin K.mid") #array that the bytes will be stored in.



header = byteread(4)
chunklength = byteread(4)
formattype = byteread(2)
numofmtrkchunks = byteread(2)
deltatime = byteread(2)#if no tempo is assigned, 120bpm is assumed.
print(deltatime)

print("Header: "+str(header.decode("utf-8")))
print("MThd chunk length: "+str(int(chunklength.hex(), 16)))
print("Midi Format Type: "+str(int(formattype.hex(), 16)))
print("Number of MTrk chunks (number of tracks): "+str(int(numofmtrkchunks.hex(), 16)))



print("Delta time: "+str(int(deltatime.hex(), 16)))
if timetype(deltatime.hex()) == True:
    print("Time signature is in ticks per beat")
else:
    print("Time signature is in frames per second")

Maybe you don't know that the official MIDI specifications are available and you can download the document for free.可能你不知道官方的MIDI规范是可用的,你可以免费下载文档 (You need to register as site user first). (您需要先注册为站点用户)。 It includes the detailed SMF format.它包括详细的 SMF 格式。

Here is the description of the header chunk.这是头块的描述。


The header chunk at the beginning of the file specifies some basic information about the data in the file.文件开头的头块指定了文件中数据的一些基本信息。 Here's the syntax of the complete chunk:这是完整块的语法:

<Header Chunk> = <chunk type> <length> <format> <ntrks> <division>

As described above, <chunk type> is the four ASCII characters 'MThd';如上所述, <chunk type>是四个ASCII字符'MThd'; <length> is a 32-bit representation of the number 6 (high byte first). <length>是数字 6 的 32 位表示(高字节在前)。 The data section contains three 16-bit words, stored most-significant byte first.数据部分包含三个 16 位字,首先存储最高有效字节。 The first word, <format> , specifies the overall organization of the file.第一个词<format>指定文件的整体组织。 Only three values of <format> are specified:仅指定了<format>三个值:

0=the file contains a single multi-channel track 0=文件包含单个多通道轨道

1=the file contains one or more simultaneous tracks (or MIDI outputs) of a sequence 1=文件包含一个或多个同步音轨(或 MIDI 输出)的序列

2=the file contains one or more sequentially independent single-track patterns More information about these formats is provided below. 2=该文件包含一个或多个顺序独立的单轨模式 下面提供了有关这些格式的更多信息。

The next word, <ntrks> , is the number of track chunks in the file.下一个词<ntrks>是文件中轨道块的数量。 It will always be 1 for a format 0 file.对于格式 0 文件,它将始终为 1。

The third word , <division> , specifies the meaning of the delta-times.第三个词<division>指定了增量时间的含义。 It has two formats, one for metrical time, and one for time-code-based time:它有两种格式,一种用于公制时间,一种用于基于时间码的时间:

  |bits                                        |
  |15|14        ...         8|7     ...      0 |
  |--|-----------------------|-----------------|
  | 0|         ticks per quarter-note          |
  | 1| negative SMPTE format | ticks per frame |

If bit 15 of <division> is a zero, the bits 14 thru 0 represent the number of delta-time "ticks" which make up a quarter-note.如果<division> 15 位为零,则第 14 到 0 位表示构成四分音符的增量时间“滴答声”的数量。 For instance, if <division> is 96, then a time interval of an eighth-note between two events in the file would be 48. If bit 15 of <division> is a one, delta-times in a file correspond to subdivisions of a second, in a way consistent with SMPTE and MIDI time code.例如,如果<division>为 96,则文件中两个事件之间的八分音符的时间间隔将为 48。如果<division> 15 位为 1,则文件中的 delta-times 对应于一秒钟,以与 SMPTE 和 MIDI 时间码一致的方式。 Bits 14 thru 8 contain one of the four values -24, -25, -29, or -30, corresponding to the four standard SMPTE and MIDI time code formats (-29 corresponds to 30 drop frame), and represents the number of frames per second.位 14 到 8 包含四个值之一 -24、-25、-29 或 -30,对应于四种标准 SMPTE 和 MIDI 时间码格式(-29 对应于 30 个丢帧),并表示帧数每秒。 These negative numbers are stored in two's complement form.这些负数以二进制补码形式存储。 The second byte (stored positive) is the resolution within a frame: typical values may be 4 (MIDI time code resolution), 8, 10, 80 (bit resolution), or 100. This system allows exact specification of time-code-based tracks, but also allows millisecond-based tracks by specifying 25 frames/sec and a resolution of 40 units per frame.第二个字节(存储的正数)是帧内的分辨率:典型值可能是 4(MIDI 时间码分辨率)、8、10、80(位分辨率)或 100。该系统允许基于时间码的精确规范跟踪,但也允许通过指定 25 帧/秒和每帧 40 个单位的分辨率来实现基于毫秒的跟踪。 If the events in a file are stored with bit resolution of thirty-frame time code, the division word would be E250 hex.如果文件中的事件以 30 帧时间码的位分辨率存储,则划分字将为 E250 十六进制。


In your example, your third word (hex 0078) means that the <division> is 120 ticks per quarter-note.在您的示例中,您的第三个单词(十六进制 0078)表示<division>是每个四分音符 120 个刻度。

Delta time is given in ticks for the events in the file. Delta 时间以文件中事件的滴答为单位给出。 Time signature is another totally different thing.时间签名是另一件完全不同的事情。 It is an indication of the rhythm, and is a meta-event type.它是节奏的指示,并且是元事件类型。 (See page 10 of the specification). (参见规范的第 10 页)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM