summaryrefslogtreecommitdiff
path: root/libs/ardour/ardour/buffer.h
blob: fe9516cb8403cf2c3e965774ff81c71447269e92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/*
    Copyright (C) 2006 Paul Davis 
    
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the Free
    Software Foundation; either version 2 of the License, or (at your option)
    any later version.
    
    This program is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    for more details.
    
    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef __ardour_buffer_h__
#define __ardour_buffer_h__

#include <cstdlib>
#include <cassert>
#include <iostream>
#include <boost/utility.hpp>
#include <ardour/types.h>
#include <ardour/data_type.h>
#include <ardour/runtime_functions.h>

namespace ARDOUR {


/** A buffer of recordable/playable data.
 *
 * This is a datatype-agnostic base class for all buffers (there are no
 * methods to actually access the data).  This provides a way for code that
 * doesn't care about the data type to still deal with buffers (which is
 * why the base class can't be a template).
 * 
 * To actually read/write buffer contents, use the appropriate derived class.
 */
class Buffer : public boost::noncopyable
{
public:
	virtual ~Buffer() {}

	/** Factory function */
	static Buffer* create(DataType type, size_t capacity);

	/** Maximum capacity of buffer.
	 * Note in some cases the entire buffer may not contain valid data, use size. */
	size_t capacity() const { return _capacity; }

	/** Amount of valid data in buffer.  Use this over capacity almost always. */
	size_t size() const { return _size; }

	/** Type of this buffer.
	 * Based on this you can static cast a Buffer* to the desired type. */
	DataType type() const { return _type; }

	bool silent() const { return _silent; }

	/** Clear (eg zero, or empty) buffer starting at TIME @a offset */
	virtual void silence(nframes_t len, nframes_t offset=0) = 0;
	
	/** Clear the entire buffer */
	virtual void clear() { silence(_capacity, 0); }

	virtual void read_from(const Buffer& src, nframes_t offset, nframes_t len) = 0;

protected:
	Buffer(DataType type, size_t capacity)
	: _type(type), _capacity(capacity), _size(0), _silent(true)
	{}

	DataType _type;
	size_t   _capacity;
	size_t   _size;
	bool     _silent;
};


/* Inside every class with a type in it's name is a template waiting to get out... */


/** Buffer containing 32-bit floating point (audio) data. */
class AudioBuffer : public Buffer
{
public:
	AudioBuffer(size_t capacity);
	
	~AudioBuffer();

	void silence(nframes_t len, nframes_t offset=0)
	{
		if (!_silent) {
			assert(_capacity > 0);
			assert(offset + len <= _capacity);
			memset(_data + offset, 0, sizeof (Sample) * len);
			if (offset == 0 && len == _capacity) {
				_silent = true;
			}
		}
	}
	
	/** Read @a len frames FROM THE START OF @a src into self at @a offset */
	void read_from(const Buffer& src, nframes_t len, nframes_t offset)
	{
		assert(_capacity > 0);
		assert(src.type() == _type == DataType::AUDIO);
		assert(offset + len <= _capacity);
		memcpy(_data + offset, ((AudioBuffer&)src).data(), sizeof(Sample) * len);
		_silent = src.silent();
	}
	
	/** Accumulate (add)@a len frames FROM THE START OF @a src into self at @a offset */
	void accumulate_from(const AudioBuffer& src, nframes_t len, nframes_t offset)
	{
		assert(_capacity > 0);
		assert(offset + len <= _capacity);

		Sample*       const dst_raw = _data + offset;
		const Sample* const src_raw = src.data();

		for (nframes_t n = 0; n < len; ++n) {
			dst_raw[n] += src_raw[n];
		}

		_silent = (src.silent() && _silent);
	}
	
	/** Accumulate (add) @a len frames FROM THE START OF @a src into self at @a offset
	 * scaling by @a gain_coeff */
	void accumulate_with_gain_from(const AudioBuffer& src, nframes_t len, nframes_t offset, gain_t gain_coeff)
	{
		assert(_capacity > 0);
		assert(offset + len <= _capacity);

		Sample*       const dst_raw = _data + offset;
		const Sample* const src_raw = src.data();

		mix_buffers_with_gain (dst_raw, src_raw, len, gain_coeff);

		_silent = ( (src.silent() && _silent) || (_silent && gain_coeff == 0) );
	}
	
	void apply_gain(gain_t gain, nframes_t len, nframes_t offset=0) {
		apply_gain_to_buffer (_data + offset, len, gain);
	}

	/** Set the data contained by this buffer manually (for setting directly to jack buffer).
	 * 
	 * Constructor MUST have been passed capacity=0 or this will die (to prevent mem leaks).
	 */
	void set_data(Sample* data, size_t size)
	{
		assert(!_owns_data); // prevent leaks
		_capacity = size;
		_size = size;
		_data = data;
		_silent = false;
	}

	const Sample* data () const { return _data; }
	Sample* data () { return _data; }

	const Sample* data(nframes_t nframes, nframes_t offset) const
		{ assert(offset + nframes <= _capacity); return _data + offset; }

	Sample* data (nframes_t nframes, nframes_t offset)
		{ assert(offset + nframes <= _capacity); return _data + offset; }

private:
	bool    _owns_data;
	Sample* _data; ///< Actual buffer contents
};



/** Buffer containing 8-bit unsigned char (MIDI) data. */
class MidiBuffer : public Buffer
{
public:
	MidiBuffer(size_t capacity);
	
	~MidiBuffer();

	void silence(nframes_t dur, nframes_t offset=0);
	
	void read_from(const Buffer& src, nframes_t nframes, nframes_t offset);

	bool  push_back(const ARDOUR::MidiEvent& event);
	bool  push_back(const jack_midi_event_t& event);
	Byte* reserve(double time, size_t size);
	
	const MidiEvent& operator[](size_t i) const { assert(i < _size); return _events[i]; }
	MidiEvent& operator[](size_t i) { assert(i < _size); return _events[i]; }

	static size_t max_event_size() { return MAX_EVENT_SIZE; }

private:
	// FIXME: Jack needs to tell us this
	static const size_t MAX_EVENT_SIZE = 4; // bytes
	
	/* We use _size as "number of events", so the size of _data is
	 * (_size * MAX_EVENT_SIZE)
	 */

	MidiEvent* _events; ///< Event structs that point to offsets in _data
	Byte*      _data;   ///< MIDI, straight up.  No time stamps.
};

} // namespace ARDOUR

#endif // __ardour_buffer_h__