Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/openal-0.0.8/src/audioconvert/ac_helper.c @ 17

Last change on this file since 17 was 17, checked in by landauf, 17 years ago

added openal

File size: 5.7 KB
Line 
1/* -*- mode: C; tab-width:8; c-basic-offset:8 -*-
2 * vi:set ts=8:
3 *
4 * ac_helper.c
5 *
6 * audioconvert helper funcs.
7 *
8 * This file and the funcs within taken almost whole from:
9 *     SDL - Simple DirectMedia Layer
10 *     Copyright (C) 1997, 1998, 1999  Sam Lantinga
11 */
12
13/* Functions for audio drivers to perform runtime conversion of audio format */
14
15#include "al_siteconfig.h"
16
17#include <AL/al.h>
18#include <assert.h>
19#include <stdio.h>
20#include <stdlib.h>
21
22#include "audioconvert/audioconvert.h"
23
24void acConvertSign(acAudioCVT *cvt, ALushort format);
25void acConvertEndian(acAudioCVT *cvt, ALushort format);
26
27/* Toggle signed/unsigned */
28void acConvertSign(acAudioCVT *cvt, ALushort format) {
29        int i;
30        ALubyte *data;
31
32        data = cvt->buf;
33        if((format & 0xFF) == 16) {
34                if((format & 0x1000) != 0x1000) { /* Little endian */
35                        ++data;
36                }
37
38                for(i = cvt->len_cvt/2; i; i-- ) {
39                        *data ^= 0x80;
40                        data += 2;
41                }
42        } else {
43                for(i = cvt->len_cvt; i; i-- ) {
44                        *data++ ^= 0x80;
45                }
46        }
47
48        format = (format ^ 0x8000);
49
50        if (cvt->filters[++cvt->filter_index] ) {
51                cvt->filters[cvt->filter_index](cvt, format);
52        }
53}
54
55/* Toggle endianness */
56void acConvertEndian(acAudioCVT *cvt, ALushort format) {
57        int i;
58        ALubyte *data, tmp;
59
60        data = cvt->buf;
61        for(i = cvt->len_cvt/2; i; i--) {
62                tmp     = data[0];
63                data[0] = data[1];
64                data[1] = tmp;
65                data   += 2;
66        }
67
68        format = (format ^ 0x1000);
69
70        if (cvt->filters[++cvt->filter_index] ) {
71                cvt->filters[cvt->filter_index](cvt, format);
72        }
73}
74
75
76/* Creates a set of audio filters to convert from one format to another.
77   Returns -1 if the format conversion is not supported, or 1 if the
78   audio filter is set up.
79*/
80
81int acBuildAudioCVT(acAudioCVT *cvt,
82        ALushort src_format, ALubyte src_channels, ALuint src_rate,
83        ALushort dst_format, ALubyte dst_channels, ALuint dst_rate) {
84
85        /* Start off with no conversion necessary */
86        cvt->needed       = 0;
87        cvt->filter_index = 0;
88        cvt->filters[0]   = NULL;
89        cvt->len_mult     = 1;
90        cvt->len_ratio    = 1.0;
91
92        /* First filter:  Endian conversion from src to dst */
93        if((( src_format & 0x1000) != (dst_format & 0x1000)) &&
94            (( src_format & 0xff) != 8))
95        {
96                cvt->filters[cvt->filter_index++] = acConvertEndian;
97        }
98
99        /* Third filter: Sign conversion -- signed/unsigned */
100        if((src_format & 0x8000) != (dst_format & 0x8000)) {
101                cvt->filters[cvt->filter_index++] = acConvertSign;
102        }
103
104        /* Second filter:  Convert 16 bit <--> 8 bit PCM */
105        if((src_format & 0xFF) != (dst_format & 0xFF)) {
106                switch(dst_format & 0x10FF) {
107                        case AUDIO_U8:
108                                cvt->filters[cvt->filter_index++] =
109                                                         acConvert8;
110                                cvt->len_ratio /= 2;
111                                break;
112                        case AUDIO_U16LSB:
113                                cvt->filters[cvt->filter_index++] =
114                                                        acConvert16LSB;
115                                cvt->len_mult *= 2;
116                                cvt->len_ratio *= 2;
117                                break;
118                        case AUDIO_U16MSB:
119                                cvt->filters[cvt->filter_index++] =
120                                                        acConvert16MSB;
121                                cvt->len_mult *= 2;
122                                cvt->len_ratio *= 2;
123                                break;
124                        default:
125                                break;
126                }
127        }
128
129        /* Last filter:  Mono/Stereo conversion */
130        if(src_channels != dst_channels) {
131                while((src_channels * 2) <= dst_channels) {
132                        cvt->filters[cvt->filter_index++] =
133                                                acConvertStereo;
134                        src_channels   *= 2;
135                        cvt->len_mult  *= 2;
136                        cvt->len_ratio *= 2;
137                }
138
139                /*
140                 * This assumes that 4 channel audio is in the format:
141                 * Left {front/back} + Right {front/back}
142                 * so converting to L/R stereo works properly.
143                 */
144                while(((src_channels%2) == 0) &&
145                        ((src_channels/2) >= dst_channels)) {
146                        cvt->filters[cvt->filter_index++] =
147                                                 acConvertMono;
148                        src_channels   /= 2;
149                        cvt->len_ratio /= 2;
150                }
151                if ( src_channels != dst_channels ) {
152                        /* Uh oh.. */;
153                }
154        }
155
156        /* Do rate conversion */
157        cvt->rate_incr = 0.0;
158        if((src_rate / 100) != (dst_rate / 100)) {
159                ALuint hi_rate, lo_rate;
160                int len_mult;
161                double len_ratio;
162                void (*rate_cvt)(acAudioCVT *, ALushort );
163
164                assert(src_rate != 0);
165
166                if ( src_rate > dst_rate ) {
167                        hi_rate   = src_rate;
168                        lo_rate   = dst_rate;
169                        rate_cvt  = acFreqDIV2;
170                        len_mult  = 1;
171                        len_ratio = 0.5;
172                } else {
173                        hi_rate   = dst_rate;
174                        lo_rate   = src_rate;
175                        rate_cvt  = acFreqMUL2;
176                        len_mult  = 2;
177                        len_ratio = 2.0;
178                }
179                /* If hi_rate = lo_rate*2^x then conversion is easy */
180                while(((lo_rate * 2)/100) <= (hi_rate/100)) {
181                        cvt->filters[cvt->filter_index++] = rate_cvt;
182                        lo_rate        *= 2;
183                        cvt->len_mult  *= len_mult;
184                        cvt->len_ratio *= len_ratio;
185                }
186
187                /* We may need a slow conversion here to finish up */
188                if((lo_rate/100) != (hi_rate/100)) {
189#if 0
190                        /* The problem with this is that if the input buffer is
191                           say 1K, and the conversion rate is say 1.1, then the
192                           output buffer is 1.1K, which may not be an acceptable
193                           buffer size for the audio driver (not a power of 2)
194                        */
195                        /* For now, punt and hope the rate distortion isn't great.
196                        */
197#else
198                        if ( src_rate < dst_rate ) {
199                                cvt->rate_incr = (double)lo_rate/hi_rate;
200                                cvt->len_mult *= 2;
201                                cvt->len_ratio /= cvt->rate_incr;
202                        } else {
203                                cvt->rate_incr = (double)hi_rate/lo_rate;
204                                cvt->len_ratio *= cvt->rate_incr;
205                        }
206                        cvt->filters[cvt->filter_index++] = acFreqSLOW;
207#endif
208                }
209        }
210
211        /* Set up the filter information */
212        if(cvt->filter_index != 0) {
213                cvt->needed     = 1;
214                cvt->len        = 0;
215                cvt->buf        = NULL;
216                cvt->src_format = src_format;
217                cvt->dst_format = dst_format;
218                cvt->filters[cvt->filter_index] = NULL;
219        }
220
221        return cvt->needed;
222}
223
224int acConvertAudio(acAudioCVT *cvt) {
225        /* Make sure there's data to convert */
226        if(cvt->buf == NULL) {
227#ifdef DEBUG_MAXIMUS
228                fprintf(stderr,
229                        "ALD_MAXIMUS\t[%s:%d]\t %s\n",
230                        __FILE__, __LINE__,
231                        "No buffer allocated for conversion");
232#endif
233                return -1;
234        }
235
236        /* Return okay if no conversion is necessary */
237        cvt->len_cvt = cvt->len;
238        if(cvt->filters[0] == NULL) {
239                return 0;
240        }
241
242        /* Set up the conversion and go! */
243        cvt->filter_index = 0;
244        cvt->filters[0](cvt, cvt->src_format);
245
246        return 0;
247}
Note: See TracBrowser for help on using the repository browser.