Moves volume icon update in the timer
[vlc.git] / modules / audio_filter / converter / dtstofloat32.c
1 /*****************************************************************************
2  * dtstofloat32.c: DTS Coherent Acoustics decoder plugin for VLC.
3  *   This plugin makes use of libdca to do the actual decoding
4  *   (http://developers.videolan.org/libdca.html).
5  *****************************************************************************
6  * Copyright (C) 2001, 2002libdca the VideoLAN team
7  * $Id$
8  *
9  * Author: Gildas Bazin <gbazin@videolan.org>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <vlc/vlc.h>
30
31
32 #include <dca.h>                                       /* libdca header file */
33
34 #include <vlc_aout.h>
35 #include <vlc_block.h>
36 #include "vlc_filter.h"
37
38 /*****************************************************************************
39  * Local prototypes
40  *****************************************************************************/
41 static int  Create    ( vlc_object_t * );
42 static void Destroy   ( vlc_object_t * );
43 static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
44                         aout_buffer_t * );
45
46 static int  Open      ( vlc_object_t *, filter_sys_t *,
47                         audio_format_t, audio_format_t );
48
49 static int  OpenFilter ( vlc_object_t * );
50 static void CloseFilter( vlc_object_t * );
51 static block_t *Convert( filter_t *, block_t * );
52
53 /* libdca channel order */
54 static const uint32_t pi_channels_in[] =
55 { AOUT_CHAN_CENTER, AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
56   AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_LFE, 0 };
57 /* our internal channel order (WG-4 order) */
58 static const uint32_t pi_channels_out[] =
59 { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
60   AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
61
62 /*****************************************************************************
63  * Local structures
64  *****************************************************************************/
65 struct filter_sys_t
66 {
67     dca_state_t * p_libdca; /* libdca internal structure */
68     vlc_bool_t b_dynrng; /* see below */
69     int i_flags; /* libdca flags, see dtsdec/doc/libdts.txt */
70     vlc_bool_t b_dontwarn;
71     int i_nb_channels; /* number of float32 per sample */
72
73     int pi_chan_table[AOUT_CHAN_MAX]; /* channel reordering */
74 };
75
76 /*****************************************************************************
77  * Module descriptor
78  *****************************************************************************/
79 #define DYNRNG_TEXT N_("DTS dynamic range compression")
80 #define DYNRNG_LONGTEXT N_( \
81     "Dynamic range compression makes the loud sounds softer, and the soft " \
82     "sounds louder, so you can more easily listen to the stream in a noisy " \
83     "environment without disturbing anyone. If you disable the dynamic range "\
84     "compression the playback will be more adapted to a movie theater or a " \
85     "listening room.")
86
87 vlc_module_begin();
88     set_category( CAT_INPUT );
89     set_subcategory( SUBCAT_INPUT_ACODEC );
90     set_shortname( "DCA" );
91     set_description( _("DTS Coherent Acoustics audio decoder") );
92     add_bool( "dts-dynrng", 1, NULL, DYNRNG_TEXT, DYNRNG_LONGTEXT, VLC_FALSE );
93     set_capability( "audio filter", 100 );
94     set_callbacks( Create, Destroy );
95
96     add_submodule();
97     set_description( _("DTS Coherent Acoustics audio decoder") );
98     set_capability( "audio filter2", 100 );
99     set_callbacks( OpenFilter, CloseFilter );
100 vlc_module_end();
101
102 /*****************************************************************************
103  * Create:
104  *****************************************************************************/
105 static int Create( vlc_object_t *p_this )
106 {
107     aout_filter_t *p_filter = (aout_filter_t *)p_this;
108     filter_sys_t *p_sys;
109     int i_ret;
110
111     if ( p_filter->input.i_format != VLC_FOURCC('d','t','s',' ')
112           || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
113     {
114         return -1;
115     }
116
117     if ( p_filter->input.i_rate != p_filter->output.i_rate )
118     {
119         return -1;
120     }
121
122     /* Allocate the memory needed to store the module's structure */
123     p_sys = malloc( sizeof(filter_sys_t) );
124     p_filter->p_sys = (struct aout_filter_sys_t *)p_sys;
125     if( p_sys == NULL )
126     {
127         msg_Err( p_filter, "out of memory" );
128         return -1;
129     }
130
131     i_ret = Open( VLC_OBJECT(p_filter), p_sys,
132                   p_filter->input, p_filter->output );
133
134     p_filter->pf_do_work = DoWork;
135     p_filter->b_in_place = 0;
136
137     return i_ret;
138 }
139
140 /*****************************************************************************
141  * Open: 
142  *****************************************************************************/
143 static int Open( vlc_object_t *p_this, filter_sys_t *p_sys,
144                  audio_format_t input, audio_format_t output )
145 {
146     p_sys->b_dynrng = config_GetInt( p_this, "dts-dynrng" );
147     p_sys->b_dontwarn = 0;
148
149     /* We'll do our own downmixing, thanks. */
150     p_sys->i_nb_channels = aout_FormatNbChannels( &output );
151     switch ( (output.i_physical_channels & AOUT_CHAN_PHYSMASK)
152               & ~AOUT_CHAN_LFE )
153     {
154     case AOUT_CHAN_CENTER:
155         if ( (output.i_original_channels & AOUT_CHAN_CENTER)
156               || (output.i_original_channels
157                    & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
158         {
159             p_sys->i_flags = DCA_MONO;
160         }
161         break;
162
163     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT:
164         if ( output.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
165         {
166             p_sys->i_flags = DCA_DOLBY;
167         }
168         else if ( input.i_original_channels == AOUT_CHAN_CENTER )
169         {
170             p_sys->i_flags = DCA_MONO;
171         }
172         else if ( input.i_original_channels & AOUT_CHAN_DUALMONO )
173         {
174             p_sys->i_flags = DCA_CHANNEL;
175         }
176         else
177         {
178             p_sys->i_flags = DCA_STEREO;
179         }
180         break;
181
182     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER:
183         p_sys->i_flags = DCA_3F;
184         break;
185
186     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARCENTER:
187         p_sys->i_flags = DCA_2F1R;
188         break;
189
190     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
191           | AOUT_CHAN_REARCENTER:
192         p_sys->i_flags = DCA_3F1R;
193         break;
194
195     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
196           | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT:
197         p_sys->i_flags = DCA_2F2R;
198         break;
199
200     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
201           | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT:
202         p_sys->i_flags = DCA_3F2R;
203         break;
204
205     default:
206         msg_Warn( p_this, "unknown sample format!" );
207         free( p_sys );
208         return -1;
209     }
210     if ( output.i_physical_channels & AOUT_CHAN_LFE )
211     {
212         p_sys->i_flags |= DCA_LFE;
213     }
214     //p_sys->i_flags |= DCA_ADJUST_LEVEL;
215
216     /* Initialize libdca */
217     p_sys->p_libdca = dca_init( 0 );
218     if( p_sys->p_libdca == NULL )
219     {
220         msg_Err( p_this, "unable to initialize libdca" );
221         return VLC_EGENERIC;
222     }
223
224     aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
225                               output.i_physical_channels & AOUT_CHAN_PHYSMASK,
226                               p_sys->i_nb_channels,
227                               p_sys->pi_chan_table );
228
229     return VLC_SUCCESS;
230 }
231
232 /*****************************************************************************
233  * Interleave: helper function to interleave channels
234  *****************************************************************************/
235 static void Interleave( float * p_out, const float * p_in, int i_nb_channels,
236                         int *pi_chan_table )
237 {
238     /* We do not only have to interleave, but also reorder the channels. */
239
240     int i, j;
241     for ( j = 0; j < i_nb_channels; j++ )
242     {
243         for ( i = 0; i < 256; i++ )
244         {
245             p_out[i * i_nb_channels + pi_chan_table[j]] = p_in[j * 256 + i];
246         }
247     }
248 }
249
250 /*****************************************************************************
251  * Duplicate: helper function to duplicate a unique channel
252  *****************************************************************************/
253 static void Duplicate( float * p_out, const float * p_in )
254 {
255     int i;
256
257     for ( i = 256; i--; )
258     {
259         *p_out++ = *p_in;
260         *p_out++ = *p_in;
261         p_in++;
262     }
263 }
264
265 /*****************************************************************************
266  * Exchange: helper function to exchange left & right channels
267  *****************************************************************************/
268 static void Exchange( float * p_out, const float * p_in )
269 {
270     int i;
271     const float * p_first = p_in + 256;
272     const float * p_second = p_in;
273
274     for ( i = 0; i < 256; i++ )
275     {
276         *p_out++ = *p_first++;
277         *p_out++ = *p_second++;
278     }
279 }
280
281 /*****************************************************************************
282  * DoWork: decode a DTS frame.
283  *****************************************************************************/
284 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
285                     aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
286 {
287     filter_sys_t    *p_sys = (filter_sys_t *)p_filter->p_sys;
288     sample_t        i_sample_level = 1;
289     int             i_flags = p_sys->i_flags;
290     int             i_bytes_per_block = 256 * p_sys->i_nb_channels
291                       * sizeof(float);
292     int             i;
293
294     /*
295      * Do the actual decoding now.
296      */
297
298     /* Needs to be called so the decoder knows which type of bitstream it is
299      * dealing with. */
300     int i_sample_rate, i_bit_rate, i_frame_length;
301     if( !dca_syncinfo( p_sys->p_libdca, p_in_buf->p_buffer, &i_flags,
302                        &i_sample_rate, &i_bit_rate, &i_frame_length ) )
303     {
304         msg_Warn( p_aout, "libdca couldn't sync on frame" );
305         p_out_buf->i_nb_samples = p_out_buf->i_nb_bytes = 0;
306         return;
307     }
308
309     i_flags = p_sys->i_flags;
310     dca_frame( p_sys->p_libdca, p_in_buf->p_buffer,
311                &i_flags, &i_sample_level, 0 );
312
313     if ( (i_flags & DCA_CHANNEL_MASK) != (p_sys->i_flags & DCA_CHANNEL_MASK)
314           && !p_sys->b_dontwarn )
315     {
316         msg_Warn( p_aout,
317                   "libdca couldn't do the requested downmix 0x%x->0x%x",
318                   p_sys->i_flags  & DCA_CHANNEL_MASK,
319                   i_flags & DCA_CHANNEL_MASK );
320
321         p_sys->b_dontwarn = 1;
322     }
323
324     if( 0)//!p_sys->b_dynrng )
325     {
326         dca_dynrng( p_sys->p_libdca, NULL, NULL );
327     }
328
329     for ( i = 0; i < dca_blocks_num(p_sys->p_libdca); i++ )
330     {
331         sample_t * p_samples;
332
333         if( dca_block( p_sys->p_libdca ) )
334         {
335             msg_Warn( p_aout, "dca_block failed for block %d", i );
336             break;
337         }
338
339         p_samples = dca_samples( p_sys->p_libdca );
340
341         if ( (p_sys->i_flags & DCA_CHANNEL_MASK) == DCA_MONO
342               && (p_filter->output.i_physical_channels 
343                    & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
344         {
345             Duplicate( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
346                        p_samples );
347         }
348         else if ( p_filter->output.i_original_channels
349                     & AOUT_CHAN_REVERSESTEREO )
350         {
351             Exchange( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
352                       p_samples );
353         }
354         else
355         {
356             /* Interleave the *$£%ù samples. */
357             Interleave( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
358                         p_samples, p_sys->i_nb_channels, p_sys->pi_chan_table);
359         }
360     }
361
362     p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
363     p_out_buf->i_nb_bytes = i_bytes_per_block * i;
364 }
365
366 /*****************************************************************************
367  * Destroy : deallocate data structures
368  *****************************************************************************/
369 static void Destroy( vlc_object_t *p_this )
370 {
371     aout_filter_t *p_filter = (aout_filter_t *)p_this;
372     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
373
374     dca_free( p_sys->p_libdca );
375     free( p_sys );
376 }
377
378 /*****************************************************************************
379  * OpenFilter: 
380  *****************************************************************************/
381 static int OpenFilter( vlc_object_t *p_this )
382 {
383     filter_t *p_filter = (filter_t *)p_this;
384     filter_sys_t *p_sys;
385     int i_ret;
386
387     if( p_filter->fmt_in.i_codec != VLC_FOURCC('d','t','s',' ')  )
388     {
389         return VLC_EGENERIC;
390     }
391
392     p_filter->fmt_out.audio.i_format =
393         p_filter->fmt_out.i_codec = VLC_FOURCC('f','l','3','2');
394
395     /* Allocate the memory needed to store the module's structure */
396     p_sys = p_filter->p_sys = malloc( sizeof(filter_sys_t) );
397     if( p_sys == NULL )
398     {
399         msg_Err( p_filter, "out of memory" );
400         return VLC_EGENERIC;
401     }
402
403     /* Allocate the memory needed to store the module's structure */
404     p_filter->p_sys = p_sys = malloc( sizeof(filter_sys_t) );
405     if( p_sys == NULL )
406     {
407         msg_Err( p_filter, "out of memory" );
408         return VLC_EGENERIC;
409     }
410
411     i_ret = Open( VLC_OBJECT(p_filter), p_sys,
412                   p_filter->fmt_in.audio, p_filter->fmt_out.audio );
413
414     p_filter->pf_audio_filter = Convert;
415     p_filter->fmt_out.audio.i_rate = p_filter->fmt_in.audio.i_rate;
416
417     return i_ret;
418 }
419
420 /*****************************************************************************
421  * CloseFilter : deallocate data structures
422  *****************************************************************************/
423 static void CloseFilter( vlc_object_t *p_this )
424 {
425     filter_t *p_filter = (filter_t *)p_this;
426     filter_sys_t *p_sys = p_filter->p_sys;
427
428     dca_free( p_sys->p_libdca );
429     free( p_sys );
430 }
431
432 static block_t *Convert( filter_t *p_filter, block_t *p_block )
433 {
434     aout_filter_t aout_filter;
435     aout_buffer_t in_buf, out_buf;
436     block_t *p_out;
437     int i_out_size;
438
439     if( !p_block || !p_block->i_samples )
440     {
441         if( p_block ) p_block->pf_release( p_block );
442         return NULL;
443     }
444
445     i_out_size = p_block->i_samples *
446       p_filter->fmt_out.audio.i_bitspersample *
447         p_filter->fmt_out.audio.i_channels / 8;
448
449     p_out = p_filter->pf_audio_buffer_new( p_filter, i_out_size );
450     if( !p_out )
451     {
452         msg_Warn( p_filter, "can't get output buffer" );
453         p_block->pf_release( p_block );
454         return NULL;
455     }
456
457     p_out->i_samples = p_block->i_samples;
458     p_out->i_dts = p_block->i_dts;
459     p_out->i_pts = p_block->i_pts;
460     p_out->i_length = p_block->i_length;
461
462     aout_filter.p_sys = (struct aout_filter_sys_t *)p_filter->p_sys;
463     aout_filter.input = p_filter->fmt_in.audio;
464     aout_filter.input.i_format = p_filter->fmt_in.i_codec;
465     aout_filter.output = p_filter->fmt_out.audio;
466     aout_filter.output.i_format = p_filter->fmt_out.i_codec;
467
468     in_buf.p_buffer = p_block->p_buffer;
469     in_buf.i_nb_bytes = p_block->i_buffer;
470     in_buf.i_nb_samples = p_block->i_samples;
471     out_buf.p_buffer = p_out->p_buffer;
472     out_buf.i_nb_bytes = p_out->i_buffer;
473     out_buf.i_nb_samples = p_out->i_samples;
474
475     DoWork( (aout_instance_t *)p_filter, &aout_filter, &in_buf, &out_buf );
476
477     p_out->i_buffer = out_buf.i_nb_bytes;
478     p_out->i_samples = out_buf.i_nb_samples;
479
480     p_block->pf_release( p_block );
481
482     return p_out;
483 }