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