]> git.sesse.net Git - mlt/blob - src/modules/core/filter_panner.c
Fix calloc() parameter ordering
[mlt] / src / modules / core / filter_panner.c
1 /*
2  * filter_panner.c --pan/balance audio channels
3  * Copyright (C) 2010 Ushodaya Enterprises Limited
4  * Author: Dan Dennedy <dan@dennedy.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <framework/mlt_filter.h>
22 #include <framework/mlt_frame.h>
23 #include <framework/mlt_log.h>
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <math.h>
29
30
31 /** Get the audio.
32 */
33
34 static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
35 {
36         mlt_properties properties = mlt_frame_pop_audio( frame );
37         mlt_filter filter = mlt_frame_pop_audio( frame );
38         mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );
39         mlt_properties frame_props = MLT_FRAME_PROPERTIES( frame );
40
41         // We can only mix s16
42         *format = mlt_audio_s16;
43         mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples );
44
45         // Apply silence
46         int silent = mlt_properties_get_int( frame_props, "silent_audio" );
47         mlt_properties_set_int( frame_props, "silent_audio", 0 );
48         if ( silent )
49                 memset( *buffer, 0, *samples * *channels * sizeof( int16_t ) );
50
51         int src_size = 0;
52         int16_t *src = mlt_properties_get_data( filter_props, "scratch_buffer", &src_size );
53         int16_t *dest = *buffer;
54         double v; // sample accumulator
55         int i, out, in;
56         double factors[6][6]; // mixing weights [in][out]
57         double mix_start = 0.5, mix_end = 0.5;
58         if ( mlt_properties_get( properties, "previous_mix" ) != NULL )
59                 mix_start = mlt_properties_get_double( properties, "previous_mix" );
60         if ( mlt_properties_get( properties, "mix" ) != NULL )
61                 mix_end = mlt_properties_get_double( properties, "mix" );
62         double weight = mix_start;
63         double weight_step = ( mix_end - mix_start ) / *samples;
64         int active_channel = mlt_properties_get_int( properties, "channel" );
65         int gang = mlt_properties_get_int( properties, "gang" ) ? 2 : 1;
66         // Use an inline low-pass filter to help avoid clipping
67         double Fc = 0.5;
68         double B = exp(-2.0 * M_PI * Fc);
69         double A = 1.0 - B;
70         double vp[6];
71
72         // Setup or resize a scratch buffer
73         if ( !src || src_size < *samples * *channels * sizeof(int16_t) )
74         {
75                 // We allocate 4 more samples than we need to deal with jitter in the sample count per frame.
76                 src_size = ( *samples + 4 ) * *channels * sizeof(int16_t);
77                 src = mlt_pool_alloc( src_size );
78                 if ( !src )
79                         return 0;
80                 mlt_properties_set_data( filter_props, "scratch_buffer", src, src_size, mlt_pool_release, NULL );
81         }
82
83         // We must use a pristine copy as the source
84         memcpy( src, *buffer, *samples * *channels * sizeof(int16_t) );
85
86         // Initialize the mix factors
87         for ( i = 0; i < 6; i++ )
88                 for ( out = 0; out < 6; out++ )
89                         factors[i][out] = 0.0;
90
91         for ( out = 0; out < *channels; out++ )
92                 vp[out] = (double) dest[out];
93
94         for ( i = 0; i < *samples; i++ )
95         {
96                 // Recompute the mix factors
97                 switch ( active_channel )
98                 {
99                         case -1: // Front L/R balance
100                         case -2: // Rear L/R balance
101                         {
102                                 // Gang front/rear balance if requested
103                                 int g, active = active_channel;
104                                 for ( g = 0; g < gang; g++, active-- )
105                                 {
106                                         int left = active == -1 ? 0 : 2;
107                                         int right = left + 1;
108                                         if ( weight < 0.0 )
109                                         {
110                                                 factors[left][left] = 1.0;
111                                                 factors[right][right] = weight + 1.0 < 0.0 ? 0.0 : weight + 1.0;
112                                         }
113                                         else
114                                         {
115                                                 factors[left][left] = 1.0 - weight < 0.0 ? 0.0 : 1.0 - weight;
116                                                 factors[right][right] = 1.0;
117                                         }
118                                 }
119                                 break;
120                         }
121                         case -3: // Left fade
122                         case -4: // right fade
123                         {
124                                 // Gang left/right fade if requested
125                                 int g, active = active_channel;
126                                 for ( g = 0; g < gang; g++, active-- )
127                                 {
128                                         int front = active == -3 ? 0 : 1;
129                                         int rear = front + 2;
130                                         if ( weight < 0.0 )
131                                         {
132                                                 factors[front][front] = 1.0;
133                                                 factors[rear][rear] = weight + 1.0 < 0.0 ? 0.0 : weight + 1.0;
134                                         }
135                                         else
136                                         {
137                                                 factors[front][front] = 1.0 - weight < 0.0 ? 0.0 : 1.0 - weight;
138                                                 factors[rear][rear] = 1.0;
139                                         }
140                                 }
141                                 break;
142                         }
143                         case 0: // left
144                         case 2:
145                         {
146                                 int left = active_channel;
147                                 int right = left + 1;
148                                 factors[right][right] = 1.0;
149                                 if ( weight < 0.0 ) // output left toward left
150                                 {
151                                         factors[left][left] = 0.5 - weight * 0.5;
152                                         factors[left][right] = ( 1.0 + weight ) * 0.5;
153                                 }
154                                 else // output left toward right
155                                 {
156                                         factors[left][left] = ( 1.0 - weight ) * 0.5;
157                                         factors[left][right] = 0.5 + weight * 0.5;
158                                 }
159                                 break;
160                         }
161                         case 1: // right
162                         case 3:
163                         {
164                                 int right = active_channel;
165                                 int left = right - 1;
166                                 factors[left][left] = 1.0;
167                                 if ( weight < 0.0 ) // output right toward left
168                                 {
169                                         factors[right][left] = 0.5 - weight * 0.5;
170                                         factors[right][right] = ( 1.0 + weight ) * 0.5;
171                                 }
172                                 else // output right toward right
173                                 {
174                                         factors[right][left] = ( 1.0 - weight ) * 0.5;
175                                         factors[right][right] = 0.5 + weight * 0.5;
176                                 }
177                                 break;
178                         }
179                 }
180
181                 // Do the mixing
182                 for ( out = 0; out < *channels && out < 6; out++ )
183                 {
184                         v = 0;
185                         for ( in = 0; in < *channels && in < 6; in++ )
186                                 v += factors[in][out] * src[ i * *channels + in ];
187 //                      dest[ i * *channels + out ] = (int16_t) ( v < -32767 ? -32767 : v > 32768 ? 32768 : v );
188                         v = v < -32767 ? -32767 : v > 32768 ? 32768 : v;
189                         vp[out] = dest[ i * *channels + out ] = (int16_t) ( v * A + vp[ out ] * B );
190                 }
191                 weight += weight_step;
192         }
193
194         return 0;
195 }
196
197
198 /** Pan filter processing.
199 */
200
201 static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
202 {
203         mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
204         mlt_properties frame_props = MLT_FRAME_PROPERTIES( frame );
205         mlt_properties instance_props = mlt_properties_new();
206
207         // Only if mix is specified, otherwise a producer may set the mix
208         if ( mlt_properties_get( properties, "start" ) != NULL )
209         {
210                 // Determine the time position of this frame in the filter duration
211                 mlt_properties props = mlt_properties_get_data( frame_props, "_producer", NULL );
212                 int always_active = mlt_properties_get_int(  properties, "always_active" );
213                 mlt_position in = !always_active ? mlt_filter_get_in( filter ) : mlt_properties_get_int( props, "in" );
214                 mlt_position out = !always_active ? mlt_filter_get_out( filter ) : mlt_properties_get_int( props, "out" );
215                 int length = mlt_properties_get_int(  properties, "length" );
216                 mlt_position time = !always_active ? mlt_frame_get_position( frame ) : mlt_properties_get_int( props, "_frame" );
217                 double mix = ( double )( time - in ) / ( double )( out - in + 1 );
218
219                 if ( length == 0 )
220                 {
221                         // If there is an end mix level adjust mix to the range
222                         if ( mlt_properties_get( properties, "end" ) != NULL )
223                         {
224                                 double start = mlt_properties_get_double( properties, "start" );
225                                 double end = mlt_properties_get_double( properties, "end" );
226                                 mix = start + ( end - start ) * mix;
227                         }
228                         // Use constant mix level if only start
229                         else if ( mlt_properties_get( properties, "start" ) != NULL )
230                         {
231                         mix = mlt_properties_get_double( properties, "start" );
232                         }
233
234                         // Convert it from [0, 1] to [-1, 1]
235                         mix = mix * 2.0 - 1.0;
236                 
237                         // Finally, set the mix property on the frame
238                         mlt_properties_set_double( instance_props, "mix", mix );
239         
240                         // Initialise filter previous mix value to prevent an inadvertant jump from 0
241                         mlt_position last_position = mlt_properties_get_position( properties, "_last_position" );
242                         mlt_position current_position = mlt_frame_get_position( frame );
243                         mlt_properties_set_position( properties, "_last_position", current_position );
244                         if ( mlt_properties_get( properties, "_previous_mix" ) == NULL
245                                  || current_position != last_position + 1 )
246                                 mlt_properties_set_double( properties, "_previous_mix", mix );
247                                 
248                         // Tell the frame what the previous mix level was
249                         mlt_properties_set_double( instance_props, "previous_mix", mlt_properties_get_double( properties, "_previous_mix" ) );
250
251                         // Save the current mix level for the next iteration
252                         mlt_properties_set_double( properties, "_previous_mix", mix );
253                 }
254                 else
255                 {
256                         double level = mlt_properties_get_double( properties, "start" );
257                         double mix_start = level;
258                         double mix_end = mix_start;
259                         double mix_increment = 1.0 / length;
260                         if ( time - in < length )
261                         {
262                                 mix_start *= ( double )( time - in ) / length;
263                                 mix_end = mix_start + mix_increment;
264                         }
265                         else if ( time > out - length )
266                         {
267                                 mix_end = mix_start * ( ( double )( out - time - in ) / length );
268                                 mix_start = mix_end - mix_increment;
269                         }
270
271                         mix_start = mix_start < 0 ? 0 : mix_start > level ? level : mix_start;
272                         mix_end = mix_end < 0 ? 0 : mix_end > level ? level : mix_end;
273                         mlt_properties_set_double( instance_props, "previous_mix", mix_start );
274                         mlt_properties_set_double( instance_props, "mix", mix_end );
275                 }
276                 mlt_properties_set_int( instance_props, "channel", mlt_properties_get_int( properties, "channel" ) );
277                 mlt_properties_set_int( instance_props, "gang", mlt_properties_get_int( properties, "gang" ) );
278         }
279         mlt_properties_set_data( frame_props, mlt_properties_get( properties, "_unique_id" ),
280                 instance_props, 0, (mlt_destructor) mlt_properties_close, NULL );
281
282         // Override the get_audio method
283         mlt_frame_push_audio( frame, filter );
284         mlt_frame_push_audio( frame, instance_props );
285         mlt_frame_push_audio( frame, filter_get_audio );
286         
287         return frame;
288 }
289
290 /** Constructor for the filter.
291 */
292
293 mlt_filter filter_panner_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
294 {
295         mlt_filter filter = calloc( 1, sizeof( struct mlt_filter_s ) );
296         if ( filter != NULL && mlt_filter_init( filter, NULL ) == 0 )
297         {
298                 filter->process = filter_process;
299                 if ( arg != NULL )
300                         mlt_properties_set_double( MLT_FILTER_PROPERTIES( filter ), "start", atof( arg ) );
301                 mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "channel", -1 );
302         }
303         return filter;
304 }
305