Skip to content

Commit b243559

Browse files
committed
mic and speaker
1 parent 018b802 commit b243559

67 files changed

Lines changed: 3483 additions & 365 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ dependencies {
109109
// compileOnly "mezz.jei:jei-${mc_version}-forge-api:${jei_version}"
110110
// runtimeOnly "mezz.jei:jei-${mc_version}-forge:${jei_version}"
111111

112-
implementation(annotationProcessor("cn.ussshenzhou:t88:26.+"))
112+
implementation(annotationProcessor("cn.ussshenzhou:t88:26.1+"))
113113

114114
implementation 'io.github.jaredmdobson:concentus:1.0.2'
115115
jarJar 'io.github.jaredmdobson:concentus:1.0.2'

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ mod_name=Channel
3030
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
3131
mod_license=GNU GPL 3.0
3232
# The mod version. See https://semver.org/
33-
mod_version=26.1.2-6+alpha
33+
mod_version=26.1.2-7+alpha
3434
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
3535
# This should match the base package used for the mod sources.
3636
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
3737
mod_group_id=cn.ussshenzhou
3838
# The authors of the mod. This is a simple text string that is used for display purposes in the mod list.
39-
mod_authors=
39+
mod_authors=USS_Shenzhou, MalayP
4040
# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list.
4141
mod_description=

src/main/java/cn/ussshenzhou/channel/Channel.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package cn.ussshenzhou.channel;
22

3+
import cn.ussshenzhou.channel.Item.ModItems;
4+
import cn.ussshenzhou.channel.block.ModBlocks;
5+
import cn.ussshenzhou.channel.blockentity.ModBlockEntityTypes;
36
import cn.ussshenzhou.channel.config.ChannelClientConfig;
47
import cn.ussshenzhou.channel.config.ChannelPlayerConfig;
58
import cn.ussshenzhou.channel.config.ChannelServerConfig;
@@ -16,13 +19,21 @@
1619
@Mod(Channel.MODID)
1720
public class Channel {
1821
public static final String MODID = "channel";
22+
public static final float DISTANCE_COMPENSATE = 2;
23+
public static final float DISTANCE_COMPENSATE_SQR = 2 * 2;
1924

2025
public Channel(IEventBus modEventBus, ModContainer modContainer) {
2126
if (FMLEnvironment.getDist() == Dist.CLIENT) {
2227
ConfigHelper.loadConfig(new ChannelClientConfig());
2328
ConfigHelper.loadConfig(new ChannelPlayerConfig());
2429
}
2530
ConfigHelper.loadConfig(new ChannelServerConfig());
31+
32+
ModBlocks.BLOCKS.register(modEventBus);
33+
ModItems.ITEMS.register(modEventBus);
34+
ModItems.CREATIVE_MODE_TABS.register(modEventBus);
35+
ModItems.DATA_COMPONENTS.register(modEventBus);
36+
ModBlockEntityTypes.BLOCK_ENTITIES.register(modEventBus);
2637
}
2738
//TODO 参考发光/泛光,声音越大,回声越强
2839
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package cn.ussshenzhou.channel.Item;
2+
3+
import cn.ussshenzhou.channel.gui.ItemChannelSettingScreen;
4+
import com.mojang.logging.annotations.MethodsReturnNonnullByDefault;
5+
import net.minecraft.client.Minecraft;
6+
import net.minecraft.world.InteractionHand;
7+
import net.minecraft.world.InteractionResult;
8+
import net.minecraft.world.entity.player.Player;
9+
import net.minecraft.world.item.Item;
10+
import net.minecraft.world.level.Level;
11+
12+
import javax.annotation.ParametersAreNonnullByDefault;
13+
import java.util.function.Supplier;
14+
15+
@ParametersAreNonnullByDefault
16+
@MethodsReturnNonnullByDefault
17+
public class HandheldMic extends Item {
18+
public HandheldMic(Properties properties) {
19+
super(properties);
20+
}
21+
22+
@Override
23+
public InteractionResult use(Level level, Player player, InteractionHand hand) {
24+
if (!level.isClientSide()) {
25+
return InteractionResult.PASS;
26+
}
27+
return new Supplier<InteractionResult>() {
28+
@Override
29+
public InteractionResult get() {
30+
Minecraft.getInstance().setScreen(new ItemChannelSettingScreen(hand, player.getItemInHand(hand)));
31+
return InteractionResult.SUCCESS;
32+
}
33+
}.get();
34+
35+
}
36+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package cn.ussshenzhou.channel.Item;
2+
3+
import cn.ussshenzhou.channel.Channel;
4+
import cn.ussshenzhou.channel.block.ModBlocks;
5+
import com.mojang.serialization.Codec;
6+
import net.minecraft.core.component.DataComponentType;
7+
import net.minecraft.core.registries.BuiltInRegistries;
8+
import net.minecraft.core.registries.Registries;
9+
import net.minecraft.network.chat.Component;
10+
import net.minecraft.network.codec.ByteBufCodecs;
11+
import net.minecraft.network.codec.StreamCodec;
12+
import net.minecraft.resources.Identifier;
13+
import net.minecraft.resources.ResourceKey;
14+
import net.minecraft.world.item.BlockItem;
15+
import net.minecraft.world.item.CreativeModeTab;
16+
import net.minecraft.world.item.Item;
17+
import net.minecraft.world.item.ItemStack;
18+
import net.neoforged.bus.api.SubscribeEvent;
19+
import net.neoforged.fml.common.EventBusSubscriber;
20+
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
21+
import net.neoforged.neoforge.registries.DeferredRegister;
22+
23+
import java.util.function.Supplier;
24+
import java.util.stream.Stream;
25+
26+
27+
/**
28+
* @author USS_Shenzhou
29+
*/
30+
@EventBusSubscriber
31+
public class ModItems {
32+
//----------Data Component----------
33+
public static final DeferredRegister.DataComponents DATA_COMPONENTS = DeferredRegister.createDataComponents(Registries.DATA_COMPONENT_TYPE, Channel.MODID);
34+
35+
public static final Supplier<DataComponentType<Integer>> CHANNEL = DATA_COMPONENTS.registerComponentType("channel", builder ->
36+
builder.persistent(Codec.INT).networkSynchronized(ByteBufCodecs.INT)
37+
);
38+
39+
//----------Item----------
40+
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(BuiltInRegistries.ITEM, Channel.MODID);
41+
42+
public static final Supplier<Item> HANDHELD_MIC_ITEM = ITEMS.register("handheld_mic", () -> new HandheldMic(new Item.Properties()
43+
.stacksTo(1)
44+
.component(CHANNEL.get(), 0)
45+
.setId(ResourceKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath(Channel.MODID, "handheld_mic")))
46+
));
47+
public static final Supplier<Item> MIC_ITEM = ITEMS.register("mic", () -> new BlockItem(ModBlocks.MIC_BLOCK.get(), new Item.Properties()
48+
.setId(ResourceKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath(Channel.MODID, "mic")))
49+
));
50+
public static final Supplier<Item> SPEAKER_ITEM = ITEMS.register("speaker", () -> new BlockItem(ModBlocks.SPEAKER_BLOCK.get(), new Item.Properties()
51+
.setId(ResourceKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath(Channel.MODID, "speaker")))
52+
));
53+
public static final Supplier<Item> SPEAKER_STAND_ITEM = ITEMS.register("speaker_stand", () -> new BlockItem(ModBlocks.SPEAKER_STAND_BLOCK.get(), new Item.Properties()
54+
.setId(ResourceKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath(Channel.MODID, "speaker_stand")))
55+
));
56+
public static final Supplier<Item> SPEAKER_HANG_ITEM = ITEMS.register("speaker_hang", () -> new BlockItem(ModBlocks.SPEAKER_HANG_BLOCK.get(), new Item.Properties()
57+
.setId(ResourceKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath(Channel.MODID, "speaker_hang")))
58+
));
59+
60+
//----------Creative Mode Tab----------
61+
public static final DeferredRegister<CreativeModeTab> CREATIVE_MODE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, Channel.MODID);
62+
63+
public static final Supplier<CreativeModeTab> TAB = CREATIVE_MODE_TABS.register("main", () -> CreativeModeTab.builder()
64+
.icon(() -> new ItemStack(MIC_ITEM.get()))
65+
.title(Component.translatable("channel.tab.title"))
66+
.build());
67+
68+
@SubscribeEvent
69+
public static void onBuildContents(BuildCreativeModeTabContentsEvent event) {
70+
var tab = BuiltInRegistries.CREATIVE_MODE_TAB.getKey(event.getTab());
71+
if (tab != null && tab.equals(BuiltInRegistries.CREATIVE_MODE_TAB.getKey(TAB.get()))) {
72+
event.acceptAll(Stream.of(
73+
HANDHELD_MIC_ITEM,
74+
MIC_ITEM,
75+
SPEAKER_ITEM,
76+
SPEAKER_STAND_ITEM,
77+
SPEAKER_HANG_ITEM
78+
).map(s -> new ItemStack(s.get())).toList());
79+
}
80+
}
81+
}

