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