1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1992-2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 * 26 * Copyright 2019 RackTop Systems. 27 */ 28 29 #include <stdlib.h> 30 #include <memory.h> 31 #include <math.h> 32 33 #include <AudioDebug.h> 34 #include <AudioTypeSampleRate.h> 35 36 // This is the first stab at a conversion class for Sample Rate conversions 37 38 // class AudioTypeSampleRate methods 39 40 // Constructor 41 AudioTypeSampleRate:: 42 AudioTypeSampleRate(int inrate, int outrate) : 43 resampler(inrate, outrate), input_rate(inrate), output_rate(outrate) 44 { 45 } 46 47 // Destructor 48 AudioTypeSampleRate:: 49 ~AudioTypeSampleRate() 50 { 51 } 52 53 // Test conversion possibilities. 54 // Return TRUE if conversion to/from the specified type is possible. 55 Boolean AudioTypeSampleRate:: 56 CanConvert( 57 AudioHdr h) const // target header 58 { 59 if ((input_rate <= 0) || (output_rate <= 0)) 60 return (FALSE); 61 if ((h.encoding != LINEAR) || 62 ((h.sample_rate != output_rate) && (h.sample_rate != input_rate)) || 63 (h.bytes_per_unit != 2) || 64 (h.channels != 1)) { 65 return (FALSE); 66 } 67 return (TRUE); 68 } 69 70 71 // Convert buffer to the specified type 72 // May replace the buffer with a new one, if necessary 73 AudioError AudioTypeSampleRate:: 74 Convert( 75 AudioBuffer*& inbuf, // data buffer to process 76 AudioHdr outhdr) // target header 77 { 78 AudioBuffer* outbuf; 79 AudioHdr inhdr; 80 Double length; 81 int i; 82 size_t nsamps; 83 #ifdef DEBUG 84 size_t insamps; 85 #endif 86 AudioError err; 87 88 inhdr = inbuf->GetHeader(); 89 length = inbuf->GetLength(); 90 91 if (Undefined(length)) { 92 return (AUDIO_ERR_BADARG); 93 } 94 95 // Make sure we're not being asked to do the impossible 96 // XXX - need a better error code 97 if ((err = inhdr.Validate()) || (err = outhdr.Validate())) { 98 return (err); 99 } 100 101 // If the requested conversion is different than what was initially 102 // established, then return an error. 103 // XXX - Maybe one day flush and re-init the filter 104 if ((inhdr.sample_rate != input_rate) || 105 (outhdr.sample_rate != output_rate)) { 106 return (AUDIO_ERR_BADARG); 107 } 108 109 // If conversion is a no-op, just return success 110 if (inhdr.sample_rate == outhdr.sample_rate) { 111 return (AUDIO_SUCCESS); 112 } 113 114 // If nothing in the buffer, do the simple thing 115 if (length == 0.) { 116 inbuf->SetHeader(outhdr); 117 return (AUDIO_SUCCESS); 118 } 119 120 // Add some padding to the output buffer 121 i = 4 * ((input_rate / output_rate) + (output_rate / input_rate)); 122 length += outhdr.Samples_to_Time(i); 123 124 // Allocate a new buffer 125 outbuf = new AudioBuffer(length, "(SampleRate conversion buffer)"); 126 if (outbuf == 0) 127 return (AUDIO_UNIXERROR); 128 if (err = outbuf->SetHeader(outhdr)) { 129 delete outbuf; 130 return (err); 131 } 132 133 // here's where the guts go ... 134 nsamps = resampler.filter((short *)inbuf->GetAddress(), 135 (int)inbuf->GetHeader().Time_to_Samples(inbuf->GetLength()), 136 (short *)outbuf->GetAddress()); 137 138 #ifdef DEBUG 139 // do a sanity check. did we write more bytes then we had 140 // available in the output buffer? 141 insamps = (unsigned int) 142 outbuf->GetHeader().Time_to_Samples(outbuf->GetSize()); 143 144 AUDIO_DEBUG((2, "TypeResample: after filter, insamps=%d, outsamps=%d\n", 145 insamps, nsamps)); 146 #endif 147 148 if (nsamps > outbuf->GetHeader().Time_to_Samples(outbuf->GetSize())) { 149 AudioStderrMsg(outbuf, AUDIO_NOERROR, Fatal, 150 (char *)"resample filter corrupted the heap"); 151 } 152 153 // set output size appropriately 154 outbuf->SetLength(outbuf->GetHeader().Samples_to_Time(nsamps)); 155 156 // This will delete the buffer 157 inbuf->Reference(); 158 inbuf->Dereference(); 159 160 inbuf = outbuf; 161 return (AUDIO_SUCCESS); 162 } 163 164 AudioError AudioTypeSampleRate:: 165 Flush( 166 AudioBuffer*& outbuf) 167 { 168 AudioHdr h; 169 Double pos; 170 int nsamp; 171 size_t cnt; 172 AudioError err; 173 unsigned char *tmpbuf; 174 175 if (outbuf == NULL) 176 return (AUDIO_SUCCESS); 177 h = outbuf->GetHeader(); 178 179 nsamp = resampler.getFlushSize(); 180 if (nsamp > 0) { 181 cnt = (size_t)nsamp * h.bytes_per_unit; 182 tmpbuf = new unsigned char[cnt]; 183 184 // this does a flush 185 nsamp = resampler.filter(NULL, 0, (short *)tmpbuf); 186 187 // Copy to the supplied buffer 188 if (nsamp > 0) { 189 cnt = (size_t)nsamp * h.bytes_per_unit; 190 pos = outbuf->GetLength(); 191 err = outbuf->AppendData(tmpbuf, cnt, pos); 192 if (err) 193 return (err); 194 } 195 delete[] tmpbuf; 196 } 197 return (AUDIO_SUCCESS); 198 } 199