src/main/java/cn/ussshenzhou/channel/audio/client/Initializer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package cn.ussshenzhou.channel.audio.client;
22

3-
import cn.ussshenzhou.channel.audio.client.receive.AudioManagerManager;
3+
import cn.ussshenzhou.channel.audio.client.receive.AudioManager;
44
import cn.ussshenzhou.channel.audio.client.send.MicManager;
55
import cn.ussshenzhou.channel.audio.client.send.MicReader;
66
import cn.ussshenzhou.channel.audio.client.send.WebRTCHelper;
@@ -23,6 +23,6 @@ public static void init(ClientStartedEvent event) {
2323
MicReader.init();
2424
WebRTCHelper.init();
2525
NvidiaHelper.init();
26-
AudioManagerManager.init();
26+
AudioManager.init();
2727
}
2828
}

src/main/java/cn/ussshenzhou/channel/audio/client/receive/PlayerAudio.java renamed to src/main/java/cn/ussshenzhou/channel/audio/client/receive/Audio.java

Lines changed: 51 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,37 @@
11
package cn.ussshenzhou.channel.audio.client.receive;
22

33
import cn.ussshenzhou.channel.audio.client.rt.RayTraceManager;
4+
import cn.ussshenzhou.channel.audio.client.rt.SourceAudioData;
45
import cn.ussshenzhou.channel.config.ChannelClientConfig;
5-
import cn.ussshenzhou.channel.config.ChannelPlayerConfig;
6-
import cn.ussshenzhou.channel.gui.OutputConfigPanel;
76
import cn.ussshenzhou.channel.util.AudioHelper;
8-
import com.mojang.logging.LogUtils;
97
import io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueue;
10-
import net.minecraft.client.Minecraft;
11-
import net.minecraft.world.entity.player.Player;
128
import net.minecraft.world.level.Level;
139
import net.minecraft.world.phys.Vec3;
1410

