ARM, API, other fixes

This commit is contained in:
Christian R. Helmrich 2020-06-22 21:00:11 +02:00
parent fd32557d3e
commit 12bb57155a
8 changed files with 88 additions and 69 deletions

View File

@ -94,17 +94,17 @@ to exhale's standard input pipe (stdin), such as foobar2000.
In a terminal, change to exhale's `bin` subdirectory and then enter
`./exhale` (on Linux and MacOS) or `exhaleApp.exe` (on Windows)
`./exhale` (on Linux and MacOS) or `exhale.exe` (on Windows)
to print out usage information. As an example, the following command
`exhaleApp.exe 5 C:\Music\Input.wav C:\Music\Output.m4a`
`exhale.exe 5 C:\Music\Input.wav C:\Music\Output.m4a`
converts file Input.wav to file Output.m4a at roughly 128 kbit/s (if
the input signal is two-channel stereo) and in xHE-AAC audio format.
Note that, when calling the exhale application with a path (such as,
e.g., `bin/exhale` or `bin\exhaleApp.exe`), but specifying the input
or output file without any path (e.g., `Input.wav`), those files are
e.g., `bin/exhale` or `bin\exhale.exe`), but specifying the input or
output file without a file path (e.g., `Input.wav`), those files are
assumed to be located in the application path (here, `bin`). Use the
"dot prefix" to indicate files in the *current* directory instead of
the application directory (here, `./Input.wav` or `.\Input.wav`).
@ -119,9 +119,9 @@ to be converted, rightclick on one of them, and select `Convert` ->
the window content changed, on `Add New`. Then select `Custom` under
"Encoder" and enter the following information:
- *Encoder file:* exhaleApp.exe (possibly including path to it)
- *Encoder file:* exhale.exe (including path to the executable)
- *Extension:* m4a
- *Parameters:* # %d (where number is the bit-rate mode, 1...9)
- *Parameters:* # %d (where # is the bit-rate mode, i.e. 1...9)
- *Format is:* lossy
- *Highest BPS mode supported:* 24 (or 32, doesn't matter much)
- *Encoder name:* xHE-AAC (exhale)
@ -129,7 +129,8 @@ the window content changed, on `Add New`. Then select `Custom` under
- *Settings:* CVBR mode # (where # equals that in *Parameters*)
Then click on `OK` and on `Back` and, in the first "Converter Setup"
window, on `Other` and ensure all "Transfer..." boxes are unchecked.
window, on `Other` and ensure the "Transfer..." box for the class of
input metadata that you wish to copy to the output files is checked.
Now set the destination settings as desired and click on `Convert`.

View File

@ -11,7 +11,7 @@
#ifndef _EXHALE_DECL_H_
#define _EXHALE_DECL_H_
#include <stdint.h> // for (u)int8_t, (u)int16_t, (u)int32_t, (u)int64_t
#include <stdint.h> /* for (u)int8_t, (u)int16_t, (u)int32_t, (u)int64_t */
#if defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64)
# ifdef EXHALE_DYN_LINK
@ -23,31 +23,43 @@
# define EXHALE_DECL
#endif
#ifdef __cplusplus
struct ExhaleEncAPI
{
// initializer
/* initializer */
virtual unsigned initEncoder (unsigned char* const audioConfigBuffer, uint32_t* const audioConfigBytes = nullptr) = 0;
// lookahead encoder
/* lookahead encoder */
virtual unsigned encodeLookahead () = 0;
// frame encoder
/* frame encoder */
virtual unsigned encodeFrame () = 0;
// destructor
/* destructor */
virtual ~ExhaleEncAPI () { }
};
// C constructor
extern "C" EXHALE_DECL ExhaleEncAPI* exhaleCreate (int32_t* const, unsigned char* const, const unsigned, const unsigned,
const unsigned, const unsigned, const unsigned, const bool, const bool);
// C destructor
extern "C" EXHALE_DECL unsigned exhaleDelete (ExhaleEncAPI*);
extern "C"
{
#else /* C, not C++ */
struct ExhaleEncAPI; /* opaque type */
typedef struct ExhaleEncAPI ExhaleEncAPI;
#endif
// C initializer
extern "C" EXHALE_DECL unsigned exhaleInitEncoder (ExhaleEncAPI*, unsigned char* const, uint32_t* const);
/* C constructor */
EXHALE_DECL ExhaleEncAPI* exhaleCreate (int32_t* const, unsigned char* const, const unsigned, const unsigned,
const unsigned, const unsigned, const unsigned, const bool, const bool);
/* C destructor */
EXHALE_DECL unsigned exhaleDelete (ExhaleEncAPI*);
// C lookahead encoder
extern "C" EXHALE_DECL unsigned exhaleEncodeLookahead (ExhaleEncAPI*);
/* C initializer */
EXHALE_DECL unsigned exhaleInitEncoder (ExhaleEncAPI*, unsigned char* const, uint32_t* const);
// C frame encoder
extern "C" EXHALE_DECL unsigned exhaleEncodeFrame (ExhaleEncAPI*);
/* C lookahead encoder */
EXHALE_DECL unsigned exhaleEncodeLookahead (ExhaleEncAPI*);
#endif // _EXHALE_DECL_H_
/* C frame encoder */
EXHALE_DECL unsigned exhaleEncodeFrame (ExhaleEncAPI*);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* _EXHALE_DECL_H_ */

View File

@ -145,7 +145,7 @@ unsigned BitStreamWriter::writeChannelWiseTnsData (const TnsData& tnsData, const
{
const int8_t* coeff = tnsData.coeff[n + f];
unsigned coefBits = (tnsData.coeffResLow[n] ? 3 : 4);
char coefMaxValue = (tnsData.coeffResLow[n] ? 2 : 4);
int8_t coefMaxValue = (tnsData.coeffResLow[n] ? 2 : 4);
bool dontCompress = false;
m_auBitStream.write (tnsData.filterDownward[n + f] ? 1 : 0, 1);

View File

@ -340,7 +340,7 @@ static const uint8_t numberOfChannels[USAC_MAX_NUM_ELCONFIGS] = {0, 1, 2, 3, 4,
static inline unsigned toNumChannels (const USAC_CCI chConfigurationIndex)
{
return numberOfChannels[__max (0, (char) chConfigurationIndex)];
return numberOfChannels[__max (0, (signed char) chConfigurationIndex)];
}
// ISO/IEC 23003-3, Table 68
@ -918,7 +918,9 @@ unsigned ExhaleEncoder::psychBitAllocation () // perceptual bit-allocation via s
const bool eightShorts = (coreConfig.icsInfoCurr[ch].windowSequence == EIGHT_SHORT);
const bool saveBitRate = (meanSpecFlat[ci] > SCHAR_MAX && samplingRate >= 32000 + (unsigned) m_bitRateMode * 12000);
const uint8_t maxSfbCh = grpData.sfbsPerGroup;
#if !RESTRICT_TO_AAC
const uint8_t numSwbCh = (eightShorts ? m_numSwbShort : m_numSwbLong);
#endif
const uint16_t mSfmFac = UCHAR_MAX - ((9u * meanSpecFlat[ci]) >> 4);
uint32_t* stepSizes = &sfbStepSizes[ci * m_numSwbShort * NUM_WINDOW_GROUPS];

View File

@ -28,7 +28,7 @@
#define WIN_SCALE double (1 << 23)
// channelConfigurationIndex setup
typedef enum USAC_CCI : char
typedef enum USAC_CCI : signed char
{
CCI_UNDEF = -1,
CCI_CONF = 0, // channel-to-speaker mapping defined in UsacChannelConfig() (not to be used here!)
@ -71,7 +71,7 @@ private:
EntropyCoder m_entropyCoder[USAC_MAX_NUM_CHANNELS];
uint32_t m_frameCount;
USAC_CCFL m_frameLength;
char m_frequencyIdx;
int8_t m_frequencyIdx;
bool m_indepFlag; // usacIndependencyFlag bit
uint32_t m_indepPeriod;
LinearPredictor m_linPredictor; // for pre-roll est, TNS
@ -153,52 +153,56 @@ public:
}; // ExhaleEncoder
#ifdef EXHALE_DYN_LINK
// C constructor
extern "C" EXHALE_DECL ExhaleEncAPI* exhaleCreate (int32_t* const inputPcmData, unsigned char* const outputAuData,
const unsigned sampleRate = 44100, const unsigned numChannels = 2,
const unsigned frameLength = 1024, const unsigned indepPeriod = 45,
const unsigned varBitRateMode = 3, const bool useNoiseFilling = true,
const bool useEcodisExt = false)
extern "C"
{
return new ExhaleEncoder (inputPcmData, outputAuData, sampleRate, numChannels, frameLength, indepPeriod, varBitRateMode
// C constructor
EXHALE_DECL ExhaleEncAPI* exhaleCreate (int32_t* const inputPcmData, unsigned char* const outputAuData,
const unsigned sampleRate = 44100, const unsigned numChannels = 2,
const unsigned frameLength = 1024, const unsigned indepPeriod = 45,
const unsigned varBitRateMode = 3, const bool useNoiseFilling = true,
const bool useEcodisExt = false)
{
return reinterpret_cast<ExhaleEncAPI*> (new ExhaleEncoder (inputPcmData, outputAuData, sampleRate, numChannels, frameLength, indepPeriod, varBitRateMode
#if !RESTRICT_TO_AAC
, useNoiseFilling, useEcodisExt
, useNoiseFilling, useEcodisExt
#endif
);
));
}
// C destructor
extern "C" EXHALE_DECL unsigned exhaleDelete (ExhaleEncAPI* exhaleEnc)
EXHALE_DECL unsigned exhaleDelete (ExhaleEncAPI* exhaleEnc)
{
if (exhaleEnc != NULL) { delete exhaleEnc; return 0; }
if (exhaleEnc != NULL) { delete reinterpret_cast<ExhaleEncoder*> (exhaleEnc); return 0; }
return USHRT_MAX; // error
}
// C initializer
extern "C" EXHALE_DECL unsigned exhaleInitEncoder (ExhaleEncAPI* exhaleEnc, unsigned char* const audioConfigBuffer,
uint32_t* const audioConfigBytes = nullptr)
EXHALE_DECL unsigned exhaleInitEncoder (ExhaleEncAPI* exhaleEnc, unsigned char* const audioConfigBuffer,
uint32_t* const audioConfigBytes = nullptr)
{
if (exhaleEnc != NULL) return exhaleEnc->initEncoder (audioConfigBuffer, audioConfigBytes);
if (exhaleEnc != NULL) return reinterpret_cast<ExhaleEncoder*> (exhaleEnc)->initEncoder (audioConfigBuffer, audioConfigBytes);
return USHRT_MAX; // error
}
// C lookahead encoder
extern "C" EXHALE_DECL unsigned exhaleEncodeLookahead (ExhaleEncAPI* exhaleEnc)
EXHALE_DECL unsigned exhaleEncodeLookahead (ExhaleEncAPI* exhaleEnc)
{
if (exhaleEnc != NULL) return exhaleEnc->encodeLookahead ();
if (exhaleEnc != NULL) return reinterpret_cast<ExhaleEncoder*> (exhaleEnc)->encodeLookahead ();
return USHRT_MAX; // error
}
// C frame encoder
extern "C" EXHALE_DECL unsigned exhaleEncodeFrame (ExhaleEncAPI* exhaleEnc)
EXHALE_DECL unsigned exhaleEncodeFrame (ExhaleEncAPI* exhaleEnc)
{
if (exhaleEnc != NULL) return exhaleEnc->encodeFrame ();
if (exhaleEnc != NULL) return reinterpret_cast<ExhaleEncoder*> (exhaleEnc)->encodeFrame ();
return USHRT_MAX; // error
}
} // extern "C"
#endif // EXHALE_DYN_LINK
#endif // _EXHALE_ENC_H_

View File

@ -53,11 +53,11 @@ static const unsigned allowedSamplingRates[USAC_NUM_SAMPLE_RATES] = {
};
// public sampling rate functions
char toSamplingFrequencyIndex (const unsigned samplingRate)
int8_t toSamplingFrequencyIndex (const unsigned samplingRate)
{
for (char i = 0; i < AAC_NUM_SAMPLE_RATES; i++)
for (int8_t i = 0; i < AAC_NUM_SAMPLE_RATES; i++)
{
if (samplingRate == allowedSamplingRates[(int) i]) // AAC rate
if (samplingRate == allowedSamplingRates[i]) // (HE-)AAC rate
{
return i;
}
@ -71,7 +71,7 @@ char toSamplingFrequencyIndex (const unsigned samplingRate)
return -1; // no index found
}
unsigned toSamplingRate (const char samplingFrequencyIndex)
unsigned toSamplingRate (const int8_t samplingFrequencyIndex)
{
#if RESTRICT_TO_AAC
if ((samplingFrequencyIndex < 0) || (samplingFrequencyIndex >= AAC_NUM_SAMPLE_RATES))

View File

@ -172,7 +172,7 @@ const uint8_t eightTimesSqrt256Minus[256] = {
const uint8_t oneTwentyEightOver[14] = {0, 128, 64, 43, 32, 26, 22, 19, 16, 15, 13, 12, 11, 10};
// public sampling rate functions
char toSamplingFrequencyIndex (const unsigned samplingRate);
unsigned toSamplingRate (const char samplingFrequencyIndex);
int8_t toSamplingFrequencyIndex (const unsigned samplingRate);
unsigned toSamplingRate (const int8_t samplingFrequencyIndex);
#endif // _EXHALE_LIB_PCH_H_

View File

@ -24,7 +24,7 @@ static const short tnsQuantCoeff4[17/*2^4+1*/] = { // = round (2^11 * sin (x * p
static const short* tnsQuantCoeff[2/*coefRes*/] = {tnsQuantCoeff3, tnsQuantCoeff4};
// ISO/IEC 14496-3, Sec. 4.6.9.3, 3-bit
static const char tnsQuantIndex3[SCHAR_MAX + 1] = { // = round (asin (x / 64) * (x < 0 ? 9 : 7) / pi)
static const int8_t tnsQuantIndex3[SCHAR_MAX + 1] = { // = round (asin (x / 64) * (x < 0 ? 9 : 7) / pi)
-4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -32,31 +32,31 @@ static const char tnsQuantIndex3[SCHAR_MAX + 1] = { // = round (asin (x / 64) *
};
// ISO/IEC 14496-3, Sec. 4.6.9.3, 4-bit
static const char tnsQuantIndex4[SCHAR_MAX + 1] = { // = round (asin (x / 64) * (x < 0 ? 17 : 15) / pi)
static const int8_t tnsQuantIndex4[SCHAR_MAX + 1] = { // = round (asin (x / 64) * (x < 0 ? 17 : 15) / pi)
-8, -7, -7, -7, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3,
-3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7
};
static const char* tnsQuantIndex[2/*coefRes*/] = {tnsQuantIndex3, tnsQuantIndex4};
static const int8_t* tnsQuantIndex[2/*coefRes*/] = {tnsQuantIndex3, tnsQuantIndex4};
// static helper functions
static int quantizeParCorCoeffs (const short* const parCorCoeffs, const uint16_t nCoeffs, const short bitDepth, int8_t* const quantCoeffs,
const bool lowRes)
{
const short bitShift = bitDepth - 7;
const unsigned tabIdx = (lowRes ? 0 : 1);
const char tabOffset = 4 << tabIdx;
const short* coeffTab = tnsQuantCoeff[tabIdx];
const char* indexTab = tnsQuantIndex[tabIdx];
const short bitShift = bitDepth - 7;
const unsigned tabIdx = (lowRes ? 0 : 1);
const int8_t tabOffset = 4 << tabIdx;
const short* coeffTab = tnsQuantCoeff[tabIdx];
const int8_t* indexTab = tnsQuantIndex[tabIdx];
int dist0, dist1, distTotal = 0;
for (uint16_t s = 0; s < nCoeffs; s++)
{
const short coeff = (bitShift < 0 ? parCorCoeffs[s] << -bitShift : parCorCoeffs[s] >> bitShift);
const char coeff1 = indexTab[coeff + 1 + (SCHAR_MAX >> 1)];
const char coeff0 = (coeff1 <= -tabOffset ? coeff1 : coeff1 - 1);
const short coeff = (bitShift < 0 ? parCorCoeffs[s] << -bitShift : parCorCoeffs[s] >> bitShift);
const int8_t coeff1 = indexTab[coeff + 1 + (SCHAR_MAX >> 1)];
const int8_t coeff0 = (coeff1 <= -tabOffset ? coeff1 : coeff1 - 1);
dist0 = (int) coeffTab[coeff0 + tabOffset] - parCorCoeffs[s];
dist0 *= dist0;
@ -249,7 +249,7 @@ uint8_t LinearPredictor::calcOptTnsCoeffs (short* const parCorCoeffs, int8_t* co
if ((parCorCoeffs == nullptr) || (quantCoeffs == nullptr) || (maxOrder == 0) || (maxOrder > MAX_PREDICTION_ORDER) || (parCorCoeffBitDepth < 2) || (bitShift < 0))
{
if (quantCoeffs) memset (quantCoeffs, 0, order * sizeof (char));
if (quantCoeffs) memset (quantCoeffs, 0, order * sizeof (int8_t));
return 0; // invalid input arguments error
}
@ -269,7 +269,7 @@ uint8_t LinearPredictor::calcOptTnsCoeffs (short* const parCorCoeffs, int8_t* co
if (predGain < 41 + (tonality >> 3)) // 1.5 dB
{
memset (quantCoeffs, 0, order * sizeof (char));
memset (quantCoeffs, 0, order * sizeof (int8_t));
return 0; // LPC prediction gain is too low
}
@ -307,7 +307,7 @@ uint8_t LinearPredictor::calcOptTnsCoeffs (short* const parCorCoeffs, int8_t* co
{
// low-res quantizer yields lower distortion
*lowCoeffRes = true;
memcpy (quantCoeffs, m_tempBuf, order * sizeof (char));
memcpy (quantCoeffs, m_tempBuf, order * sizeof (int8_t));
}
for (; order > 0; order--) // return opt order
@ -385,9 +385,9 @@ unsigned LinearPredictor::parCorToLpCoeffs (const short* const parCorCoeffs, con
unsigned LinearPredictor::quantTnsToLpCoeffs (const int8_t* const quantTnsCoeffs, const uint16_t nCoeffs, const bool lowCoeffRes,
short* const parCorCoeffs, short* const lpCoeffs)
{
const unsigned tabIdx = (lowCoeffRes ? 0 : 1);
const char tabOffset = 4 << tabIdx;
const short* coeffTab = tnsQuantCoeff[tabIdx];
const unsigned tabIdx = (lowCoeffRes ? 0 : 1);
const int8_t tabOffset = 4 << tabIdx;
const short* coeffTab = tnsQuantCoeff[tabIdx];
if ((quantTnsCoeffs == nullptr) || (parCorCoeffs == nullptr) || (lpCoeffs == nullptr) || (nCoeffs == 0) || (nCoeffs > MAX_PREDICTION_ORDER))
{