Patch by Sergiy <piratfm@gmail.com>: implement sample rate conversion for all codecs using libsamplerate, and keeping internal aflibConverter as fallback
This commit is contained in:
parent
542ac4b022
commit
2fa04c0e34
|
@ -270,6 +270,7 @@ dnl link JACK sound server if requested
|
||||||
dnl-----------------------------------------------------------------------------
|
dnl-----------------------------------------------------------------------------
|
||||||
AC_SUBST(JACK_CFLAGS)
|
AC_SUBST(JACK_CFLAGS)
|
||||||
AC_SUBST(JACK_LDFLAGS)
|
AC_SUBST(JACK_LDFLAGS)
|
||||||
|
AC_SUBST(JACK_INCFLAGS)
|
||||||
|
|
||||||
AC_ARG_WITH(jack,
|
AC_ARG_WITH(jack,
|
||||||
[ --with-jack use JACK sound system [yes] ],
|
[ --with-jack use JACK sound system [yes] ],
|
||||||
|
@ -301,6 +302,43 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
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-----------------------------------------------------------------------------
|
||||||
dnl check for MSG_NOSIGNAL for the send() function in libsocket
|
dnl check for MSG_NOSIGNAL for the send() function in libsocket
|
||||||
dnl-----------------------------------------------------------------------------
|
dnl-----------------------------------------------------------------------------
|
||||||
|
|
|
@ -81,7 +81,7 @@ FaacEncoder :: open ( void )
|
||||||
faacEncGetVersion(&faacVersion, &faacCopyright);
|
faacEncGetVersion(&faacVersion, &faacCopyright);
|
||||||
reportEvent(1, "Using faac codec version", faacVersion);
|
reportEvent(1, "Using faac codec version", faacVersion);
|
||||||
|
|
||||||
encoderHandle = faacEncOpen(getInSampleRate(),
|
encoderHandle = faacEncOpen(getOutSampleRate(),
|
||||||
getInChannel(),
|
getInChannel(),
|
||||||
&inputSamples,
|
&inputSamples,
|
||||||
&maxOutputBytes);
|
&maxOutputBytes);
|
||||||
|
@ -107,6 +107,31 @@ FaacEncoder :: open ( void )
|
||||||
"error configuring faac library");
|
"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;
|
faacOpen = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -134,25 +159,89 @@ FaacEncoder :: write ( const void * buf,
|
||||||
int samples = (int) nSamples * channels;
|
int samples = (int) nSamples * channels;
|
||||||
int processedSamples = 0;
|
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;
|
delete[] faacBuf;
|
||||||
|
|
||||||
return processedSamples;
|
// return processedSamples;
|
||||||
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,11 @@
|
||||||
#include "Reporter.h"
|
#include "Reporter.h"
|
||||||
#include "AudioEncoder.h"
|
#include "AudioEncoder.h"
|
||||||
#include "Sink.h"
|
#include "Sink.h"
|
||||||
|
#ifdef HAVE_SRC_LIB
|
||||||
|
#include <samplerate.h>
|
||||||
|
#else
|
||||||
|
#include "aflibConverter.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* ================================================================ constants */
|
/* ================================================================ constants */
|
||||||
|
@ -98,6 +103,24 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter
|
||||||
*/
|
*/
|
||||||
int lowpass;
|
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.
|
* Initialize the object.
|
||||||
*
|
*
|
||||||
|
@ -133,6 +156,58 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter
|
||||||
throw Exception( __FILE__, __LINE__,
|
throw Exception( __FILE__, __LINE__,
|
||||||
"input channels and output channels do not match");
|
"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
|
inline void
|
||||||
strip ( void ) throw ( Exception )
|
strip ( void ) throw ( Exception )
|
||||||
{
|
{
|
||||||
|
if ( converter ) {
|
||||||
|
#ifdef HAVE_SRC_LIB
|
||||||
|
delete [] converterData.data_in;
|
||||||
|
src_delete (converter);
|
||||||
|
#else
|
||||||
|
delete converter;
|
||||||
|
#endif
|
||||||
|
delete [] resampledOffset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,21 @@
|
||||||
bin_PROGRAMS = darkice
|
bin_PROGRAMS = darkice
|
||||||
AM_CXXFLAGS = -O2 -pedantic -Wall @DEBUG_CXXFLAGS@ @PTHREAD_CFLAGS@
|
AM_CXXFLAGS = -O2 -pedantic -Wall @DEBUG_CXXFLAGS@ @PTHREAD_CFLAGS@
|
||||||
@JACK_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@ \
|
LDADD = @PTHREAD_LIBS@ @LAME_LDFLAGS@ @VORBIS_LDFLAGS@ @FAAC_LDFLAGS@ @AACPLUS_LDFLAGS@ @TWOLAME_LDFLAGS@ \
|
||||||
@ALSA_LDFLAGS@ @JACK_LDFLAGS@
|
@ALSA_LDFLAGS@ @JACK_LDFLAGS@ @SRC_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\
|
darkice_SOURCES = AudioEncoder.h\
|
||||||
AudioSource.h\
|
AudioSource.h\
|
||||||
|
@ -40,12 +52,6 @@ darkice_SOURCES = AudioEncoder.h\
|
||||||
FaacEncoder.h\
|
FaacEncoder.h\
|
||||||
aacPlusEncoder.cpp\
|
aacPlusEncoder.cpp\
|
||||||
aacPlusEncoder.h\
|
aacPlusEncoder.h\
|
||||||
aflibDebug.h\
|
|
||||||
aflibDebug.cc\
|
|
||||||
aflibConverter.h\
|
|
||||||
aflibConverter.cc\
|
|
||||||
aflibConverterLargeFilter.h\
|
|
||||||
aflibConverterSmallFilter.h\
|
|
||||||
OssDspSource.cpp\
|
OssDspSource.cpp\
|
||||||
OssDspSource.h\
|
OssDspSource.h\
|
||||||
SerialUlaw.cpp\
|
SerialUlaw.cpp\
|
||||||
|
@ -68,7 +74,14 @@ darkice_SOURCES = AudioEncoder.h\
|
||||||
Reporter.cpp\
|
Reporter.cpp\
|
||||||
AlsaDspSource.h\
|
AlsaDspSource.h\
|
||||||
AlsaDspSource.cpp\
|
AlsaDspSource.cpp\
|
||||||
JackDspSource.h\
|
JackDspSource.h\
|
||||||
JackDspSource.cpp\
|
JackDspSource.cpp\
|
||||||
main.cpp
|
main.cpp \
|
||||||
|
$(AFLIB_SOURCE)
|
||||||
|
|
||||||
|
EXTRA_darkice_SOURCES = aflibDebug.h\
|
||||||
|
aflibDebug.cc\
|
||||||
|
aflibConverter.h\
|
||||||
|
aflibConverter.cc\
|
||||||
|
aflibConverterLargeFilter.h\
|
||||||
|
aflibConverterSmallFilter.h
|
||||||
|
|
|
@ -117,7 +117,15 @@ VorbisLibEncoder :: init ( unsigned int outMaxBitrate )
|
||||||
// - high quality
|
// - high quality
|
||||||
// - linear or quadratic (non-linear) based on algorithm
|
// - linear or quadratic (non-linear) based on algorithm
|
||||||
// - not filter interpolation
|
// - 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);
|
converter = new aflibConverter( true, useLinear, false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
encoderOpen = false;
|
encoderOpen = false;
|
||||||
|
@ -243,7 +251,16 @@ VorbisLibEncoder :: open ( void )
|
||||||
|
|
||||||
// initialize the resampling coverter if needed
|
// initialize the resampling coverter if needed
|
||||||
if ( converter ) {
|
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());
|
converter->initialize( resampleRatio, getInChannel());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
encoderOpen = true;
|
encoderOpen = true;
|
||||||
|
@ -307,13 +324,24 @@ VorbisLibEncoder :: write ( const void * buf,
|
||||||
// resample if needed
|
// resample if needed
|
||||||
int inCount = nSamples;
|
int inCount = nSamples;
|
||||||
int outCount = (int) (inCount * resampleRatio);
|
int outCount = (int) (inCount * resampleRatio);
|
||||||
short int * resampledBuffer = new short int[outCount * channels];
|
short int * resampledBuffer = new short int[(outCount+1)* channels];
|
||||||
int converted;
|
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,
|
converted = converter->resample( inCount,
|
||||||
outCount,
|
outCount,
|
||||||
shortBuffer,
|
shortBuffer,
|
||||||
resampledBuffer );
|
resampledBuffer );
|
||||||
|
#endif
|
||||||
|
|
||||||
vorbisBuffer = vorbis_analysis_buffer( &vorbisDspState,
|
vorbisBuffer = vorbis_analysis_buffer( &vorbisDspState,
|
||||||
converted);
|
converted);
|
||||||
|
|
|
@ -52,7 +52,11 @@
|
||||||
#include "Reporter.h"
|
#include "Reporter.h"
|
||||||
#include "AudioEncoder.h"
|
#include "AudioEncoder.h"
|
||||||
#include "CastSink.h"
|
#include "CastSink.h"
|
||||||
|
#ifdef HAVE_SRC_LIB
|
||||||
|
#include <samplerate.h>
|
||||||
|
#else
|
||||||
#include "aflibConverter.h"
|
#include "aflibConverter.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* ================================================================ constants */
|
/* ================================================================ constants */
|
||||||
|
@ -115,9 +119,14 @@ class VorbisLibEncoder : public AudioEncoder, public virtual Reporter
|
||||||
double resampleRatio;
|
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;
|
aflibConverter * converter;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the object.
|
* Initialize the object.
|
||||||
|
@ -137,7 +146,13 @@ class VorbisLibEncoder : public AudioEncoder, public virtual Reporter
|
||||||
strip ( void ) throw ( Exception )
|
strip ( void ) throw ( Exception )
|
||||||
{
|
{
|
||||||
if ( converter ) {
|
if ( converter ) {
|
||||||
|
#ifdef HAVE_SRC_LIB
|
||||||
|
delete [] converterData.data_in;
|
||||||
|
delete [] converterData.data_out;
|
||||||
|
src_delete (converter);
|
||||||
|
#else
|
||||||
delete converter;
|
delete converter;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ aacPlusEncoder :: open ( void )
|
||||||
writeOffset += IIR21_reSampler[0].delay*MAX_CHANNELS;
|
writeOffset += IIR21_reSampler[0].delay*MAX_CHANNELS;
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleRateAAC = getInSampleRate();
|
sampleRateAAC = getOutSampleRate();
|
||||||
config.bitRate = bitrate;
|
config.bitRate = bitrate;
|
||||||
config.nChannelsIn=getInChannel();
|
config.nChannelsIn=getInChannel();
|
||||||
config.nChannelsOut=nChannelsAAC;
|
config.nChannelsOut=nChannelsAAC;
|
||||||
|
@ -152,6 +152,31 @@ aacPlusEncoder :: open ( void )
|
||||||
|
|
||||||
inSamples = AACENC_BLOCKSIZE * getInChannel() * 2;
|
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;
|
aacplusOpen = true;
|
||||||
reportEvent(10, "bitrate=", bitrate);
|
reportEvent(10, "bitrate=", bitrate);
|
||||||
reportEvent(10, "nChannelsIn", getInChannel());
|
reportEvent(10, "nChannelsIn", getInChannel());
|
||||||
|
@ -181,34 +206,84 @@ aacPlusEncoder :: write ( const void * buf,
|
||||||
unsigned int processed = len - (len % sampleSize);
|
unsigned int processed = len - (len % sampleSize);
|
||||||
unsigned int nSamples = processed / sampleSize;
|
unsigned int nSamples = processed / sampleSize;
|
||||||
unsigned int samples = (unsigned int) nSamples * channels;
|
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");
|
// encode samples (if enough)
|
||||||
short *TimeDataPcm = (short *) buf;
|
while(resampledOffsetSize - processedSamples >= inSamples/channels) {
|
||||||
|
#ifdef HAVE_SRC_LIB
|
||||||
if(channels == 2) {
|
short *shortData = new short[inSamples];
|
||||||
for (i=0; i<samples; i++)
|
src_float_to_short_array(resampledOffset + (processedSamples * channels),
|
||||||
inBuf[i+writeOffset+writtenSamples] = (float) TimeDataPcm[i];
|
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 {
|
} else {
|
||||||
/* using only left channel buffer for mono encoder */
|
encodeAacSamples ((short *) buf, samples, channels);
|
||||||
for (i=0; i<samples; i++)
|
|
||||||
inBuf[writeOffset+2*writtenSamples+2*i] = (float) TimeDataPcm[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
aacPlusEncoder :: encodeAacSamples (short *TimeDataPcm, unsigned int samples, int channels)
|
||||||
|
throw ( Exception )
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
int ch, outSamples, numOutBytes;
|
||||||
|
|
||||||
|
for (i=0; i<samples; i++)
|
||||||
|
inBuf[(2/channels)*i+writeOffset+writtenSamples] = (float) TimeDataPcm[i];
|
||||||
|
|
||||||
writtenSamples+=samples;
|
writtenSamples+=samples;
|
||||||
reportEvent(10, "writtenSamples", writtenSamples);
|
|
||||||
|
|
||||||
if (writtenSamples < inSamples)
|
if (writtenSamples < inSamples)
|
||||||
return samples;
|
return;
|
||||||
|
|
||||||
/* encode one SBR frame */
|
/* encode one SBR frame */
|
||||||
reportEvent(10, "encode one SBR frame");
|
|
||||||
EnvEncodeFrame( hEnvEnc,
|
EnvEncodeFrame( hEnvEnc,
|
||||||
inBuf + envReadOffset,
|
inBuf + envReadOffset,
|
||||||
inBuf + coreWriteOffset,
|
inBuf + coreWriteOffset,
|
||||||
|
@ -216,11 +291,8 @@ aacPlusEncoder :: write ( const void * buf,
|
||||||
&numAncDataBytes,
|
&numAncDataBytes,
|
||||||
ancDataBytes);
|
ancDataBytes);
|
||||||
|
|
||||||
reportEvent(10, "numAncDataBytes=", numAncDataBytes);
|
|
||||||
|
|
||||||
/* 2:1 downsampling for AAC core */
|
/* 2:1 downsampling for AAC core */
|
||||||
if (!useParametricStereo) {
|
if (!useParametricStereo) {
|
||||||
reportEvent(10, "2:1 downsampling for AAC core");
|
|
||||||
for( ch=0; ch<nChannelsAAC; ch++ )
|
for( ch=0; ch<nChannelsAAC; ch++ )
|
||||||
IIR21_Downsample( &(IIR21_reSampler[ch]),
|
IIR21_Downsample( &(IIR21_reSampler[ch]),
|
||||||
inBuf + writeOffset+ch,
|
inBuf + writeOffset+ch,
|
||||||
|
@ -229,12 +301,9 @@ aacPlusEncoder :: write ( const void * buf,
|
||||||
inBuf+ch,
|
inBuf+ch,
|
||||||
&outSamples,
|
&outSamples,
|
||||||
MAX_CHANNELS);
|
MAX_CHANNELS);
|
||||||
|
|
||||||
reportEvent(10, "outSamples=", outSamples);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* encode one AAC frame */
|
/* encode one AAC frame */
|
||||||
reportEvent(10, "encode one AAC frame");
|
|
||||||
AacEncEncode( aacEnc,
|
AacEncEncode( aacEnc,
|
||||||
inBuf,
|
inBuf,
|
||||||
useParametricStereo ? 1 : MAX_CHANNELS, /* stride (step) */
|
useParametricStereo ? 1 : MAX_CHANNELS, /* stride (step) */
|
||||||
|
@ -250,16 +319,14 @@ aacPlusEncoder :: write ( const void * buf,
|
||||||
|
|
||||||
/* Write one frame of encoded audio */
|
/* Write one frame of encoded audio */
|
||||||
if (numOutBytes) {
|
if (numOutBytes) {
|
||||||
reportEvent(10, "Write one frame of encoded audio:", numOutBytes+ADTS_HEADER_SIZE);
|
adts_hdr_up(outBuf, numOutBytes);
|
||||||
adts_hdr_up(outBuf, numOutBytes);
|
sink->write(outBuf, numOutBytes+ADTS_HEADER_SIZE);
|
||||||
sink->write(outBuf, numOutBytes+ADTS_HEADER_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writtenSamples=0;
|
writtenSamples=0;
|
||||||
|
|
||||||
return samples;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
* Flush the data from the encoder
|
* Flush the data from the encoder
|
||||||
|
|
|
@ -65,6 +65,11 @@ extern "C" {
|
||||||
#include "Reporter.h"
|
#include "Reporter.h"
|
||||||
#include "AudioEncoder.h"
|
#include "AudioEncoder.h"
|
||||||
#include "Sink.h"
|
#include "Sink.h"
|
||||||
|
#ifdef HAVE_SRC_LIB
|
||||||
|
#include <samplerate.h>
|
||||||
|
#else
|
||||||
|
#include "aflibConverter.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* ================================================================ constants */
|
/* ================================================================ constants */
|
||||||
|
@ -95,7 +100,25 @@ class aacPlusEncoder : public AudioEncoder, public virtual Reporter
|
||||||
* A flag to indicate if the encoding session is open.
|
* A flag to indicate if the encoding session is open.
|
||||||
*/
|
*/
|
||||||
bool aacplusOpen;
|
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
|
* The Sink to dump aac+ data to
|
||||||
*/
|
*/
|
||||||
|
@ -161,7 +184,60 @@ class aacPlusEncoder : public AudioEncoder, public virtual Reporter
|
||||||
throw Exception( __FILE__, __LINE__,
|
throw Exception( __FILE__, __LINE__,
|
||||||
"input channels and output channels do not match");
|
"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;
|
bitrate = getOutBitrate() * 1000;
|
||||||
bandwidth = 0;
|
bandwidth = 0;
|
||||||
useParametricStereo = 0;
|
useParametricStereo = 0;
|
||||||
|
@ -171,8 +247,7 @@ class aacPlusEncoder : public AudioEncoder, public virtual Reporter
|
||||||
writeOffset = INPUT_DELAY*MAX_CHANNELS;
|
writeOffset = INPUT_DELAY*MAX_CHANNELS;
|
||||||
writtenSamples = 0;
|
writtenSamples = 0;
|
||||||
aacEnc = NULL;
|
aacEnc = NULL;
|
||||||
hEnvEnc=NULL;
|
hEnvEnc=NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -183,8 +258,20 @@ class aacPlusEncoder : public AudioEncoder, public virtual Reporter
|
||||||
inline void
|
inline void
|
||||||
strip ( void ) throw ( Exception )
|
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:
|
protected:
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue