Progress on the disk side of things:
[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         , _data(NULL)
43 {
44         _size = capacity; // For audio buffers, size = capacity (always)
45         if (capacity > 0) {
46 #ifdef NO_POSIX_MEMALIGN
47                 _data =  (Sample *) malloc(sizeof(Sample) * capacity);
48 #else
49                 posix_memalign((void**)&_data, 16, sizeof(Sample) * capacity);
50 #endif  
51                 assert(_data);
52                 clear();
53                 _owns_data = true;
54         } else {
55                 _owns_data = false;
56         }
57 }
58
59 AudioBuffer::~AudioBuffer()
60 {
61         if (_owns_data)
62                 free(_data);
63 }
64
65 // FIXME: mirroring for MIDI buffers?
66 MidiBuffer::MidiBuffer(size_t capacity)
67         : Buffer(DataType::MIDI, capacity)
68 //      , _owns_data(true)
69         , _events(NULL)
70         , _data(NULL)
71 {
72         assert(capacity > 0);
73
74         _size = 0;
75
76 #ifdef NO_POSIX_MEMALIGN
77         _events =  (MidiEvent *) malloc(sizeof(MidiEvent) * capacity);
78         _data =  (RawMidi *) malloc(sizeof(RawMidi) * capacity * MAX_EVENT_SIZE);
79 #else
80         posix_memalign((void**)&_events, 16, sizeof(MidiEvent) * capacity);
81         posix_memalign((void**)&_data, 16, sizeof(RawMidi) * capacity * MAX_EVENT_SIZE);
82 #endif  
83         assert(_data);
84         assert(_events);
85         silence(_capacity);
86 }
87
88 MidiBuffer::~MidiBuffer()
89 {
90         free(_events);
91         free(_data);
92 }
93
94
95 /** Read events from @a src starting at time @a offset into the START of this buffer, for
96  * time direction @a nframes.  Relative time, where 0 = start of buffer.
97  *
98  * Note that offset and nframes refer to sample time, NOT buffer offsets or event counts.
99  */
100 void
101 MidiBuffer::read_from(const Buffer& src, jack_nframes_t nframes, jack_nframes_t offset)
102 {
103         assert(src.type() == DataType::MIDI);
104         const MidiBuffer& msrc = (MidiBuffer&)src;
105
106         assert(_capacity >= src.size());
107
108         clear();
109         assert(_size == 0);
110
111         // FIXME: This is embarrassingly slow.  branch branch branch
112         for (size_t i=0; i < src.size(); ++i) {
113                 const MidiEvent& ev = msrc[i];
114                 if (ev.time >= offset && ev.time < offset+nframes) {
115                         push_back(ev);
116                 }
117         }
118 }
119
120
121 /** Push an event into the buffer.
122  *
123  * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
124  * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
125  * Realtime safe.
126  * @return false if operation failed (not enough room)
127  */
128 bool
129 MidiBuffer::push_back(const MidiEvent& ev)
130 {
131         if (_size == _capacity)
132                 return false;
133
134         RawMidi* const write_loc = _data + (_size * MAX_EVENT_SIZE);
135
136         memcpy(write_loc, ev.buffer, ev.size);
137         _events[_size] = ev;
138         _events[_size].buffer = write_loc;
139         ++_size;
140
141         //cerr << "MidiBuffer: pushed, size = " << _size << endl;
142
143         return true;
144 }
145
146
147 void
148 MidiBuffer::silence(jack_nframes_t dur, jack_nframes_t offset)
149 {
150         // FIXME use parameters
151         assert(offset == 0);
152         //assert(dur == _capacity);
153
154         memset(_events, 0, sizeof(MidiEvent) * _capacity);
155         memset(_data, 0, sizeof(RawMidi) * _capacity * MAX_EVENT_SIZE);
156         _size = 0;
157 }
158
159
160 } // namespace ARDOUR
161