XMMS2
|
00001 /* XMMS2 - X Music Multiplexer System 00002 * Copyright (C) 2003-2009 XMMS2 Team 00003 * 00004 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!! 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 */ 00016 00017 00018 #include <glib.h> 00019 #include <math.h> 00020 #include "xmmspriv/xmms_sample.h" 00021 #include "xmms/xmms_medialib.h" 00022 #include "xmms/xmms_object.h" 00023 #include "xmms/xmms_log.h" 00024 00025 /** 00026 * @defgroup Sample Sample Converter 00027 * @ingroup XMMSServer 00028 * @brief Convert sample formats back and forth. 00029 * @{ 00030 */ 00031 00032 /** 00033 * The converter module 00034 */ 00035 struct xmms_sample_converter_St { 00036 xmms_object_t obj; 00037 00038 xmms_stream_type_t *from; 00039 xmms_stream_type_t *to; 00040 00041 gboolean same; 00042 gboolean resample; 00043 00044 /* buffer for result */ 00045 guint bufsiz; 00046 xmms_sample_t *buf; 00047 00048 guint interpolator_ratio; 00049 guint decimator_ratio; 00050 00051 guint offset; 00052 00053 xmms_sample_t *state; 00054 00055 xmms_sample_conv_func_t func; 00056 00057 }; 00058 00059 static void recalculate_resampler (xmms_sample_converter_t *conv, guint from, guint to); 00060 static xmms_sample_conv_func_t 00061 xmms_sample_conv_get (guint inchannels, xmms_sample_format_t intype, 00062 guint outchannels, xmms_sample_format_t outtype, 00063 gboolean resample); 00064 00065 00066 00067 static void 00068 xmms_sample_converter_destroy (xmms_object_t *obj) 00069 { 00070 xmms_sample_converter_t *conv = (xmms_sample_converter_t *) obj; 00071 00072 g_free (conv->buf); 00073 g_free (conv->state); 00074 } 00075 00076 xmms_sample_converter_t * 00077 xmms_sample_converter_init (xmms_stream_type_t *from, xmms_stream_type_t *to) 00078 { 00079 xmms_sample_converter_t *conv = xmms_object_new (xmms_sample_converter_t, xmms_sample_converter_destroy); 00080 gint fformat, fsamplerate, fchannels; 00081 gint tformat, tsamplerate, tchannels; 00082 00083 fformat = xmms_stream_type_get_int (from, XMMS_STREAM_TYPE_FMT_FORMAT); 00084 fsamplerate = xmms_stream_type_get_int (from, XMMS_STREAM_TYPE_FMT_SAMPLERATE); 00085 fchannels = xmms_stream_type_get_int (from, XMMS_STREAM_TYPE_FMT_CHANNELS); 00086 tformat = xmms_stream_type_get_int (to, XMMS_STREAM_TYPE_FMT_FORMAT); 00087 tsamplerate = xmms_stream_type_get_int (to, XMMS_STREAM_TYPE_FMT_SAMPLERATE); 00088 tchannels = xmms_stream_type_get_int (to, XMMS_STREAM_TYPE_FMT_CHANNELS); 00089 00090 g_return_val_if_fail (tformat != -1, NULL); 00091 g_return_val_if_fail (tchannels != -1, NULL); 00092 g_return_val_if_fail (tsamplerate != -1, NULL); 00093 00094 conv->from = from; 00095 conv->to = to; 00096 00097 conv->resample = fsamplerate != tsamplerate; 00098 00099 conv->func = xmms_sample_conv_get (fchannels, fformat, 00100 tchannels, tformat, 00101 conv->resample); 00102 00103 if (!conv->func) { 00104 xmms_object_unref (conv); 00105 xmms_log_error ("Unable to convert from %s/%d/%d to %s/%d/%d.", 00106 xmms_sample_name_get (fformat), fsamplerate, fchannels, 00107 xmms_sample_name_get (tformat), tsamplerate, tchannels); 00108 return NULL; 00109 } 00110 00111 if (conv->resample) 00112 recalculate_resampler (conv, fsamplerate, tsamplerate); 00113 00114 return conv; 00115 } 00116 00117 /** 00118 * Return the audio format used by the converter as source 00119 */ 00120 xmms_stream_type_t * 00121 xmms_sample_converter_get_from (xmms_sample_converter_t *conv) 00122 { 00123 g_return_val_if_fail (conv, NULL); 00124 00125 return conv->from; 00126 } 00127 00128 /** 00129 * Return the audio format used by the converter as target 00130 */ 00131 xmms_stream_type_t * 00132 xmms_sample_converter_get_to (xmms_sample_converter_t *conv) 00133 { 00134 g_return_val_if_fail (conv, NULL); 00135 00136 return conv->to; 00137 } 00138 00139 /** 00140 */ 00141 void 00142 xmms_sample_converter_to_medialib (xmms_sample_converter_t *conv, xmms_medialib_entry_t entry) 00143 { 00144 #if 0 00145 xmms_medialib_session_t *session; 00146 00147 session = xmms_medialib_begin_write (); 00148 xmms_medialib_entry_property_set_str (session, entry, 00149 XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_SAMPLEFMT_IN, 00150 xmms_sample_name_get (conv->from->format)); 00151 xmms_medialib_entry_property_set_int (session, entry, 00152 XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_SAMPLERATE_IN, 00153 conv->from->samplerate); 00154 xmms_medialib_entry_property_set_int (session, entry, 00155 XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_CHANNELS_IN, 00156 conv->from->channels); 00157 00158 xmms_medialib_entry_property_set_str (session, entry, 00159 XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_SAMPLEFMT_OUT, 00160 xmms_sample_name_get (conv->to->format)); 00161 xmms_medialib_entry_property_set_int (session, entry, 00162 XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_SAMPLERATE_OUT, 00163 conv->to->samplerate); 00164 xmms_medialib_entry_property_set_int (session, entry, 00165 XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_CHANNELS_OUT, 00166 conv->to->channels); 00167 00168 xmms_medialib_end (session); 00169 #endif 00170 } 00171 00172 00173 /** 00174 * convert from milliseconds to samples for this format. 00175 */ 00176 guint 00177 xmms_sample_ms_to_samples (const xmms_stream_type_t *st, guint milliseconds) 00178 { 00179 gint rate; 00180 rate = xmms_stream_type_get_int (st, XMMS_STREAM_TYPE_FMT_SAMPLERATE); 00181 return (guint)(((gdouble) rate) * milliseconds / 1000); 00182 } 00183 00184 /** 00185 * Convert from samples to milliseconds for this format 00186 */ 00187 guint 00188 xmms_sample_samples_to_ms (const xmms_stream_type_t *st, guint samples) 00189 { 00190 gint rate; 00191 rate = xmms_stream_type_get_int (st, XMMS_STREAM_TYPE_FMT_SAMPLERATE); 00192 return (guint) (((gdouble)samples) * 1000.0 / rate); 00193 } 00194 00195 /** 00196 * Convert from bytes to milliseconds for this format 00197 */ 00198 guint 00199 xmms_sample_bytes_to_ms (const xmms_stream_type_t *st, guint bytes) 00200 { 00201 guint samples = bytes / xmms_sample_frame_size_get (st); 00202 return xmms_sample_samples_to_ms (st, samples); 00203 } 00204 00205 gint 00206 xmms_sample_frame_size_get (const xmms_stream_type_t *st) 00207 { 00208 gint format, channels; 00209 format = xmms_stream_type_get_int (st, XMMS_STREAM_TYPE_FMT_FORMAT); 00210 channels = xmms_stream_type_get_int (st, XMMS_STREAM_TYPE_FMT_CHANNELS); 00211 return xmms_sample_size_get (format) * channels; 00212 } 00213 00214 static void 00215 recalculate_resampler (xmms_sample_converter_t *conv, guint from, guint to) 00216 { 00217 guint a,b; 00218 00219 /* calculate ratio */ 00220 if (from > to){ 00221 a = from; 00222 b = to; 00223 } else { 00224 b = to; 00225 a = from; 00226 } 00227 00228 while (b != 0) { /* good 'ol euclid is helpful as usual */ 00229 guint t = a % b; 00230 a = b; 00231 b = t; 00232 } 00233 00234 XMMS_DBG ("Resampling ratio: %d:%d", 00235 from / a, to / a); 00236 00237 conv->interpolator_ratio = to/a; 00238 conv->decimator_ratio = from/a; 00239 00240 conv->state = g_malloc0 (xmms_sample_frame_size_get (conv->from)); 00241 00242 /* 00243 * calculate filter here 00244 * 00245 * We don't use no stinkning filter. Maybe we should, 00246 * but I'm deaf anyway, I wont hear any difference. 00247 */ 00248 00249 } 00250 00251 00252 /** 00253 * do the actual converstion between two audio formats. 00254 */ 00255 void 00256 xmms_sample_convert (xmms_sample_converter_t *conv, xmms_sample_t *in, guint len, xmms_sample_t **out, guint *outlen) 00257 { 00258 int inusiz, outusiz; 00259 int olen; 00260 guint res; 00261 00262 inusiz = xmms_sample_frame_size_get (conv->from); 00263 00264 g_return_if_fail (len % inusiz == 0); 00265 00266 if (conv->same) { 00267 *outlen = len; 00268 *out = in; 00269 return; 00270 } 00271 00272 len /= inusiz; 00273 00274 outusiz = xmms_sample_frame_size_get (conv->to); 00275 00276 if (conv->resample) { 00277 olen = (len * conv->interpolator_ratio / conv->decimator_ratio) * outusiz + outusiz; 00278 } else { 00279 olen = len * outusiz; 00280 } 00281 if (olen > conv->bufsiz) { 00282 void *t; 00283 t = g_realloc (conv->buf, olen); 00284 g_assert (t); /* XXX */ 00285 conv->buf = t; 00286 conv->bufsiz = olen; 00287 } 00288 00289 res = conv->func (conv, in, len, conv->buf); 00290 00291 *outlen = res * outusiz; 00292 *out = conv->buf; 00293 00294 } 00295 00296 gint64 00297 xmms_sample_convert_scale (xmms_sample_converter_t *conv, gint64 samples) 00298 { 00299 /* this isn't 100% accurate, we should take care 00300 of rounding here and set conv->offset, but noone 00301 will notice, except when reading this comment :) */ 00302 00303 if (!conv->resample) 00304 return samples; 00305 return samples * conv->decimator_ratio / conv->interpolator_ratio; 00306 } 00307 00308 gint64 00309 xmms_sample_convert_rev_scale (xmms_sample_converter_t *conv, gint64 samples) 00310 { 00311 if (!conv->resample) 00312 return samples; 00313 return samples * conv->interpolator_ratio / conv->decimator_ratio; 00314 } 00315 00316 void 00317 xmms_sample_convert_reset (xmms_sample_converter_t *conv) 00318 { 00319 if (conv->resample) { 00320 conv->offset = 0; 00321 memset (conv->state, 0, xmms_sample_frame_size_get (conv->from)); 00322 } 00323 } 00324 00325 /** 00326 * @} 00327 */