00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
00027
00028
00029
00030
00031
00032
00033
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
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 static 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 if (tsamplerate == -1)
00091 tsamplerate = fsamplerate;
00092
00093 conv->from = from;
00094 conv->to = to;
00095
00096 conv->resample = fsamplerate != tsamplerate;
00097
00098 conv->func = xmms_sample_conv_get (fchannels, fformat,
00099 tchannels, tformat,
00100 conv->resample);
00101
00102 if (!conv->func) {
00103 xmms_object_unref (conv);
00104 xmms_log_error ("Can not convert between requested formats");
00105 return NULL;
00106 }
00107
00108 if (conv->resample)
00109 recalculate_resampler (conv, fsamplerate, tsamplerate);
00110
00111 return conv;
00112 }
00113
00114
00115
00116
00117 xmms_stream_type_t *
00118 xmms_sample_converter_get_from (xmms_sample_converter_t *conv)
00119 {
00120 g_return_val_if_fail (conv, NULL);
00121
00122 return conv->from;
00123 }
00124
00125
00126
00127
00128 xmms_stream_type_t *
00129 xmms_sample_converter_get_to (xmms_sample_converter_t *conv)
00130 {
00131 g_return_val_if_fail (conv, NULL);
00132
00133 return conv->to;
00134 }
00135
00136
00137
00138 void
00139 xmms_sample_converter_to_medialib (xmms_sample_converter_t *conv, xmms_medialib_entry_t entry)
00140 {
00141 #if 0
00142 xmms_medialib_session_t *session;
00143
00144 session = xmms_medialib_begin_write ();
00145 xmms_medialib_entry_property_set_str (session, entry,
00146 XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_SAMPLEFMT_IN,
00147 xmms_sample_name_get (conv->from->format));
00148 xmms_medialib_entry_property_set_int (session, entry,
00149 XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_SAMPLERATE_IN,
00150 conv->from->samplerate);
00151 xmms_medialib_entry_property_set_int (session, entry,
00152 XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_CHANNELS_IN,
00153 conv->from->channels);
00154
00155 xmms_medialib_entry_property_set_str (session, entry,
00156 XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_SAMPLEFMT_OUT,
00157 xmms_sample_name_get (conv->to->format));
00158 xmms_medialib_entry_property_set_int (session, entry,
00159 XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_SAMPLERATE_OUT,
00160 conv->to->samplerate);
00161 xmms_medialib_entry_property_set_int (session, entry,
00162 XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_CHANNELS_OUT,
00163 conv->to->channels);
00164
00165 xmms_medialib_end (session);
00166 #endif
00167 }
00168
00169
00170
00171
00172 xmms_sample_converter_t *
00173 xmms_sample_audioformats_coerce (xmms_stream_type_t *in, const GList *goal_types)
00174 {
00175 xmms_stream_type_t *best = NULL;
00176 const GList *on;
00177
00178 gint bestscore = 100000;
00179 gint format, samplerate, channels;
00180 gint gformat, gsamplerate, gchannels;
00181
00182 format = xmms_stream_type_get_int (in, XMMS_STREAM_TYPE_FMT_FORMAT);
00183 samplerate = xmms_stream_type_get_int (in, XMMS_STREAM_TYPE_FMT_SAMPLERATE);
00184 channels = xmms_stream_type_get_int (in, XMMS_STREAM_TYPE_FMT_CHANNELS);
00185
00186 if (format == -1 || samplerate == -1 || channels == -1) {
00187 xmms_log_info ("In-type lacks format, samplerate or channels");
00188 return NULL;
00189 }
00190
00191 for (on = goal_types ; on; on = g_list_next (on)) {
00192 xmms_stream_type_t *goal = on->data;
00193 const gchar *mime;
00194 gint score = 0;
00195
00196 mime = xmms_stream_type_get_str (goal, XMMS_STREAM_TYPE_MIMETYPE);
00197 if (strcmp (mime, "audio/pcm") != 0) {
00198 continue;
00199 }
00200
00201 gformat = xmms_stream_type_get_int (goal, XMMS_STREAM_TYPE_FMT_FORMAT);
00202 gsamplerate = xmms_stream_type_get_int (goal, XMMS_STREAM_TYPE_FMT_SAMPLERATE);
00203 gchannels = xmms_stream_type_get_int (goal, XMMS_STREAM_TYPE_FMT_CHANNELS);
00204 if (gsamplerate == -1) {
00205 gsamplerate = samplerate;
00206 }
00207 if (gformat == -1 || gchannels == -1) {
00208 continue;
00209 }
00210
00211
00212 if (gchannels > channels) {
00213
00214 score += gchannels - channels;
00215 } else if (gchannels < gchannels) {
00216
00217 score += 10 * (channels - gchannels);
00218 }
00219
00220
00221
00222 if (gformat > format) {
00223
00224 score += gformat - format;
00225 } else if (gformat < format) {
00226
00227 score += 10 * (format - gformat);
00228 }
00229
00230
00231 if (gsamplerate > samplerate) {
00232
00233 score += 2 * gsamplerate / samplerate;
00234 } else if (gsamplerate < samplerate) {
00235
00236 score += 20 * samplerate / gsamplerate;
00237 }
00238
00239 if (score < bestscore) {
00240 best = goal;
00241 bestscore = score;
00242 }
00243 }
00244
00245 if (!best) {
00246 xmms_log_error ("Couldn't convert sample format to any of the %d goal formats", g_list_length (goal_types));
00247 return NULL;
00248 }
00249
00250 return xmms_sample_converter_init (in, best);
00251
00252 }
00253
00254
00255
00256
00257 guint
00258 xmms_sample_ms_to_samples (const xmms_stream_type_t *st, guint milliseconds)
00259 {
00260 gint rate;
00261 rate = xmms_stream_type_get_int (st, XMMS_STREAM_TYPE_FMT_SAMPLERATE);
00262 return (guint)(((gdouble) rate) * milliseconds / 1000);
00263 }
00264
00265
00266
00267
00268 guint
00269 xmms_sample_samples_to_ms (const xmms_stream_type_t *st, guint samples)
00270 {
00271 gint rate;
00272 rate = xmms_stream_type_get_int (st, XMMS_STREAM_TYPE_FMT_SAMPLERATE);
00273 return (guint) (((gdouble)samples) * 1000.0 / rate);
00274 }
00275
00276
00277
00278
00279 guint
00280 xmms_sample_bytes_to_ms (const xmms_stream_type_t *st, guint bytes)
00281 {
00282 guint samples = bytes / xmms_sample_frame_size_get (st);
00283 return xmms_sample_samples_to_ms (st, samples);
00284 }
00285
00286 gint
00287 xmms_sample_frame_size_get (const xmms_stream_type_t *st)
00288 {
00289 gint format, channels;
00290 format = xmms_stream_type_get_int (st, XMMS_STREAM_TYPE_FMT_FORMAT);
00291 channels = xmms_stream_type_get_int (st, XMMS_STREAM_TYPE_FMT_CHANNELS);
00292 return xmms_sample_size_get (format) * channels;
00293 }
00294
00295 static void
00296 recalculate_resampler (xmms_sample_converter_t *conv, guint from, guint to)
00297 {
00298 guint a,b;
00299
00300
00301 if (from > to){
00302 a = from;
00303 b = to;
00304 } else {
00305 b = to;
00306 a = from;
00307 }
00308
00309 while (b != 0) {
00310 guint t = a % b;
00311 a = b;
00312 b = t;
00313 }
00314
00315 XMMS_DBG ("Resampling ratio: %d:%d",
00316 from / a, to / a);
00317
00318 conv->interpolator_ratio = to/a;
00319 conv->decimator_ratio = from/a;
00320
00321 conv->state = g_malloc0 (xmms_sample_frame_size_get (conv->from));
00322
00323
00324
00325
00326
00327
00328
00329
00330 }
00331
00332
00333
00334
00335
00336 void
00337 xmms_sample_convert (xmms_sample_converter_t *conv, xmms_sample_t *in, guint len, xmms_sample_t **out, guint *outlen)
00338 {
00339 int inusiz, outusiz;
00340 int olen;
00341 guint res;
00342
00343 inusiz = xmms_sample_frame_size_get (conv->from);
00344
00345 g_return_if_fail (len % inusiz == 0);
00346
00347 if (conv->same) {
00348 *outlen = len;
00349 *out = in;
00350 return;
00351 }
00352
00353 len /= inusiz;
00354
00355 outusiz = xmms_sample_frame_size_get (conv->to);
00356
00357 if (conv->resample) {
00358 olen = (len * conv->interpolator_ratio / conv->decimator_ratio) * outusiz + outusiz;
00359 } else {
00360 olen = len * outusiz;
00361 }
00362 if (olen > conv->bufsiz) {
00363 void *t;
00364 t = g_realloc (conv->buf, olen);
00365 g_assert (t);
00366 conv->buf = t;
00367 conv->bufsiz = olen;
00368 }
00369
00370 res = conv->func (conv, in, len, conv->buf);
00371
00372 *outlen = res * outusiz;
00373 *out = conv->buf;
00374
00375 }
00376
00377 gint64
00378 xmms_sample_convert_scale (xmms_sample_converter_t *conv, gint64 samples)
00379 {
00380
00381
00382
00383
00384 if (!conv->resample)
00385 return samples;
00386 return samples * conv->decimator_ratio / conv->interpolator_ratio;
00387 }
00388
00389 gint64
00390 xmms_sample_convert_rev_scale (xmms_sample_converter_t *conv, gint64 samples)
00391 {
00392 if (!conv->resample)
00393 return samples;
00394 return samples * conv->interpolator_ratio / conv->decimator_ratio;
00395 }
00396
00397 void
00398 xmms_sample_convert_reset (xmms_sample_converter_t *conv)
00399 {
00400 if (conv->resample) {
00401 conv->offset = 0;
00402 memset (conv->state, 0, xmms_sample_frame_size_get (conv->from));
00403 }
00404 }
00405
00406
00407
00408