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/UI/BackgroundAudio.cpp
Views: 1401
1
#include <string>
2
#include <mutex>
3
4
#include "ext/minimp3/minimp3_ex.h"
5
6
#include "Common/File/VFS/VFS.h"
7
#include "Common/UI/Root.h"
8
9
#include "Common/Data/Text/I18n.h"
10
#include "Common/CommonTypes.h"
11
#include "Common/Data/Format/RIFF.h"
12
#include "Common/Log.h"
13
#include "Common/System/System.h"
14
#include "Common/System/OSD.h"
15
#include "Common/Serialize/SerializeFuncs.h"
16
#include "Common/TimeUtil.h"
17
#include "Common/Data/Collections/FixedSizeQueue.h"
18
#include "Core/HW/SimpleAudioDec.h"
19
#include "Core/HLE/__sceAudio.h"
20
#include "Core/System.h"
21
#include "Core/Config.h"
22
#include "UI/GameInfoCache.h"
23
#include "UI/BackgroundAudio.h"
24
25
struct WavData {
26
int num_channels = -1;
27
int sample_rate = -1;
28
int numFrames = -1;
29
int samplesPerSec = -1;
30
int avgBytesPerSec = -1;
31
int raw_offset_loop_start = 0;
32
int raw_offset_loop_end = 0;
33
int loop_start_offset = 0;
34
int loop_end_offset = 0;
35
int codec = 0;
36
int raw_bytes_per_frame = 0;
37
uint8_t *raw_data = nullptr;
38
int raw_data_size = 0;
39
u8 at3_extradata[16];
40
41
bool Read(RIFFReader &riff);
42
43
~WavData() {
44
free(raw_data);
45
raw_data = nullptr;
46
}
47
48
bool IsSimpleWAV() const {
49
bool isBad = raw_bytes_per_frame > sizeof(int16_t) * num_channels;
50
return !isBad && num_channels > 0 && sample_rate >= 8000 && codec == 0;
51
}
52
};
53
54
bool WavData::Read(RIFFReader &file_) {
55
// If we have no loop start info, we'll just loop the entire audio.
56
raw_offset_loop_start = 0;
57
raw_offset_loop_end = 0;
58
59
if (file_.Descend('RIFF')) {
60
file_.ReadInt(); //get past 'WAVE'
61
if (file_.Descend('fmt ')) { //enter the format chunk
62
int temp = file_.ReadInt();
63
int format = temp & 0xFFFF;
64
switch (format) {
65
case 0xFFFE:
66
codec = PSP_CODEC_AT3PLUS;
67
break;
68
case 0x270:
69
codec = PSP_CODEC_AT3;
70
break;
71
case 1:
72
// Raw wave data, no codec
73
codec = 0;
74
break;
75
default:
76
ERROR_LOG(Log::sceAudio, "Unexpected wave format %04x", format);
77
return false;
78
}
79
80
num_channels = temp >> 16;
81
82
samplesPerSec = file_.ReadInt();
83
/*avgBytesPerSec =*/ file_.ReadInt();
84
85
temp = file_.ReadInt();
86
raw_bytes_per_frame = temp & 0xFFFF;
87
88
if (codec == PSP_CODEC_AT3) {
89
// The first two bytes are actually not a useful part of the extradata.
90
// We already read 16 bytes, so make sure there's enough left.
91
if (file_.GetCurrentChunkSize() >= 32) {
92
file_.ReadData(at3_extradata, 16);
93
} else {
94
memset(at3_extradata, 0, sizeof(at3_extradata));
95
}
96
}
97
file_.Ascend();
98
// INFO_LOG(Log::AUDIO, "got fmt data: %i", samplesPerSec);
99
} else {
100
ERROR_LOG(Log::Audio, "Error - no format chunk in wav");
101
file_.Ascend();
102
return false;
103
}
104
105
if (file_.Descend('smpl')) {
106
std::vector<u8> smplData;
107
smplData.resize(file_.GetCurrentChunkSize());
108
file_.ReadData(&smplData[0], (int)smplData.size());
109
110
int numLoops = *(int *)&smplData[28];
111
struct AtracLoopInfo {
112
int cuePointID;
113
int type;
114
int startSample;
115
int endSample;
116
int fraction;
117
int playCount;
118
};
119
120
if (numLoops > 0 && smplData.size() >= 36 + sizeof(AtracLoopInfo) * numLoops) {
121
AtracLoopInfo *loops = (AtracLoopInfo *)&smplData[36];
122
int samplesPerFrame = codec == PSP_CODEC_AT3PLUS ? 2048 : 1024;
123
124
for (int i = 0; i < numLoops; ++i) {
125
// Only seen forward loops, so let's ignore others.
126
if (loops[i].type != 0)
127
continue;
128
129
// We ignore loop interpolation (fraction) and play count for now.
130
raw_offset_loop_start = (loops[i].startSample / samplesPerFrame) * raw_bytes_per_frame;
131
loop_start_offset = loops[i].startSample % samplesPerFrame;
132
raw_offset_loop_end = (loops[i].endSample / samplesPerFrame) * raw_bytes_per_frame;
133
loop_end_offset = loops[i].endSample % samplesPerFrame;
134
135
if (loops[i].playCount == 0) {
136
// This was an infinite loop, so ignore the rest.
137
// In practice, there's usually only one and it's usually infinite.
138
break;
139
}
140
}
141
}
142
143
file_.Ascend();
144
}
145
146
// enter the data chunk
147
if (file_.Descend('data')) {
148
int numBytes = file_.GetCurrentChunkSize();
149
numFrames = numBytes / raw_bytes_per_frame; // numFrames
150
151
// It seems the atrac3 codec likes to read a little bit outside.
152
const int padding = 32; // 32 is the value FFMPEG uses.
153
raw_data = (uint8_t *)malloc(numBytes + padding);
154
raw_data_size = numBytes;
155
156
if (num_channels == 1 || num_channels == 2) {
157
file_.ReadData(raw_data, numBytes);
158
} else {
159
ERROR_LOG(Log::Audio, "Error - bad blockalign or channels");
160
free(raw_data);
161
raw_data = nullptr;
162
return false;
163
}
164
file_.Ascend();
165
} else {
166
ERROR_LOG(Log::Audio, "Error - no data chunk in wav");
167
file_.Ascend();
168
return false;
169
}
170
file_.Ascend();
171
} else {
172
ERROR_LOG(Log::Audio, "Could not descend into RIFF file.");
173
return false;
174
}
175
sample_rate = samplesPerSec;
176
return true;
177
}
178
179
// Really simple looping in-memory AT3 player that also takes care of reading the file format.
180
// Turns out that AT3 files used for this are modified WAVE files so fairly easy to parse.
181
class AT3PlusReader {
182
public:
183
explicit AT3PlusReader(const std::string &data)
184
: file_((const uint8_t *)&data[0], (int32_t)data.size()) {
185
// Normally 8k but let's be safe.
186
buffer_ = new short[32 * 1024];
187
188
skip_next_samples_ = 0;
189
190
wave_.Read(file_);
191
192
uint8_t *extraData = nullptr;
193
size_t extraDataSize = 0;
194
size_t blockSize = 0;
195
if (wave_.codec == PSP_CODEC_AT3) {
196
extraData = &wave_.at3_extradata[2];
197
extraDataSize = 14;
198
blockSize = wave_.raw_bytes_per_frame;
199
} else if (wave_.codec == PSP_CODEC_AT3PLUS) {
200
blockSize = wave_.raw_bytes_per_frame;
201
}
202
decoder_ = CreateAudioDecoder((PSPAudioType)wave_.codec, wave_.sample_rate, wave_.num_channels, blockSize, extraData, extraDataSize);
203
INFO_LOG(Log::Audio, "read ATRAC, frames: %d, rate %d", wave_.numFrames, wave_.sample_rate);
204
}
205
206
~AT3PlusReader() {
207
delete[] buffer_;
208
buffer_ = nullptr;
209
delete decoder_;
210
decoder_ = nullptr;
211
}
212
213
bool IsOK() { return wave_.raw_data != nullptr; }
214
215
bool Read(int *buffer, int len) {
216
if (!wave_.raw_data)
217
return false;
218
219
while (bgQueue.size() < (size_t)(len * 2)) {
220
int outSamples = 0;
221
int inbytesConsumed = 0;
222
bool result = decoder_->Decode(wave_.raw_data + raw_offset_, wave_.raw_bytes_per_frame, &inbytesConsumed, 2, (int16_t *)buffer_, &outSamples);
223
if (!result || !outSamples)
224
return false;
225
int outBytes = outSamples * 2 * sizeof(int16_t);
226
227
if (wave_.raw_offset_loop_end != 0 && raw_offset_ == wave_.raw_offset_loop_end) {
228
// Only take the remaining bytes, but convert to stereo s16.
229
outBytes = std::min(outBytes, wave_.loop_end_offset * 4);
230
}
231
232
int start = skip_next_samples_;
233
skip_next_samples_ = 0;
234
235
for (int i = start; i < outBytes / 2; i++) {
236
bgQueue.push(buffer_[i]);
237
}
238
239
if (wave_.raw_offset_loop_end != 0 && raw_offset_ == wave_.raw_offset_loop_end) {
240
// Time to loop. Account for the addition below.
241
raw_offset_ = wave_.raw_offset_loop_start - wave_.raw_bytes_per_frame;
242
// This time we're counting each stereo sample.
243
skip_next_samples_ = wave_.loop_start_offset * 2;
244
}
245
246
// Handle loops when there's no loop info.
247
raw_offset_ += wave_.raw_bytes_per_frame;
248
if (raw_offset_ >= wave_.raw_data_size) {
249
raw_offset_ = 0;
250
}
251
}
252
253
for (int i = 0; i < len * 2; i++) {
254
buffer[i] = bgQueue.pop_front();
255
}
256
return true;
257
}
258
259
private:
260
RIFFReader file_;
261
262
WavData wave_;
263
264
int raw_offset_ = 0;
265
int skip_next_samples_ = 0;
266
FixedSizeQueue<s16, 128 * 1024> bgQueue;
267
short *buffer_ = nullptr;
268
AudioDecoder *decoder_ = nullptr;
269
};
270
271
BackgroundAudio g_BackgroundAudio;
272
273
BackgroundAudio::BackgroundAudio() {
274
buffer = new int[BUFSIZE]();
275
sndLoadPending_.store(false);
276
}
277
278
BackgroundAudio::~BackgroundAudio() {
279
delete at3Reader_;
280
delete[] buffer;
281
}
282
283
void BackgroundAudio::Clear(bool hard) {
284
if (!hard) {
285
fadingOut_ = true;
286
volume_ = 1.0f;
287
return;
288
}
289
if (at3Reader_) {
290
delete at3Reader_;
291
at3Reader_ = nullptr;
292
}
293
playbackOffset_ = 0;
294
sndLoadPending_ = false;
295
}
296
297
void BackgroundAudio::SetGame(const Path &path) {
298
if (path == bgGamePath_) {
299
// Do nothing
300
return;
301
}
302
303
std::lock_guard<std::mutex> lock(mutex_);
304
if (path.empty()) {
305
Clear(false);
306
sndLoadPending_ = false;
307
fadingOut_ = true;
308
} else {
309
Clear(true);
310
gameLastChanged_ = time_now_d();
311
sndLoadPending_ = true;
312
fadingOut_ = false;
313
}
314
volume_ = 1.0f;
315
bgGamePath_ = path;
316
}
317
318
bool BackgroundAudio::Play() {
319
std::lock_guard<std::mutex> lock(mutex_);
320
321
// Immediately stop the sound if it is turned off while playing.
322
if (!g_Config.bEnableSound) {
323
Clear(true);
324
System_AudioClear();
325
return true;
326
}
327
328
double now = time_now_d();
329
int sz = 44100 / 60;
330
if (lastPlaybackTime_ > 0.0 && lastPlaybackTime_ <= now) {
331
sz = (int)((now - lastPlaybackTime_) * 44100);
332
}
333
sz = std::min(BUFSIZE / 2, sz);
334
if (at3Reader_) {
335
if (at3Reader_->Read(buffer, sz)) {
336
if (fadingOut_) {
337
for (int i = 0; i < sz*2; i += 2) {
338
buffer[i] *= volume_;
339
buffer[i + 1] *= volume_;
340
volume_ += delta_;
341
}
342
}
343
}
344
} else {
345
for (int i = 0; i < sz * 2; i += 2) {
346
buffer[i] = 0;
347
buffer[i + 1] = 0;
348
}
349
}
350
351
System_AudioPushSamples(buffer, sz);
352
353
if (at3Reader_ && fadingOut_ && volume_ <= 0.0f) {
354
Clear(true);
355
fadingOut_ = false;
356
gameLastChanged_ = 0;
357
}
358
359
lastPlaybackTime_ = now;
360
361
return true;
362
}
363
364
void BackgroundAudio::Update() {
365
// If there's a game, and some time has passed since the selected game
366
// last changed... (to prevent crazy amount of reads when skipping through a list)
367
if (sndLoadPending_ && (time_now_d() - gameLastChanged_ > 0.5)) {
368
std::lock_guard<std::mutex> lock(mutex_);
369
// Already loaded somehow? Or no game info cache?
370
if (at3Reader_ || !g_gameInfoCache)
371
return;
372
373
// Grab some audio from the current game and play it.
374
std::shared_ptr<GameInfo> gameInfo = g_gameInfoCache->GetInfo(nullptr, bgGamePath_, GameInfoFlags::SND);
375
if (!gameInfo->Ready(GameInfoFlags::SND)) {
376
// Should try again shortly..
377
return;
378
}
379
380
const std::string &data = gameInfo->sndFileData;
381
if (!data.empty()) {
382
at3Reader_ = new AT3PlusReader(data);
383
lastPlaybackTime_ = 0.0;
384
}
385
sndLoadPending_ = false;
386
}
387
}
388
389
inline int16_t ConvertU8ToI16(uint8_t value) {
390
int ivalue = value - 128;
391
return ivalue * 255;
392
}
393
394
Sample *Sample::Load(const std::string &path) {
395
size_t data_size = 0;
396
uint8_t *data = g_VFS.ReadFile(path.c_str(), &data_size);
397
if (!data || data_size > 100000000) {
398
WARN_LOG(Log::Audio, "Failed to load sample '%s'", path.c_str());
399
return nullptr;
400
}
401
402
const char *mp3_magic = "ID3\03";
403
const char *wav_magic = "RIFF";
404
if (!memcmp(data, wav_magic, 4)) {
405
RIFFReader reader(data, (int)data_size);
406
WavData wave;
407
if (!wave.Read(reader)) {
408
delete[] data;
409
return nullptr;
410
}
411
// A wav file.
412
delete[] data;
413
414
if (!wave.IsSimpleWAV()) {
415
ERROR_LOG(Log::Audio, "Wave format not supported for mixer playback. Must be 8-bit or 16-bit raw mono or stereo. '%s'", path.c_str());
416
return nullptr;
417
}
418
419
int16_t *samples = new int16_t[wave.num_channels * wave.numFrames];
420
if (wave.raw_bytes_per_frame == wave.num_channels * 2) {
421
// 16-bit
422
memcpy(samples, wave.raw_data, wave.numFrames * wave.raw_bytes_per_frame);
423
} else if (wave.raw_bytes_per_frame == wave.num_channels) {
424
// 8-bit. Convert.
425
for (int i = 0; i < wave.num_channels * wave.numFrames; i++) {
426
samples[i] = ConvertU8ToI16(wave.raw_data[i]);
427
}
428
}
429
430
// Protect against bad metadata.
431
int actualFrames = std::min(wave.numFrames, wave.raw_data_size / wave.raw_bytes_per_frame);
432
433
return new Sample(samples, wave.num_channels, actualFrames, wave.sample_rate);
434
}
435
436
// Something else.
437
// Let's see if minimp3 can read it.
438
mp3dec_t mp3d;
439
mp3dec_init(&mp3d);
440
mp3dec_file_info_t mp3_info;
441
int retval = mp3dec_load_buf(&mp3d, data, data_size, &mp3_info, nullptr, nullptr);
442
443
if (retval < 0 || mp3_info.samples == 0) {
444
ERROR_LOG(Log::Audio, "Couldn't load MP3 for sound effect from %s", path.c_str());
445
return nullptr;
446
}
447
448
// mp3_info contains the decoded data.
449
int16_t *sample_data = new int16_t[mp3_info.samples];
450
memcpy(sample_data, mp3_info.buffer, mp3_info.samples * sizeof(int16_t));
451
452
Sample *sample = new Sample(sample_data, mp3_info.channels, (int)mp3_info.samples / mp3_info.channels, mp3_info.hz);
453
free(mp3_info.buffer);
454
delete[] data;
455
return sample;
456
}
457
458
static inline int16_t Clamp16(int32_t sample) {
459
if (sample < -32767) return -32767;
460
if (sample > 32767) return 32767;
461
return sample;
462
}
463
464
void SoundEffectMixer::Mix(int16_t *buffer, int sz, int sampleRateHz) {
465
{
466
std::lock_guard<std::mutex> guard(mutex_);
467
if (!queue_.empty()) {
468
for (const auto &entry : queue_) {
469
plays_.push_back(entry);
470
}
471
queue_.clear();
472
}
473
if (plays_.empty()) {
474
return;
475
}
476
}
477
478
for (std::vector<PlayInstance>::iterator iter = plays_.begin(); iter != plays_.end(); ) {
479
auto sample = samples_[(int)iter->sound].get();
480
if (!sample) {
481
// Remove playback instance if sample invalid.
482
iter = plays_.erase(iter);
483
continue;
484
}
485
486
int64_t rateOfSample = sample->rateInHz_;
487
int64_t stride = (rateOfSample << 32) / sampleRateHz;
488
489
for (int i = 0; i < sz * 2; i += 2) {
490
if ((iter->offset >> 32) >= sample->length_ - 2) {
491
iter->done = true;
492
break;
493
}
494
495
int wholeOffset = iter->offset >> 32;
496
int frac = (iter->offset >> 20) & 0xFFF; // Use a 12 bit fraction to get away with 32-bit multiplies
497
498
if (sample->channels_ == 2) {
499
int interpolatedLeft = (sample->data_[wholeOffset * 2] * (0x1000 - frac) + sample->data_[(wholeOffset + 1) * 2] * frac) >> 12;
500
int interpolatedRight = (sample->data_[wholeOffset * 2 + 1] * (0x1000 - frac) + sample->data_[(wholeOffset + 1) * 2 + 1] * frac) >> 12;
501
502
// Clamping add on top per sample. Not great, we should be mixing at higher bitrate instead. Oh well.
503
int left = Clamp16(buffer[i] + (interpolatedLeft * iter->volume >> 8));
504
int right = Clamp16(buffer[i + 1] + (interpolatedRight * iter->volume >> 8));
505
506
buffer[i] = left;
507
buffer[i + 1] = right;
508
} else if (sample->channels_ == 1) {
509
int interpolated = (sample->data_[wholeOffset] * (0x1000 - frac) + sample->data_[wholeOffset + 1] * frac) >> 12;
510
511
// Clamping add on top per sample. Not great, we should be mixing at higher bitrate instead. Oh well.
512
int value = Clamp16(buffer[i] + (interpolated * iter->volume >> 8));
513
514
buffer[i] = value;
515
buffer[i + 1] = value;
516
}
517
518
iter->offset += stride;
519
}
520
521
if (iter->done) {
522
iter = plays_.erase(iter);
523
} else {
524
iter++;
525
}
526
}
527
}
528
529
void SoundEffectMixer::Play(UI::UISound sfx, float volume) {
530
std::lock_guard<std::mutex> guard(mutex_);
531
queue_.push_back(PlayInstance{ sfx, 0, (int)(255.0f * volume), false });
532
}
533
534
void SoundEffectMixer::UpdateSample(UI::UISound sound, Sample *sample) {
535
if (sample) {
536
std::lock_guard<std::mutex> guard(mutex_);
537
samples_[(size_t)sound] = std::unique_ptr<Sample>(sample);
538
} else {
539
LoadDefaultSample(sound);
540
}
541
}
542
543
void SoundEffectMixer::LoadDefaultSample(UI::UISound sound) {
544
const char *filename = nullptr;
545
switch (sound) {
546
case UI::UISound::BACK: filename = "sfx_back.wav"; break;
547
case UI::UISound::SELECT: filename = "sfx_select.wav"; break;
548
case UI::UISound::CONFIRM: filename = "sfx_confirm.wav"; break;
549
case UI::UISound::TOGGLE_ON: filename = "sfx_toggle_on.wav"; break;
550
case UI::UISound::TOGGLE_OFF: filename = "sfx_toggle_off.wav"; break;
551
case UI::UISound::ACHIEVEMENT_UNLOCKED: filename = "sfx_achievement_unlocked.wav"; break;
552
case UI::UISound::LEADERBOARD_SUBMITTED: filename = "sfx_leaderbord_submitted.wav"; break;
553
default:
554
return;
555
}
556
Sample *sample = Sample::Load(filename);
557
if (!sample) {
558
ERROR_LOG(Log::System, "Failed to load the default sample for UI sound %d", (int)sound);
559
}
560
std::lock_guard<std::mutex> guard(mutex_);
561
samples_[(size_t)sound] = std::unique_ptr<Sample>(sample);
562
}
563
564
void SoundEffectMixer::LoadSamples() {
565
samples_.resize((size_t)UI::UISound::COUNT);
566
LoadDefaultSample(UI::UISound::BACK);
567
LoadDefaultSample(UI::UISound::SELECT);
568
LoadDefaultSample(UI::UISound::CONFIRM);
569
LoadDefaultSample(UI::UISound::TOGGLE_ON);
570
LoadDefaultSample(UI::UISound::TOGGLE_OFF);
571
572
if (!g_Config.sAchievementsUnlockAudioFile.empty()) {
573
UpdateSample(UI::UISound::ACHIEVEMENT_UNLOCKED, Sample::Load(g_Config.sAchievementsUnlockAudioFile));
574
} else {
575
LoadDefaultSample(UI::UISound::ACHIEVEMENT_UNLOCKED);
576
}
577
if (!g_Config.sAchievementsLeaderboardSubmitAudioFile.empty()) {
578
UpdateSample(UI::UISound::LEADERBOARD_SUBMITTED, Sample::Load(g_Config.sAchievementsLeaderboardSubmitAudioFile));
579
} else {
580
LoadDefaultSample(UI::UISound::LEADERBOARD_SUBMITTED);
581
}
582
583
UI::SetSoundCallback([](UI::UISound sound, float volume) {
584
g_BackgroundAudio.SFX().Play(sound, volume);
585
});
586
}
587
588