]> git.sesse.net Git - vlc/blob - modules/audio_filter/converter/dtstofloat32.c
* modules/video_output/directx/directx.c: fixed the "refresh" button for the --direct...
[vlc] / modules / audio_filter / converter / dtstofloat32.c
1 /*****************************************************************************
2  * dtstofloat32.c: DTS Coherent Acoustics decoder plugin for VLC.
3  *   This plugin makes use of libdts to do the actual decoding
4  *   (http://www.videolan.org/dtsdec/).
5  *****************************************************************************
6  * Copyright (C) 2001, 2002 VideoLAN
7  * $Id: dtstofloat32.c,v 1.1 2004/02/05 22:56:12 gbazin Exp $
8  *
9  * Author: Gildas Bazin <gbazin@netcourrier.com>
10  *      
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <vlc/vlc.h>
30
31 #include <stdlib.h>                                      /* malloc(), free() */
32 #include <string.h>                                              /* strdup() */
33
34 #ifdef USE_DTSDEC_TREE                                 /* libdts header file */
35 #   include "include/dts.h"
36 #else
37 #   include "dtsdec/dts.h"
38 #endif
39
40 #include "audio_output.h"
41 #include "aout_internal.h"
42
43 /*****************************************************************************
44  * Local prototypes
45  *****************************************************************************/
46 static int  Create    ( vlc_object_t * );
47 static void Destroy   ( vlc_object_t * );
48 static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,  
49                         aout_buffer_t * );
50
51 /*****************************************************************************
52  * Local structures
53  *****************************************************************************/
54 struct aout_filter_sys_t
55 {
56     dts_state_t * p_libdts; /* libdts internal structure */
57     vlc_bool_t b_dynrng; /* see below */
58     int i_flags; /* libdts flags, see dtsdec/doc/libdts.txt */
59     vlc_bool_t b_dontwarn;
60     int i_nb_channels; /* number of float32 per sample */
61 };
62
63 /*****************************************************************************
64  * Module descriptor
65  *****************************************************************************/
66 #define DYNRNG_TEXT N_("DTS dynamic range compression")
67 #define DYNRNG_LONGTEXT N_( \
68     "Dynamic range compression makes the loud sounds softer, and the soft " \
69     "sounds louder, so you can more easily listen to the stream in a noisy " \
70     "environment without disturbing anyone. If you disable the dynamic range "\
71     "compression the playback will be more adapted to a movie theater or a " \
72     "listening room.")
73
74 vlc_module_begin();
75     set_description( _("DTS Coherent Acoustics audio decoder") );
76     add_bool( "dts-dynrng", 1, NULL, DYNRNG_TEXT, DYNRNG_LONGTEXT, VLC_FALSE );
77     set_capability( "audio filter", 100 );
78     set_callbacks( Create, Destroy );
79 vlc_module_end();
80
81 /*****************************************************************************
82  * Create: 
83  *****************************************************************************/
84 static int Create( vlc_object_t * _p_filter )
85 {
86     aout_filter_t * p_filter = (aout_filter_t *)_p_filter;
87     struct aout_filter_sys_t * p_sys;
88
89     if ( p_filter->input.i_format != VLC_FOURCC('d','t','s',' ')
90           || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
91     {
92         return -1;
93     }
94
95     if ( p_filter->input.i_rate != p_filter->output.i_rate )
96     {
97         return -1;
98     }
99
100     /* Allocate the memory needed to store the module's structure */
101     p_sys = p_filter->p_sys = malloc( sizeof(struct aout_filter_sys_t) );
102     if( p_sys == NULL )
103     {
104         msg_Err( p_filter, "out of memory" );
105         return -1;
106     }
107
108     p_sys->b_dynrng = config_GetInt( p_filter, "dts-dynrng" );
109     p_sys->b_dontwarn = 0;
110
111     /* We'll do our own downmixing, thanks. */
112     p_sys->i_nb_channels = aout_FormatNbChannels( &p_filter->output );
113     switch ( (p_filter->output.i_physical_channels & AOUT_CHAN_PHYSMASK)
114               & ~AOUT_CHAN_LFE )
115     {
116     case AOUT_CHAN_CENTER:
117         if ( (p_filter->output.i_original_channels & AOUT_CHAN_CENTER)
118               || (p_filter->output.i_original_channels
119                    & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
120         {
121             p_sys->i_flags = DTS_MONO;
122         }
123         break;
124
125     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT:
126         if ( p_filter->output.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
127         {
128             p_sys->i_flags = DTS_DOLBY;
129         }
130         else if ( p_filter->input.i_original_channels == AOUT_CHAN_CENTER )
131         {
132             p_sys->i_flags = DTS_MONO;
133         }
134         else if ( p_filter->input.i_original_channels & AOUT_CHAN_DUALMONO )
135         {
136             p_sys->i_flags = DTS_CHANNEL;
137         }
138         else
139         {
140             p_sys->i_flags = DTS_STEREO;
141         }
142         break;
143
144     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER:
145         p_sys->i_flags = DTS_3F;
146         break;
147
148     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARCENTER:
149         p_sys->i_flags = DTS_2F1R;
150         break;
151
152     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
153           | AOUT_CHAN_REARCENTER:
154         p_sys->i_flags = DTS_3F1R;
155         break;
156
157     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
158           | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT:
159         p_sys->i_flags = DTS_2F2R;
160         break;
161
162     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
163           | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT:
164         p_sys->i_flags = DTS_3F2R;
165         break;
166
167     default:
168         msg_Warn( p_filter, "unknown sample format!" );
169         free( p_sys );
170         return -1;
171     }
172     if ( p_filter->output.i_physical_channels & AOUT_CHAN_LFE )
173     {
174         p_sys->i_flags |= DTS_LFE;
175     }
176     //p_sys->i_flags |= DTS_ADJUST_LEVEL;
177
178     /* Initialize libdts */
179     p_sys->p_libdts = dts_init( 0 );
180     if( p_sys->p_libdts == NULL )
181     {
182         msg_Err( p_filter, "unable to initialize libdts" );
183         return -1;
184     }
185
186     p_filter->pf_do_work = DoWork;
187     p_filter->b_in_place = 0;
188
189     return 0;
190 }
191
192 /*****************************************************************************
193  * Interleave: helper function to interleave channels
194  *****************************************************************************/
195 static void Interleave( float * p_out, const float * p_in, int i_nb_channels )
196 {
197     /* We do not only have to interleave, but also reorder the channels
198      * Channel reordering according to number of output channels of libdts
199      * The reordering needs to be different for different channel configurations
200      * (3F2R, 1F2R etc), so this is only temporary.
201      * The WG-4 order is appropriate for stereo, quadrophonia, and 5.1 surround.
202      *
203      * 6 channel mode
204      * channel  libdts order    WG-4 order
205      * 0        C               // L
206      * 1        L               // R
207      * 2        R               // LS
208      * 3        LS              // RS
209      * 4        RS              // C
210      * 5        LFE             // LFE
211      *
212      * The libdts moves channels to the front if there are unused spaces, so
213      * there is no gap between channels. The translation table says which
214      * channel of the new stream is taken from which original channel [use
215      * the new channel as the array index, use the number you get from the
216      * array to address the original channel].
217      */
218
219     static const int translation[7][6] =
220     {{ 0, 0, 0, 0, 0, 0 },      /* 0 channels (rarely used) */
221     { 0, 0, 0, 0, 0, 0 },       /* 1 ch */
222     { 0, 1, 0, 0, 0, 0 },       /* 2 */
223     { 1, 2, 0, 0, 0, 0 },       /* 3 */
224     { 0, 1, 2, 3, 0, 0 },       /* 4 */
225     { 1, 2, 3, 4, 0, 0 },       /* 5 */
226     { 1, 2, 3, 4, 0, 5 }};      /* 6 */
227
228     int i, j;
229     for ( j = 0; j < i_nb_channels; j++ )
230     {
231         for ( i = 0; i < 256; i++ )
232         {
233             p_out[i * i_nb_channels + j] = p_in[translation[i_nb_channels][j]
234                                                  * 256 + i];
235         }
236     }
237 }
238
239 /*****************************************************************************
240  * Duplicate: helper function to duplicate a unique channel
241  *****************************************************************************/
242 static void Duplicate( float * p_out, const float * p_in )
243 {
244     int i;
245
246     for ( i = 256; i--; )
247     {
248         *p_out++ = *p_in;
249         *p_out++ = *p_in;
250         p_in++;
251     }
252 }
253
254 /*****************************************************************************
255  * Exchange: helper function to exchange left & right channels
256  *****************************************************************************/
257 static void Exchange( float * p_out, const float * p_in )
258 {
259     int i;
260     const float * p_first = p_in + 256;
261     const float * p_second = p_in;
262
263     for ( i = 0; i < 256; i++ )
264     {
265         *p_out++ = *p_first++;
266         *p_out++ = *p_second++;
267     }
268 }
269
270 /*****************************************************************************
271  * DoWork: decode a DTS frame.
272  *****************************************************************************/
273 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
274                     aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
275 {
276     struct aout_filter_sys_t * p_sys = p_filter->p_sys;
277     sample_t        i_sample_level = 1;
278     int             i_flags = p_sys->i_flags;
279     int             i_bytes_per_block = 256 * p_sys->i_nb_channels
280                       * sizeof(float);
281     int             i;
282
283     /*
284      * Do the actual decoding now.
285      */
286
287     /* Needs to be called so the decoder knows which type of bitstream it is
288      * dealing with. */
289     int i_sample_rate, i_bit_rate, i_frame_length;
290     if( !dts_syncinfo( p_sys->p_libdts, p_in_buf->p_buffer, &i_flags,
291                        &i_sample_rate, &i_bit_rate, &i_frame_length ) )
292     {
293         msg_Warn( p_filter, "libdts couldn't sync on frame" );
294         p_out_buf->i_nb_samples = p_out_buf->i_nb_bytes = 0;
295         return;
296     }
297
298     i_flags = p_sys->i_flags;
299     dts_frame( p_sys->p_libdts, p_in_buf->p_buffer,
300                &i_flags, &i_sample_level, 0 );
301
302     if ( (i_flags & DTS_CHANNEL_MASK) != (p_sys->i_flags & DTS_CHANNEL_MASK)
303           && !p_sys->b_dontwarn )
304     {
305         msg_Warn( p_filter,
306                   "libdts couldn't do the requested downmix 0x%x->0x%x",
307                   p_sys->i_flags  & DTS_CHANNEL_MASK,
308                   i_flags & DTS_CHANNEL_MASK );
309
310         p_sys->b_dontwarn = 1;
311     }
312
313     if( 0)//!p_sys->b_dynrng )
314     {
315         dts_dynrng( p_filter->p_sys->p_libdts, NULL, NULL );
316     }
317
318     for ( i = 0; i < dts_blocks_num(p_filter->p_sys->p_libdts); i++ )
319     {
320         sample_t * p_samples;
321
322         if( dts_block( p_sys->p_libdts ) )
323         {
324             msg_Warn( p_filter, "dts_block failed for block %d", i );
325             break;
326         }
327
328         p_samples = dts_samples( p_sys->p_libdts );
329
330         if ( (p_sys->i_flags & DTS_CHANNEL_MASK) == DTS_MONO
331               && (p_filter->output.i_physical_channels 
332                    & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
333         {
334             Duplicate( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
335                        p_samples );
336         }
337         else if ( p_filter->output.i_original_channels
338                     & AOUT_CHAN_REVERSESTEREO )
339         {
340             Exchange( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
341                       p_samples );
342         }
343         else
344         {
345             /* Interleave the *$£%ù samples. */
346             Interleave( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
347                         p_samples, p_sys->i_nb_channels );
348         }
349     }
350
351     p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
352     p_out_buf->i_nb_bytes = i_bytes_per_block * i;
353 }
354
355 /*****************************************************************************
356  * Destroy : deallocate data structures
357  *****************************************************************************/
358 static void Destroy( vlc_object_t * _p_filter )
359 {
360     aout_filter_t * p_filter = (aout_filter_t *)_p_filter;
361     struct aout_filter_sys_t * p_sys = p_filter->p_sys;
362
363     dts_free( p_sys->p_libdts );
364     free( p_sys );
365 }