mirror of https://gitlab.com/ecodis/exhale.git
clean WAVE reader
This commit is contained in:
parent
b17f659c35
commit
14cdd94f9e
|
@ -1,11 +1,11 @@
|
|||
/* basicWavReader.cpp - source file for class with basic WAVE file reading capability
|
||||
* written by C. R. Helmrich, last modified in 2021 - see License.htm for legal notices
|
||||
* written by C. R. Helmrich, last modified in 2024 - see License.htm for legal notices
|
||||
*
|
||||
* The copyright in this software is being made available under the exhale Copyright License
|
||||
* and comes with ABSOLUTELY NO WARRANTY. This software may be subject to other third-
|
||||
* party rights, including patent rights. No such rights are granted under this License.
|
||||
*
|
||||
* Copyright (c) 2018-2021 Christian R. Helmrich, project ecodis. All rights reserved.
|
||||
* Copyright (c) 2018-2024 Christian R. Helmrich, project ecodis. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "exhaleAppPch.h"
|
||||
|
@ -25,7 +25,7 @@ static int64_t fourBytesToLength (const uint8_t* b, const int64_t lengthLimit)
|
|||
|
||||
return __min (lengthLimit, chunkLength); // for security
|
||||
}
|
||||
#if BWR_BUFFERED_READ
|
||||
|
||||
static inline unsigned getFrames (const int fileHandle, void* dataBuf, const unsigned frameCount,
|
||||
const bool roundSize, const unsigned bytesPerFrame)
|
||||
{
|
||||
|
@ -40,7 +40,8 @@ static inline unsigned getFrames (const int fileHandle, void* dataBuf, const uns
|
|||
}
|
||||
return bytesRead / bytesPerFrame; // num of frames read
|
||||
}
|
||||
#endif
|
||||
|
||||
static const uint8_t allowedChMask[7] = {0x00, 0x04, 0xC0, 0x00, 0x00, 0x37, 0xCF};
|
||||
|
||||
// private reader functions
|
||||
bool BasicWavReader::readRiffHeader ()
|
||||
|
@ -70,15 +71,18 @@ bool BasicWavReader::readFormatChunk ()
|
|||
if (m_bytesRead != m_chunkLength) return false; // error
|
||||
m_bytesRemaining -= m_bytesRead;
|
||||
|
||||
m_waveChannels = (unsigned (b[3]) << 8) | b[2]; // <64k
|
||||
if ((b[0] == 0xFE) && (b[1] == 0xFF) && (m_chunkLength == CHUNK_FORMAT_MAX) && (b[16] == CHUNK_FORMAT_MAX - CHUNK_FORMAT_SIZE - 2) &&
|
||||
(b[17] == 0) && (b[18] == b[14]) && ((b[19] | b[25] | b[26] | b[27] | b[28] | b[29] | b[31] | b[33] | b[34] | b[36]) == 0))
|
||||
(b[17] == 0) && (b[18] <= b[14]) && ((b[19] | b[25] | b[26] | b[27] | b[28] | b[29] | b[31] | b[33] | b[34] | b[36]) == 0))
|
||||
{
|
||||
m_waveDataType = WAV_TYPE (b[24]-1); // extensible WAV
|
||||
if ((b[18] + 8u <= b[14]) || (b[20] != 0 && b[20] != (m_waveChannels < 7 ? allowedChMask[m_waveChannels] : 0) &&
|
||||
b[20] != (1u << __min (8u, m_waveChannels)) - 1u)) return false; // no unusual or nonstandard channel configs
|
||||
b[14] = b[18];
|
||||
b[ 1] = 0;
|
||||
}
|
||||
else
|
||||
m_waveDataType = WAV_TYPE (b[0]-1); // 1: PCM, 3: float
|
||||
m_waveChannels = b[2]; // only 1, 2, ..., 63 supported
|
||||
m_waveFrameRate = reverseFourBytes (&b[4]); // frames/s
|
||||
m_waveBitRate = reverseFourBytes (&b[8]) * 8; // bit/s
|
||||
m_waveFrameSize = b[12]; // bytes/s divided by frames/s
|
||||
|
@ -133,7 +137,6 @@ bool BasicWavReader::seekToChunkTag (uint8_t* const buf, const uint32_t tagID)
|
|||
unsigned BasicWavReader::readDataFloat16 (const int fileHandle, int32_t* frameBuf, const unsigned frameCount,
|
||||
const unsigned chanCount, void* tempBuf)
|
||||
{
|
||||
#if BWR_BUFFERED_READ
|
||||
const unsigned rest = ((frameCount >> (BWR_READ_FRACT - 1)) << (BWR_READ_FRACT - 1)) < frameCount ? 1 : 0;
|
||||
unsigned framesRead = 0;
|
||||
|
||||
|
@ -159,30 +162,11 @@ unsigned BasicWavReader::readDataFloat16 (const int fileHandle, int32_t* frameBu
|
|||
memset (frameBuf, 0, (frameCount - framesRead) * chanCount * sizeof (int32_t));
|
||||
}
|
||||
return framesRead;
|
||||
#else
|
||||
unsigned bytesRead = 0;
|
||||
|
||||
for (unsigned i = frameCount * chanCount; i > 0; i--)
|
||||
{
|
||||
int16_t i16 = 0;
|
||||
|
||||
bytesRead += _READ (fileHandle, &i16, 2);
|
||||
|
||||
const int32_t e = ((i16 & 0x7C00) >> 10) - 18; // exp.
|
||||
// an exponent e <= -12 will lead to zero-quantization
|
||||
*frameBuf = int32_t (e < 0 ? (1024 + (i16 & 0x03FF) + (1 << (-1 - e)) /*rounding offset*/) >> -e
|
||||
: (e > 12 ? MAX_VALUE_AUDIO24 /*inf*/ : (1024 + (i16 & 0x03FF)) << e));
|
||||
if ((i16 & 0x8000) != 0) *frameBuf *= -1; // neg. sign
|
||||
frameBuf++;
|
||||
}
|
||||
return bytesRead / (chanCount * 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned BasicWavReader::readDataFloat32 (const int fileHandle, int32_t* frameBuf, const unsigned frameCount,
|
||||
const unsigned chanCount, void* tempBuf)
|
||||
{
|
||||
#if BWR_BUFFERED_READ
|
||||
const unsigned rest = ((frameCount >> (BWR_READ_FRACT - 1)) << (BWR_READ_FRACT - 1)) < frameCount ? 1 : 0;
|
||||
unsigned framesRead = 0;
|
||||
|
||||
|
@ -208,28 +192,11 @@ unsigned BasicWavReader::readDataFloat32 (const int fileHandle, int32_t* frameBu
|
|||
memset (frameBuf, 0, (frameCount - framesRead) * chanCount * sizeof (int32_t));
|
||||
}
|
||||
return framesRead;
|
||||
#else
|
||||
unsigned bytesRead = 0;
|
||||
|
||||
for (unsigned i = frameCount * chanCount; i > 0; i--)
|
||||
{
|
||||
float f32 = 0.0;
|
||||
|
||||
bytesRead += _READ (fileHandle, &f32, 4);
|
||||
*frameBuf = int32_t (f32 * (1 << 23) + (f32 < 0.0 ? -0.5 : 0.5)); // * 2^23 with rounding
|
||||
if (*frameBuf < MIN_VALUE_AUDIO24) *frameBuf = MIN_VALUE_AUDIO24;
|
||||
else
|
||||
if (*frameBuf > MAX_VALUE_AUDIO24) *frameBuf = MAX_VALUE_AUDIO24;
|
||||
frameBuf++;
|
||||
}
|
||||
return bytesRead / (chanCount * 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned BasicWavReader::readDataLnPcm08 (const int fileHandle, int32_t* frameBuf, const unsigned frameCount,
|
||||
const unsigned chanCount, void* tempBuf)
|
||||
{
|
||||
#if BWR_BUFFERED_READ
|
||||
const unsigned rest = ((frameCount >> (BWR_READ_FRACT - 1)) << (BWR_READ_FRACT - 1)) < frameCount ? 1 : 0;
|
||||
unsigned framesRead = 0;
|
||||
|
||||
|
@ -249,24 +216,11 @@ unsigned BasicWavReader::readDataLnPcm08 (const int fileHandle, int32_t* frameBu
|
|||
memset (frameBuf, 0, (frameCount - framesRead) * chanCount * sizeof (int32_t));
|
||||
}
|
||||
return framesRead;
|
||||
#else
|
||||
unsigned bytesRead = 0;
|
||||
|
||||
for (unsigned i = frameCount * chanCount; i > 0; i--)
|
||||
{
|
||||
uint8_t ui8 = 128;
|
||||
|
||||
bytesRead += _READ (fileHandle, &ui8, 1);
|
||||
*(frameBuf++) = ((int32_t) ui8 - 128) << 16; // * 2^16
|
||||
}
|
||||
return bytesRead / chanCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned BasicWavReader::readDataLnPcm16 (const int fileHandle, int32_t* frameBuf, const unsigned frameCount,
|
||||
const unsigned chanCount, void* tempBuf)
|
||||
{
|
||||
#if BWR_BUFFERED_READ
|
||||
const unsigned rest = ((frameCount >> (BWR_READ_FRACT - 1)) << (BWR_READ_FRACT - 1)) < frameCount ? 1 : 0;
|
||||
unsigned framesRead = 0;
|
||||
|
||||
|
@ -286,24 +240,11 @@ unsigned BasicWavReader::readDataLnPcm16 (const int fileHandle, int32_t* frameBu
|
|||
memset (frameBuf, 0, (frameCount - framesRead) * chanCount * sizeof (int32_t));
|
||||
}
|
||||
return framesRead;
|
||||
#else
|
||||
unsigned bytesRead = 0;
|
||||
|
||||
for (unsigned i = frameCount * chanCount; i > 0; i--)
|
||||
{
|
||||
int16_t i16 = 0;
|
||||
|
||||
bytesRead += _READ (fileHandle, &i16, 2);
|
||||
*(frameBuf++) = (int32_t) i16 << 8; // * 2^8
|
||||
}
|
||||
return bytesRead / (chanCount * 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned BasicWavReader::readDataLnPcm24 (const int fileHandle, int32_t* frameBuf, const unsigned frameCount,
|
||||
const unsigned chanCount, void* tempBuf)
|
||||
{
|
||||
#if BWR_BUFFERED_READ
|
||||
const unsigned rest = ((frameCount >> (BWR_READ_FRACT - 1)) << (BWR_READ_FRACT - 1)) < frameCount ? 1 : 0;
|
||||
unsigned framesRead = 0;
|
||||
|
||||
|
@ -325,24 +266,11 @@ unsigned BasicWavReader::readDataLnPcm24 (const int fileHandle, int32_t* frameBu
|
|||
memset (frameBuf, 0, (frameCount - framesRead) * chanCount * sizeof (int32_t));
|
||||
}
|
||||
return framesRead;
|
||||
#else
|
||||
unsigned bytesRead = 0;
|
||||
|
||||
for (unsigned i = frameCount * chanCount; i > 0; i--)
|
||||
{
|
||||
int32_t i24 = 0;
|
||||
|
||||
bytesRead += _READ (fileHandle, &i24, 3);
|
||||
*(frameBuf++) = (i24 > MAX_VALUE_AUDIO24 ? i24 + 2 * MIN_VALUE_AUDIO24 : i24);
|
||||
}
|
||||
return bytesRead / (chanCount * 3);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned BasicWavReader::readDataLnPcm32 (const int fileHandle, int32_t* frameBuf, const unsigned frameCount,
|
||||
const unsigned chanCount, void* tempBuf)
|
||||
{
|
||||
#if BWR_BUFFERED_READ
|
||||
const unsigned rest = ((frameCount >> (BWR_READ_FRACT - 1)) << (BWR_READ_FRACT - 1)) < frameCount ? 1 : 0;
|
||||
unsigned framesRead = 0;
|
||||
|
||||
|
@ -364,18 +292,6 @@ unsigned BasicWavReader::readDataLnPcm32 (const int fileHandle, int32_t* frameBu
|
|||
memset (frameBuf, 0, (frameCount - framesRead) * chanCount * sizeof (int32_t));
|
||||
}
|
||||
return framesRead;
|
||||
#else
|
||||
unsigned bytesRead = 0;
|
||||
|
||||
for (unsigned i = frameCount * chanCount; i > 0; i--)
|
||||
{
|
||||
int32_t i24 = 0;
|
||||
bytesRead += _READ (fileHandle, &i24, 4);
|
||||
i24 = ((i24 >> 1) + (1 << 6)) >> 7; // * 2^-8 with rounding, overflow-safe
|
||||
*(frameBuf++) = __min (MAX_VALUE_AUDIO24, i24);
|
||||
}
|
||||
return bytesRead / (chanCount * 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
// public functions
|
||||
|
@ -414,6 +330,13 @@ unsigned BasicWavReader::open (const int wavFileHandle, const uint16_t maxFrameR
|
|||
}
|
||||
m_frameLimit = maxFrameRead;
|
||||
|
||||
if (m_waveChMpegMap > 0)
|
||||
{
|
||||
if (m_waveChannels < 3) m_waveChMpegMap = 0; // mono and stereo inputs do not need to be remapped
|
||||
else
|
||||
if (m_waveChannels == 6) m_waveChMpegMap++; // when m_waveChMpegMap is even, relocate LFE channel
|
||||
}
|
||||
|
||||
// ready to read audio data: initialize byte counter
|
||||
if (m_bytesRemaining > m_chunkLength)
|
||||
{
|
||||
|
@ -463,6 +386,32 @@ unsigned BasicWavReader::read (int32_t* const frameBuf, const uint16_t frameCoun
|
|||
|
||||
if (framesRead < framesTotal) eaExtrapolate (frameBuf, framesRead, framesTotal, m_waveChannels); // fade-out, for gapless playback on more content
|
||||
|
||||
if (m_waveChMpegMap > 0)
|
||||
{
|
||||
int32_t* sampBuf = frameBuf; // remap multichannel PCM input to MPEG-4 or D channel configuration
|
||||
|
||||
if (m_waveChMpegMap & 1)
|
||||
{
|
||||
for (unsigned i = framesTotal; i > 0; i--, sampBuf += m_waveChannels)
|
||||
{
|
||||
int32_t c = sampBuf[2];
|
||||
sampBuf[2] = sampBuf[1];
|
||||
sampBuf[1] = sampBuf[0];
|
||||
sampBuf[0] = c; // cntr.
|
||||
}
|
||||
}
|
||||
else // m_waveChMpegMap even
|
||||
{
|
||||
for (unsigned i = framesTotal; i > 0; i--, sampBuf += m_waveChannels)
|
||||
{
|
||||
int32_t c = sampBuf[2], /*int32*/ l = sampBuf[3];
|
||||
sampBuf[2] = sampBuf[1]; sampBuf[3] = sampBuf[4];
|
||||
sampBuf[1] = sampBuf[0]; sampBuf[4] = sampBuf[5];
|
||||
sampBuf[0] = c; /*cntr.*/ sampBuf[5] = l; // LFE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return framesRead;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/* basicWavReader.h - header file for class with basic WAVE file reading capability
|
||||
* written by C. R. Helmrich, last modified in 2020 - see License.htm for legal notices
|
||||
* written by C. R. Helmrich, last modified in 2024 - see License.htm for legal notices
|
||||
*
|
||||
* The copyright in this software is being made available under the exhale Copyright License
|
||||
* and comes with ABSOLUTELY NO WARRANTY. This software may be subject to other third-
|
||||
* party rights, including patent rights. No such rights are granted under this License.
|
||||
*
|
||||
* Copyright (c) 2018-2021 Christian R. Helmrich, project ecodis. All rights reserved.
|
||||
* Copyright (c) 2018-2024 Christian R. Helmrich, project ecodis. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _BASIC_WAV_READER_H_
|
||||
|
@ -14,7 +14,6 @@
|
|||
#include "exhaleAppPch.h"
|
||||
|
||||
// constant data sizes & limits
|
||||
#define BWR_BUFFERED_READ 1 // faster reader
|
||||
#define BWR_READ_FRACT 5 // 2^-READ_FRACT
|
||||
#define CHUNK_FORMAT_MAX 40
|
||||
#define CHUNK_FORMAT_SIZE 16
|
||||
|
@ -24,7 +23,7 @@
|
|||
#define MIN_VALUE_AUDIO24 -8388608 // (1 << 23) *-1
|
||||
|
||||
// WAVE data format definitions
|
||||
typedef enum WAV_TYPE
|
||||
typedef enum WAV_TYPE : int16_t
|
||||
{
|
||||
WAV_PCM = 0, // linear PCM
|
||||
WAV_ADPCM, // ADPCM
|
||||
|
@ -51,6 +50,7 @@ private:
|
|||
unsigned m_waveBitDepth;
|
||||
unsigned m_waveBitRate;
|
||||
unsigned m_waveChannels;
|
||||
uint16_t m_waveChMpegMap;
|
||||
WAV_TYPE m_waveDataType;
|
||||
unsigned m_waveFrameRate;
|
||||
unsigned m_waveFrameSize;
|
||||
|
@ -76,7 +76,7 @@ private:
|
|||
public:
|
||||
|
||||
// constructor
|
||||
BasicWavReader () { m_fileHandle = -1; reset (); }
|
||||
BasicWavReader (const int mpegChCfg) { m_fileHandle = -1; m_waveChMpegMap = (!mpegChCfg ? 0 : 1); reset (); }
|
||||
// destructor
|
||||
~BasicWavReader() { if (m_byteBuffer != nullptr) free ((void*) m_byteBuffer); }
|
||||
// public functions
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* exhaleApp.cpp - source file with main() routine for exhale application executable
|
||||
* written by C. R. Helmrich, last modified in 2023 - see License.htm for legal notices
|
||||
* written by C. R. Helmrich, last modified in 2024 - see License.htm for legal notices
|
||||
*
|
||||
* The copyright in this software is being made available under the exhale Copyright License
|
||||
* and comes with ABSOLUTELY NO WARRANTY. This software may be subject to other third-
|
||||
|
@ -325,7 +325,7 @@ int main (const int argc, char* argv[])
|
|||
if (argc <= 0) return argc; // for safety
|
||||
|
||||
const bool readStdin = (argc == 3 || argc == 5);
|
||||
BasicWavReader wavReader;
|
||||
BasicWavReader wavReader(1);
|
||||
int32_t* inPcmData = nullptr; // 24-bit WAVE audio input buffer
|
||||
int32_t* inPcmRsmp = nullptr; // temporary buffer for resampler
|
||||
uint8_t* outAuData = nullptr; // access unit (AU) output buffer
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* exhaleApp.rc - resource file for exhale application binaries compiled under Windows
|
||||
* written by C. R. Helmrich, last modified in 2023 - see License.htm for legal notices
|
||||
* written by C. R. Helmrich, last modified in 2024 - see License.htm for legal notices
|
||||
*
|
||||
* The copyright in this software is being made available under the exhale Copyright License
|
||||
* and comes with ABSOLUTELY NO WARRANTY. This software may be subject to other third-
|
||||
|
@ -13,7 +13,7 @@
|
|||
|
||||
0 ICON "exhaleApp.ico"
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,2,1,0
|
||||
FILEVERSION 1,2,1,1
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* exhaleEnc.cpp - source file for class providing Extended HE-AAC encoding capability
|
||||
* written by C. R. Helmrich, last modified in 2023 - see License.htm for legal notices
|
||||
* written by C. R. Helmrich, last modified in 2024 - see License.htm for legal notices
|
||||
* C API corrected and API compilation extended by J. Regan in 2022, see merge request 8
|
||||
*
|
||||
* The copyright in this software is being made available under the exhale Copyright License
|
||||
|
@ -828,9 +828,14 @@ unsigned ExhaleEncoder::psychBitAllocation () // perceptual bit-allocation via s
|
|||
const int16_t chanCorrSign = (coreConfig.stereoConfig & 2 ? -1 : 1);
|
||||
const uint16_t nSamplesMax = (useMaxBandwidth ? nSamplesInFrame : swbOffsetsL[m_swbTableIdx][__min (m_numSwbLong, maxSfbLong + 1)]);
|
||||
const bool reducedStrength = (coreConfig.tnsActive && (m_bitRateMode > 0)) || (m_bitRateMode >= 5);
|
||||
const uint8_t steppFadeLen = (eightShorts0 ? 4 : (reducedStrength ? 32 : 64));
|
||||
const uint8_t steppFadeOff = ((m_bitRateMode + 77000 / samplingRate) & 6) << (eightShorts0 ? 2 : 5);
|
||||
#if BA_MORE_CBR
|
||||
const uint8_t steppFadeLen = (eightShorts0 ? 4 : (reducedStrength || (m_bitRateMode == 0) ? 32 : 64));
|
||||
const int64_t steppWeightI = __min (64, m_perCorrHCurr[el] - 128) >> ((eightShorts0 && (m_bitRateMode > 0)) || reducedStrength ? 1 : 0); // crosstalk * 128
|
||||
#else
|
||||
const uint8_t steppFadeLen = (eightShorts0 ? 4 : (reducedStrength ? 32 : 64));
|
||||
const int64_t steppWeightI = __min (64, m_perCorrHCurr[el] - 128) >> (eightShorts0 || reducedStrength ? 1 : 0); // crosstalk * 128
|
||||
#endif
|
||||
const int64_t steppWeightD = 128 - steppWeightI; // decrement, (1 - crosstalk) * 128
|
||||
|
||||
for (uint16_t n = 0, gr = 0; gr < coreConfig.groupingData[0].numWindowGroups; gr++)
|
||||
|
@ -1465,6 +1470,9 @@ unsigned ExhaleEncoder::spectralProcessing () // complete ics_info(), calc TNS
|
|||
|
||||
m_perCorrHCurr[el] = (uint8_t) __max (prevPerCorr - allowedDiff, __min (prevPerCorr + allowedDiff, currPerCorr));
|
||||
}
|
||||
#if BA_MORE_CBR
|
||||
if (m_bitRateMode == 0) m_perCorrHCurr[el] = uint8_t (85 + (2 * s) / 3); // stronger
|
||||
#endif
|
||||
m_perCorrLCurr[el] = coreConfig.stereoDataCurr[0];
|
||||
|
||||
if ((int) s == steAnaStats * -1) coreConfig.stereoConfig = 2; // 2: S>M, pred_dir=1
|
||||
|
|
Loading…
Reference in New Issue