mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-17 04:39:34 +00:00
Play the game's SND0.AT3 when a game is selected in the menu and on the "game screen".
This commit is contained in:
parent
12cef8fa80
commit
cefc0bc96f
@ -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;
|
||||
}
|
||||
|
@ -61,13 +61,7 @@ bool SimpleAudio::GetAudioCodecID(int audioType) {
|
||||
}
|
||||
|
||||
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) {
|
||||
: codec_(0), codecCtx_(0), swrCtx_(0), ctxPtr(0xFFFFFFFF), audioType(audioType), outSamples(0), srcPos(0), wanted_resample_freq(44100) {
|
||||
Init();
|
||||
}
|
||||
|
||||
@ -240,18 +234,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 +339,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,
|
||||
@ -49,19 +44,22 @@ enum {
|
||||
class SimpleAudio {
|
||||
public:
|
||||
SimpleAudio(int audioType);
|
||||
SimpleAudio(u32 ctxPtr, int audioType);
|
||||
~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
|
||||
|
||||
// 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:
|
||||
@ -73,13 +71,11 @@ private:
|
||||
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
|
||||
};
|
||||
|
||||
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 \
|
||||
|
186
UI/BackgroundAudio.cpp
Normal file
186
UI/BackgroundAudio.cpp
Normal file
@ -0,0 +1,186 @@
|
||||
#include <string>
|
||||
#include "base/logging.h"
|
||||
#include "base/timeutil.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;
|
||||
|
||||
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:
|
||||
// Dunno? 3rd Birthday has this.
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
num_channels = temp >> 16;
|
||||
|
||||
samplesPerSec = file_.readInt();
|
||||
avgBytesPerSec = file_.readInt();
|
||||
|
||||
temp = file_.readInt();
|
||||
raw_bytes_per_frame_ = temp & 0xFFFF;
|
||||
Nothing = temp >> 16;
|
||||
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);
|
||||
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; }
|
||||
|
||||
void Read(short *buffer, int len) {
|
||||
if (!raw_data_)
|
||||
return;
|
||||
while (bgQueue.size() < len * 2) {
|
||||
int outBytes;
|
||||
decoder_->Decode(raw_data_ + raw_offset_, raw_bytes_per_frame_, (uint8_t *)buffer_, &outBytes);
|
||||
if (!outBytes)
|
||||
return;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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 std::string bgGamePath;
|
||||
static int playbackOffset;
|
||||
static AT3PlusReader *at3Reader;
|
||||
static double gameLastChanged;
|
||||
|
||||
void SetBackgroundAudioGame(const std::string &path) {
|
||||
if (path == bgGamePath) {
|
||||
// Do nothing
|
||||
return;
|
||||
}
|
||||
time_update();
|
||||
gameLastChanged = time_now_d();
|
||||
if (at3Reader) {
|
||||
at3Reader->Shutdown();
|
||||
delete at3Reader;
|
||||
at3Reader = 0;
|
||||
}
|
||||
playbackOffset = 0;
|
||||
bgGamePath = path;
|
||||
}
|
||||
|
||||
int MixBackgroundAudio(short *buffer, int size) {
|
||||
time_update();
|
||||
// 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);
|
||||
} else {
|
||||
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);
|
@ -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"
|
||||
@ -704,8 +705,14 @@ UI::EventReturn GameBrowser::NavigateClick(UI::EventParams &e) {
|
||||
|
||||
MainScreen::MainScreen() : highlightProgress_(0.0f), prevHighlightProgress_(0.0f), backFromStore_(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 +885,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);
|
||||
@ -990,6 +998,7 @@ UI::EventReturn MainScreen::OnGameHighlight(UI::EventParams &e) {
|
||||
highlightedGamePath_ = path;
|
||||
highlightProgress_ = 0.0f;
|
||||
}
|
||||
SetBackgroundAudioGame(highlightedGamePath_);
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
class MainScreen : public UIScreenWithBackground {
|
||||
public:
|
||||
MainScreen();
|
||||
~MainScreen();
|
||||
|
||||
virtual bool isTopLevel() const { return true; }
|
||||
|
||||
|
@ -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>
|
Loading…
x
Reference in New Issue
Block a user