1 /*
2 * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
3 * Copyright (C) 2007-2017 Paul Davis <paul@linuxaudiosystems.com>
4 * Copyright (C) 2008-2012 Hans Baier <hansfbaier@googlemail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #ifndef __ardour_midi_ring_buffer_h__
22 #define __ardour_midi_ring_buffer_h__
23
24 #include <iostream>
25 #include <algorithm>
26
27 #include "ardour/event_ring_buffer.h"
28 #include "ardour/libardour_visibility.h"
29 #include "ardour/types.h"
30 #include "ardour/midi_state_tracker.h"
31
32 namespace ARDOUR {
33
34 class MidiBuffer;
35
36 /** A RingBuffer for (MIDI) events.
37 *
38 * This is simply a wrapper around a raw ringbuffer which writes/reads events
39 * as flat placked blobs.
40 * The buffer looks like this:
41 *
42 * [timestamp][type][size][size bytes of raw MIDI][timestamp][type][size](etc...)
43 */
44 template<typename T>
45 class /*LIBARDOUR_API*/ MidiRingBuffer : public EventRingBuffer<T> {
46 public:
47 /** @param size Size in bytes. */
MidiRingBuffer(size_t size)48 MidiRingBuffer(size_t size) : EventRingBuffer<T>(size) {}
49
50 inline bool read_prefix(T* time, Evoral::EventType* type, uint32_t* size);
51 inline bool read_contents(uint32_t size, uint8_t* buf);
52
53 size_t read(MidiBuffer& dst, samplepos_t start, samplepos_t end, samplecnt_t offset=0, bool stop_on_overflow_in_destination=false);
54 size_t skip_to(samplepos_t start);
55
56 void dump(std::ostream& dst);
57 void flush (samplepos_t start, samplepos_t end);
58
59 void reset_tracker ();
60 void resolve_tracker (MidiBuffer& dst, samplepos_t);
61 void resolve_tracker (Evoral::EventSink<samplepos_t>& dst, samplepos_t);
62
63 private:
64 MidiStateTracker _tracker;
65 };
66
67
68 /** Read the time and size of an event. This call MUST be immediately proceeded
69 * by a call to read_contents (or the read pointer will be garbage).
70 */
71 template<typename T>
72 inline bool
read_prefix(T * time,Evoral::EventType * type,uint32_t * size)73 MidiRingBuffer<T>::read_prefix(T* time, Evoral::EventType* type, uint32_t* size)
74 {
75 if (PBD::RingBufferNPT<uint8_t>::read((uint8_t*)time, sizeof(T)) != sizeof (T)) {
76 return false;
77 }
78
79 if (PBD::RingBufferNPT<uint8_t>::read((uint8_t*)type, sizeof(Evoral::EventType)) != sizeof (Evoral::EventType)) {
80 return false;
81 }
82
83 if (PBD::RingBufferNPT<uint8_t>::read((uint8_t*)size, sizeof(uint32_t)) != sizeof (uint32_t)) {
84 return false;
85 }
86
87 return true;
88 }
89
90
91 /** Read the content of an event. This call MUST be immediately preceded
92 * by a call to read_prefix (or the returned even will be garbage).
93 */
94 template<typename T>
95 inline bool
read_contents(uint32_t size,uint8_t * buf)96 MidiRingBuffer<T>::read_contents(uint32_t size, uint8_t* buf)
97 {
98 return PBD::RingBufferNPT<uint8_t>::read(buf, size) == size;
99 }
100
101 } // namespace ARDOUR
102
103 #endif // __ardour_midi_ring_buffer_h__
104
105