From f27514b4f5f2c4c99e0f7656eabc12db55066a12 Mon Sep 17 00:00:00 2001 From: "rafael@riseup.net" Date: Mon, 10 May 2010 00:07:25 +0000 Subject: [PATCH] synced with trunk --- darkice/branches/darkice-macosx/AUTHORS | 4 +- darkice/branches/darkice-macosx/ChangeLog | 16 +++ darkice/branches/darkice-macosx/Makefile.am | 2 +- darkice/branches/darkice-macosx/configure.in | 38 ++++++ darkice/branches/darkice-macosx/man/darkice.1 | 2 +- .../branches/darkice-macosx/man/darkice.cfg.5 | 2 +- .../darkice-macosx/src/AlsaDspSource.cpp | 4 +- .../darkice-macosx/src/BufferedSink.cpp | 11 +- .../darkice-macosx/src/FaacEncoder.cpp | 117 ++++++++++++++-- .../branches/darkice-macosx/src/FaacEncoder.h | 84 ++++++++++++ .../branches/darkice-macosx/src/IceCast2.cpp | 2 +- .../branches/darkice-macosx/src/Makefile.am | 39 ++++-- .../darkice-macosx/src/VorbisLibEncoder.cpp | 30 ++++- .../darkice-macosx/src/VorbisLibEncoder.h | 17 ++- .../darkice-macosx/src/aacPlusEncoder.cpp | 127 +++++++++++++----- .../darkice-macosx/src/aacPlusEncoder.h | 95 ++++++++++++- darkice/branches/darkice-macosx/src/main.cpp | 4 +- 17 files changed, 520 insertions(+), 74 deletions(-) diff --git a/darkice/branches/darkice-macosx/AUTHORS b/darkice/branches/darkice-macosx/AUTHORS index 43086e2..dec1fee 100644 --- a/darkice/branches/darkice-macosx/AUTHORS +++ b/darkice/branches/darkice-macosx/AUTHORS @@ -39,4 +39,6 @@ with contributions by: Daniel Hazelbaker Alessandro Beretta Roland Hermans - + Sergiy + Clemens Ladisch + Edwin van den Oetelaar diff --git a/darkice/branches/darkice-macosx/ChangeLog b/darkice/branches/darkice-macosx/ChangeLog index 1ae3077..619620e 100644 --- a/darkice/branches/darkice-macosx/ChangeLog +++ b/darkice/branches/darkice-macosx/ChangeLog @@ -1,3 +1,19 @@ +Next release + o fixed a bug in BufferedSink.cpp that leads to some buffers + being written twice, causing corruption of datastream, + thanks to Edwin van den Oetelaar + o implemented samplerate conversion for all codecs using libsamplerate, + and keeping internal aflibConverter as fallback, + thanks to Sergiy + o bugfix: fix for alsa driver - closes ticked #8 + thanks to Clemens Ladisch + o Implemented CoreAudio driver for MacOS X + +14-11-2009 Darkice 0.20.1 released + o added rc.darkice init script + thanks to Niels Dettenbach + o bugfix: fix for gcc 4.4 + 05-11-2009 Darkice 0.20 released o new maintainer: Rafael Diniz diff --git a/darkice/branches/darkice-macosx/Makefile.am b/darkice/branches/darkice-macosx/Makefile.am index b533a99..c9ef6d9 100644 --- a/darkice/branches/darkice-macosx/Makefile.am +++ b/darkice/branches/darkice-macosx/Makefile.am @@ -6,7 +6,7 @@ SUBDIRS = src man sysconf_DATA = darkice.cfg -EXTRA_DIST = $(DOC_DIR) darkice.cfg INSTALL.lame INSTALL.vorbis FAQ +EXTRA_DIST = $(DOC_DIR) darkice.cfg INSTALL.lame INSTALL.vorbis FAQ rc.darkice .PHONY: doc diff --git a/darkice/branches/darkice-macosx/configure.in b/darkice/branches/darkice-macosx/configure.in index f0ce058..0b6c699 100644 --- a/darkice/branches/darkice-macosx/configure.in +++ b/darkice/branches/darkice-macosx/configure.in @@ -270,6 +270,7 @@ dnl link JACK sound server if requested dnl----------------------------------------------------------------------------- AC_SUBST(JACK_CFLAGS) AC_SUBST(JACK_LDFLAGS) +AC_SUBST(JACK_INCFLAGS) AC_ARG_WITH(jack, [ --with-jack use JACK sound system [yes] ], @@ -315,6 +316,43 @@ AC_ARG_WITH(core, [ --with-core = choose CoreAudio API support (mac only)], [ +dnl----------------------------------------------------------------------------- +dnl link Secret Rabbit Code (aka libsamplerate) if requested +dnl----------------------------------------------------------------------------- +AC_SUBST(SRC_CFLAGS) +AC_SUBST(SRC_LDFLAGS) +AC_SUBST(SRC_INCFLAGS) + +AC_ARG_WITH(samplerate, +[ --with-samplerate use Secret Rabbit Code (aka libsamplerate) for samplerate conversion [yes] ], + USE_SRC=${withval}, USE_SRC="yes" ) +AC_ARG_WITH(samplerate-prefix, +[ --with-samplerate-prefix=DIR alternate location for samplerate [/usr] + look for libraries in SRC-PREFIX/lib, + for headers in SRC-PREFIX/include], + CONFIG_SRC_PREFIX="${withval}", CONFIG_SRC_PREFIX="/usr") + +if test "x${USE_SRC}" = "xyes" ; then + AC_MSG_CHECKING( [for samplerate libraries at ${CONFIG_SRC_PREFIX}] ) + LA_SEARCH_LIB( SRC_LIB_LOC, SRC_INC_LOC, libsamplerate.la libsamplerate.so libsamplerate.dylib, samplerate.h, + ${CONFIG_SRC_PREFIX}) + + if test "x${SRC_LIB_LOC}" != "x" ; then + + AC_DEFINE( HAVE_SRC_LIB, 1, [build with samplerate conversion through libsamplerate] ) + if test "x${SRC_INC_LOC}" != "x${SYSTEM_INCLUDE}" ; then + SRC_INCFLAGS="-I${SRC_INC_LOC}" + fi + SRC_LDFLAGS="-L${SRC_LIB_LOC} -lsamplerate" + AC_MSG_RESULT( [found at ${CONFIG_SRC_PREFIX}] ) + else + AC_MSG_WARN( [not found, building libsamplerate support]) + fi +else + AC_MSG_RESULT( [building without libsamplerate support] ) +fi + +AM_CONDITIONAL(HAVE_SRC_LIB, test "x${SRC_LIB_LOC}" != "x") dnl----------------------------------------------------------------------------- dnl check for MSG_NOSIGNAL for the send() function in libsocket dnl----------------------------------------------------------------------------- diff --git a/darkice/branches/darkice-macosx/man/darkice.1 b/darkice/branches/darkice-macosx/man/darkice.1 index b780400..2be095c 100644 --- a/darkice/branches/darkice-macosx/man/darkice.1 +++ b/darkice/branches/darkice-macosx/man/darkice.1 @@ -114,7 +114,7 @@ Developed with contributions by .SH LINKS Project homepage: -.I http://darkice.tyrell.hu/ +.I http://code.google.com/p/darkice/ .B IceCast homepage: diff --git a/darkice/branches/darkice-macosx/man/darkice.cfg.5 b/darkice/branches/darkice-macosx/man/darkice.cfg.5 index 0ab4be0..37ffba9 100644 --- a/darkice/branches/darkice-macosx/man/darkice.cfg.5 +++ b/darkice/branches/darkice-macosx/man/darkice.cfg.5 @@ -655,7 +655,7 @@ Akos Maroy .SH LINKS Project homepage: -.I http://darkice.tyrell.hu/ +.I http://code.google.com/p/darkice/ .B IceCast homepage: diff --git a/darkice/branches/darkice-macosx/src/AlsaDspSource.cpp b/darkice/branches/darkice-macosx/src/AlsaDspSource.cpp index 0e443d1..17894c5 100644 --- a/darkice/branches/darkice-macosx/src/AlsaDspSource.cpp +++ b/darkice/branches/darkice-macosx/src/AlsaDspSource.cpp @@ -173,8 +173,8 @@ AlsaDspSource :: open ( void ) throw ( Exception ) throw Exception( __FILE__, __LINE__, "can't set channels", u); } - u = getBufferTime() / 4; - if (snd_pcm_hw_params_set_period_time_near(captureHandle, hwParams, &u, 0) + u = 4; + if (snd_pcm_hw_params_set_periods_near(captureHandle, hwParams, &u, 0) < 0) { snd_pcm_hw_params_free(hwParams); close(); diff --git a/darkice/branches/darkice-macosx/src/BufferedSink.cpp b/darkice/branches/darkice-macosx/src/BufferedSink.cpp index aabbadd..f27b774 100644 --- a/darkice/branches/darkice-macosx/src/BufferedSink.cpp +++ b/darkice/branches/darkice-macosx/src/BufferedSink.cpp @@ -330,10 +330,15 @@ BufferedSink :: write ( const void * buf, // the internal buffer is empty, try to write the fresh data soFar = 0; - if ( inp != outp ) { + if ( inp == outp ) { while ( soFar < len && sink->canWrite( 0, 0) ) { - soFar += sink->write( b + soFar, len - soFar); - } + try { + soFar += sink->write( b + soFar, len - soFar); + } catch (Exception &e) { + reportEvent(3,"Exception caught in BufferedSink :: write3\n"); + throw; /* up a level */ + } + } } length = soFar; diff --git a/darkice/branches/darkice-macosx/src/FaacEncoder.cpp b/darkice/branches/darkice-macosx/src/FaacEncoder.cpp index 87bd243..5f37fa8 100644 --- a/darkice/branches/darkice-macosx/src/FaacEncoder.cpp +++ b/darkice/branches/darkice-macosx/src/FaacEncoder.cpp @@ -81,7 +81,7 @@ FaacEncoder :: open ( void ) faacEncGetVersion(&faacVersion, &faacCopyright); reportEvent(1, "Using faac codec version", faacVersion); - encoderHandle = faacEncOpen(getInSampleRate(), + encoderHandle = faacEncOpen(getOutSampleRate(), getInChannel(), &inputSamples, &maxOutputBytes); @@ -107,6 +107,31 @@ FaacEncoder :: open ( void ) "error configuring faac library"); } + // initialize the resampling coverter if needed + if ( converter ) { + +#ifdef HAVE_SRC_LIB + converterData.input_frames = 4096/((getInBitsPerSample() / 8) * getInChannel()); + converterData.data_in = new float[converterData.input_frames*getInChannel()]; + converterData.output_frames = (int) (converterData.input_frames * resampleRatio + 1); + if ((int) inputSamples > getInChannel() * converterData.output_frames) { + resampledOffset = new float[2 * inputSamples]; + } else { + resampledOffset = new float[2 * getInChannel() * converterData.input_frames]; + } + converterData.src_ratio = resampleRatio; + converterData.end_of_input = 0; +#else + converter->initialize( resampleRatio, getInChannel()); + //needed 2x(converted input samples) to handle offsets + int outCount = 2 * getInChannel() * (inputSamples + 1); + if (resampleRatio > 1) + outCount = (int) (outCount * resampleRatio); + resampledOffset = new short int[outCount]; +#endif + resampledOffsetSize = 0; + } + faacOpen = true; return true; @@ -134,25 +159,89 @@ FaacEncoder :: write ( const void * buf, int samples = (int) nSamples * channels; int processedSamples = 0; - while (processedSamples < samples) { - int outputBytes; - int inSamples = samples - processedSamples < (int) inputSamples - ? samples - processedSamples - : inputSamples; - outputBytes = faacEncEncode(encoderHandle, - (int32_t*) (b + processedSamples/sampleSize), - inSamples, - faacBuf, - maxOutputBytes); - getSink()->write(faacBuf, outputBytes); - processedSamples += inSamples; + if ( converter ) { + unsigned int converted; +#ifdef HAVE_SRC_LIB + src_short_to_float_array ((short *) b, converterData.data_in, samples); + converterData.input_frames = nSamples; + converterData.data_out = resampledOffset + (resampledOffsetSize * channels); + int srcError = src_process (converter, &converterData); + if (srcError) + throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError)); + converted = converterData.output_frames_gen; +#else + int inCount = nSamples; + short int * shortBuffer = new short int[samples]; + int outCount = (int) (inCount * resampleRatio); + Util::conv( bitsPerSample, b, processed, shortBuffer, isInBigEndian()); + converted = converter->resample( inCount, + outCount+1, + shortBuffer, + &resampledOffset[resampledOffsetSize*channels]); + delete[] shortBuffer; +#endif + resampledOffsetSize += converted; + + // encode samples (if enough) + while(resampledOffsetSize - processedSamples >= inputSamples/channels) { + int outputBytes; +#ifdef HAVE_SRC_LIB + short *shortData = new short[inputSamples]; + src_float_to_short_array(resampledOffset + (processedSamples * channels), + shortData, inputSamples) ; + outputBytes = faacEncEncode(encoderHandle, + (int32_t*) shortData, + inputSamples, + faacBuf, + maxOutputBytes); + delete [] shortData; +#else + outputBytes = faacEncEncode(encoderHandle, + (int32_t*) &resampledOffset[processedSamples*channels], + inputSamples, + faacBuf, + maxOutputBytes); +#endif + getSink()->write(faacBuf, outputBytes); + processedSamples+=inputSamples/channels; + } + + if (processedSamples && (int) resampledOffsetSize >= processedSamples) { + resampledOffsetSize -= processedSamples; + //move least part of resampled data to beginning + if(resampledOffsetSize) +#ifdef HAVE_SRC_LIB + resampledOffset = (float *) memmove(resampledOffset, &resampledOffset[processedSamples*channels], + resampledOffsetSize*channels*sizeof(float)); +#else + resampledOffset = (short *) memmove(resampledOffset, &resampledOffset[processedSamples*channels], + resampledOffsetSize*sampleSize); +#endif + } + } else { + while (processedSamples < samples) { + int outputBytes; + int inSamples = samples - processedSamples < (int) inputSamples + ? samples - processedSamples + : inputSamples; + + outputBytes = faacEncEncode(encoderHandle, + (int32_t*) (b + processedSamples/sampleSize), + inSamples, + faacBuf, + maxOutputBytes); + getSink()->write(faacBuf, outputBytes); + + processedSamples += inSamples; + } } delete[] faacBuf; - return processedSamples; +// return processedSamples; + return samples; } diff --git a/darkice/branches/darkice-macosx/src/FaacEncoder.h b/darkice/branches/darkice-macosx/src/FaacEncoder.h index 4589a8a..ec2d80a 100644 --- a/darkice/branches/darkice-macosx/src/FaacEncoder.h +++ b/darkice/branches/darkice-macosx/src/FaacEncoder.h @@ -52,6 +52,11 @@ #include "Reporter.h" #include "AudioEncoder.h" #include "Sink.h" +#ifdef HAVE_SRC_LIB +#include +#else +#include "aflibConverter.h" +#endif /* ================================================================ constants */ @@ -98,6 +103,24 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter */ int lowpass; + /** + * Resample ratio + */ + double resampleRatio; + + /** + * sample rate converter object for possible resampling + */ +#ifdef HAVE_SRC_LIB + SRC_STATE *converter; + SRC_DATA converterData; + float *resampledOffset; +#else + aflibConverter *converter; + short *resampledOffset; +#endif + unsigned int resampledOffsetSize; + /** * Initialize the object. * @@ -133,6 +156,58 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter throw Exception( __FILE__, __LINE__, "input channels and output channels do not match"); } + if ( getOutSampleRate() == getInSampleRate() ) { + resampleRatio = 1; + converter = 0; + } else if (getInBitsPerSample() == 16) { + resampleRatio = ( (double) getOutSampleRate() / + (double) getInSampleRate() ); + + // Determine if we can use linear interpolation. + // The inverse of the ratio must be a power of two for linear mode to + // be of sufficient quality. + + bool useLinear = true; + double inverse = 1 / resampleRatio; + int integer = (int) inverse; + + // Check that the inverse of the ratio is an integer + if( integer == inverse ) { + while( useLinear && integer ) { // Loop through the bits + // If the lowest order bit is not the only one set + if( integer & 1 && integer != 1 ) { + // Not a power of two; cannot use linear + useLinear = false; + } else { + // Shift all the bits over and try again + integer >>= 1; + } + } + } else { + useLinear = false; + } + + // If we get here and useLinear is still true, then we have + // a power of two. + + // open the aflibConverter in + // - high quality + // - linear or quadratic (non-linear) based on algorithm + // - not filter interpolation +#ifdef HAVE_SRC_LIB + int srcError = 0; + converter = src_new(useLinear == true ? SRC_LINEAR : SRC_SINC_FASTEST, + getInChannel(), &srcError); + if(srcError) + throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError)); +#else + converter = new aflibConverter( true, useLinear, false); +#endif + } else { + throw Exception( __FILE__, __LINE__, + "specified bits per sample with samplerate conversion not supported", + getInBitsPerSample() ); + } } /** @@ -143,6 +218,15 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter inline void strip ( void ) throw ( Exception ) { + if ( converter ) { +#ifdef HAVE_SRC_LIB + delete [] converterData.data_in; + src_delete (converter); +#else + delete converter; +#endif + delete [] resampledOffset; + } } diff --git a/darkice/branches/darkice-macosx/src/IceCast2.cpp b/darkice/branches/darkice-macosx/src/IceCast2.cpp index b1469fb..f07b4e0 100644 --- a/darkice/branches/darkice-macosx/src/IceCast2.cpp +++ b/darkice/branches/darkice-macosx/src/IceCast2.cpp @@ -190,7 +190,7 @@ IceCast2 :: sendLogin ( void ) throw ( Exception ) } // send user agent info - str = "\nUser-Agent: DarkIce/" VERSION " (http://darkice.tyrell.hu/)"; + str = "\nUser-Agent: DarkIce/" VERSION " (http://code.google.com/p/darkice/)"; sink->write( str, strlen( str)); // send the ice- headers diff --git a/darkice/branches/darkice-macosx/src/Makefile.am b/darkice/branches/darkice-macosx/src/Makefile.am index 8a12e87..b1c49bc 100644 --- a/darkice/branches/darkice-macosx/src/Makefile.am +++ b/darkice/branches/darkice-macosx/src/Makefile.am @@ -1,9 +1,21 @@ bin_PROGRAMS = darkice AM_CXXFLAGS = -O2 -pedantic -Wall @DEBUG_CXXFLAGS@ @PTHREAD_CFLAGS@ @JACK_CFLAGS@ -INCLUDES = @LAME_INCFLAGS@ @VORBIS_INCFLAGS@ @FAAC_INCFLAGS@ @AACPLUS_INCFLAGS@ @TWOLAME_INCFLAGS@ @ALSA_INCFLAGS@ +INCLUDES = @LAME_INCFLAGS@ @VORBIS_INCFLAGS@ @FAAC_INCFLAGS@ @AACPLUS_INCFLAGS@ @TWOLAME_INCFLAGS@ \ + @ALSA_INCFLAGS@ @JACK_INCFLAGS@ @SRC_INCFLAGS@ LDADD = @PTHREAD_LIBS@ @LAME_LDFLAGS@ @VORBIS_LDFLAGS@ @FAAC_LDFLAGS@ @AACPLUS_LDFLAGS@ @TWOLAME_LDFLAGS@ \ - @ALSA_LDFLAGS@ @JACK_LDFLAGS@ @COREAUDIO_LDFLAGS@ + @ALSA_LDFLAGS@ @JACK_LDFLAGS@ @SRC_LDFLAGS@ @COREAUDIO_LDFLAGS@ + +if HAVE_SRC_LIB +AFLIB_SOURCE = +else +AFLIB_SOURCE = aflibDebug.h\ + aflibDebug.cc\ + aflibConverter.h\ + aflibConverter.cc\ + aflibConverterLargeFilter.h\ + aflibConverterSmallFilter.h +endif darkice_SOURCES = AudioEncoder.h\ AudioSource.h\ @@ -40,12 +52,6 @@ darkice_SOURCES = AudioEncoder.h\ FaacEncoder.h\ aacPlusEncoder.cpp\ aacPlusEncoder.h\ - aflibDebug.h\ - aflibDebug.cc\ - aflibConverter.h\ - aflibConverter.cc\ - aflibConverterLargeFilter.h\ - aflibConverterSmallFilter.h\ OssDspSource.cpp\ OssDspSource.h\ SerialUlaw.cpp\ @@ -68,9 +74,16 @@ darkice_SOURCES = AudioEncoder.h\ Reporter.cpp\ AlsaDspSource.h\ AlsaDspSource.cpp\ - JackDspSource.h\ - JackDspSource.cpp\ - CoreAudioDspSource.h\ - CoreAudioDspSource.cpp\ - main.cpp + JackDspSource.h\ + JackDspSource.cpp\ + CoreAudioDspSource.h\ + CoreAudioDspSource.cpp\ + main.cpp\ + $(AFLIB_SOURCE) +EXTRA_darkice_SOURCES = aflibDebug.h\ + aflibDebug.cc\ + aflibConverter.h\ + aflibConverter.cc\ + aflibConverterLargeFilter.h\ + aflibConverterSmallFilter.h diff --git a/darkice/branches/darkice-macosx/src/VorbisLibEncoder.cpp b/darkice/branches/darkice-macosx/src/VorbisLibEncoder.cpp index 2f5e276..c5087eb 100644 --- a/darkice/branches/darkice-macosx/src/VorbisLibEncoder.cpp +++ b/darkice/branches/darkice-macosx/src/VorbisLibEncoder.cpp @@ -117,7 +117,15 @@ VorbisLibEncoder :: init ( unsigned int outMaxBitrate ) // - high quality // - linear or quadratic (non-linear) based on algorithm // - not filter interpolation +#ifdef HAVE_SRC_LIB + int srcError = 0; + converter = src_new(useLinear == true ? SRC_LINEAR : SRC_SINC_FASTEST, + getInChannel(), &srcError); + if(srcError) + throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError)); +#else converter = new aflibConverter( true, useLinear, false); +#endif } encoderOpen = false; @@ -243,7 +251,16 @@ VorbisLibEncoder :: open ( void ) // initialize the resampling coverter if needed if ( converter ) { +#ifdef HAVE_SRC_LIB + converterData.input_frames = 4096/((getInBitsPerSample() / 8) * getInChannel()); + converterData.data_in = new float[converterData.input_frames*getInChannel()]; + converterData.output_frames = (int) (converterData.input_frames * resampleRatio + 1); + converterData.data_out = new float[getInChannel() * converterData.output_frames]; + converterData.src_ratio = resampleRatio; + converterData.end_of_input = 0; +#else converter->initialize( resampleRatio, getInChannel()); +#endif } encoderOpen = true; @@ -307,13 +324,24 @@ VorbisLibEncoder :: write ( const void * buf, // resample if needed int inCount = nSamples; int outCount = (int) (inCount * resampleRatio); - short int * resampledBuffer = new short int[outCount * channels]; + short int * resampledBuffer = new short int[(outCount+1)* channels]; int converted; +#ifdef HAVE_SRC_LIB + converterData.input_frames = nSamples; + src_short_to_float_array (shortBuffer, converterData.data_in, totalSamples); + int srcError = src_process (converter, &converterData); + if (srcError) + throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError)); + converted = converterData.output_frames_gen; + src_float_to_short_array(converterData.data_out, resampledBuffer, converted*channels); + +#else converted = converter->resample( inCount, outCount, shortBuffer, resampledBuffer ); +#endif vorbisBuffer = vorbis_analysis_buffer( &vorbisDspState, converted); diff --git a/darkice/branches/darkice-macosx/src/VorbisLibEncoder.h b/darkice/branches/darkice-macosx/src/VorbisLibEncoder.h index 8d12b61..f73f062 100644 --- a/darkice/branches/darkice-macosx/src/VorbisLibEncoder.h +++ b/darkice/branches/darkice-macosx/src/VorbisLibEncoder.h @@ -52,7 +52,11 @@ #include "Reporter.h" #include "AudioEncoder.h" #include "CastSink.h" +#ifdef HAVE_SRC_LIB +#include +#else #include "aflibConverter.h" +#endif /* ================================================================ constants */ @@ -115,9 +119,14 @@ class VorbisLibEncoder : public AudioEncoder, public virtual Reporter double resampleRatio; /** - * aflibConverter object for possible resampling + * sample rate converter object for possible resampling */ +#ifdef HAVE_SRC_LIB + SRC_STATE * converter; + SRC_DATA converterData; +#else aflibConverter * converter; +#endif /** * Initialize the object. @@ -137,7 +146,13 @@ class VorbisLibEncoder : public AudioEncoder, public virtual Reporter strip ( void ) throw ( Exception ) { if ( converter ) { +#ifdef HAVE_SRC_LIB + delete [] converterData.data_in; + delete [] converterData.data_out; + src_delete (converter); +#else delete converter; +#endif } } diff --git a/darkice/branches/darkice-macosx/src/aacPlusEncoder.cpp b/darkice/branches/darkice-macosx/src/aacPlusEncoder.cpp index 9b71ccb..c9683b8 100644 --- a/darkice/branches/darkice-macosx/src/aacPlusEncoder.cpp +++ b/darkice/branches/darkice-macosx/src/aacPlusEncoder.cpp @@ -113,7 +113,7 @@ aacPlusEncoder :: open ( void ) writeOffset += IIR21_reSampler[0].delay*MAX_CHANNELS; } - sampleRateAAC = getInSampleRate(); + sampleRateAAC = getOutSampleRate(); config.bitRate = bitrate; config.nChannelsIn=getInChannel(); config.nChannelsOut=nChannelsAAC; @@ -152,6 +152,31 @@ aacPlusEncoder :: open ( void ) inSamples = AACENC_BLOCKSIZE * getInChannel() * 2; + + // initialize the resampling coverter if needed + if ( converter ) { +#ifdef HAVE_SRC_LIB + converterData.input_frames = 4096/((getInBitsPerSample() / 8) * getInChannel()); + converterData.data_in = new float[converterData.input_frames*getInChannel()]; + converterData.output_frames = (int) (converterData.input_frames * resampleRatio + 1); + if ((int) inSamples > getInChannel() * converterData.output_frames) { + resampledOffset = new float[2 * inSamples]; + } else { + resampledOffset = new float[2 * getInChannel() * converterData.input_frames]; + } + converterData.src_ratio = resampleRatio; + converterData.end_of_input = 0; +#else + converter->initialize( resampleRatio, getInChannel()); + //needed 2x(converted input samples) to handle offsets + int outCount = 2 * getInChannel() * (inSamples + 1); + if (resampleRatio > 1) + outCount = (int) (outCount * resampleRatio); + resampledOffset = new short int[outCount]; +#endif + resampledOffsetSize = 0; + } + aacplusOpen = true; reportEvent(10, "bitrate=", bitrate); reportEvent(10, "nChannelsIn", getInChannel()); @@ -181,34 +206,84 @@ aacPlusEncoder :: write ( const void * buf, unsigned int processed = len - (len % sampleSize); unsigned int nSamples = processed / sampleSize; unsigned int samples = (unsigned int) nSamples * channels; + int processedSamples = 0; - - - unsigned int i; - int ch, outSamples, numOutBytes; + if ( converter ) { + unsigned int converted; +#ifdef HAVE_SRC_LIB + src_short_to_float_array ((short *) buf, converterData.data_in, samples); + converterData.input_frames = nSamples; + converterData.data_out = resampledOffset + (resampledOffsetSize * channels); + int srcError = src_process (converter, &converterData); + if (srcError) + throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError)); + converted = converterData.output_frames_gen; +#else + int inCount = nSamples; + short int * shortBuffer = new short int[samples]; + int outCount = (int) (inCount * resampleRatio); + unsigned char * b = (unsigned char*) buf; + Util::conv( bitsPerSample, b, processed, shortBuffer, isInBigEndian()); + converted = converter->resample( inCount, + outCount+1, + shortBuffer, + &resampledOffset[resampledOffsetSize*channels]); + delete[] shortBuffer; +#endif + resampledOffsetSize += converted; - reportEvent(10, "converting short to float"); - short *TimeDataPcm = (short *) buf; - - if(channels == 2) { - for (i=0; i= inSamples/channels) { +#ifdef HAVE_SRC_LIB + short *shortData = new short[inSamples]; + src_float_to_short_array(resampledOffset + (processedSamples * channels), + shortData, inSamples) ; + + encodeAacSamples (shortData, inSamples, channels); + delete [] shortData; +#else + encodeAacSamples (&resampledOffset[processedSamples*channels], inSamples, channels); +#endif + processedSamples+=inSamples/channels; + } + + if (processedSamples && (int) resampledOffsetSize >= processedSamples) { + resampledOffsetSize -= processedSamples; + //move least part of resampled data to beginning + if(resampledOffsetSize) +#ifdef HAVE_SRC_LIB + resampledOffset = (float *) memmove(resampledOffset, &resampledOffset[processedSamples*channels], + resampledOffsetSize*channels*sizeof(float)); +#else + resampledOffset = (short *) memmove(resampledOffset, &resampledOffset[processedSamples*channels], + resampledOffsetSize*sampleSize); +#endif + } } else { - /* using only left channel buffer for mono encoder */ - for (i=0; iwrite(outBuf, numOutBytes+ADTS_HEADER_SIZE); + adts_hdr_up(outBuf, numOutBytes); + sink->write(outBuf, numOutBytes+ADTS_HEADER_SIZE); } writtenSamples=0; - - return samples; -} + return; +} /*------------------------------------------------------------------------------ * Flush the data from the encoder diff --git a/darkice/branches/darkice-macosx/src/aacPlusEncoder.h b/darkice/branches/darkice-macosx/src/aacPlusEncoder.h index dff56c9..f3ff45a 100644 --- a/darkice/branches/darkice-macosx/src/aacPlusEncoder.h +++ b/darkice/branches/darkice-macosx/src/aacPlusEncoder.h @@ -65,6 +65,11 @@ extern "C" { #include "Reporter.h" #include "AudioEncoder.h" #include "Sink.h" +#ifdef HAVE_SRC_LIB +#include +#else +#include "aflibConverter.h" +#endif /* ================================================================ constants */ @@ -95,7 +100,25 @@ class aacPlusEncoder : public AudioEncoder, public virtual Reporter * A flag to indicate if the encoding session is open. */ bool aacplusOpen; - + + /** + * Resample ratio + */ + double resampleRatio; + + /** + * sample rate converter object for possible resampling + */ +#ifdef HAVE_SRC_LIB + SRC_STATE *converter; + SRC_DATA converterData; + float *resampledOffset; +#else + aflibConverter *converter; + short *resampledOffset; +#endif + unsigned int resampledOffsetSize; + /** * The Sink to dump aac+ data to */ @@ -161,7 +184,60 @@ class aacPlusEncoder : public AudioEncoder, public virtual Reporter throw Exception( __FILE__, __LINE__, "input channels and output channels do not match"); } - + + if ( getOutSampleRate() == getInSampleRate() ) { + resampleRatio = 1; + converter = 0; + } else if (getInBitsPerSample() == 16) { + resampleRatio = ( (double) getOutSampleRate() / + (double) getInSampleRate() ); + + // Determine if we can use linear interpolation. + // The inverse of the ratio must be a power of two for linear mode to + // be of sufficient quality. + + bool useLinear = true; + double inverse = 1 / resampleRatio; + int integer = (int) inverse; + + // Check that the inverse of the ratio is an integer + if( integer == inverse ) { + while( useLinear && integer ) { // Loop through the bits + // If the lowest order bit is not the only one set + if( integer & 1 && integer != 1 ) { + // Not a power of two; cannot use linear + useLinear = false; + } else { + // Shift all the bits over and try again + integer >>= 1; + } + } + } else { + useLinear = false; + } + + // If we get here and useLinear is still true, then we have + // a power of two. + + // open the aflibConverter in + // - high quality + // - linear or quadratic (non-linear) based on algorithm + // - not filter interpolation +#ifdef HAVE_SRC_LIB + int srcError = 0; + converter = src_new(useLinear == true ? SRC_LINEAR : SRC_SINC_FASTEST, + getInChannel(), &srcError); + if(srcError) + throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError)); +#else + converter = new aflibConverter( true, useLinear, false); +#endif + } else { + throw Exception( __FILE__, __LINE__, + "specified bits per sample with samplerate conversion not supported", + getInBitsPerSample() ); + } + bitrate = getOutBitrate() * 1000; bandwidth = 0; useParametricStereo = 0; @@ -171,8 +247,7 @@ class aacPlusEncoder : public AudioEncoder, public virtual Reporter writeOffset = INPUT_DELAY*MAX_CHANNELS; writtenSamples = 0; aacEnc = NULL; - hEnvEnc=NULL; - + hEnvEnc=NULL; } /** @@ -183,8 +258,20 @@ class aacPlusEncoder : public AudioEncoder, public virtual Reporter inline void strip ( void ) throw ( Exception ) { + if ( converter ) { +#ifdef HAVE_SRC_LIB + delete [] converterData.data_in; + src_delete (converter); +#else + delete converter; +#endif + delete [] resampledOffset; + } } + void + encodeAacSamples (short *TimeDataPcm, unsigned int samples, int channels) + throw ( Exception ); protected: diff --git a/darkice/branches/darkice-macosx/src/main.cpp b/darkice/branches/darkice-macosx/src/main.cpp index 2cf3d67..d6cdbdf 100644 --- a/darkice/branches/darkice-macosx/src/main.cpp +++ b/darkice/branches/darkice-macosx/src/main.cpp @@ -107,9 +107,11 @@ main ( int res = -1; std::cout << "DarkIce " << VERSION - << " live audio streamer, http://darkice.tyrell.hu/" + << " live audio streamer, http://code.google.com/p/darkice/" << std::endl << "Copyright (c) 2000-2007, Tyrell Hungary, http://tyrell.hu/" + << std::endl + << "Copyright (c) 2008-2009, Akos Maroy and Rafael Diniz" << std::endl << std::endl; try {