Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/HLE/sceAudio.cpp
3186 views
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include "Common/Serialize/Serializer.h"
19
#include "Common/Serialize/SerializeFuncs.h"
20
#include "Common/Data/Collections/FixedSizeQueue.h"
21
#include "Core/MIPS/MIPS.h"
22
#include "Core/CoreTiming.h"
23
#include "Core/HLE/HLE.h"
24
#include "Core/HLE/ErrorCodes.h"
25
#include "Core/HLE/FunctionWrappers.h"
26
#include "Core/HLE/sceKernelThread.h"
27
#include "Core/HLE/sceAudio.h"
28
#include "Core/HLE/sceUsbMic.h"
29
#include "Core/HLE/__sceAudio.h"
30
#include "Core/Reporting.h"
31
32
const u32 PSP_AUDIO_SAMPLE_MAX = 65536 - 64;
33
const int PSP_AUDIO_ERROR_SRC_FORMAT_4 = 0x80000003;
34
const int AUDIO_ROUTING_SPEAKER_OFF = 0;
35
const int AUDIO_ROUTING_SPEAKER_ON = 1;
36
int defaultRoutingMode = AUDIO_ROUTING_SPEAKER_ON;
37
int defaultRoutingVolMode = AUDIO_ROUTING_SPEAKER_ON;
38
39
// TODO: These are way oversized and together consume 4MB of memory.
40
extern FixedSizeQueue<s16, 32768 * 8> chanSampleQueues[PSP_AUDIO_CHANNEL_MAX + 1];
41
42
// The extra channel is for SRC/Output2/Vaudio.
43
AudioChannel g_audioChans[PSP_AUDIO_CHANNEL_MAX + 1];
44
45
void AudioChannel::DoState(PointerWrap &p)
46
{
47
auto s = p.Section("AudioChannel", 1, 2);
48
if (!s)
49
return;
50
51
Do(p, reserved);
52
Do(p, sampleAddress);
53
Do(p, sampleCount);
54
Do(p, leftVolume);
55
Do(p, rightVolume);
56
Do(p, format);
57
Do(p, waitingThreads);
58
if (s >= 2) {
59
Do(p, defaultRoutingMode);
60
Do(p, defaultRoutingVolMode);
61
}
62
chanSampleQueues[index].DoState(p);
63
}
64
65
void AudioChannel::reset()
66
{
67
__AudioWakeThreads(*this, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED);
68
clear();
69
}
70
71
void AudioChannel::clear()
72
{
73
reserved = false;
74
leftVolume = 0;
75
rightVolume = 0;
76
format = 0;
77
sampleAddress = 0;
78
sampleCount = 0;
79
chanSampleQueues[index].clear();
80
waitingThreads.clear();
81
}
82
83
// Enqueues the buffer pointed to on the channel. If channel buffer queue is full (2 items?) will block until it isn't.
84
// For solid audio output we'll need a queue length of 2 buffers at least.
85
86
// Not sure about the range of volume, I often see 0x800 so that might be either
87
// max or 50%?
88
static u32 sceAudioOutputBlocking(u32 chan, int vol, u32 samplePtr) {
89
if (vol > 0xFFFF) {
90
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume");
91
} else if (chan >= PSP_AUDIO_CHANNEL_MAX) {
92
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_CHANNEL, "bad channel");
93
} else if (!g_audioChans[chan].reserved) {
94
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_INIT, "channel not reserved");
95
}
96
97
if (vol >= 0) {
98
g_audioChans[chan].leftVolume = vol;
99
g_audioChans[chan].rightVolume = vol;
100
}
101
g_audioChans[chan].sampleAddress = samplePtr;
102
return hleLogDebug(Log::sceAudio, __AudioEnqueue(g_audioChans[chan], chan, true));
103
}
104
105
static u32 sceAudioOutputPannedBlocking(u32 chan, int leftvol, int rightvol, u32 samplePtr) {
106
// For some reason, this is the only one that checks for negative.
107
if (leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || rightvol < 0) {
108
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume");
109
} else if (chan >= PSP_AUDIO_CHANNEL_MAX) {
110
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_CHANNEL, "bad channel");
111
} else if (!g_audioChans[chan].reserved) {
112
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_INIT, "channel not reserved");
113
}
114
115
if (leftvol >= 0) {
116
g_audioChans[chan].leftVolume = leftvol;
117
}
118
if (rightvol >= 0) {
119
g_audioChans[chan].rightVolume = rightvol;
120
}
121
g_audioChans[chan].sampleAddress = samplePtr;
122
u32 result = __AudioEnqueue(g_audioChans[chan], chan, true);
123
return hleLogDebug(Log::sceAudio, result);
124
}
125
126
static u32 sceAudioOutput(u32 chan, int vol, u32 samplePtr) {
127
if (vol > 0xFFFF) {
128
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume");
129
} else if (chan >= PSP_AUDIO_CHANNEL_MAX) {
130
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_CHANNEL, "bad channel");
131
} else if (!g_audioChans[chan].reserved) {
132
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_INIT, "channel not reserved");
133
}
134
135
if (vol >= 0) {
136
g_audioChans[chan].leftVolume = vol;
137
g_audioChans[chan].rightVolume = vol;
138
}
139
g_audioChans[chan].sampleAddress = samplePtr;
140
u32 result = __AudioEnqueue(g_audioChans[chan], chan, false);
141
return hleLogDebug(Log::sceAudio, result);
142
}
143
144
static u32 sceAudioOutputPanned(u32 chan, int leftvol, int rightvol, u32 samplePtr) {
145
if (leftvol > 0xFFFF || rightvol > 0xFFFF) {
146
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume");
147
} else if (chan >= PSP_AUDIO_CHANNEL_MAX) {
148
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_CHANNEL, "bad channel");
149
} else if (!g_audioChans[chan].reserved) {
150
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_INIT, "channel not reserved");
151
} else {
152
if (leftvol >= 0) {
153
g_audioChans[chan].leftVolume = leftvol;
154
}
155
if (rightvol >= 0) {
156
g_audioChans[chan].rightVolume = rightvol;
157
}
158
g_audioChans[chan].sampleAddress = samplePtr;
159
u32 result = __AudioEnqueue(g_audioChans[chan], chan, false);
160
return hleLogDebug(Log::sceAudio, result);
161
}
162
}
163
164
static int sceAudioGetChannelRestLen(u32 chan) {
165
if (chan >= PSP_AUDIO_CHANNEL_MAX) {
166
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_CHANNEL, "bad channel");
167
}
168
int remainingSamples = (int)chanSampleQueues[chan].size() / 2;
169
return hleLogVerbose(Log::sceAudio, remainingSamples);
170
}
171
172
static int sceAudioGetChannelRestLength(u32 chan) {
173
if (chan >= PSP_AUDIO_CHANNEL_MAX) {
174
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_CHANNEL, "bad channel");
175
}
176
int remainingSamples = (int)chanSampleQueues[chan].size() / 2;
177
return hleLogVerbose(Log::sceAudio, remainingSamples);
178
}
179
180
static u32 GetFreeChannel() {
181
for (u32 i = PSP_AUDIO_CHANNEL_MAX - 1; i > 0; --i) {
182
if (!g_audioChans[i].reserved)
183
return i;
184
}
185
return -1;
186
}
187
188
static u32 sceAudioChReserve(int chan, u32 sampleCount, u32 format) {
189
if (chan < 0) {
190
chan = GetFreeChannel();
191
if (chan < 0) {
192
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_NO_CHANNELS_AVAILABLE, "no channels remaining");
193
}
194
}
195
if ((u32)chan >= PSP_AUDIO_CHANNEL_MAX) {
196
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_CHANNEL, "bad channel %d", chan);
197
}
198
if ((sampleCount & 63) != 0 || sampleCount == 0 || sampleCount > PSP_AUDIO_SAMPLE_MAX) {
199
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_OUTPUT_SAMPLE_DATA_SIZE_NOT_ALIGNED, "invalid sample count (not aligned)");
200
}
201
if (format != PSP_AUDIO_FORMAT_MONO && format != PSP_AUDIO_FORMAT_STEREO) {
202
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_FORMAT, "invalid format");
203
}
204
if (g_audioChans[chan].reserved) {
205
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_CHANNEL, "reserve channel failed");
206
}
207
208
g_audioChans[chan].sampleCount = sampleCount;
209
g_audioChans[chan].format = format;
210
g_audioChans[chan].reserved = true;
211
g_audioChans[chan].leftVolume = 0;
212
g_audioChans[chan].rightVolume = 0;
213
return hleLogDebug(Log::sceAudio, chan);
214
}
215
216
static u32 sceAudioChRelease(u32 chan) {
217
if (chan >= PSP_AUDIO_CHANNEL_MAX) {
218
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_CHANNEL, "bad channel %d", chan);
219
} else if (!g_audioChans[chan].reserved) {
220
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_INIT, "channel %d not reserved", chan);
221
}
222
223
// TODO: Does this error if busy?
224
g_audioChans[chan].reset();
225
g_audioChans[chan].reserved = false;
226
return hleLogDebug(Log::sceAudio, 0);
227
}
228
229
static u32 sceAudioSetChannelDataLen(u32 chan, u32 len) {
230
if (chan >= PSP_AUDIO_CHANNEL_MAX) {
231
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_CHANNEL, "bad channel %d", chan);
232
} else if (!g_audioChans[chan].reserved) {
233
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_INIT, "channel %d not reserved", chan);
234
} else if ((len & 63) != 0 || len == 0 || len > PSP_AUDIO_SAMPLE_MAX) {
235
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_OUTPUT_SAMPLE_DATA_SIZE_NOT_ALIGNED, "invalid sample count");
236
}
237
238
g_audioChans[chan].sampleCount = len;
239
return hleLogDebug(Log::sceAudio, 0);
240
}
241
242
static u32 sceAudioChangeChannelConfig(u32 chan, u32 format) {
243
if (chan >= PSP_AUDIO_CHANNEL_MAX) {
244
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_CHANNEL, "invalid channel number %d", chan);
245
} else if (!g_audioChans[chan].reserved) {
246
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel %d not reserved", chan);
247
}
248
249
g_audioChans[chan].format = format;
250
return hleLogDebug(Log::sceAudio, 0);
251
}
252
253
static u32 sceAudioChangeChannelVolume(u32 chan, u32 leftvol, u32 rightvol) {
254
if (leftvol > 0xFFFF || rightvol > 0xFFFF) {
255
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid chan %d volume %d %d", chan, leftvol, rightvol);
256
} else if (chan >= PSP_AUDIO_CHANNEL_MAX) {
257
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_CHANNEL, "invalid channel %d", chan);
258
} else if (!g_audioChans[chan].reserved) {
259
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel %d not reserved", chan);
260
}
261
262
g_audioChans[chan].leftVolume = leftvol;
263
g_audioChans[chan].rightVolume = rightvol;
264
return hleLogDebug(Log::sceAudio, 0);
265
}
266
267
static u32 sceAudioInit() {
268
// Don't need to do anything
269
return hleLogDebug(Log::sceAudio, 0);
270
}
271
272
static u32 sceAudioEnd() {
273
// Don't need to do anything
274
return hleLogDebug(Log::sceAudio, 0);
275
}
276
277
static u32 sceAudioOutput2Reserve(u32 sampleCount) {
278
auto &chan = g_audioChans[PSP_AUDIO_CHANNEL_OUTPUT2];
279
// This seems to ignore the MSB, for some reason.
280
sampleCount &= 0x7FFFFFFF;
281
if (sampleCount < 17 || sampleCount > 4111) {
282
return hleLogError(Log::sceAudio, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid sample count");
283
} else if (chan.reserved) {
284
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "channel already reserved");
285
}
286
287
chan.sampleCount = sampleCount;
288
chan.format = PSP_AUDIO_FORMAT_STEREO;
289
chan.reserved = true;
290
__AudioSetSRCFrequency(0);
291
return hleLogDebug(Log::sceAudio, 0);
292
}
293
294
static u32 sceAudioOutput2OutputBlocking(u32 vol, u32 dataPtr) {
295
// Note: 0xFFFFF, not 0xFFFF!
296
if (vol > 0xFFFFF) {
297
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume");
298
}
299
300
auto &chan = g_audioChans[PSP_AUDIO_CHANNEL_OUTPUT2];
301
if (!chan.reserved) {
302
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");
303
}
304
305
chan.leftVolume = vol;
306
chan.rightVolume = vol;
307
chan.sampleAddress = dataPtr;
308
309
hleEatCycles(10000);
310
int result = __AudioEnqueue(chan, PSP_AUDIO_CHANNEL_OUTPUT2, true);
311
if (result < 0)
312
return hleLogError(Log::sceAudio, result);
313
return hleLogDebug(Log::sceAudio, result);
314
}
315
316
static u32 sceAudioOutput2ChangeLength(u32 sampleCount) {
317
auto &chan = g_audioChans[PSP_AUDIO_CHANNEL_OUTPUT2];
318
if (!chan.reserved) {
319
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");
320
}
321
chan.sampleCount = sampleCount;
322
return hleLogDebug(Log::sceAudio, 0);
323
}
324
325
static u32 sceAudioOutput2GetRestSample() {
326
auto &chan = g_audioChans[PSP_AUDIO_CHANNEL_OUTPUT2];
327
if (!chan.reserved) {
328
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");
329
}
330
u32 size = (u32)chanSampleQueues[PSP_AUDIO_CHANNEL_OUTPUT2].size() / 2;
331
if (size > chan.sampleCount) {
332
// If ChangeLength reduces the size, it still gets output but this return is clamped.
333
size = chan.sampleCount;
334
}
335
return hleLogDebug(Log::sceAudio, size);
336
}
337
338
static u32 sceAudioOutput2Release() {
339
auto &chan = g_audioChans[PSP_AUDIO_CHANNEL_OUTPUT2];
340
if (!chan.reserved)
341
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");
342
if (!chanSampleQueues[PSP_AUDIO_CHANNEL_OUTPUT2].empty())
343
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "output busy");
344
345
chan.reset();
346
chan.reserved = false;
347
return hleLogDebug(Log::sceAudio, 0);
348
}
349
350
static u32 sceAudioSetFrequency(u32 freq) {
351
// TODO: Not available from user code.
352
if (freq == 44100 || freq == 48000) {
353
INFO_LOG(Log::sceAudio, "sceAudioSetFrequency(%08x)", freq);
354
__AudioSetOutputFrequency(freq);
355
return 0;
356
} else {
357
ERROR_LOG(Log::sceAudio, "sceAudioSetFrequency(%08x) - invalid frequency (must be 44.1 or 48 khz)", freq);
358
return SCE_ERROR_AUDIO_INVALID_FREQUENCY;
359
}
360
}
361
362
static u32 sceAudioSetVolumeOffset() {
363
ERROR_LOG(Log::sceAudio, "UNIMPL sceAudioSetVolumeOffset()");
364
return 0;
365
}
366
367
static bool SRCFrequencyAllowed(int freq) {
368
if (freq == 44100 || freq == 22050 || freq == 11025)
369
return true;
370
if (freq == 48000 || freq == 32000 || freq == 24000 || freq == 16000 || freq == 12000 || freq == 8000)
371
return true;
372
return false;
373
}
374
375
static u32 sceAudioSRCChReserve(u32 sampleCount, u32 freq, u32 format) {
376
auto &chan = g_audioChans[PSP_AUDIO_CHANNEL_SRC];
377
// This seems to ignore the MSB, for some reason.
378
sampleCount &= 0x7FFFFFFF;
379
if (format == 4) {
380
return hleReportError(Log::sceAudio, PSP_AUDIO_ERROR_SRC_FORMAT_4, "unexpected format");
381
} else if (format != 2) {
382
return hleLogError(Log::sceAudio, SCE_KERNEL_ERROR_INVALID_SIZE, "unexpected format");
383
} else if (sampleCount < 17 || sampleCount > 4111) {
384
return hleLogError(Log::sceAudio, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid sample count");
385
} else if (freq != 0 && !SRCFrequencyAllowed(freq)) {
386
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_FREQUENCY, "invalid frequency");
387
} else if (chan.reserved) {
388
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "channel already reserved");
389
}
390
391
chan.reserved = true;
392
chan.sampleCount = sampleCount;
393
chan.format = format == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO;
394
// Zero means default to 44.1kHz.
395
__AudioSetSRCFrequency(freq);
396
return hleLogDebug(Log::sceAudio, 0);
397
}
398
399
static u32 sceAudioSRCChRelease() {
400
auto &chan = g_audioChans[PSP_AUDIO_CHANNEL_SRC];
401
if (!chan.reserved)
402
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");
403
if (!chanSampleQueues[PSP_AUDIO_CHANNEL_SRC].empty())
404
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "output busy");
405
406
chan.reset();
407
chan.reserved = false;
408
return hleLogDebug(Log::sceAudio, 0);
409
}
410
411
static u32 sceAudioSRCOutputBlocking(u32 vol, u32 buf) {
412
if (vol > 0xFFFFF) {
413
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume");
414
}
415
416
auto &chan = g_audioChans[PSP_AUDIO_CHANNEL_SRC];
417
if (!chan.reserved) {
418
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");
419
}
420
421
chan.leftVolume = vol;
422
chan.rightVolume = vol;
423
chan.sampleAddress = buf;
424
425
hleEatCycles(10000);
426
int result = __AudioEnqueue(chan, PSP_AUDIO_CHANNEL_SRC, true);
427
if (result < 0)
428
return hleLogError(Log::sceAudio, result);
429
return hleLogDebug(Log::sceAudio, result);
430
}
431
432
static int sceAudioInputBlocking(u32 maxSamples, u32 sampleRate, u32 bufAddr) {
433
if (!Memory::IsValidAddress(bufAddr)) {
434
return hleLogError(Log::HLE, -1, "invalid address");
435
}
436
return hleLogInfo(Log::HLE, __MicInput(maxSamples, sampleRate, bufAddr, AUDIOINPUT));
437
}
438
439
static int sceAudioInput(u32 maxSamples, u32 sampleRate, u32 bufAddr) {
440
if (!Memory::IsValidAddress(bufAddr)) {
441
return hleLogError(Log::HLE, -1, "invalid address");
442
}
443
444
ERROR_LOG(Log::HLE, "UNTEST sceAudioInput: maxSamples: %d, samplerate: %d, bufAddr: %08x", maxSamples, sampleRate, bufAddr);
445
return __MicInput(maxSamples, sampleRate, bufAddr, AUDIOINPUT, false);
446
}
447
448
static int sceAudioInputInit(int unknown1, int gain, int unknown2) {
449
ERROR_LOG(Log::HLE, "UNIMPL sceAudioInputInit: unknown1: %d, gain: %d, unknown2: %d", unknown1, gain, unknown2);
450
return 0;
451
}
452
453
static int sceAudioInputInitEx(u32 paramAddr) {
454
ERROR_LOG(Log::HLE, "UNIMPL sceAudioInputInitEx: paramAddr: %08x", paramAddr);
455
return 0;
456
}
457
458
static int sceAudioPollInputEnd() {
459
ERROR_LOG(Log::HLE, "UNIMPL sceAudioPollInputEnd");
460
return 0;
461
}
462
463
static int sceAudioWaitInputEnd() {
464
ERROR_LOG(Log::HLE, "UNIMPL sceAudioWaitInputEnd");
465
return 0;
466
}
467
468
static int sceAudioGetInputLength() {
469
int ret = Microphone::getReadMicDataLength() / 2;
470
ERROR_LOG(Log::HLE, "UNTEST sceAudioGetInputLength(ret: %d)", ret);
471
return ret;
472
}
473
474
static u32 sceAudioRoutingSetMode(u32 mode) {
475
ERROR_LOG_REPORT(Log::sceAudio, "sceAudioRoutingSetMode(%08x)", mode);
476
int previousMode = defaultRoutingMode;
477
defaultRoutingMode = mode;
478
return previousMode;
479
}
480
481
static u32 sceAudioRoutingGetMode() {
482
ERROR_LOG_REPORT(Log::sceAudio, "sceAudioRoutingGetMode()");
483
return defaultRoutingMode;
484
}
485
486
static u32 sceAudioRoutingSetVolumeMode(u32 mode) {
487
ERROR_LOG_REPORT(Log::sceAudio, "sceAudioRoutingSetVolumeMode(%08x)", mode);
488
int previousMode = defaultRoutingVolMode;
489
defaultRoutingVolMode = mode;
490
return previousMode;
491
}
492
493
static u32 sceAudioRoutingGetVolumeMode() {
494
ERROR_LOG_REPORT(Log::sceAudio, "sceAudioRoutingGetVolumeMode()");
495
return defaultRoutingVolMode;
496
}
497
498
const HLEFunction sceAudio[] =
499
{
500
// Newer simplified single channel audio output. Presumably for games that use Atrac3
501
// directly from Sas instead of playing it on a separate audio channel.
502
{0X01562BA3, &WrapU_U<sceAudioOutput2Reserve>, "sceAudioOutput2Reserve", 'x', "i" },
503
{0X2D53F36E, &WrapU_UU<sceAudioOutput2OutputBlocking>, "sceAudioOutput2OutputBlocking", 'x', "xx" },
504
{0X63F2889C, &WrapU_U<sceAudioOutput2ChangeLength>, "sceAudioOutput2ChangeLength", 'x', "i" },
505
{0X647CEF33, &WrapU_V<sceAudioOutput2GetRestSample>, "sceAudioOutput2GetRestSample", 'i', "" },
506
{0X43196845, &WrapU_V<sceAudioOutput2Release>, "sceAudioOutput2Release", 'x', "" },
507
508
// "Traditional" audio channel interface
509
{0X80F1F7E0, &WrapU_V<sceAudioInit>, "sceAudioInit", 'x', "" },
510
{0X210567F7, &WrapU_V<sceAudioEnd>, "sceAudioEnd", 'x', "" },
511
{0XA2BEAA6C, &WrapU_U<sceAudioSetFrequency>, "sceAudioSetFrequency", 'x', "i" },
512
{0X927AC32B, &WrapU_V<sceAudioSetVolumeOffset>, "sceAudioSetVolumeOffset", 'x', "" },
513
{0X8C1009B2, &WrapU_UIU<sceAudioOutput>, "sceAudioOutput", 'x', "ixx" },
514
{0X136CAF51, &WrapU_UIU<sceAudioOutputBlocking>, "sceAudioOutputBlocking", 'x', "ixx" },
515
{0XE2D56B2D, &WrapU_UIIU<sceAudioOutputPanned>, "sceAudioOutputPanned", 'x', "ixxx"},
516
{0X13F592BC, &WrapU_UIIU<sceAudioOutputPannedBlocking>, "sceAudioOutputPannedBlocking", 'x', "ixxx"},
517
{0X5EC81C55, &WrapU_IUU<sceAudioChReserve>, "sceAudioChReserve", 'x', "iii" },
518
{0X6FC46853, &WrapU_U<sceAudioChRelease>, "sceAudioChRelease", 'x', "i" },
519
{0XE9D97901, &WrapI_U<sceAudioGetChannelRestLen>, "sceAudioGetChannelRestLen", 'i', "i" },
520
{0XB011922F, &WrapI_U<sceAudioGetChannelRestLength>, "sceAudioGetChannelRestLength", 'i', "i" },
521
{0XCB2E439E, &WrapU_UU<sceAudioSetChannelDataLen>, "sceAudioSetChannelDataLen", 'x', "ii" },
522
{0X95FD0C2D, &WrapU_UU<sceAudioChangeChannelConfig>, "sceAudioChangeChannelConfig", 'x', "ii" },
523
{0XB7E1D8E7, &WrapU_UUU<sceAudioChangeChannelVolume>, "sceAudioChangeChannelVolume", 'x', "ixx" },
524
525
// Like Output2, but with ability to do sample rate conversion.
526
{0X38553111, &WrapU_UUU<sceAudioSRCChReserve>, "sceAudioSRCChReserve", 'x', "iii" },
527
{0X5C37C0AE, &WrapU_V<sceAudioSRCChRelease>, "sceAudioSRCChRelease", 'x', "" },
528
{0XE0727056, &WrapU_UU<sceAudioSRCOutputBlocking>, "sceAudioSRCOutputBlocking", 'x', "xx" },
529
530
// Never seen these used
531
{0X41EFADE7, nullptr, "sceAudioOneshotOutput", '?', "" },
532
{0XB61595C0, nullptr, "sceAudioLoopbackTest", '?', "" },
533
534
// Microphone interface
535
{0X7DE61688, &WrapI_III<sceAudioInputInit>, "sceAudioInputInit", 'i', "iii" },
536
{0XE926D3FB, &WrapI_U<sceAudioInputInitEx>, "sceAudioInputInitEx", 'i', "x" },
537
{0X6D4BEC68, &WrapI_UUU<sceAudioInput>, "sceAudioInput", 'i', "xxx" },
538
{0X086E5895, &WrapI_UUU<sceAudioInputBlocking>, "sceAudioInputBlocking", 'i', "xxx" },
539
{0XA708C6A6, &WrapI_V<sceAudioGetInputLength>, "sceAudioGetInputLength", 'i', "" },
540
{0XA633048E, &WrapI_V<sceAudioPollInputEnd>, "sceAudioPollInputEnd", 'i', "" },
541
{0X87B2E651, &WrapI_V<sceAudioWaitInputEnd>, "sceAudioWaitInputEnd", 'i', "" },
542
543
{0X36FD8AA9, &WrapU_U<sceAudioRoutingSetMode>, "sceAudioRoutingSetMode", 'x', "x" },
544
{0X39240E7D, &WrapU_V<sceAudioRoutingGetMode>, "sceAudioRoutingGetMode", 'x', "" },
545
{0XBB548475, &WrapU_U<sceAudioRoutingSetVolumeMode>, "sceAudioRoutingSetVolumeMode", 'x', "x" },
546
{0X28235C56, &WrapU_V<sceAudioRoutingGetVolumeMode>, "sceAudioRoutingGetVolumeMode", 'x', "" },
547
548
};
549
550
void Register_sceAudio()
551
{
552
RegisterHLEModule("sceAudio", ARRAY_SIZE(sceAudio), sceAudio);
553
}
554
555