fix -Wreorder
[ardour.git] / libs / backends / wavesaudio / waves_midi_event.cc
1 /*
2     Copyright (C) 2013 Waves Audio Ltd.
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "pbd/debug.h"
21 #include "pbd/compose.h"
22
23 #include "memory.h"
24 #include "waves_midi_event.h"
25
26 using namespace ARDOUR;
27 using namespace PBD;
28
29 WavesMidiEvent::WavesMidiEvent (PmTimestamp timestamp)
30     : _size (0)
31     , _timestamp (timestamp)
32     , _data (NULL)
33     , _state (INCOMPLETE)
34 {
35
36 }
37
38
39 WavesMidiEvent::WavesMidiEvent (PmTimestamp timestamp, const uint8_t* data, size_t datalen)
40     : _size (datalen)
41     , _timestamp (timestamp)
42     , _data (data && datalen ? new uint8_t[ (datalen < sizeof (PmMessage)) ? sizeof (PmMessage) : datalen] : NULL)
43     , _state (data && datalen ? COMPLETE : BROKEN)
44 {
45         DEBUG_TRACE (DEBUG::WavesMIDI, string_compose ( "WavesMidiEvent::WavesMidiEvent (const WavesMidiEvent& source) : Size=%1---%2\n", _size, datalen));
46         if (_state == COMPLETE) {
47                 DEBUG_TRACE (DEBUG::WavesMIDI, string_compose ( "\t\t\t Allocated Size=%1\n", ((datalen < sizeof (PmMessage)) ? sizeof (PmMessage) : datalen)));
48                 memcpy (_data, data, datalen);
49
50 #ifndef NDEBUG
51                 if (DEBUG_ENABLED (DEBUG::WavesMIDI)) {
52                         DEBUG_STR_DECL(a);
53                         for (size_t i=0; i < datalen; ++i) {
54                                 DEBUG_STR_APPEND(a,std::hex);
55                                 DEBUG_STR_APPEND(a,"0x");
56                                 DEBUG_STR_APPEND(a,(int)data[i]);
57                                 DEBUG_STR_APPEND(a,' ');
58                         }
59                         DEBUG_STR_APPEND(a,'\n');
60                         DEBUG_TRACE (DEBUG::WavesMIDI, DEBUG_STR(a).str());
61         }
62 #endif
63
64         }
65 }
66
67 WavesMidiEvent::WavesMidiEvent (const WavesMidiEvent& source)
68     : _size (source.size ())
69     , _timestamp (source.timestamp ())
70     , _data ((source.size () && source.const_data ()) ? new uint8_t[ (source.size () < sizeof (PmMessage)) ? sizeof (PmMessage) : source.size ()] : NULL)
71     , _state (source.state () )
72 {
73         DEBUG_TRACE (DEBUG::WavesMIDI, string_compose ( "WavesMidiEvent::WavesMidiEvent (const WavesMidiEvent& source) : Size=%1---%2\n", _size, source.size ()));
74         DEBUG_TRACE (DEBUG::WavesMIDI, string_compose ( "\t\t\t Allocated Size=%1\n", ((source.size () < sizeof (PmMessage)) ? sizeof (PmMessage) : source.size ())));
75         if (_data && source.const_data ()) {
76                 memcpy (_data, source.const_data (), source.size ());
77
78 #ifndef NDEBUG
79                 if (DEBUG_ENABLED (DEBUG::WavesMIDI)) {
80                         DEBUG_STR_DECL(a);
81                         for (size_t i=0; i < source.size(); ++i) {
82                                 DEBUG_STR_APPEND(a,std::hex);
83                                 DEBUG_STR_APPEND(a,"0x");
84                                 DEBUG_STR_APPEND(a,(int)source.const_data()[i]);
85                                 DEBUG_STR_APPEND(a,' ');
86                         }
87                         DEBUG_STR_APPEND(a,'\n');
88                         DEBUG_TRACE (DEBUG::WavesMIDI, DEBUG_STR(a).str());
89                 }
90 #endif
91         }
92 }
93
94
95 WavesMidiEvent::~WavesMidiEvent ()
96 {
97     delete _data;
98 }
99
100
101 WavesMidiEvent *WavesMidiEvent::append_data (const PmEvent &midi_event)
102 {
103         switch ( _state ) {
104         case INCOMPLETE:
105                 break;
106         default:
107                 DEBUG_TRACE (DEBUG::WavesMIDI, "WavesMidiEvent::append_data (): NO case INCOMPLETE\n");
108                 _state = BROKEN;
109                 return NULL;
110         }
111
112         size_t message_size = _midi_message_size (midi_event.message);
113         uint8_t message_status = Pm_MessageStatus (midi_event.message);
114
115         if (_data == NULL) { // This is a first event to add
116                 bool sysex = (message_status == SYSEX);
117                 _data = new unsigned char [sysex ? PM_DEFAULT_SYSEX_BUFFER_SIZE : sizeof (PmMessage)];
118                 if (!sysex)
119                 {
120                         DEBUG_TRACE (DEBUG::WavesMIDI, "WavesMidiEvent::append_data (): SHORT MSG\n");
121                         * (PmMessage*)_data = 0;
122                         switch (message_size) {
123                         case 1:
124                         case 2:
125                         case 3:
126                                 _size = message_size;
127                                 DEBUG_TRACE (DEBUG::WavesMIDI, string_compose ( "WavesMidiEvent::append_data (): size = %1\n", _size));
128                                 break;
129                          default:
130                                 DEBUG_TRACE (DEBUG::WavesMIDI, string_compose ( "WavesMidiEvent::append_data (): WRONG MESSAGE SIZE (%1 not %2) %3 [%4 %5 %6 %7] %8\n",
131                                                                                 message_size,
132                                                                                 std::hex,
133                                                                                 (int) ((unsigned char*)&midi_event)[0],
134                                                                                 (int) ((unsigned char*)&midi_event)[1],
135                                                                                 (int) ((unsigned char*)&midi_event)[2],
136                                                                                 (int) ((unsigned char*)&midi_event)[3],
137                                                                                 std::dec));
138                                 _state = BROKEN;
139                                 return NULL;
140                         }
141                         memcpy (_data, &midi_event.message, _size);
142                         _state = COMPLETE;
143                         DEBUG_TRACE (DEBUG::WavesMIDI, string_compose ( "\t\t\t size = %1\n", _size));
144                         return NULL;
145                 }
146         }
147
148         // Now let's parse to sysex msg
149         if (message_status >= REAL_TIME_FIRST) { // Nested Real Time MIDI event
150                 WavesMidiEvent *waves_midi_message = new WavesMidiEvent (midi_event.timestamp);
151                 waves_midi_message->append_data (midi_event);
152                 return waves_midi_message;
153         }
154
155         if (message_status >= STATUS_FIRST && (message_status != EOX) && _size) { // Certainly it's a broken SYSEX case
156                 WavesMidiEvent *waves_midi_message = new WavesMidiEvent (midi_event.timestamp);
157                 waves_midi_message->append_data (midi_event);
158                 return waves_midi_message;
159         }
160
161         const uint8_t* source_data ((uint8_t*)&midi_event.message);
162
163         for (size_t i = 0; i < sizeof (midi_event.message); ++i) {
164                 _data[_size] = source_data[i];
165                 _size++;
166
167                 if (source_data[i] == EOX) { // Ended SYSEX message
168                         _state = COMPLETE;
169                         return NULL;
170                 }
171         }
172         return NULL;
173 }
174
175 size_t WavesMidiEvent::_midi_message_size (PmMessage midi_message)
176 {
177     static int high_lengths[] = {
178         1, 1, 1, 1, 1, 1, 1, 1,         /* 0x00 through 0x70 */
179         3, 3, 3, 3, 2, 2, 3, 1          /* 0x80 through 0xf0 */
180     };
181
182     static int low_lengths[] = {
183         1, 2, 3, 2, 1, 1, 1, 1,         /* 0xf0 through 0xf7 */
184         1, 1, 1, 1, 1, 1, 1, 1          /* 0xf8 through 0xff */
185     };
186
187     int midi_message_status = Pm_MessageStatus (midi_message);
188
189     if (midi_message_status < STATUS_FIRST) {
190         return sizeof (midi_message);
191     }
192
193     int high = midi_message_status >> 4;
194     int low = midi_message_status & 0xF;
195
196     return (high != 0xF) ? high_lengths[high] : low_lengths[low];
197 }