diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2024-08-19 23:41:16 +0200 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2024-08-19 23:41:16 +0200 |
commit | 88deefbaecdbf6cfd9e74826b3962dc607c44f78 (patch) | |
tree | 077e950aa4ba6df65fc0e179e9e469906f2063d9 | |
parent | a62963044e8d9230375c2f8b7022fa017616fe9f (diff) | |
download | atracdenc-88deefbaecdbf6cfd9e74826b3962dc607c44f78.tar.gz |
Possibility to "look ahead" during encoding
-rw-r--r-- | src/atrac/at3p/at3p.cpp | 42 | ||||
-rw-r--r-- | src/atrac/at3p/at3p_gha.cpp | 26 | ||||
-rw-r--r-- | src/atrac/at3p/at3p_gha.h | 4 | ||||
-rw-r--r-- | src/atrac/at3p/at3p_gha_ut.cpp | 7 | ||||
-rw-r--r-- | src/atrac1denc.cpp | 4 | ||||
-rw-r--r-- | src/atrac3denc.cpp | 2 | ||||
-rw-r--r-- | src/pcmengin.h | 36 | ||||
-rw-r--r-- | src/wav.h | 15 |
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()); @@ -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; }); } |