2 #include "base/logging.h"
3 #include "base/timeutil.h"
4 #include "base/mutex.h"
5 #include "native/file/chunk_file.h"
7 #include "Common/CommonTypes.h"
8 #include "Core/HW/SimpleAudioDec.h"
9 #include "Core/HLE/__sceAudio.h"
10 #include "Common/FixedSizeQueue.h"
11 #include "GameInfoCache.h"
12 #include "Core/Config.h"
14 // Really simple looping in-memory AT3 player that also takes care of reading the file format.
15 // Turns out that AT3 files used for this are modified WAVE files so fairly easy to parse.
18 AT3PlusReader(const std::string
&data
)
19 : file_((const uint8_t *)&data
[0],
20 (int32_t)data
.size()),
27 // Normally 8k but let's be safe.
28 buffer_
= new short[32 * 1024];
30 int codec
= PSP_CODEC_AT3PLUS
;
33 int num_channels
, sample_rate
, numFrames
, samplesPerSec
, avgBytesPerSec
, Nothing
;
34 if (file_
.descend('RIFF')) {
35 file_
.readInt(); //get past 'WAVE'
36 if (file_
.descend('fmt ')) { //enter the format chunk
37 int temp
= file_
.readInt();
38 int format
= temp
& 0xFFFF;
41 codec
= PSP_CODEC_AT3PLUS
;
44 codec
= PSP_CODEC_AT3
;
47 ERROR_LOG(HLE
, "Unexpected SND0.AT3 format %04x", format
);
51 num_channels
= temp
>> 16;
53 samplesPerSec
= file_
.readInt();
54 avgBytesPerSec
= file_
.readInt();
56 temp
= file_
.readInt();
57 raw_bytes_per_frame_
= temp
& 0xFFFF;
60 if (codec
== PSP_CODEC_AT3
) {
61 // The first two bytes are actually not a useful part of the extradata.
62 // We already read 16 bytes, so make sure there's enough left.
63 if (file_
.getCurrentChunkSize() >= 32) {
64 file_
.readData(at3_extradata
, 16);
66 memset(at3_extradata
, 0, sizeof(at3_extradata
));
70 // ILOG("got fmt data: %i", samplesPerSec);
72 ELOG("Error - no format chunk in wav");
77 if (file_
.descend('data')) { //enter the data chunk
78 int numBytes
= file_
.getCurrentChunkSize();
79 numFrames
= numBytes
/ raw_bytes_per_frame_
; // numFrames
81 raw_data_
= (uint8_t *)malloc(numBytes
);
82 raw_data_size_
= numBytes
;
83 if (/*raw_bytes_per_frame_ == 280 && */ num_channels
== 2) {
84 file_
.readData(raw_data_
, numBytes
);
86 ELOG("Error - bad blockalign or channels");
93 ELOG("Error - no data chunk in wav");
99 ELOG("Could not descend into RIFF file");
102 sample_rate
= samplesPerSec
;
103 decoder_
= new SimpleAudio(codec
, sample_rate
, num_channels
);
104 if (codec
== PSP_CODEC_AT3
) {
105 decoder_
->SetExtraData(&at3_extradata
[2], 14, raw_bytes_per_frame_
);
107 ILOG("read ATRAC, frames: %i, rate %i", numFrames
, sample_rate
);
122 bool IsOK() { return raw_data_
!= 0; }
124 bool Read(int *buffer
, int len
) {
128 while (bgQueue
.size() < (size_t)(len
* 2)) {
130 decoder_
->Decode(raw_data_
+ raw_offset_
, raw_bytes_per_frame_
, (uint8_t *)buffer_
, &outBytes
);
134 for (int i
= 0; i
< outBytes
/ 2; i
++) {
135 bgQueue
.push(buffer_
[i
]);
139 raw_offset_
+= raw_bytes_per_frame_
;
140 if (raw_offset_
>= raw_data_size_
) {
145 for (int i
= 0; i
< len
* 2; i
++) {
146 buffer
[i
] = bgQueue
.pop_front();
156 int raw_bytes_per_frame_
;
157 FixedSizeQueue
<s16
, 128 * 1024> bgQueue
;
159 SimpleAudio
*decoder_
;
162 static recursive_mutex bgMutex
;
163 static std::string bgGamePath
;
164 static int playbackOffset
;
165 static AT3PlusReader
*at3Reader
;
166 static double gameLastChanged
;
167 static double lastPlaybackTime
;
168 static int buffer
[44100];
170 static void ClearBackgroundAudio() {
172 at3Reader
->Shutdown();
179 void SetBackgroundAudioGame(const std::string
&path
) {
182 lock_guard
lock(bgMutex
);
183 if (path
== bgGamePath
) {
188 if (!g_Config
.bEnableSound
) {
189 ClearBackgroundAudio();
193 ClearBackgroundAudio();
194 gameLastChanged
= time_now_d();
198 int PlayBackgroundAudio() {
201 lock_guard
lock(bgMutex
);
203 // Immediately stop the sound if it is turned off while playing.
204 if (!g_Config
.bEnableSound
) {
205 ClearBackgroundAudio();
206 __PushExternalAudio(0, 0);
210 // If there's a game, and some time has passed since the selected game
211 // last changed... (to prevent crazy amount of reads when skipping through a list)
212 if (!at3Reader
&& bgGamePath
.size() && (time_now_d() - gameLastChanged
> 0.5)) {
213 // Grab some audio from the current game and play it.
214 GameInfo
*gameInfo
= g_gameInfoCache
.GetInfo(NULL
, bgGamePath
, GAMEINFO_WANTSND
);
218 if (gameInfo
->sndFileData
.size()) {
219 const std::string
&data
= gameInfo
->sndFileData
;
220 at3Reader
= new AT3PlusReader(data
);
221 lastPlaybackTime
= 0.0;
225 double now
= time_now();
227 int sz
= lastPlaybackTime
<= 0.0 ? 44100 / 60 : (int)((now
- lastPlaybackTime
) * 44100);
228 sz
= std::min((int)ARRAY_SIZE(buffer
) / 2, sz
);
230 if (at3Reader
->Read(buffer
, sz
))
231 __PushExternalAudio(buffer
, sz
);
232 lastPlaybackTime
= now
;
235 __PushExternalAudio(0, 0);
236 lastPlaybackTime
= now
;