1511
import javax.annotation.Nullable;
1612
import java.nio.ByteBuffer;
17-
import java.nio.ByteOrder;
18-
import java.util.*;
19-
20-
import static org.lwjgl.openal.AL11.*;
13+
import java.util.List;
14+
15+
import static org.lwjgl.openal.AL10.*;
16+
import static org.lwjgl.openal.AL10.AL_FALSE;
17+
import static org.lwjgl.openal.AL10.AL_LOOPING;
18+
import static org.lwjgl.openal.AL10.AL_MAX_GAIN;
19+
import static org.lwjgl.openal.AL10.AL_PITCH;
20+
import static org.lwjgl.openal.AL10.AL_REFERENCE_DISTANCE;
21+
import static org.lwjgl.openal.AL10.AL_ROLLOFF_FACTOR;
22+
import static org.lwjgl.openal.AL10.alSourcef;
23+
import static org.lwjgl.openal.AL10.alSourcei;
24+
import static org.lwjgl.openal.AL11.alSource3i;
2125
import static org.lwjgl.openal.EXTEfx.*;
26+
import static org.lwjgl.openal.EXTEfx.AL_AUXILIARY_SEND_FILTER;
27+
28+
public abstract class Audio {
29+
protected static final int MAX_BUFFER_10MS = 3 * 100;
30+
protected int readyBufferMs = 0;
31+
protected final int alSource, sampleRate, alDirectFilter, alReverbFilter;
32+
protected double x, y, z;
2233

23-
/**
24-
* @author USS_Shenzhou
25-
*/
26-
public class PlayerAudio {
27-
private static final int MAX_BUFFER_10MS = 3 * 100;
28-
private final MpscArrayQueue<short[]> audioBuffer = new MpscArrayQueue<>((int) (1.1 * MAX_BUFFER_10MS));
29-
private int readyBufferMs = 0;
30-
public final int alSource, sampleRate, alDirectFilter, alReverbFilter;
31-
public final UUID playerId;
32-
private double x, y, z;
33-
34-
public PlayerAudio(UUID playerId, int sampleRate) {
35-
this.playerId = playerId;
34+
public Audio(int sampleRate) {
3635
this.sampleRate = sampleRate;
3736
this.alSource = alGenSources();
3837
alSourcef(alSource, AL_GAIN, 1);
@@ -56,57 +55,29 @@ public PlayerAudio(UUID playerId, int sampleRate) {
5655
}
5756
}
5857

59-
public void push(short[] audio) {
60-
int length = sampleRate / 100;
61-
for (int i = 0; i < audio.length / length; i++) {
62-
audioBuffer.offer(Arrays.copyOfRange(audio, i * length, (i + 1) * length));
63-
}
64-
}
58+
public void updateSourceParameters(SourceAudioData data, int auxSlot) {
59+
alFilterf(this.alDirectFilter, AL_LOWPASS_GAIN, data.directGain());
60+
alFilterf(this.alDirectFilter, AL_LOWPASS_GAINHF, data.directHF());
61+
alSourcei(this.alSource, AL_DIRECT_FILTER, this.alDirectFilter);
6562

66-
@Nullable
67-
public List<ByteBuffer> read(int sizeIn10Ms) {
68-
if (audioBuffer.isEmpty()) {
69-
return null;
70-
}
71-
checkTooMuchDelay();
72-
int toRead = Math.min(sizeIn10Ms, audioBuffer.size());
73-
int length = sampleRate / 100;
74-
List<ByteBuffer> buffers = new ArrayList<>(toRead);
75-
for (int i = 0; i < toRead; i++) {
76-
var chunk = audioBuffer.poll();
77-
if (chunk != null) {
78-
var buffer = ByteBuffer.allocateDirect(length * 2).order(ByteOrder.LITTLE_ENDIAN);
79-
buffer.asShortBuffer().put(chunk).rewind();
80-
buffers.add(buffer);
81-
}
82-
}
83-
return buffers;
84-
}
63+
alFilterf(this.alReverbFilter, AL_LOWPASS_GAIN, data.reverbGain());
64+
alFilterf(this.alReverbFilter, AL_LOWPASS_GAINHF, 1);
65+
alSource3i(this.alSource, AL_AUXILIARY_SEND_FILTER, auxSlot, 0, this.alReverbFilter);
8566

86-
public void checkTooMuchDelay() {
87-
if (audioBuffer.size() >= ChannelClientConfig.get().networkTolerance * 1.5 / 10 || audioBuffer.size() >= MAX_BUFFER_10MS) {
88-
int targetBufferSize = (int) (ChannelClientConfig.get().networkTolerance * 1.1 / 10);
89-
int drop = audioBuffer.size() - targetBufferSize;
90-
for (int i = 0; i < drop; i++) {
91-
audioBuffer.poll();
92-
}
93-
}
67+
alSource3f(this.alSource, AL_POSITION, (float) data.virtualPos().x, (float) data.virtualPos().y, (float) data.virtualPos().z);
9468
}
9569

96-
public void play() {
70+
public boolean play() {
9771
//TODO close self by last active time
98-
var vol = ChannelPlayerConfig.getOrDefault(playerId);
99-
alSourcef(alSource, AL_GAIN, AudioHelper.db2factor(vol));
100-
OutputConfigPanel.PlayerVolumePanel.update(playerId, vol);
101-
72+
//TODO use low-pass filter to make underwater effect in 26.2
73+
alSourcef(alSource, AL_GAIN, getGain());
10274
int processed = alGetSourcei(alSource, AL_BUFFERS_PROCESSED);
10375
while (processed-- > 0) {
10476
int buf = alSourceUnqueueBuffers(alSource);
10577
readyBufferMs -= 10;
10678
alDeleteBuffers(buf);
10779
}
10880
var pcms = read(MAX_BUFFER_10MS);
109-
//TODO use low-pass filter to make underwater effect in 26.2
11081
if (pcms != null) {
11182
for (ByteBuffer pcm : pcms) {
11283
int buf = alGenBuffers();
@@ -123,6 +94,22 @@ public void play() {
12394
alSourcePlay(alSource);
12495
}
12596
}
97+
return false;
98+
}
99+
100+
protected abstract float getGain();
101+
102+
@Nullable
103+
public abstract List<ByteBuffer> read(int sizeIn10Ms);
104+
105+
protected static void checkTooMuchDelay(MpscArrayQueue<short[]> buffer) {
106+
if (buffer.size() >= ChannelClientConfig.get().networkTolerance * 1.5 / 10 || buffer.size() >= MAX_BUFFER_10MS) {
107+
int targetBufferSize = (int) (ChannelClientConfig.get().networkTolerance * 1.1 / 10);
108+
int drop = buffer.size() - targetBufferSize;
109+
for (int i = 0; i < drop; i++) {
110+
buffer.poll();
111+
}
112+
}
126113
}
127114

128115
public void close() {
@@ -137,11 +124,7 @@ public void close() {
137124
}
138125

139126
public Vec3 getPos(Level level) {
140-
var player = level.getPlayerByUUID(this.playerId);
141-
if (player == null) {
142-
return new Vec3(x, y, z);
143-
}
144-
return player.getEyePosition();
127+
return new Vec3(x, y, z);
145128
}
146129

147130
public void setPos(double x, double y, double z) {
@@ -151,15 +134,8 @@ public void setPos(double x, double y, double z) {
151134
}
152135

153136
@Override
154-
public boolean equals(Object other) {
155-
if (!(other instanceof PlayerAudio that)) {
156-
return false;
157-
}
158-
return playerId == that.playerId;
159-
}
137+
public abstract int hashCode();
160138

161139
@Override
162-
public int hashCode() {
163-
return Objects.hashCode(playerId);
164-
}
140+
public abstract boolean equals(Object obj);
165141
}

0 commit comments

Comments
 (0)