qt: playlist: use item title if available
[vlc.git] / modules / audio_filter / resampler / speex.c
1 /*****************************************************************************
2  * speex.c : libspeex DSP resampler
3  *****************************************************************************
4  * Copyright © 2011-2012 Rémi Denis-Courmont
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <inttypes.h>
26
27 #include <vlc_common.h>
28 #include <vlc_aout.h>
29 #include <vlc_filter.h>
30 #include <vlc_plugin.h>
31
32 #include <speex/speex_resampler.h>
33
34 #define QUALITY_TEXT N_("Resampling quality")
35 #define QUALITY_LONGTEXT N_( "Resampling quality, from worst to best" )
36
37 static int Open (vlc_object_t *);
38 static int OpenResampler (vlc_object_t *);
39 static void Close (filter_t *);
40
41 vlc_module_begin ()
42     set_shortname (N_("Speex resampler"))
43     set_description (N_("Speex resampler") )
44     set_category (CAT_AUDIO)
45     set_subcategory (SUBCAT_AUDIO_RESAMPLER)
46     add_integer ("speex-resampler-quality", 4,
47                  QUALITY_TEXT, QUALITY_LONGTEXT, true)
48         change_integer_range (0, 10)
49     set_capability ("audio converter", 0)
50     set_callback (Open)
51
52     add_submodule ()
53     set_capability ("audio resampler", 0)
54     set_callback (OpenResampler)
55     add_shortcut ("speex")
56 vlc_module_end ()
57
58 static block_t *Resample (filter_t *, block_t *);
59
60 static int OpenResampler (vlc_object_t *obj)
61 {
62     filter_t *filter = (filter_t *)obj;
63
64     /* Cannot convert format */
65     if (filter->fmt_in.audio.i_format != filter->fmt_out.audio.i_format
66     /* Cannot remix */
67      || filter->fmt_in.audio.i_channels != filter->fmt_out.audio.i_channels
68      || filter->fmt_in.audio.i_physical_channels == 0 )
69         return VLC_EGENERIC;
70
71     switch (filter->fmt_in.audio.i_format)
72     {
73         case VLC_CODEC_FL32: break;
74         case VLC_CODEC_S16N: break;
75         default:             return VLC_EGENERIC;
76     }
77
78     SpeexResamplerState *st;
79
80     unsigned q = var_InheritInteger (obj, "speex-resampler-quality");
81     if (unlikely(q > 10))
82         q = 3;
83
84     int err;
85     st = speex_resampler_init(filter->fmt_in.audio.i_channels,
86                               filter->fmt_in.audio.i_rate,
87                               filter->fmt_out.audio.i_rate, q, &err);
88     if (unlikely(st == NULL))
89     {
90         msg_Err (obj, "cannot initialize resampler: %s",
91                  speex_resampler_strerror (err));
92         return VLC_ENOMEM;
93     }
94
95     static const struct vlc_filter_operations filter_ops =
96         { .filter_audio = Resample, .close = Close };
97
98     filter->p_sys = st;
99     filter->ops = &filter_ops;
100
101     return VLC_SUCCESS;
102 }
103
104 static int Open (vlc_object_t *obj)
105 {
106     filter_t *filter = (filter_t *)obj;
107
108     /* Will change rate */
109     if (filter->fmt_in.audio.i_rate == filter->fmt_out.audio.i_rate)
110         return VLC_EGENERIC;
111     return OpenResampler (obj);
112 }
113
114 static void Close (filter_t *filter)
115 {
116     SpeexResamplerState *st = (SpeexResamplerState *)filter->p_sys;
117
118     speex_resampler_destroy (st);
119 }
120
121 static block_t *Resample (filter_t *filter, block_t *in)
122 {
123     SpeexResamplerState *st = (SpeexResamplerState *)filter->p_sys;
124
125     const size_t framesize = filter->fmt_out.audio.i_bytes_per_frame;
126     const unsigned irate = filter->fmt_in.audio.i_rate;
127     const unsigned orate = filter->fmt_out.audio.i_rate;
128
129     spx_uint32_t ilen = in->i_nb_samples;
130     spx_uint32_t olen = ((ilen + 2) * orate * UINT64_C(11))
131                       / (irate * UINT64_C(10));
132
133     block_t *out = block_Alloc (olen * framesize);
134     if (unlikely(out == NULL))
135         goto error;
136
137     speex_resampler_set_rate (st, irate, orate);
138
139     int err;
140     if (filter->fmt_in.audio.i_format == VLC_CODEC_FL32)
141         err = speex_resampler_process_interleaved_float (st,
142             (float *)in->p_buffer, &ilen, (float *)out->p_buffer, &olen);
143     else
144         err = speex_resampler_process_interleaved_int (st,
145             (int16_t *)in->p_buffer, &ilen, (int16_t *)out->p_buffer, &olen);
146     if (err != 0)
147     {
148         msg_Err (filter, "cannot resample: %s",
149                  speex_resampler_strerror (err));
150         block_Release (out);
151         out = NULL;
152         goto error;
153     }
154
155     if (ilen < in->i_nb_samples)
156         msg_Err (filter, "lost %"PRIu32" of %u input frames",
157                  in->i_nb_samples - ilen, in->i_nb_samples);
158
159     out->i_buffer = olen * framesize;
160     out->i_nb_samples = olen;
161     out->i_pts = in->i_pts;
162     out->i_length = vlc_tick_from_samples(olen, filter->fmt_out.audio.i_rate);
163 error:
164     block_Release (in);
165     return out;
166 }