Fixes for IO port adding/removing
[ardour.git] / libs / ardour / buffer.cc
1 /*
2     Copyright (C) 2006 Paul Davis 
3     
4     This program is free software; you can redistribute it and/or modify it
5     under the terms of the GNU General Public License as published by the Free
6     Software Foundation; either version 2 of the License, or (at your option)
7     any later version.
8     
9     This program is distributed in the hope that it will be useful, but WITHOUT
10     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12     for more details.
13     
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <algorithm>
20 #include <iostream>
21 using std::cerr; using std::endl;
22
23 #include <ardour/buffer.h>
24
25 namespace ARDOUR {
26
27
28 Buffer*
29 Buffer::create(DataType type, size_t capacity)
30 {
31         if (type == DataType::AUDIO)
32                 return new AudioBuffer(capacity);
33         else if (type == DataType::MIDI)
34                 return new MidiBuffer(capacity);
35         else
36                 return NULL;
37 }
38
39
40 AudioBuffer::AudioBuffer(size_t capacity)
41         : Buffer(DataType::AUDIO, capacity)
42         , _owns_data(false)
43         , _data(NULL)
44 {
45         _size = capacity; // For audio buffers, size = capacity (always)
46         if (capacity > 0) {
47 #ifdef NO_POSIX_MEMALIGN
48                 _data =  (Sample *) malloc(sizeof(Sample) * capacity);
49 #else
50                 posix_memalign((void**)&_data, 16, sizeof(Sample) * capacity);
51 #endif  
52                 assert(_data);
53                 _owns_data = true;
54                 clear();
55         }
56 }
57
58 AudioBuffer::~AudioBuffer()
59 {
60         if (_owns_data)
61                 free(_data);
62 }
63
64 // FIXME: mirroring for MIDI buffers?
65 MidiBuffer::MidiBuffer(size_t capacity)
66         : Buffer(DataType::MIDI, capacity)
67 //      , _owns_data(true)
68         , _events(NULL)
69         , _data(NULL)
70 {
71         assert(capacity > 0);
72
73         _size = 0;
74
75 #ifdef NO_POSIX_MEMALIGN
76         _events =  (MidiEvent *) malloc(sizeof(MidiEvent) * capacity);
77         _data =  (RawMidi *) malloc(sizeof(RawMidi) * capacity * MAX_EVENT_SIZE);
78 #else
79         posix_memalign((void**)&_events, 16, sizeof(MidiEvent) * capacity);
80         posix_memalign((void**)&_data, 16, sizeof(RawMidi) * capacity * MAX_EVENT_SIZE);
81 #endif  
82         assert(_data);
83         assert(_events);
84         silence(_capacity);
85 }
86
87 MidiBuffer::~MidiBuffer()
88 {
89         free(_events);
90         free(_data);
91 }
92
93
94 /** Read events from @a src starting at time @a offset into the START of this buffer, for
95  * time direction @a nframes.  Relative time, where 0 = start of buffer.
96  *
97  * Note that offset and nframes refer to sample time, NOT buffer offsets or event counts.
98  */
99 void
100 MidiBuffer::read_from(const Buffer& src, jack_nframes_t nframes, jack_nframes_t offset)
101 {
102         assert(src.type() == DataType::MIDI);
103         const MidiBuffer& msrc = (MidiBuffer&)src;
104
105         assert(_capacity >= src.size());
106
107         clear();
108         assert(_size == 0);
109
110         // FIXME: slow
111         for (size_t i=0; i < src.size(); ++i) {
112                 const MidiEvent& ev = msrc[i];
113                 if (ev.time >= offset && ev.time < offset+nframes) {
114                         push_back(ev);
115                 }
116         }
117
118         _silent = src.silent();
119 }
120
121
122 /** Push an event into the buffer.
123  *
124  * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
125  * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
126  * Realtime safe.
127  * @return false if operation failed (not enough room)
128  */
129 bool
130 MidiBuffer::push_back(const MidiEvent& ev)
131 {
132         if (_size == _capacity)
133                 return false;
134
135         RawMidi* const write_loc = _data + (_size * MAX_EVENT_SIZE);
136
137         memcpy(write_loc, ev.buffer, ev.size);
138         _events[_size] = ev;
139         _events[_size].buffer = write_loc;
140         ++_size;
141
142         //cerr << "MidiBuffer: pushed, size = " << _size << endl;
143
144         _silent = false;
145
146         return true;
147 }
148
149
150 void
151 MidiBuffer::silence(jack_nframes_t dur, jack_nframes_t offset)
152 {
153         // FIXME use parameters
154         assert(offset == 0);
155         //assert(dur == _capacity);
156
157         memset(_events, 0, sizeof(MidiEvent) * _capacity);
158         memset(_data, 0, sizeof(RawMidi) * _capacity * MAX_EVENT_SIZE);
159         _size = 0;
160         _silent = true;
161 }
162
163
164 } // namespace ARDOUR
165