pcm_utils: moved code to pcm_resample.c
Separate the resampling code from the rest of pcm_utils.c. Create two sub-libraries: pcm_resample_libsamplerate.c and pcm_resample_fallback.c.
This commit is contained in:
		| @@ -390,6 +390,8 @@ if test x$enable_lsr = xyes; then | |||||||
| 	                  [enable_lsr=no;AC_MSG_WARN([libsamplerate not found -- disabling])]) | 	                  [enable_lsr=no;AC_MSG_WARN([libsamplerate not found -- disabling])]) | ||||||
| fi | fi | ||||||
|  |  | ||||||
|  | AM_CONDITIONAL(HAVE_LIBSAMPLERATE, test x$enable_lsr = xyes) | ||||||
|  |  | ||||||
| if test x$enable_fifo = xyes; then | if test x$enable_fifo = xyes; then | ||||||
| 	AC_CHECK_FUNC([mkfifo], | 	AC_CHECK_FUNC([mkfifo], | ||||||
| 	              [enable_fifo=yes;AC_DEFINE([HAVE_FIFO], 1, [Define to enable support for writing audio to a FIFO])], | 	              [enable_fifo=yes;AC_DEFINE([HAVE_FIFO], 1, [Define to enable support for writing audio to a FIFO])], | ||||||
|   | |||||||
| @@ -66,6 +66,7 @@ mpd_headers = \ | |||||||
| 	path.h \ | 	path.h \ | ||||||
| 	mapper.h \ | 	mapper.h \ | ||||||
| 	pcm_utils.h \ | 	pcm_utils.h \ | ||||||
|  | 	pcm_resample.h \ | ||||||
| 	pcm_dither.h \ | 	pcm_dither.h \ | ||||||
| 	permission.h \ | 	permission.h \ | ||||||
| 	player_thread.h \ | 	player_thread.h \ | ||||||
| @@ -146,6 +147,7 @@ mpd_SOURCES = \ | |||||||
| 	path.c \ | 	path.c \ | ||||||
| 	mapper.c \ | 	mapper.c \ | ||||||
| 	pcm_utils.c \ | 	pcm_utils.c \ | ||||||
|  | 	pcm_resample.c \ | ||||||
| 	pcm_dither.c \ | 	pcm_dither.c \ | ||||||
| 	permission.c \ | 	permission.c \ | ||||||
| 	player_thread.c \ | 	player_thread.c \ | ||||||
| @@ -176,6 +178,12 @@ mpd_SOURCES = \ | |||||||
| 	stored_playlist.c \ | 	stored_playlist.c \ | ||||||
| 	timer.c | 	timer.c | ||||||
|  |  | ||||||
|  | if HAVE_LIBSAMPLERATE | ||||||
|  | mpd_SOURCES += pcm_resample_libsamplerate.c | ||||||
|  | else | ||||||
|  | mpd_SOURCES += pcm_resample_fallback.c | ||||||
|  | endif | ||||||
|  |  | ||||||
| if HAVE_ID3TAG | if HAVE_ID3TAG | ||||||
| mpd_SOURCES += tag_id3.c | mpd_SOURCES += tag_id3.c | ||||||
| endif | endif | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								src/pcm_resample.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/pcm_resample.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | /* 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_resample.h" | ||||||
|  |  | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | void pcm_resample_init(struct pcm_resample_state *state) | ||||||
|  | { | ||||||
|  | 	memset(state, 0, sizeof(*state)); | ||||||
|  | } | ||||||
							
								
								
									
										63
									
								
								src/pcm_resample.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/pcm_resample.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | /* the Music Player Daemon (MPD) | ||||||
|  |  * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) | ||||||
|  |  * 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_RESAMPLE_H | ||||||
|  | #define MPD_PCM_RESAMPLE_H | ||||||
|  |  | ||||||
|  | #include "config.h" | ||||||
|  |  | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stddef.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  |  | ||||||
|  | #ifdef HAVE_LIBSAMPLERATE | ||||||
|  | #include <samplerate.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | struct pcm_resample_state { | ||||||
|  | #ifdef HAVE_LIBSAMPLERATE | ||||||
|  | 	SRC_STATE *state; | ||||||
|  | 	SRC_DATA data; | ||||||
|  | 	size_t data_in_size; | ||||||
|  | 	size_t data_out_size; | ||||||
|  |  | ||||||
|  | 	struct { | ||||||
|  | 		unsigned src_rate; | ||||||
|  | 		unsigned dest_rate; | ||||||
|  | 		uint8_t channels; | ||||||
|  | 	} prev; | ||||||
|  |  | ||||||
|  | 	bool error; | ||||||
|  | #else | ||||||
|  | 	/* struct must not be empty */ | ||||||
|  | 	int dummy; | ||||||
|  | #endif | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | void pcm_resample_init(struct pcm_resample_state *state); | ||||||
|  |  | ||||||
|  | size_t | ||||||
|  | pcm_resample_16(uint8_t channels, | ||||||
|  | 		unsigned src_rate, | ||||||
|  | 		const int16_t *src_buffer, size_t src_size, | ||||||
|  | 		unsigned dest_rate, | ||||||
|  | 		int16_t *dest_buffer, size_t dest_size, | ||||||
|  | 		struct pcm_resample_state *state); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										61
									
								
								src/pcm_resample_fallback.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/pcm_resample_fallback.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | |||||||
|  | /* the Music Player Daemon (MPD) | ||||||
|  |  * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) | ||||||
|  |  * 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_resample.h" | ||||||
|  | #include "gcc.h" | ||||||
|  |  | ||||||
|  | /* resampling code blatantly ripped from ESD */ | ||||||
|  | size_t | ||||||
|  | pcm_resample_16(uint8_t channels, | ||||||
|  | 		unsigned src_rate, | ||||||
|  | 		const int16_t *src_buffer, mpd_unused size_t src_size, | ||||||
|  | 		unsigned dest_rate, | ||||||
|  | 		int16_t *dest_buffer, size_t dest_size, | ||||||
|  | 		mpd_unused struct pcm_resample_state *state) | ||||||
|  | { | ||||||
|  | 	unsigned src_pos, dest_pos = 0; | ||||||
|  | 	unsigned dest_samples = dest_size / 2; | ||||||
|  | 	int16_t lsample, rsample; | ||||||
|  |  | ||||||
|  | 	switch (channels) { | ||||||
|  | 	case 1: | ||||||
|  | 		while (dest_pos < dest_samples) { | ||||||
|  | 			src_pos = dest_pos * src_rate / dest_rate; | ||||||
|  |  | ||||||
|  | 			lsample = src_buffer[src_pos++]; | ||||||
|  |  | ||||||
|  | 			dest_buffer[dest_pos++] = lsample; | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	case 2: | ||||||
|  | 		while (dest_pos < dest_samples) { | ||||||
|  | 			src_pos = dest_pos * src_rate / dest_rate; | ||||||
|  | 			src_pos &= ~1; | ||||||
|  |  | ||||||
|  | 			lsample = src_buffer[src_pos++]; | ||||||
|  | 			rsample = src_buffer[src_pos++]; | ||||||
|  |  | ||||||
|  | 			dest_buffer[dest_pos++] = lsample; | ||||||
|  | 			dest_buffer[dest_pos++] = rsample; | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return dest_size; | ||||||
|  | } | ||||||
							
								
								
									
										140
									
								
								src/pcm_resample_libsamplerate.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								src/pcm_resample_libsamplerate.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,140 @@ | |||||||
|  | /* the Music Player Daemon (MPD) | ||||||
|  |  * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) | ||||||
|  |  * 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_resample.h" | ||||||
|  | #include "conf.h" | ||||||
|  | #include "log.h" | ||||||
|  | #include "utils.h" | ||||||
|  |  | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | static int pcm_resample_get_converter(void) | ||||||
|  | { | ||||||
|  | 	const char *conf = getConfigParamValue(CONF_SAMPLERATE_CONVERTER); | ||||||
|  | 	long convalgo; | ||||||
|  | 	char *test; | ||||||
|  | 	const char *test2; | ||||||
|  | 	size_t len; | ||||||
|  |  | ||||||
|  | 	if (!conf) { | ||||||
|  | 		convalgo = SRC_SINC_FASTEST; | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	convalgo = strtol(conf, &test, 10); | ||||||
|  | 	if (*test == '\0' && src_get_name(convalgo)) | ||||||
|  | 		goto out; | ||||||
|  |  | ||||||
|  | 	len = strlen(conf); | ||||||
|  | 	for (convalgo = 0 ; ; convalgo++) { | ||||||
|  | 		test2 = src_get_name(convalgo); | ||||||
|  | 		if (!test2) { | ||||||
|  | 			convalgo = SRC_SINC_FASTEST; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		if (strncasecmp(test2, conf, len) == 0) | ||||||
|  | 			goto out; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ERROR("unknown samplerate converter \"%s\"\n", conf); | ||||||
|  | out: | ||||||
|  | 	DEBUG("selecting samplerate converter \"%s\"\n", | ||||||
|  | 	      src_get_name(convalgo)); | ||||||
|  |  | ||||||
|  | 	return convalgo; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | size_t | ||||||
|  | pcm_resample_16(uint8_t channels, | ||||||
|  | 		unsigned src_rate, | ||||||
|  | 		const int16_t *src_buffer, size_t src_size, | ||||||
|  | 		unsigned dest_rate, | ||||||
|  | 		int16_t *dest_buffer, size_t dest_size, | ||||||
|  | 		struct pcm_resample_state *state) | ||||||
|  | { | ||||||
|  | 	static int convalgo = -1; | ||||||
|  | 	SRC_DATA *data = &state->data; | ||||||
|  | 	size_t data_in_size; | ||||||
|  | 	size_t data_out_size; | ||||||
|  | 	int error; | ||||||
|  |  | ||||||
|  | 	if (convalgo < 0) | ||||||
|  | 		convalgo = pcm_resample_get_converter(); | ||||||
|  |  | ||||||
|  | 	/* (re)set the state/ratio if the in or out format changed */ | ||||||
|  | 	if (channels != state->prev.channels || | ||||||
|  | 	    src_rate != state->prev.src_rate || | ||||||
|  | 	    dest_rate != state->prev.dest_rate) { | ||||||
|  | 		state->error = false; | ||||||
|  | 		state->prev.channels = channels; | ||||||
|  | 		state->prev.src_rate = src_rate; | ||||||
|  | 		state->prev.dest_rate = dest_rate; | ||||||
|  |  | ||||||
|  | 		if (state->state) | ||||||
|  | 			state->state = src_delete(state->state); | ||||||
|  |  | ||||||
|  | 		state->state = src_new(convalgo, channels, &error); | ||||||
|  | 		if (!state->state) { | ||||||
|  | 			ERROR("cannot create new libsamplerate state: %s\n", | ||||||
|  | 			      src_strerror(error)); | ||||||
|  | 			state->error = true; | ||||||
|  | 			return 0; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		data->src_ratio = (double)dest_rate / (double)src_rate; | ||||||
|  | 		DEBUG("setting samplerate conversion ratio to %.2lf\n", | ||||||
|  | 		      data->src_ratio); | ||||||
|  | 		src_set_ratio(state->state, data->src_ratio); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* there was an error previously, and nothing has changed */ | ||||||
|  | 	if (state->error) | ||||||
|  | 		return 0; | ||||||
|  |  | ||||||
|  | 	data->input_frames = src_size / 2 / channels; | ||||||
|  | 	data_in_size = data->input_frames * sizeof(float) * channels; | ||||||
|  | 	if (data_in_size > state->data_in_size) { | ||||||
|  | 		state->data_in_size = data_in_size; | ||||||
|  | 		data->data_in = xrealloc(data->data_in, data_in_size); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	data->output_frames = dest_size / 2 / channels; | ||||||
|  | 	data_out_size = data->output_frames * sizeof(float) * channels; | ||||||
|  | 	if (data_out_size > state->data_out_size) { | ||||||
|  | 		state->data_out_size = data_out_size; | ||||||
|  | 		data->data_out = xrealloc(data->data_out, data_out_size); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	src_short_to_float_array(src_buffer, data->data_in, | ||||||
|  | 				 data->input_frames * channels); | ||||||
|  |  | ||||||
|  | 	error = src_process(state->state, data); | ||||||
|  | 	if (error) { | ||||||
|  | 		ERROR("error processing samples with libsamplerate: %s\n", | ||||||
|  | 		      src_strerror(error)); | ||||||
|  | 		state->error = true; | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	src_float_to_short_array(data->data_out, dest_buffer, | ||||||
|  | 				 data->output_frames_gen * channels); | ||||||
|  |  | ||||||
|  | 	return data->output_frames_gen * 2 * channels; | ||||||
|  | } | ||||||
							
								
								
									
										162
									
								
								src/pcm_utils.c
									
									
									
									
									
								
							
							
						
						
									
										162
									
								
								src/pcm_utils.c
									
									
									
									
									
								
							| @@ -209,166 +209,10 @@ void pcm_convert_init(struct pcm_convert_state *state) | |||||||
| { | { | ||||||
| 	memset(state, 0, sizeof(*state)); | 	memset(state, 0, sizeof(*state)); | ||||||
|  |  | ||||||
|  | 	pcm_resample_init(&state->resample); | ||||||
| 	pcm_dither_24_init(&state->dither); | 	pcm_dither_24_init(&state->dither); | ||||||
| } | } | ||||||
|  |  | ||||||
| #ifdef HAVE_LIBSAMPLERATE |  | ||||||
| static int pcm_resample_get_converter(void) |  | ||||||
| { |  | ||||||
| 	const char *conf = getConfigParamValue(CONF_SAMPLERATE_CONVERTER); |  | ||||||
| 	long convalgo; |  | ||||||
| 	char *test; |  | ||||||
| 	const char *test2; |  | ||||||
| 	size_t len; |  | ||||||
|  |  | ||||||
| 	if (!conf) { |  | ||||||
| 		convalgo = SRC_SINC_FASTEST; |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	convalgo = strtol(conf, &test, 10); |  | ||||||
| 	if (*test == '\0' && src_get_name(convalgo)) |  | ||||||
| 		goto out; |  | ||||||
|  |  | ||||||
| 	len = strlen(conf); |  | ||||||
| 	for (convalgo = 0 ; ; convalgo++) { |  | ||||||
| 		test2 = src_get_name(convalgo); |  | ||||||
| 		if (!test2) { |  | ||||||
| 			convalgo = SRC_SINC_FASTEST; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 		if (strncasecmp(test2, conf, len) == 0) |  | ||||||
| 			goto out; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ERROR("unknown samplerate converter \"%s\"\n", conf); |  | ||||||
| out: |  | ||||||
| 	DEBUG("selecting samplerate converter \"%s\"\n", |  | ||||||
| 	      src_get_name(convalgo)); |  | ||||||
|  |  | ||||||
| 	return convalgo; |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifdef HAVE_LIBSAMPLERATE |  | ||||||
| static size_t pcm_resample(int8_t channels, uint32_t inSampleRate, |  | ||||||
| 			   const int16_t *src, size_t src_size, |  | ||||||
| 			   uint32_t outSampleRate, int16_t *outBuffer, |  | ||||||
| 			   size_t outSize, |  | ||||||
| 			   struct pcm_convert_state *convState) |  | ||||||
| { |  | ||||||
| 	static int convalgo = -1; |  | ||||||
| 	SRC_DATA *data = &convState->data; |  | ||||||
| 	size_t dataInSize; |  | ||||||
| 	size_t dataOutSize; |  | ||||||
| 	int error; |  | ||||||
|  |  | ||||||
| 	if (convalgo < 0) |  | ||||||
| 		convalgo = pcm_resample_get_converter(); |  | ||||||
|  |  | ||||||
| 	/* (re)set the state/ratio if the in or out format changed */ |  | ||||||
| 	if ((channels != convState->lastChannels) || |  | ||||||
| 	    (inSampleRate != convState->lastInSampleRate) || |  | ||||||
| 	    (outSampleRate != convState->lastOutSampleRate)) { |  | ||||||
| 		convState->error = 0; |  | ||||||
| 		convState->lastChannels = channels; |  | ||||||
| 		convState->lastInSampleRate = inSampleRate; |  | ||||||
| 		convState->lastOutSampleRate = outSampleRate; |  | ||||||
|  |  | ||||||
| 		if (convState->state) |  | ||||||
| 			convState->state = src_delete(convState->state); |  | ||||||
|  |  | ||||||
| 		convState->state = src_new(convalgo, channels, &error); |  | ||||||
| 		if (!convState->state) { |  | ||||||
| 			ERROR("cannot create new libsamplerate state: %s\n", |  | ||||||
| 			      src_strerror(error)); |  | ||||||
| 			convState->error = 1; |  | ||||||
| 			return 0; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		data->src_ratio = (double)outSampleRate / (double)inSampleRate; |  | ||||||
| 		DEBUG("setting samplerate conversion ratio to %.2lf\n", |  | ||||||
| 		      data->src_ratio); |  | ||||||
| 		src_set_ratio(convState->state, data->src_ratio); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* there was an error previously, and nothing has changed */ |  | ||||||
| 	if (convState->error) |  | ||||||
| 		return 0; |  | ||||||
|  |  | ||||||
| 	data->input_frames = src_size / 2 / channels; |  | ||||||
| 	dataInSize = data->input_frames * sizeof(float) * channels; |  | ||||||
| 	if (dataInSize > convState->dataInSize) { |  | ||||||
| 		convState->dataInSize = dataInSize; |  | ||||||
| 		data->data_in = xrealloc(data->data_in, dataInSize); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	data->output_frames = outSize / 2 / channels; |  | ||||||
| 	dataOutSize = data->output_frames * sizeof(float) * channels; |  | ||||||
| 	if (dataOutSize > convState->dataOutSize) { |  | ||||||
| 		convState->dataOutSize = dataOutSize; |  | ||||||
| 		data->data_out = xrealloc(data->data_out, dataOutSize); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	src_short_to_float_array((const short *)src, data->data_in, |  | ||||||
| 	                         data->input_frames * channels); |  | ||||||
|  |  | ||||||
| 	error = src_process(convState->state, data); |  | ||||||
| 	if (error) { |  | ||||||
| 		ERROR("error processing samples with libsamplerate: %s\n", |  | ||||||
| 		      src_strerror(error)); |  | ||||||
| 		convState->error = 1; |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	src_float_to_short_array(data->data_out, (short *)outBuffer, |  | ||||||
| 	                         data->output_frames_gen * channels); |  | ||||||
|  |  | ||||||
| 	return data->output_frames_gen * 2 * channels; |  | ||||||
| } |  | ||||||
| #else /* !HAVE_LIBSAMPLERATE */ |  | ||||||
| /* resampling code blatantly ripped from ESD */ |  | ||||||
| static size_t pcm_resample(int8_t channels, uint32_t inSampleRate, |  | ||||||
| 			   const int16_t *src, mpd_unused size_t src_size, |  | ||||||
| 			   uint32_t outSampleRate, char *outBuffer, |  | ||||||
| 			   size_t outSize, |  | ||||||
| 			   mpd_unused struct pcm_convert_state *convState) |  | ||||||
| { |  | ||||||
| 	uint32_t rd_dat = 0; |  | ||||||
| 	uint32_t wr_dat = 0; |  | ||||||
| 	const int16_t *in = (const int16_t *)src; |  | ||||||
| 	int16_t *out = (int16_t *)outBuffer; |  | ||||||
| 	uint32_t nlen = outSize / 2; |  | ||||||
| 	int16_t lsample, rsample; |  | ||||||
|  |  | ||||||
| 	switch (channels) { |  | ||||||
| 	case 1: |  | ||||||
| 		while (wr_dat < nlen) { |  | ||||||
| 			rd_dat = wr_dat * inSampleRate / outSampleRate; |  | ||||||
|  |  | ||||||
| 			lsample = in[rd_dat++]; |  | ||||||
|  |  | ||||||
| 			out[wr_dat++] = lsample; |  | ||||||
| 		} |  | ||||||
| 		break; |  | ||||||
| 	case 2: |  | ||||||
| 		while (wr_dat < nlen) { |  | ||||||
| 			rd_dat = wr_dat * inSampleRate / outSampleRate; |  | ||||||
| 			rd_dat &= ~1; |  | ||||||
|  |  | ||||||
| 			lsample = in[rd_dat++]; |  | ||||||
| 			rsample = in[rd_dat++]; |  | ||||||
|  |  | ||||||
| 			out[wr_dat++] = lsample; |  | ||||||
| 			out[wr_dat++] = rsample; |  | ||||||
| 		} |  | ||||||
| 		break; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return outSize; |  | ||||||
| } |  | ||||||
| #endif /* !HAVE_LIBSAMPLERATE */ |  | ||||||
|  |  | ||||||
| static void | static void | ||||||
| pcm_convert_channels_1_to_2(int16_t *dest, const int16_t *src, | pcm_convert_channels_1_to_2(int16_t *dest, const int16_t *src, | ||||||
| 			    unsigned num_frames) | 			    unsigned num_frames) | ||||||
| @@ -542,11 +386,11 @@ size_t pcm_convert(const struct audio_format *inFormat, | |||||||
| 		assert(dest_size >= len); | 		assert(dest_size >= len); | ||||||
| 		memcpy(outBuffer, buf, len); | 		memcpy(outBuffer, buf, len); | ||||||
| 	} else { | 	} else { | ||||||
| 		len = pcm_resample(outFormat->channels, | 		len = pcm_resample_16(outFormat->channels, | ||||||
| 				      inFormat->sample_rate, buf, len, | 				      inFormat->sample_rate, buf, len, | ||||||
| 				      outFormat->sample_rate, | 				      outFormat->sample_rate, | ||||||
| 				      (int16_t*)outBuffer, | 				      (int16_t*)outBuffer, | ||||||
| 				   dest_size, convState); | 				      dest_size, &convState->resample); | ||||||
| 		if (len == 0) | 		if (len == 0) | ||||||
| 			exit(EXIT_FAILURE); | 			exit(EXIT_FAILURE); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -19,28 +19,16 @@ | |||||||
| #ifndef PCM_UTILS_H | #ifndef PCM_UTILS_H | ||||||
| #define PCM_UTILS_H | #define PCM_UTILS_H | ||||||
|  |  | ||||||
| #include "../config.h" | #include "pcm_resample.h" | ||||||
| #include "pcm_dither.h" | #include "pcm_dither.h" | ||||||
|  |  | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stddef.h> | #include <stddef.h> | ||||||
|  |  | ||||||
| #ifdef HAVE_LIBSAMPLERATE |  | ||||||
| #include <samplerate.h> |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| struct audio_format; | struct audio_format; | ||||||
|  |  | ||||||
| struct pcm_convert_state { | struct pcm_convert_state { | ||||||
| #ifdef HAVE_LIBSAMPLERATE | 	struct pcm_resample_state resample; | ||||||
| 	SRC_STATE *state; |  | ||||||
| 	SRC_DATA data; |  | ||||||
| 	size_t dataInSize; |  | ||||||
| 	size_t dataOutSize; |  | ||||||
| 	int8_t lastChannels; |  | ||||||
| 	uint32_t lastInSampleRate; |  | ||||||
| 	uint32_t lastOutSampleRate; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	struct pcm_dither_24 dither; | 	struct pcm_dither_24 dither; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Max Kellermann
					Max Kellermann