Một tệp MIDI là một chuỗi các khúc. Các khúc này có cùng một khuôn dạng chung giống nhƣ các khúc đƣợc sử dụng trong các tệp Aiff, Iff, và Wave. Mỗi khúc có 4 ký tự phân loại, một mã độ dài kích thƣớc 4-byte (trong khuôn dạng MSB), và một vài dữ liệu. Tuy nhiên, khác với các khuôn dạng khác, các khúc MIDI không xếp chồng.
Hiện nay, chỉ có 2 loại khúc. Khúc MThd chứa thông tin về header nói chung; và khúc MTrk chứa một rãnh đơn. Khúc MThd xuất hiện tại phần đầu của mọi tệp MIDI, và đây là dấu hiệu để định danh một tệp MIDI chuẩn.
Khúc MIDI Header
Khúc MThd chứa một chút các sự kiện cơ sở về tệp MIDI. Mọi giá trị này đƣợc lƣu trữ trong khuôn dạng MSB. Sau đây là nội dung của khúc MIDI MThd:
Bytes Mô tả
2 Dạng tệp 2 Số các rãnh
2 Khuôn dạng thời gian
Có 3 loại tệp MIDI, chúng đƣợc phân loại tuỳ theo cách xử lý các rãnh:
· Tệp dạng 0 chỉ chứa duy nhất một rãnh. Một cách rõ ràng, đây là tệp dễ nhất để có thể phát, nên đây là dạng thông dụng cho các tệp quảng cáo. · Tệp dạng 1 chứa rất nhiều rãnh mà chúng đƣợc phát một cách đồng thời.
Một chƣơng trình dùng để phát các tệp dạng 1 phải bằng cách nào đó san phẳng dữ liệu thành các dòng sự kiện đơn trƣớc khi phát.
· Tệp dạng 2 chứa nhiều rãnh nhƣng không thừa nhận bất cứ sự liên hệ nào giữa các rãnh. Nói chung, các tệp dạng 2 là không phổ biến.
Các rãnh MIDI
Chú ý rằng một rãnh là khác so với một kênh MIDI. Mặc dù đây là dạng chung cho các tệp multi-track để có thể phát mỗi rãnh trên một kênh khác nhau, và trong quá trình tổ hợp một bản nhạc có thể sử dụng số các rãnh tuỳ ý để có thể phát các rãnh trên các kênh khác nhau theo bất cứ kiểu mẫu nào.
Mỗi rãnh MIDI là một danh sách các sự kiện, mà mỗi sự kiện có một “delta time” đặt trƣớc. Mỗi khúc trong một tệp MIDI có một độ dài đã đƣợc ấn định, nên cần thận trọng khi rãnh hoá số các bytes đƣợc đọc để ta có thể biết khi nào dữ liệu rãnh kết thúc. Nếu đây không phải rãnh đầu tiên, thì cần phải đảm bảo rằng các sự kiện mới đã hoàn toàn đƣợc chèn vào trong bộ nhớ danh sách các sự kiện.
Giống nhƣ bất kỳ danh sách mã chèn nào, quá trình chèn một sự kiện MIDI yêu cầu hai trƣờng hợp sau: một, nếu sự kiện vào phần đầu của danh sách (trong trường hợp này cần phải cập nhật đầu đọc danh sách); hai, nếu sự kiện vào giữa danh sách (trong trường hợp này một container trỏ khác nhận sự cập nhật).
Điều này làm tăng sự phức tạp bởi sự cần thiết chèn nó vào tại vị trí tạm thời chính xác và điều chỉnh các độ trễ một cách thích hợp. Ngoài ra, để duy trì không gian, các tệp MIDI sử dụng các số nguyên biến độ dài để lƣu trữ các “delta times” và các giá trị tới hạn khác. Điều này cho phép các giá trị nhỏ (như giá trị 0) có thể đƣợc lƣu trữ trong một byte đơn đồng thời cho phép các giá trị đạt tới 32 bits.
Delta times
Các sự kiện MIDI xuất hiện tại một số thời điểm xác định. Có 2 cách để đánh dấu các thông tin này:
·Lƣu trữ thời gian tuyệt đối tại mỗi thời điểm mà sự kiện xuất hiện, hay có thể lƣu trữ các quãng thời gian giữa các sự kiện.
·Mỗi sự kiện đƣợc đặt trƣớc bởi một số chỉ ra số các ticks để tách biệt nó với sự kiện trƣớc đó. Khoảng tồn tại chính xác của một tick phụ thuộc vào khuôn dạng thời gian đã đƣợc ấn định trong header, và cũng có thể đƣợc thay đổi bởi các sự kiện riêng biệt trong tệp.
Các sự kiện MIDI
Một sự kiện MIDI là một gói các dữ liệu mà nó chỉ rõ một số các sự kiện âm nhạc, nhƣ việc nhấn và nhả phím. Byte đầu tiên của gói là byte trạng thái, mà nó định rõ dạng của sự kiện, và đôi khi, là kênh truyền. Các bytes trạng thái thƣờng xuyên có thiết lập bit cao. Còn lại là các byte dữ liệu, mà chúng không bao giờ có thiết lập bit cao. Sự phân biệt này là rất quan trọng.
Theo cách chung, các kênh truyền MIDI đƣợc đánh số từ 1 tới 16, và các nhạc cụ MIDI là từ 1 tới 128. Tuy nhiên, các mã hoá số xắp hàng từ 0 tới 15 và 0 tới 127 một cách tƣơng ứng. Ta sẽ thêm hay bớt 1 khi chuyển đổi giữa các mã số hoá và ngôn ngữ MIDI.
Running Status
Để tạo "wire protocol" thêm hiệu quả, MIDI sử dụng một kỹ thuật gọi là “running status”, kỹ thuật này bỏ qua các bytes trạng thái lặp. Khi đọc một tệp MIDI, nếu gặp một byte dữ liệu, trong khi ta đang cần một byte trạng thái, thì ta dùng lại trạng thái trƣớc đó. Để tạo cho kỹ thuật này thêm hữu hiệu, có một quy ƣớc rằng một “note-on event” với một vận tốc (velocity) thiết lập về 0 cũng giống nhƣ một “note-off event” với một vận tốc ngầm định là 64. Nhƣ vậy, một dẫy dài các notes trên một kênh truyền đơn có thể đƣợc kiểm soát với chỉ 2 bytes cho mỗi sự kiện.
Quản lý các sự kiện MIDI
Các tệp MIDI thƣờng đƣợc lƣu trữ nhƣ các rãnh đơn. Mặc dù các sự kiện trong mỗi rãnh đƣợc lƣu trữ theo thứ tự tạm thời, luồng sự kiện mà nó nhận đƣợc để phát là một tổ hợp của các rãnh này. Hơn nữa, các sự kiện trong mỗi rãnh (như những sự thay đổi về nhịp độ) tác động lên quá trình phát lại của các sự kiện trong các rãnh khác.
Cho các tệp dạng 1, cần phải đọc mọi sự kiện vào bộ nhớ trƣớc khi phát chúng. Để đạt đƣợc điều này, cần lƣu trữ một danh sách liên kết đơn của các sự kiện MIDI.
Phần lớn các sự kiện gồm một byte trạng thái và một cặp byte dữ liệu. Và cũng cần phải lƣu trữ giá trị độ trễ và số rãnh mà sự kiện này xuất hiện. Vài sự kiện MIDI riêng biệt có thể chứa một lƣợng tuỳ ý các dữ liệu, nên cần thêm một cấu trúc phụ để nắm giữ dữ liệu đó khi cần đến. Phần lớn các sự kiện MIDI có độ dài cố định. Ví dụ nhƣ một “note-on event” có 2 bytes dữ liệu tiếp theo các bytes trạng thái.
Khuôn dạng MIDI
Khuôn dạng MID là các tệp điều khiển âm thanh trong multimedia. MIDI là một hệ thống hoàn chỉnh không chỉ có khuôn dạng xác định mà còn có các tín hiệu và hệ thống phần cứng.
Các tệp MIDI lƣu giữ một dòng các lệnh cho các hệ thống tổng hợp (synthesizer) MIDI. Các tệp đƣợc xây dựng từ các khúc (chunks). Có hai loại khúc:
header chunk và track chunk. Mỗi tệp MIDI gồm một header chunk và một hoặc nhiều track chunk.
Mỗi khúc có 4 byte để nhận dạng. Các dấu hiệu theo sau 4 byte xác định độ dài dữ liệu trong khúc (không kể 8 byte dữ liệu mô tả), cho phép một khúc dài 4GB.
Header chunk
Bắt đầu bằng các ký tự “MThd” trong dạng mã ASCII, header chunk thƣờng có độ dài 16byte, mã hoá nhƣ 06 00 00 00 theo khuôn dạng "little-endian" (Intel) trong tệp MIDI. 8byte đầu của header chunk theo dạng word biểu diễn phạm vi dữ liệu trong tệp.
·0, (trên đĩa 00 00): tệp định nghĩa một rãnh đa kênh đơn.
·1, (trên đĩa 01 00): tệp giữ một hoặc nhiều rãnh đƣợc chơi cùng một lúc. ·2, (trên đĩa 02 00): tệp nén một hoặc nhiều mẫu rãnh đơn mà chúng độc lập
với quá trình chơi liên tiếp.
Vị trí từ tiếp theo (byte thứ 11 và 12) biểu thị số track chunk riêng biệt đƣợc chứa trong tệp. Khuôn dạng này cho phép tới 65.535 chunk dữ liệu trong một tệp. Từ cuối cùng trong header chunk (byte thứ 13 và 14) xác định gía trị trung bình của delta-time trong một track chunk.
Dữ liệu trong các byte đó lấy một trong hai dạng. Khi bit MSB = 0 thì 15 bit thấp hơn biểu thị số tick trong một phần tƣ nốt nhạc. Khi bit MSB = 1 nó biểu diễn thời gian trong một time code và byte thấp hơn biểu thị số tick trong một khung SMPTE.
Track chunk
Bắt đầu với “MTrk” trong dạng mã ASCII, một track chunk bắt đầu với 8 byte nhận dạng (4byte như “MTrk”, 4byte sau biểu diễn độ dài) theo sau là một track event. Mỗi track event có hai phần, một biến độ dài delta time (1 tới 4 byte) mô tả thời gian trƣớc sự kiện và bản thân sự kiện. Sự kiện có thể là một trong số các dạng sau: một sự kiện MIDI (đơn giản là một bản tin về kênh truyền MIDI), một bản tin dành riêng của hệ thống (gọi là sysex event), hoặc một Meta event, không phải thông tin cho bộ tuần tự.
Một bản tin dành riêng của hệ thống là một chuỗi dữ liệu có dạng ba phần: một byte nhận dạng, thƣờng là F0(Hex) hoặc F7(Hex), theo sau là một tới ba byte biểu diễn độ dài chuỗi dữ liệu và bản thân chuỗi dữ liệu.
Một Meta event gồm bốn phần: byte đầu tiên thƣờng là FF(Hex), tiếp theo là mã kiểu 1byte. Tiếp theo là một biến biểu diễn độ dài của dữ liệu trong Meta event. Phần cuối cùng là dữ liệu Meta event.