protected internal static int doAudioOutput(SoundChannel channel, int pvoid_buf) { int ret = -1; if (channel.Reserved) { //if (log.DebugEnabled) { Console.WriteLine(string.Format("doAudioOutput({0}, 0x{1:X8})", channel.ToString(), pvoid_buf)); } int bytesPerSample = channel.FormatStereo ? 4 : 2; int nbytes = bytesPerSample * channel.SampleLength; sbyte[] data = new sbyte[nbytes]; IMemoryReader memoryReader = MemoryReader.getMemoryReader(pvoid_buf, nbytes, 2); if (channel.FormatMono) { int volume = Audio.getVolume(channel.LeftVolume); for (int i = 0; i < nbytes; i += 2) { short sample = (short)memoryReader.readNext(); sample = SoundChannel.adjustSample(sample, volume); SoundChannel.storeSample(sample, data, i); } } else { int leftVolume = Audio.getVolume(channel.LeftVolume); int rightVolume = Audio.getVolume(channel.RightVolume); for (int i = 0; i < nbytes; i += 4) { short lsample = (short)memoryReader.readNext(); short rsample = (short)memoryReader.readNext(); lsample = SoundChannel.adjustSample(lsample, leftVolume); rsample = SoundChannel.adjustSample(rsample, rightVolume); SoundChannel.storeSample(lsample, data, i); SoundChannel.storeSample(rsample, data, i + 2); } } Modules.sceAudioModule.audioData = data; channel.play(data); ret = channel.SampleLength; } else { Console.WriteLine("doAudioOutput: channel " + channel.Index + " not reserved"); } return(ret); }
public virtual void hleAudioBlockingOutput(int threadId, SoundChannel channel, int addr, int leftVolume, int rightVolume) { //if (log.DebugEnabled) { Console.WriteLine(string.Format("hleAudioBlockingOutput {0}", channel.ToString())); } if (addr == 0) { // If another thread is also sending audio data on this channel, // do not wait for the channel to be drained, unblock the thread now. ThreadManForUser threadMan = Modules.ThreadManForUserModule; SceKernelThreadInfo thread = threadMan.getThreadById(threadId); if (thread != null) { thread.cpuContext._v0 = channel.SampleLength; threadMan.hleUnblockThread(threadId); } channel.Busy = false; } else if (!channel.OutputBlocking) { ThreadManForUser threadMan = Modules.ThreadManForUserModule; SceKernelThreadInfo thread = threadMan.getThreadById(threadId); if (thread != null) { changeChannelVolume(channel, leftVolume, rightVolume); int ret = doAudioOutput(channel, addr); thread.cpuContext._v0 = ret; threadMan.hleUnblockThread(threadId); } channel.Busy = false; } else { blockThreadOutput(threadId, channel, addr, leftVolume, rightVolume); } }
public virtual int sceAudioSRCOutputBlocking(int vol, 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 = FreeSRCChannel; if (pspSRCChannel == null) { return(SceKernelErrors.ERROR_AUDIO_CHANNEL_BUSY); } pspSRCChannel.Volume = channelVolume; if (buf.Null) { // Tested on PSP: // SRC audio also delays when buf == 0, in order to drain all // audio samples from the audio driver. if (!pspSRCChannel.Drained) { //if (log.DebugEnabled) { Console.WriteLine("sceAudioSRCOutputBlocking[buf==0] blocking " + pspSRCChannel); } // Do not update volume, it has already been updated above blockThreadOutput(pspSRCChannel, buf.Address, -1, -1); } else { Modules.ThreadManForUserModule.hleYieldCurrentThread(); } } else if (!pspSRC1Channel.Reserved) { // Channel is automatically reserved. The audio data (buf) is not used in this case. //if (log.DebugEnabled) { Console.WriteLine(string.Format("sceAudioSRCOutputBlocking automatically reserving channel {0}", pspSRCChannel)); } pspSRC1Channel.Reserved = true; pspSRC2Channel.Reserved = true; } else { if (!pspSRCChannel.OutputBlocking) { //if (log.DebugEnabled) { Console.WriteLine(string.Format("sceAudioSRCOutputBlocking[not blocking] {0} to {1}", buf, pspSRCChannel.ToString())); } Modules.ThreadManForUserModule.hleRescheduleCurrentThread(); return(doAudioOutput(pspSRCChannel, buf.Address)); } //if (log.DebugEnabled) { Console.WriteLine(string.Format("sceAudioSRCOutputBlocking[blocking] {0} to {1}", buf, pspSRCChannel.ToString())); } // Do not update volume, it has already been updated above blockThreadOutput(pspSRCChannel, buf.Address, -1, -1); } return(0); }