aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2024-08-19 23:41:16 +0200
committerDaniil Cherednik <dan.cherednik@gmail.com>2024-08-19 23:41:16 +0200
commit88deefbaecdbf6cfd9e74826b3962dc607c44f78 (patch)
tree077e950aa4ba6df65fc0e179e9e469906f2063d9
parenta62963044e8d9230375c2f8b7022fa017616fe9f (diff)
downloadatracdenc-88deefbaecdbf6cfd9e74826b3962dc607c44f78.tar.gz
Possibility to "look ahead" during encoding
-rw-r--r--src/atrac/at3p/at3p.cpp42
-rw-r--r--src/atrac/at3p/at3p_gha.cpp26
-rw-r--r--src/atrac/at3p/at3p_gha.h4
-rw-r--r--src/atrac/at3p/at3p_gha_ut.cpp7
-rw-r--r--src/atrac1denc.cpp4
-rw-r--r--src/atrac3denc.cpp2
-rw-r--r--src/pcmengin.h36
-rw-r--r--src/wav.h15
8 files changed, 94 insertions, 42 deletions
diff --git a/src/atrac/at3p/at3p.cpp b/src/atrac/at3p/at3p.cpp
index 5069354..62e51ae 100644
--- a/src/atrac/at3p/at3p.cpp
+++ b/src/atrac/at3p/at3p.cpp
@@ -23,6 +23,7 @@
#include "at3p_bitstream.h"
#include "at3p_gha.h"
+#include <cassert>
#include <vector>
using std::vector;
@@ -34,10 +35,10 @@ public:
TImpl(ICompressedOutput* out, int channels)
: BitStream(out, 2048)
, ChannelCtx(channels)
- , GhaProcessor(MakeGhaProcessor0(ChannelCtx[0].SubbandsBuf, channels == 2 ? ChannelCtx[1].SubbandsBuf : nullptr))
+ , GhaProcessor(MakeGhaProcessor0(channels == 2))
{}
- void EncodeFrame(const TFloat* data, int channels);
+ TPCMEngine<float>::EProcessResult EncodeFrame(const TFloat* data, int channels);
private:
struct TChannelCtx {
TChannelCtx()
@@ -49,7 +50,11 @@ private:
}
at3plus_pqf_a_ctx_t PqfCtx;
- TFloat SubbandsBuf[TAt3PEnc::NumSamples];
+
+ TFloat* NextBuf = Buf1;
+ TFloat* CurBuf = nullptr;
+ TFloat Buf1[TAt3PEnc::NumSamples];
+ TFloat Buf2[TAt3PEnc::NumSamples];
};
TAt3PBitStream BitStream;
@@ -57,21 +62,44 @@ private:
std::unique_ptr<IGhaProcessor> GhaProcessor;
};
-void TAt3PEnc::TImpl::
+TPCMEngine<float>::EProcessResult TAt3PEnc::TImpl::
EncodeFrame(const TFloat* data, int channels)
{
+ int needMore = 0;
for (int ch = 0; ch < channels; ch++) {
float src[TAt3PEnc::NumSamples];
for (size_t i = 0; i < NumSamples; ++i) {
src[i] = data[i * channels + ch];
}
- at3plus_pqf_do_analyse(ChannelCtx[ch].PqfCtx, src, ChannelCtx[ch].SubbandsBuf);
+ at3plus_pqf_do_analyse(ChannelCtx[ch].PqfCtx, src, ChannelCtx[ch].NextBuf);
+ if (ChannelCtx[ch].CurBuf == nullptr) {
+ assert(ChannelCtx[ch].NextBuf == ChannelCtx[ch].Buf1);
+ ChannelCtx[ch].CurBuf = ChannelCtx[ch].Buf2;
+ std::swap(ChannelCtx[ch].NextBuf, ChannelCtx[ch].CurBuf);
+ needMore++;
+ }
+ }
+
+ if (needMore == channels) {
+ return TPCMEngine<TFloat>::EProcessResult::LOOK_AHEAD;
}
- auto tonalBlock = GhaProcessor->DoAnalize();
+ assert(needMore == 0);
+
+ const float* b1 = ChannelCtx[0].CurBuf;
+ const float* b2 = (channels == 2) ? ChannelCtx[1].CurBuf : nullptr;
+
+ auto tonalBlock = GhaProcessor->DoAnalize(b1, b2);
+
BitStream.WriteFrame(channels, tonalBlock);
+
+ for (int ch = 0; ch < channels; ch++) {
+ std::swap(ChannelCtx[ch].NextBuf, ChannelCtx[ch].CurBuf);
+ }
+
+ return TPCMEngine<TFloat>::EProcessResult::PROCESSED;
}
TAt3PEnc::TAt3PEnc(TCompressedOutputPtr&& out, int channels)
@@ -84,7 +112,7 @@ TPCMEngine<TFloat>::TProcessLambda TAt3PEnc::GetLambda() {
Impl.reset(new TImpl(Out.get(), Channels));
return [this](TFloat* data, const TPCMEngine<TFloat>::ProcessMeta&) {
- Impl->EncodeFrame(data, Channels);
+ return Impl->EncodeFrame(data, Channels);
};
}
diff --git a/src/atrac/at3p/at3p_gha.cpp b/src/atrac/at3p/at3p_gha.cpp
index ea73dc3..0a45f61 100644
--- a/src/atrac/at3p/at3p_gha.cpp
+++ b/src/atrac/at3p/at3p_gha.cpp
@@ -79,11 +79,10 @@ class TGhaProcessor : public IGhaProcessor {
};
public:
- TGhaProcessor(float* b1, float* b2)
- : B1(b1)
- , B2(b2)
- , LibGhaCtx(gha_create_ctx(128))
+ TGhaProcessor(bool stereo)
+ : LibGhaCtx(gha_create_ctx(128))
, AmpSfTab(CreateAmpSfTab())
+ , Stereo(stereo)
{
FillSubbandAth(&SubbandAth[0]);
}
@@ -93,7 +92,7 @@ public:
gha_free_ctx(LibGhaCtx);
}
- const TAt3PGhaData* DoAnalize() override;
+ const TAt3PGhaData* DoAnalize(const float* b1, const float* b2) override;
private:
static void FillSubbandAth(float* out) {
const auto ath = CalcATH(16 * 1024, 44100);
@@ -125,25 +124,20 @@ private:
pair<uint32_t, uint32_t> FindPos(const float* src, const float* analized, float magn, uint32_t freqIdx) const;
void FillResultBuf(const vector<TChannelData>& data);
- bool IsStereo() const {
- return (bool)B2;
- }
-
- float* const B1;
- float* const B2;
gha_ctx_t LibGhaCtx;
const TAmpSfTab AmpSfTab;
float SubbandAth[SUBBANDS];
TAt3PGhaData ResultBuf;
+ const bool Stereo;
};
-const TAt3PGhaData* TGhaProcessor::DoAnalize()
+const TAt3PGhaData* TGhaProcessor::DoAnalize(const float* b1, const float* b2)
{
- vector<TChannelData> data((size_t)IsStereo() + 1);
+ vector<TChannelData> data((size_t)Stereo + 1);
bool progress[2] = {false};
for (size_t ch = 0; ch < data.size(); ch++) {
- const float* b = (ch == 0) ? B1 : B2;
+ const float* b = (ch == 0) ? b1 : b2;
data[ch].SrcBuf = b;
memcpy(&data[ch].Buf[0], b, sizeof(float) * CHANNEL_BUF_SZ);
}
@@ -494,9 +488,9 @@ uint32_t TGhaProcessor::AmplitudeToSf(float amp)
} // namespace
-std::unique_ptr<IGhaProcessor> MakeGhaProcessor0(float* b1, float* b2)
+std::unique_ptr<IGhaProcessor> MakeGhaProcessor0(bool stereo)
{
- return std::unique_ptr<TGhaProcessor>(new TGhaProcessor(b1, b2));
+ return std::unique_ptr<TGhaProcessor>(new TGhaProcessor(stereo));
}
} // namespace NAtracDEnc
diff --git a/src/atrac/at3p/at3p_gha.h b/src/atrac/at3p/at3p_gha.h
index 35785a6..5fef68d 100644
--- a/src/atrac/at3p/at3p_gha.h
+++ b/src/atrac/at3p/at3p_gha.h
@@ -61,10 +61,10 @@ struct TAt3PGhaData {
class IGhaProcessor {
public:
virtual ~IGhaProcessor() {}
- virtual const TAt3PGhaData* DoAnalize() = 0;
+ virtual const TAt3PGhaData* DoAnalize(const float* b1, const float* b2) = 0;
};
-std::unique_ptr<IGhaProcessor> MakeGhaProcessor0(float* b1, float* b2);
+std::unique_ptr<IGhaProcessor> MakeGhaProcessor0(bool stereo);
} // namespace NAtracDEnc
diff --git a/src/atrac/at3p/at3p_gha_ut.cpp b/src/atrac/at3p/at3p_gha_ut.cpp
index 6554a41..a65cb35 100644
--- a/src/atrac/at3p/at3p_gha_ut.cpp
+++ b/src/atrac/at3p/at3p_gha_ut.cpp
@@ -45,10 +45,11 @@ static const TAt3PGhaData __attribute__ ((noinline)) GenAndRunGha(vector<TTestPa
}
}
- auto processor = MakeGhaProcessor0(buf1.data(), buf2.empty() ? nullptr : buf2.data());
+ auto processor = MakeGhaProcessor0(!p2.empty());
+ const float* b1 = buf1.data();
+ const float* b2 = buf2.empty() ? nullptr : buf2.data();
-
- return *(processor->DoAnalize());
+ return *(processor->DoAnalize(b1, b2));
}
static class TDumper {
diff --git a/src/atrac1denc.cpp b/src/atrac1denc.cpp
index d622007..48f1864 100644
--- a/src/atrac1denc.cpp
+++ b/src/atrac1denc.cpp
@@ -157,7 +157,7 @@ TPCMEngine<TFloat>::TProcessLambda TAtrac1Decoder::GetLambda() {
data[i * srcChannels + channel] = sum[i];
}
}
-
+ return TPCMEngine<TFloat>::EProcessResult::PROCESSED;
};
}
@@ -199,6 +199,8 @@ TPCMEngine<TFloat>::TProcessLambda TAtrac1Encoder::GetLambda() {
Mdct(&specs[0], &PcmBufLow[channel][0], &PcmBufMid[channel][0], &PcmBufHi[channel][0], blockSize);
bitAlloc[channel]->Write(Scaler.ScaleFrame(specs, blockSize), blockSize);
}
+
+ return TPCMEngine<TFloat>::EProcessResult::PROCESSED;
};
}
diff --git a/src/atrac3denc.cpp b/src/atrac3denc.cpp
index a07c11e..b1f81d1 100644
--- a/src/atrac3denc.cpp
+++ b/src/atrac3denc.cpp
@@ -342,6 +342,8 @@ TPCMEngine<TFloat>::TProcessLambda TAtrac3Encoder::GetLambda()
}
bitStreamWriter->WriteSoundUnit(SingleChannelElements);
+
+ return TPCMEngine<TFloat>::EProcessResult::PROCESSED;
};
}
diff --git a/src/pcmengin.h b/src/pcmengin.h
index dcf7d44..5971421 100644
--- a/src/pcmengin.h
+++ b/src/pcmengin.h
@@ -28,6 +28,9 @@
#include <assert.h>
#include <string.h>
+class TNoDataToRead : public std::exception {
+};
+
class TPCMBufferTooSmall : public std::exception {
virtual const char* what() const throw() {
return "PCM buffer too small";
@@ -102,7 +105,7 @@ class IPCMWriter {
template <class T>
class IPCMReader {
public:
- virtual void Read(TPCMBuffer<T>& data , const uint32_t size) const = 0;
+ virtual bool Read(TPCMBuffer<T>& data , const uint32_t size) const = 0;
IPCMReader() {};
virtual ~IPCMReader() {};
};
@@ -120,6 +123,7 @@ private:
TWriterPtr Writer;
TReaderPtr Reader;
uint64_t Processed = 0;
+ uint64_t ToDrain = 0;
public:
TPCMEngine(uint16_t bufSize, uint8_t numChannels)
: Buffer(bufSize, numChannels) {
@@ -141,23 +145,45 @@ public:
, Reader(std::move(reader)) {
}
- typedef std::function<void(T* data, const ProcessMeta& meta)> TProcessLambda;
+ enum class EProcessResult {
+ LOOK_AHEAD, // need more data to process
+ PROCESSED,
+ };
+
+ typedef std::function<EProcessResult(T* data, const ProcessMeta& meta)> TProcessLambda;
uint64_t ApplyProcess(size_t step, TProcessLambda lambda) {
if (step > Buffer.Size()) {
throw TPCMBufferTooSmall();
}
+ bool drain = false;
if (Reader) {
const uint32_t sizeToRead = Buffer.Size();
- Reader->Read(Buffer, sizeToRead);
+ const bool ok = Reader->Read(Buffer, sizeToRead);
+ if (!ok) {
+ if (ToDrain) {
+ drain = true;
+ } else {
+ throw TNoDataToRead();
+ }
+ }
}
size_t lastPos = 0;
ProcessMeta meta = {Buffer.Channels()};
+
for (size_t i = 0; i + step <= Buffer.Size(); i+=step) {
- lambda(Buffer[i], meta);
- lastPos = i + step;
+ auto res = lambda(Buffer[i], meta);
+ if (res == EProcessResult::PROCESSED) {
+ lastPos += step;
+ if (drain && ToDrain--) {
+ break;
+ }
+ } else {
+ assert(!drain);
+ ToDrain++;
+ }
}
assert(lastPos == Buffer.Size());
diff --git a/src/wav.h b/src/wav.h
index e3daf7d..55e6d38 100644
--- a/src/wav.h
+++ b/src/wav.h
@@ -28,19 +28,16 @@
class TFileAlreadyExists : public std::exception {
};
-class TNoDataToRead : public std::exception {
-};
-
template<class T>
class TWavPcmReader : public IPCMReader<T> {
public:
- typedef std::function<void(TPCMBuffer<T>& data, const uint32_t size)> TLambda;
+ typedef std::function<bool(TPCMBuffer<T>& data, const uint32_t size)> TLambda;
TLambda Lambda;
TWavPcmReader(TLambda lambda)
: Lambda(lambda)
{}
- void Read(TPCMBuffer<T>& data , const uint32_t size) const override {
- Lambda(data, size);
+ bool Read(TPCMBuffer<T>& data , const uint32_t size) const override {
+ return Lambda(data, size);
}
};
@@ -93,17 +90,19 @@ typedef std::unique_ptr<TWav> TWavPtr;
template<class T>
IPCMReader<T>* TWav::GetPCMReader() const {
- return new TWavPcmReader<T>([this](TPCMBuffer<T>& data, const uint32_t size) {
+ return new TWavPcmReader<T>([this](TPCMBuffer<T>& data, const uint32_t size) -> bool {
if (data.Channels() != Impl->GetChannelsNum())
throw TWrongReadBuffer();
size_t read;
if ((read = Impl->Read(data, size)) != size) {
if (!read)
- throw TNoDataToRead();
+ return false;
data.Zero(read, size - read);
}
+
+ return true;
});
}