XMMS2
src/xmms/sample.head.c
Go to the documentation of this file.
00001 /*  XMMS2 - X Music Multiplexer System
00002  *  Copyright (C) 2003-2011 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  */