Mercurial > mplayer.hg
annotate libmpcodecs/ad_msadpcm.c @ 20807:da9d37758410
sync w/ 20191, patch by Alexandre Coutherez %newt A neopulsar P org%
author | gpoirier |
---|---|
date | Thu, 09 Nov 2006 20:57:55 +0000 |
parents | 9d0b052c4f74 |
children | 1767c271d710 |
rev | line source |
---|---|
5408 | 1 /* |
2 MS ADPCM Decoder for MPlayer | |
3 by Mike Melanson | |
4 | |
5 This file is responsible for decoding Microsoft ADPCM data. | |
6 Details about the data format can be found here: | |
7 http://www.pcisys.net/~melanson/codecs/ | |
8 */ | |
9 | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
10 #include <stdio.h> |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
11 #include <stdlib.h> |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
12 #include <unistd.h> |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
13 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
14 #include "config.h" |
5408 | 15 #include "bswap.h" |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
16 #include "ad_internal.h" |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
17 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
18 static ad_info_t info = |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
19 { |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
20 "MS ADPCM audio decoder", |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
21 "msadpcm", |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
22 "Nick Kurshev", |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
23 "Mike Melanson", |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
24 "" |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
25 }; |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
26 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
27 LIBAD_EXTERN(msadpcm) |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
28 |
5408 | 29 static int ms_adapt_table[] = |
30 { | |
31 230, 230, 230, 230, 307, 409, 512, 614, | |
32 768, 614, 512, 409, 307, 230, 230, 230 | |
33 }; | |
34 | |
35 static int ms_adapt_coeff1[] = | |
36 { | |
37 256, 512, 0, 192, 240, 460, 392 | |
38 }; | |
39 | |
40 static int ms_adapt_coeff2[] = | |
41 { | |
42 0, -256, 0, 64, 0, -208, -232 | |
43 }; | |
44 | |
6609 | 45 #define MS_ADPCM_PREAMBLE_SIZE 6 |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
46 |
7893 | 47 #define LE_16(x) ((x)[0]+(256*((x)[1]))) |
7890 | 48 //#define LE_16(x) (le2me_16((x)[1]+(256*((x)[0])))) |
7888 | 49 //#define LE_16(x) (le2me_16(*(unsigned short *)(x))) |
50 //#define LE_32(x) (le2me_32(*(unsigned int *)(x))) | |
5408 | 51 |
52 // useful macros | |
53 // clamp a number between 0 and 88 | |
54 #define CLAMP_0_TO_88(x) if (x < 0) x = 0; else if (x > 88) x = 88; | |
55 // clamp a number within a signed 16-bit range | |
56 #define CLAMP_S16(x) if (x < -32768) x = -32768; \ | |
57 else if (x > 32767) x = 32767; | |
58 // clamp a number above 16 | |
59 #define CLAMP_ABOVE_16(x) if (x < 16) x = 16; | |
60 // sign extend a 16-bit value | |
61 #define SE_16BIT(x) if (x & 0x8000) x -= 0x10000; | |
62 // sign extend a 4-bit value | |
63 #define SE_4BIT(x) if (x & 0x8) x -= 0x10; | |
64 | |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
65 static int preinit(sh_audio_t *sh_audio) |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
66 { |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
67 sh_audio->audio_out_minsize = sh_audio->wf->nBlockAlign * 4; |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
68 sh_audio->ds->ss_div = |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
69 (sh_audio->wf->nBlockAlign - MS_ADPCM_PREAMBLE_SIZE) * 2; |
5458 | 70 sh_audio->audio_in_minsize = |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
71 sh_audio->ds->ss_mul = sh_audio->wf->nBlockAlign; |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
72 return 1; |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
73 } |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
74 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
75 static int init(sh_audio_t *sh_audio) |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
76 { |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
77 sh_audio->channels=sh_audio->wf->nChannels; |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
78 sh_audio->samplerate=sh_audio->wf->nSamplesPerSec; |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
79 sh_audio->i_bps = sh_audio->wf->nBlockAlign * |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
80 (sh_audio->channels*sh_audio->samplerate) / sh_audio->ds->ss_div; |
13427
9d0b052c4f74
setting samplesize to 2 in decoders where neccessary.
reimar
parents:
7893
diff
changeset
|
81 sh_audio->samplesize=2; |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
82 |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
83 return 1; |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
84 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
85 |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
86 static void uninit(sh_audio_t *sh_audio) |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
87 { |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
88 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
89 |
5481 | 90 static int control(sh_audio_t *sh_audio,int cmd,void* arg, ...) |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
91 { |
5481 | 92 if(cmd==ADCTRL_SKIP_FRAME){ |
93 demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,sh_audio->ds->ss_mul); | |
94 return CONTROL_TRUE; | |
95 } | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
96 return CONTROL_UNKNOWN; |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
97 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
98 |
5408 | 99 static int ms_adpcm_decode_block(unsigned short *output, unsigned char *input, |
100 int channels, int block_size) | |
101 { | |
102 int current_channel = 0; | |
103 int idelta[2]; | |
104 int sample1[2]; | |
105 int sample2[2]; | |
106 int coeff1[2]; | |
107 int coeff2[2]; | |
108 int stream_ptr = 0; | |
109 int out_ptr = 0; | |
110 int upper_nibble = 1; | |
111 int nibble; | |
112 int snibble; // signed nibble | |
113 int predictor; | |
114 | |
115 // fetch the header information, in stereo if both channels are present | |
116 if (input[stream_ptr] > 6) | |
117 mp_msg(MSGT_DECAUDIO, MSGL_WARN, | |
118 "MS ADPCM: coefficient (%d) out of range (should be [0..6])\n", | |
119 input[stream_ptr]); | |
120 coeff1[0] = ms_adapt_coeff1[input[stream_ptr]]; | |
121 coeff2[0] = ms_adapt_coeff2[input[stream_ptr]]; | |
122 stream_ptr++; | |
123 if (channels == 2) | |
124 { | |
125 if (input[stream_ptr] > 6) | |
126 mp_msg(MSGT_DECAUDIO, MSGL_WARN, | |
127 "MS ADPCM: coefficient (%d) out of range (should be [0..6])\n", | |
128 input[stream_ptr]); | |
129 coeff1[1] = ms_adapt_coeff1[input[stream_ptr]]; | |
130 coeff2[1] = ms_adapt_coeff2[input[stream_ptr]]; | |
131 stream_ptr++; | |
132 } | |
133 | |
134 idelta[0] = LE_16(&input[stream_ptr]); | |
135 stream_ptr += 2; | |
136 SE_16BIT(idelta[0]); | |
137 if (channels == 2) | |
138 { | |
139 idelta[1] = LE_16(&input[stream_ptr]); | |
140 stream_ptr += 2; | |
141 SE_16BIT(idelta[1]); | |
142 } | |
143 | |
144 sample1[0] = LE_16(&input[stream_ptr]); | |
145 stream_ptr += 2; | |
146 SE_16BIT(sample1[0]); | |
147 if (channels == 2) | |
148 { | |
149 sample1[1] = LE_16(&input[stream_ptr]); | |
150 stream_ptr += 2; | |
151 SE_16BIT(sample1[1]); | |
152 } | |
153 | |
154 sample2[0] = LE_16(&input[stream_ptr]); | |
155 stream_ptr += 2; | |
156 SE_16BIT(sample2[0]); | |
157 if (channels == 2) | |
158 { | |
159 sample2[1] = LE_16(&input[stream_ptr]); | |
160 stream_ptr += 2; | |
161 SE_16BIT(sample2[1]); | |
162 } | |
163 | |
6609 | 164 if (channels == 1) |
165 { | |
166 output[out_ptr++] = sample2[0]; | |
167 output[out_ptr++] = sample1[0]; | |
168 } else { | |
169 output[out_ptr++] = sample2[0]; | |
170 output[out_ptr++] = sample2[1]; | |
171 output[out_ptr++] = sample1[0]; | |
172 output[out_ptr++] = sample1[1]; | |
173 } | |
174 | |
5408 | 175 while (stream_ptr < block_size) |
176 { | |
177 // get the next nibble | |
178 if (upper_nibble) | |
179 nibble = snibble = input[stream_ptr] >> 4; | |
180 else | |
181 nibble = snibble = input[stream_ptr++] & 0x0F; | |
182 upper_nibble ^= 1; | |
183 SE_4BIT(snibble); | |
184 | |
185 predictor = ( | |
186 ((sample1[current_channel] * coeff1[current_channel]) + | |
187 (sample2[current_channel] * coeff2[current_channel])) / 256) + | |
188 (snibble * idelta[current_channel]); | |
189 CLAMP_S16(predictor); | |
190 sample2[current_channel] = sample1[current_channel]; | |
191 sample1[current_channel] = predictor; | |
192 output[out_ptr++] = predictor; | |
193 | |
194 // compute the next adaptive scale factor (a.k.a. the variable idelta) | |
195 idelta[current_channel] = | |
196 (ms_adapt_table[nibble] * idelta[current_channel]) / 256; | |
197 CLAMP_ABOVE_16(idelta[current_channel]); | |
198 | |
199 // toggle the channel | |
200 current_channel ^= channels - 1; | |
201 } | |
202 | |
203 return (block_size - (MS_ADPCM_PREAMBLE_SIZE * channels)) * 2; | |
204 } | |
205 | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
206 static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
207 { |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
208 if (demux_read_data(sh_audio->ds, sh_audio->a_in_buffer, |
5408 | 209 sh_audio->ds->ss_mul) != |
210 sh_audio->ds->ss_mul) | |
211 return -1; /* EOF */ | |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
212 |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
213 return 2 * ms_adpcm_decode_block( |
5408 | 214 (unsigned short*)buf, sh_audio->a_in_buffer, |
215 sh_audio->wf->nChannels, sh_audio->wf->nBlockAlign); | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
216 } |