diff options
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/pcm_channels.c | 102 | ||||
-rw-r--r-- | src/pcm_channels.h | 30 | ||||
-rw-r--r-- | src/pcm_utils.c | 86 |
4 files changed, 138 insertions, 82 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 47a121484..35a4d2b62 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -66,6 +66,7 @@ mpd_headers = \ path.h \ mapper.h \ pcm_utils.h \ + pcm_channels.h \ pcm_resample.h \ pcm_dither.h \ permission.h \ @@ -147,6 +148,7 @@ mpd_SOURCES = \ path.c \ mapper.c \ pcm_utils.c \ + pcm_channels.c \ pcm_resample.c \ pcm_dither.c \ permission.c \ diff --git a/src/pcm_channels.c b/src/pcm_channels.c new file mode 100644 index 000000000..6555a3b74 --- /dev/null +++ b/src/pcm_channels.c @@ -0,0 +1,102 @@ +/* the Music Player Daemon (MPD) + * Copyright (C) 2008 Max Kellermann <max@duempel.org> + * This project's homepage is: http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "pcm_channels.h" +#include "utils.h" +#include "log.h" + +#include <assert.h> + +static void +pcm_convert_channels_16_1_to_2(int16_t *dest, const int16_t *src, + unsigned num_frames) +{ + while (num_frames-- > 0) { + int16_t value = *src++; + + *dest++ = value; + *dest++ = value; + } +} + +static void +pcm_convert_channels_16_2_to_1(int16_t *dest, const int16_t *src, + unsigned num_frames) +{ + while (num_frames-- > 0) { + int32_t a = *src++, b = *src++; + + *dest++ = (a + b) / 2; + } +} + +static void +pcm_convert_channels_16_n_to_2(int16_t *dest, + unsigned src_channels, const int16_t *src, + unsigned num_frames) +{ + unsigned c; + + assert(src_channels > 0); + + while (num_frames-- > 0) { + int32_t sum = 0; + int16_t value; + + for (c = 0; c < src_channels; ++c) + sum += *src++; + value = sum / (int)src_channels; + + /* XXX this is actually only mono ... */ + *dest++ = value; + *dest++ = value; + } +} + +const int16_t * +pcm_convert_channels_16(int8_t dest_channels, + int8_t src_channels, const int16_t *src, + size_t src_size, size_t *dest_size_r) +{ + static int16_t *buf; + static size_t len; + unsigned num_frames = src_size / src_channels / sizeof(*src); + unsigned dest_size = num_frames * dest_channels * sizeof(*src); + + if (dest_size > len) { + len = dest_size; + buf = xrealloc(buf, len); + } + + *dest_size_r = dest_size; + + if (src_channels == 1 && dest_channels == 2) + pcm_convert_channels_16_1_to_2(buf, src, num_frames); + else if (src_channels == 2 && dest_channels == 1) + pcm_convert_channels_16_2_to_1(buf, src, num_frames); + else if (dest_channels == 2) + pcm_convert_channels_16_n_to_2(buf, src_channels, src, + num_frames); + else { + ERROR("conversion %u->%u channels is not supported\n", + src_channels, dest_channels); + return NULL; + } + + return buf; +} diff --git a/src/pcm_channels.h b/src/pcm_channels.h new file mode 100644 index 000000000..169fd3693 --- /dev/null +++ b/src/pcm_channels.h @@ -0,0 +1,30 @@ +/* the Music Player Daemon (MPD) + * Copyright (C) 2008 Max Kellermann <max@duempel.org> + * This project's homepage is: http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MPD_PCM_CHANNELS_H +#define MPD_PCM_CHANNELS_H + +#include <stdint.h> +#include <stddef.h> + +const int16_t * +pcm_convert_channels_16(int8_t dest_channels, + int8_t src_channels, const int16_t *src, + size_t src_size, size_t *dest_size_r); + +#endif diff --git a/src/pcm_utils.c b/src/pcm_utils.c index 6d76aba90..56627098f 100644 --- a/src/pcm_utils.c +++ b/src/pcm_utils.c @@ -17,6 +17,7 @@ */ #include "pcm_utils.h" +#include "pcm_channels.h" #include "log.h" #include "utils.h" #include "conf.h" @@ -214,85 +215,6 @@ void pcm_convert_init(struct pcm_convert_state *state) } static void -pcm_convert_channels_1_to_2(int16_t *dest, const int16_t *src, - unsigned num_frames) -{ - while (num_frames-- > 0) { - int16_t value = *src++; - - *dest++ = value; - *dest++ = value; - } -} - -static void -pcm_convert_channels_2_to_1(int16_t *dest, const int16_t *src, - unsigned num_frames) -{ - while (num_frames-- > 0) { - int32_t a = *src++, b = *src++; - - *dest++ = (a + b) / 2; - } -} - -static void -pcm_convert_channels_n_to_2(int16_t *dest, - unsigned src_channels, const int16_t *src, - unsigned num_frames) -{ - unsigned c; - - assert(src_channels > 0); - - while (num_frames-- > 0) { - int32_t sum = 0; - int16_t value; - - for (c = 0; c < src_channels; ++c) - sum += *src++; - value = sum / (int)src_channels; - - /* XXX this is actually only mono ... */ - *dest++ = value; - *dest++ = value; - } -} - -static const int16_t * -pcm_convert_channels(int8_t dest_channels, - int8_t src_channels, const int16_t *src, - size_t src_size, size_t *dest_size_r) -{ - static int16_t *buf; - static size_t len; - unsigned num_frames = src_size / src_channels / sizeof(*src); - unsigned dest_size = num_frames * dest_channels * sizeof(*src); - - if (dest_size > len) { - len = dest_size; - buf = xrealloc(buf, len); - } - - *dest_size_r = dest_size; - - if (src_channels == 1 && dest_channels == 2) - pcm_convert_channels_1_to_2(buf, src, num_frames); - else if (src_channels == 2 && dest_channels == 1) - pcm_convert_channels_2_to_1(buf, src, num_frames); - else if (dest_channels == 2) - pcm_convert_channels_n_to_2(buf, src_channels, src, - num_frames); - else { - ERROR("conversion %u->%u channels is not supported\n", - src_channels, dest_channels); - return NULL; - } - - return buf; -} - -static void pcm_convert_8_to_16(int16_t *out, const int8_t *in, unsigned num_samples) { @@ -375,9 +297,9 @@ size_t pcm_convert(const struct audio_format *inFormat, exit(EXIT_FAILURE); if (inFormat->channels != outFormat->channels) { - buf = pcm_convert_channels(outFormat->channels, - inFormat->channels, - buf, len, &len); + buf = pcm_convert_channels_16(outFormat->channels, + inFormat->channels, + buf, len, &len); if (!buf) exit(EXIT_FAILURE); } |