diff --git a/Core/HLE/AtracCtx.cpp b/Core/HLE/AtracCtx.cpp index 8d5d668b19..0a9dffce8d 100644 --- a/Core/HLE/AtracCtx.cpp +++ b/Core/HLE/AtracCtx.cpp @@ -831,7 +831,7 @@ void Atrac::SeekToSample(int sample) { const u32 start = off - track_.dataOff < backfill ? track_.dataOff : off - backfill; for (u32 pos = start; pos < off; pos += track_.bytesPerFrame) { - decoder_->Decode(BufferStart() + pos, track_.bytesPerFrame, nullptr, nullptr, nullptr); + decoder_->Decode(BufferStart() + pos, track_.bytesPerFrame, nullptr, 2, nullptr, nullptr); } } @@ -933,7 +933,7 @@ u32 Atrac::DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, i uint8_t *indata = BufferStart() + off; int bytesConsumed = 0; int outBytes = 0; - if (!decoder_->Decode(indata, track_.bytesPerFrame, &bytesConsumed, outbuf, &outBytes)) { + if (!decoder_->Decode(indata, track_.bytesPerFrame, &bytesConsumed, outputChannels_, outbuf, &outBytes)) { // Decode failed. *SamplesNum = 0; *finish = 1; diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 13344f209a..192c099184 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -948,7 +948,7 @@ static int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesCo int bytesConsumed = 0; int bytesWritten = 0; - atrac->GetDecoder()->Decode(srcp, atrac->GetTrack().BytesPerFrame(), &bytesConsumed, outp, &bytesWritten); + atrac->GetDecoder()->Decode(srcp, atrac->GetTrack().BytesPerFrame(), &bytesConsumed, 2, outp, &bytesWritten); *srcConsumed = bytesConsumed; *outWritten = bytesWritten; diff --git a/Core/HLE/sceAudiocodec.cpp b/Core/HLE/sceAudiocodec.cpp index 9934aa1d56..7361468063 100644 --- a/Core/HLE/sceAudiocodec.cpp +++ b/Core/HLE/sceAudiocodec.cpp @@ -119,7 +119,7 @@ static int sceAudiocodecDecode(u32 ctxPtr, int codec) { auto ctx = PSPPointer::Create(ctxPtr); // On stack, no need to allocate. // Decode audio int inDataConsumed = 0; - decoder->Decode(Memory::GetPointer(ctx->inDataPtr), ctx->inDataSize, &inDataConsumed, Memory::GetPointerWrite(ctx->outDataPtr), &outbytes); + decoder->Decode(Memory::GetPointer(ctx->inDataPtr), ctx->inDataSize, &inDataConsumed, 2, Memory::GetPointerWrite(ctx->outDataPtr), &outbytes); } DEBUG_LOG(ME, "sceAudiocodecDec(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec)); return 0; diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index cdd8f09964..1b337e800f 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -744,7 +744,7 @@ static u32 sceMp3LowLevelDecode(u32 mp3, u32 sourceAddr, u32 sourceBytesConsumed int outpcmbytes = 0; int inbytesConsumed = 0; - ctx->decoder->Decode(inbuff, 4096, &inbytesConsumed, outbuff, &outpcmbytes); + ctx->decoder->Decode(inbuff, 4096, &inbytesConsumed, 2, outbuff, &outpcmbytes); NotifyMemInfo(MemBlockFlags::WRITE, samplesAddr, outpcmbytes, "Mp3LowLevelDecode"); Memory::Write_U32(inbytesConsumed, sourceBytesConsumedAddr); diff --git a/Core/HW/Atrac3Standalone.cpp b/Core/HW/Atrac3Standalone.cpp index b109effd44..63845bbc37 100644 --- a/Core/HW/Atrac3Standalone.cpp +++ b/Core/HW/Atrac3Standalone.cpp @@ -15,7 +15,8 @@ inline int16_t clamp16(float f) { // Test case for ATRAC3: Mega Man Maverick Hunter X, PSP menu sound class Atrac3Audio : public AudioDecoder { public: - Atrac3Audio(PSPAudioType audioType, int channels, size_t blockAlign, const uint8_t *extraData, size_t extraDataSize) : audioType_(audioType) { + Atrac3Audio(PSPAudioType audioType, int channels, size_t blockAlign, const uint8_t *extraData, size_t extraDataSize) + : audioType_(audioType), channels_(channels) { blockAlign_ = (int)blockAlign; if (audioType == PSP_CODEC_AT3PLUS) { at3pCtx_ = atrac3p_alloc(channels, &blockAlign_); @@ -55,7 +56,7 @@ public: } } - bool Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, uint8_t *outbuf, int *outbytes) override { + bool Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, int outputChannels, uint8_t *outbuf, int *outbytes) override { if (!codecOpen_) { _dbg_assert_(false); } @@ -84,12 +85,20 @@ public: *outbytes = nb_samples * 2 * 2; } if (outbuf) { - // Convert frame to outbuf. TODO: Very SIMDable, though hardly hot. - for (int channel = 0; channel < 2; channel++) { - int16_t *output = (int16_t *)outbuf; + _dbg_assert_(outputChannels == 1 || outputChannels == 2); + int16_t *output = (int16_t *)outbuf; + const float *left = buffers_[0]; + if (outputChannels == 2) { + // Stereo output, standard. + const float *right = channels_ == 2 ? buffers_[1] : buffers_[0]; for (int i = 0; i < nb_samples; i++) { - output[i * 2] = clamp16(buffers_[0][i]); - output[i * 2 + 1] = clamp16(buffers_[1][i]); + output[i * 2] = clamp16(left[i]); + output[i * 2 + 1] = clamp16(right[i]); + } + } else { + // Mono output, just take the left channel. + for (int i = 0; i < nb_samples; i++) { + output[i] = clamp16(left[i]); } } } @@ -113,6 +122,7 @@ private: ATRAC3PContext *at3pCtx_ = nullptr; ATRAC3Context *at3Ctx_ = nullptr; + int channels_ = 0; int blockAlign_ = 0; int outSamples_ = 0; diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index cd5d1b9b1e..c7f89de5c4 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -1078,7 +1078,7 @@ int MediaEngine::getAudioSamples(u32 bufferPtr) { } int inbytesConsumed = 0; - if (!m_audioContext->Decode(audioFrame, frameSize, &inbytesConsumed, buffer, &outbytes)) { + if (!m_audioContext->Decode(audioFrame, frameSize, &inbytesConsumed, 2, buffer, &outbytes)) { ERROR_LOG(ME, "Audio (%s) decode failed during video playback", GetCodecName(m_audioType)); } diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index abf7722d1d..2b7a16055f 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -67,7 +67,9 @@ public: } ~MiniMp3Audio() {} - bool Decode(const uint8_t* inbuf, int inbytes, int *inbytesConsumed, uint8_t *outbuf, int *outbytes) override { + bool Decode(const uint8_t* inbuf, int inbytes, int *inbytesConsumed, int outputChannels, uint8_t *outbuf, int *outbytes) override { + _dbg_assert_(outputChannels == 2); + mp3dec_frame_info_t info{}; int samplesWritten = mp3dec_decode_frame(&mp3_, inbuf, inbytes, (mp3d_sample_t *)outbuf, &info); *inbytesConsumed = info.frame_bytes; @@ -101,7 +103,7 @@ public: FFmpegAudioDecoder(PSPAudioType audioType, int sampleRateHz = 44100, int channels = 2); ~FFmpegAudioDecoder(); - bool Decode(const uint8_t* inbuf, int inbytes, int *inbytesConsumed, uint8_t *outbuf, int *outbytes) override; + bool Decode(const uint8_t* inbuf, int inbytes, int *inbytesConsumed, int outputChannels, uint8_t *outbuf, int *outbytes) override; bool IsOK() const override { #ifdef USE_FFMPEG return codec_ != 0; @@ -264,7 +266,7 @@ FFmpegAudioDecoder::~FFmpegAudioDecoder() { } // Decodes a single input frame. -bool FFmpegAudioDecoder::Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, uint8_t *outbuf, int *outbytes) { +bool FFmpegAudioDecoder::Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, int outputChannels, uint8_t *outbuf, int *outbytes) { #ifdef USE_FFMPEG if (!codecOpen_) { OpenCodec(inbytes); @@ -315,6 +317,7 @@ bool FFmpegAudioDecoder::Decode(const uint8_t *inbuf, int inbytes, int *inbytesC if (got_frame) { // Initializing the sample rate convert. We will use it to convert float output into int. + _dbg_assert_(outputChannels == 2); int64_t wanted_channel_layout = AV_CH_LAYOUT_STEREO; // we want stereo output layout int64_t dec_channel_layout = frame_->channel_layout; // decoded channel layout @@ -436,7 +439,7 @@ u32 AuCtx::AuDecode(u32 pcmAddr) { nextSync = (int)FindNextMp3Sync(); } int inbytesConsumed = 0; - decoder->Decode(&sourcebuff[nextSync], (int)sourcebuff.size() - nextSync, &inbytesConsumed, outbuf, &outpcmbufsize); + decoder->Decode(&sourcebuff[nextSync], (int)sourcebuff.size() - nextSync, &inbytesConsumed, 2, outbuf, &outpcmbufsize); if (outpcmbufsize == 0) { // Nothing was output, hopefully we're at the end of the stream. diff --git a/Core/HW/SimpleAudioDec.h b/Core/HW/SimpleAudioDec.h index 904b8f927f..ddf3d9c589 100644 --- a/Core/HW/SimpleAudioDec.h +++ b/Core/HW/SimpleAudioDec.h @@ -37,7 +37,7 @@ public: virtual PSPAudioType GetAudioType() const = 0; // inbytesConsumed can include skipping metadata. - virtual bool Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, uint8_t *outbuf, int *outbytes) = 0; + virtual bool Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, int outputChannels, uint8_t *outbuf, int *outbytes) = 0; virtual bool IsOK() const = 0; // These two are only ever called after Decode, so can initialize on first. diff --git a/UI/BackgroundAudio.cpp b/UI/BackgroundAudio.cpp index 0231c77edc..2f6c7ea3f7 100644 --- a/UI/BackgroundAudio.cpp +++ b/UI/BackgroundAudio.cpp @@ -219,7 +219,7 @@ public: while (bgQueue.size() < (size_t)(len * 2)) { int outBytes = 0; int inbytesConsumed = 0; - decoder_->Decode(wave_.raw_data + raw_offset_, wave_.raw_bytes_per_frame, &inbytesConsumed, (uint8_t *)buffer_, &outBytes); + decoder_->Decode(wave_.raw_data + raw_offset_, wave_.raw_bytes_per_frame, &inbytesConsumed, 2, (uint8_t *)buffer_, &outBytes); if (!outBytes) return false;