17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright (c) 1992-2001 by Sun Microsystems, Inc.
247c478bd9Sstevel@tonic-gate  * All rights reserved.
258e0c8248SAndrew Stormont  *
268e0c8248SAndrew Stormont  * Copyright 2019 RackTop Systems.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <memory.h>
317c478bd9Sstevel@tonic-gate #include <math.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <AudioDebug.h>
347c478bd9Sstevel@tonic-gate #include <AudioTypeSampleRate.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate // This is the first stab at a conversion class for Sample Rate conversions
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate // class AudioTypeSampleRate methods
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate // Constructor
417c478bd9Sstevel@tonic-gate AudioTypeSampleRate::
AudioTypeSampleRate(int inrate,int outrate)427c478bd9Sstevel@tonic-gate AudioTypeSampleRate(int inrate, int outrate) :
437c478bd9Sstevel@tonic-gate 	resampler(inrate, outrate), input_rate(inrate), output_rate(outrate)
447c478bd9Sstevel@tonic-gate {
457c478bd9Sstevel@tonic-gate }
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate // Destructor
487c478bd9Sstevel@tonic-gate AudioTypeSampleRate::
~AudioTypeSampleRate()497c478bd9Sstevel@tonic-gate ~AudioTypeSampleRate()
507c478bd9Sstevel@tonic-gate {
517c478bd9Sstevel@tonic-gate }
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate // Test conversion possibilities.
547c478bd9Sstevel@tonic-gate // Return TRUE if conversion to/from the specified type is possible.
557c478bd9Sstevel@tonic-gate Boolean AudioTypeSampleRate::
CanConvert(AudioHdr h) const567c478bd9Sstevel@tonic-gate CanConvert(
577c478bd9Sstevel@tonic-gate 	AudioHdr	h) const		// target header
587c478bd9Sstevel@tonic-gate {
597c478bd9Sstevel@tonic-gate 	if ((input_rate <= 0) || (output_rate <= 0))
607c478bd9Sstevel@tonic-gate 		return (FALSE);
617c478bd9Sstevel@tonic-gate 	if ((h.encoding != LINEAR) ||
627c478bd9Sstevel@tonic-gate 	    ((h.sample_rate != output_rate) && (h.sample_rate != input_rate)) ||
637c478bd9Sstevel@tonic-gate 	    (h.bytes_per_unit != 2) ||
647c478bd9Sstevel@tonic-gate 	    (h.channels != 1)) {
657c478bd9Sstevel@tonic-gate 		return (FALSE);
667c478bd9Sstevel@tonic-gate 	}
677c478bd9Sstevel@tonic-gate 	return (TRUE);
687c478bd9Sstevel@tonic-gate }
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate // Convert buffer to the specified type
727c478bd9Sstevel@tonic-gate // May replace the buffer with a new one, if necessary
737c478bd9Sstevel@tonic-gate AudioError AudioTypeSampleRate::
Convert(AudioBuffer * & inbuf,AudioHdr outhdr)747c478bd9Sstevel@tonic-gate Convert(
757c478bd9Sstevel@tonic-gate 	AudioBuffer*&	inbuf,			// data buffer to process
767c478bd9Sstevel@tonic-gate 	AudioHdr	outhdr)			// target header
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate 	AudioBuffer*	outbuf;
797c478bd9Sstevel@tonic-gate 	AudioHdr	inhdr;
807c478bd9Sstevel@tonic-gate 	Double		length;
817c478bd9Sstevel@tonic-gate 	int		i;
827c478bd9Sstevel@tonic-gate 	size_t		nsamps;
838e0c8248SAndrew Stormont #ifdef DEBUG
847c478bd9Sstevel@tonic-gate 	size_t		insamps;
858e0c8248SAndrew Stormont #endif
867c478bd9Sstevel@tonic-gate 	AudioError	err;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	inhdr = inbuf->GetHeader();
897c478bd9Sstevel@tonic-gate 	length = inbuf->GetLength();
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	if (Undefined(length)) {
927c478bd9Sstevel@tonic-gate 		return (AUDIO_ERR_BADARG);
937c478bd9Sstevel@tonic-gate 	}
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	// Make sure we're not being asked to do the impossible
967c478bd9Sstevel@tonic-gate 	// XXX - need a better error code
977c478bd9Sstevel@tonic-gate 	if ((err = inhdr.Validate()) || (err = outhdr.Validate())) {
987c478bd9Sstevel@tonic-gate 		return (err);
997c478bd9Sstevel@tonic-gate 	}
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	// If the requested conversion is different than what was initially
1027c478bd9Sstevel@tonic-gate 	// established, then return an error.
1037c478bd9Sstevel@tonic-gate 	// XXX - Maybe one day flush and re-init the filter
1047c478bd9Sstevel@tonic-gate 	if ((inhdr.sample_rate != input_rate) ||
1057c478bd9Sstevel@tonic-gate 	    (outhdr.sample_rate != output_rate)) {
1067c478bd9Sstevel@tonic-gate 		return (AUDIO_ERR_BADARG);
1077c478bd9Sstevel@tonic-gate 	}
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	// If conversion is a no-op, just return success
1107c478bd9Sstevel@tonic-gate 	if (inhdr.sample_rate == outhdr.sample_rate) {
1117c478bd9Sstevel@tonic-gate 		return (AUDIO_SUCCESS);
1127c478bd9Sstevel@tonic-gate 	}
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	// If nothing in the buffer, do the simple thing
1157c478bd9Sstevel@tonic-gate 	if (length == 0.) {
1167c478bd9Sstevel@tonic-gate 		inbuf->SetHeader(outhdr);
1177c478bd9Sstevel@tonic-gate 		return (AUDIO_SUCCESS);
1187c478bd9Sstevel@tonic-gate 	}
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	// Add some padding to the output buffer
1217c478bd9Sstevel@tonic-gate 	i = 4 * ((input_rate / output_rate) + (output_rate / input_rate));
1227c478bd9Sstevel@tonic-gate 	length += outhdr.Samples_to_Time(i);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	// Allocate a new buffer
1257c478bd9Sstevel@tonic-gate 	outbuf = new AudioBuffer(length, "(SampleRate conversion buffer)");
1267c478bd9Sstevel@tonic-gate 	if (outbuf == 0)
1277c478bd9Sstevel@tonic-gate 		return (AUDIO_UNIXERROR);
1287c478bd9Sstevel@tonic-gate 	if (err = outbuf->SetHeader(outhdr)) {
1297c478bd9Sstevel@tonic-gate 		delete outbuf;
1307c478bd9Sstevel@tonic-gate 		return (err);
1317c478bd9Sstevel@tonic-gate 	}
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	// here's where the guts go ...
1347c478bd9Sstevel@tonic-gate 	nsamps = resampler.filter((short *)inbuf->GetAddress(),
1357c478bd9Sstevel@tonic-gate 		    (int)inbuf->GetHeader().Time_to_Samples(inbuf->GetLength()),
1367c478bd9Sstevel@tonic-gate 		    (short *)outbuf->GetAddress());
1377c478bd9Sstevel@tonic-gate 
1388e0c8248SAndrew Stormont #ifdef DEBUG
1397c478bd9Sstevel@tonic-gate 	// do a sanity check. did we write more bytes then we had
1407c478bd9Sstevel@tonic-gate 	// available in the output buffer?
1417c478bd9Sstevel@tonic-gate 	insamps = (unsigned int)
1427c478bd9Sstevel@tonic-gate 		outbuf->GetHeader().Time_to_Samples(outbuf->GetSize());
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	AUDIO_DEBUG((2, "TypeResample: after filter, insamps=%d, outsamps=%d\n",
1457c478bd9Sstevel@tonic-gate 		    insamps, nsamps));
1468e0c8248SAndrew Stormont #endif
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	if (nsamps > outbuf->GetHeader().Time_to_Samples(outbuf->GetSize())) {
1497c478bd9Sstevel@tonic-gate 		AudioStderrMsg(outbuf, AUDIO_NOERROR, Fatal,
1507c478bd9Sstevel@tonic-gate 		    (char *)"resample filter corrupted the heap");
1517c478bd9Sstevel@tonic-gate 	}
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	// set output size appropriately
1547c478bd9Sstevel@tonic-gate 	outbuf->SetLength(outbuf->GetHeader().Samples_to_Time(nsamps));
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	// This will delete the buffer
1577c478bd9Sstevel@tonic-gate 	inbuf->Reference();
1587c478bd9Sstevel@tonic-gate 	inbuf->Dereference();
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	inbuf = outbuf;
1617c478bd9Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate AudioError AudioTypeSampleRate::
Flush(AudioBuffer * & outbuf)1657c478bd9Sstevel@tonic-gate Flush(
1667c478bd9Sstevel@tonic-gate 	AudioBuffer*&	outbuf)
1677c478bd9Sstevel@tonic-gate {
1687c478bd9Sstevel@tonic-gate 	AudioHdr	h;
1697c478bd9Sstevel@tonic-gate 	Double		pos;
1707c478bd9Sstevel@tonic-gate 	int		nsamp;
1717c478bd9Sstevel@tonic-gate 	size_t		cnt;
1727c478bd9Sstevel@tonic-gate 	AudioError	err;
1737c478bd9Sstevel@tonic-gate 	unsigned char	*tmpbuf;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	if (outbuf == NULL)
1767c478bd9Sstevel@tonic-gate 		return (AUDIO_SUCCESS);
1777c478bd9Sstevel@tonic-gate 	h = outbuf->GetHeader();
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	nsamp = resampler.getFlushSize();
1807c478bd9Sstevel@tonic-gate 	if (nsamp > 0) {
1817c478bd9Sstevel@tonic-gate 		cnt = (size_t)nsamp * h.bytes_per_unit;
1827c478bd9Sstevel@tonic-gate 		tmpbuf = new unsigned char[cnt];
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 		// this does a flush
1857c478bd9Sstevel@tonic-gate 		nsamp = resampler.filter(NULL, 0, (short *)tmpbuf);
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 		// Copy to the supplied buffer
1887c478bd9Sstevel@tonic-gate 		if (nsamp > 0) {
1897c478bd9Sstevel@tonic-gate 			cnt = (size_t)nsamp * h.bytes_per_unit;
1907c478bd9Sstevel@tonic-gate 			pos = outbuf->GetLength();
1917c478bd9Sstevel@tonic-gate 			err = outbuf->AppendData(tmpbuf, cnt, pos);
1927c478bd9Sstevel@tonic-gate 			if (err)
1937c478bd9Sstevel@tonic-gate 				return (err);
1947c478bd9Sstevel@tonic-gate 		}
195*7cad4b84SToomas Soome 		delete[] tmpbuf;
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
1987c478bd9Sstevel@tonic-gate }
199