XMMS2
sample.head.c
Go to the documentation of this file.
1 /* XMMS2 - X Music Multiplexer System
2  * Copyright (C) 2003-2011 XMMS2 Team
3  *
4  * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
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 
17 
18 #include <glib.h>
19 #include <math.h>
20 #include "xmmspriv/xmms_sample.h"
21 #include "xmms/xmms_medialib.h"
22 #include "xmms/xmms_object.h"
23 #include "xmms/xmms_log.h"
24 
25 /**
26  * @defgroup Sample Sample Converter
27  * @ingroup XMMSServer
28  * @brief Convert sample formats back and forth.
29  * @{
30  */
31 
32 /**
33  * The converter module
34  */
35 struct xmms_sample_converter_St {
36  xmms_object_t obj;
37 
38  xmms_stream_type_t *from;
40 
41  gboolean same;
42  gboolean resample;
43 
44  /* buffer for result */
45  guint bufsiz;
46  xmms_sample_t *buf;
47 
48  guint interpolator_ratio;
49  guint decimator_ratio;
50 
51  guint offset;
52 
53  xmms_sample_t *state;
54 
56 
57 };
58 
59 static void recalculate_resampler (xmms_sample_converter_t *conv, guint from, guint to);
61 xmms_sample_conv_get (guint inchannels, xmms_sample_format_t intype,
62  guint outchannels, xmms_sample_format_t outtype,
63  gboolean resample);
64 
65 
66 
67 static void
68 xmms_sample_converter_destroy (xmms_object_t *obj)
69 {
71 
72  g_free (conv->buf);
73  g_free (conv->state);
74 }
75 
78 {
79  xmms_sample_converter_t *conv = xmms_object_new (xmms_sample_converter_t, xmms_sample_converter_destroy);
80  gint fformat, fsamplerate, fchannels;
81  gint tformat, tsamplerate, tchannels;
82 
89 
90  g_return_val_if_fail (tformat != -1, NULL);
91  g_return_val_if_fail (tchannels != -1, NULL);
92  g_return_val_if_fail (tsamplerate != -1, NULL);
93 
94  conv->from = from;
95  conv->to = to;
96 
97  conv->resample = fsamplerate != tsamplerate;
98 
99  conv->func = xmms_sample_conv_get (fchannels, fformat,
100  tchannels, tformat,
101  conv->resample);
102 
103  if (!conv->func) {
104  xmms_object_unref (conv);
105  xmms_log_error ("Unable to convert from %s/%d/%d to %s/%d/%d.",
106  xmms_sample_name_get (fformat), fsamplerate, fchannels,
107  xmms_sample_name_get (tformat), tsamplerate, tchannels);
108  return NULL;
109  }
110 
111  if (conv->resample)
112  recalculate_resampler (conv, fsamplerate, tsamplerate);
113 
114  return conv;
115 }
116 
117 /**
118  * Return the audio format used by the converter as source
119  */
122 {
123  g_return_val_if_fail (conv, NULL);
124 
125  return conv->from;
126 }
127 
128 /**
129  * Return the audio format used by the converter as target
130  */
133 {
134  g_return_val_if_fail (conv, NULL);
135 
136  return conv->to;
137 }
138 
139 /**
140  */
141 void
143 {
144 #if 0
145  xmms_medialib_session_t *session;
146 
147  session = xmms_medialib_begin_write ();
148  xmms_medialib_entry_property_set_str (session, entry,
149  XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_SAMPLEFMT_IN,
150  xmms_sample_name_get (conv->from->format));
151  xmms_medialib_entry_property_set_int (session, entry,
152  XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_SAMPLERATE_IN,
153  conv->from->samplerate);
154  xmms_medialib_entry_property_set_int (session, entry,
155  XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_CHANNELS_IN,
156  conv->from->channels);
157 
158  xmms_medialib_entry_property_set_str (session, entry,
159  XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_SAMPLEFMT_OUT,
160  xmms_sample_name_get (conv->to->format));
161  xmms_medialib_entry_property_set_int (session, entry,
162  XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_SAMPLERATE_OUT,
163  conv->to->samplerate);
164  xmms_medialib_entry_property_set_int (session, entry,
165  XMMS_MEDIALIB_ENTRY_PROPERTY_FMT_CHANNELS_OUT,
166  conv->to->channels);
167 
168  xmms_medialib_end (session);
169 #endif
170 }
171 
172 
173 /**
174  * convert from milliseconds to samples for this format.
175  */
176 guint
177 xmms_sample_ms_to_samples (const xmms_stream_type_t *st, guint milliseconds)
178 {
179  gint rate;
181  return (guint)(((gdouble) rate) * milliseconds / 1000);
182 }
183 
184 /**
185  * Convert from samples to milliseconds for this format
186  */
187 guint
189 {
190  gint rate;
192  return (guint) (((gdouble)samples) * 1000.0 / rate);
193 }
194 
195 /**
196  * Convert from bytes to milliseconds for this format
197  */
198 guint
200 {
201  guint samples = bytes / xmms_sample_frame_size_get (st);
202  return xmms_sample_samples_to_ms (st, samples);
203 }
204 
205 gint
207 {
208  gint format, channels;
211  return xmms_sample_size_get (format) * channels;
212 }
213 
214 static void
215 recalculate_resampler (xmms_sample_converter_t *conv, guint from, guint to)
216 {
217  guint a,b;
218 
219  /* calculate ratio */
220  if (from > to){
221  a = from;
222  b = to;
223  } else {
224  b = to;
225  a = from;
226  }
227 
228  while (b != 0) { /* good 'ol euclid is helpful as usual */
229  guint t = a % b;
230  a = b;
231  b = t;
232  }
233 
234  XMMS_DBG ("Resampling ratio: %d:%d",
235  from / a, to / a);
236 
237  conv->interpolator_ratio = to/a;
238  conv->decimator_ratio = from/a;
239 
240  conv->state = g_malloc0 (xmms_sample_frame_size_get (conv->from));
241 
242  /*
243  * calculate filter here
244  *
245  * We don't use no stinkning filter. Maybe we should,
246  * but I'm deaf anyway, I wont hear any difference.
247  */
248 
249 }
250 
251 
252 /**
253  * do the actual converstion between two audio formats.
254  */
255 void
256 xmms_sample_convert (xmms_sample_converter_t *conv, xmms_sample_t *in, guint len, xmms_sample_t **out, guint *outlen)
257 {
258  int inusiz, outusiz;
259  int olen;
260  guint res;
261 
262  inusiz = xmms_sample_frame_size_get (conv->from);
263 
264  g_return_if_fail (len % inusiz == 0);
265 
266  if (conv->same) {
267  *outlen = len;
268  *out = in;
269  return;
270  }
271 
272  len /= inusiz;
273 
274  outusiz = xmms_sample_frame_size_get (conv->to);
275 
276  if (conv->resample) {
277  olen = (len * conv->interpolator_ratio / conv->decimator_ratio) * outusiz + outusiz;
278  } else {
279  olen = len * outusiz;
280  }
281  if (olen > conv->bufsiz) {
282  void *t;
283  t = g_realloc (conv->buf, olen);
284  g_assert (t); /* XXX */
285  conv->buf = t;
286  conv->bufsiz = olen;
287  }
288 
289  res = conv->func (conv, in, len, conv->buf);
290 
291  *outlen = res * outusiz;
292  *out = conv->buf;
293 
294 }
295 
296 gint64
298 {
299  /* this isn't 100% accurate, we should take care
300  of rounding here and set conv->offset, but noone
301  will notice, except when reading this comment :) */
302 
303  if (!conv->resample)
304  return samples;
305  return samples * conv->decimator_ratio / conv->interpolator_ratio;
306 }
307 
308 gint64
310 {
311  if (!conv->resample)
312  return samples;
313  return samples * conv->interpolator_ratio / conv->decimator_ratio;
314 }
315 
316 void
318 {
319  if (conv->resample) {
320  conv->offset = 0;
321  memset (conv->state, 0, xmms_sample_frame_size_get (conv->from));
322  }
323 }
324 
325 /**
326  * @}
327  */
G_BEGIN_DECLS typedef gint32 xmms_medialib_entry_t
Definition: xmms_medialib.h:86
guint xmms_sample_ms_to_samples(const xmms_stream_type_t *st, guint milliseconds)
convert from milliseconds to samples for this format.
Definition: sample.head.c:177
gint xmms_stream_type_get_int(const xmms_stream_type_t *st, xmms_stream_type_key_t key)
Definition: streamtype.c:171
#define xmms_object_unref(obj)
Definition: xmms_object.h:109
xmms_sample_format_t
Definition: xmms_sample.h:25
struct xmms_stream_type_St xmms_stream_type_t
xmms_sample_converter_t * xmms_sample_converter_init(xmms_stream_type_t *from, xmms_stream_type_t *to)
Definition: sample.head.c:77
gboolean xmms_medialib_entry_property_set_str(xmms_medialib_session_t *session, xmms_medialib_entry_t entry, const gchar *property, const gchar *value)
Set a entry property to a new value, overwriting the old value.
Definition: medialib.c:621
guint xmms_sample_bytes_to_ms(const xmms_stream_type_t *st, guint bytes)
Convert from bytes to milliseconds for this format.
Definition: sample.head.c:199
struct xmms_sample_converter_St xmms_sample_converter_t
Definition: xmms_sample.h:38
#define xmms_log_error(fmt,...)
Definition: xmms_log.h:35
void xmms_sample_t
Definition: xmms_sample.h:58
guint xmms_sample_samples_to_ms(const xmms_stream_type_t *st, guint samples)
Convert from samples to milliseconds for this format.
Definition: sample.head.c:188
guint(* xmms_sample_conv_func_t)(xmms_sample_converter_t *, xmms_sample_t *, guint, xmms_sample_t *)
Definition: xmms_sample.h:24
xmms_stream_type_t * xmms_sample_converter_get_from(xmms_sample_converter_t *conv)
Return the audio format used by the converter as source.
Definition: sample.head.c:121
struct xmms_medialib_session_St xmms_medialib_session_t
Definition: xmms_medialib.h:87
gint64 xmms_sample_convert_scale(xmms_sample_converter_t *conv, gint64 samples)
Definition: sample.head.c:297
void xmms_sample_convert(xmms_sample_converter_t *conv, xmms_sample_t *in, guint len, xmms_sample_t **out, guint *outlen)
do the actual converstion between two audio formats.
Definition: sample.head.c:256
gint xmms_sample_frame_size_get(const xmms_stream_type_t *st)
Definition: sample.head.c:206
#define XMMS_DBG(fmt,...)
Definition: xmms_log.h:32
#define xmms_medialib_begin_write()
xmms_stream_type_t * xmms_sample_converter_get_to(xmms_sample_converter_t *conv)
Return the audio format used by the converter as target.
Definition: sample.head.c:132
void xmms_sample_converter_to_medialib(xmms_sample_converter_t *conv, xmms_medialib_entry_t entry)
Definition: sample.head.c:142
#define xmms_object_new(objtype, destroyfunc)
Definition: xmms_object.h:115
gboolean xmms_medialib_entry_property_set_int(xmms_medialib_session_t *session, xmms_medialib_entry_t entry, const gchar *property, gint value)
Set a entry property to a new value, overwriting the old value.
Definition: medialib.c:571
gint64 xmms_sample_convert_rev_scale(xmms_sample_converter_t *conv, gint64 samples)
Definition: sample.head.c:309
void xmms_medialib_end(xmms_medialib_session_t *session)
Definition: medialib.c:425
void xmms_sample_convert_reset(xmms_sample_converter_t *conv)
Definition: sample.head.c:317