2 * Copyright (C) 2006-2008 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
24 #include "swfdec_audio_decoder_adpcm.h"
25 #include "swfdec_debug.h"
26 #include "swfdec_internal.h"
28 G_DEFINE_TYPE (SwfdecAudioDecoderAdpcm
, swfdec_audio_decoder_adpcm
, SWFDEC_TYPE_AUDIO_DECODER
)
31 swfdec_audio_decoder_adpcm_prepare (guint codec
, SwfdecAudioFormat format
, char **missing
)
33 return codec
== SWFDEC_AUDIO_CODEC_ADPCM
;
36 static SwfdecAudioDecoder
*
37 swfdec_audio_decoder_adpcm_create (guint codec
, SwfdecAudioFormat format
)
39 if (codec
!= SWFDEC_AUDIO_CODEC_ADPCM
)
42 return g_object_new (SWFDEC_TYPE_AUDIO_DECODER_ADPCM
, NULL
);
45 static const int indexTable
[4][16] = {
48 { -1, -1, -1, -1, 2, 4, 6, 8 },
49 { -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 }
52 static const int stepSizeTable
[89] = {
53 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
54 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
55 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
56 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
57 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
58 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
59 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
60 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
61 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
65 swfdec_audio_decoder_adpcm_decode_chunk (SwfdecBits
*bits
, guint n_bits
,
66 guint channels
, guint granularity
)
74 guint delta
, sign
, sign_mask
;
76 const int *realIndexTable
;
79 /* for scaling up the audio to 44100kHz */
80 repeat
= 2 * granularity
- channels
;
82 realIndexTable
= indexTable
[n_bits
- 2];
83 for (ch
= 0; ch
< channels
; ch
++) {
84 /* can't use get_s16 here since that would be aligned */
85 pred
[ch
] = swfdec_bits_getsbits (bits
, 16);
86 index
[ch
] = swfdec_bits_getbits (bits
, 6);
87 if (index
[ch
] >= G_N_ELEMENTS (stepSizeTable
)) {
88 SWFDEC_ERROR ("initial index too big: %u, max allowed is %td",
89 index
[ch
], G_N_ELEMENTS (stepSizeTable
) - 1);
90 index
[ch
] = G_N_ELEMENTS (stepSizeTable
) - 1;
92 step
[ch
] = stepSizeTable
[index
[ch
]];
94 len
= swfdec_bits_left (bits
) / channels
/ n_bits
;
95 len
= MIN (len
, 4095);
96 ret
= swfdec_buffer_new ((len
+ 1) * sizeof (gint16
) * granularity
* 2);
97 out
= (gint16
*) (void *) ret
->data
;
98 /* output initial value */
99 SWFDEC_LOG ("decoding %u samples", len
+ 1);
100 for (ch
= 0; ch
< channels
; ch
++)
102 /* upscale to 44.1kHz */
103 for (ch
= 0; ch
< repeat
; ch
++) {
104 *out
= out
[-(gssize
) channels
];
108 sign_mask
= 1 << (n_bits
- 1);
109 for (i
= 0; i
< len
; i
++) {
110 for (ch
= 0; ch
< channels
; ch
++) {
111 /* Step 1 - get the delta value */
112 delta
= swfdec_bits_getbits (bits
, n_bits
);
114 /* Step 2 - Separate sign and magnitude */
115 sign
= delta
& sign_mask
;
118 /* Step 3 - Find new index value (for later) */
119 index
[ch
] += realIndexTable
[delta
];
120 if ( index
[ch
] >= G_MAXINT
) index
[ch
] = 0; /* underflow */
121 if ( index
[ch
] >= G_N_ELEMENTS (stepSizeTable
) ) index
[ch
] = G_N_ELEMENTS (stepSizeTable
) - 1;
123 /* Step 4 - Compute difference and new predicted value */
125 diff
= step
[ch
] >> j
;
129 diff
+= step
[ch
] >> j
;
131 } while (j
> 0 && delta
);
138 /* Step 5 - clamp output value */
139 pred
[ch
] = CLAMP (pred
[ch
], -32768, 32767);
141 /* Step 6 - Update step value */
142 step
[ch
] = stepSizeTable
[index
[ch
]];
144 /* Step 7 - Output value */
148 /* upscale to 44.1kHz */
149 for (ch
= 0; ch
< repeat
; ch
++) {
150 *out
= out
[-(gssize
) channels
];
158 swfdec_audio_decoder_adpcm_push (SwfdecAudioDecoder
*dec
, SwfdecBuffer
*buffer
)
160 SwfdecAudioDecoderAdpcm
*adpcm
= (SwfdecAudioDecoderAdpcm
*) dec
;
161 guint channels
, n_bits
, granularity
;
167 channels
= swfdec_audio_format_get_channels (dec
->format
);
168 granularity
= swfdec_audio_format_get_granularity (dec
->format
);
169 swfdec_bits_init (&bits
, buffer
);
170 n_bits
= swfdec_bits_getbits (&bits
, 2) + 2;
171 SWFDEC_DEBUG ("starting decoding: %u channels, %u bits", channels
, n_bits
);
172 /* 22 is minimum required header size */
173 while (swfdec_bits_left (&bits
) >= 22) {
174 buffer
= swfdec_audio_decoder_adpcm_decode_chunk (&bits
, n_bits
, channels
, granularity
);
176 swfdec_buffer_queue_push (adpcm
->queue
, buffer
);
180 static SwfdecBuffer
*
181 swfdec_audio_decoder_adpcm_pull (SwfdecAudioDecoder
*dec
)
183 SwfdecAudioDecoderAdpcm
*adpcm
= (SwfdecAudioDecoderAdpcm
*) dec
;
185 return swfdec_buffer_queue_pull_buffer (adpcm
->queue
);
189 swfdec_audio_decoder_adpcm_dispose (GObject
*object
)
191 SwfdecAudioDecoderAdpcm
*dec
= (SwfdecAudioDecoderAdpcm
*) object
;
193 swfdec_buffer_queue_unref (dec
->queue
);
195 G_OBJECT_CLASS (swfdec_audio_decoder_adpcm_parent_class
)->dispose (object
);
199 swfdec_audio_decoder_adpcm_class_init (SwfdecAudioDecoderAdpcmClass
*klass
)
201 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
202 SwfdecAudioDecoderClass
*decoder_class
= SWFDEC_AUDIO_DECODER_CLASS (klass
);
204 object_class
->dispose
= swfdec_audio_decoder_adpcm_dispose
;
206 decoder_class
->prepare
= swfdec_audio_decoder_adpcm_prepare
;
207 decoder_class
->create
= swfdec_audio_decoder_adpcm_create
;
208 decoder_class
->pull
= swfdec_audio_decoder_adpcm_pull
;
209 decoder_class
->push
= swfdec_audio_decoder_adpcm_push
;
213 swfdec_audio_decoder_adpcm_init (SwfdecAudioDecoderAdpcm
*dec
)
215 dec
->queue
= swfdec_buffer_queue_new ();