2012-11-01 15:19:01 +00:00
|
|
|
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
2012-11-04 22:01:49 +00:00
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official git repository and contact information can be found at
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
|
|
|
// SAS is a software mixing engine that runs on the Media Engine CPU. We just HLE it.
|
|
|
|
// This is a very rough implementation that needs lots of work.
|
|
|
|
//
|
2012-12-17 17:05:10 +00:00
|
|
|
// This file just contains the API, the real stuff is in HW/SasAudio.cpp/h.
|
|
|
|
//
|
2012-11-01 15:19:01 +00:00
|
|
|
// JPCSP is, as it often is, a pretty good reference although I didn't actually use it much yet:
|
|
|
|
// http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/sceSasCore.java
|
|
|
|
|
|
|
|
#include "base/basictypes.h"
|
2012-12-16 19:40:49 +00:00
|
|
|
#include "Log.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
#include "HLE.h"
|
|
|
|
#include "../MIPS/MIPS.h"
|
2012-12-16 19:40:49 +00:00
|
|
|
#include "../HW/SasAudio.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
#include "sceSas.h"
|
|
|
|
#include "sceKernel.h"
|
|
|
|
|
2012-12-17 17:05:10 +00:00
|
|
|
enum {
|
|
|
|
ERROR_SAS_INVALID_VOICE = 0x80420010,
|
|
|
|
ERROR_SAS_INVALID_ADSR_CURVE_MODE = 0x80420013,
|
|
|
|
ERROR_SAS_INVALID_PARAMETER = 0x80420014,
|
|
|
|
ERROR_SAS_VOICE_PAUSED = 0x80420016,
|
|
|
|
ERROR_SAS_INVALID_SIZE = 0x8042001A,
|
|
|
|
ERROR_SAS_BUSY = 0x80420030,
|
|
|
|
ERROR_SAS_NOT_INIT = 0x80420100,
|
|
|
|
};
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
// TODO - allow more than one, associating each with one Core pointer (passed in to all the functions)
|
|
|
|
// No known games use more than one instance of Sas though.
|
2012-12-17 20:43:31 +00:00
|
|
|
SasInstance *sas;
|
|
|
|
|
|
|
|
void __SasInit() {
|
|
|
|
sas = new SasInstance();
|
|
|
|
}
|
|
|
|
|
2012-12-28 08:05:54 +00:00
|
|
|
void __SasDoState(PointerWrap &p) {
|
|
|
|
if (sas != NULL) {
|
|
|
|
sas->DoState(p);
|
|
|
|
}
|
|
|
|
p.DoMarker("sceSas");
|
|
|
|
}
|
|
|
|
|
2012-12-17 20:43:31 +00:00
|
|
|
void __SasShutdown() {
|
|
|
|
delete sas;
|
|
|
|
sas = 0;
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
|
2012-12-07 04:45:16 +00:00
|
|
|
u32 sceSasInit(u32 core, u32 grainSize, u32 maxVoices, u32 outputMode, u32 sampleRate)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
INFO_LOG(HLE,"sceSasInit(%08x, %i, %i, %i, %i)", core, grainSize, maxVoices, outputMode, sampleRate);
|
2012-12-17 20:43:31 +00:00
|
|
|
sas->SetGrainSize(grainSize);
|
|
|
|
sas->maxVoices = maxVoices;
|
|
|
|
sas->sampleRate = sampleRate;
|
|
|
|
sas->outputMode = outputMode;
|
2012-11-01 15:19:01 +00:00
|
|
|
for (int i = 0; i < 32; i++) {
|
2012-12-17 20:43:31 +00:00
|
|
|
sas->voices[i].playing = false;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-12-07 04:45:16 +00:00
|
|
|
u32 sceSasGetEndFlag(u32 core)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
u32 endFlag = 0;
|
2012-12-17 20:43:31 +00:00
|
|
|
for (int i = 0; i < sas->maxVoices; i++) {
|
|
|
|
if (!sas->voices[i].playing)
|
2013-01-23 06:50:36 +00:00
|
|
|
endFlag |= (1 << i);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasGetEndFlag(%08x)", endFlag);
|
2012-11-01 15:19:01 +00:00
|
|
|
return endFlag;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Runs the mixer
|
2012-12-16 19:40:49 +00:00
|
|
|
u32 _sceSasCore(u32 core, u32 outAddr)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 08:19:44 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasCore(%08x, %08x)", core, outAddr);
|
2012-12-17 17:05:10 +00:00
|
|
|
if (!Memory::IsValidAddress(outAddr)) {
|
|
|
|
return ERROR_SAS_INVALID_PARAMETER;
|
|
|
|
}
|
2012-12-17 20:43:31 +00:00
|
|
|
Memory::Memset(outAddr, 0, sas->GetGrainSize() * 2 * 2);
|
|
|
|
sas->Mix(outAddr);
|
2012-12-16 19:40:49 +00:00
|
|
|
return 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Another way of running the mixer, what was the difference again?
|
2013-01-23 06:50:36 +00:00
|
|
|
u32 _sceSasCoreWithMix(u32 core, u32 outAddr, int leftVolume, int rightVolume)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 08:19:44 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasCoreWithMix(%08x, %08x, %i, %i)", core , outAddr, leftVolume, rightVolume);
|
2012-12-17 17:05:10 +00:00
|
|
|
if (!Memory::IsValidAddress(outAddr)) {
|
|
|
|
return ERROR_SAS_INVALID_PARAMETER;
|
|
|
|
}
|
2012-12-17 20:43:31 +00:00
|
|
|
sas->Mix(outAddr);
|
2012-12-16 19:40:49 +00:00
|
|
|
return 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-16 19:40:49 +00:00
|
|
|
u32 sceSasSetVoice(u32 core, int voiceNum, u32 vagAddr, int size, int loop)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasSetVoice(%08x, %i, %08x, %i, %i)", core, voiceNum, vagAddr, size, loop);
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-01-23 06:50:36 +00:00
|
|
|
if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) {
|
2012-12-15 23:04:46 +00:00
|
|
|
WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum);
|
2012-12-17 17:05:10 +00:00
|
|
|
return ERROR_SAS_INVALID_VOICE;
|
2012-12-15 23:04:46 +00:00
|
|
|
}
|
|
|
|
|
2012-12-20 21:44:28 +00:00
|
|
|
if (!Memory::IsValidAddress(vagAddr)) {
|
|
|
|
ERROR_LOG(HLE, "Ignoring invalid VAG audio address %08x", vagAddr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-23 06:50:36 +00:00
|
|
|
if (size <= 0 || (size & 0xF) != 0) {
|
|
|
|
WARN_LOG(HLE, "%s: invalid size %d", __FUNCTION__, size);
|
|
|
|
return ERROR_SAS_INVALID_SIZE;
|
|
|
|
}
|
|
|
|
|
2013-01-25 17:36:05 +00:00
|
|
|
u32 prevVagAddr = vagAddr;
|
2012-11-01 15:19:01 +00:00
|
|
|
//Real VAG header is 0x30 bytes behind the vagAddr
|
2012-12-17 20:43:31 +00:00
|
|
|
SasVoice &v = sas->voices[voiceNum];
|
2012-12-16 19:40:49 +00:00
|
|
|
v.type = VOICETYPE_VAG;
|
2012-11-01 15:19:01 +00:00
|
|
|
v.vagAddr = vagAddr;
|
2012-12-16 19:40:49 +00:00
|
|
|
v.vagSize = size;
|
2013-01-24 12:13:12 +00:00
|
|
|
v.loop = loop ? false : true;
|
2013-01-25 17:36:05 +00:00
|
|
|
v.ChangedParams(vagAddr == prevVagAddr);
|
2012-12-17 20:43:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 sceSasSetVoicePCM(u32 core, int voiceNum, u32 pcmAddr, int size, int loop)
|
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasSetVoicePCM(%08x, %i, %08x, %i, %i)", core, voiceNum, pcmAddr, size, loop);
|
|
|
|
|
|
|
|
if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) {
|
|
|
|
WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum);
|
|
|
|
return ERROR_SAS_INVALID_VOICE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Memory::IsValidAddress(pcmAddr)) {
|
|
|
|
ERROR_LOG(HLE, "Ignoring invalid PCM audio address %08x", pcmAddr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size <= 0 || size > 0x10000) {
|
|
|
|
WARN_LOG(HLE, "%s: invalid size %d", __FUNCTION__, size);
|
|
|
|
return ERROR_SAS_INVALID_SIZE;
|
|
|
|
}
|
|
|
|
|
2012-12-17 20:43:31 +00:00
|
|
|
SasVoice &v = sas->voices[voiceNum];
|
|
|
|
v.type = VOICETYPE_PCM;
|
|
|
|
v.pcmAddr = pcmAddr;
|
|
|
|
v.pcmSize = size;
|
2013-01-24 12:13:12 +00:00
|
|
|
v.loop = loop ? false : true;
|
2012-12-17 20:43:31 +00:00
|
|
|
v.playing = true;
|
2013-01-23 06:50:36 +00:00
|
|
|
v.ChangedParams(true);
|
2012-12-16 19:40:49 +00:00
|
|
|
return 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-17 17:05:10 +00:00
|
|
|
u32 sceSasGetPauseFlag(u32 core)
|
|
|
|
{
|
|
|
|
u32 pauseFlag = 0;
|
2012-12-17 20:43:31 +00:00
|
|
|
for (int i = 0; i < sas->maxVoices; i++) {
|
|
|
|
if (sas->voices[i].paused)
|
2013-01-23 06:50:36 +00:00
|
|
|
pauseFlag |= (1 << i);
|
2012-12-17 17:05:10 +00:00
|
|
|
}
|
2013-01-23 06:50:36 +00:00
|
|
|
|
|
|
|
DEBUG_LOG(HLE,"sceSasGetPauseFlag(%08x)", pauseFlag)
|
2012-12-17 17:05:10 +00:00
|
|
|
return pauseFlag;
|
|
|
|
}
|
|
|
|
|
2012-12-07 04:45:16 +00:00
|
|
|
u32 sceSasSetPause(u32 core, int voicebit, int pause)
|
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasSetPause(%08x, %08x, %i)", core, voicebit, pause);
|
|
|
|
for (int i = 0; voicebit != 0; i++, voicebit >>= 1) {
|
|
|
|
if (i < PSP_SAS_VOICES_MAX && i >= 0) {
|
2012-12-10 08:09:56 +00:00
|
|
|
if ((voicebit & 1) != 0)
|
2012-12-17 20:43:31 +00:00
|
|
|
sas->voices[i].paused = pause ? true : false;
|
2012-12-10 08:09:56 +00:00
|
|
|
}
|
|
|
|
// TODO: Correct error code? Mimana crashes otherwise.
|
|
|
|
else
|
2012-12-17 17:05:10 +00:00
|
|
|
return ERROR_SAS_INVALID_VOICE;
|
2012-12-07 04:45:16 +00:00
|
|
|
}
|
2012-12-10 08:09:56 +00:00
|
|
|
|
2012-12-07 04:45:16 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-12-16 19:40:49 +00:00
|
|
|
u32 sceSasSetVolume(u32 core, int voiceNum, int l, int r, int el, int er)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasSetVolume(%08x, %i, %i, %i, %i, %i)", core, voiceNum, l, r, el, er);
|
2012-12-15 23:04:46 +00:00
|
|
|
|
2013-01-23 06:50:36 +00:00
|
|
|
if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) {
|
2012-12-15 23:04:46 +00:00
|
|
|
WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum);
|
2012-12-17 17:05:10 +00:00
|
|
|
return ERROR_SAS_INVALID_VOICE;
|
2012-12-15 23:04:46 +00:00
|
|
|
}
|
|
|
|
|
2012-12-17 20:43:31 +00:00
|
|
|
SasVoice &v = sas->voices[voiceNum];
|
2012-11-01 15:19:01 +00:00
|
|
|
v.volumeLeft = l;
|
|
|
|
v.volumeRight = r;
|
2012-12-16 19:40:49 +00:00
|
|
|
return 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-16 19:40:49 +00:00
|
|
|
u32 sceSasSetPitch(u32 core, int voiceNum, int pitch)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasSetPitch(%08x, %i, %i)", core, voiceNum, pitch);
|
2012-12-15 23:04:46 +00:00
|
|
|
|
2013-01-23 06:50:36 +00:00
|
|
|
if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) {
|
2012-12-15 23:04:46 +00:00
|
|
|
WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum);
|
2012-12-17 17:05:10 +00:00
|
|
|
return ERROR_SAS_INVALID_VOICE;
|
2012-12-15 23:04:46 +00:00
|
|
|
}
|
|
|
|
|
2012-12-17 20:43:31 +00:00
|
|
|
SasVoice &v = sas->voices[voiceNum];
|
2012-11-01 15:19:01 +00:00
|
|
|
v.pitch = pitch;
|
2013-01-25 17:36:05 +00:00
|
|
|
v.ChangedParams(false);
|
2012-12-16 19:40:49 +00:00
|
|
|
return 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-16 19:40:49 +00:00
|
|
|
u32 sceSasSetKeyOn(u32 core, int voiceNum)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasSetKeyOn(%08x, %i)", core, voiceNum);
|
2012-12-15 23:04:46 +00:00
|
|
|
|
2013-01-23 06:50:36 +00:00
|
|
|
if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) {
|
2012-12-15 23:04:46 +00:00
|
|
|
WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum);
|
2012-12-17 17:05:10 +00:00
|
|
|
return ERROR_SAS_INVALID_VOICE;
|
2012-12-15 23:04:46 +00:00
|
|
|
}
|
|
|
|
|
2012-12-17 20:43:31 +00:00
|
|
|
SasVoice &v = sas->voices[voiceNum];
|
2013-01-23 06:50:36 +00:00
|
|
|
if (sas->voices[voiceNum].paused) {
|
|
|
|
return ERROR_SAS_VOICE_PAUSED;
|
|
|
|
}
|
|
|
|
|
2012-12-17 17:05:10 +00:00
|
|
|
v.KeyOn();
|
2012-12-16 19:40:49 +00:00
|
|
|
return 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// sceSasSetKeyOff can be used to start sounds, that just sound during the Release phase!
|
2012-12-16 19:40:49 +00:00
|
|
|
u32 sceSasSetKeyOff(u32 core, int voiceNum)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-03 23:16:34 +00:00
|
|
|
if (voiceNum == -1) {
|
|
|
|
// TODO: Some games (like Every Extend Extra) deliberately pass voiceNum = -1. Does that mean all voices? for now let's ignore.
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasSetKeyOff(%08x, %i) - voiceNum = -1???", core, voiceNum);
|
2013-01-03 23:16:34 +00:00
|
|
|
return 0;
|
|
|
|
} else if (voiceNum < 0 || voiceNum >= PSP_SAS_VOICES_MAX) {
|
2012-12-15 23:04:46 +00:00
|
|
|
WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum);
|
2012-12-17 17:05:10 +00:00
|
|
|
return ERROR_SAS_INVALID_VOICE;
|
2013-01-03 23:16:34 +00:00
|
|
|
} else {
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasSetKeyOff(%08x, %i)", core, voiceNum);
|
2013-01-03 23:16:34 +00:00
|
|
|
SasVoice &v = sas->voices[voiceNum];
|
2013-01-23 06:50:36 +00:00
|
|
|
if (sas->voices[voiceNum].paused) {
|
|
|
|
return ERROR_SAS_VOICE_PAUSED;
|
|
|
|
}
|
|
|
|
|
2013-01-03 23:16:34 +00:00
|
|
|
v.KeyOff();
|
|
|
|
return 0;
|
2012-12-15 23:04:46 +00:00
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-06 17:45:09 +00:00
|
|
|
u32 sceSasSetNoise(u32 core, int voiceNum, int freq)
|
2012-12-06 15:05:55 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasSetNoise(%08x, %i, %i)", core, voiceNum, freq);
|
2012-12-15 23:04:46 +00:00
|
|
|
|
2013-01-23 06:50:36 +00:00
|
|
|
if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) {
|
2012-12-15 23:04:46 +00:00
|
|
|
WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum);
|
2012-12-17 17:05:10 +00:00
|
|
|
return ERROR_SAS_INVALID_VOICE;
|
2012-12-15 23:04:46 +00:00
|
|
|
}
|
|
|
|
|
2012-12-17 20:43:31 +00:00
|
|
|
SasVoice &v = sas->voices[voiceNum];
|
2012-12-16 19:40:49 +00:00
|
|
|
v.type = VOICETYPE_NOISE;
|
|
|
|
v.noiseFreq = freq;
|
2013-01-23 06:50:36 +00:00
|
|
|
v.ChangedParams(true);
|
2012-12-07 04:45:16 +00:00
|
|
|
return 0;
|
2012-12-06 15:05:55 +00:00
|
|
|
}
|
|
|
|
|
2012-12-06 17:45:09 +00:00
|
|
|
u32 sceSasSetSL(u32 core, int voiceNum, int level)
|
2012-12-06 15:05:55 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasSetSL(%08x, %i, %i)", core, voiceNum, level);
|
2012-12-15 23:04:46 +00:00
|
|
|
|
2013-01-23 06:50:36 +00:00
|
|
|
if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) {
|
2012-12-15 23:04:46 +00:00
|
|
|
WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum);
|
2012-12-17 17:05:10 +00:00
|
|
|
return ERROR_SAS_INVALID_VOICE;
|
2012-12-15 23:04:46 +00:00
|
|
|
}
|
|
|
|
|
2012-12-17 20:43:31 +00:00
|
|
|
SasVoice &v = sas->voices[voiceNum];
|
2012-12-16 19:40:49 +00:00
|
|
|
v.envelope.sustainLevel = level;
|
2012-12-07 04:45:16 +00:00
|
|
|
return 0;
|
2012-12-06 15:05:55 +00:00
|
|
|
}
|
|
|
|
|
2013-01-23 06:50:36 +00:00
|
|
|
u32 sceSasSetADSR(u32 core, int voiceNum, int flag , int a, int d, int s, int r)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"0=sceSasSetADSR(%08x, %i, %i, %08x, %08x, %08x, %08x)",core, voiceNum, flag, a, d, s, r)
|
2012-12-15 23:04:46 +00:00
|
|
|
|
2013-01-23 06:50:36 +00:00
|
|
|
if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) {
|
2012-12-15 23:04:46 +00:00
|
|
|
WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum);
|
2012-12-17 17:05:10 +00:00
|
|
|
return ERROR_SAS_INVALID_VOICE;
|
2012-12-15 23:04:46 +00:00
|
|
|
}
|
|
|
|
|
2012-12-17 20:43:31 +00:00
|
|
|
SasVoice &v = sas->voices[voiceNum];
|
2012-12-16 19:40:49 +00:00
|
|
|
if ((flag & 0x1) != 0) v.envelope.attackRate = a;
|
|
|
|
if ((flag & 0x2) != 0) v.envelope.decayRate = d;
|
|
|
|
if ((flag & 0x4) != 0) v.envelope.sustainRate = s;
|
|
|
|
if ((flag & 0x8) != 0) v.envelope.releaseRate = r;
|
2012-12-05 15:51:10 +00:00
|
|
|
return 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-05 16:09:01 +00:00
|
|
|
u32 sceSasSetADSRMode(u32 core, int voiceNum,int flag ,int a, int d, int s, int r)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasSetADSRMode(%08x, %i, %i, %08x, %08x, %08x, %08x)",core, voiceNum, flag, a,d,s,r)
|
2012-12-15 23:04:46 +00:00
|
|
|
|
2013-01-23 06:50:36 +00:00
|
|
|
if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) {
|
2012-12-15 23:04:46 +00:00
|
|
|
WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum);
|
2012-12-17 17:05:10 +00:00
|
|
|
return ERROR_SAS_INVALID_VOICE;
|
2012-12-15 23:04:46 +00:00
|
|
|
}
|
|
|
|
|
2012-12-17 20:43:31 +00:00
|
|
|
SasVoice &v = sas->voices[voiceNum];
|
2012-12-16 19:40:49 +00:00
|
|
|
if ((flag & 0x1) != 0) v.envelope.attackType = a;
|
|
|
|
if ((flag & 0x2) != 0) v.envelope.decayType = d;
|
|
|
|
if ((flag & 0x4) != 0) v.envelope.sustainType = s;
|
|
|
|
if ((flag & 0x8) != 0) v.envelope.releaseType = r;
|
2012-12-07 04:45:16 +00:00
|
|
|
return 0 ;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-06 14:37:41 +00:00
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
u32 sceSasSetSimpleADSR(u32 core, u32 voiceNum, u32 ADSREnv1, u32 ADSREnv2)
|
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sasSetSimpleADSR(%08x, %i, %08x, %08x)", core, voiceNum, ADSREnv1, ADSREnv2);
|
2012-12-17 20:43:31 +00:00
|
|
|
SasVoice &v = sas->voices[voiceNum];
|
2012-12-16 19:40:49 +00:00
|
|
|
v.envelope.SetSimpleEnvelope(ADSREnv1 & 0xFFFF, ADSREnv2 & 0xFFFF);
|
2012-11-01 15:19:01 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 sceSasGetEnvelopeHeight(u32 core, u32 voiceNum)
|
|
|
|
{
|
|
|
|
// Spam reduction
|
2013-01-23 06:50:36 +00:00
|
|
|
if (voiceNum == 17) {
|
|
|
|
DEBUG_LOG(HLE,"sceSasGetEnvelopeHeight(%08x, %i)", core, voiceNum);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
2013-01-23 06:50:36 +00:00
|
|
|
if (voiceNum >= PSP_SAS_VOICES_MAX) {
|
2012-12-17 17:05:10 +00:00
|
|
|
WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum);
|
|
|
|
return ERROR_SAS_INVALID_VOICE;
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2012-12-17 20:43:31 +00:00
|
|
|
SasVoice &v = sas->voices[voiceNum];
|
2012-12-17 17:05:10 +00:00
|
|
|
return v.envelope.GetHeight();
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-16 19:40:49 +00:00
|
|
|
u32 sceSasRevType(u32 core, int type)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasRevType(%08x, %i)", core, type);
|
2012-12-17 20:43:31 +00:00
|
|
|
sas->waveformEffect.type = type;
|
2012-12-16 19:40:49 +00:00
|
|
|
return 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-16 19:40:49 +00:00
|
|
|
u32 sceSasRevParam(u32 core, int delay, int feedback)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasRevParam(%08x, %i, %i)", core, delay, feedback);
|
2012-12-17 20:43:31 +00:00
|
|
|
sas->waveformEffect.delay = delay;
|
|
|
|
sas->waveformEffect.feedback = feedback;
|
2012-12-16 19:40:49 +00:00
|
|
|
return 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-16 19:40:49 +00:00
|
|
|
u32 sceSasRevEVOL(u32 core, int lv, int rv)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasRevEVOL(%08x, %i, %i)", core, lv, rv);
|
2012-12-17 20:43:31 +00:00
|
|
|
sas->waveformEffect.leftVol = lv;
|
|
|
|
sas->waveformEffect.rightVol = rv;
|
2012-12-16 19:40:49 +00:00
|
|
|
return 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
2012-12-05 11:50:25 +00:00
|
|
|
|
2012-12-16 19:40:49 +00:00
|
|
|
u32 sceSasRevVON(u32 core, int dry, int wet)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasRevVON(%08x, %i, %i)", core, dry, wet);
|
2012-12-17 20:43:31 +00:00
|
|
|
sas->waveformEffect.isDryOn = (dry > 0);
|
|
|
|
sas->waveformEffect.isWetOn = (wet > 0);
|
2012-12-16 19:40:49 +00:00
|
|
|
return 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-07 04:45:16 +00:00
|
|
|
u32 sceSasGetGrain(u32 core)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasGetGrain(%08x)", core);
|
2012-12-17 20:43:31 +00:00
|
|
|
return sas->GetGrainSize();
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-07 04:45:16 +00:00
|
|
|
u32 sceSasSetGrain(u32 core, int grain)
|
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
INFO_LOG(HLE,"sceSasSetGrain(%08x, %i)", core, grain);
|
2012-12-17 20:43:31 +00:00
|
|
|
sas->SetGrainSize(grain);
|
2012-12-08 06:13:41 +00:00
|
|
|
return 0;
|
2012-12-07 04:45:16 +00:00
|
|
|
}
|
|
|
|
|
2012-12-08 23:56:21 +00:00
|
|
|
u32 sceSasGetOutputMode(u32 core)
|
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasGetOutputMode(%08x)", core);
|
2012-12-17 20:43:31 +00:00
|
|
|
return sas->outputMode;
|
2012-12-08 23:56:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
u32 sceSasSetOutputMode(u32 core, u32 outputMode)
|
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasSetOutputMode(%08x, %i)", core, outputMode);
|
2012-12-17 20:43:31 +00:00
|
|
|
sas->outputMode = outputMode;
|
2012-12-08 23:56:21 +00:00
|
|
|
return 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-07 04:45:16 +00:00
|
|
|
u32 sceSasGetAllEnvelopeHeights(u32 core, u32 heightsAddr)
|
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
DEBUG_LOG(HLE,"sceSasGetAllEnvelopeHeights(%08x, %i)", core, heightsAddr);
|
2012-12-09 08:27:21 +00:00
|
|
|
if (Memory::IsValidAddress(heightsAddr)) {
|
2012-12-17 20:43:31 +00:00
|
|
|
for (int i = 0; i < PSP_SAS_VOICES_MAX; i++) {
|
|
|
|
int voiceHeight = sas->voices[i].envelope.GetHeight();
|
2012-12-09 08:27:21 +00:00
|
|
|
Memory::Write_U32(voiceHeight, heightsAddr + i * 4);
|
|
|
|
}
|
2012-12-07 04:45:16 +00:00
|
|
|
}
|
2012-12-09 08:27:21 +00:00
|
|
|
return 0;
|
2012-12-07 04:45:16 +00:00
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2012-12-17 17:05:10 +00:00
|
|
|
u32 sceSasSetTriangularWave(u32 sasCore, int voice, int unknown)
|
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
ERROR_LOG(HLE,"UNIMPL sceSasSetTriangularWave(%08x, %i, %i)", sasCore, voice, unknown);
|
2012-12-17 17:05:10 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 sceSasSetSteepWave(u32 sasCore, int voice, int unknown)
|
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
ERROR_LOG(HLE,"UNIMPL sceSasSetSteepWave(%08x, %i, %i)", sasCore, voice, unknown);
|
2012-12-17 17:05:10 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
const HLEFunction sceSasCore[] =
|
|
|
|
{
|
2013-01-23 06:50:36 +00:00
|
|
|
{0x42778a9f, WrapU_UUUUU<sceSasInit>, "__sceSasInit"},
|
2012-12-16 19:40:49 +00:00
|
|
|
{0xa3589d81, WrapU_UU<_sceSasCore>, "__sceSasCore"},
|
2013-01-23 06:50:36 +00:00
|
|
|
{0x50a14dfc, WrapU_UUII<_sceSasCoreWithMix>, "__sceSasCoreWithMix"},
|
2012-12-17 17:05:10 +00:00
|
|
|
{0x68a46b95, WrapU_U<sceSasGetEndFlag>, "__sceSasGetEndFlag"},
|
2012-12-16 19:40:49 +00:00
|
|
|
{0x440ca7d8, WrapU_UIIIII<sceSasSetVolume>, "__sceSasSetVolume"},
|
|
|
|
{0xad84d37f, WrapU_UII<sceSasSetPitch>, "__sceSasSetPitch"},
|
2012-12-17 17:05:10 +00:00
|
|
|
{0x99944089, WrapU_UIUII<sceSasSetVoice>, "__sceSasSetVoice"},
|
2012-12-06 17:45:09 +00:00
|
|
|
{0xb7660a23, WrapU_UII<sceSasSetNoise>, "__sceSasSetNoise"},
|
2012-12-05 15:51:10 +00:00
|
|
|
{0x019b25eb, WrapU_UIIIIII<sceSasSetADSR>, "__sceSasSetADSR"},
|
2012-12-05 16:17:55 +00:00
|
|
|
{0x9ec3676a, WrapU_UIIIIII<sceSasSetADSRMode>, "__sceSasSetADSRmode"},
|
2012-12-06 17:45:09 +00:00
|
|
|
{0x5f9529f6, WrapU_UII<sceSasSetSL>, "__sceSasSetSL"},
|
2012-11-05 09:05:09 +00:00
|
|
|
{0x74ae582a, WrapU_UU<sceSasGetEnvelopeHeight>, "__sceSasGetEnvelopeHeight"},
|
|
|
|
{0xcbcd4f79, WrapU_UUUU<sceSasSetSimpleADSR>, "__sceSasSetSimpleADSR"},
|
2012-12-16 19:40:49 +00:00
|
|
|
{0xa0cf2fa4, WrapU_UI<sceSasSetKeyOff>, "__sceSasSetKeyOff"},
|
2012-12-17 17:05:10 +00:00
|
|
|
{0x76f01aca, WrapU_UI<sceSasSetKeyOn>, "__sceSasSetKeyOn"},
|
|
|
|
{0xf983b186, WrapU_UII<sceSasRevVON>, "__sceSasRevVON"},
|
2013-01-23 06:50:36 +00:00
|
|
|
{0xd5a229c9, WrapU_UII<sceSasRevEVOL>, "__sceSasRevEVOL"},
|
2012-12-17 17:05:10 +00:00
|
|
|
{0x33d4ab37, WrapU_UI<sceSasRevType>, "__sceSasRevType"},
|
|
|
|
{0x267a6dd2, WrapU_UII<sceSasRevParam>, "__sceSasRevParam"},
|
|
|
|
{0x2c8e6ab3, WrapU_U<sceSasGetPauseFlag>, "__sceSasGetPauseFlag"},
|
2012-12-07 04:45:16 +00:00
|
|
|
{0x787d04d5, WrapU_UII<sceSasSetPause>, "__sceSasSetPause"},
|
2012-12-17 17:05:10 +00:00
|
|
|
{0xa232cbe6, WrapU_UII<sceSasSetTriangularWave>, "__sceSasSetTriangularWave"},
|
|
|
|
{0xd5ebbbcd, WrapU_UII<sceSasSetSteepWave>, "__sceSasSetSteepWave"},
|
2012-12-07 04:45:16 +00:00
|
|
|
{0xBD11B7C2, WrapU_U<sceSasGetGrain>, "__sceSasGetGrain"},
|
|
|
|
{0xd1e0a01e, WrapU_UI<sceSasSetGrain>, "__sceSasSetGrain"},
|
|
|
|
{0xe175ef66, WrapU_U<sceSasGetOutputMode>, "__sceSasGetOutputmode"},
|
|
|
|
{0xe855bf76, WrapU_UU<sceSasSetOutputMode>, "__sceSasSetOutputmode"},
|
2012-12-17 17:05:10 +00:00
|
|
|
{0x07f58c24, WrapU_UU<sceSasGetAllEnvelopeHeights>, "__sceSasGetAllEnvelopeHeights"},
|
2012-12-16 19:40:49 +00:00
|
|
|
{0xE1CD9561, WrapU_UIUII<sceSasSetVoicePCM>, "__sceSasSetVoicePCM"},
|
2012-11-01 15:19:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void Register_sceSasCore()
|
|
|
|
{
|
|
|
|
RegisterModule("sceSasCore", ARRAY_SIZE(sceSasCore), sceSasCore);
|
|
|
|
}
|
|
|
|
|