CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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