CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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