SoundEngine.java
net.minecraft.client.sounds.SoundEngine
信息
- 全限定名:net.minecraft.client.sounds.SoundEngine
- 类型:public class
- 包:net.minecraft.client.sounds
- 源码路径:src/main/java/net/minecraft/client/sounds/SoundEngine.java
- 起始行号:L47
- 职责:
TODO
字段/常量
-
MARKER- 类型:
Marker - 修饰符:
private static final - 源码定位:
L48 - 说明:
TODO
- 类型:
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L49 - 说明:
TODO
- 类型:
-
PITCH_MIN- 类型:
float - 修饰符:
private static final - 源码定位:
L50 - 说明:
TODO
- 类型:
-
PITCH_MAX- 类型:
float - 修饰符:
private static final - 源码定位:
L51 - 说明:
TODO
- 类型:
-
VOLUME_MIN- 类型:
float - 修饰符:
private static final - 源码定位:
L52 - 说明:
TODO
- 类型:
-
VOLUME_MAX- 类型:
float - 修饰符:
private static final - 源码定位:
L53 - 说明:
TODO
- 类型:
-
MIN_SOURCE_LIFETIME- 类型:
int - 修饰符:
private static final - 源码定位:
L54 - 说明:
TODO
- 类型:
-
ONLY_WARN_ONCE- 类型:
Set<Identifier> - 修饰符:
private static final - 源码定位:
L55 - 说明:
TODO
- 类型:
-
MISSING_SOUND- 类型:
String - 修饰符:
public static final - 源码定位:
L56 - 说明:
TODO
- 类型:
-
OPEN_AL_SOFT_PREFIX- 类型:
String - 修饰符:
public static final - 源码定位:
L57 - 说明:
TODO
- 类型:
-
OPEN_AL_SOFT_PREFIX_LENGTH- 类型:
int - 修饰符:
public static final - 源码定位:
L58 - 说明:
TODO
- 类型:
-
soundManager- 类型:
SoundManager - 修饰符:
private final - 源码定位:
L59 - 说明:
TODO
- 类型:
-
options- 类型:
Options - 修饰符:
private final - 源码定位:
L60 - 说明:
TODO
- 类型:
-
loaded- 类型:
boolean - 修饰符:
private - 源码定位:
L61 - 说明:
TODO
- 类型:
-
library- 类型:
Library - 修饰符:
private final - 源码定位:
L62 - 说明:
TODO
- 类型:
-
listener- 类型:
Listener - 修饰符:
private final - 源码定位:
L63 - 说明:
TODO
- 类型:
-
soundBuffers- 类型:
SoundBufferLibrary - 修饰符:
private final - 源码定位:
L64 - 说明:
TODO
- 类型:
-
executor- 类型:
SoundEngineExecutor - 修饰符:
private final - 源码定位:
L65 - 说明:
TODO
- 类型:
-
channelAccess- 类型:
ChannelAccess - 修饰符:
private final - 源码定位:
L66 - 说明:
TODO
- 类型:
-
tickCount- 类型:
int - 修饰符:
private - 源码定位:
L67 - 说明:
TODO
- 类型:
-
lastSeenDevices- 类型:
DeviceList - 修饰符:
private - 源码定位:
L68 - 说明:
TODO
- 类型:
-
deviceTracker- 类型:
DeviceTracker - 修饰符:
private final - 源码定位:
L69 - 说明:
TODO
- 类型:
-
instanceToChannel- 类型:
Map<SoundInstance,ChannelAccess.ChannelHandle> - 修饰符:
private final - 源码定位:
L70 - 说明:
TODO
- 类型:
-
instanceBySource- 类型:
Multimap<SoundSource,SoundInstance> - 修饰符:
private final - 源码定位:
L71 - 说明:
TODO
- 类型:
-
gainBySource- 类型:
Object2FloatMap<SoundSource> - 修饰符:
private final - 源码定位:
L72 - 说明:
TODO
- 类型:
-
tickingSounds- 类型:
List<TickableSoundInstance> - 修饰符:
private final - 源码定位:
L73 - 说明:
TODO
- 类型:
-
queuedSounds- 类型:
Map<SoundInstance,Integer> - 修饰符:
private final - 源码定位:
L74 - 说明:
TODO
- 类型:
-
soundDeleteTime- 类型:
Map<SoundInstance,Integer> - 修饰符:
private final - 源码定位:
L75 - 说明:
TODO
- 类型:
-
listeners- 类型:
List<SoundEventListener> - 修饰符:
private final - 源码定位:
L76 - 说明:
TODO
- 类型:
-
queuedTickableSounds- 类型:
List<TickableSoundInstance> - 修饰符:
private final - 源码定位:
L77 - 说明:
TODO
- 类型:
-
preloadQueue- 类型:
List<Sound> - 修饰符:
private final - 源码定位:
L78 - 说明:
TODO
- 类型:
内部类/嵌套类型
net.minecraft.client.sounds.SoundEngine.PlayResult- 类型:
enum - 修饰符:
public static - 源码定位:
L532 - 说明:
TODO
- 类型:
构造器
public SoundEngine(SoundManager soundManager, Options options, ResourceProvider resourceProvider) @ L80
- 构造器名:SoundEngine
- 源码定位:L80
- 修饰符:public
参数:
- soundManager: SoundManager
- options: Options
- resourceProvider: ResourceProvider
说明:
TODO
方法
下面的方法块按源码顺序生成。
public void reload() @ L87
- 方法名:reload
- 源码定位:L87
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
private synchronized void loadLibrary() @ L104
- 方法名:loadLibrary
- 源码定位:L104
- 返回类型:void
- 修饰符:private synchronized
参数:
- 无
说明:
TODO
public void refreshCategoryVolume(SoundSource source) @ L120
- 方法名:refreshCategoryVolume
- 源码定位:L120
- 返回类型:void
- 修饰符:public
参数:
- source: SoundSource
说明:
TODO
public void destroy() @ L131
- 方法名:destroy
- 源码定位:L131
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public void emergencyShutdown() @ L140
- 方法名:emergencyShutdown
- 源码定位:L140
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public void stop(SoundInstance soundInstance) @ L146
- 方法名:stop
- 源码定位:L146
- 返回类型:void
- 修饰符:public
参数:
- soundInstance: SoundInstance
说明:
TODO
public void updateCategoryVolume(SoundSource source, float gain) @ L155
- 方法名:updateCategoryVolume
- 源码定位:L155
- 返回类型:void
- 修饰符:public
参数:
- source: SoundSource
- gain: float
说明:
TODO
public void stopAll() @ L160
- 方法名:stopAll
- 源码定位:L160
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public void addEventListener(SoundEventListener listener) @ L175
- 方法名:addEventListener
- 源码定位:L175
- 返回类型:void
- 修饰符:public
参数:
- listener: SoundEventListener
说明:
TODO
public void removeEventListener(SoundEventListener listener) @ L179
- 方法名:removeEventListener
- 源码定位:L179
- 返回类型:void
- 修饰符:public
参数:
- listener: SoundEventListener
说明:
TODO
private boolean shouldChangeDevice() @ L183
- 方法名:shouldChangeDevice
- 源码定位:L183
- 返回类型:boolean
- 修饰符:private
参数:
- 无
说明:
TODO
public void tick(boolean paused) @ L218
- 方法名:tick
- 源码定位:L218
- 返回类型:void
- 修饰符:public
参数:
- paused: boolean
说明:
TODO
private void tickInGameSound() @ L232
- 方法名:tickInGameSound
- 源码定位:L232
- 返回类型:void
- 修饰符:private
参数:
- 无
说明:
TODO
private void tickMusicWhenPaused() @ L305
- 方法名:tickMusicWhenPaused
- 源码定位:L305
- 返回类型:void
- 修饰符:private
参数:
- 无
说明:
TODO
private static boolean requiresManualLooping(SoundInstance instance) @ L321
- 方法名:requiresManualLooping
- 源码定位:L321
- 返回类型:boolean
- 修饰符:private static
参数:
- instance: SoundInstance
说明:
TODO
private static boolean shouldLoopManually(SoundInstance instance) @ L325
- 方法名:shouldLoopManually
- 源码定位:L325
- 返回类型:boolean
- 修饰符:private static
参数:
- instance: SoundInstance
说明:
TODO
private static boolean shouldLoopAutomatically(SoundInstance instance) @ L329
- 方法名:shouldLoopAutomatically
- 源码定位:L329
- 返回类型:boolean
- 修饰符:private static
参数:
- instance: SoundInstance
说明:
TODO
public boolean isActive(SoundInstance instance) @ L333
- 方法名:isActive
- 源码定位:L333
- 返回类型:boolean
- 修饰符:public
参数:
- instance: SoundInstance
说明:
TODO
public SoundEngine.PlayResult play(SoundInstance instance) @ L343
- 方法名:play
- 源码定位:L343
- 返回类型:SoundEngine.PlayResult
- 修饰符:public
参数:
- instance: SoundInstance
说明:
TODO
public void queueTickingSound(TickableSoundInstance tickableSoundInstance) @ L450
- 方法名:queueTickingSound
- 源码定位:L450
- 返回类型:void
- 修饰符:public
参数:
- tickableSoundInstance: TickableSoundInstance
说明:
TODO
public void requestPreload(Sound sound) @ L454
- 方法名:requestPreload
- 源码定位:L454
- 返回类型:void
- 修饰符:public
参数:
- sound: Sound
说明:
TODO
private float calculatePitch(SoundInstance instance) @ L458
- 方法名:calculatePitch
- 源码定位:L458
- 返回类型:float
- 修饰符:private
参数:
- instance: SoundInstance
说明:
TODO
private float calculateVolume(SoundInstance instance) @ L462
- 方法名:calculateVolume
- 源码定位:L462
- 返回类型:float
- 修饰符:private
参数:
- instance: SoundInstance
说明:
TODO
private float calculateVolume(float volume, SoundSource source) @ L466
- 方法名:calculateVolume
- 源码定位:L466
- 返回类型:float
- 修饰符:private
参数:
- volume: float
- source: SoundSource
说明:
TODO
public void pauseAllExcept(SoundSource... ignoredSources) @ L470
- 方法名:pauseAllExcept
- 源码定位:L470
- 返回类型:void
- 修饰符:public
参数:
- ignoredSources: SoundSource…
说明:
TODO
public void resume() @ L480
- 方法名:resume
- 源码定位:L480
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public void playDelayed(SoundInstance instance, int delay) @ L486
- 方法名:playDelayed
- 源码定位:L486
- 返回类型:void
- 修饰符:public
参数:
- instance: SoundInstance
- delay: int
说明:
TODO
public void updateSource(Camera camera) @ L490
- 方法名:updateSource
- 源码定位:L490
- 返回类型:void
- 修饰符:public
参数:
- camera: Camera
说明:
TODO
public void stop(Identifier sound, SoundSource source) @ L497
- 方法名:stop
- 源码定位:L497
- 返回类型:void
- 修饰符:public
参数:
- sound: Identifier
- source: SoundSource
说明:
TODO
public String getChannelDebugString() @ L515
- 方法名:getChannelDebugString
- 源码定位:L515
- 返回类型:String
- 修饰符:public
参数:
- 无
说明:
TODO
public void getSoundCacheDebugStats(SoundBufferLibrary.DebugOutput output) @ L519
- 方法名:getSoundCacheDebugStats
- 源码定位:L519
- 返回类型:void
- 修饰符:public
参数:
- output: SoundBufferLibrary.DebugOutput
说明:
TODO
public List<String> getAvailableSoundDevices() @ L523
- 方法名:getAvailableSoundDevices
- 源码定位:L523
- 返回类型:List
- 修饰符:public
参数:
- 无
说明:
TODO
public ListenerTransform getListenerTransform() @ L527
- 方法名:getListenerTransform
- 源码定位:L527
- 返回类型:ListenerTransform
- 修饰符:public
参数:
- 无
说明:
TODO
代码
@OnlyIn(Dist.CLIENT)
public class SoundEngine {
private static final Marker MARKER = MarkerFactory.getMarker("SOUNDS");
private static final Logger LOGGER = LogUtils.getLogger();
private static final float PITCH_MIN = 0.5F;
private static final float PITCH_MAX = 2.0F;
private static final float VOLUME_MIN = 0.0F;
private static final float VOLUME_MAX = 1.0F;
private static final int MIN_SOURCE_LIFETIME = 20;
private static final Set<Identifier> ONLY_WARN_ONCE = Sets.newHashSet();
public static final String MISSING_SOUND = "FOR THE DEBUG!";
public static final String OPEN_AL_SOFT_PREFIX = "OpenAL Soft on ";
public static final int OPEN_AL_SOFT_PREFIX_LENGTH = "OpenAL Soft on ".length();
private final SoundManager soundManager;
private final Options options;
private boolean loaded;
private final Library library = new Library();
private final Listener listener = this.library.getListener();
private final SoundBufferLibrary soundBuffers;
private final SoundEngineExecutor executor = new SoundEngineExecutor();
private final ChannelAccess channelAccess = new ChannelAccess(this.library, this.executor);
private int tickCount;
private DeviceList lastSeenDevices;
private final DeviceTracker deviceTracker = Library.createDeviceTracker();
private final Map<SoundInstance, ChannelAccess.ChannelHandle> instanceToChannel = Maps.newHashMap();
private final Multimap<SoundSource, SoundInstance> instanceBySource = HashMultimap.create();
private final Object2FloatMap<SoundSource> gainBySource = Util.make(new Object2FloatOpenHashMap<>(), map -> map.defaultReturnValue(1.0F));
private final List<TickableSoundInstance> tickingSounds = Lists.newArrayList();
private final Map<SoundInstance, Integer> queuedSounds = Maps.newHashMap();
private final Map<SoundInstance, Integer> soundDeleteTime = Maps.newHashMap();
private final List<SoundEventListener> listeners = Lists.newArrayList();
private final List<TickableSoundInstance> queuedTickableSounds = Lists.newArrayList();
private final List<Sound> preloadQueue = Lists.newArrayList();
public SoundEngine(SoundManager soundManager, Options options, ResourceProvider resourceProvider) {
this.soundManager = soundManager;
this.options = options;
this.soundBuffers = new SoundBufferLibrary(resourceProvider);
this.lastSeenDevices = this.deviceTracker.currentDevices();
}
public void reload() {
ONLY_WARN_ONCE.clear();
for (SoundEvent sound : BuiltInRegistries.SOUND_EVENT) {
if (sound != SoundEvents.EMPTY) {
Identifier location = sound.location();
if (this.soundManager.getSoundEvent(location) == null) {
LOGGER.warn("Missing sound for event: {}", BuiltInRegistries.SOUND_EVENT.getKey(sound));
ONLY_WARN_ONCE.add(location);
}
}
}
this.destroy();
this.loadLibrary();
}
private synchronized void loadLibrary() {
if (!this.loaded) {
try {
String soundDevice = this.options.soundDevice().get();
DeviceList currentDevices = this.deviceTracker.currentDevices();
this.library.init(Options.isSoundDeviceDefault(soundDevice) ? null : soundDevice, currentDevices, this.options.directionalAudio().get());
this.listener.reset();
this.soundBuffers.preload(this.preloadQueue).thenRun(this.preloadQueue::clear);
this.loaded = true;
LOGGER.info(MARKER, "Sound engine started");
} catch (RuntimeException var3) {
LOGGER.error(MARKER, "Error starting SoundSystem. Turning off sounds & music", (Throwable)var3);
}
}
}
public void refreshCategoryVolume(SoundSource source) {
if (this.loaded) {
this.instanceToChannel.forEach((soundInstance, channelHandle) -> {
if (source == soundInstance.getSource() || source == SoundSource.MASTER) {
float newVolume = this.calculateVolume(soundInstance);
channelHandle.execute(channel -> channel.setVolume(newVolume));
}
});
}
}
public void destroy() {
if (this.loaded) {
this.stopAll();
this.soundBuffers.clear();
this.library.cleanup();
this.loaded = false;
}
}
public void emergencyShutdown() {
if (this.loaded) {
this.library.cleanup();
}
}
public void stop(SoundInstance soundInstance) {
if (this.loaded) {
ChannelAccess.ChannelHandle handle = this.instanceToChannel.get(soundInstance);
if (handle != null) {
handle.execute(Channel::stop);
}
}
}
public void updateCategoryVolume(SoundSource source, float gain) {
this.gainBySource.put(source, Mth.clamp(gain, 0.0F, 1.0F));
this.refreshCategoryVolume(source);
}
public void stopAll() {
if (this.loaded) {
this.executor.shutDown();
this.instanceToChannel.clear();
this.channelAccess.clear();
this.queuedSounds.clear();
this.tickingSounds.clear();
this.instanceBySource.clear();
this.soundDeleteTime.clear();
this.queuedTickableSounds.clear();
this.gainBySource.clear();
this.executor.startUp();
}
}
public void addEventListener(SoundEventListener listener) {
this.listeners.add(listener);
}
public void removeEventListener(SoundEventListener listener) {
this.listeners.remove(listener);
}
private boolean shouldChangeDevice() {
if (this.library.isCurrentDeviceDisconnected()) {
LOGGER.info("Audio device was lost!");
this.deviceTracker.forceRefresh();
return true;
} else {
this.deviceTracker.tick();
boolean shouldChangeDevice = false;
DeviceList currentDevices = this.deviceTracker.currentDevices();
if (!currentDevices.equals(this.lastSeenDevices)) {
String currentDeviceName = this.library.currentDeviceName();
if (!currentDevices.allDevices().contains(currentDeviceName)) {
LOGGER.info("Current audio device has disapeared!");
shouldChangeDevice = true;
}
String userSelectedDevice = this.options.soundDevice().get();
if (Options.isSoundDeviceDefault(userSelectedDevice)) {
String newDefault = currentDevices.defaultDevice();
if (!Objects.equals(currentDeviceName, newDefault)) {
LOGGER.info("System default audio device has changed!");
shouldChangeDevice = true;
}
} else if (!Objects.equals(currentDeviceName, userSelectedDevice) && currentDevices.allDevices().contains(userSelectedDevice)) {
LOGGER.info("Preferred audio device has become available!");
shouldChangeDevice = true;
}
this.lastSeenDevices = currentDevices;
}
return shouldChangeDevice;
}
}
public void tick(boolean paused) {
if (this.shouldChangeDevice()) {
this.reload();
}
if (!paused) {
this.tickInGameSound();
} else {
this.tickMusicWhenPaused();
}
this.channelAccess.scheduleTick();
}
private void tickInGameSound() {
this.tickCount++;
this.queuedTickableSounds.stream().filter(SoundInstance::canPlaySound).forEach(this::play);
this.queuedTickableSounds.clear();
for (TickableSoundInstance instance : this.tickingSounds) {
if (!instance.canPlaySound()) {
this.stop(instance);
}
instance.tick();
if (instance.isStopped()) {
this.stop(instance);
} else {
float volume = this.calculateVolume(instance);
float pitch = this.calculatePitch(instance);
Vec3 position = new Vec3(instance.getX(), instance.getY(), instance.getZ());
ChannelAccess.ChannelHandle handle = this.instanceToChannel.get(instance);
if (handle != null) {
handle.execute(channel -> {
channel.setVolume(volume);
channel.setPitch(pitch);
channel.setSelfPosition(position);
});
}
}
}
Iterator<Entry<SoundInstance, ChannelAccess.ChannelHandle>> iterator = this.instanceToChannel.entrySet().iterator();
while (iterator.hasNext()) {
Entry<SoundInstance, ChannelAccess.ChannelHandle> entry = iterator.next();
ChannelAccess.ChannelHandle handle = entry.getValue();
SoundInstance instance = entry.getKey();
if (handle.isStopped()) {
int minDeleteTime = this.soundDeleteTime.get(instance);
if (minDeleteTime <= this.tickCount) {
if (shouldLoopManually(instance)) {
this.queuedSounds.put(instance, this.tickCount + instance.getDelay());
}
iterator.remove();
LOGGER.debug(MARKER, "Removed channel {} because it's not playing anymore", handle);
this.soundDeleteTime.remove(instance);
try {
this.instanceBySource.remove(instance.getSource(), instance);
} catch (RuntimeException var7) {
}
if (instance instanceof TickableSoundInstance) {
this.tickingSounds.remove(instance);
}
}
}
}
Iterator<Entry<SoundInstance, Integer>> queueIterator = this.queuedSounds.entrySet().iterator();
while (queueIterator.hasNext()) {
Entry<SoundInstance, Integer> next = queueIterator.next();
if (this.tickCount >= next.getValue()) {
SoundInstance instance = next.getKey();
if (instance instanceof TickableSoundInstance) {
((TickableSoundInstance)instance).tick();
}
this.play(instance);
queueIterator.remove();
}
}
}
private void tickMusicWhenPaused() {
Iterator<Entry<SoundInstance, ChannelAccess.ChannelHandle>> iterator = this.instanceToChannel.entrySet().iterator();
while (iterator.hasNext()) {
Entry<SoundInstance, ChannelAccess.ChannelHandle> entry = iterator.next();
ChannelAccess.ChannelHandle handle = entry.getValue();
SoundInstance instance = entry.getKey();
if (instance.getSource() == SoundSource.MUSIC && handle.isStopped()) {
iterator.remove();
LOGGER.debug(MARKER, "Removed channel {} because it's not playing anymore", handle);
this.soundDeleteTime.remove(instance);
this.instanceBySource.remove(instance.getSource(), instance);
}
}
}
private static boolean requiresManualLooping(SoundInstance instance) {
return instance.getDelay() > 0;
}
private static boolean shouldLoopManually(SoundInstance instance) {
return instance.isLooping() && requiresManualLooping(instance);
}
private static boolean shouldLoopAutomatically(SoundInstance instance) {
return instance.isLooping() && !requiresManualLooping(instance);
}
public boolean isActive(SoundInstance instance) {
if (!this.loaded) {
return false;
} else {
return this.soundDeleteTime.containsKey(instance) && this.soundDeleteTime.get(instance) <= this.tickCount
? true
: this.instanceToChannel.containsKey(instance);
}
}
public SoundEngine.PlayResult play(SoundInstance instance) {
if (!this.loaded) {
return SoundEngine.PlayResult.NOT_STARTED;
} else if (!instance.canPlaySound()) {
return SoundEngine.PlayResult.NOT_STARTED;
} else {
WeighedSoundEvents soundEvent = instance.resolve(this.soundManager);
Identifier eventLocation = instance.getIdentifier();
if (soundEvent == null) {
if (ONLY_WARN_ONCE.add(eventLocation)) {
LOGGER.warn(MARKER, "Unable to play unknown soundEvent: {}", eventLocation);
}
if (!SharedConstants.DEBUG_SUBTITLES) {
return SoundEngine.PlayResult.NOT_STARTED;
}
soundEvent = new WeighedSoundEvents(eventLocation, "FOR THE DEBUG!");
}
Sound sound = instance.getSound();
if (sound == SoundManager.INTENTIONALLY_EMPTY_SOUND) {
return SoundEngine.PlayResult.NOT_STARTED;
} else if (sound == SoundManager.EMPTY_SOUND) {
if (ONLY_WARN_ONCE.add(eventLocation)) {
LOGGER.warn(MARKER, "Unable to play empty soundEvent: {}", eventLocation);
}
return SoundEngine.PlayResult.NOT_STARTED;
} else {
float instanceVolume = instance.getVolume();
float attenuationDistance = Math.max(instanceVolume, 1.0F) * sound.getAttenuationDistance();
SoundSource soundSource = instance.getSource();
float volume = this.calculateVolume(instanceVolume, soundSource);
float pitch = this.calculatePitch(instance);
SoundInstance.Attenuation attenuation = instance.getAttenuation();
boolean isRelative = instance.isRelative();
if (!this.listeners.isEmpty()) {
float range = !isRelative && attenuation != SoundInstance.Attenuation.NONE ? attenuationDistance : Float.POSITIVE_INFINITY;
for (SoundEventListener listener : this.listeners) {
listener.onPlaySound(instance, soundEvent, range);
}
}
boolean startedSilently = false;
if (volume == 0.0F) {
if (!instance.canStartSilent() && soundSource != SoundSource.MUSIC) {
LOGGER.debug(MARKER, "Skipped playing sound {}, volume was zero.", sound.getLocation());
return SoundEngine.PlayResult.NOT_STARTED;
}
startedSilently = true;
}
Vec3 position = new Vec3(instance.getX(), instance.getY(), instance.getZ());
boolean isLooping = shouldLoopAutomatically(instance);
boolean isStreaming = sound.shouldStream();
CompletableFuture<ChannelAccess.ChannelHandle> handleFuture = this.channelAccess
.createHandle(sound.shouldStream() ? Library.Pool.STREAMING : Library.Pool.STATIC);
ChannelAccess.ChannelHandle handle = handleFuture.join();
if (handle == null) {
if (SharedConstants.IS_RUNNING_IN_IDE) {
LOGGER.warn("Failed to create new sound handle");
}
return SoundEngine.PlayResult.NOT_STARTED;
} else {
LOGGER.debug(MARKER, "Playing sound {} for event {}", sound.getLocation(), eventLocation);
this.soundDeleteTime.put(instance, this.tickCount + 20);
this.instanceToChannel.put(instance, handle);
this.instanceBySource.put(soundSource, instance);
handle.execute(channel -> {
channel.setPitch(pitch);
channel.setVolume(volume);
if (attenuation == SoundInstance.Attenuation.LINEAR) {
channel.linearAttenuation(attenuationDistance);
} else {
channel.disableAttenuation();
}
channel.setLooping(isLooping && !isStreaming);
channel.setSelfPosition(position);
channel.setRelative(isRelative);
});
if (!isStreaming) {
this.soundBuffers.getCompleteBuffer(sound.getPath()).thenAccept(soundBuffer -> handle.execute(channel -> {
channel.attachStaticBuffer(soundBuffer);
channel.play();
}));
} else {
this.soundBuffers.getStream(sound.getPath(), isLooping).thenAccept(stream -> handle.execute(channel -> {
channel.attachBufferStream(stream);
channel.play();
}));
}
if (instance instanceof TickableSoundInstance) {
this.tickingSounds.add((TickableSoundInstance)instance);
}
return startedSilently ? SoundEngine.PlayResult.STARTED_SILENTLY : SoundEngine.PlayResult.STARTED;
}
}
}
}
public void queueTickingSound(TickableSoundInstance tickableSoundInstance) {
this.queuedTickableSounds.add(tickableSoundInstance);
}
public void requestPreload(Sound sound) {
this.preloadQueue.add(sound);
}
private float calculatePitch(SoundInstance instance) {
return Mth.clamp(instance.getPitch(), 0.5F, 2.0F);
}
private float calculateVolume(SoundInstance instance) {
return this.calculateVolume(instance.getVolume(), instance.getSource());
}
private float calculateVolume(float volume, SoundSource source) {
return Mth.clamp(volume, 0.0F, 1.0F) * Mth.clamp(this.options.getFinalSoundSourceVolume(source), 0.0F, 1.0F) * this.gainBySource.getFloat(source);
}
public void pauseAllExcept(SoundSource... ignoredSources) {
if (this.loaded) {
for (Entry<SoundInstance, ChannelAccess.ChannelHandle> instance : this.instanceToChannel.entrySet()) {
if (!List.of(ignoredSources).contains(instance.getKey().getSource())) {
instance.getValue().execute(Channel::pause);
}
}
}
}
public void resume() {
if (this.loaded) {
this.channelAccess.executeOnChannels(channels -> channels.forEach(Channel::unpause));
}
}
public void playDelayed(SoundInstance instance, int delay) {
this.queuedSounds.put(instance, this.tickCount + delay);
}
public void updateSource(Camera camera) {
if (this.loaded && camera.isInitialized()) {
ListenerTransform transform = new ListenerTransform(camera.position(), new Vec3(camera.forwardVector()), new Vec3(camera.upVector()));
this.executor.execute(() -> this.listener.setTransform(transform));
}
}
public void stop(@Nullable Identifier sound, @Nullable SoundSource source) {
if (source != null) {
for (SoundInstance instance : this.instanceBySource.get(source)) {
if (sound == null || instance.getIdentifier().equals(sound)) {
this.stop(instance);
}
}
} else if (sound == null) {
this.stopAll();
} else {
for (SoundInstance instancex : this.instanceToChannel.keySet()) {
if (instancex.getIdentifier().equals(sound)) {
this.stop(instancex);
}
}
}
}
public String getChannelDebugString() {
return this.library.getChannelDebugString();
}
public void getSoundCacheDebugStats(SoundBufferLibrary.DebugOutput output) {
this.soundBuffers.enumerate(output);
}
public List<String> getAvailableSoundDevices() {
return this.deviceTracker.currentDevices().allDevices();
}
public ListenerTransform getListenerTransform() {
return this.listener.getTransform();
}
@OnlyIn(Dist.CLIENT)
public static enum PlayResult {
STARTED,
STARTED_SILENTLY,
NOT_STARTED;
}
}引用的其他类
-
- 引用位置:
字段
- 引用位置:
-
- 引用位置:
字段
- 引用位置:
-
- 引用位置:
字段/方法调用/构造调用 - 关联成员:
Library(), Library.createDeviceTracker()
- 引用位置:
-
- 引用位置:
字段
- 引用位置:
-
- 引用位置:
构造调用/返回值 - 关联成员:
ListenerTransform()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/字段/方法调用 - 关联成员:
Options.isSoundDeviceDefault()
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
字段/构造调用 - 关联成员:
ChannelAccess()
- 引用位置:
-
- 引用位置:
参数/字段/构造调用 - 关联成员:
SoundBufferLibrary()
- 引用位置:
-
- 引用位置:
字段/构造调用 - 关联成员:
SoundEngineExecutor()
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
WeighedSoundEvents()
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Mth.clamp()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Util.make()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
Vec3()
- 引用位置: