Add a return value to 'WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates()'
[ardour.git] / libs / backends / wavesaudio / waves_midi_event.cc
1 /*
2     Copyright (C) 2013 Valeriy amyshniy
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 #include "memory.h"
20 #include "waves_midi_event.h"
21
22 using namespace ARDOUR;
23
24 WavesMidiEvent::WavesMidiEvent (PmTimestamp timestamp)
25     : _size (0)
26     , _timestamp (timestamp)
27     , _data (NULL)
28     , _state (INCOMPLETE) 
29 {
30
31 }
32
33
34 WavesMidiEvent::WavesMidiEvent (PmTimestamp timestamp, const uint8_t* data, size_t datalen)
35     : _size (datalen)
36     , _timestamp (timestamp)
37     , _data (data && datalen ? new uint8_t[ (datalen < sizeof (PmMessage)) ? sizeof (PmMessage) : datalen] : NULL)
38     , _state (data && datalen ? COMPLETE : BROKEN) 
39 {
40     // COMMENTED DBG LOGS */ std::cout  << "WavesMidiEvent::WavesMidiEvent (const WavesMidiEvent& source) : Size=" << _size << "---" << datalen << std::endl;
41     if (_state == COMPLETE) {
42         // COMMENTED DBG LOGS */ std::cout  << "\t\t\t Allocated Size=" << ((datalen < sizeof (PmMessage)) ? sizeof (PmMessage) : datalen) << std::endl;
43         memcpy (_data, data, datalen);
44     }
45 }
46
47
48 WavesMidiEvent::WavesMidiEvent (const WavesMidiEvent& source)
49     : _size (source.size ())
50     , _timestamp (source.timestamp ())
51     , _data ((source.size () && source.const_data ()) ? new uint8_t[ (source.size () < sizeof (PmMessage)) ? sizeof (PmMessage) : source.size ()] : NULL)
52     , _state (source.state () ) 
53 {
54     // COMMENTED DBG LOGS */ std::cout  << "WavesMidiEvent::WavesMidiEvent (const WavesMidiEvent& source) : Size=" << _size << "---" << source.size () << std::endl;
55     // COMMENTED DBG LOGS */ std::cout  << "\t\t\t Allocated Size=" << ((source.size () < sizeof (PmMessage)) ? sizeof (PmMessage) : source.size ()) << std::endl;
56     if (_data && source.const_data ()) {
57         memcpy (_data, source.const_data (), source.size ());
58     }
59 }
60
61
62 WavesMidiEvent::~WavesMidiEvent ()
63 {
64     delete _data;
65 }
66
67
68 WavesMidiEvent *WavesMidiEvent::append_data (const PmEvent &midi_event)
69 {
70     switch ( _state ) {
71         case INCOMPLETE: 
72             break;
73         default:
74             // COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::append_data (): NO case INCOMPLETE" << std::endl;
75             _state = BROKEN;
76             return NULL;
77     }
78
79     size_t message_size = _midi_message_size (midi_event.message);
80     uint8_t message_status = Pm_MessageStatus (midi_event.message);
81
82     if (_data == NULL) { // This is a first event to add
83         bool sysex = (message_status == SYSEX);
84         _data = new unsigned char [sysex ? PM_DEFAULT_SYSEX_BUFFER_SIZE : sizeof (PmMessage)];
85         if (!sysex)
86         {
87             // COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::append_data (): SHORT MSG" << std::endl;
88             * (PmMessage*)_data = 0; 
89             switch (message_size) {
90                 case 1:
91                 case 3:
92                     _size = message_size;
93                     // COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::append_data (): size = " << _size << std::endl;
94                 break;
95                 default:
96                     // COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::append_data (): WRONG MESSAGE SIZE (" << message_size << ") in the message: ";
97                     // COMMENTED DBG LOGS */ std::cout << std::hex << (int) ((unsigned char*)&midi_event)[0] << " " << (int) ((unsigned char*)&midi_event)[1] << " " << (int) ((unsigned char*)&midi_event)[2] << " " << (int) ((unsigned char*)&midi_event)[3] << std::dec << std::endl;
98                     _state = BROKEN;
99                 return NULL;
100             }
101             // COMMENTED DBG LOGS */ std::cout << "\t size = " << _size << std::endl;
102             memcpy (_data, &midi_event.message, _size);
103             // COMMENTED DBG LOGS */ std::cout << "\t\t size = " << _size << std::endl;
104             _state = COMPLETE;
105             // COMMENTED DBG LOGS */ std::cout << "\t\t\t size = " << _size << std::endl;
106             return NULL;
107         }
108     }
109
110     // Now let's parse to sysex msg
111     if (message_status >= REAL_TIME_FIRST) { // Nested Real Time MIDI event
112         WavesMidiEvent *waves_midi_message = new WavesMidiEvent (midi_event.timestamp);
113         waves_midi_message->append_data (midi_event);
114         return waves_midi_message;
115     }
116
117     if (message_status >= STATUS_FIRST && (message_status != EOX) && _size) { // Certainly it's a broken SYSEX case
118         WavesMidiEvent *waves_midi_message = new WavesMidiEvent (midi_event.timestamp);
119         waves_midi_message->append_data (midi_event);
120         return waves_midi_message;
121     }
122
123     const uint8_t* source_data ((uint8_t*)&midi_event.message);
124     
125     for (size_t i = 0; i < sizeof (midi_event.message); ++i) {
126         _data[_size] = source_data[i];
127         _size++;
128         
129         if (source_data[i] == EOX) { // Ended SYSEX message
130             _state = COMPLETE;
131             return NULL;
132         }
133     }
134     return NULL;
135 }
136
137
138 size_t WavesMidiEvent::_midi_message_size (PmMessage midi_message)
139 {
140     static int high_lengths[] = {
141         1, 1, 1, 1, 1, 1, 1, 1,         /* 0x00 through 0x70 */
142         3, 3, 3, 3, 2, 2, 3, 1          /* 0x80 through 0xf0 */
143     };
144
145     static int low_lengths[] = {
146         1, 2, 3, 2, 1, 1, 1, 1,         /* 0xf0 through 0xf7 */
147         1, 1, 1, 1, 1, 1, 1, 1          /* 0xf8 through 0xff */
148     };
149
150     int midi_message_status = Pm_MessageStatus (midi_message);
151
152     if (midi_message_status < STATUS_FIRST) {
153         return sizeof (midi_message);
154     }
155
156     int high = midi_message_status >> 4;
157     int low = midi_message_status & 0xF;
158
159     return (high != 0xF) ? high_lengths[high] : low_lengths[low];
160 }