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// AudioBuffer.cpp
33// e.moon 31mar99
34//
35
36#include <Buffer.h>
37#include <Debug.h>
38#include <RealtimeAlloc.h>
39#include "AudioBuffer.h"
40#include "SoundUtils.h"
41
42#include <cmath>
43#include <cstring>
44
45#include "audio_buffer_tools.h"
46
47const media_raw_audio_format AudioBuffer::defaultFormat = {
48	44100.0,
49	2,
50	media_raw_audio_format::B_AUDIO_FLOAT,
51	media_raw_audio_format::wildcard.byte_order,
52	media_raw_audio_format::wildcard.buffer_size
53};
54
55// -------------------------------------------------------- //
56// ctor/dtor/accessors
57// -------------------------------------------------------- //
58
59AudioBuffer::AudioBuffer(
60	const media_raw_audio_format& format,
61	rtm_pool* pFromPool) :
62
63	RawBuffer(
64		(format.format & 0x0f) * format.channel_count,
65		0,
66		true,
67		pFromPool),
68	m_format(format) {}
69
70AudioBuffer::AudioBuffer(
71	const media_raw_audio_format& format,
72	uint32 frames,
73	bool bCircular,
74	rtm_pool* pFromPool) :
75
76	RawBuffer(
77		(format.format & 0x0f) * format.channel_count,
78		0,
79		bCircular,
80		pFromPool),
81	m_format(format) {
82
83	resize(frames);
84}
85
86AudioBuffer::AudioBuffer(
87	const media_raw_audio_format& format,
88	void* pData,
89	uint32 frames,
90	bool bCircular,
91	rtm_pool* pFromPool) :
92
93	RawBuffer(
94		pData,
95		(format.format & 0x0f) * format.channel_count,
96		frames,
97		bCircular,
98		pFromPool) {}
99
100AudioBuffer::AudioBuffer(
101	const media_raw_audio_format& format,
102	BBuffer* pBuffer,
103	bool bCircular) :
104
105	RawBuffer(),
106	m_format(format)
107
108{
109	if(pBuffer->Header()->type != B_MEDIA_RAW_AUDIO)
110		return;
111
112	// reference it:
113	m_pData = pBuffer->Data();
114	m_frameSize = bytes_per_frame(m_format);
115	m_frames = pBuffer->Header()->size_used / m_frameSize;
116	m_allocatedSize = 0;
117	m_bOwnData = false;
118	m_bCircular = bCircular;
119}
120
121// generate a reference (point) to the target's buffer
122AudioBuffer::AudioBuffer(const AudioBuffer& clone) :
123	RawBuffer(clone),
124	m_format(clone.m_format) {}
125
126AudioBuffer& AudioBuffer::operator=(const AudioBuffer& clone) {
127	RawBuffer::operator=(clone);
128	m_format = clone.m_format;
129	return *this;
130}
131
132AudioBuffer::~AudioBuffer() {}
133
134// format access
135
136void AudioBuffer::setFormat(const media_raw_audio_format& format) {
137	m_format = format;
138}
139
140const media_raw_audio_format& AudioBuffer::format() const {
141	return m_format;
142}
143
144// extra adoption support
145
146void AudioBuffer::adopt(
147	const media_raw_audio_format& format,
148	void* pData,
149	uint32 frames,
150	bool bCircular,
151	rtm_pool* pFromPool) {
152
153	// clean up myself first
154	free();
155
156	// reference
157	operator=(AudioBuffer(format, pData, frames, bCircular, pFromPool));
158
159	// mark ownership
160	m_bOwnData = true;
161}
162
163// as with RawBuffer::adopt(), returns false if the target
164// doesn't own its buffer, but references it anyway
165
166bool AudioBuffer::adopt(AudioBuffer& target) {
167	m_format = target.m_format;
168	return RawBuffer::adopt(target);
169}
170
171// -------------------------------------------------------- //
172// operations
173// -------------------------------------------------------- //
174
175// test for format equivalence against target buffer
176// (ie. determine whether any conversion would be necessary
177//  for copy/mix operations)
178
179bool AudioBuffer::formatSameAs(const AudioBuffer& target) const {
180	return
181		m_format.format == target.m_format.format &&
182		m_format.channel_count == target.m_format.channel_count;
183}
184
185// copy to target audio buffer, applying any necessary
186// format conversions.  behaves like rawCopyTo().
187
188uint32 AudioBuffer::copyTo(
189	AudioBuffer& target,
190	uint32* pioFromFrame,
191	uint32* pioTargetFrame,
192	uint32 frames) const {
193
194	// simplest case:
195	if(formatSameAs(target))
196		return rawCopyTo(target, pioFromFrame, pioTargetFrame, frames);
197
198	// sanity checks
199	ASSERT(m_pData);
200	ASSERT(m_frames);
201	ASSERT(target.m_pData);
202
203	// figure byte offsets & sizes
204	uint32 fromOffset = *pioFromFrame * m_frameSize;
205	uint32 targetOffset = *pioTargetFrame * m_frameSize;
206
207	uint32 size = m_frames * m_frameSize;
208	uint32 targetSize = target.m_frames * target.m_frameSize;
209
210	// figure number of samples to convert
211	uint32 toCopy = frames * m_format.channel_count;
212	if(target.m_bCircular) {
213		if(toCopy > targetSize)
214			toCopy = targetSize;
215	} else {
216		if(toCopy > (targetSize-targetOffset))
217			toCopy = (targetSize-targetOffset);
218	}
219	uint32 remaining = toCopy;
220
221	uint32 sampleSize = m_frameSize / m_format.channel_count;
222
223	// convert and copy a sample at a time
224	for(; remaining; remaining -= sampleSize) {
225		convert_sample(
226			(void*) ((int8*)m_pData + fromOffset),
227			(void*) ((int8*)target.m_pData + targetOffset),
228			m_format.format,
229			target.m_format.format);
230
231		fromOffset += sampleSize;
232		if(fromOffset == size)
233			fromOffset = 0;
234
235		targetOffset += sampleSize;
236		if(targetOffset == targetSize)
237			targetOffset = 0;
238	}
239
240	// write new offsets
241	*pioFromFrame = fromOffset / m_frameSize;
242	*pioTargetFrame = targetOffset / m_frameSize;
243
244	return toCopy;
245}
246
247uint32 AudioBuffer::copyTo(
248	AudioBuffer& target,
249	uint32* pioFromFrame,
250	uint32* pioTargetFrame) const {
251
252	return copyTo(target, pioFromFrame, pioTargetFrame, m_frames);
253}
254
255// mix to target audio buffer, applying any necessary
256// format conversions.  behaves like rawCopyTo().
257
258uint32 AudioBuffer::mixTo(
259	AudioBuffer& target,
260	uint32* pioFromFrame,
261	uint32* pioTargetFrame,
262	uint32 frames,
263	float fGain /*=1.0*/) const { return 0; } //nyi
264
265// calculate minimum & maximum peak levels
266// (converted/scaled to given type if necessary)
267// pMax and pMin must point to arrays with enough room
268// for one value per channel.  existing array values aren't
269// cleared first.
270//
271// (if pMin isn't provided, the maximum absolute levels will
272// be written to pMax)
273
274void AudioBuffer::findMin(float* pMin, uint32* pAt /*=0*/) const {
275	findMin(0, m_frames, pMin, pAt);
276}
277
278uint32 AudioBuffer::findMin(uint32 fromFrame, uint32 frameCount,
279	float* pMin, uint32* pAt /*=0*/) const {
280
281	size_t channels = m_format.channel_count;
282	size_t samples = m_frames * channels;
283	size_t bytesPerSample = m_format.format & 0x0f;
284
285	size_t firstSample = fromFrame * channels;
286	size_t remaining = frameCount * channels;
287
288	if(!m_pData)
289		return fromFrame;
290
291	int8* pCur = (int8*)m_pData + (firstSample * bytesPerSample);
292
293	uint32 n;
294
295	if(pAt) {
296		// reset pAt
297		for(n = 0; n < channels; n++)
298			pAt[n] = UINT32_MAX;
299	}
300
301	// find minimum for each channel
302	for(
303		n = firstSample;
304		remaining;
305		remaining--, n++, pCur += bytesPerSample) {
306
307		// wrap around to start of buffer?
308		if(n == samples) {
309			pCur = (int8*)m_pData;
310			n = 0;
311		}
312
313		float fCur = 0;
314		convert_sample(pCur, fCur, m_format.format);
315
316		if(fCur < pMin[n % channels]) {
317			pMin[n % channels] = fCur;
318			if(pAt)
319				pAt[n % channels] = n / channels;
320		}
321	}
322
323	// return current frame
324	return n / channels;
325}
326
327void AudioBuffer::findMax(float* pMax, uint32* pAt /*=0*/) const {
328	findMax(0, m_frames, pMax, pAt);
329}
330
331uint32 AudioBuffer::findMax(uint32 fromFrame, uint32 frameCount,
332	float* pMax, uint32* pAt /*=0*/) const {
333
334	size_t channels = m_format.channel_count;
335	size_t samples = m_frames * channels;
336	size_t bytesPerSample = m_format.format & 0x0f;
337
338	size_t firstSample = fromFrame * channels;
339	size_t remaining = frameCount * channels;
340
341	if(!m_pData)
342		return fromFrame;
343
344	int8* pCur = (int8*)m_pData + (firstSample * bytesPerSample);
345
346	uint32 n;
347
348	if(pAt) {
349		// reset pAt
350		for(n = 0; n < channels; n++)
351			pAt[n] = UINT32_MAX;
352	}
353
354	// find minimum for each channel
355	for(
356		n = firstSample;
357		remaining;
358		remaining--, n++, pCur += bytesPerSample) {
359
360		// wrap around to start of buffer?
361		if(n == samples) {
362			pCur = (int8*)m_pData;
363			n = 0;
364		}
365
366		float fCur = 0;
367		convert_sample(pCur, fCur, m_format.format);
368
369		if(fCur > pMax[n % channels]) {
370			pMax[n % channels] = fCur;
371			if(pAt)
372				pAt[n % channels] = n / channels;
373		}
374	}
375
376	// return current frame
377	return n / channels;
378}
379
380void AudioBuffer::findPeaks(float* pPeaks, uint32* pAt /*=0*/) const {
381	findPeaks(0, m_frames, pPeaks, pAt);
382}
383
384uint32 AudioBuffer::findPeaks(uint32 fromFrame, uint32 frameCount,
385	float* pPeaks, uint32* pAt) const {
386
387	size_t channels = m_format.channel_count;
388	size_t samples = m_frames * channels;
389	size_t bytesPerSample = m_format.format & 0x0f;
390
391	size_t firstSample = fromFrame * channels;
392	size_t remaining = frameCount * channels;
393
394	if(!m_pData)
395		return fromFrame;
396	int8* pCur = (int8*)m_pData + (firstSample * bytesPerSample);
397
398	uint32 n;
399
400	if(pAt) {
401		// reset pAt
402		for(n = 0; n < channels; n++)
403			pAt[n] = UINT32_MAX;
404	}
405
406	// find peaks in both directions
407	for(
408		n = firstSample;
409		remaining;
410		remaining--, n++, pCur += bytesPerSample) {
411
412		// wrap around to start of buffer?
413		if(n == samples) {
414			pCur = (int8*)m_pData;
415			n = 0;
416		}
417
418		float fCur = 0;
419		convert_sample(pCur, fCur, m_format.format);
420
421		if(fabs(fCur) > pPeaks[n % channels]) {
422			pPeaks[n % channels] = fCur;
423			if(pAt)
424				pAt[n % channels] = n / channels;
425		}
426	}
427
428	// return current frame
429	return n / channels;
430}
431
432// find average level
433// (converted/scaled as necessary)
434// pAverage must point to an array with enough room
435// for one value per channel.
436
437void AudioBuffer::average(float* pAverage) const {
438	average(0, m_frames, pAverage);
439}
440
441uint32 AudioBuffer::average(uint32 fromFrame, uint32 frameCount,
442	float* pAverage) const {
443
444	size_t channels = m_format.channel_count;
445	size_t samples = m_frames * channels;
446	size_t bytesPerSample = m_format.format & 0x0f;
447
448	size_t firstSample = fromFrame * channels;
449	size_t remaining = frameCount * channels;
450
451	if(!m_pData)
452		return fromFrame;
453	int8* pCur = (int8*)m_pData + (firstSample * bytesPerSample);
454
455	// clear averages
456	memset(pAverage, 0, sizeof(float)*channels);
457
458	// calculate
459	uint32 n;
460	for(
461		n = firstSample;
462		remaining;
463		remaining--, n++, pCur += bytesPerSample) {
464
465		// wrap around to start of buffer
466		if(n == samples) {
467			pCur = (int8*)m_pData;
468			n = 0;
469		}
470
471		float fCur = 0;
472		convert_sample(pCur, fCur, m_format.format);
473
474		pAverage[n%channels] += fCur;
475	}
476
477	for(uint32 n = 0; n < channels; n++)
478		pAverage[n] /= frameCount;
479
480	// return current frame
481	return n / channels;
482}
483
484// -------------------------------------------------------- //
485
486
487// END -- AudioBuffer.h --
488