CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/HW/Atrac3Standalone.cpp
Views: 1401
#include "SimpleAudioDec.h"1#include "Common/LogReporting.h"2#include "ext/at3_standalone/at3_decoders.h"34inline int16_t clamp16(float f) {5if (f >= 1.0f)6return 32767;7else if (f <= -1.0f)8return -32767;9else10return (int)(f * 32767);11}1213// Uses our standalone AT3/AT3+ decoder derived from FFMPEG14// Test case for ATRAC3: Mega Man Maverick Hunter X, PSP menu sound15class Atrac3Audio : public AudioDecoder {16public:17Atrac3Audio(PSPAudioType audioType, int channels, size_t blockAlign, const uint8_t *extraData, size_t extraDataSize)18: audioType_(audioType), channels_(channels) {19blockAlign_ = (int)blockAlign;20if (audioType == PSP_CODEC_AT3PLUS) {21at3pCtx_ = atrac3p_alloc(channels, &blockAlign_);22if (at3pCtx_) {23codecOpen_ = true;24} else {25ERROR_LOG(Log::ME, "Failed to open atrac3+ context! (channels=%d blockAlign=%d ed=%d)", channels, (int)blockAlign, (int)extraDataSize);26}27} else if (audioType_ == PSP_CODEC_AT3) {28at3Ctx_ = atrac3_alloc(channels, &blockAlign_, extraData, (int)extraDataSize);29if (at3Ctx_) {30codecOpen_ = true;31} else {32ERROR_LOG(Log::ME, "Failed to open atrac3 context! !channels=%d blockAlign=%d ed=%d)", channels, (int)blockAlign, (int)extraDataSize);33}34}35for (int i = 0; i < 2; i++) {36buffers_[i] = new float[4096];37}38}39~Atrac3Audio() {40if (at3Ctx_) {41atrac3_free(at3Ctx_);42}43if (at3pCtx_) {44atrac3p_free(at3pCtx_);45}46for (int i = 0; i < 2; i++) {47delete[] buffers_[i];48}49}5051bool IsOK() const override {52return codecOpen_;53}5455void FlushBuffers() override {56if (at3Ctx_) {57atrac3_flush_buffers(at3Ctx_);58}59if (at3pCtx_) {60atrac3p_flush_buffers(at3pCtx_);61}62}6364bool Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, int outputChannels, int16_t *outbuf, int *outSamples) override {65if (!codecOpen_) {66WARN_LOG_N_TIMES(codecNotOpen, 5, Log::ME, "Atrac3Audio:Decode: Codec not open, not decoding");67if (outSamples)68*outSamples = 0;69if (inbytesConsumed)70*inbytesConsumed = 0;71return false;72}73if (inbytes != blockAlign_ && blockAlign_ != 0) {74WARN_LOG(Log::ME, "Atrac3Audio::Decode: Unexpected block align %d (expected %d). %s", inbytes, blockAlign_, at3pCtx_ ? "Atrac3+" : "Atrac3");75}76blockAlign_ = inbytes;77// We just call the decode function directly without going through the whole packet machinery.78int result;79int nb_samples = 0;80if (audioType_ == PSP_CODEC_AT3PLUS) {81result = atrac3p_decode_frame(at3pCtx_, buffers_, &nb_samples, inbuf, inbytes);82} else {83result = atrac3_decode_frame(at3Ctx_, buffers_, &nb_samples, inbuf, inbytes);84}85if (result < 0) {86if (outSamples) {87*outSamples = 0;88}89return false;90}91if (inbytesConsumed) {92*inbytesConsumed = result;93}94if (outSamples) {95// Allow capping the output samples by setting *outSamples to non-zero.96if (*outSamples != 0) {97nb_samples = std::min(*outSamples, nb_samples);98}99*outSamples = nb_samples;100}101if (nb_samples > 0) {102if (outSamples) {103*outSamples = nb_samples;104}105if (outbuf) {106_dbg_assert_(outputChannels == 1 || outputChannels == 2);107const float *left = buffers_[0];108if (outputChannels == 2) {109// Stereo output, standard.110const float *right = channels_ == 2 ? buffers_[1] : buffers_[0];111for (int i = 0; i < nb_samples; i++) {112outbuf[i * 2] = clamp16(left[i]);113outbuf[i * 2 + 1] = clamp16(right[i]);114}115} else {116// Mono output, just take the left channel.117for (int i = 0; i < nb_samples; i++) {118outbuf[i] = clamp16(left[i]);119}120}121}122}123return true;124}125126void SetChannels(int channels) override {127// Hmm. ignore for now.128}129130PSPAudioType GetAudioType() const override { return audioType_; }131132private:133ATRAC3PContext *at3pCtx_ = nullptr;134ATRAC3Context *at3Ctx_ = nullptr;135136int channels_ = 0;137int blockAlign_ = 0;138139int srcPos_ = 0;140float *buffers_[2]{};141142bool codecOpen_ = false;143144PSPAudioType audioType_;145};146147AudioDecoder *CreateAtrac3Audio(int channels, size_t blockAlign, const uint8_t *extraData, size_t extraDataSize) {148return new Atrac3Audio(PSP_CODEC_AT3, channels, blockAlign, extraData, extraDataSize);149}150AudioDecoder *CreateAtrac3PlusAudio(int channels, size_t blockAlign) {151return new Atrac3Audio(PSP_CODEC_AT3PLUS, channels, blockAlign, nullptr, 0);152}153154155