summaryrefslogtreecommitdiffabout
path: root/lib/message.cc
Unidiff
Diffstat (limited to 'lib/message.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--lib/message.cc1
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
7namespace midillo { 8namespace 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}