CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/HLE/sceAudio.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include "Common/Serialize/Serializer.h"18#include "Common/Serialize/SerializeFuncs.h"19#include "Common/Data/Collections/FixedSizeQueue.h"20#include "Core/MIPS/MIPS.h"21#include "Core/CoreTiming.h"22#include "Core/HLE/HLE.h"23#include "Core/HLE/FunctionWrappers.h"24#include "Core/HLE/sceKernelThread.h"25#include "Core/HLE/sceAudio.h"26#include "Core/HLE/sceUsbMic.h"27#include "Core/HLE/__sceAudio.h"28#include "Core/Reporting.h"2930const u32 PSP_AUDIO_SAMPLE_MAX = 65536 - 64;31const int PSP_AUDIO_ERROR_SRC_FORMAT_4 = 0x80000003;32const int AUDIO_ROUTING_SPEAKER_OFF = 0;33const int AUDIO_ROUTING_SPEAKER_ON = 1;34int defaultRoutingMode = AUDIO_ROUTING_SPEAKER_ON;35int defaultRoutingVolMode = AUDIO_ROUTING_SPEAKER_ON;3637// TODO: These are way oversized and together consume 4MB of memory.38extern FixedSizeQueue<s16, 32768 * 8> chanSampleQueues[PSP_AUDIO_CHANNEL_MAX + 1];3940// The extra channel is for SRC/Output2/Vaudio.41AudioChannel chans[PSP_AUDIO_CHANNEL_MAX + 1];4243void AudioChannel::DoState(PointerWrap &p)44{45auto s = p.Section("AudioChannel", 1, 2);46if (!s)47return;4849Do(p, reserved);50Do(p, sampleAddress);51Do(p, sampleCount);52Do(p, leftVolume);53Do(p, rightVolume);54Do(p, format);55Do(p, waitingThreads);56if (s >= 2) {57Do(p, defaultRoutingMode);58Do(p, defaultRoutingVolMode);59}60chanSampleQueues[index].DoState(p);61}6263void AudioChannel::reset()64{65__AudioWakeThreads(*this, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED);66clear();67}6869void AudioChannel::clear()70{71reserved = false;72leftVolume = 0;73rightVolume = 0;74format = 0;75sampleAddress = 0;76sampleCount = 0;77chanSampleQueues[index].clear();78waitingThreads.clear();79}8081// Enqueues the buffer pointed to on the channel. If channel buffer queue is full (2 items?) will block until it isn't.82// For solid audio output we'll need a queue length of 2 buffers at least.8384// Not sure about the range of volume, I often see 0x800 so that might be either85// max or 50%?86static u32 sceAudioOutputBlocking(u32 chan, int vol, u32 samplePtr) {87if (vol > 0xFFFF) {88ERROR_LOG(Log::sceAudio, "sceAudioOutputBlocking() - invalid volume");89return SCE_ERROR_AUDIO_INVALID_VOLUME;90} else if (chan >= PSP_AUDIO_CHANNEL_MAX) {91ERROR_LOG(Log::sceAudio, "sceAudioOutputBlocking() - bad channel");92return SCE_ERROR_AUDIO_INVALID_CHANNEL;93} else if (!chans[chan].reserved) {94ERROR_LOG(Log::sceAudio, "sceAudioOutputBlocking() - channel not reserved");95return SCE_ERROR_AUDIO_CHANNEL_NOT_INIT;96} else {97DEBUG_LOG(Log::sceAudio, "sceAudioOutputBlocking(%08x, %08x, %08x)", chan, vol, samplePtr);98if (vol >= 0) {99chans[chan].leftVolume = vol;100chans[chan].rightVolume = vol;101}102chans[chan].sampleAddress = samplePtr;103return __AudioEnqueue(chans[chan], chan, true);104}105}106107static u32 sceAudioOutputPannedBlocking(u32 chan, int leftvol, int rightvol, u32 samplePtr) {108int result = 0;109// For some reason, this is the only one that checks for negative.110if (leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || rightvol < 0) {111ERROR_LOG(Log::sceAudio, "sceAudioOutputPannedBlocking() - invalid volume");112result = SCE_ERROR_AUDIO_INVALID_VOLUME;113} else if (chan >= PSP_AUDIO_CHANNEL_MAX) {114ERROR_LOG(Log::sceAudio, "sceAudioOutputPannedBlocking() - bad channel");115result = SCE_ERROR_AUDIO_INVALID_CHANNEL;116} else if (!chans[chan].reserved) {117ERROR_LOG(Log::sceAudio, "sceAudioOutputPannedBlocking() - channel not reserved");118result = SCE_ERROR_AUDIO_CHANNEL_NOT_INIT;119} else {120if (leftvol >= 0) {121chans[chan].leftVolume = leftvol;122}123if (rightvol >= 0) {124chans[chan].rightVolume = rightvol;125}126chans[chan].sampleAddress = samplePtr;127result = __AudioEnqueue(chans[chan], chan, true);128}129130DEBUG_LOG(Log::sceAudio, "%08x = sceAudioOutputPannedBlocking(%08x, %08x, %08x, %08x)", result, chan, leftvol, rightvol, samplePtr);131return result;132133}134135static u32 sceAudioOutput(u32 chan, int vol, u32 samplePtr) {136if (vol > 0xFFFF) {137ERROR_LOG(Log::sceAudio, "sceAudioOutput() - invalid volume");138return SCE_ERROR_AUDIO_INVALID_VOLUME;139} else if (chan >= PSP_AUDIO_CHANNEL_MAX) {140ERROR_LOG(Log::sceAudio, "sceAudioOutput() - bad channel");141return SCE_ERROR_AUDIO_INVALID_CHANNEL;142} else if (!chans[chan].reserved) {143ERROR_LOG(Log::sceAudio, "sceAudioOutput(%08x, %08x, %08x) - channel not reserved", chan, vol, samplePtr);144return SCE_ERROR_AUDIO_CHANNEL_NOT_INIT;145} else {146DEBUG_LOG(Log::sceAudio, "sceAudioOutput(%08x, %08x, %08x)", chan, vol, samplePtr);147if (vol >= 0) {148chans[chan].leftVolume = vol;149chans[chan].rightVolume = vol;150}151chans[chan].sampleAddress = samplePtr;152return __AudioEnqueue(chans[chan], chan, false);153}154}155156static u32 sceAudioOutputPanned(u32 chan, int leftvol, int rightvol, u32 samplePtr) {157if (leftvol > 0xFFFF || rightvol > 0xFFFF) {158ERROR_LOG(Log::sceAudio, "sceAudioOutputPanned() - invalid volume");159return SCE_ERROR_AUDIO_INVALID_VOLUME;160} else if (chan >= PSP_AUDIO_CHANNEL_MAX) {161ERROR_LOG(Log::sceAudio, "sceAudioOutputPanned() - bad channel");162return SCE_ERROR_AUDIO_INVALID_CHANNEL;163} else if (!chans[chan].reserved) {164ERROR_LOG(Log::sceAudio, "sceAudioOutputPanned(%08x, %08x, %08x, %08x) - channel not reserved", chan, leftvol, rightvol, samplePtr);165return SCE_ERROR_AUDIO_CHANNEL_NOT_INIT;166} else {167DEBUG_LOG(Log::sceAudio, "sceAudioOutputPanned(%08x, %08x, %08x, %08x)", chan, leftvol, rightvol, samplePtr);168if (leftvol >= 0) {169chans[chan].leftVolume = leftvol;170}171if (rightvol >= 0) {172chans[chan].rightVolume = rightvol;173}174chans[chan].sampleAddress = samplePtr;175return __AudioEnqueue(chans[chan], chan, false);176}177}178179static int sceAudioGetChannelRestLen(u32 chan) {180if (chan >= PSP_AUDIO_CHANNEL_MAX) {181ERROR_LOG(Log::sceAudio, "sceAudioGetChannelRestLen(%08x) - bad channel", chan);182return SCE_ERROR_AUDIO_INVALID_CHANNEL;183}184int remainingSamples = (int)chanSampleQueues[chan].size() / 2;185VERBOSE_LOG(Log::sceAudio, "%d=sceAudioGetChannelRestLen(%08x)", remainingSamples, chan);186return remainingSamples;187}188189static int sceAudioGetChannelRestLength(u32 chan) {190if (chan >= PSP_AUDIO_CHANNEL_MAX) {191ERROR_LOG(Log::sceAudio, "sceAudioGetChannelRestLength(%08x) - bad channel", chan);192return SCE_ERROR_AUDIO_INVALID_CHANNEL;193}194int remainingSamples = (int)chanSampleQueues[chan].size() / 2;195VERBOSE_LOG(Log::sceAudio, "%d=sceAudioGetChannelRestLength(%08x)", remainingSamples, chan);196return remainingSamples;197}198199static u32 GetFreeChannel() {200for (u32 i = PSP_AUDIO_CHANNEL_MAX - 1; i > 0; --i) {201if (!chans[i].reserved)202return i;203}204return -1;205}206207static u32 sceAudioChReserve(int chan, u32 sampleCount, u32 format) {208if (chan < 0) {209chan = GetFreeChannel();210if (chan < 0) {211ERROR_LOG(Log::sceAudio, "sceAudioChReserve - no channels remaining");212return SCE_ERROR_AUDIO_NO_CHANNELS_AVAILABLE;213}214}215if ((u32)chan >= PSP_AUDIO_CHANNEL_MAX) {216ERROR_LOG(Log::sceAudio, "sceAudioChReserve(%08x, %08x, %08x) - bad channel", chan, sampleCount, format);217return SCE_ERROR_AUDIO_INVALID_CHANNEL;218}219if ((sampleCount & 63) != 0 || sampleCount == 0 || sampleCount > PSP_AUDIO_SAMPLE_MAX) {220ERROR_LOG(Log::sceAudio, "sceAudioChReserve(%08x, %08x, %08x) - invalid sample count", chan, sampleCount, format);221return SCE_ERROR_AUDIO_OUTPUT_SAMPLE_DATA_SIZE_NOT_ALIGNED;222}223if (format != PSP_AUDIO_FORMAT_MONO && format != PSP_AUDIO_FORMAT_STEREO) {224ERROR_LOG(Log::sceAudio, "sceAudioChReserve(%08x, %08x, %08x) - invalid format", chan, sampleCount, format);225return SCE_ERROR_AUDIO_INVALID_FORMAT;226}227if (chans[chan].reserved) {228ERROR_LOG(Log::sceAudio, "sceAudioChReserve - reserve channel failed");229return SCE_ERROR_AUDIO_INVALID_CHANNEL;230}231232DEBUG_LOG(Log::sceAudio, "sceAudioChReserve(%08x, %08x, %08x)", chan, sampleCount, format);233chans[chan].sampleCount = sampleCount;234chans[chan].format = format;235chans[chan].reserved = true;236chans[chan].leftVolume = 0;237chans[chan].rightVolume = 0;238return chan;239}240241static u32 sceAudioChRelease(u32 chan) {242if (chan >= PSP_AUDIO_CHANNEL_MAX) {243ERROR_LOG(Log::sceAudio, "sceAudioChRelease(%i) - bad channel", chan);244return SCE_ERROR_AUDIO_INVALID_CHANNEL;245}246247if (!chans[chan].reserved) {248ERROR_LOG(Log::sceAudio, "sceAudioChRelease(%i) - channel not reserved", chan);249return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;250}251// TODO: Does this error if busy?252chans[chan].reset();253chans[chan].reserved = false;254return hleLogSuccessI(Log::sceAudio, 0);255}256257static u32 sceAudioSetChannelDataLen(u32 chan, u32 len) {258int result = 0;259if (chan >= PSP_AUDIO_CHANNEL_MAX) {260ERROR_LOG(Log::sceAudio, "sceAudioSetChannelDataLen(%08x, %08x) - bad channel", chan, len);261result = SCE_ERROR_AUDIO_INVALID_CHANNEL;262} else if (!chans[chan].reserved) {263ERROR_LOG(Log::sceAudio, "sceAudioSetChannelDataLen(%08x, %08x) - channel not reserved", chan, len);264result = SCE_ERROR_AUDIO_CHANNEL_NOT_INIT;265} else if ((len & 63) != 0 || len == 0 || len > PSP_AUDIO_SAMPLE_MAX) {266ERROR_LOG(Log::sceAudio, "sceAudioSetChannelDataLen(%08x, %08x) - invalid sample count", chan, len);267result = SCE_ERROR_AUDIO_OUTPUT_SAMPLE_DATA_SIZE_NOT_ALIGNED;268} else {269chans[chan].sampleCount = len;270}271DEBUG_LOG(Log::sceAudio, "%08x = sceAudioSetChannelDataLen(%08x, %08x)", result , chan, len);272return result;273}274275static u32 sceAudioChangeChannelConfig(u32 chan, u32 format) {276if (chan >= PSP_AUDIO_CHANNEL_MAX) {277ERROR_LOG(Log::sceAudio, "sceAudioChangeChannelConfig(%08x, %08x) - invalid channel number", chan, format);278return SCE_ERROR_AUDIO_INVALID_CHANNEL;279} else if (!chans[chan].reserved) {280ERROR_LOG(Log::sceAudio, "sceAudioChangeChannelConfig(%08x, %08x) - channel not reserved", chan, format);281return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;282} else {283DEBUG_LOG(Log::sceAudio, "sceAudioChangeChannelConfig(%08x, %08x)", chan, format);284chans[chan].format = format;285return 0;286}287}288289static u32 sceAudioChangeChannelVolume(u32 chan, u32 leftvol, u32 rightvol) {290if (leftvol > 0xFFFF || rightvol > 0xFFFF) {291ERROR_LOG(Log::sceAudio, "sceAudioChangeChannelVolume(%08x, %08x, %08x) - invalid volume", chan, leftvol, rightvol);292return SCE_ERROR_AUDIO_INVALID_VOLUME;293} else if (chan >= PSP_AUDIO_CHANNEL_MAX) {294ERROR_LOG(Log::sceAudio, "sceAudioChangeChannelVolume(%08x, %08x, %08x) - invalid channel number", chan, leftvol, rightvol);295return SCE_ERROR_AUDIO_INVALID_CHANNEL;296} else if (!chans[chan].reserved) {297ERROR_LOG(Log::sceAudio, "sceAudioChangeChannelVolume(%08x, %08x, %08x) - channel not reserved", chan, leftvol, rightvol);298return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;299} else {300DEBUG_LOG(Log::sceAudio, "sceAudioChangeChannelVolume(%08x, %08x, %08x)", chan, leftvol, rightvol);301chans[chan].leftVolume = leftvol;302chans[chan].rightVolume = rightvol;303return 0;304}305}306307static u32 sceAudioInit() {308DEBUG_LOG(Log::sceAudio, "sceAudioInit()");309// Don't need to do anything310return 0;311}312313static u32 sceAudioEnd() {314DEBUG_LOG(Log::sceAudio, "sceAudioEnd()");315// Don't need to do anything316return 0;317}318319static u32 sceAudioOutput2Reserve(u32 sampleCount) {320auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2];321// This seems to ignore the MSB, for some reason.322sampleCount &= 0x7FFFFFFF;323if (sampleCount < 17 || sampleCount > 4111) {324return hleLogError(Log::sceAudio, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid sample count");325} else if (chan.reserved) {326return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "channel already reserved");327}328329chan.sampleCount = sampleCount;330chan.format = PSP_AUDIO_FORMAT_STEREO;331chan.reserved = true;332__AudioSetSRCFrequency(0);333return hleLogSuccessI(Log::sceAudio, 0);334}335336static u32 sceAudioOutput2OutputBlocking(u32 vol, u32 dataPtr) {337// Note: 0xFFFFF, not 0xFFFF!338if (vol > 0xFFFFF) {339return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume");340}341342auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2];343if (!chan.reserved) {344return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");345}346347chan.leftVolume = vol;348chan.rightVolume = vol;349chan.sampleAddress = dataPtr;350351hleEatCycles(10000);352int result = __AudioEnqueue(chan, PSP_AUDIO_CHANNEL_OUTPUT2, true);353if (result < 0)354return hleLogError(Log::sceAudio, result);355return hleLogSuccessI(Log::sceAudio, result);356}357358static u32 sceAudioOutput2ChangeLength(u32 sampleCount) {359auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2];360if (!chan.reserved) {361return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");362}363chan.sampleCount = sampleCount;364return hleLogSuccessI(Log::sceAudio, 0);365}366367static u32 sceAudioOutput2GetRestSample() {368auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2];369if (!chan.reserved) {370return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");371}372u32 size = (u32)chanSampleQueues[PSP_AUDIO_CHANNEL_OUTPUT2].size() / 2;373if (size > chan.sampleCount) {374// If ChangeLength reduces the size, it still gets output but this return is clamped.375size = chan.sampleCount;376}377return hleLogSuccessI(Log::sceAudio, size);378}379380static u32 sceAudioOutput2Release() {381auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2];382if (!chan.reserved)383return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");384if (!chanSampleQueues[PSP_AUDIO_CHANNEL_OUTPUT2].empty())385return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "output busy");386387chan.reset();388chan.reserved = false;389return hleLogSuccessI(Log::sceAudio, 0);390}391392static u32 sceAudioSetFrequency(u32 freq) {393// TODO: Not available from user code.394if (freq == 44100 || freq == 48000) {395INFO_LOG(Log::sceAudio, "sceAudioSetFrequency(%08x)", freq);396__AudioSetOutputFrequency(freq);397return 0;398} else {399ERROR_LOG(Log::sceAudio, "sceAudioSetFrequency(%08x) - invalid frequency (must be 44.1 or 48 khz)", freq);400return SCE_ERROR_AUDIO_INVALID_FREQUENCY;401}402}403404static u32 sceAudioSetVolumeOffset() {405ERROR_LOG(Log::sceAudio, "UNIMPL sceAudioSetVolumeOffset()");406return 0;407}408409static bool SRCFrequencyAllowed(int freq) {410if (freq == 44100 || freq == 22050 || freq == 11025)411return true;412if (freq == 48000 || freq == 32000 || freq == 24000 || freq == 16000 || freq == 12000 || freq == 8000)413return true;414return false;415}416417static u32 sceAudioSRCChReserve(u32 sampleCount, u32 freq, u32 format) {418auto &chan = chans[PSP_AUDIO_CHANNEL_SRC];419// This seems to ignore the MSB, for some reason.420sampleCount &= 0x7FFFFFFF;421if (format == 4) {422return hleReportError(Log::sceAudio, PSP_AUDIO_ERROR_SRC_FORMAT_4, "unexpected format");423} else if (format != 2) {424return hleLogError(Log::sceAudio, SCE_KERNEL_ERROR_INVALID_SIZE, "unexpected format");425} else if (sampleCount < 17 || sampleCount > 4111) {426return hleLogError(Log::sceAudio, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid sample count");427} else if (freq != 0 && !SRCFrequencyAllowed(freq)) {428return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_FREQUENCY, "invalid frequency");429} else if (chan.reserved) {430return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "channel already reserved");431}432433chan.reserved = true;434chan.sampleCount = sampleCount;435chan.format = format == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO;436// Zero means default to 44.1kHz.437__AudioSetSRCFrequency(freq);438return hleLogSuccessI(Log::sceAudio, 0);439}440441static u32 sceAudioSRCChRelease() {442auto &chan = chans[PSP_AUDIO_CHANNEL_SRC];443if (!chan.reserved)444return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");445if (!chanSampleQueues[PSP_AUDIO_CHANNEL_SRC].empty())446return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "output busy");447448chan.reset();449chan.reserved = false;450return hleLogSuccessI(Log::sceAudio, 0);451}452453static u32 sceAudioSRCOutputBlocking(u32 vol, u32 buf) {454if (vol > 0xFFFFF) {455return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume");456}457458auto &chan = chans[PSP_AUDIO_CHANNEL_SRC];459if (!chan.reserved) {460return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");461}462463chan.leftVolume = vol;464chan.rightVolume = vol;465chan.sampleAddress = buf;466467hleEatCycles(10000);468int result = __AudioEnqueue(chan, PSP_AUDIO_CHANNEL_SRC, true);469if (result < 0)470return hleLogError(Log::sceAudio, result);471return hleLogSuccessI(Log::sceAudio, result);472}473474static int sceAudioInputBlocking(u32 maxSamples, u32 sampleRate, u32 bufAddr) {475if (!Memory::IsValidAddress(bufAddr)) {476ERROR_LOG(Log::HLE, "sceAudioInputBlocking(%d, %d, %08x): invalid addresses", maxSamples, sampleRate, bufAddr);477return -1;478}479480INFO_LOG(Log::HLE, "sceAudioInputBlocking: maxSamples: %d, samplerate: %d, bufAddr: %08x", maxSamples, sampleRate, bufAddr);481return __MicInput(maxSamples, sampleRate, bufAddr, AUDIOINPUT);482}483484static int sceAudioInput(u32 maxSamples, u32 sampleRate, u32 bufAddr) {485if (!Memory::IsValidAddress(bufAddr)) {486ERROR_LOG(Log::HLE, "sceAudioInput(%d, %d, %08x): invalid addresses", maxSamples, sampleRate, bufAddr);487return -1;488}489490ERROR_LOG(Log::HLE, "UNTEST sceAudioInput: maxSamples: %d, samplerate: %d, bufAddr: %08x", maxSamples, sampleRate, bufAddr);491return __MicInput(maxSamples, sampleRate, bufAddr, AUDIOINPUT, false);492}493494static int sceAudioInputInit(int unknown1, int gain, int unknown2) {495ERROR_LOG(Log::HLE, "UNIMPL sceAudioInputInit: unknown1: %d, gain: %d, unknown2: %d", unknown1, gain, unknown2);496return 0;497}498499static int sceAudioInputInitEx(u32 paramAddr) {500ERROR_LOG(Log::HLE, "UNIMPL sceAudioInputInitEx: paramAddr: %08x", paramAddr);501return 0;502}503504static int sceAudioPollInputEnd() {505ERROR_LOG(Log::HLE, "UNIMPL sceAudioPollInputEnd");506return 0;507}508509static int sceAudioWaitInputEnd() {510ERROR_LOG(Log::HLE, "UNIMPL sceAudioWaitInputEnd");511return 0;512}513514static int sceAudioGetInputLength() {515int ret = Microphone::getReadMicDataLength() / 2;516ERROR_LOG(Log::HLE, "UNTEST sceAudioGetInputLength(ret: %d)", ret);517return ret;518}519520static u32 sceAudioRoutingSetMode(u32 mode) {521ERROR_LOG_REPORT(Log::sceAudio, "sceAudioRoutingSetMode(%08x)", mode);522int previousMode = defaultRoutingMode;523defaultRoutingMode = mode;524return previousMode;525}526527static u32 sceAudioRoutingGetMode() {528ERROR_LOG_REPORT(Log::sceAudio, "sceAudioRoutingGetMode()");529return defaultRoutingMode;530}531532static u32 sceAudioRoutingSetVolumeMode(u32 mode) {533ERROR_LOG_REPORT(Log::sceAudio, "sceAudioRoutingSetVolumeMode(%08x)", mode);534int previousMode = defaultRoutingVolMode;535defaultRoutingVolMode = mode;536return previousMode;537}538539static u32 sceAudioRoutingGetVolumeMode() {540ERROR_LOG_REPORT(Log::sceAudio, "sceAudioRoutingGetVolumeMode()");541return defaultRoutingVolMode;542}543544const HLEFunction sceAudio[] =545{546// Newer simplified single channel audio output. Presumably for games that use Atrac3547// directly from Sas instead of playing it on a separate audio channel.548{0X01562BA3, &WrapU_U<sceAudioOutput2Reserve>, "sceAudioOutput2Reserve", 'x', "i" },549{0X2D53F36E, &WrapU_UU<sceAudioOutput2OutputBlocking>, "sceAudioOutput2OutputBlocking", 'x', "xx" },550{0X63F2889C, &WrapU_U<sceAudioOutput2ChangeLength>, "sceAudioOutput2ChangeLength", 'x', "i" },551{0X647CEF33, &WrapU_V<sceAudioOutput2GetRestSample>, "sceAudioOutput2GetRestSample", 'i', "" },552{0X43196845, &WrapU_V<sceAudioOutput2Release>, "sceAudioOutput2Release", 'x', "" },553554// "Traditional" audio channel interface555{0X80F1F7E0, &WrapU_V<sceAudioInit>, "sceAudioInit", 'x', "" },556{0X210567F7, &WrapU_V<sceAudioEnd>, "sceAudioEnd", 'x', "" },557{0XA2BEAA6C, &WrapU_U<sceAudioSetFrequency>, "sceAudioSetFrequency", 'x', "i" },558{0X927AC32B, &WrapU_V<sceAudioSetVolumeOffset>, "sceAudioSetVolumeOffset", 'x', "" },559{0X8C1009B2, &WrapU_UIU<sceAudioOutput>, "sceAudioOutput", 'x', "ixx" },560{0X136CAF51, &WrapU_UIU<sceAudioOutputBlocking>, "sceAudioOutputBlocking", 'x', "ixx" },561{0XE2D56B2D, &WrapU_UIIU<sceAudioOutputPanned>, "sceAudioOutputPanned", 'x', "ixxx"},562{0X13F592BC, &WrapU_UIIU<sceAudioOutputPannedBlocking>, "sceAudioOutputPannedBlocking", 'x', "ixxx"},563{0X5EC81C55, &WrapU_IUU<sceAudioChReserve>, "sceAudioChReserve", 'x', "iii" },564{0X6FC46853, &WrapU_U<sceAudioChRelease>, "sceAudioChRelease", 'x', "i" },565{0XE9D97901, &WrapI_U<sceAudioGetChannelRestLen>, "sceAudioGetChannelRestLen", 'i', "i" },566{0XB011922F, &WrapI_U<sceAudioGetChannelRestLength>, "sceAudioGetChannelRestLength", 'i', "i" },567{0XCB2E439E, &WrapU_UU<sceAudioSetChannelDataLen>, "sceAudioSetChannelDataLen", 'x', "ii" },568{0X95FD0C2D, &WrapU_UU<sceAudioChangeChannelConfig>, "sceAudioChangeChannelConfig", 'x', "ii" },569{0XB7E1D8E7, &WrapU_UUU<sceAudioChangeChannelVolume>, "sceAudioChangeChannelVolume", 'x', "ixx" },570571// Like Output2, but with ability to do sample rate conversion.572{0X38553111, &WrapU_UUU<sceAudioSRCChReserve>, "sceAudioSRCChReserve", 'x', "iii" },573{0X5C37C0AE, &WrapU_V<sceAudioSRCChRelease>, "sceAudioSRCChRelease", 'x', "" },574{0XE0727056, &WrapU_UU<sceAudioSRCOutputBlocking>, "sceAudioSRCOutputBlocking", 'x', "xx" },575576// Never seen these used577{0X41EFADE7, nullptr, "sceAudioOneshotOutput", '?', "" },578{0XB61595C0, nullptr, "sceAudioLoopbackTest", '?', "" },579580// Microphone interface581{0X7DE61688, &WrapI_III<sceAudioInputInit>, "sceAudioInputInit", 'i', "iii" },582{0XE926D3FB, &WrapI_U<sceAudioInputInitEx>, "sceAudioInputInitEx", 'i', "x" },583{0X6D4BEC68, &WrapI_UUU<sceAudioInput>, "sceAudioInput", 'i', "xxx" },584{0X086E5895, &WrapI_UUU<sceAudioInputBlocking>, "sceAudioInputBlocking", 'i', "xxx" },585{0XA708C6A6, &WrapI_V<sceAudioGetInputLength>, "sceAudioGetInputLength", 'i', "" },586{0XA633048E, &WrapI_V<sceAudioPollInputEnd>, "sceAudioPollInputEnd", 'i', "" },587{0X87B2E651, &WrapI_V<sceAudioWaitInputEnd>, "sceAudioWaitInputEnd", 'i', "" },588589{0X36FD8AA9, &WrapU_U<sceAudioRoutingSetMode>, "sceAudioRoutingSetMode", 'x', "x" },590{0X39240E7D, &WrapU_V<sceAudioRoutingGetMode>, "sceAudioRoutingGetMode", 'x', "" },591{0XBB548475, &WrapU_U<sceAudioRoutingSetVolumeMode>, "sceAudioRoutingSetVolumeMode", 'x', "x" },592{0X28235C56, &WrapU_V<sceAudioRoutingGetVolumeMode>, "sceAudioRoutingGetVolumeMode", 'x', "" },593594};595596void Register_sceAudio()597{598RegisterModule("sceAudio", ARRAY_SIZE(sceAudio), sceAudio);599}600601602