mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
Merge pull request #6393 from hrydgard/menu-audio
Play the game's SND0.AT3 when a game is selected in the menu and on the "game screen".
This commit is contained in:
commit
b2ae317560
@ -1401,6 +1401,7 @@ endif()
|
||||
|
||||
set(NativeAppSource
|
||||
UI/NativeApp.cpp
|
||||
UI/BackgroundAudio.cpp
|
||||
UI/DevScreens.cpp
|
||||
UI/EmuScreen.cpp
|
||||
android/jni/TestRunner.cpp
|
||||
|
@ -18,6 +18,7 @@
|
||||
#pragma once
|
||||
|
||||
// Extremely simple serialization framework.
|
||||
// Currently mis-named, a native ChunkFile is something different (a RIFF file)
|
||||
|
||||
// (mis)-features:
|
||||
// + Super fast
|
||||
|
@ -81,7 +81,8 @@ int sceAudiocodecInit(u32 ctxPtr, int codec) {
|
||||
if (removeDecoder(ctxPtr)) {
|
||||
WARN_LOG_REPORT(HLE, "sceAudiocodecInit(%08x, %d): replacing existing context", ctxPtr, codec);
|
||||
}
|
||||
auto decoder = new SimpleAudio(ctxPtr, codec);
|
||||
auto decoder = new SimpleAudio(codec);
|
||||
decoder->SetCtxPtr(ctxPtr);
|
||||
audioList[ctxPtr] = decoder;
|
||||
INFO_LOG(ME, "sceAudiocodecInit(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
|
||||
DEBUG_LOG(ME, "Number of playing sceAudioCodec audios : %d", (int)audioList.size());
|
||||
@ -107,7 +108,8 @@ int sceAudiocodecDecode(u32 ctxPtr, int codec) {
|
||||
if (!decoder && oldStateLoaded) {
|
||||
// We must have loaded an old state that did not have sceAudiocodec information.
|
||||
// Fake it by creating the desired context.
|
||||
decoder = new SimpleAudio(ctxPtr, codec);
|
||||
decoder = new SimpleAudio(codec);
|
||||
decoder->SetCtxPtr(ctxPtr);
|
||||
audioList[ctxPtr] = decoder;
|
||||
}
|
||||
|
||||
@ -181,7 +183,8 @@ void __sceAudiocodecDoState(PointerWrap &p){
|
||||
p.DoArray(codec_, s >= 2 ? count : (int)ARRAY_SIZE(codec_));
|
||||
p.DoArray(ctxPtr_, s >= 2 ? count : (int)ARRAY_SIZE(ctxPtr_));
|
||||
for (int i = 0; i < count; i++) {
|
||||
auto decoder = new SimpleAudio(ctxPtr_[i], codec_[i]);
|
||||
auto decoder = new SimpleAudio(codec_[i]);
|
||||
decoder->SetCtxPtr(ctxPtr_[i]);
|
||||
audioList[ctxPtr_[i]] = decoder;
|
||||
}
|
||||
delete[] codec_;
|
||||
|
@ -333,7 +333,7 @@ int sceMp3Init(u32 mp3) {
|
||||
|
||||
// for mp3, if required freq is 48000, reset resampling Frequency to 48000 seems get better sound quality (e.g. Miku Custom BGM)
|
||||
if (ctx->freq == 48000) {
|
||||
ctx->decoder->setResampleFrequency(ctx->freq);
|
||||
ctx->decoder->SetResampleFrequency(ctx->freq);
|
||||
}
|
||||
|
||||
// For mp3 file, if ID3 tag is detected, we must move startPos to 0x400 (stream start position), remove 0x400 bytes of the sourcebuff, and reduce the available buffer size by 0x400
|
||||
@ -557,7 +557,7 @@ u32 sceMp3LowLevelDecode(u32 mp3, u32 sourceAddr, u32 sourceBytesConsumedAddr, u
|
||||
int outpcmbytes = 0;
|
||||
ctx->decoder->Decode((void*)inbuff, 4096, outbuff, &outpcmbytes);
|
||||
|
||||
Memory::Write_U32(ctx->decoder->getSourcePos(), sourceBytesConsumedAddr);
|
||||
Memory::Write_U32(ctx->decoder->GetSourcePos(), sourceBytesConsumedAddr);
|
||||
Memory::Write_U32(outpcmbytes, sampleBytesAddr);
|
||||
return 0;
|
||||
}
|
||||
|
@ -60,14 +60,8 @@ bool SimpleAudio::GetAudioCodecID(int audioType) {
|
||||
#endif // USE_FFMPEG
|
||||
}
|
||||
|
||||
SimpleAudio::SimpleAudio(int audioType)
|
||||
: codec_(0), codecCtx_(0), swrCtx_(0), audioType(audioType), outSamples(0), wanted_resample_freq(44100) {
|
||||
Init();
|
||||
}
|
||||
|
||||
|
||||
SimpleAudio::SimpleAudio(u32 ctxPtr, int audioType)
|
||||
: codec_(0), codecCtx_(0), swrCtx_(0), ctxPtr(ctxPtr), audioType(audioType), outSamples(0), wanted_resample_freq(44100) {
|
||||
SimpleAudio::SimpleAudio(int audioType, int sample_rate, int channels)
|
||||
: ctxPtr(0xFFFFFFFF), audioType(audioType), sample_rate_(sample_rate), channels_(channels), codec_(0), codecCtx_(0), swrCtx_(0), outSamples(0), srcPos(0), wanted_resample_freq(44100), extradata_(0) {
|
||||
Init();
|
||||
}
|
||||
|
||||
@ -97,19 +91,24 @@ void SimpleAudio::Init() {
|
||||
ERROR_LOG(ME, "Failed to allocate a codec context");
|
||||
return;
|
||||
}
|
||||
codecCtx_->channels = 2;
|
||||
codecCtx_->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
codecCtx_->sample_rate = 44100;
|
||||
// Open codec
|
||||
codecCtx_->channels = channels_;
|
||||
codecCtx_->channel_layout = channels_ == 2 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
|
||||
codecCtx_->sample_rate = sample_rate_;
|
||||
OpenCodec();
|
||||
#endif // USE_FFMPEG
|
||||
}
|
||||
|
||||
bool SimpleAudio::OpenCodec() {
|
||||
#ifdef USE_FFMPEG
|
||||
AVDictionary *opts = 0;
|
||||
bool result = true;
|
||||
if (avcodec_open2(codecCtx_, codec_, &opts) < 0) {
|
||||
ERROR_LOG(ME, "Failed to open codec");
|
||||
av_dict_free(&opts);
|
||||
return;
|
||||
result = false;
|
||||
}
|
||||
|
||||
av_dict_free(&opts);
|
||||
#endif // USE_FFMPEG
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SimpleAudio::ResetCodecCtx(int channels, int samplerate){
|
||||
@ -128,21 +127,35 @@ bool SimpleAudio::ResetCodecCtx(int channels, int samplerate){
|
||||
codecCtx_->channels = channels;
|
||||
codecCtx_->channel_layout = channels==2?AV_CH_LAYOUT_STEREO:AV_CH_LAYOUT_MONO;
|
||||
codecCtx_->sample_rate = samplerate;
|
||||
// Open codec
|
||||
AVDictionary *opts = 0;
|
||||
if (avcodec_open2(codecCtx_, codec_, &opts) < 0) {
|
||||
ERROR_LOG(ME, "Failed to open codec");
|
||||
av_dict_free(&opts);
|
||||
return false;
|
||||
}
|
||||
av_dict_free(&opts);
|
||||
OpenCodec();
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void SimpleAudio::SetExtraData(u8 *data, int size, int wav_bytes_per_packet) {
|
||||
delete [] extradata_;
|
||||
extradata_ = 0;
|
||||
|
||||
if (data != 0) {
|
||||
extradata_ = new u8[size];
|
||||
memcpy(extradata_, data, size);
|
||||
}
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
if (codecCtx_) {
|
||||
codecCtx_->extradata = extradata_;
|
||||
codecCtx_->extradata_size = size;
|
||||
codecCtx_->block_align = wav_bytes_per_packet;
|
||||
OpenCodec();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SimpleAudio::~SimpleAudio() {
|
||||
#ifdef USE_FFMPEG
|
||||
if (swrCtx_)
|
||||
swr_free(&swrCtx_);
|
||||
if (frame_)
|
||||
av_frame_free(&frame_);
|
||||
if (codecCtx_)
|
||||
@ -151,6 +164,8 @@ SimpleAudio::~SimpleAudio() {
|
||||
codecCtx_ = 0;
|
||||
codec_ = 0;
|
||||
#endif // USE_FFMPEG
|
||||
delete [] extradata_;
|
||||
extradata_ = 0;
|
||||
}
|
||||
|
||||
bool SimpleAudio::IsOK() const {
|
||||
@ -183,7 +198,7 @@ bool SimpleAudio::Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbyte
|
||||
srcPos = 0;
|
||||
int len = avcodec_decode_audio4(codecCtx_, frame_, &got_frame, &packet);
|
||||
if (len < 0) {
|
||||
ERROR_LOG(ME, "Error decoding Audio frame");
|
||||
ERROR_LOG(ME, "Error decoding Audio frame (%i bytes): %i (%08x)", inbytes, len, len);
|
||||
// TODO: cleanup
|
||||
return false;
|
||||
}
|
||||
@ -197,30 +212,32 @@ bool SimpleAudio::Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbyte
|
||||
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
|
||||
|
||||
swrCtx_ = swr_alloc_set_opts(
|
||||
swrCtx_,
|
||||
wanted_channel_layout,
|
||||
AV_SAMPLE_FMT_S16,
|
||||
wanted_resample_freq,
|
||||
dec_channel_layout,
|
||||
codecCtx_->sample_fmt,
|
||||
codecCtx_->sample_rate,
|
||||
0,
|
||||
NULL);
|
||||
if (!swrCtx_) {
|
||||
swrCtx_ = swr_alloc_set_opts(
|
||||
swrCtx_,
|
||||
wanted_channel_layout,
|
||||
AV_SAMPLE_FMT_S16,
|
||||
wanted_resample_freq,
|
||||
dec_channel_layout,
|
||||
codecCtx_->sample_fmt,
|
||||
codecCtx_->sample_rate,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (!swrCtx_ || swr_init(swrCtx_) < 0) {
|
||||
ERROR_LOG(ME, "swr_init: Failed to initialize the resampling context");
|
||||
avcodec_close(codecCtx_);
|
||||
codec_ = 0;
|
||||
return false;
|
||||
if (!swrCtx_ || swr_init(swrCtx_) < 0) {
|
||||
ERROR_LOG(ME, "swr_init: Failed to initialize the resampling context");
|
||||
avcodec_close(codecCtx_);
|
||||
codec_ = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// convert audio to AV_SAMPLE_FMT_S16
|
||||
int swrRet = swr_convert(swrCtx_, &outbuf, frame_->nb_samples, (const u8 **)frame_->extended_data, frame_->nb_samples);
|
||||
if (swrRet < 0) {
|
||||
ERROR_LOG(ME, "swr_convert: Error while converting %d", swrRet);
|
||||
return false;
|
||||
}
|
||||
swr_free(&swrCtx_);
|
||||
// output samples per frame, we should *2 since we have two channels
|
||||
outSamples = swrRet * 2;
|
||||
|
||||
@ -240,18 +257,14 @@ bool SimpleAudio::Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbyte
|
||||
#endif // USE_FFMPEG
|
||||
}
|
||||
|
||||
int SimpleAudio::getOutSamples(){
|
||||
int SimpleAudio::GetOutSamples(){
|
||||
return outSamples;
|
||||
}
|
||||
|
||||
int SimpleAudio::getSourcePos(){
|
||||
int SimpleAudio::GetSourcePos(){
|
||||
return srcPos;
|
||||
}
|
||||
|
||||
void SimpleAudio::setResampleFrequency(int freq){
|
||||
wanted_resample_freq = freq;
|
||||
}
|
||||
|
||||
void AudioClose(SimpleAudio **ctx) {
|
||||
#ifdef USE_FFMPEG
|
||||
delete *ctx;
|
||||
@ -349,9 +362,9 @@ u32 AuCtx::AuDecode(u32 pcmAddr)
|
||||
// count total output pcm size
|
||||
outpcmbufsize += pcmframesize;
|
||||
// count total output samples
|
||||
SumDecodedSamples += decoder->getOutSamples();
|
||||
SumDecodedSamples += decoder->GetOutSamples();
|
||||
// get consumed source length
|
||||
int srcPos = decoder->getSourcePos();
|
||||
int srcPos = decoder->GetSourcePos();
|
||||
// remove the consumed source
|
||||
sourcebuff.erase(0, srcPos);
|
||||
// reduce the available Aubuff size
|
||||
|
@ -33,11 +33,6 @@ struct SwrContext;
|
||||
|
||||
// Based on http://ffmpeg.org/doxygen/trunk/doc_2examples_2decoding_encoding_8c-example.html#_a13
|
||||
|
||||
// Ideally, Maxim's Atrac3+ decoder would be available as a standalone library
|
||||
// that we could link, as that would be totally sufficient for the use case here.
|
||||
// However, it will be maintained as a part of FFMPEG so that's the way we'll go
|
||||
// for simplicity and sanity.
|
||||
|
||||
// audioType
|
||||
enum {
|
||||
PSP_CODEC_AT3PLUS = 0x00001000,
|
||||
@ -48,38 +43,48 @@ enum {
|
||||
|
||||
class SimpleAudio {
|
||||
public:
|
||||
SimpleAudio(int audioType);
|
||||
SimpleAudio(u32 ctxPtr, int audioType);
|
||||
SimpleAudio(int audioType, int sample_rate = 44100, int channels = 2);
|
||||
~SimpleAudio();
|
||||
|
||||
bool Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbytes);
|
||||
bool IsOK() const;
|
||||
int getOutSamples();
|
||||
int getSourcePos();
|
||||
|
||||
int GetOutSamples();
|
||||
int GetSourcePos();
|
||||
bool ResetCodecCtx(int channels, int samplerate);
|
||||
void setResampleFrequency(int freq);
|
||||
bool GetAudioCodecID(int audioType); // Get audioCodecId from audioType
|
||||
|
||||
// Not save stated, only used by UI. Used for ATRAC3 (non+) files.
|
||||
void SetExtraData(u8 *data, int size, int wav_bytes_per_packet);
|
||||
|
||||
// These two are only here because of save states.
|
||||
int GetAudioType() const { return audioType; }
|
||||
void SetResampleFrequency(int freq) { wanted_resample_freq = freq; }
|
||||
|
||||
// Just metadata.
|
||||
void SetCtxPtr(u32 ptr) { ctxPtr = ptr; }
|
||||
u32 GetCtxPtr() const { return ctxPtr; }
|
||||
|
||||
private:
|
||||
void Init();
|
||||
bool OpenCodec();
|
||||
|
||||
u32 ctxPtr;
|
||||
int audioType;
|
||||
int sample_rate_;
|
||||
int channels_;
|
||||
int outSamples; // output samples per frame
|
||||
int srcPos; // bytes consumed in source during the last decoding
|
||||
int wanted_resample_freq; // wanted resampling rate/frequency
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
AVFrame *frame_;
|
||||
AVCodec *codec_;
|
||||
AVCodecContext *codecCtx_;
|
||||
SwrContext *swrCtx_;
|
||||
int audioCodecId; // AV_CODEC_ID_XXX
|
||||
#endif // USE_FFMPEG
|
||||
|
||||
// Not savestated, only used by UI.
|
||||
u8 *extradata_;
|
||||
};
|
||||
|
||||
void AudioClose(SimpleAudio **ctx);
|
||||
|
@ -91,6 +91,7 @@ symbian {
|
||||
# UI
|
||||
SOURCES += $$P/UI/*Screen.cpp \
|
||||
$$P/UI/*Screens.cpp \
|
||||
$$P/UI/BackgroundAudio.cpp \
|
||||
$$P/UI/Store.cpp \
|
||||
$$P/UI/GamepadEmu.cpp \
|
||||
$$P/UI/GameInfoCache.cpp \
|
||||
|
208
UI/BackgroundAudio.cpp
Normal file
208
UI/BackgroundAudio.cpp
Normal file
@ -0,0 +1,208 @@
|
||||
#include <string>
|
||||
#include "base/logging.h"
|
||||
#include "base/timeutil.h"
|
||||
#include "base/mutex.h"
|
||||
#include "native/file/chunk_file.h"
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/HW/SimpleAudioDec.h"
|
||||
#include "Common/FixedSizeQueue.h"
|
||||
#include "GameInfoCache.h"
|
||||
|
||||
// Really simple looping in-memory AT3 player that also takes care of reading the file format.
|
||||
// Turns out that AT3 files used for this are modified WAVE files so fairly easy to parse.
|
||||
class AT3PlusReader {
|
||||
public:
|
||||
AT3PlusReader(const std::string &data)
|
||||
: data_(data),
|
||||
raw_offset_(0),
|
||||
file_((const uint8_t *)&data[0],
|
||||
(int32_t)data.size()),
|
||||
raw_data_(0),
|
||||
raw_data_size_(0),
|
||||
buffer_(0),
|
||||
decoder_(0) {
|
||||
|
||||
// Normally 8k but let's be safe.
|
||||
buffer_ = new short[32 * 1024];
|
||||
|
||||
int codec = PSP_CODEC_AT3PLUS;
|
||||
u8 at3_extradata[16];
|
||||
|
||||
int num_channels, sample_rate, numFrames, samplesPerSec, avgBytesPerSec, Nothing;
|
||||
if (file_.descend('RIFF')) {
|
||||
file_.readInt(); //get past 'WAVE'
|
||||
if (file_.descend('fmt ')) { //enter the format chunk
|
||||
int temp = file_.readInt();
|
||||
int format = temp & 0xFFFF;
|
||||
switch (format) {
|
||||
case 0xFFFE:
|
||||
codec = PSP_CODEC_AT3PLUS;
|
||||
break;
|
||||
case 0x270:
|
||||
codec = PSP_CODEC_AT3;
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(HLE, "Unexpected SND0.AT3 format %04x", format);
|
||||
return;
|
||||
}
|
||||
|
||||
num_channels = temp >> 16;
|
||||
|
||||
samplesPerSec = file_.readInt();
|
||||
avgBytesPerSec = file_.readInt();
|
||||
|
||||
temp = file_.readInt();
|
||||
raw_bytes_per_frame_ = temp & 0xFFFF;
|
||||
Nothing = temp >> 16;
|
||||
|
||||
if (codec == PSP_CODEC_AT3) {
|
||||
// The first two bytes are actually not useful part of the extradata.
|
||||
// We already read 16 bytes, so make sure there's enough left.
|
||||
if (file_.getCurrentChunkSize() >= 32) {
|
||||
file_.readData(at3_extradata, 16);
|
||||
} else {
|
||||
memset(at3_extradata, 0, sizeof(at3_extradata));
|
||||
}
|
||||
}
|
||||
file_.ascend();
|
||||
// ILOG("got fmt data: %i", samplesPerSec);
|
||||
} else {
|
||||
ELOG("Error - no format chunk in wav");
|
||||
file_.ascend();
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_.descend('data')) { //enter the data chunk
|
||||
int numBytes = file_.getCurrentChunkSize();
|
||||
numFrames = numBytes / raw_bytes_per_frame_; // numFrames
|
||||
|
||||
raw_data_ = (uint8_t *)malloc(numBytes);
|
||||
raw_data_size_ = numBytes;
|
||||
if (/*raw_bytes_per_frame_ == 280 && */ num_channels == 2) {
|
||||
file_.readData(raw_data_, numBytes);
|
||||
} else {
|
||||
ELOG("Error - bad blockalign or channels");
|
||||
free(raw_data_);
|
||||
raw_data_ = 0;
|
||||
return;
|
||||
}
|
||||
file_.ascend();
|
||||
} else {
|
||||
ELOG("Error - no data chunk in wav");
|
||||
file_.ascend();
|
||||
return;
|
||||
}
|
||||
file_.ascend();
|
||||
} else {
|
||||
ELOG("Could not descend into RIFF file");
|
||||
return;
|
||||
}
|
||||
sample_rate = samplesPerSec;
|
||||
decoder_ = new SimpleAudio(codec, sample_rate, num_channels);
|
||||
if (codec == PSP_CODEC_AT3) {
|
||||
decoder_->SetExtraData(&at3_extradata[2], 14, raw_bytes_per_frame_);
|
||||
}
|
||||
ILOG("read ATRAC, frames: %i, rate %i", numFrames, sample_rate);
|
||||
}
|
||||
|
||||
~AT3PlusReader() {
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
free(raw_data_);
|
||||
raw_data_ = 0;
|
||||
delete[] buffer_;
|
||||
buffer_ = 0;
|
||||
delete decoder_;
|
||||
decoder_ = 0;
|
||||
}
|
||||
|
||||
bool IsOK() { return raw_data_ != 0; }
|
||||
|
||||
bool Read(short *buffer, int len) {
|
||||
if (!raw_data_)
|
||||
return false;
|
||||
while (bgQueue.size() < len * 2) {
|
||||
int outBytes;
|
||||
decoder_->Decode(raw_data_ + raw_offset_, raw_bytes_per_frame_, (uint8_t *)buffer_, &outBytes);
|
||||
if (!outBytes)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < outBytes / 2; i++) {
|
||||
bgQueue.push(buffer_[i]);
|
||||
}
|
||||
|
||||
// loop!
|
||||
raw_offset_ += raw_bytes_per_frame_;
|
||||
if (raw_offset_ >= raw_data_size_) {
|
||||
raw_offset_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < len * 2; i++) {
|
||||
buffer[i] = bgQueue.pop_front();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string &data_;
|
||||
ChunkFile file_;
|
||||
uint8_t *raw_data_;
|
||||
int raw_data_size_;
|
||||
int raw_offset_;
|
||||
int raw_bytes_per_frame_;
|
||||
FixedSizeQueue<s16, 128 * 1024> bgQueue;
|
||||
short *buffer_;
|
||||
SimpleAudio *decoder_;
|
||||
};
|
||||
|
||||
static recursive_mutex bgMutex;
|
||||
static std::string bgGamePath;
|
||||
static int playbackOffset;
|
||||
static AT3PlusReader *at3Reader;
|
||||
static double gameLastChanged;
|
||||
|
||||
void SetBackgroundAudioGame(const std::string &path) {
|
||||
time_update();
|
||||
|
||||
lock_guard lock(bgMutex);
|
||||
if (path == bgGamePath) {
|
||||
// Do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
gameLastChanged = time_now_d();
|
||||
if (at3Reader) {
|
||||
at3Reader->Shutdown();
|
||||
delete at3Reader;
|
||||
at3Reader = 0;
|
||||
}
|
||||
playbackOffset = 0;
|
||||
bgGamePath = path;
|
||||
}
|
||||
|
||||
int MixBackgroundAudio(short *buffer, int size) {
|
||||
time_update();
|
||||
|
||||
lock_guard lock(bgMutex);
|
||||
// If there's a game, and some time has passed since the selected game
|
||||
// last changed... (to prevent crazy amount of reads when skipping through a list)
|
||||
if (!at3Reader && bgGamePath.size() && (time_now_d() - gameLastChanged > 0.5)) {
|
||||
// Grab some audio from the current game and play it.
|
||||
GameInfo *gameInfo = g_gameInfoCache.GetInfo(bgGamePath, GAMEINFO_WANTSND);
|
||||
if (!gameInfo)
|
||||
return 0;
|
||||
|
||||
if (gameInfo->sndFileData.size()) {
|
||||
const std::string &data = gameInfo->sndFileData;
|
||||
at3Reader = new AT3PlusReader(data);
|
||||
}
|
||||
}
|
||||
|
||||
if (!at3Reader || !at3Reader->Read(buffer, size)) {
|
||||
memset(buffer, 0, size * 2 * sizeof(s16));
|
||||
}
|
||||
return 0;
|
||||
}
|
6
UI/BackgroundAudio.h
Normal file
6
UI/BackgroundAudio.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
void SetBackgroundAudioGame(const std::string &path);
|
||||
int MixBackgroundAudio(short *buffer, int size);
|
@ -576,12 +576,15 @@ GameInfo *GameInfoCache::GetInfo(const std::string &gamePath, int wantFlags) {
|
||||
}
|
||||
if (info->iconDataLoaded) {
|
||||
SetupTexture(info, info->iconTextureData, info->iconTexture, info->timeIconWasLoaded);
|
||||
info->iconDataLoaded = false;
|
||||
}
|
||||
if (info->pic0DataLoaded) {
|
||||
SetupTexture(info, info->pic0TextureData, info->pic0Texture, info->timePic0WasLoaded);
|
||||
info->pic0DataLoaded = false;
|
||||
}
|
||||
if (info->pic1DataLoaded) {
|
||||
SetupTexture(info, info->pic1TextureData, info->pic1Texture, info->timePic1WasLoaded);
|
||||
info->pic1DataLoaded = false;
|
||||
}
|
||||
iter->second->lastAccessedTime = time_now_d();
|
||||
return iter->second;
|
||||
|
@ -31,9 +31,19 @@
|
||||
#include "UI/GameInfoCache.h"
|
||||
#include "UI/MiscScreens.h"
|
||||
#include "UI/MainScreen.h"
|
||||
#include "UI/BackgroundAudio.h"
|
||||
|
||||
#include "Core/Host.h"
|
||||
#include "Core/Config.h"
|
||||
|
||||
GameScreen::GameScreen(const std::string &gamePath) : UIDialogScreenWithGameBackground(gamePath) {
|
||||
SetBackgroundAudioGame(gamePath);
|
||||
}
|
||||
|
||||
GameScreen::~GameScreen() {
|
||||
SetBackgroundAudioGame("");
|
||||
}
|
||||
|
||||
void GameScreen::CreateViews() {
|
||||
GameInfo *info = g_gameInfoCache.GetInfo(gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
|
||||
|
||||
|
@ -29,7 +29,8 @@
|
||||
|
||||
class GameScreen : public UIDialogScreenWithGameBackground {
|
||||
public:
|
||||
GameScreen(const std::string &gamePath) : UIDialogScreenWithGameBackground(gamePath) {}
|
||||
GameScreen(const std::string &gamePath);
|
||||
~GameScreen();
|
||||
|
||||
virtual void update(InputState &input);
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "Core/Reporting.h"
|
||||
#include "Core/SaveState.h"
|
||||
|
||||
#include "UI/BackgroundAudio.h"
|
||||
#include "UI/EmuScreen.h"
|
||||
#include "UI/MainScreen.h"
|
||||
#include "UI/GameScreen.h"
|
||||
@ -235,7 +236,8 @@ void GameButton::Draw(UIContext &dc) {
|
||||
if (HasFocus()) {
|
||||
dc.Draw()->Flush();
|
||||
dc.RebindTexture();
|
||||
dc.Draw()->DrawImage4Grid(dc.theme->dropShadow4Grid, x - dropsize*1.5f, y - dropsize*1.5f, x+w + dropsize*1.5f, y+h+dropsize*1.5f, alphaMul(color, 1.0f), 1.0f);
|
||||
float pulse = sinf(time_now() * 7.0f) * 0.25 + 0.8;
|
||||
dc.Draw()->DrawImage4Grid(dc.theme->dropShadow4Grid, x - dropsize*1.5f, y - dropsize*1.5f, x + w + dropsize*1.5f, y + h + dropsize*1.5f, alphaMul(color, pulse), 1.0f);
|
||||
dc.Draw()->Flush();
|
||||
} else {
|
||||
dc.Draw()->Flush();
|
||||
@ -702,10 +704,16 @@ UI::EventReturn GameBrowser::NavigateClick(UI::EventParams &e) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
MainScreen::MainScreen() : highlightProgress_(0.0f), prevHighlightProgress_(0.0f), backFromStore_(false) {
|
||||
MainScreen::MainScreen() : highlightProgress_(0.0f), prevHighlightProgress_(0.0f), backFromStore_(false), lockBackgroundAudio_(false) {
|
||||
System_SendMessage("event", "mainscreen");
|
||||
SetBackgroundAudioGame("");
|
||||
}
|
||||
|
||||
MainScreen::~MainScreen() {
|
||||
SetBackgroundAudioGame("");
|
||||
}
|
||||
|
||||
|
||||
void MainScreen::CreateViews() {
|
||||
// Information in the top left.
|
||||
// Back button to the bottom left.
|
||||
@ -878,6 +886,7 @@ void MainScreen::sendMessage(const char *message, const char *value) {
|
||||
|
||||
if (!strcmp(message, "boot")) {
|
||||
screenManager()->switchScreen(new EmuScreen(value));
|
||||
SetBackgroundAudioGame(value);
|
||||
}
|
||||
if (!strcmp(message, "control mapping")) {
|
||||
UpdateUIState(UISTATE_MENU);
|
||||
@ -963,17 +972,19 @@ bool MainScreen::DrawBackgroundFor(UIContext &dc, const std::string &gamePath, f
|
||||
}
|
||||
|
||||
UI::EventReturn MainScreen::OnGameSelected(UI::EventParams &e) {
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
std::string path = ReplaceAll(e.s, "\\", "/");
|
||||
#else
|
||||
std::string path = e.s;
|
||||
#endif
|
||||
SetBackgroundAudioGame(path);
|
||||
lockBackgroundAudio_ = true;
|
||||
screenManager()->push(new GameScreen(path));
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn MainScreen::OnGameHighlight(UI::EventParams &e) {
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
std::string path = ReplaceAll(e.s, "\\", "/");
|
||||
#else
|
||||
std::string path = e.s;
|
||||
@ -990,11 +1001,15 @@ UI::EventReturn MainScreen::OnGameHighlight(UI::EventParams &e) {
|
||||
highlightedGamePath_ = path;
|
||||
highlightProgress_ = 0.0f;
|
||||
}
|
||||
|
||||
if ((!highlightedGamePath_.empty() || e.a == FF_LOSTFOCUS) && !lockBackgroundAudio_)
|
||||
SetBackgroundAudioGame(highlightedGamePath_);
|
||||
lockBackgroundAudio_ = false;
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn MainScreen::OnGameSelectedInstant(UI::EventParams &e) {
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
std::string path = ReplaceAll(e.s, "\\", "/");
|
||||
#else
|
||||
std::string path = e.s;
|
||||
|
@ -29,6 +29,7 @@
|
||||
class MainScreen : public UIScreenWithBackground {
|
||||
public:
|
||||
MainScreen();
|
||||
~MainScreen();
|
||||
|
||||
virtual bool isTopLevel() const { return true; }
|
||||
|
||||
@ -68,6 +69,7 @@ private:
|
||||
std::string prevHighlightedGamePath_;
|
||||
float highlightProgress_;
|
||||
float prevHighlightProgress_;
|
||||
bool lockBackgroundAudio_;
|
||||
bool backFromStore_;
|
||||
};
|
||||
|
||||
|
@ -86,6 +86,7 @@
|
||||
#include "UI/OnScreenDisplay.h"
|
||||
#include "UI/MiscScreens.h"
|
||||
#include "UI/TiltEventProcessor.h"
|
||||
#include "UI/BackgroundAudio.h"
|
||||
|
||||
#if !defined(MOBILE_DEVICE)
|
||||
#include "Common/KeyMap.h"
|
||||
@ -207,8 +208,8 @@ int NativeMix(short *audio, int num_samples) {
|
||||
if (g_mixer && GetUIState() == UISTATE_INGAME) {
|
||||
num_samples = g_mixer->Mix(audio, num_samples);
|
||||
} else {
|
||||
// MixBackgroundAudio(audio, num_samples);
|
||||
memset(audio, 0, num_samples * 2 * sizeof(short));
|
||||
MixBackgroundAudio(audio, num_samples);
|
||||
// memset(audio, 0, num_samples * 2 * sizeof(short));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -19,6 +19,7 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BackgroundAudio.cpp" />
|
||||
<ClCompile Include="ControlMappingScreen.cpp" />
|
||||
<ClCompile Include="CwCheatScreen.cpp" />
|
||||
<ClCompile Include="DevScreens.cpp" />
|
||||
@ -41,6 +42,7 @@
|
||||
<ClCompile Include="ui_atlas.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BackgroundAudio.h" />
|
||||
<ClInclude Include="ControlMappingScreen.h" />
|
||||
<ClInclude Include="DevScreens.h" />
|
||||
<ClInclude Include="EmuScreen.h" />
|
||||
|
@ -47,6 +47,7 @@
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Store.cpp" />
|
||||
<ClCompile Include="BackgroundAudio.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="GameInfoCache.h" />
|
||||
@ -94,10 +95,11 @@
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Store.h" />
|
||||
<ClInclude Include="BackgroundAudio.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Screens">
|
||||
<UniqueIdentifier>{faee5dce-633b-4ba6-b19d-ea70ee3c1c38}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
@ -279,6 +279,7 @@ LOCAL_MODULE := ppsspp_jni
|
||||
LOCAL_SRC_FILES := \
|
||||
$(EXEC_AND_LIB_FILES) \
|
||||
$(SRC)/native/android/app-android.cpp \
|
||||
$(SRC)/UI/BackgroundAudio.cpp \
|
||||
$(SRC)/UI/DevScreens.cpp \
|
||||
$(SRC)/UI/EmuScreen.cpp \
|
||||
$(SRC)/UI/MainScreen.cpp \
|
||||
|
2
native
2
native
@ -1 +1 @@
|
||||
Subproject commit bddebfceebd1b8e4c57ac300c4deddb526cdea08
|
||||
Subproject commit 8685d02e6d44cbe327ab49f69efbcc1275771d6f
|
Loading…
Reference in New Issue
Block a user