Mercurial > audlegacy
annotate libaudacious/xconvert.c @ 737:8efa4b799c19 trunk
[svn] Added a get_volume plugin function, to ensure that the player volume is properly updated when the player is remotely controlled
| author | giacomo |
|---|---|
| date | Mon, 27 Feb 2006 16:52:02 -0800 |
| parents | 0a73d1faeb4e |
| children | 6f1346ce2764 |
| rev | line source |
|---|---|
| 0 | 1 /* |
| 2 * Copyright (C) 2001-2003 Haavard Kvaalen <havardk@xmms.org> | |
| 3 * | |
| 4 * Licensed under GNU LGPL version 2. | |
| 5 */ | |
| 6 | |
| 7 #include "config.h" | |
| 8 #include <stdlib.h> | |
| 9 #include <audacious/plugin.h> | |
| 10 #include "xconvert.h" | |
| 11 | |
| 12 #define IS_BIG_ENDIAN (G_BYTE_ORDER==G_BIG_ENDIAN) | |
| 13 | |
| 14 struct buffer { | |
| 15 void *buffer; | |
| 16 int size; | |
| 17 }; | |
| 18 | |
| 19 struct xmms_convert_buffers { | |
| 20 struct buffer format_buffer, stereo_buffer, freq_buffer; | |
| 21 }; | |
| 22 | |
| 23 struct xmms_convert_buffers * | |
| 24 xmms_convert_buffers_new(void) | |
| 25 { | |
| 26 return g_malloc0(sizeof(struct xmms_convert_buffers)); | |
| 27 } | |
| 28 | |
| 29 static void * | |
| 30 convert_get_buffer(struct buffer *buffer, size_t size) | |
| 31 { | |
|
625
0a73d1faeb4e
[svn] GCC 4.1 warning fixes by Diego 'Flameeyes' Petteno from Gentoo.
chainsaw
parents:
0
diff
changeset
|
32 if (size > 0 && size <= (size_t)buffer->size) |
| 0 | 33 return buffer->buffer; |
| 34 | |
| 35 buffer->size = size; | |
| 36 buffer->buffer = g_realloc(buffer->buffer, size); | |
| 37 return buffer->buffer; | |
| 38 } | |
| 39 | |
| 40 void | |
| 41 xmms_convert_buffers_free(struct xmms_convert_buffers *buf) | |
| 42 { | |
| 43 convert_get_buffer(&buf->format_buffer, 0); | |
| 44 convert_get_buffer(&buf->stereo_buffer, 0); | |
| 45 convert_get_buffer(&buf->freq_buffer, 0); | |
| 46 } | |
| 47 | |
| 48 void | |
| 49 xmms_convert_buffers_destroy(struct xmms_convert_buffers *buf) | |
| 50 { | |
| 51 if (!buf) | |
| 52 return; | |
| 53 xmms_convert_buffers_free(buf); | |
| 54 g_free(buf); | |
| 55 } | |
| 56 | |
| 57 static int | |
| 58 convert_swap_endian(struct xmms_convert_buffers *buf, void **data, int length) | |
| 59 { | |
| 60 guint16 *ptr = *data; | |
| 61 int i; | |
| 62 for (i = 0; i < length; i += 2, ptr++) | |
| 63 *ptr = GUINT16_SWAP_LE_BE(*ptr); | |
| 64 | |
| 65 return i; | |
| 66 } | |
| 67 | |
| 68 static int | |
| 69 convert_swap_sign_and_endian_to_native(struct | |
| 70 xmms_convert_buffers | |
| 71 *buf, void **data, int length) | |
| 72 { | |
| 73 guint16 *ptr = *data; | |
| 74 int i; | |
| 75 for (i = 0; i < length; i += 2, ptr++) | |
| 76 *ptr = GUINT16_SWAP_LE_BE(*ptr) ^ 1 << 15; | |
| 77 | |
| 78 return i; | |
| 79 } | |
| 80 | |
| 81 static int | |
| 82 convert_swap_sign_and_endian_to_alien(struct | |
| 83 xmms_convert_buffers *buf, | |
| 84 void **data, int length) | |
| 85 { | |
| 86 guint16 *ptr = *data; | |
| 87 int i; | |
| 88 for (i = 0; i < length; i += 2, ptr++) | |
| 89 *ptr = GUINT16_SWAP_LE_BE(*ptr ^ 1 << 15); | |
| 90 | |
| 91 return i; | |
| 92 } | |
| 93 | |
| 94 static int | |
| 95 convert_swap_sign16(struct xmms_convert_buffers *buf, void **data, int length) | |
| 96 { | |
| 97 gint16 *ptr = *data; | |
| 98 int i; | |
| 99 for (i = 0; i < length; i += 2, ptr++) | |
| 100 *ptr ^= 1 << 15; | |
| 101 | |
| 102 return i; | |
| 103 } | |
| 104 | |
| 105 static int | |
| 106 convert_swap_sign8(struct xmms_convert_buffers *buf, void **data, int length) | |
| 107 { | |
| 108 gint8 *ptr = *data; | |
| 109 int i; | |
| 110 for (i = 0; i < length; i++) | |
| 111 *ptr++ ^= 1 << 7; | |
| 112 | |
| 113 return i; | |
| 114 } | |
| 115 | |
| 116 static int | |
| 117 convert_to_8_native_endian(struct xmms_convert_buffers *buf, | |
| 118 void **data, int length) | |
| 119 { | |
| 120 gint8 *output = *data; | |
| 121 gint16 *input = *data; | |
| 122 int i; | |
| 123 for (i = 0; i < length / 2; i++) | |
| 124 *output++ = *input++ >> 8; | |
| 125 | |
| 126 return i; | |
| 127 } | |
| 128 | |
| 129 static int | |
| 130 convert_to_8_native_endian_swap_sign(struct xmms_convert_buffers | |
| 131 *buf, void **data, int length) | |
| 132 { | |
| 133 gint8 *output = *data; | |
| 134 gint16 *input = *data; | |
| 135 int i; | |
| 136 for (i = 0; i < length / 2; i++) | |
| 137 *output++ = (*input++ >> 8) ^ (1 << 7); | |
| 138 | |
| 139 return i; | |
| 140 } | |
| 141 | |
| 142 | |
| 143 static int | |
| 144 convert_to_8_alien_endian(struct xmms_convert_buffers *buf, | |
| 145 void **data, int length) | |
| 146 { | |
| 147 gint8 *output = *data; | |
| 148 gint16 *input = *data; | |
| 149 int i; | |
| 150 for (i = 0; i < length / 2; i++) | |
| 151 *output++ = *input++ & 0xff; | |
| 152 | |
| 153 return i; | |
| 154 } | |
| 155 | |
| 156 static int | |
| 157 convert_to_8_alien_endian_swap_sign(struct xmms_convert_buffers | |
| 158 *buf, void **data, int length) | |
| 159 { | |
| 160 gint8 *output = *data; | |
| 161 gint16 *input = *data; | |
| 162 int i; | |
| 163 for (i = 0; i < length / 2; i++) | |
| 164 *output++ = (*input++ & 0xff) ^ (1 << 7); | |
| 165 | |
| 166 return i; | |
| 167 } | |
| 168 | |
| 169 static int | |
| 170 convert_to_16_native_endian(struct xmms_convert_buffers *buf, | |
| 171 void **data, int length) | |
| 172 { | |
| 173 guint8 *input = *data; | |
| 174 guint16 *output; | |
| 175 int i; | |
| 176 *data = convert_get_buffer(&buf->format_buffer, length * 2); | |
| 177 output = *data; | |
| 178 for (i = 0; i < length; i++) | |
| 179 *output++ = *input++ << 8; | |
| 180 | |
| 181 return i * 2; | |
| 182 } | |
| 183 | |
| 184 static int | |
| 185 convert_to_16_native_endian_swap_sign(struct | |
| 186 xmms_convert_buffers *buf, | |
| 187 void **data, int length) | |
| 188 { | |
| 189 guint8 *input = *data; | |
| 190 guint16 *output; | |
| 191 int i; | |
| 192 *data = convert_get_buffer(&buf->format_buffer, length * 2); | |
| 193 output = *data; | |
| 194 for (i = 0; i < length; i++) | |
| 195 *output++ = (*input++ << 8) ^ (1 << 15); | |
| 196 | |
| 197 return i * 2; | |
| 198 } | |
| 199 | |
| 200 | |
| 201 static int | |
| 202 convert_to_16_alien_endian(struct xmms_convert_buffers *buf, | |
| 203 void **data, int length) | |
| 204 { | |
| 205 guint8 *input = *data; | |
| 206 guint16 *output; | |
| 207 int i; | |
| 208 *data = convert_get_buffer(&buf->format_buffer, length * 2); | |
| 209 output = *data; | |
| 210 for (i = 0; i < length; i++) | |
| 211 *output++ = *input++; | |
| 212 | |
| 213 return i * 2; | |
| 214 } | |
| 215 | |
| 216 static int | |
| 217 convert_to_16_alien_endian_swap_sign(struct xmms_convert_buffers | |
| 218 *buf, void **data, int length) | |
| 219 { | |
| 220 guint8 *input = *data; | |
| 221 guint16 *output; | |
| 222 int i; | |
| 223 *data = convert_get_buffer(&buf->format_buffer, length * 2); | |
| 224 output = *data; | |
| 225 for (i = 0; i < length; i++) | |
| 226 *output++ = *input++ ^ (1 << 7); | |
| 227 | |
| 228 return i * 2; | |
| 229 } | |
| 230 | |
| 231 static AFormat | |
| 232 unnativize(AFormat fmt) | |
| 233 { | |
| 234 if (fmt == FMT_S16_NE) { | |
| 235 if (IS_BIG_ENDIAN) | |
| 236 return FMT_S16_BE; | |
| 237 else | |
| 238 return FMT_S16_LE; | |
| 239 } | |
| 240 if (fmt == FMT_U16_NE) { | |
| 241 if (IS_BIG_ENDIAN) | |
| 242 return FMT_U16_BE; | |
| 243 else | |
| 244 return FMT_U16_LE; | |
| 245 } | |
| 246 return fmt; | |
| 247 } | |
| 248 | |
| 249 convert_func_t | |
| 250 xmms_convert_get_func(AFormat output, AFormat input) | |
| 251 { | |
| 252 output = unnativize(output); | |
| 253 input = unnativize(input); | |
| 254 | |
| 255 if (output == input) | |
| 256 return NULL; | |
| 257 | |
| 258 if ((output == FMT_U16_BE && input == FMT_U16_LE) || | |
| 259 (output == FMT_U16_LE && input == FMT_U16_BE) || | |
| 260 (output == FMT_S16_BE && input == FMT_S16_LE) || | |
| 261 (output == FMT_S16_LE && input == FMT_S16_BE)) | |
| 262 return convert_swap_endian; | |
| 263 | |
| 264 if ((output == FMT_U16_BE && input == FMT_S16_BE) || | |
| 265 (output == FMT_U16_LE && input == FMT_S16_LE) || | |
| 266 (output == FMT_S16_BE && input == FMT_U16_BE) || | |
| 267 (output == FMT_S16_LE && input == FMT_U16_LE)) | |
| 268 return convert_swap_sign16; | |
| 269 | |
| 270 if ((IS_BIG_ENDIAN && | |
| 271 ((output == FMT_U16_BE && input == FMT_S16_LE) || | |
| 272 (output == FMT_S16_BE && input == FMT_U16_LE))) || | |
| 273 (!IS_BIG_ENDIAN && | |
| 274 ((output == FMT_U16_LE && input == FMT_S16_BE) || | |
| 275 (output == FMT_S16_LE && input == FMT_U16_BE)))) | |
| 276 return convert_swap_sign_and_endian_to_native; | |
| 277 | |
| 278 if ((!IS_BIG_ENDIAN && | |
| 279 ((output == FMT_U16_BE && input == FMT_S16_LE) || | |
| 280 (output == FMT_S16_BE && input == FMT_U16_LE))) || | |
| 281 (IS_BIG_ENDIAN && | |
| 282 ((output == FMT_U16_LE && input == FMT_S16_BE) || | |
| 283 (output == FMT_S16_LE && input == FMT_U16_BE)))) | |
| 284 return convert_swap_sign_and_endian_to_alien; | |
| 285 | |
| 286 if ((IS_BIG_ENDIAN && | |
| 287 ((output == FMT_U8 && input == FMT_U16_BE) || | |
| 288 (output == FMT_S8 && input == FMT_S16_BE))) || | |
| 289 (!IS_BIG_ENDIAN && | |
| 290 ((output == FMT_U8 && input == FMT_U16_LE) || | |
| 291 (output == FMT_S8 && input == FMT_S16_LE)))) | |
| 292 return convert_to_8_native_endian; | |
| 293 | |
| 294 if ((IS_BIG_ENDIAN && | |
| 295 ((output == FMT_U8 && input == FMT_S16_BE) || | |
| 296 (output == FMT_S8 && input == FMT_U16_BE))) || | |
| 297 (!IS_BIG_ENDIAN && | |
| 298 ((output == FMT_U8 && input == FMT_S16_LE) || | |
| 299 (output == FMT_S8 && input == FMT_U16_LE)))) | |
| 300 return convert_to_8_native_endian_swap_sign; | |
| 301 | |
| 302 if ((!IS_BIG_ENDIAN && | |
| 303 ((output == FMT_U8 && input == FMT_U16_BE) || | |
| 304 (output == FMT_S8 && input == FMT_S16_BE))) || | |
| 305 (IS_BIG_ENDIAN && | |
| 306 ((output == FMT_U8 && input == FMT_U16_LE) || | |
| 307 (output == FMT_S8 && input == FMT_S16_LE)))) | |
| 308 return convert_to_8_alien_endian; | |
| 309 | |
| 310 if ((!IS_BIG_ENDIAN && | |
| 311 ((output == FMT_U8 && input == FMT_S16_BE) || | |
| 312 (output == FMT_S8 && input == FMT_U16_BE))) || | |
| 313 (IS_BIG_ENDIAN && | |
| 314 ((output == FMT_U8 && input == FMT_S16_LE) || | |
| 315 (output == FMT_S8 && input == FMT_U16_LE)))) | |
| 316 return convert_to_8_alien_endian_swap_sign; | |
| 317 | |
| 318 if ((output == FMT_U8 && input == FMT_S8) || | |
| 319 (output == FMT_S8 && input == FMT_U8)) | |
| 320 return convert_swap_sign8; | |
| 321 | |
| 322 if ((IS_BIG_ENDIAN && | |
| 323 ((output == FMT_U16_BE && input == FMT_U8) || | |
| 324 (output == FMT_S16_BE && input == FMT_S8))) || | |
| 325 (!IS_BIG_ENDIAN && | |
| 326 ((output == FMT_U16_LE && input == FMT_U8) || | |
| 327 (output == FMT_S16_LE && input == FMT_S8)))) | |
| 328 return convert_to_16_native_endian; | |
| 329 | |
| 330 if ((IS_BIG_ENDIAN && | |
| 331 ((output == FMT_U16_BE && input == FMT_S8) || | |
| 332 (output == FMT_S16_BE && input == FMT_U8))) || | |
| 333 (!IS_BIG_ENDIAN && | |
| 334 ((output == FMT_U16_LE && input == FMT_S8) || | |
| 335 (output == FMT_S16_LE && input == FMT_U8)))) | |
| 336 return convert_to_16_native_endian_swap_sign; | |
| 337 | |
| 338 if ((!IS_BIG_ENDIAN && | |
| 339 ((output == FMT_U16_BE && input == FMT_U8) || | |
| 340 (output == FMT_S16_BE && input == FMT_S8))) || | |
| 341 (IS_BIG_ENDIAN && | |
| 342 ((output == FMT_U16_LE && input == FMT_U8) || | |
| 343 (output == FMT_S16_LE && input == FMT_S8)))) | |
| 344 return convert_to_16_alien_endian; | |
| 345 | |
| 346 if ((!IS_BIG_ENDIAN && | |
| 347 ((output == FMT_U16_BE && input == FMT_S8) || | |
| 348 (output == FMT_S16_BE && input == FMT_U8))) || | |
| 349 (IS_BIG_ENDIAN && | |
| 350 ((output == FMT_U16_LE && input == FMT_S8) || | |
| 351 (output == FMT_S16_LE && input == FMT_U8)))) | |
| 352 return convert_to_16_alien_endian_swap_sign; | |
| 353 | |
| 354 g_warning("Translation needed, but not available.\n" | |
| 355 "Input: %d; Output %d.", input, output); | |
| 356 return NULL; | |
| 357 } | |
| 358 | |
| 359 static int | |
| 360 convert_mono_to_stereo(struct xmms_convert_buffers *buf, | |
| 361 void **data, int length, int b16) | |
| 362 { | |
| 363 int i; | |
| 364 void *outbuf = convert_get_buffer(&buf->stereo_buffer, length * 2); | |
| 365 | |
| 366 if (b16) { | |
| 367 guint16 *output = outbuf, *input = *data; | |
| 368 for (i = 0; i < length / 2; i++) { | |
| 369 *output++ = *input; | |
| 370 *output++ = *input; | |
| 371 input++; | |
| 372 } | |
| 373 } | |
| 374 else { | |
| 375 guint8 *output = outbuf, *input = *data; | |
| 376 for (i = 0; i < length; i++) { | |
| 377 *output++ = *input; | |
| 378 *output++ = *input; | |
| 379 input++; | |
| 380 } | |
| 381 } | |
| 382 *data = outbuf; | |
| 383 | |
| 384 return length * 2; | |
| 385 } | |
| 386 | |
| 387 static int | |
| 388 convert_mono_to_stereo_8(struct xmms_convert_buffers *buf, | |
| 389 void **data, int length) | |
| 390 { | |
| 391 return convert_mono_to_stereo(buf, data, length, FALSE); | |
| 392 } | |
| 393 | |
| 394 static int | |
| 395 convert_mono_to_stereo_16(struct xmms_convert_buffers *buf, | |
| 396 void **data, int length) | |
| 397 { | |
| 398 return convert_mono_to_stereo(buf, data, length, TRUE); | |
| 399 } | |
| 400 | |
| 401 static int | |
| 402 convert_stereo_to_mono_u8(struct xmms_convert_buffers *buf, | |
| 403 void **data, int length) | |
| 404 { | |
| 405 guint8 *output = *data, *input = *data; | |
| 406 int i; | |
| 407 for (i = 0; i < length / 2; i++) { | |
| 408 guint16 tmp; | |
| 409 tmp = *input++; | |
| 410 tmp += *input++; | |
| 411 *output++ = tmp / 2; | |
| 412 } | |
| 413 return length / 2; | |
| 414 } | |
| 415 static int | |
| 416 convert_stereo_to_mono_s8(struct xmms_convert_buffers *buf, | |
| 417 void **data, int length) | |
| 418 { | |
| 419 gint8 *output = *data, *input = *data; | |
| 420 int i; | |
| 421 for (i = 0; i < length / 2; i++) { | |
| 422 gint16 tmp; | |
| 423 tmp = *input++; | |
| 424 tmp += *input++; | |
| 425 *output++ = tmp / 2; | |
| 426 } | |
| 427 return length / 2; | |
| 428 } | |
| 429 static int | |
| 430 convert_stereo_to_mono_u16le(struct xmms_convert_buffers *buf, | |
| 431 void **data, int length) | |
| 432 { | |
| 433 guint16 *output = *data, *input = *data; | |
| 434 int i; | |
| 435 for (i = 0; i < length / 4; i++) { | |
| 436 guint32 tmp; | |
| 437 guint16 stmp; | |
| 438 tmp = GUINT16_FROM_LE(*input); | |
| 439 input++; | |
| 440 tmp += GUINT16_FROM_LE(*input); | |
| 441 input++; | |
| 442 stmp = tmp / 2; | |
| 443 *output++ = GUINT16_TO_LE(stmp); | |
| 444 } | |
| 445 return length / 2; | |
| 446 } | |
| 447 | |
| 448 static int | |
| 449 convert_stereo_to_mono_u16be(struct xmms_convert_buffers *buf, | |
| 450 void **data, int length) | |
| 451 { | |
| 452 guint16 *output = *data, *input = *data; | |
| 453 int i; | |
| 454 for (i = 0; i < length / 4; i++) { | |
| 455 guint32 tmp; | |
| 456 guint16 stmp; | |
| 457 tmp = GUINT16_FROM_BE(*input); | |
| 458 input++; | |
| 459 tmp += GUINT16_FROM_BE(*input); | |
| 460 input++; | |
| 461 stmp = tmp / 2; | |
| 462 *output++ = GUINT16_TO_BE(stmp); | |
| 463 } | |
| 464 return length / 2; | |
| 465 } | |
| 466 | |
| 467 static int | |
| 468 convert_stereo_to_mono_s16le(struct xmms_convert_buffers *buf, | |
| 469 void **data, int length) | |
| 470 { | |
| 471 gint16 *output = *data, *input = *data; | |
| 472 int i; | |
| 473 for (i = 0; i < length / 4; i++) { | |
| 474 gint32 tmp; | |
| 475 gint16 stmp; | |
| 476 tmp = GINT16_FROM_LE(*input); | |
| 477 input++; | |
| 478 tmp += GINT16_FROM_LE(*input); | |
| 479 input++; | |
| 480 stmp = tmp / 2; | |
| 481 *output++ = GINT16_TO_LE(stmp); | |
| 482 } | |
| 483 return length / 2; | |
| 484 } | |
| 485 | |
| 486 static int | |
| 487 convert_stereo_to_mono_s16be(struct xmms_convert_buffers *buf, | |
| 488 void **data, int length) | |
| 489 { | |
| 490 gint16 *output = *data, *input = *data; | |
| 491 int i; | |
| 492 for (i = 0; i < length / 4; i++) { | |
| 493 gint32 tmp; | |
| 494 gint16 stmp; | |
| 495 tmp = GINT16_FROM_BE(*input); | |
| 496 input++; | |
| 497 tmp += GINT16_FROM_BE(*input); | |
| 498 input++; | |
| 499 stmp = tmp / 2; | |
| 500 *output++ = GINT16_TO_BE(stmp); | |
| 501 } | |
| 502 return length / 2; | |
| 503 } | |
| 504 | |
| 505 convert_channel_func_t | |
| 506 xmms_convert_get_channel_func(AFormat fmt, int output, int input) | |
| 507 { | |
| 508 fmt = unnativize(fmt); | |
| 509 | |
| 510 if (output == input) | |
| 511 return NULL; | |
| 512 | |
| 513 if (input == 1 && output == 2) | |
| 514 switch (fmt) { | |
| 515 case FMT_U8: | |
| 516 case FMT_S8: | |
| 517 return convert_mono_to_stereo_8; | |
| 518 case FMT_U16_LE: | |
| 519 case FMT_U16_BE: | |
| 520 case FMT_S16_LE: | |
| 521 case FMT_S16_BE: | |
| 522 return convert_mono_to_stereo_16; | |
| 523 default: | |
| 524 g_warning("Unknown format: %d" "No conversion available.", fmt); | |
| 525 return NULL; | |
| 526 } | |
| 527 if (input == 2 && output == 1) | |
| 528 switch (fmt) { | |
| 529 case FMT_U8: | |
| 530 return convert_stereo_to_mono_u8; | |
| 531 case FMT_S8: | |
| 532 return convert_stereo_to_mono_s8; | |
| 533 case FMT_U16_LE: | |
| 534 return convert_stereo_to_mono_u16le; | |
| 535 case FMT_U16_BE: | |
| 536 return convert_stereo_to_mono_u16be; | |
| 537 case FMT_S16_LE: | |
| 538 return convert_stereo_to_mono_s16le; | |
| 539 case FMT_S16_BE: | |
| 540 return convert_stereo_to_mono_s16be; | |
| 541 default: | |
| 542 g_warning("Unknown format: %d. " | |
| 543 "No conversion available.", fmt); | |
| 544 return NULL; | |
| 545 | |
| 546 } | |
| 547 | |
| 548 g_warning("Input has %d channels, soundcard uses %d channels\n" | |
| 549 "No conversion is available", input, output); | |
| 550 return NULL; | |
| 551 } | |
| 552 | |
| 553 | |
| 554 #define RESAMPLE_STEREO(sample_type, bswap) \ | |
| 555 const int shift = sizeof (sample_type); \ | |
| 556 int i, in_samples, out_samples, x, delta; \ | |
| 557 sample_type *inptr = *data, *outptr; \ | |
| 558 guint nlen = (((length >> shift) * ofreq) / ifreq); \ | |
| 559 void *nbuf; \ | |
| 560 if (nlen == 0) \ | |
| 561 return 0; \ | |
| 562 nlen <<= shift; \ | |
| 563 if (bswap) \ | |
| 564 convert_swap_endian(NULL, data, length); \ | |
| 565 nbuf = convert_get_buffer(&buf->freq_buffer, nlen); \ | |
| 566 outptr = nbuf; \ | |
| 567 in_samples = length >> shift; \ | |
| 568 out_samples = nlen >> shift; \ | |
| 569 delta = (in_samples << 12) / out_samples; \ | |
| 570 for (x = 0, i = 0; i < out_samples; i++) \ | |
| 571 { \ | |
| 572 int x1, frac; \ | |
| 573 x1 = (x >> 12) << 12; \ | |
| 574 frac = x - x1; \ | |
| 575 *outptr++ = \ | |
| 576 ((inptr[(x1 >> 12) << 1] * \ | |
| 577 ((1<<12) - frac) + \ | |
| 578 inptr[((x1 >> 12) + 1) << 1] * \ | |
| 579 frac) >> 12); \ | |
| 580 *outptr++ = \ | |
| 581 ((inptr[((x1 >> 12) << 1) + 1] * \ | |
| 582 ((1<<12) - frac) + \ | |
| 583 inptr[(((x1 >> 12) + 1) << 1) + 1] * \ | |
| 584 frac) >> 12); \ | |
| 585 x += delta; \ | |
| 586 } \ | |
| 587 if (bswap) \ | |
| 588 convert_swap_endian(NULL, &nbuf, nlen); \ | |
| 589 *data = nbuf; \ | |
| 590 return nlen; \ | |
| 591 | |
| 592 | |
| 593 #define RESAMPLE_MONO(sample_type, bswap) \ | |
| 594 const int shift = sizeof (sample_type) - 1; \ | |
| 595 int i, x, delta, in_samples, out_samples; \ | |
| 596 sample_type *inptr = *data, *outptr; \ | |
| 597 guint nlen = (((length >> shift) * ofreq) / ifreq); \ | |
| 598 void *nbuf; \ | |
| 599 if (nlen == 0) \ | |
| 600 return 0; \ | |
| 601 nlen <<= shift; \ | |
| 602 if (bswap) \ | |
| 603 convert_swap_endian(NULL, data, length); \ | |
| 604 nbuf = convert_get_buffer(&buf->freq_buffer, nlen); \ | |
| 605 outptr = nbuf; \ | |
| 606 in_samples = length >> shift; \ | |
| 607 out_samples = nlen >> shift; \ | |
| 608 delta = ((length >> shift) << 12) / out_samples; \ | |
| 609 for (x = 0, i = 0; i < out_samples; i++) \ | |
| 610 { \ | |
| 611 int x1, frac; \ | |
| 612 x1 = (x >> 12) << 12; \ | |
| 613 frac = x - x1; \ | |
| 614 *outptr++ = \ | |
| 615 ((inptr[x1 >> 12] * ((1<<12) - frac) + \ | |
| 616 inptr[(x1 >> 12) + 1] * frac) >> 12); \ | |
| 617 x += delta; \ | |
| 618 } \ | |
| 619 if (bswap) \ | |
| 620 convert_swap_endian(NULL, &nbuf, nlen); \ | |
| 621 *data = nbuf; \ | |
| 622 return nlen; \ | |
| 623 | |
| 624 static int | |
| 625 convert_resample_stereo_s16ne(struct xmms_convert_buffers *buf, | |
| 626 void **data, int length, int ifreq, int ofreq) | |
| 627 { | |
| 628 RESAMPLE_STEREO(gint16, FALSE); | |
| 629 } | |
| 630 | |
| 631 static int | |
| 632 convert_resample_stereo_s16ae(struct xmms_convert_buffers *buf, | |
| 633 void **data, int length, int ifreq, int ofreq) | |
| 634 { | |
| 635 RESAMPLE_STEREO(gint16, TRUE); | |
| 636 } | |
| 637 | |
| 638 static int | |
| 639 convert_resample_stereo_u16ne(struct xmms_convert_buffers *buf, | |
| 640 void **data, int length, int ifreq, int ofreq) | |
| 641 { | |
| 642 RESAMPLE_STEREO(guint16, FALSE); | |
| 643 } | |
| 644 | |
| 645 static int | |
| 646 convert_resample_stereo_u16ae(struct xmms_convert_buffers *buf, | |
| 647 void **data, int length, int ifreq, int ofreq) | |
| 648 { | |
| 649 RESAMPLE_STEREO(guint16, TRUE); | |
| 650 } | |
| 651 | |
| 652 static int | |
| 653 convert_resample_mono_s16ne(struct xmms_convert_buffers *buf, | |
| 654 void **data, int length, int ifreq, int ofreq) | |
| 655 { | |
| 656 RESAMPLE_MONO(gint16, FALSE); | |
| 657 } | |
| 658 | |
| 659 static int | |
| 660 convert_resample_mono_s16ae(struct xmms_convert_buffers *buf, | |
| 661 void **data, int length, int ifreq, int ofreq) | |
| 662 { | |
| 663 RESAMPLE_MONO(gint16, TRUE); | |
| 664 } | |
| 665 | |
| 666 static int | |
| 667 convert_resample_mono_u16ne(struct xmms_convert_buffers *buf, | |
| 668 void **data, int length, int ifreq, int ofreq) | |
| 669 { | |
| 670 RESAMPLE_MONO(guint16, FALSE); | |
| 671 } | |
| 672 | |
| 673 static int | |
| 674 convert_resample_mono_u16ae(struct xmms_convert_buffers *buf, | |
| 675 void **data, int length, int ifreq, int ofreq) | |
| 676 { | |
| 677 RESAMPLE_MONO(guint16, TRUE); | |
| 678 } | |
| 679 | |
| 680 static int | |
| 681 convert_resample_stereo_u8(struct xmms_convert_buffers *buf, | |
| 682 void **data, int length, int ifreq, int ofreq) | |
| 683 { | |
| 684 RESAMPLE_STEREO(guint8, FALSE); | |
| 685 } | |
| 686 | |
| 687 static int | |
| 688 convert_resample_mono_u8(struct xmms_convert_buffers *buf, | |
| 689 void **data, int length, int ifreq, int ofreq) | |
| 690 { | |
| 691 RESAMPLE_MONO(guint8, FALSE); | |
| 692 } | |
| 693 | |
| 694 static int | |
| 695 convert_resample_stereo_s8(struct xmms_convert_buffers *buf, | |
| 696 void **data, int length, int ifreq, int ofreq) | |
| 697 { | |
| 698 RESAMPLE_STEREO(gint8, FALSE); | |
| 699 } | |
| 700 | |
| 701 static int | |
| 702 convert_resample_mono_s8(struct xmms_convert_buffers *buf, | |
| 703 void **data, int length, int ifreq, int ofreq) | |
| 704 { | |
| 705 RESAMPLE_MONO(gint8, FALSE); | |
| 706 } | |
| 707 | |
| 708 | |
| 709 convert_freq_func_t | |
| 710 xmms_convert_get_frequency_func(AFormat fmt, int channels) | |
| 711 { | |
| 712 fmt = unnativize(fmt); | |
| 713 g_message("fmt %d, channels: %d", fmt, channels); | |
| 714 | |
| 715 if (channels < 1 || channels > 2) { | |
| 716 g_warning("Unsupported number of channels: %d. " | |
| 717 "Resample function not available", channels); | |
| 718 return NULL; | |
| 719 } | |
| 720 if ((IS_BIG_ENDIAN && fmt == FMT_U16_BE) || | |
| 721 (!IS_BIG_ENDIAN && fmt == FMT_U16_LE)) { | |
| 722 if (channels == 1) | |
| 723 return convert_resample_mono_u16ne; | |
| 724 else | |
| 725 return convert_resample_stereo_u16ne; | |
| 726 } | |
| 727 if ((IS_BIG_ENDIAN && fmt == FMT_S16_BE) || | |
| 728 (!IS_BIG_ENDIAN && fmt == FMT_S16_LE)) { | |
| 729 if (channels == 1) | |
| 730 return convert_resample_mono_s16ne; | |
| 731 else | |
| 732 return convert_resample_stereo_s16ne; | |
| 733 } | |
| 734 if ((!IS_BIG_ENDIAN && fmt == FMT_U16_BE) || | |
| 735 (IS_BIG_ENDIAN && fmt == FMT_U16_LE)) { | |
| 736 if (channels == 1) | |
| 737 return convert_resample_mono_u16ae; | |
| 738 else | |
| 739 return convert_resample_stereo_u16ae; | |
| 740 } | |
| 741 if ((!IS_BIG_ENDIAN && fmt == FMT_S16_BE) || | |
| 742 (IS_BIG_ENDIAN && fmt == FMT_S16_LE)) { | |
| 743 if (channels == 1) | |
| 744 return convert_resample_mono_s16ae; | |
| 745 else | |
| 746 return convert_resample_stereo_s16ae; | |
| 747 } | |
| 748 if (fmt == FMT_U8) { | |
| 749 if (channels == 1) | |
| 750 return convert_resample_mono_u8; | |
| 751 else | |
| 752 return convert_resample_stereo_u8; | |
| 753 } | |
| 754 if (fmt == FMT_S8) { | |
| 755 if (channels == 1) | |
| 756 return convert_resample_mono_s8; | |
| 757 else | |
| 758 return convert_resample_stereo_s8; | |
| 759 } | |
| 760 g_warning("Resample function not available" "Format %d.", fmt); | |
| 761 return NULL; | |
| 762 } |
