-rw-r--r-- | lib/message.cc | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/lib/message.cc b/lib/message.cc index 8f9e68a..6a5cfd6 100644 --- a/lib/message.cc +++ b/lib/message.cc | |||
@@ -1,247 +1,248 @@ | |||
1 | #include <algorithm> | 1 | #include <algorithm> |
2 | #include <iterator> | 2 | #include <iterator> |
3 | #include <cassert> | ||
3 | #include <midillo/message.h> | 4 | #include <midillo/message.h> |
4 | #include <midillo/util.h> | 5 | #include <midillo/util.h> |
5 | #include <midillo/exception.h> | 6 | #include <midillo/exception.h> |
6 | 7 | ||
7 | namespace midillo { | 8 | namespace midillo { |
8 | using std::copy; | 9 | using std::copy; |
9 | using std::ostream_iterator; | 10 | using std::ostream_iterator; |
10 | 11 | ||
11 | unsigned long message_t::calculate_save_size(int& rs) const { | 12 | unsigned long message_t::calculate_save_size(int& rs) const { |
12 | unsigned long rv = 0; | 13 | unsigned long rv = 0; |
13 | if(status!=rs) { | 14 | if(status!=rs) { |
14 | ++rv; | 15 | ++rv; |
15 | rs = status; | 16 | rs = status; |
16 | }else if((status&status_event_bits)==status_system) { | 17 | }else if((status&status_event_bits)==status_system) { |
17 | rs = -1; | 18 | rs = -1; |
18 | ++rv; // XXX: is it really needed? | 19 | ++rv; // XXX: is it really needed? |
19 | } | 20 | } |
20 | switch(status&status_event_bits) { | 21 | switch(status&status_event_bits) { |
21 | case status_note_off: | 22 | case status_note_off: |
22 | case status_note_on: | 23 | case status_note_on: |
23 | case status_polyphonic_key_pressure: // aka status_aftertouch | 24 | case status_polyphonic_key_pressure: // aka status_aftertouch |
24 | case status_control_change: | 25 | case status_control_change: |
25 | case status_pitch_wheel_change: | 26 | case status_pitch_wheel_change: |
26 | rv += 2; break; | 27 | rv += 2; break; |
27 | case status_program_change: | 28 | case status_program_change: |
28 | case status_channel_pressure: | 29 | case status_channel_pressure: |
29 | ++rv; break; | 30 | ++rv; break; |
30 | case status_system: | 31 | case status_system: |
31 | switch(status&status_system_bits) { | 32 | switch(status&status_system_bits) { |
32 | case status_system_sysex: | 33 | case status_system_sysex: |
33 | case status_system_end_of_sysex: | 34 | case status_system_end_of_sysex: |
34 | rv += data.size()+1; break; | 35 | rv += data.size()+1; break; |
35 | case status_system_MTC_quarter_frame: | 36 | case status_system_MTC_quarter_frame: |
36 | case status_system_song_select: | 37 | case status_system_song_select: |
37 | ++rv; break; | 38 | ++rv; break; |
38 | case status_system_song_position_pointer: | 39 | case status_system_song_position_pointer: |
39 | rv += 2; break; | 40 | rv += 2; break; |
40 | case status_system_tune_request: | 41 | case status_system_tune_request: |
41 | case status_system_timing_clock: // aka status_system_midi_clock | 42 | case status_system_timing_clock: // aka status_system_midi_clock |
42 | case status_system_midi_tick: | 43 | case status_system_midi_tick: |
43 | case status_system_start: // aka status_system_midi_start | 44 | case status_system_start: // aka status_system_midi_start |
44 | case status_system_stop: // aka status_system_midi_stop | 45 | case status_system_stop: // aka status_system_midi_stop |
45 | case status_system_continue: // aka status_system_midi_continue | 46 | case status_system_continue: // aka status_system_midi_continue |
46 | case status_system_active_sense: | 47 | case status_system_active_sense: |
47 | break; /* XXX: ensure there is no data? */ | 48 | break; /* XXX: ensure there is no data? */ |
48 | case status_system_meta: // also reset, but not for the purpose of midi file | 49 | case status_system_meta: // also reset, but not for the purpose of midi file |
49 | ++rv; | 50 | ++rv; |
50 | rv += calcVLsize(data.size()); | 51 | rv += calcVLsize(data.size()); |
51 | rv += data.size(); | 52 | rv += data.size(); |
52 | break; | 53 | break; |
53 | default: | 54 | default: |
54 | throw exception(CODEPOINT,"Internal error"); | 55 | throw exception(CODEPOINT,"Internal error"); |
55 | break; | 56 | break; |
56 | } | 57 | } |
57 | break; | 58 | break; |
58 | default: | 59 | default: |
59 | throw exception(CODEPOINT,"Internal error"); | 60 | throw exception(CODEPOINT,"Internal error"); |
60 | break; | 61 | break; |
61 | } | 62 | } |
62 | return rv; | 63 | return rv; |
63 | } | 64 | } |
64 | 65 | ||
65 | void message_t::save(int& rs,ostream& s) const { | 66 | void message_t::save(int& rs,ostream& s) const { |
66 | if(status!=rs) { | 67 | if(status!=rs) { |
67 | s.put(status); | 68 | s.put(status); |
68 | if(!s.good()) | 69 | if(!s.good()) |
69 | throw exception_output_error(CODEPOINT,"Error writing midi status byte"); | 70 | throw exception_output_error(CODEPOINT,"Error writing midi status byte"); |
70 | rs = status; | 71 | rs = status; |
71 | }else if((status&status_event_bits)==status_system) { | 72 | }else if((status&status_event_bits)==status_system) { |
72 | rs = -1; | 73 | rs = -1; |
73 | s.put(status); // XXX: is it really needed? | 74 | s.put(status); // XXX: is it really needed? |
74 | if(!s.good()) | 75 | if(!s.good()) |
75 | throw exception_output_error(CODEPOINT,"Error writing midi system status byte"); | 76 | throw exception_output_error(CODEPOINT,"Error writing midi system status byte"); |
76 | } | 77 | } |
77 | switch(status&status_event_bits) { | 78 | switch(status&status_event_bits) { |
78 | case status_note_off: | 79 | case status_note_off: |
79 | case status_note_on: | 80 | case status_note_on: |
80 | case status_polyphonic_key_pressure: // aka status_aftertouch | 81 | case status_polyphonic_key_pressure: // aka status_aftertouch |
81 | case status_control_change: | 82 | case status_control_change: |
82 | case status_pitch_wheel_change: | 83 | case status_pitch_wheel_change: |
83 | save_data(s,2); break; | 84 | save_data(s,2); break; |
84 | case status_program_change: | 85 | case status_program_change: |
85 | case status_channel_pressure: | 86 | case status_channel_pressure: |
86 | save_data(s,1); break; | 87 | save_data(s,1); break; |
87 | case status_system: | 88 | case status_system: |
88 | switch(status&status_system_bits) { | 89 | switch(status&status_system_bits) { |
89 | case status_system_sysex: | 90 | case status_system_sysex: |
90 | case status_system_end_of_sysex: | 91 | case status_system_end_of_sysex: |
91 | save_sysex(s); break; | 92 | save_sysex(s); break; |
92 | case status_system_MTC_quarter_frame: | 93 | case status_system_MTC_quarter_frame: |
93 | case status_system_song_select: | 94 | case status_system_song_select: |
94 | save_data(s,1); break; | 95 | save_data(s,1); break; |
95 | case status_system_song_position_pointer: | 96 | case status_system_song_position_pointer: |
96 | save_data(s,2); break; | 97 | save_data(s,2); break; |
97 | case status_system_tune_request: | 98 | case status_system_tune_request: |
98 | case status_system_timing_clock: // aka status_system_midi_clock | 99 | case status_system_timing_clock: // aka status_system_midi_clock |
99 | case status_system_midi_tick: | 100 | case status_system_midi_tick: |
100 | case status_system_start: // aka status_system_midi_start | 101 | case status_system_start: // aka status_system_midi_start |
101 | case status_system_stop: // aka status_system_midi_stop | 102 | case status_system_stop: // aka status_system_midi_stop |
102 | case status_system_continue: // aka status_system_midi_continue | 103 | case status_system_continue: // aka status_system_midi_continue |
103 | case status_system_active_sense: | 104 | case status_system_active_sense: |
104 | break; /* XXX: ensure there is no data? */ | 105 | break; /* XXX: ensure there is no data? */ |
105 | case status_system_meta: // also reset, but not for the purpose of midi file | 106 | case status_system_meta: // also reset, but not for the purpose of midi file |
106 | s.put(meta_status&0xFF); | 107 | s.put(meta_status&0xFF); |
107 | if(!s.good()) | 108 | if(!s.good()) |
108 | throw exception_output_error(CODEPOINT,"Error writing meta event"); | 109 | throw exception_output_error(CODEPOINT,"Error writing meta event"); |
109 | writeVL(s,data.size()); | 110 | writeVL(s,data.size()); |
110 | save_data(s); | 111 | save_data(s); |
111 | break; | 112 | break; |
112 | default: | 113 | default: |
113 | throw exception(CODEPOINT,"Internal error"); | 114 | throw exception(CODEPOINT,"Internal error"); |
114 | break; | 115 | break; |
115 | } | 116 | } |
116 | break; | 117 | break; |
117 | default: | 118 | default: |
118 | throw exception(CODEPOINT,"Internal error"); | 119 | throw exception(CODEPOINT,"Internal error"); |
119 | break; | 120 | break; |
120 | } | 121 | } |
121 | } | 122 | } |
122 | 123 | ||
123 | void message_t::load(int& rs,istream& s) { | 124 | void message_t::load(int& rs,istream& s) { |
124 | data.clear(); | 125 | data.clear(); |
125 | status = s.get(); | 126 | status = s.get(); |
126 | if(!s.good()) | 127 | if(!s.good()) |
127 | throw exception_input_error(CODEPOINT,"Error reading MIDI event status byte"); | 128 | throw exception_input_error(CODEPOINT,"Error reading MIDI event status byte"); |
128 | if(status&status_bit) { | 129 | if(status&status_bit) { |
129 | if((status&status_event_bits)!=status_system) | 130 | if((status&status_event_bits)!=status_system) |
130 | rs = status; | 131 | rs = status; |
131 | }else{ | 132 | }else{ |
132 | if(rs<0) | 133 | if(rs<0) |
133 | throw exception_invalid_input(CODEPOINT,"Attempt to rely on the absent running status"); | 134 | throw exception_invalid_input(CODEPOINT,"Attempt to rely on the absent running status"); |
134 | data.push_back(status); | 135 | data.push_back(status); |
135 | status = rs; | 136 | status = rs; |
136 | } | 137 | } |
137 | switch(status&status_event_bits) { | 138 | switch(status&status_event_bits) { |
138 | case status_note_off: | 139 | case status_note_off: |
139 | case status_note_on: | 140 | case status_note_on: |
140 | case status_polyphonic_key_pressure: // a.k.a. status_aftertouch | 141 | case status_polyphonic_key_pressure: // a.k.a. status_aftertouch |
141 | case status_control_change: | 142 | case status_control_change: |
142 | case status_pitch_wheel_change: | 143 | case status_pitch_wheel_change: |
143 | load_data(s,2); break; | 144 | load_data(s,2); break; |
144 | case status_program_change: | 145 | case status_program_change: |
145 | case status_channel_pressure: | 146 | case status_channel_pressure: |
146 | load_data(s,1); break; | 147 | load_data(s,1); break; |
147 | case status_system: | 148 | case status_system: |
148 | switch(status&status_system_bits) { | 149 | switch(status&status_system_bits) { |
149 | case status_system_sysex: | 150 | case status_system_sysex: |
150 | case status_system_end_of_sysex: | 151 | case status_system_end_of_sysex: |
151 | load_sysex(s); break; | 152 | load_sysex(s); break; |
152 | case status_system_MTC_quarter_frame: | 153 | case status_system_MTC_quarter_frame: |
153 | case status_system_song_select: | 154 | case status_system_song_select: |
154 | load_data(s,1); break; | 155 | load_data(s,1); break; |
155 | case status_system_song_position_pointer: | 156 | case status_system_song_position_pointer: |
156 | load_data(s,2); break; | 157 | load_data(s,2); break; |
157 | case status_system_tune_request: | 158 | case status_system_tune_request: |
158 | case status_system_timing_clock: // a.k.a. status_system_midi_clock | 159 | case status_system_timing_clock: // a.k.a. status_system_midi_clock |
159 | case status_system_midi_tick: | 160 | case status_system_midi_tick: |
160 | case status_system_start: // a.k.a. status_system_midi_start | 161 | case status_system_start: // a.k.a. status_system_midi_start |
161 | case status_system_stop: // a.k.a. status_system_midi_stop | 162 | case status_system_stop: // a.k.a. status_system_midi_stop |
162 | case status_system_continue: // a.k.a. status_system_midi_continue | 163 | case status_system_continue: // a.k.a. status_system_midi_continue |
163 | case status_system_active_sense: | 164 | case status_system_active_sense: |
164 | break; | 165 | break; |
165 | case status_system_meta: // also, reset, but not in midi files | 166 | case status_system_meta: // also, reset, but not in midi files |
166 | { | 167 | { |
167 | meta_status = s.get(); | 168 | meta_status = s.get(); |
168 | if(!s.good()) | 169 | if(!s.good()) |
169 | throw exception_input_error(CODEPOINT,"Error reading meta event type"); | 170 | throw exception_input_error(CODEPOINT,"Error reading meta event type"); |
170 | int l = readVL(s); | 171 | int l = readVL(s); |
171 | load_data(s,l); | 172 | load_data(s,l); |
172 | } | 173 | } |
173 | break; | 174 | break; |
174 | default: | 175 | default: |
175 | throw exception(CODEPOINT,"Internal error"); | 176 | throw exception(CODEPOINT,"Internal error"); |
176 | break; | 177 | break; |
177 | } | 178 | } |
178 | break; | 179 | break; |
179 | default: | 180 | default: |
180 | throw exception(CODEPOINT,"Internal error"); | 181 | throw exception(CODEPOINT,"Internal error"); |
181 | break; | 182 | break; |
182 | } | 183 | } |
183 | } | 184 | } |
184 | 185 | ||
185 | void message_t::save_data(ostream& s,int c) const { | 186 | void message_t::save_data(ostream& s,int c) const { |
186 | if(c!=data.size()) | 187 | if(c!=data.size()) |
187 | throw exception(CODEPOINT,"Writing corrupt data"); | 188 | throw exception(CODEPOINT,"Writing corrupt data"); |
188 | save_data(s); | 189 | save_data(s); |
189 | } | 190 | } |
190 | 191 | ||
191 | void message_t::save_data(ostream& s) const { | 192 | void message_t::save_data(ostream& s) const { |
192 | for(bytes_t::const_iterator i=data.begin();i!=data.end();++i) | 193 | for(bytes_t::const_iterator i=data.begin();i!=data.end();++i) |
193 | s.put(*i); | 194 | s.put(*i); |
194 | if(!s.good()) | 195 | if(!s.good()) |
195 | throw exception_output_error(CODEPOINT,"Error writing MIDI message data"); | 196 | throw exception_output_error(CODEPOINT,"Error writing MIDI message data"); |
196 | } | 197 | } |
197 | 198 | ||
198 | void message_t::load_data(istream& s,int c) { | 199 | void message_t::load_data(istream& s,int c) { |
199 | c -= data.size(); | 200 | c -= data.size(); |
200 | if(c<0) | 201 | if(c<0) |
201 | throw exception(CODEPOINT,"Internal error"); | 202 | throw exception(CODEPOINT,"Internal error"); |
202 | while(c-- > 0) { | 203 | while(c-- > 0) { |
203 | data.push_back(s.get()); | 204 | data.push_back(s.get()); |
204 | if(!s.good()) | 205 | if(!s.good()) |
205 | throw exception_input_error(CODEPOINT,"Error reading MIDI data"); | 206 | throw exception_input_error(CODEPOINT,"Error reading MIDI data"); |
206 | } | 207 | } |
207 | } | 208 | } |
208 | 209 | ||
209 | void message_t::save_sysex(ostream& s) const { | 210 | void message_t::save_sysex(ostream& s) const { |
210 | save_data(s); | 211 | save_data(s); |
211 | s.put(0xF7); /* XXX: Or is it better to put it into data? */ | 212 | s.put(0xF7); /* XXX: Or is it better to put it into data? */ |
212 | if(!s.good()) | 213 | if(!s.good()) |
213 | throw exception_output_error(CODEPOINT,"Error writing sysex data"); | 214 | throw exception_output_error(CODEPOINT,"Error writing sysex data"); |
214 | } | 215 | } |
215 | 216 | ||
216 | void message_t::load_sysex(istream& s) { | 217 | void message_t::load_sysex(istream& s) { |
217 | int b = s.get(); | 218 | int b = s.get(); |
218 | if(!s.good()) | 219 | if(!s.good()) |
219 | throw exception_input_error(CODEPOINT,"Error reading sysex data"); | 220 | throw exception_input_error(CODEPOINT,"Error reading sysex data"); |
220 | assert(!(b&0x80)); // manufacturer ought to be 7 bit. not sure if it belongs here, it may well be continuation. | 221 | assert(!(b&0x80)); // manufacturer ought to be 7 bit. not sure if it belongs here, it may well be continuation. |
221 | do { | 222 | do { |
222 | data.push_back(b); | 223 | data.push_back(b); |
223 | b = s.get(); | 224 | b = s.get(); |
224 | if(!s.good()) | 225 | if(!s.good()) |
225 | throw exception_input_error(CODEPOINT,"Error reading sysex data"); | 226 | throw exception_input_error(CODEPOINT,"Error reading sysex data"); |
226 | }while(b!=0xF7); | 227 | }while(b!=0xF7); |
227 | } | 228 | } |
228 | 229 | ||
229 | void message_t::dump(ostream& s) const { | 230 | void message_t::dump(ostream& s) const { |
230 | std::ios::fmtflags ff = s.flags(); | 231 | std::ios::fmtflags ff = s.flags(); |
231 | int w = s.width(2); | 232 | int w = s.width(2); |
232 | s.unsetf(std::ios::dec); s.setf(std::ios::hex); | 233 | s.unsetf(std::ios::dec); s.setf(std::ios::hex); |
233 | s << "status=" << status; | 234 | s << "status=" << status; |
234 | if(is_meta()) { | 235 | if(is_meta()) { |
235 | s << ", meta_status=" << meta_status; | 236 | s << ", meta_status=" << meta_status; |
236 | } | 237 | } |
237 | if(!data.empty()) { | 238 | if(!data.empty()) { |
238 | s << ", data: "; | 239 | s << ", data: "; |
239 | copy( | 240 | copy( |
240 | data.begin(), data.end(), | 241 | data.begin(), data.end(), |
241 | ostream_iterator<int>(s," ") ); | 242 | ostream_iterator<int>(s," ") ); |
242 | } | 243 | } |
243 | s.width(w); | 244 | s.width(w); |
244 | s.flags(ff); | 245 | s.flags(ff); |
245 | } | 246 | } |
246 | 247 | ||
247 | } | 248 | } |