xref: /illumos-gate/usr/src/cmd/audio/utilities/AudioTypeSampleRate.cc (revision 7d98732934f32a5f80fe624c9689e8f54dd17ffe)
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::
AudioTypeSampleRate(int inrate,int outrate)42 AudioTypeSampleRate(int inrate, int outrate) :
43 	resampler(inrate, outrate), input_rate(inrate), output_rate(outrate)
44 {
45 }
46 
47 // Destructor
48 AudioTypeSampleRate::
~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::
CanConvert(AudioHdr h) const56 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::
Convert(AudioBuffer * & inbuf,AudioHdr outhdr)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 	err = outbuf->SetHeader(outhdr);
129 	if (err != AUDIO_SUCCESS) {
130 		delete outbuf;
131 		return (err);
132 	}
133 
134 	// here's where the guts go ...
135 	nsamps = resampler.filter((short *)inbuf->GetAddress(),
136 		    (int)inbuf->GetHeader().Time_to_Samples(inbuf->GetLength()),
137 		    (short *)outbuf->GetAddress());
138 
139 #ifdef DEBUG
140 	// do a sanity check. did we write more bytes then we had
141 	// available in the output buffer?
142 	insamps = (unsigned int)
143 		outbuf->GetHeader().Time_to_Samples(outbuf->GetSize());
144 
145 	AUDIO_DEBUG((2, "TypeResample: after filter, insamps=%d, outsamps=%d\n",
146 		    insamps, nsamps));
147 #endif
148 
149 	if (nsamps > outbuf->GetHeader().Time_to_Samples(outbuf->GetSize())) {
150 		AudioStderrMsg(outbuf, AUDIO_NOERROR, Fatal,
151 		    (char *)"resample filter corrupted the heap");
152 	}
153 
154 	// set output size appropriately
155 	outbuf->SetLength(outbuf->GetHeader().Samples_to_Time(nsamps));
156 
157 	// This will delete the buffer
158 	inbuf->Reference();
159 	inbuf->Dereference();
160 
161 	inbuf = outbuf;
162 	return (AUDIO_SUCCESS);
163 }
164 
165 AudioError AudioTypeSampleRate::
Flush(AudioBuffer * & outbuf)166 Flush(
167 	AudioBuffer*&	outbuf)
168 {
169 	AudioHdr	h;
170 	Double		pos;
171 	int		nsamp;
172 	size_t		cnt;
173 	AudioError	err;
174 	unsigned char	*tmpbuf;
175 
176 	if (outbuf == NULL)
177 		return (AUDIO_SUCCESS);
178 	h = outbuf->GetHeader();
179 
180 	nsamp = resampler.getFlushSize();
181 	if (nsamp > 0) {
182 		cnt = (size_t)nsamp * h.bytes_per_unit;
183 		tmpbuf = new unsigned char[cnt];
184 
185 		// this does a flush
186 		nsamp = resampler.filter(NULL, 0, (short *)tmpbuf);
187 
188 		// Copy to the supplied buffer
189 		if (nsamp > 0) {
190 			cnt = (size_t)nsamp * h.bytes_per_unit;
191 			pos = outbuf->GetLength();
192 			err = outbuf->AppendData(tmpbuf, cnt, pos);
193 			if (err)
194 				return (err);
195 		}
196 		delete[] tmpbuf;
197 	}
198 	return (AUDIO_SUCCESS);
199 }
200