Skip to content

Commit

Permalink
Improved compatibility of SRC audio output (sceAudioSRCOutputBlocking…
Browse files Browse the repository at this point in the history
… and sceAudioOutput2OutputBlocking): two different threads can output audio on the SRC channel without interfering with each others. Simulate using 2 SRC channels.

git-svn-id: http://jpcsp.googlecode.com/svn/trunk@3658 4ab978e6-3352-0410-996c-0b42db0051c8
  • Loading branch information
[email protected] committed Oct 22, 2014
1 parent 133c664 commit 685caea
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 27 deletions.
66 changes: 50 additions & 16 deletions src/jpcsp/HLE/modules150/sceAudio.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ public void start() {
for (int channel = 0; channel < pspPCMChannels.length; channel++) {
pspPCMChannels[channel] = new SoundChannel(channel);
}
pspSRCChannel = new SoundChannel(8); // Use a special channel 8 to handle SRC functions.
pspSRC1Channel = new SoundChannel(8); // Use a special channel 8 to handle SRC functions (first channel).
pspSRC2Channel = new SoundChannel(9); // Use a special channel 9 to handle SRC functions (second channel).

setSettingsListener("emu.disablesceAudio", new DisableAudioSettingsListerner());
setSettingsListener("emu.disableblockingaudio", new DisableBlockingAudioSettingsListerner());
Expand Down Expand Up @@ -116,7 +117,10 @@ public void stop() {
protected static final int PSP_AUDIO_FORMAT_MONO = 0x10;

protected SoundChannel[] pspPCMChannels;
protected SoundChannel pspSRCChannel;
// Two different threads can output audio on the SRC channel
// without interfering with each others.
protected SoundChannel pspSRC1Channel;
protected SoundChannel pspSRC2Channel;

protected boolean disableChReserve;
protected boolean disableBlockingAudio;
Expand Down Expand Up @@ -202,6 +206,7 @@ protected static void blockThreadOutput(SoundChannel channel, int addr, int left
ThreadManForUser threadMan = Modules.ThreadManForUserModule;
blockThreadOutput(threadMan.getCurrentThreadID(), channel, addr, leftVolume, rightVolume);
threadMan.hleBlockCurrentThread(SceKernelThreadInfo.JPCSP_WAIT_AUDIO);
channel.setBusy(true);
}

protected static void blockThreadOutput(int threadId, SoundChannel channel, int addr, int leftVolume, int rightVolume) {
Expand All @@ -228,6 +233,7 @@ public void hleAudioBlockingOutput(int threadId, SoundChannel channel, int addr,
thread.cpuContext._v0 = channel.getSampleLength();
threadMan.hleUnblockThread(threadId);
}
channel.setBusy(false);
} else if (!channel.isOutputBlocking()) {
ThreadManForUser threadMan = Modules.ThreadManForUserModule;
SceKernelThreadInfo thread = threadMan.getThreadById(threadId);
Expand All @@ -237,6 +243,7 @@ public void hleAudioBlockingOutput(int threadId, SoundChannel channel, int addr,
thread.cpuContext._v0 = ret;
threadMan.hleUnblockThread(threadId);
}
channel.setBusy(false);
} else {
blockThreadOutput(threadId, channel, addr, leftVolume, rightVolume);
}
Expand Down Expand Up @@ -276,23 +283,39 @@ protected int hleAudioGetChannelRestLength(SoundChannel channel) {
return len;
}

protected SoundChannel getFreeSRCChannel() {
if (!pspSRC1Channel.isBusy()) {
return pspSRC1Channel;
}
if (!pspSRC2Channel.isBusy()) {
return pspSRC2Channel;
}
return null;
}

protected int hleAudioSRCChReserve(int sampleCount, int freq, int format) {
if (disableChReserve) {
log.warn(String.format("IGNORED hleAudioSRCChReserve sampleCount=%d, freq=%d, format=%d", sampleCount, freq, format));
return -1;
}

if (pspSRCChannel.isReserved()) {
if (pspSRC1Channel.isReserved()) {
if (log.isDebugEnabled()) {
log.debug(String.format("hleAudioSRCChReserve returning ERROR_AUDIO_CHANNEL_ALREADY_RESERVED"));
}
return SceKernelErrors.ERROR_AUDIO_CHANNEL_ALREADY_RESERVED;
}

pspSRCChannel.setSampleRate(freq);
pspSRCChannel.setReserved(true);
pspSRCChannel.setSampleLength(sampleCount);
pspSRCChannel.setFormat(format);
// Reserve both SRC channels
pspSRC1Channel.setSampleRate(freq);
pspSRC1Channel.setReserved(true);
pspSRC1Channel.setSampleLength(sampleCount);
pspSRC1Channel.setFormat(format);

pspSRC2Channel.setSampleRate(freq);
pspSRC2Channel.setReserved(true);
pspSRC2Channel.setSampleLength(sampleCount);
pspSRC2Channel.setFormat(format);

return 0;
}
Expand Down Expand Up @@ -750,26 +773,27 @@ public int sceAudioOutput2OutputBlocking(@CheckArgument("checkVolume2") int vol,

@HLEFunction(nid = 0x647CEF33, version = 150, checkInsideInterrupt = true)
public int sceAudioOutput2GetRestSample() {
if (!pspSRCChannel.isReserved()) {
if (!pspSRC1Channel.isReserved()) {
if (log.isDebugEnabled()) {
log.debug(String.format("sceAudioOutput2GetRestSample returning ERROR_AUDIO_CHANNEL_NOT_RESERVED"));
}
return SceKernelErrors.ERROR_AUDIO_CHANNEL_NOT_RESERVED;
}

return hleAudioGetChannelRestLength(pspSRCChannel);
return hleAudioGetChannelRestLength(pspSRC1Channel) + hleAudioGetChannelRestLength(pspSRC2Channel);
}

@HLEFunction(nid = 0x63F2889C, version = 150, checkInsideInterrupt = true)
public int sceAudioOutput2ChangeLength(@CheckArgument("checkSmallSampleCount") int sampleCount) {
if (!pspSRCChannel.isReserved()) {
if (!pspSRC1Channel.isReserved()) {
if (log.isDebugEnabled()) {
log.debug(String.format("sceAudioOutput2ChangeLength returning ERROR_AUDIO_CHANNEL_NOT_RESERVED"));
}
return SceKernelErrors.ERROR_AUDIO_CHANNEL_NOT_RESERVED;
}

pspSRCChannel.setSampleLength(sampleCount);
pspSRC1Channel.setSampleLength(sampleCount);
pspSRC2Channel.setSampleLength(sampleCount);

return 0;
}
Expand All @@ -781,15 +805,18 @@ public int sceAudioSRCChReserve(@CheckArgument("checkReserveSampleCount") int sa

@HLEFunction(nid = 0x5C37C0AE, version = 150, checkInsideInterrupt = true)
public int sceAudioSRCChRelease() {
if (!pspSRCChannel.isReserved()) {
if (!pspSRC1Channel.isReserved()) {
if (log.isDebugEnabled()) {
log.debug(String.format("sceAudioSRCChRelease returning ERROR_AUDIO_CHANNEL_NOT_RESERVED"));
}
return SceKernelErrors.ERROR_AUDIO_CHANNEL_NOT_RESERVED;
}

pspSRCChannel.release();
pspSRCChannel.setReserved(false);
pspSRC1Channel.release();
pspSRC1Channel.setReserved(false);

pspSRC2Channel.release();
pspSRC2Channel.setReserved(false);

return 0;
}
Expand All @@ -798,6 +825,12 @@ public int sceAudioSRCChRelease() {
public int sceAudioSRCOutputBlocking(@CheckArgument("checkVolume2") int vol, @CanBeNull TPointer buf) {
// Tested on PSP: any sound volume above MAX_VOLUME has the same effect as MAX_VOLUME.
int channelVolume = min(SoundChannel.MAX_VOLUME, vol);

SoundChannel pspSRCChannel = getFreeSRCChannel();
if (pspSRCChannel == null) {
return SceKernelErrors.ERROR_AUDIO_CHANNEL_BUSY;
}

pspSRCChannel.setVolume(channelVolume);

if (buf.isNull()) {
Expand All @@ -813,12 +846,13 @@ public int sceAudioSRCOutputBlocking(@CheckArgument("checkVolume2") int vol, @Ca
} else {
Modules.ThreadManForUserModule.hleYieldCurrentThread();
}
} else if (!pspSRCChannel.isReserved() && !disableChReserve) {
} else if (!pspSRC1Channel.isReserved() && !disableChReserve) {
// Channel is automatically reserved. The audio data (buf) is not used in this case.
if (log.isDebugEnabled()) {
log.debug(String.format("sceAudioSRCOutputBlocking automatically reserving channel %s", pspSRCChannel));
}
pspSRCChannel.setReserved(true);
pspSRC1Channel.setReserved(true);
pspSRC2Channel.setReserved(true);
} else {
if (!pspSRCChannel.isOutputBlocking() || disableBlockingAudio) {
if (log.isDebugEnabled()) {
Expand Down
32 changes: 21 additions & 11 deletions src/jpcsp/HLE/modules150/sceVaudio.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ public String getName() {
public void start() {
SoundChannel.init();

// The PSP is using the same channel as the SRC channel
pspVaudioChannel = Modules.sceAudioModule.pspSRCChannel;
// The PSP is using the same channel as the SRC channel(s)
pspVaudio1Channel = Modules.sceAudioModule.pspSRC1Channel;
pspVaudio2Channel = Modules.sceAudioModule.pspSRC2Channel;
pspVaudioChannelReserved = false;

super.start();
Expand All @@ -64,7 +65,8 @@ public void start() {
protected static final int PSP_VAUDIO_ALC_MODE_NONE = 0;
protected static final int PSP_VAUDIO_ALC_MODE_1 = 1;

protected SoundChannel pspVaudioChannel;
protected SoundChannel pspVaudio1Channel;
protected SoundChannel pspVaudio2Channel;
protected boolean pspVaudioChannelReserved;

public int checkSampleCount(int sampleCount) {
Expand Down Expand Up @@ -123,13 +125,15 @@ protected int changeChannelVolume(SoundChannel channel, int leftvol, int rightvo

@HLEFunction(nid = 0x67585DFD, version = 150, checkInsideInterrupt = true)
public int sceVaudioChRelease() {
if (!pspVaudioChannel.isReserved()) {
if (!pspVaudio1Channel.isReserved()) {
return SceKernelErrors.ERROR_AUDIO_CHANNEL_NOT_RESERVED;
}

pspVaudioChannelReserved = false;
pspVaudioChannel.release();
pspVaudioChannel.setReserved(false);
pspVaudio1Channel.release();
pspVaudio1Channel.setReserved(false);
pspVaudio2Channel.release();
pspVaudio2Channel.setReserved(false);

return 0;
}
Expand All @@ -140,17 +144,22 @@ public int sceVaudioChReserve(@CheckArgument("checkSampleCount") int sampleCount
if (pspVaudioChannelReserved) {
return SceKernelErrors.ERROR_BUSY;
}
if (pspVaudioChannel.isReserved()) {
if (pspVaudio1Channel.isReserved()) {
// PSP is yielding in this error case
Modules.ThreadManForUserModule.hleYieldCurrentThread();
return SceKernelErrors.ERROR_AUDIO_CHANNEL_ALREADY_RESERVED;
}

pspVaudioChannelReserved = true;
pspVaudioChannel.setReserved(true);
pspVaudioChannel.setSampleLength(sampleCount);
pspVaudioChannel.setSampleRate(freq);
pspVaudioChannel.setFormat(format == PSP_VAUDIO_FORMAT_MONO ? sceAudio.PSP_AUDIO_FORMAT_MONO : sceAudio.PSP_AUDIO_FORMAT_STEREO);
pspVaudio1Channel.setReserved(true);
pspVaudio1Channel.setSampleLength(sampleCount);
pspVaudio1Channel.setSampleRate(freq);
pspVaudio1Channel.setFormat(format == PSP_VAUDIO_FORMAT_MONO ? sceAudio.PSP_AUDIO_FORMAT_MONO : sceAudio.PSP_AUDIO_FORMAT_STEREO);

pspVaudio2Channel.setReserved(true);
pspVaudio2Channel.setSampleLength(sampleCount);
pspVaudio2Channel.setSampleRate(freq);
pspVaudio2Channel.setFormat(format == PSP_VAUDIO_FORMAT_MONO ? sceAudio.PSP_AUDIO_FORMAT_MONO : sceAudio.PSP_AUDIO_FORMAT_STEREO);

Modules.ThreadManForUserModule.hleYieldCurrentThread();

Expand All @@ -161,6 +170,7 @@ public int sceVaudioChReserve(@CheckArgument("checkSampleCount") int sampleCount
public int sceVaudioOutputBlocking(int vol, TPointer buf) {
int result = 0;

SoundChannel pspVaudioChannel = Modules.sceAudioModule.getFreeSRCChannel();
if (!pspVaudioChannel.isOutputBlocking()) {
if (log.isDebugEnabled()) {
log.debug(String.format("sceVaudioOutputBlocking[not blocking] %s", pspVaudioChannel));
Expand Down
10 changes: 10 additions & 0 deletions src/jpcsp/sound/SoundChannel.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public class SoundChannel {
private int sampleLength;
private int format;
private int numberBlockingBuffers;
private boolean busy;

public static void init() {
if (!AL.isCreated()) {
Expand Down Expand Up @@ -307,6 +308,14 @@ public static void storeSample(short sample, byte[] data, int index) {
data[index + 1] = (byte) (sample >> 8);
}

public boolean isBusy() {
return busy;
}

public void setBusy(boolean busy) {
this.busy = busy;
}

@Override
public String toString() {
StringBuilder s = new StringBuilder();
Expand All @@ -321,6 +330,7 @@ public String toString() {
s.append(String.format(", reserved=%b", reserved));
s.append(String.format(", sampleLength=%d", getSampleLength()));
s.append(String.format(", sampleRate=%d", getSampleRate()));
s.append(String.format(", busy=%b", busy));
}
s.append(")");

Expand Down

0 comments on commit 685caea

Please sign in to comment.