midird3.m
来自「非常好的数字处理教程」· M 代码 · 共 909 行 · 第 1/3 页
M
909 行
function [midi,info,ext,ms_per_quarter,ms_per_tick] = midird3(fname,txtname)
% function [midi,info,ext,ms_per_quarter,ms_per_tick] = midird3(fname,txtname)
%
% This function reads Standard MIDI Files (SMFs) and returns their contents
% in the two structures midi and info.
%
% midi is a struct array containing one field for each track of the
% midi file. Within each field, the midi notes are given in
% the format
%
% (delta time,absolute time, midi note number, note duration, note velocity,
% channel)
%
% info contains all sideinfo from the header chunk as well as meter and time
% information from the MIDI meta events
%
% ext is all extended information besides notes contained in the MIDI file.
% This is needed, e.g., to reproduce the binary MIDI files
% using midiwr.m
%
% -> All system exclusive data are stored in ext
%
% Format of ext: (track abstime [binary MIDI sequence])
%
% ms_per_quarter milliseconds per quarter note, if indicated by
% MIDI-file (set to 0, if no information on time-coding is
% found in MIDI-file)
%
% ms_per_tick milliseconds per MIDI tick, if indicated by
% MIDI-file (set to 0, if no information on time-coding is
% found in MIDI-file)
%
% Inputs: fname Name of input MIDI-File
%
% (optional) txtname Name of Output-Textfile
%
% If the optional second argument txtname is used, a text
% version of the MIDI-file is written to a file named textname
%
% Changes: * Frank Kurth, Feb., 26th, 2004: Rework to cope with wrongly
% formatted SMFs
% * Andreas Ribbrock, Apr., 14th, 2004: Stabilized w.r.t. wrongly
% formatted SMFiles
% * Frank Kurth, May, 11th, 2004: Incorporated functionality to
% read time-coding from SMF (by Hinnerk Feldwisch and Meinard M黮ler)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%% Last changes by Frank Kurth, May, 11th, 2004
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
VLQLEN = 4; % Length of variable length quantities, currently == 4
TUPLEN = 6;
% The following are define global for use in the subfunctions within
% this file:
global smf;
global abstime;
%global ext;
%global extptr;
% some constants
UNDEF = -1; NOTEON = 0; NOTEOFF = 1; POLYAT = 2; CONTROLCHANGE = 3; PROGCHANGE = 4;
CHANNELAT = 5; PITCHWHEEL = 6; EXCEPT = 7;
% -fk 25.02.04
data = zeros(1,2);
% open input file
fid = fopen(fname,'r');
if fid < 0
disp(['midird3: Error opening MIDI file: ' fname]);
return;
end
% check if output file (MIDIasText) is requested
if nargin > 1
TXT = 1;
fidtxt = fopen(txtname,'w');
if fid < 0
disp('midird3: Error opening output file!');
fclose(fid);
return;
end
else
TXT = 0;
end
% read full MIDI file
smf = [fread(fid,inf,'uint8')' zeros(1,10)];
ptr = 1;
extptr = 1;
status = 255;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Read MIDI Track header
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ptr = NextValidHeader(ptr);
if(ptr <0 | ptr+4 > length(smf) | ptr+7 > length(smf))
disp('Midi file format error on line 99 of midird3');
fclose(fid);
info = cell(0,0);
midi = cell(0,0);
ext = cell(0,0);
return;
end
len = Read32(smf(ptr+4:ptr+7));
ptr = ptr + 8; % 'MThd'
if(ptr <0 | ptr+1 > length(smf))
disp('Midi file format error on line 110 of midird3');
fclose(fid);
info = cell(0,0);
midi = cell(0,0);
ext = cell(0,0);
return;
end
info.format = Read16(smf(ptr:ptr+1));
if(ptr <0 | ptr+2 > length(smf) | ptr+3 > length(smf))
disp('Midi file format error on line 118 of midird3');
fclose(fid);
info = cell(0,0);
midi = cell(0,0);
ext = cell(0,0);
return;
end
info.ntrks = Read16(smf(ptr+2:ptr+3));
if smf(ptr+4) < 0
info.division.up = double(uint8(smf(ptr+4)));
info.division.low = smf(ptr+5);
info.division.main = inf;
else
info.division.main = Read16(smf(ptr+4:ptr+5));
info.division.up = inf;
info.division.low = inf;
end
if TXT
fprintf(fidtxt,'MIDI Header Chunk\n\n');
fprintf(fidtxt,'MIDI File Format: %d \n',info.format);
fprintf(fidtxt,'No. of Tracks: %d\n',info.ntrks);
if smf(ptr+4) < 0
fprintf(fidtxt,'Time Division: (%d,%d)\n',[info.division.up info.division.low]);
else
fprintf(fidtxt,'Time Division: %d\n',info.division.main);
end
end
ptr = ptr + len; % 32BitLength, the length should be 6 in SMFs
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Read Tracks
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
midi = cell(1,info.ntrks);
abstime = 0;
for k = 1:info.ntrks
if(ptr < 1 | ptr > length(smf))
disp('Midi file format error on line 162 of midird3');
fclose(fid);
info = cell(0,0);
midi = cell(0,0);
ext = cell(0,0);
return;
end
ptr = NextValidHeader(ptr);
if(ptr < 1 | ptr > length(smf))
disp('Midi file format error on line 171 of midird3');
fclose(fid);
info = cell(0,0);
midi = cell(0,0);
ext = cell(0,0);
return;
end
ptrackstart = ptr;
if TXT
fprintf(fidtxt,'---------------------------------------------------------------------------\n');
fprintf(fidtxt,'MIDI Track Chunk #%d\n\n',k-1);
end
s = char(smf(ptr:ptr+3));
%s = sprintf('%s',smf(ptr:ptr+3))
if(~strcmp(s,'MTrk'))
s = sprintf('midird3: MTrk expected, %s found!',smf(ptr:ptr+3));
disp(s);
return;
end
tracklen = Read32(smf(ptr+4:ptr+7)); % track length
ptr = ptr + 8; % track start after header
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% start: process track
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
notes = zeros(tracklen,TUPLEN); % faster to create array at once
notepos = 1;
runningstatus.cmd = UNDEF;
runningstatus.channel = UNDEF;
actnotes = ones(1,TUPLEN)*-1;
uniqueID = -2;
if info.format ~= 2 % Note: abstime (here) is independent of the
abstime = 0; % time signature which is eventually
end % present in the MIDI file (Meta Event)
% abstime only counts delta ticks
while ptr <= ptrackstart + 8 + tracklen % start: track loop
if(ptr+VLQLEN-1 <0 | ptr+VLQLEN-1 > length(smf))
disp('Midi file format error on line 215 of midird3');
fclose(fid);
info = cell(0,0);
midi = cell(0,0);
ext = cell(0,0);
return;
end
if(ptr <1 | (ptr+VLQLEN-1) > length(smf))
info = cell(0,0);
midi = cell(0,0);
ext = cell(0,0);
disp('Midi file format error on line 224 of midird3');
fclose(fid);
return;
end
[delta,offs] = readvarlenintern(smf(ptr:ptr+VLQLEN-1));
if(delta == 0 & offs == 0)
info = cell(0,0);
midi = cell(0,0);
ext = cell(0,0);
disp('Midi file format error on line 234 of midird3');
fclose(fid);
return;
end
abstime = abstime + delta;
ptr = ptr+offs;
eventstring = sprintf('%d\t\t\t\t',delta);
next = double(uint8(smf(ptr)));
if(bitand(next,128)) % status byte found if expn TRUE
% evaluate new command (->running status)
status = next;
if TXT
eventstring = [eventstring sprintf('Status %x ',next)];
end
channel = bitand(next,15);
switch bitand(next,240) % &F0
case 144, % $90, NOTEON
runningstatus.cmd = NOTEON;
runningstatus.channel = channel;
ptr = ptr + 1;
case 128 % $80, NOTEOFF
runningstatus.cmd = NOTEOFF;
runningstatus.channel = channel;
ptr = ptr + 1;
case 160, % $A0, POLYAT
runningstatus.cmd = POLYAT;
runningstatus.channel = channel;
ptr = ptr + 1;
case 176, % $B0, CONTROLCHANGE
runningstatus.cmd = CONTROLCHANGE;
runningstatus.channel = channel;
ptr = ptr + 1;
case 192, % $C0, PROGCHANGE
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?