1/*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions, and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions, and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32// RawBuffer.cpp
33// e.moon 31mar99
34
35#include "RawBuffer.h"
36
37#include <RealtimeAlloc.h>
38#include <Debug.h>
39#include <cstring>
40
41// -------------------------------------------------------- //
42// ctor/dtor/accessors
43// -------------------------------------------------------- //
44
45// allocate buffer (if frames > 0)
46RawBuffer::RawBuffer(
47	uint32 frameSize,
48	uint32 frames,
49	bool bCircular,
50	rtm_pool* pFromPool) :
51
52	m_pData(0),
53	m_pPool(pFromPool),
54	m_frameSize(frameSize),
55	m_frames(frames),
56	m_allocatedSize(0),
57	m_bCircular(bCircular),
58	m_bOwnData(true)
59{
60
61	if(m_frames)
62		resize(m_frames);
63}
64
65// point to given data (does NOT take responsibility for
66// deleting it; use adopt() for that.)
67RawBuffer::RawBuffer(
68	void* pData,
69	uint32 frameSize,
70	uint32 frames,
71	bool bCircular,
72	rtm_pool* pFromPool) :
73
74	m_pData(pData),
75	m_pPool(pFromPool),
76	m_frameSize(frameSize),
77	m_frames(frames),
78	m_allocatedSize(0),
79	m_bCircular(bCircular),
80	m_bOwnData(false)
81{}
82
83RawBuffer::RawBuffer(const RawBuffer& clone) {
84	operator=(clone);
85}
86
87// generate a reference to the buffer
88RawBuffer& RawBuffer::operator=(const RawBuffer& clone) {
89	m_pData = clone.m_pData;
90	m_allocatedSize = clone.m_allocatedSize;
91	m_frameSize = clone.m_frameSize;
92	m_frames = clone.m_frames;
93	m_bCircular = clone.m_bCircular;
94	m_pPool = clone.m_pPool;
95	m_bOwnData = false;
96
97	return *this;
98}
99
100// deallocate if I own the data
101RawBuffer::~RawBuffer() {
102	free();
103}
104
105char* RawBuffer::data() const { return (char*)m_pData; }
106// returns pointer to given frame
107char* RawBuffer::frame(uint32 frame) const {
108	return data() + (frame * frameSize());
109}
110uint32 RawBuffer::frameSize() const { return m_frameSize; }
111uint32 RawBuffer::frames() const { return m_frames; }
112uint32 RawBuffer::size() const { return m_frames * m_frameSize; }
113
114bool RawBuffer::isCircular() const { return m_bCircular; }
115bool RawBuffer::ownsBuffer() const { return m_bOwnData; }
116
117rtm_pool* RawBuffer::pool() const { return m_pPool; }
118
119// resize buffer, re-allocating if necessary to contain
120// designated number of frames.
121// Does not preserve buffer contents.
122
123void RawBuffer::resize(uint32 frames) {
124	uint32 sizeRequired = frames * m_frameSize;
125
126	// already have enough storage?
127	if(sizeRequired 	< m_allocatedSize &&
128		m_bOwnData) {
129		m_frames = frames;
130		return;
131	}
132
133	// free existing storage
134	free();
135
136	// allocate
137	m_pData = (m_pPool) ?
138		rtm_alloc(m_pPool, sizeRequired) :
139		new int8[sizeRequired];
140
141	m_bOwnData = true;
142	m_allocatedSize = sizeRequired;
143	m_frames = frames;
144
145}
146
147// take ownership of buffer from target
148// (deletes current buffer data, if any owned)
149
150void RawBuffer::adopt(
151	void* pData,
152	uint32 frameSize,
153	uint32 frames,
154	bool bCircular,
155	rtm_pool* pPool) {
156
157	// clean up myself first
158	free();
159
160	// reference
161	operator=(RawBuffer(pData, frameSize, frames, bCircular, pPool));
162
163	// mark ownership
164	m_bOwnData = true;
165}
166
167// returns false if the target doesn't own the data, but references it
168// one way or the other
169
170bool RawBuffer::adopt(RawBuffer& target) {
171
172	// reference
173	operator=(target);
174
175	// take ownership if possible
176
177	if(!target.m_bOwnData) {
178		m_bOwnData = false;
179		return false;
180	}
181
182	target.m_bOwnData = false;
183	m_bOwnData = true;
184	return true;
185}
186
187// adopt currently ref'd data (if any; returns false if no buffer data or
188// already owned)
189
190bool RawBuffer::adopt() {
191	if(!m_pData || m_bOwnData)
192		return false;
193
194	m_bOwnData = true;
195	return true;
196}
197
198// -------------------------------------------------------- //
199// operations
200// -------------------------------------------------------- //
201
202// fill the buffer with zeroes
203
204void RawBuffer::zero() {
205	if(!m_pData || !m_frames)
206		return;
207
208	memset(m_pData, 0, m_frames * m_frameSize);
209}
210
211// raw copy to destination buffer, returning the number of
212// frames written, and adjusting both offsets accordingly.
213//
214// no frames will be written if the buffers' frame sizes
215// differ.
216
217uint32 RawBuffer::rawCopyTo(
218	RawBuffer& target,
219	uint32* pioFromFrame,
220	uint32* pioTargetFrame,
221	uint32 frames) const {
222
223	if(m_frameSize != target.m_frameSize)
224		return 0;
225
226	ASSERT(m_pData);
227	ASSERT(m_frames);
228	ASSERT(target.m_pData);
229
230	// convert frame counts to byte offsets
231	uint32 fromOffset = *pioFromFrame * m_frameSize;
232	uint32 targetOffset = *pioTargetFrame * m_frameSize;
233
234	// figure buffer sizes in bytes
235	uint32 size = m_frames * m_frameSize;
236	uint32 targetSize = target.m_frames * target.m_frameSize;
237
238	// figure amount to write
239	uint32 toCopy = frames * m_frameSize;
240	if(target.m_bCircular) {
241		if(toCopy > targetSize)
242			toCopy = targetSize;
243	} else {
244		if(toCopy > (targetSize-targetOffset))
245			toCopy = (targetSize-targetOffset);
246	}
247	uint32 remaining = toCopy;
248
249	// do it
250	while(remaining) {
251
252		// figure a contiguous area to fill
253		uint32 targetChunk = targetSize - targetOffset;
254
255		if(targetChunk > remaining)
256			targetChunk = remaining;
257
258		// fill it (from one or more source areas)
259		while(targetChunk > 0) {
260
261			// figure a contiguous source area
262			uint32 sourceChunk = size - fromOffset;
263			if(sourceChunk > targetChunk)
264				sourceChunk = targetChunk;
265
266			// copy it
267			memcpy(
268				(int8*)target.m_pData + targetOffset,
269				(int8*)m_pData + fromOffset,
270				sourceChunk);
271
272			// advance offsets
273			targetOffset += sourceChunk;
274			if(targetOffset == targetSize)
275				targetOffset = 0;
276
277			fromOffset += sourceChunk;
278			if(fromOffset == size)
279				fromOffset = 0;
280
281			// figure remaining portion of target area to fill
282			targetChunk -= sourceChunk;
283			remaining -= sourceChunk;
284		}
285	}
286
287	// write new offsets
288	*pioFromFrame = fromOffset / m_frameSize;
289	*pioTargetFrame = targetOffset / m_frameSize;
290
291	return toCopy;
292}
293
294// more convenient version of above if you don't care
295// how the offsets change.
296
297uint32 RawBuffer::rawCopyTo(
298	RawBuffer& target,
299	uint32 fromOffset,
300	uint32 targetOffset,
301	uint32 frames) const {
302
303	return rawCopyTo(target, &fromOffset, &targetOffset, frames);
304}
305
306// -------------------------------------------------------- //
307// internal operations
308// -------------------------------------------------------- //
309
310// free owned data, if any
311// [16jun99] uses proper rtm_free() call if needed
312void RawBuffer::free() {
313	if(!(m_bOwnData && m_pData))
314		return;
315
316	if(m_pPool)
317		rtm_free(m_pData);
318	else
319		delete [] (int8 *)m_pData;
320
321	m_pData = 0;
322}
323
324
325// END -- RawBuffer.cpp --
326