-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,194 +1,195 @@ | |||
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()) |