1 /*
2  * filter_mono.c -- mix all channels to a mono signal across n channels
3  * Copyright (C) 2003-2018 Meltytech, LLC
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #include <framework/mlt_filter.h>
21 #include <framework/mlt_frame.h>
22 #include <framework/mlt_log.h>
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 
27 /** Get the audio.
28 */
29 
filter_get_audio(mlt_frame frame,void ** buffer,mlt_audio_format * format,int * frequency,int * channels,int * samples)30 static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
31 {
32 	// Get the properties of the a frame
33 	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
34 	int channels_out = mlt_properties_get_int( properties, "mono.channels" );
35 	int i, j, size;
36 
37 	// Get the producer's audio
38 	mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
39 
40 	if ( channels_out == -1 )
41 		channels_out = *channels;
42 	size = mlt_audio_format_size( *format, *samples, channels_out );
43 
44 	switch ( *format )
45 	{
46 		case mlt_audio_u8:
47 		{
48 			uint8_t *new_buffer = mlt_pool_alloc( size );
49 			for ( i = 0; i < *samples; i++ )
50 			{
51 				uint8_t mixdown = 0;
52 				for ( j = 0; j < *channels; j++ )
53 					mixdown += ((uint8_t*) *buffer)[ ( i * *channels ) + j ];
54 				for ( j = 0; j < channels_out; j++ )
55 					new_buffer[ ( i * channels_out ) + j ] = mixdown;
56 			}
57 			*buffer = new_buffer;
58 			break;
59 		}
60 		case mlt_audio_s16:
61 		{
62 			int16_t *new_buffer = mlt_pool_alloc( size );
63 			for ( i = 0; i < *samples; i++ )
64 			{
65 				int16_t mixdown = 0;
66 				for ( j = 0; j < *channels; j++ )
67 					mixdown += ((int16_t*) *buffer)[ ( i * *channels ) + j ];
68 				for ( j = 0; j < channels_out; j++ )
69 					new_buffer[ ( i * channels_out ) + j ] = mixdown;
70 			}
71 			*buffer = new_buffer;
72 			break;
73 		}
74 		case mlt_audio_s32le:
75 		{
76 			int32_t *new_buffer = mlt_pool_alloc( size );
77 			for ( i = 0; i < *samples; i++ )
78 			{
79 				int32_t mixdown = 0;
80 				for ( j = 0; j < *channels; j++ )
81 					mixdown += ((int32_t*) *buffer)[ ( i * *channels ) + j ];
82 				for ( j = 0; j < channels_out; j++ )
83 					new_buffer[ ( i * channels_out ) + j ] = mixdown;
84 			}
85 			*buffer = new_buffer;
86 			break;
87 		}
88 		case mlt_audio_f32le:
89 		{
90 			float *new_buffer = mlt_pool_alloc( size );
91 			for ( i = 0; i < *samples; i++ )
92 			{
93 				float mixdown = 0;
94 				for ( j = 0; j < *channels; j++ )
95 					mixdown += ((float*) *buffer)[ ( i * *channels ) + j ];
96 				for ( j = 0; j < channels_out; j++ )
97 					new_buffer[ ( i * channels_out ) + j ] = mixdown;
98 			}
99 			*buffer = new_buffer;
100 			break;
101 		}
102 		case mlt_audio_s32:
103 		{
104 			int32_t *new_buffer = mlt_pool_alloc( size );
105 			for ( i = 0; i < *samples; i++ )
106 			{
107 				int32_t mixdown = 0;
108 				for ( j = 0; j < *channels; j++ )
109 					mixdown += ((int32_t*) *buffer)[ ( j * *channels ) + i ];
110 				for ( j = 0; j < channels_out; j++ )
111 					new_buffer[ ( j * *samples ) + i ] = mixdown;
112 			}
113 			*buffer = new_buffer;
114 			break;
115 		}
116 		case mlt_audio_float:
117 		{
118 			float *new_buffer = mlt_pool_alloc( size );
119 			for ( i = 0; i < *samples; i++ )
120 			{
121 				float mixdown = 0;
122 				for ( j = 0; j < *channels; j++ )
123 					mixdown += ((float*) *buffer)[ ( j * *channels ) + i ];
124 				for ( j = 0; j < channels_out; j++ )
125 					new_buffer[ ( j * *samples ) + i ] = mixdown;
126 			}
127 			*buffer = new_buffer;
128 			break;
129 		}
130 		default:
131 			mlt_log_error( NULL, "[filter mono] Invalid audio format\n" );
132 			break;
133 	}
134 	if ( size > *samples * channels_out )
135 	{
136 		mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release );
137 		*channels = channels_out;
138 	}
139 
140 	return 0;
141 }
142 
143 /** Filter processing.
144 */
145 
filter_process(mlt_filter filter,mlt_frame frame)146 static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
147 {
148 	mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
149 	mlt_properties frame_props = MLT_FRAME_PROPERTIES( frame );
150 
151 	// Propagate the parameters
152 	mlt_properties_set_int( frame_props, "mono.channels", mlt_properties_get_int( properties, "channels" ) );
153 
154 	// Override the get_audio method
155 	mlt_frame_push_audio( frame, filter_get_audio );
156 
157 	return frame;
158 }
159 
160 /** Constructor for the filter.
161 */
162 
filter_mono_init(mlt_profile profile,mlt_service_type type,const char * id,char * arg)163 mlt_filter filter_mono_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
164 {
165 	mlt_filter filter = mlt_filter_new( );
166 	if ( filter != NULL )
167 	{
168 		filter->process = filter_process;
169 		if ( arg != NULL )
170 			mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "channels", atoi( arg ) );
171 		else
172 			mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "channels", -1 );
173 	}
174 	return filter;
175 }
176 
177