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