diff --git a/Makefile.defs b/Makefile.defs index 927d325c..069d3672 100644 --- a/Makefile.defs +++ b/Makefile.defs @@ -27,6 +27,12 @@ CPPFLAGS += -D_DEBUG \ #LIBSPANDSP_STATIC = yes #LIBSPANDSP_LDIR = /usr/local/lib/ + +# compile with sample rate conversion from secret rabbit code? +# (see http://www.mega-nerd.com/SRC/) +# +#USE_LIBSAMPLERATE = yes + LDFLAGS += -lm OS = $(shell uname -s | sed -e s/SunOS/solaris/ | tr "[A-Z]" "[a-z]") diff --git a/core/AmAudio.cpp b/core/AmAudio.cpp index d7582bbb..58c083ce 100644 --- a/core/AmAudio.cpp +++ b/core/AmAudio.cpp @@ -39,6 +39,8 @@ #include +#define SYSTEM_SAMPLERATE 8000 // fixme: sr per session + /** \brief structure to hold loaded codec instances */ struct CodecContainer { @@ -246,6 +248,10 @@ AmAudio::AmAudio() : fmt(new AmAudioSimpleFormat(CODEC_PCM16)), max_rec_time(-1), rec_time(0) +#ifdef USE_LIBSAMPLERATE + , resample_state(NULL), + resample_buf_samples(0) +#endif { } @@ -258,6 +264,10 @@ AmAudio::AmAudio(AmAudioFormat *_fmt) AmAudio::~AmAudio() { +#ifdef USE_LIBSAMPLERATE + if (NULL != resample_state) + src_delete(resample_state); +#endif } void AmAudio::close() @@ -384,6 +394,54 @@ unsigned int AmAudio::downMix(unsigned int size) samples.swap(); } +#ifdef USE_LIBSAMPLERATE + if (fmt->rate != SYSTEM_SAMPLERATE) { + if (!resample_state) { + int src_error; + // for better quality but more CPU usage, use SRC_SINC_ converters + resample_state = src_new(SRC_LINEAR, 1, &src_error); + if (!resample_state) { + ERROR("samplerate initialization error: "); + } + } + + if (resample_state) { + if (resample_buf_samples + PCM16_B2S(s) > PCM16_B2S(AUDIO_BUFFER_SIZE) * 2) { + WARN("resample input buffer overflow! (%d)\n", + resample_buf_samples + PCM16_B2S(s)); + } else { + signed short* samples_s = (signed short*)(unsigned char*)samples; + src_short_to_float_array(samples_s, &resample_in[resample_buf_samples], PCM16_B2S(s)); + resample_buf_samples += PCM16_B2S(s); + } + + SRC_DATA src_data; + src_data.data_in = resample_in; + src_data.input_frames = resample_buf_samples; + src_data.data_out = resample_out; + src_data.output_frames = PCM16_B2S(AUDIO_BUFFER_SIZE); + src_data.src_ratio = (double)SYSTEM_SAMPLERATE / (double)fmt->rate; + src_data.end_of_input = 0; + + int src_err = src_process(resample_state, &src_data); + if (src_err) { + DBG("resample error: '%s'\n", src_strerror(src_err)); + }else { + signed short* samples_s = (signed short*)(unsigned char*)samples; + src_float_to_short_array(resample_out, samples_s, src_data.output_frames_gen); + s = PCM16_S2B(src_data.output_frames_gen); + + if (resample_buf_samples != (unsigned int)src_data.input_frames_used) { + memmove(resample_in, &resample_in[src_data.input_frames_used], + (resample_buf_samples - src_data.input_frames_used) * sizeof(float)); + } + resample_buf_samples = resample_buf_samples - src_data.input_frames_used; + } + } + } +#endif + + return s; } diff --git a/core/AmAudio.h b/core/AmAudio.h index f8e79249..d1393082 100644 --- a/core/AmAudio.h +++ b/core/AmAudio.h @@ -40,6 +40,10 @@ using std::auto_ptr; using std::string; #include +#ifdef USE_LIBSAMPLERATE +#include +#endif + #define PCM16_B2S(b) ((b) >> 1) #define PCM16_S2B(s) ((s) << 1) @@ -203,6 +207,13 @@ private: int rec_time; // in samples int max_rec_time; +#ifdef USE_LIBSAMPLERATE + SRC_STATE* resample_state; + float resample_in[PCM16_B2S(AUDIO_BUFFER_SIZE)*2]; + float resample_out[PCM16_B2S(AUDIO_BUFFER_SIZE)]; + size_t resample_buf_samples; +#endif + protected: /** Sample buffer. */ DblBuffer samples; diff --git a/core/Makefile b/core/Makefile index e54bc864..b668fbfe 100644 --- a/core/Makefile +++ b/core/Makefile @@ -56,6 +56,10 @@ ifdef USE_SPANDSP CPPFLAGS += -DUSE_SPANDSP -D__STDC_LIMIT_MACROS endif +ifdef USE_LIBSAMPLERATE +CPPFLAGS += -DUSE_LIBSAMPLERATE +LDFLAGS +=-lsamplerate +endif # implicit rules %.o : %.cpp %.d