ivan@81
|
1 function rawbytes=writemidi(midi,filename,do_run_mode)
|
ivan@81
|
2 % rawbytes=writemidi(midi,filename,do_run_mode)
|
ivan@81
|
3 %
|
ivan@81
|
4 % writes to a midi file
|
ivan@81
|
5 %
|
ivan@81
|
6 % midi is a structure like that created by readmidi.m
|
ivan@81
|
7 %
|
ivan@81
|
8 % do_run_mode: flag - use running mode when possible.
|
ivan@81
|
9 % if given, will override the msg.used_running_mode
|
ivan@81
|
10 % default==0. (1 may not work...)
|
ivan@81
|
11 %
|
ivan@81
|
12 % TODO: use note-on for note-off... (for other function...)
|
ivan@81
|
13 %
|
ivan@81
|
14
|
ivan@81
|
15 % Copyright (c) 2009 Ken Schutte
|
ivan@81
|
16 % more info at: http://www.kenschutte.com/midi
|
ivan@81
|
17
|
ivan@81
|
18
|
ivan@81
|
19 %if (nargin<3)
|
ivan@81
|
20 do_run_mode = 0;
|
ivan@81
|
21 %end
|
ivan@81
|
22
|
ivan@81
|
23
|
ivan@81
|
24 % do each track:
|
ivan@81
|
25 Ntracks = length(midi.track);
|
ivan@81
|
26
|
ivan@81
|
27 for i=1:Ntracks
|
ivan@81
|
28
|
ivan@81
|
29 databytes_track{i} = [];
|
ivan@81
|
30
|
ivan@81
|
31 for j=1:length(midi.track(i).messages)
|
ivan@81
|
32
|
ivan@81
|
33 msg = midi.track(i).messages(j);
|
ivan@81
|
34
|
ivan@81
|
35 msg_bytes = encode_var_length(msg.deltatime);
|
ivan@81
|
36
|
ivan@81
|
37 if (msg.midimeta==1)
|
ivan@81
|
38
|
ivan@81
|
39 % check for doing running mode
|
ivan@81
|
40 run_mode = 0;
|
ivan@81
|
41 run_mode = msg.used_running_mode;
|
ivan@81
|
42
|
ivan@81
|
43 % should check that prev msg has same type to allow run
|
ivan@81
|
44 % mode...
|
ivan@81
|
45
|
ivan@81
|
46
|
ivan@81
|
47 % if (j>1 && do_run_mode && msg.type == midi.track(i).messages(j-1).type)
|
ivan@81
|
48 % run_mode = 1;
|
ivan@81
|
49 % end
|
ivan@81
|
50
|
ivan@81
|
51
|
ivan@81
|
52 msg_bytes = [msg_bytes; encode_midi_msg(msg, run_mode)];
|
ivan@81
|
53
|
ivan@81
|
54
|
ivan@81
|
55 else
|
ivan@81
|
56
|
ivan@81
|
57 msg_bytes = [msg_bytes; encode_meta_msg(msg)];
|
ivan@81
|
58
|
ivan@81
|
59 end
|
ivan@81
|
60
|
ivan@81
|
61 % disp(msg_bytes')
|
ivan@81
|
62
|
ivan@81
|
63 %if (msg_bytes ~= msg.rawbytes)
|
ivan@81
|
64 % error('rawbytes mismatch');
|
ivan@81
|
65 %end
|
ivan@81
|
66
|
ivan@81
|
67 databytes_track{i} = [databytes_track{i}; msg_bytes];
|
ivan@81
|
68
|
ivan@81
|
69 end
|
ivan@81
|
70 end
|
ivan@81
|
71
|
ivan@81
|
72
|
ivan@81
|
73 % HEADER
|
ivan@81
|
74 % double('MThd') = [77 84 104 100]
|
ivan@81
|
75 rawbytes = [77 84 104 100 ...
|
ivan@81
|
76 0 0 0 6 ...
|
ivan@81
|
77 encode_int(midi.format,2) ...
|
ivan@81
|
78 encode_int(Ntracks,2) ...
|
ivan@81
|
79 encode_int(midi.ticks_per_quarter_note,2) ...
|
ivan@81
|
80 ]';
|
ivan@81
|
81
|
ivan@81
|
82 % TRACK_CHUCKS
|
ivan@81
|
83 for i=1:Ntracks
|
ivan@81
|
84 a = length(databytes_track{i});
|
ivan@81
|
85 % double('MTrk') = [77 84 114 107]
|
ivan@81
|
86 tmp = [77 84 114 107 ...
|
ivan@81
|
87 encode_int(length(databytes_track{i}),4) ...
|
ivan@81
|
88 databytes_track{i}']';
|
ivan@81
|
89 rawbytes(end+1:end+length(tmp)) = tmp;
|
ivan@81
|
90 end
|
ivan@81
|
91
|
ivan@81
|
92
|
ivan@81
|
93 % write to file
|
ivan@81
|
94 fid = fopen(filename,'w');
|
ivan@81
|
95 %fwrite(fid,rawbytes,'char');
|
ivan@81
|
96 fwrite(fid,rawbytes,'uint8');
|
ivan@81
|
97 fclose(fid);
|
ivan@81
|
98
|
ivan@81
|
99 % return a _column_ vector
|
ivan@81
|
100 function A=encode_int(val,Nbytes)
|
ivan@81
|
101
|
ivan@81
|
102 for i=1:Nbytes
|
ivan@81
|
103 A(i) = bitand(bitshift(val, -8*(Nbytes-i)), 255);
|
ivan@81
|
104 end
|
ivan@81
|
105
|
ivan@81
|
106
|
ivan@81
|
107 function bytes=encode_var_length(val)
|
ivan@81
|
108
|
ivan@81
|
109 binStr = dec2base(round(val),2);
|
ivan@81
|
110 Nbytes = ceil(length(binStr)/7);
|
ivan@81
|
111
|
ivan@81
|
112 binStr = ['00000000' binStr];
|
ivan@81
|
113 bytes = [];
|
ivan@81
|
114 for i=1:Nbytes
|
ivan@81
|
115 if (i==1)
|
ivan@81
|
116 lastbit = '0';
|
ivan@81
|
117 else
|
ivan@81
|
118 lastbit = '1';
|
ivan@81
|
119 end
|
ivan@81
|
120 B = bin2dec([lastbit binStr(end-i*7+1:end-(i-1)*7)]);
|
ivan@81
|
121 bytes = [B; bytes];
|
ivan@81
|
122 end
|
ivan@81
|
123
|
ivan@81
|
124
|
ivan@81
|
125 function bytes=encode_midi_msg(msg, run_mode)
|
ivan@81
|
126
|
ivan@81
|
127 bytes = [];
|
ivan@81
|
128
|
ivan@81
|
129 if (run_mode ~= 1)
|
ivan@81
|
130 bytes = msg.type;
|
ivan@81
|
131 % channel:
|
ivan@81
|
132 bytes = bytes + msg.chan; % lower nibble should be chan
|
ivan@81
|
133 end
|
ivan@81
|
134
|
ivan@81
|
135 bytes = [bytes; msg.data];
|
ivan@81
|
136
|
ivan@81
|
137 function bytes=encode_meta_msg(msg)
|
ivan@81
|
138
|
ivan@81
|
139 bytes = 255;
|
ivan@81
|
140 bytes = [bytes; msg.type];
|
ivan@81
|
141 bytes = [bytes; encode_var_length(length(msg.data))];
|
ivan@81
|
142 bytes = [bytes; msg.data];
|
ivan@81
|
143
|