1207 lines
43 KiB
JavaScript
Raw Normal View History

2024-10-22 09:17:28 +08:00
import { isAndroid, isPc, webAudioNeedResume, isSupportBufferURL, isSupportPlayBackRate, isSupportInnerAudio, } from '../../check-version';
import { WEBAudio, unityAudioVolume } from './store';
import { TEMP_DIR_PATH } from './const';
import { createInnerAudio, destroyInnerAudio, printErrMsg, resumeWebAudio } from './utils';
const defaultSoundLength = 441000;
const needGetLength = false;
function jsAudioCreateUncompressedSoundClip(buffer, error, length) {
const soundClip = {
buffer,
error,
release() {
this.buffer = null;
WEBAudio.audioBufferLength -= length;
},
getLength() {
if (!this.buffer) {
return 0;
}
const sampleRateRatio = 44100 / this.buffer.sampleRate;
return this.buffer.length * sampleRateRatio;
},
getData(ptr, length) {
if (!this.buffer) {
console.log('Trying to get data of sound which is not loaded.');
return 0;
}
const startOutputBuffer = ptr >> 2;
const output = GameGlobal.unityNamespace.Module.HEAPF32.subarray(startOutputBuffer, startOutputBuffer + (length >> 2));
const numMaxSamples = Math.floor((length >> 2) / this.buffer.numberOfChannels);
const numReadSamples = Math.min(this.buffer.length, numMaxSamples);
for (let i = 0; i < this.buffer.numberOfChannels; i++) {
const channelData = this.buffer.getChannelData(i).subarray(0, numReadSamples);
output.set(channelData, i * numReadSamples);
}
return numReadSamples * this.buffer.numberOfChannels * 4;
},
getNumberOfChannels() {
if (!this.buffer) {
console.log('Trying to get metadata of sound which is not loaded.');
return 0;
}
return this.buffer.numberOfChannels;
},
getFrequency() {
if (!this.buffer) {
console.log('Trying to get metadata of sound which is not loaded.');
return 0;
}
return this.buffer.sampleRate;
},
};
return soundClip;
}
function jsAudioCreateUncompressedSoundClipFromCompressedAudio(audioData, ptr, length) {
const soundClip = jsAudioCreateUncompressedSoundClip(null, false, length);
WEBAudio.audioContext?.decodeAudioData(audioData, (buffer) => {
soundClip.buffer = buffer;
WEBAudio.audioBufferLength += length;
}, (error) => {
soundClip.error = true;
console.log(`Decode error: ${error}`);
});
return soundClip;
}
function jsAudioCreateCompressedSoundClip(audioData, ptr, length) {
const soundClip = {
error: false,
length: needGetLength ? 0 : defaultSoundLength,
url: undefined,
release() {
WEBAudio.audioBufferLength -= length;
if (isSupportBufferURL && this.url) {
wx.revokeBufferURL(this.url);
}
delete this.url;
},
getLength() {
return this.length || 0;
},
getData(ptr, length) {
console.warn('getData() is not supported for compressed sound.');
return 0;
},
getNumberOfChannels() {
console.warn('getNumberOfChannels() is not supported for compressed sound.');
return 0;
},
getFrequency() {
console.warn('getFrequency() is not supported for compressed sound.');
return 0;
},
};
if (isSupportBufferURL) {
const url = wx.createBufferURL(audioData);
soundClip.url = url;
WEBAudio.audioBufferLength += length;
}
else {
const tempFilePath = `${TEMP_DIR_PATH}/temp-audio${ptr + length}.mp3`;
if (GameGlobal.manager.getCachePath(tempFilePath)) {
soundClip.url = tempFilePath;
WEBAudio.audioBufferLength += length;
}
else {
GameGlobal.manager
.writeFile(tempFilePath, audioData)
.then(() => {
soundClip.url = tempFilePath;
WEBAudio.audioBufferLength += length;
})
.catch((res) => {
soundClip.error = true;
printErrMsg(res);
});
}
}
if (needGetLength && soundClip.url) {
const { audio: getAudio } = createInnerAudio();
getAudio.src = soundClip.url;
getAudio.onCanplay(() => {
soundClip.length = getAudio.duration * 44100;
setTimeout(() => {
soundClip.length = getAudio.duration * 44100;
getAudio.destroy();
}, 0);
});
}
return soundClip;
}
function jsAudioCreateUncompressedSoundClipFromPCM(channels, length, sampleRate, ptr) {
if (WEBAudio.audioContext) {
const buffer = WEBAudio.audioContext.createBuffer(channels, length, sampleRate);
for (let i = 0; i < channels; i++) {
const offs = (ptr >> 2) + length * i;
const copyToChannel = buffer.copyToChannel
|| function (source, channelNumber, startInChannel) {
const clipped = source.subarray(0, Math.min(source.length, buffer.length - (startInChannel | 0)));
buffer.getChannelData(channelNumber | 0).set(clipped, startInChannel | 0);
};
copyToChannel.apply(buffer, [GameGlobal.unityNamespace.Module.HEAPF32.subarray(offs, offs + length), i, 0]);
}
return jsAudioCreateUncompressedSoundClip(buffer, false, length);
}
return jsAudioCreateUncompressedSoundClip(null, false, length);
}
export class AudioChannelInstance {
threeD = false;
source;
gain;
callback = 0;
userData = 0;
loop = false;
loopStart = 0;
loopEnd = 0;
deleyTime = 0;
deleyOffset = 0;
constructor(callback, userData) {
if (WEBAudio.audioContext) {
this.gain = WEBAudio.audioContext.createGain();
if (this.gain) {
this.gain.connect(WEBAudio.audioContext.destination);
}
}
this.callback = callback;
this.userData = userData;
}
release() {
this.disconnectSource();
if (this.gain) {
this.gain.disconnect();
}
}
setLoop(loop) {
this.loop = loop;
if (!this.source || this.source.loop == loop) {
return;
}
this.source.loop = loop;
}
setLoopPoints(loopStart, loopEnd) {
this.loopStart = loopStart;
this.loopEnd = loopEnd;
if (!this.source) {
return;
}
if (this.source.loopStart !== loopStart) {
this.source.loopStart = loopStart;
}
if (this.source.loopEnd !== loopEnd) {
this.source.loopEnd = loopEnd;
}
}
playUrl(startTime, url, startOffset, volume, soundClip) {
try {
this.setup(url);
if (!this.source || !this.source.mediaElement) {
return;
}
if (typeof volume !== 'undefined') {
this.source.mediaElement.volume = volume;
}
if (WEBAudio.isMute) {
this.source.mediaElement.volume = 0;
}
this.source.mediaElement.onPlay(() => {
if (typeof this.source !== 'undefined') {
this.source.isPlaying = true;
if (!this.source.loop && this.source.mediaElement) {
const { duration } = this.source.mediaElement;
if (duration > 0) {
if (this.source.stopTicker) {
clearTimeout(this.source.stopTicker);
this.source.stopTicker = undefined;
}
const time = Math.floor(duration * 1000) + 1000;
this.source.stopTicker = setTimeout(() => {
if (this.source && this.source.mediaElement) {
this.source.mediaElement.stop();
}
}, time);
}
}
}
});
this.source.mediaElement.onPause(() => {
if (typeof this.source !== 'undefined') {
this.source.isPlaying = false;
if (this.source.stopTicker) {
clearTimeout(this.source.stopTicker);
this.source.stopTicker = undefined;
}
}
});
this.source.mediaElement.onStop(() => {
if (typeof this.source !== 'undefined') {
if (this.source.playAfterStop) {
this.source._reset();
if (typeof this.source.mediaElement !== 'undefined') {
this.source.mediaElement.play();
}
return;
}
this.source._reset();
this.disconnectSource();
}
if (this.callback) {
GameGlobal.unityNamespace.Module.dynCall_vi(this.callback, [this.userData]);
}
});
this.source.mediaElement.onEnded(() => {
if (typeof this.source !== 'undefined') {
this.source._reset();
this.disconnectSource();
}
if (this.callback) {
GameGlobal.unityNamespace.Module.dynCall_vi(this.callback, [this.userData]);
}
});
this.source.mediaElement.onError((e) => {
printErrMsg(e);
const { errMsg } = e;
if (errMsg && errMsg.indexOf('play audio fail') < 0) {
return;
}
if (typeof this.source !== 'undefined' && this.source.mediaElement) {
this.source._reset();
this.source.mediaElement.stop();
}
});
const fn = () => {
if (typeof this.source !== 'undefined' && this.source.mediaElement) {
const { duration } = this.source.mediaElement;
setTimeout(() => {
if (soundClip && this.source && this.source.mediaElement) {
soundClip.length = Math.round(Math.max(this.source.mediaElement.duration, 0) * 44100);
}
}, 0);
}
};
if (!this.source.canPlayFnList) {
this.source.canPlayFnList = [];
}
this.source.canPlayFnList.push(fn);
this.source.mediaElement.onCanplay(fn);
this.source.mediaElement.loop = this.loop;
this.deleyTime = startTime;
this.deleyOffset = startOffset;
this.source.start(startTime, startOffset);
this.source.playbackStartTime = startTime - startOffset / this.source.playbackRateValue;
}
catch (e) {
printErrMsg(`playUrl error. Exception: ${e}`);
}
}
playBuffer(startTime, buffer, startOffset, channel) {
try {
this.setup();
if (!this.source) {
return;
}
this.source.buffer = buffer;
this.source.onended = () => {
this.disconnectSource();
if (this.callback) {
GameGlobal.unityNamespace.Module.dynCall_vi(this.callback, [this.userData]);
}
};
if (this.gain && channel) {
let volume;
if (WEBAudio.isMute) {
unityAudioVolume.set(channel, this.gain.gain.value || 1);
volume = 0;
}
else {
volume = unityAudioVolume.get(channel);
}
if (this.gain.gain.value !== volume && typeof volume === 'number') {
this.gain.gain.value = volume;
}
}
this.source.loop = this.loop;
this.source.loopStart = this.loopStart;
this.source.loopEnd = this.loopEnd;
this.source.start(startTime, startOffset);
this.source.playbackStartTime = startTime - startOffset / this.source.playbackRateValue;
}
catch (e) {
printErrMsg(`playBuffer error. Exception: ${e}`);
}
}
disconnectSource() {
if (this.source) {
if (this.source.mediaElement) {
destroyInnerAudio(this.source.instanceId, false);
delete this.source.mediaElement;
delete this.source;
}
else if (!this.source.isPausedMockNode) {
this.source.onended = null;
if (this.source.disconnect) {
this.source.disconnect();
}
if (GameGlobal.isIOSHighPerformanceMode) {
this.source.buffer = null;
}
WEBAudio.bufferSourceNodeLength -= 1;
delete this.source;
}
else {
this.source.buffer = null;
}
}
}
stop(delay) {
if (!WEBAudio.audioContext) {
return;
}
if (this.source) {
if (this.source.buffer) {
try {
this.source.stop(WEBAudio.audioContext.currentTime + delay);
}
catch (e) { }
if (delay == 0) {
this.disconnectSource();
}
}
else if (this.source.mediaElement) {
this.source.stop(delay);
}
}
}
isPaused() {
if (!this.source) {
return true;
}
if (this.source.isPausedMockNode) {
return true;
}
if (this.source.mediaElement) {
return (!this.source.isPlaying || this.source.pauseRequested) ?? true;
}
return false;
}
pause() {
const { source } = this;
if (!source) {
return;
}
if (source.mediaElement) {
source._pauseMediaElement?.();
return;
}
if (source.isPausedMockNode) {
return;
}
const pausedSource = {
isPausedMockNode: true,
loop: this.loop,
loopStart: this.loopStart,
loopEnd: this.loopEnd,
buffer: source.buffer,
playbackRate: source.playbackRateValue,
playbackPausedAtPosition: source.estimatePlaybackPosition(),
setPitch(v) {
this.playbackRate = v;
},
_reset() { },
};
this.stop(0);
this.disconnectSource();
this.source = pausedSource;
}
resume() {
if (!WEBAudio.audioContext) {
return;
}
if (!this.source) {
return;
}
if (this.source.mediaElement) {
this.source.start(this.deleyTime, this.deleyOffset);
delete this.deleyTime;
delete this.deleyOffset;
return;
}
const pausedSource = this.source;
if (!pausedSource.isPausedMockNode) {
return;
}
delete this.source;
if (!pausedSource.buffer) {
return;
}
this.playBuffer(WEBAudio.audioContext.currentTime - Math.min(0, pausedSource.playbackPausedAtPosition), pausedSource.buffer, Math.max(0, pausedSource.playbackPausedAtPosition));
const getSource = this.source;
if (getSource) {
getSource.loop = pausedSource.loop;
getSource.loopStart = pausedSource.loopStart;
getSource.loopEnd = pausedSource.loopEnd;
getSource.setPitch(pausedSource.playbackRate);
}
}
setVolume(volume, isDefault) {
if (!WEBAudio.audioContext) {
return;
}
if (WEBAudio.isMute) {
volume = 0;
}
if (isDefault && volume == 1) {
return;
}
if (this.source) {
if (this.source.buffer && this.gain) {
this.gain.gain.value = volume;
}
else if (this.source.mediaElement) {
this.source.mediaElement.volume = volume;
}
}
}
setup(url) {
if (!WEBAudio.audioContext) {
return;
}
if (this.source && !this.source.isPausedMockNode) {
if (!this.source.url) {
if (typeof url !== 'undefined') {
this.stop(0);
}
else {
}
}
else if (typeof url === 'undefined') {
if (typeof this.source !== 'undefined') {
this.source._reset();
}
this.disconnectSource();
}
else {
this.source._reset();
this.disconnectSource();
}
}
if (!url) {
this.source = WEBAudio.audioContext.createBufferSource();
WEBAudio.bufferSourceNodeLength += 1;
const { source } = this;
Object.defineProperty(this.source, 'playbackRateValue', {
get() {
return source?.playbackRate?.value ?? 0;
},
set(v) {
if (!source) {
return;
}
if (typeof source.playbackRate === 'undefined') {
return;
}
source.playbackRate.value = v;
},
});
}
else {
const { audio: getAudio, id: instanceId } = createInnerAudio();
getAudio.src = url;
const innerFixPlay = () => {
if (!this.source) {
return;
}
this.source.needCanPlay = true;
if (this.source.fixPlayTicker) {
clearTimeout(this.source.fixPlayTicker);
delete this.source.fixPlayTicker;
}
this.source.fixPlayTicker = setTimeout(() => {
if (this.source && this.source.mediaElement && this.source.needCanPlay && !this.source.isPlaying) {
this.source.mediaElement.play();
}
}, 100);
};
const innerPlay = () => {
if (this.source && this.source.mediaElement) {
if (isSupportBufferURL && this.source.readyToPlay) {
if (this.source.stopCache) {
this.source.stopCache = false;
this.source.playAfterStop = true;
}
else if (!this.source.isPlaying) {
if (isAndroid) {
innerFixPlay();
}
this.source.mediaElement.play();
}
}
else {
const fn = () => {
if (!this.source) {
return;
}
this.source.needCanPlay = false;
this.source.readyToPlay = true;
if (typeof this.source.mediaElement !== 'undefined') {
const { duration } = this.source.mediaElement;
this.source.canPlayFnList.forEach((fn) => {
this.source?.mediaElement?.offCanplay(fn);
});
this.source.canPlayFnList = [];
}
if (this.source.stopCache) {
this.source.stopCache = false;
this.source.playAfterStop = true;
}
else if (!this.source.isPlaying) {
if (isAndroid) {
innerFixPlay();
}
if (typeof this.source.mediaElement !== 'undefined') {
this.source.mediaElement.play();
}
}
};
if (!this.source.canPlayFnList) {
this.source.canPlayFnList = [];
}
this.source.canPlayFnList.push(fn);
this.source.mediaElement.onCanplay(fn);
innerFixPlay();
}
}
};
const _reset = () => {
if (!this.source) {
return;
}
this.source.readyToPlay = false;
this.source.isPlaying = false;
this.source.stopCache = false;
this.source.playAfterStop = false;
this.source.needCanPlay = false;
if (this.source.stopTicker) {
clearTimeout(this.source.stopTicker);
this.source.stopTicker = undefined;
}
};
const _pauseMediaElement = () => {
if (typeof this.source === 'undefined') {
return;
}
if (this.source.playTimeout) {
this.source.pauseRequested = true;
}
else if (this.source.isPlaying && this.source.mediaElement) {
this.source.mediaElement.pause();
}
};
const _startPlayback = (offset) => {
if (typeof this.source === 'undefined' || !this.source.mediaElement) {
return;
}
if (this.source.playTimeout) {
if (typeof this.source.mediaElement.seek === 'function') {
this.source.mediaElement.seek(offset);
}
else {
this.source.mediaElement.currentTime = offset;
}
this.source.pauseRequested = false;
return;
}
innerPlay();
if (typeof this.source.mediaElement.seek === 'function') {
this.source.mediaElement.seek(offset);
}
else {
this.source.mediaElement.currentTime = offset;
}
};
const start = (startTime, offset) => {
if (typeof this.source === 'undefined') {
return;
}
if (typeof startTime === 'undefined' && typeof offset === 'undefined') {
innerPlay();
return;
}
if (typeof startTime === 'undefined') {
startTime = 0;
}
if (typeof offset === 'undefined') {
offset = 0;
}
const startDelayThresholdMS = 4;
const startDelayMS = startTime * 1e3;
if (startDelayMS > startDelayThresholdMS) {
if (this.source.playTimeout) {
clearTimeout(this.source.playTimeout);
}
this.source.playTimeout = setTimeout(() => {
if (typeof this.source !== 'undefined') {
delete this.source.playTimeout;
this.source._startPlayback?.(offset || 0);
}
}, startDelayMS);
}
else {
this.source._startPlayback?.(offset);
}
};
const stop = (stopTime) => {
if (typeof this.source === 'undefined') {
return;
}
if (typeof stopTime === 'undefined') {
stopTime = 0;
}
const stopDelayThresholdMS = 4;
const stopDelayMS = stopTime * 1e3;
if (stopDelayMS > stopDelayThresholdMS) {
setTimeout(() => {
if (this.source && this.source.mediaElement) {
this.source.stopCache = true;
this.source.mediaElement.stop();
}
}, stopDelayMS);
}
else if (this.source.mediaElement) {
this.source.stopCache = true;
this.source.mediaElement.stop();
}
};
this.source = {
instanceId,
mediaElement: getAudio,
url,
playbackStartTime: 0,
playbackRate: 1,
pauseRequested: false,
_reset,
_pauseMediaElement,
_startPlayback,
start,
stop,
};
const { buffered, referrerPolicy, volume } = getAudio;
const { source } = this;
Object.defineProperty(this.source, 'loopStart', {
get() {
return 0;
},
set(v) { },
});
Object.defineProperty(source, 'loopEnd', {
get() {
return 0;
},
set(v) { },
});
Object.defineProperty(source, 'loop', {
get() {
return source?.mediaElement?.loop ?? false;
},
set(v) {
if (!source || !source.mediaElement) {
return;
}
source.mediaElement.loop = v;
},
});
Object.defineProperty(source, 'playbackRateValue', {
get() {
return source?.playbackRate ?? 1;
},
set(v) {
if (!source || !source.mediaElement) {
return;
}
if (!isSupportPlayBackRate) {
source.mediaElement.playbackRate = 1;
}
else {
source.playbackRate = v;
source.mediaElement.playbackRate = v;
}
},
});
Object.defineProperty(source, 'currentTime', {
get() {
return source?.mediaElement?.currentTime ?? 0;
},
set(v) {
if (!source || !source.mediaElement) {
return;
}
if (typeof source.mediaElement.seek === 'function') {
source.mediaElement.seek(v);
}
else {
source.mediaElement.currentTime = v;
}
},
});
}
if (!this.source) {
return;
}
this.source.estimatePlaybackPosition = () => {
if (!this.source) {
return 0;
}
let t;
if (WEBAudio.audioContext) {
t = (WEBAudio.audioContext.currentTime - this.source.playbackStartTime) * this.source.playbackRateValue;
}
else {
t = -this.source.playbackStartTime * this.source.playbackRateValue;
}
if (typeof this.source.loopStart !== 'undefined' && typeof this.source.loopEnd !== 'undefined') {
if (this.source.loop && t >= this.source.loopStart) {
t = ((t - this.source.loopStart) % (this.source.loopEnd - this.source.loopStart)) + this.source.loopStart;
}
}
return t;
};
this.source.setPitch = (newPitch) => {
if (!this.source) {
return 0;
}
const curPosition = this.source.estimatePlaybackPosition();
if (curPosition >= 0) {
if (WEBAudio.audioContext) {
this.source.playbackStartTime = WEBAudio.audioContext.currentTime - curPosition / newPitch;
}
}
this.source.playbackRateValue = newPitch;
};
this.setupPanning();
}
setupPanning() {
if (typeof this.source === 'undefined') {
return;
}
if (this.source.isPausedMockNode) {
return;
}
if (this.source.disconnect && this.source.connect) {
this.source.disconnect();
if (this.gain) {
this.source.connect(this.gain);
}
}
}
isStopped() {
return !this.source;
}
}
export default {
_JS_Sound_Create_Channel(callback, userData) {
if (!WEBAudio.audioContext || WEBAudio.audioWebEnabled === 0) {
return 0;
}
const channel = new AudioChannelInstance(callback, userData);
WEBAudio.audioInstances[++WEBAudio.audioInstanceIdCounter] = channel;
return WEBAudio.audioInstanceIdCounter;
},
_JS_Sound_GetLength(bufferInstance) {
if (WEBAudio.audioWebEnabled === 0) {
return defaultSoundLength;
}
const soundClip = WEBAudio.audioInstances[bufferInstance];
if (!soundClip) {
return defaultSoundLength;
}
const length = soundClip.getLength() || defaultSoundLength;
return length;
},
_JS_Sound_GetLoadState(bufferInstance) {
if (WEBAudio.audioWebEnabled === 0) {
return 2;
}
const soundClip = WEBAudio.audioInstances[bufferInstance];
if (!soundClip || soundClip.error) {
return 2;
}
if (soundClip.buffer) {
return 0;
}
if (soundClip.url && soundClip.length) {
return 0;
}
return 1;
},
_JS_Sound_Init() {
try {
if (wx && wx.createWebAudioContext) {
WEBAudio.audioContext = wx.createWebAudioContext();
console.log('use wx WebAudio');
}
if (!WEBAudio.audioContext) {
printErrMsg('Minigame Web Audio API not suppoted');
return;
}
WEBAudio.audioWebSupport = 1;
WEBAudio.audioWebEnabled = 1;
let webAutoResumeTicker = null;
wx.onHide(() => {
if (webAutoResumeTicker) {
clearTimeout(webAutoResumeTicker);
webAutoResumeTicker = null;
}
if (!GameGlobal.isIOSHighPerformanceMode) {
WEBAudio.audioContext?.suspend();
}
});
wx.onShow(() => {
WEBAudio.audioContext?.resume();
});
if (webAudioNeedResume) {
webAutoResumeTicker = setTimeout(() => {
resumeWebAudio();
}, 2000);
}
}
catch (e) {
printErrMsg('Web Audio API is not supported in this browser');
}
},
_JS_Sound_IsStopped(channelInstance) {
if (WEBAudio.audioWebEnabled == 0) {
return true;
}
const channel = WEBAudio.audioInstances[channelInstance];
if (!channel) {
return true;
}
return channel.isStopped();
},
_JS_Sound_Load(ptr, length, decompress) {
if (!WEBAudio.audioContext || WEBAudio.audioWebEnabled === 0) {
return 0;
}
const audioData = GameGlobal.unityNamespace.Module.HEAPU8.buffer.slice(ptr, ptr + length);
if (length > 131072) {
decompress = 0;
}
else {
decompress = 1;
}
if (isPc) {
decompress = 1;
}
if (isAndroid && !isSupportInnerAudio) {
decompress = 1;
}
let soundClip;
if (decompress && WEBAudio.audioWebSupport) {
soundClip = jsAudioCreateUncompressedSoundClipFromCompressedAudio(audioData, ptr, length);
}
else {
soundClip = jsAudioCreateCompressedSoundClip(audioData, ptr, length);
}
WEBAudio.audioInstances[++WEBAudio.audioInstanceIdCounter] = soundClip;
return WEBAudio.audioInstanceIdCounter;
},
_JS_Sound_Load_PCM(channels, length, sampleRate, ptr) {
if (!WEBAudio.audioContext || WEBAudio.audioWebSupport === 0 || WEBAudio.audioWebEnabled === 0) {
return 0;
}
const sound = jsAudioCreateUncompressedSoundClipFromPCM(channels, length, sampleRate, ptr);
WEBAudio.audioInstances[++WEBAudio.audioInstanceIdCounter] = sound;
return WEBAudio.audioInstanceIdCounter;
},
_JS_Sound_Play(bufferInstance, channelInstance, offset, delay) {
if (!WEBAudio.audioContext || WEBAudio.audioWebEnabled === 0) {
return;
}
WXWASMSDK._JS_Sound_Stop(channelInstance, 0);
const soundClip = WEBAudio.audioInstances[bufferInstance];
const channel = WEBAudio.audioInstances[channelInstance];
if (soundClip && soundClip.url) {
try {
channel.playUrl(delay, soundClip.url, offset, unityAudioVolume.get(channel), soundClip);
}
catch (e) {
printErrMsg(`playUrl error. Exception: ${e}`);
}
}
else if (soundClip && soundClip.buffer) {
try {
channel.playBuffer(WEBAudio.audioContext.currentTime + delay, soundClip.buffer, offset, channel);
}
catch (e) {
printErrMsg(`playBuffer error. Exception: ${e}`);
}
}
else {
console.log('Trying to play sound which is not loaded.');
}
},
_JS_Sound_ReleaseInstance(instance) {
if (WEBAudio.audioWebEnabled === 0) {
return;
}
const object = WEBAudio.audioInstances[instance];
if (object) {
object.release();
}
delete WEBAudio.audioInstances[instance];
},
_JS_Sound_ResumeIfNeeded() {
if (WEBAudio.audioWebSupport === 0 || WEBAudio.audioWebEnabled === 0) {
return;
}
resumeWebAudio();
},
_JS_Sound_Set3D(channelInstance, threeD) {
if (WEBAudio.audio3DSupport === 0 || WEBAudio.audioWebEnabled === 0) {
return;
}
const channel = WEBAudio.audioInstances[channelInstance];
if (channel.threeD != threeD) {
channel.threeD = threeD;
if (!channel.source) {
channel.setup();
}
channel.setupPanning();
}
},
_JS_Sound_SetListenerOrientation(x, y, z, xUp, yUp, zUp) {
if (!WEBAudio.audioContext
|| WEBAudio.audio3DSupport === 0
|| WEBAudio.audioWebSupport === 0
|| WEBAudio.audioWebEnabled === 0) {
return;
}
x = x > 0 ? 0 : x;
y = y > 0 ? 0 : y;
z = z > 0 ? 0 : z;
xUp = xUp < 0 ? 0 : xUp;
yUp = yUp < 0 ? 0 : yUp;
zUp = zUp < 0 ? 0 : zUp;
if (x == WEBAudio.lOrientation.x
&& y == WEBAudio.lOrientation.y
&& z == WEBAudio.lOrientation.z
&& xUp == WEBAudio.lOrientation.xUp
&& yUp == WEBAudio.lOrientation.yUp
&& zUp == WEBAudio.lOrientation.zUp) {
return;
}
WEBAudio.lOrientation.x = x;
WEBAudio.lOrientation.y = y;
WEBAudio.lOrientation.z = z;
WEBAudio.lOrientation.xUp = xUp;
WEBAudio.lOrientation.yUp = yUp;
WEBAudio.lOrientation.zUp = zUp;
if (WEBAudio.audioContext.listener.forwardX) {
WEBAudio.audioContext.listener.forwardX.setValueAtTime(-x, WEBAudio.audioContext.currentTime);
WEBAudio.audioContext.listener.forwardY.setValueAtTime(-y, WEBAudio.audioContext.currentTime);
WEBAudio.audioContext.listener.forwardZ.setValueAtTime(-z, WEBAudio.audioContext.currentTime);
WEBAudio.audioContext.listener.upX.setValueAtTime(xUp, WEBAudio.audioContext.currentTime);
WEBAudio.audioContext.listener.upY.setValueAtTime(yUp, WEBAudio.audioContext.currentTime);
WEBAudio.audioContext.listener.upZ.setValueAtTime(zUp, WEBAudio.audioContext.currentTime);
}
else {
WEBAudio.audioContext.listener.setOrientation(-x, -y, -z, xUp, yUp, zUp);
}
},
_JS_Sound_SetListenerPosition(x, y, z) {
if (!WEBAudio.audioContext
|| WEBAudio.audio3DSupport === 0
|| WEBAudio.audioWebSupport === 0
|| WEBAudio.audioWebEnabled === 0) {
return;
}
x = x < 0 ? 0 : x;
y = y < 0 ? 0 : y;
z = z < 0 ? 0 : z;
if (x == WEBAudio.lPosition.x && y == WEBAudio.lPosition.y && z == WEBAudio.lPosition.z) {
return;
}
WEBAudio.lPosition.x = x;
WEBAudio.lPosition.y = y;
WEBAudio.lPosition.z = z;
if (WEBAudio.audioContext.listener.positionX) {
WEBAudio.audioContext.listener.positionX.setValueAtTime(x, WEBAudio.audioContext.currentTime);
WEBAudio.audioContext.listener.positionY.setValueAtTime(y, WEBAudio.audioContext.currentTime);
WEBAudio.audioContext.listener.positionZ.setValueAtTime(z, WEBAudio.audioContext.currentTime);
}
else {
WEBAudio.audioContext.listener.setPosition(x, y, z);
}
},
_JS_Sound_SetLoop(channelInstance, loop) {
if (WEBAudio.audioWebEnabled === 0) {
return;
}
const channel = WEBAudio.audioInstances[channelInstance];
if (!channel.source) {
channel.setup();
}
if (!channel.source) {
return;
}
channel.setLoop(loop > 0);
},
_JS_Sound_SetLoopPoints(channelInstance, loopStart, loopEnd) {
if (WEBAudio.audioWebEnabled === 0) {
return;
}
const channel = WEBAudio.audioInstances[channelInstance];
if (!channel.source) {
channel.setup();
}
if (!channel.source) {
return;
}
channel.setLoopPoints(loopStart, loopEnd);
},
_JS_Sound_SetPaused(channelInstance, paused) {
if (WEBAudio.audioWebEnabled === 0) {
return;
}
const channel = WEBAudio.audioInstances[channelInstance];
if (!!paused !== channel.isPaused()) {
if (paused) {
channel.pause();
}
else {
channel.resume();
}
}
},
_JS_Sound_SetPitch(channelInstance, v) {
if (WEBAudio.audioWebSupport === 0 || WEBAudio.audioWebEnabled === 0) {
return;
}
try {
WEBAudio.audioInstances[channelInstance].source?.setPitch(v);
}
catch (e) {
printErrMsg(`Invalid audio pitch ${v} specified to WebAudio backend!`);
}
},
_JS_Sound_SetPosition(channelInstance, x, y, z) {
if (WEBAudio.audio3DSupport === 0 || WEBAudio.audioWebSupport === 0 || WEBAudio.audioWebEnabled === 0) {
return;
}
console.error('不支持3d音效');
},
_JS_Sound_SetVolume(channelInstance, v) {
if (WEBAudio.audioWebEnabled === 0) {
return;
}
try {
const volume = Number(v.toFixed(2));
const channel = WEBAudio.audioInstances[channelInstance];
const cur = unityAudioVolume.get(channel);
if (cur === volume) {
return;
}
unityAudioVolume.set(channel, volume);
channel.setVolume(volume, cur == undefined);
}
catch (e) {
printErrMsg(`Invalid audio volume ${v} specified to WebAudio backend!`);
}
},
_JS_Sound_Stop(channelInstance, delay) {
if (WEBAudio.audioWebEnabled === 0) {
return;
}
const channel = WEBAudio.audioInstances[channelInstance];
channel.stop(delay);
},
_JS_Sound_GetData(bufferInstance, ptr, length) {
if (WEBAudio.audioWebEnabled === 0) {
return 0;
}
const soundClip = WEBAudio.audioInstances[bufferInstance];
if (!soundClip) {
return 0;
}
return soundClip.getData(ptr, length) ?? 0;
},
_JS_Sound_GetMetaData(buffer, bufferInstance, metaData) {
if (WEBAudio.audioWebEnabled === 0) {
buffer[metaData >> 2] = 0;
buffer[(metaData >> 2) + 1] = 0;
return false;
}
const soundClip = WEBAudio.audioInstances[bufferInstance];
if (!soundClip) {
buffer[metaData >> 2] = 0;
buffer[(metaData >> 2) + 1] = 0;
return false;
}
buffer[metaData >> 2] = soundClip.getNumberOfChannels() ?? 0;
buffer[(metaData >> 2) + 1] = soundClip.getFrequency() ?? 0;
return true;
},
_JS_Sound_GetAudioBufferSampleRate(soundInstance) {
if (WEBAudio.audioWebEnabled === 0) {
return WEBAudio.FAKEMOD_SAMPLERATE;
}
const audioInstance = WEBAudio.audioInstances[soundInstance];
if (!audioInstance) {
return WEBAudio.FAKEMOD_SAMPLERATE;
}
const buffer = audioInstance.buffer
? audioInstance.buffer
: audioInstance.source
? audioInstance.source?.buffer
: null;
if (!buffer) {
return WEBAudio.FAKEMOD_SAMPLERATE;
}
return buffer.sampleRate;
},
_JS_Sound_GetAudioContextSampleRate() {
if (WEBAudio.audioWebEnabled === 0 || !WEBAudio.audioContext) {
return WEBAudio.FAKEMOD_SAMPLERATE;
}
return WEBAudio.audioContext.sampleRate;
},
};