From da1f4b3ede750c83039bcd21647569bde00a2992 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 30 Jul 2013 08:48:53 +0200 Subject: encoder/wave: convert to C++ --- Makefile.am | 4 +- src/EncoderList.cxx | 2 +- src/encoder/WaveEncoderPlugin.cxx | 281 ++++++++++++++++++++++++++++++++++++++ src/encoder/WaveEncoderPlugin.hxx | 25 ++++ src/encoder/wave_encoder.c | 274 ------------------------------------- 5 files changed, 310 insertions(+), 276 deletions(-) create mode 100644 src/encoder/WaveEncoderPlugin.cxx create mode 100644 src/encoder/WaveEncoderPlugin.hxx delete mode 100644 src/encoder/wave_encoder.c diff --git a/Makefile.am b/Makefile.am index 20a631ab0..da97f2e6c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -644,7 +644,9 @@ libencoder_plugins_a_SOURCES = \ src/EncoderList.cxx src/EncoderList.hxx if ENABLE_WAVE_ENCODER -libencoder_plugins_a_SOURCES += src/encoder/wave_encoder.c +libencoder_plugins_a_SOURCES += \ + src/encoder/WaveEncoderPlugin.cxx \ + src/encoder/WaveEncoderPlugin.hxx endif if ENABLE_VORBIS_ENCODER diff --git a/src/EncoderList.cxx b/src/EncoderList.cxx index 6c338bd36..a07f41afa 100644 --- a/src/EncoderList.cxx +++ b/src/EncoderList.cxx @@ -21,6 +21,7 @@ #include "EncoderList.hxx" #include "encoder_plugin.h" #include "encoder/NullEncoderPlugin.hxx" +#include "encoder/WaveEncoderPlugin.hxx" #include "encoder/VorbisEncoderPlugin.hxx" #include "encoder/OpusEncoderPlugin.hxx" #include "encoder/FlacEncoderPlugin.hxx" @@ -29,7 +30,6 @@ extern const struct encoder_plugin lame_encoder_plugin; extern const struct encoder_plugin twolame_encoder_plugin; -extern const struct encoder_plugin wave_encoder_plugin; const struct encoder_plugin *const encoder_plugins[] = { &null_encoder_plugin, diff --git a/src/encoder/WaveEncoderPlugin.cxx b/src/encoder/WaveEncoderPlugin.cxx new file mode 100644 index 000000000..fb52d7906 --- /dev/null +++ b/src/encoder/WaveEncoderPlugin.cxx @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "WaveEncoderPlugin.hxx" +#include "encoder_api.h" +#include "encoder_plugin.h" +#include "util/fifo_buffer.h" +extern "C" { +#include "util/growing_fifo.h" +} + +#include + +#include +#include + +struct WaveEncoder { + struct encoder encoder; + unsigned bits; + + struct fifo_buffer *buffer; + + WaveEncoder() { + encoder_struct_init(&encoder, &wave_encoder_plugin); + } +}; + +struct wave_header { + uint32_t id_riff; + uint32_t riff_size; + uint32_t id_wave; + uint32_t id_fmt; + uint32_t fmt_size; + uint16_t format; + uint16_t channels; + uint32_t freq; + uint32_t byterate; + uint16_t blocksize; + uint16_t bits; + uint32_t id_data; + uint32_t data_size; +}; + +extern const struct encoder_plugin wave_encoder_plugin; + +static void +fill_wave_header(struct wave_header *header, int channels, int bits, + int freq, int block_size) +{ + int data_size = 0x0FFFFFFF; + + /* constants */ + header->id_riff = GUINT32_TO_LE(0x46464952); + header->id_wave = GUINT32_TO_LE(0x45564157); + header->id_fmt = GUINT32_TO_LE(0x20746d66); + header->id_data = GUINT32_TO_LE(0x61746164); + + /* wave format */ + header->format = GUINT16_TO_LE(1); // PCM_FORMAT + header->channels = GUINT16_TO_LE(channels); + header->bits = GUINT16_TO_LE(bits); + header->freq = GUINT32_TO_LE(freq); + header->blocksize = GUINT16_TO_LE(block_size); + header->byterate = GUINT32_TO_LE(freq * block_size); + + /* chunk sizes (fake data length) */ + header->fmt_size = GUINT32_TO_LE(16); + header->data_size = GUINT32_TO_LE(data_size); + header->riff_size = GUINT32_TO_LE(4 + (8 + 16) + + (8 + data_size)); +} + +static struct encoder * +wave_encoder_init(gcc_unused const struct config_param *param, + gcc_unused GError **error) +{ + WaveEncoder *encoder = new WaveEncoder(); + return &encoder->encoder; +} + +static void +wave_encoder_finish(struct encoder *_encoder) +{ + WaveEncoder *encoder = (WaveEncoder *)_encoder; + + g_free(encoder); +} + +static bool +wave_encoder_open(struct encoder *_encoder, + gcc_unused struct audio_format *audio_format, + gcc_unused GError **error) +{ + WaveEncoder *encoder = (WaveEncoder *)_encoder; + + assert(audio_format_valid(audio_format)); + + switch (audio_format->format) { + case SAMPLE_FORMAT_S8: + encoder->bits = 8; + break; + + case SAMPLE_FORMAT_S16: + encoder->bits = 16; + break; + + case SAMPLE_FORMAT_S24_P32: + encoder->bits = 24; + break; + + case SAMPLE_FORMAT_S32: + encoder->bits = 32; + break; + + default: + audio_format->format = SAMPLE_FORMAT_S16; + encoder->bits = 16; + break; + } + + encoder->buffer = growing_fifo_new(); + wave_header *header = (wave_header *) + growing_fifo_write(&encoder->buffer, sizeof(*header)); + + /* create PCM wave header in initial buffer */ + fill_wave_header(header, + audio_format->channels, + encoder->bits, + audio_format->sample_rate, + (encoder->bits / 8) * audio_format->channels ); + fifo_buffer_append(encoder->buffer, sizeof(*header)); + + return true; +} + +static void +wave_encoder_close(struct encoder *_encoder) +{ + WaveEncoder *encoder = (WaveEncoder *)_encoder; + + fifo_buffer_free(encoder->buffer); +} + +static inline size_t +pcm16_to_wave(uint16_t *dst16, const uint16_t *src16, size_t length) +{ + size_t cnt = length >> 1; + while (cnt > 0) { + *dst16++ = GUINT16_TO_LE(*src16++); + cnt--; + } + return length; +} + +static inline size_t +pcm32_to_wave(uint32_t *dst32, const uint32_t *src32, size_t length) +{ + size_t cnt = length >> 2; + while (cnt > 0){ + *dst32++ = GUINT32_TO_LE(*src32++); + cnt--; + } + return length; +} + +static inline size_t +pcm24_to_wave(uint8_t *dst8, const uint32_t *src32, size_t length) +{ + uint32_t value; + uint8_t *dst_old = dst8; + + length = length >> 2; + while (length > 0){ + value = *src32++; + *dst8++ = (value) & 0xFF; + *dst8++ = (value >> 8) & 0xFF; + *dst8++ = (value >> 16) & 0xFF; + length--; + } + //correct buffer length + return (dst8 - dst_old); +} + +static bool +wave_encoder_write(struct encoder *_encoder, + const void *src, size_t length, + gcc_unused GError **error) +{ + WaveEncoder *encoder = (WaveEncoder *)_encoder; + + uint8_t *dst = (uint8_t *)growing_fifo_write(&encoder->buffer, length); + +#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) + switch (encoder->bits) { + case 8: + case 16: + case 32:// optimized cases + memcpy(dst, src, length); + break; + case 24: + length = pcm24_to_wave(dst, (const uint32_t *)src, length); + break; + } +#elif (G_BYTE_ORDER == G_BIG_ENDIAN) + switch (encoder->bits) { + case 8: + memcpy(dst, src, length); + break; + case 16: + length = pcm16_to_wave(dst, (const uint16_t *)src, length); + break; + case 24: + length = pcm24_to_wave(dst, (const uint32_t *)src, length); + break; + case 32: + length = pcm32_to_wave(dst, (const uint32_t *)src, length); + break; + } +#else +#error G_BYTE_ORDER set to G_PDP_ENDIAN is not supported by wave_encoder +#endif + + fifo_buffer_append(encoder->buffer, length); + return true; +} + +static size_t +wave_encoder_read(struct encoder *_encoder, void *dest, size_t length) +{ + WaveEncoder *encoder = (WaveEncoder *)_encoder; + + size_t max_length; + const void *src = fifo_buffer_read(encoder->buffer, &max_length); + if (src == NULL) + return 0; + + if (length > max_length) + length = max_length; + + memcpy(dest, src, length); + fifo_buffer_consume(encoder->buffer, length); + return length; +} + +static const char * +wave_encoder_get_mime_type(gcc_unused struct encoder *_encoder) +{ + return "audio/wav"; +} + +const struct encoder_plugin wave_encoder_plugin = { + "wave", + wave_encoder_init, + wave_encoder_finish, + wave_encoder_open, + wave_encoder_close, + nullptr, + nullptr, + nullptr, + nullptr, + wave_encoder_write, + wave_encoder_read, + wave_encoder_get_mime_type, +}; diff --git a/src/encoder/WaveEncoderPlugin.hxx b/src/encoder/WaveEncoderPlugin.hxx new file mode 100644 index 000000000..b50fe5514 --- /dev/null +++ b/src/encoder/WaveEncoderPlugin.hxx @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_ENCODER_WAVE_HXX +#define MPD_ENCODER_WAVE_HXX + +extern const struct encoder_plugin wave_encoder_plugin; + +#endif diff --git a/src/encoder/wave_encoder.c b/src/encoder/wave_encoder.c deleted file mode 100644 index 9b3c21fca..000000000 --- a/src/encoder/wave_encoder.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "encoder_api.h" -#include "encoder_plugin.h" -#include "util/fifo_buffer.h" -#include "util/growing_fifo.h" - -#include - -#include -#include - -struct wave_encoder { - struct encoder encoder; - unsigned bits; - - struct fifo_buffer *buffer; -}; - -struct wave_header { - uint32_t id_riff; - uint32_t riff_size; - uint32_t id_wave; - uint32_t id_fmt; - uint32_t fmt_size; - uint16_t format; - uint16_t channels; - uint32_t freq; - uint32_t byterate; - uint16_t blocksize; - uint16_t bits; - uint32_t id_data; - uint32_t data_size; -}; - -extern const struct encoder_plugin wave_encoder_plugin; - -static void -fill_wave_header(struct wave_header *header, int channels, int bits, - int freq, int block_size) -{ - int data_size = 0x0FFFFFFF; - - /* constants */ - header->id_riff = GUINT32_TO_LE(0x46464952); - header->id_wave = GUINT32_TO_LE(0x45564157); - header->id_fmt = GUINT32_TO_LE(0x20746d66); - header->id_data = GUINT32_TO_LE(0x61746164); - - /* wave format */ - header->format = GUINT16_TO_LE(1); // PCM_FORMAT - header->channels = GUINT16_TO_LE(channels); - header->bits = GUINT16_TO_LE(bits); - header->freq = GUINT32_TO_LE(freq); - header->blocksize = GUINT16_TO_LE(block_size); - header->byterate = GUINT32_TO_LE(freq * block_size); - - /* chunk sizes (fake data length) */ - header->fmt_size = GUINT32_TO_LE(16); - header->data_size = GUINT32_TO_LE(data_size); - header->riff_size = GUINT32_TO_LE(4 + (8 + 16) + - (8 + data_size)); -} - -static struct encoder * -wave_encoder_init(gcc_unused const struct config_param *param, - gcc_unused GError **error) -{ - struct wave_encoder *encoder; - - encoder = g_new(struct wave_encoder, 1); - encoder_struct_init(&encoder->encoder, &wave_encoder_plugin); - - return &encoder->encoder; -} - -static void -wave_encoder_finish(struct encoder *_encoder) -{ - struct wave_encoder *encoder = (struct wave_encoder *)_encoder; - - g_free(encoder); -} - -static bool -wave_encoder_open(struct encoder *_encoder, - gcc_unused struct audio_format *audio_format, - gcc_unused GError **error) -{ - struct wave_encoder *encoder = (struct wave_encoder *)_encoder; - - assert(audio_format_valid(audio_format)); - - switch (audio_format->format) { - case SAMPLE_FORMAT_S8: - encoder->bits = 8; - break; - - case SAMPLE_FORMAT_S16: - encoder->bits = 16; - break; - - case SAMPLE_FORMAT_S24_P32: - encoder->bits = 24; - break; - - case SAMPLE_FORMAT_S32: - encoder->bits = 32; - break; - - default: - audio_format->format = SAMPLE_FORMAT_S16; - encoder->bits = 16; - break; - } - - encoder->buffer = growing_fifo_new(); - struct wave_header *header = - growing_fifo_write(&encoder->buffer, sizeof(*header)); - - /* create PCM wave header in initial buffer */ - fill_wave_header(header, - audio_format->channels, - encoder->bits, - audio_format->sample_rate, - (encoder->bits / 8) * audio_format->channels ); - fifo_buffer_append(encoder->buffer, sizeof(*header)); - - return true; -} - -static void -wave_encoder_close(struct encoder *_encoder) -{ - struct wave_encoder *encoder = (struct wave_encoder *)_encoder; - - fifo_buffer_free(encoder->buffer); -} - -static inline size_t -pcm16_to_wave(uint16_t *dst16, const uint16_t *src16, size_t length) -{ - size_t cnt = length >> 1; - while (cnt > 0) { - *dst16++ = GUINT16_TO_LE(*src16++); - cnt--; - } - return length; -} - -static inline size_t -pcm32_to_wave(uint32_t *dst32, const uint32_t *src32, size_t length) -{ - size_t cnt = length >> 2; - while (cnt > 0){ - *dst32++ = GUINT32_TO_LE(*src32++); - cnt--; - } - return length; -} - -static inline size_t -pcm24_to_wave(uint8_t *dst8, const uint32_t *src32, size_t length) -{ - uint32_t value; - uint8_t *dst_old = dst8; - - length = length >> 2; - while (length > 0){ - value = *src32++; - *dst8++ = (value) & 0xFF; - *dst8++ = (value >> 8) & 0xFF; - *dst8++ = (value >> 16) & 0xFF; - length--; - } - //correct buffer length - return (dst8 - dst_old); -} - -static bool -wave_encoder_write(struct encoder *_encoder, - const void *src, size_t length, - gcc_unused GError **error) -{ - struct wave_encoder *encoder = (struct wave_encoder *)_encoder; - - void *dst = growing_fifo_write(&encoder->buffer, length); - -#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) - switch (encoder->bits) { - case 8: - case 16: - case 32:// optimized cases - memcpy(dst, src, length); - break; - case 24: - length = pcm24_to_wave(dst, src, length); - break; - } -#elif (G_BYTE_ORDER == G_BIG_ENDIAN) - switch (encoder->bits) { - case 8: - memcpy(dst, src, length); - break; - case 16: - length = pcm16_to_wave(dst, src, length); - break; - case 24: - length = pcm24_to_wave(dst, src, length); - break; - case 32: - length = pcm32_to_wave(dst, src, length); - break; - } -#else -#error G_BYTE_ORDER set to G_PDP_ENDIAN is not supported by wave_encoder -#endif - - fifo_buffer_append(encoder->buffer, length); - return true; -} - -static size_t -wave_encoder_read(struct encoder *_encoder, void *dest, size_t length) -{ - struct wave_encoder *encoder = (struct wave_encoder *)_encoder; - - size_t max_length; - const void *src = fifo_buffer_read(encoder->buffer, &max_length); - if (src == NULL) - return 0; - - if (length > max_length) - length = max_length; - - memcpy(dest, src, length); - fifo_buffer_consume(encoder->buffer, length); - return length; -} - -static const char * -wave_encoder_get_mime_type(gcc_unused struct encoder *_encoder) -{ - return "audio/wav"; -} - -const struct encoder_plugin wave_encoder_plugin = { - .name = "wave", - .init = wave_encoder_init, - .finish = wave_encoder_finish, - .open = wave_encoder_open, - .close = wave_encoder_close, - .write = wave_encoder_write, - .read = wave_encoder_read, - .get_mime_type = wave_encoder_get_mime_type, -}; -- cgit v1.2.3