forked from ChomeNS/chomens-bot-java
ADD AN EXTREMELY BROKEN MUSIC
This commit is contained in:
parent
e0969ad1f9
commit
b515b1b8b1
14 changed files with 1376 additions and 0 deletions
|
@ -40,6 +40,7 @@ public class Bot {
|
|||
@Getter private final CommandHandlerPlugin commandHandler = new CommandHandlerPlugin();
|
||||
@Getter private final ChatCommandHandlerPlugin chatCommandHandler = new ChatCommandHandlerPlugin(this);
|
||||
@Getter private final HashingPlugin hashing = new HashingPlugin(this);
|
||||
@Getter private final MusicPlayerPlugin music = new MusicPlayerPlugin(this);
|
||||
|
||||
public Bot (String host, int port, int reconnectDelay, String username, List<Bot> allBots) {
|
||||
this.host = host;
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
package me.chayapak1.chomensbot_mabe.commands;
|
||||
|
||||
import me.chayapak1.chomensbot_mabe.Bot;
|
||||
import me.chayapak1.chomensbot_mabe.command.Command;
|
||||
import me.chayapak1.chomensbot_mabe.command.CommandContext;
|
||||
import me.chayapak1.chomensbot_mabe.plugins.MusicPlayerPlugin;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class MusicCommand implements Command {
|
||||
private Path root;
|
||||
|
||||
public String name() { return "music"; }
|
||||
|
||||
public String description() {
|
||||
return "Plays music";
|
||||
}
|
||||
|
||||
public List<String> usage() {
|
||||
final List<String> usages = new ArrayList<>();
|
||||
usages.add("play <{song|URL}>");
|
||||
usages.add("stop");
|
||||
usages.add("loop <current|all|off>");
|
||||
usages.add("list [{directory}]");
|
||||
usages.add("skip");
|
||||
usages.add("nowplaying");
|
||||
usages.add("queue");
|
||||
|
||||
return usages;
|
||||
}
|
||||
|
||||
public List<String> alias() {
|
||||
final List<String> aliases = new ArrayList<>();
|
||||
aliases.add("song");
|
||||
|
||||
return aliases;
|
||||
}
|
||||
|
||||
public int trustLevel() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Component execute(CommandContext context, String[] args, String[] fullArgs) {
|
||||
root = Path.of(context.bot().music().SONG_DIR.getPath());
|
||||
switch (args[0]) {
|
||||
case "play" -> {
|
||||
return play(context, args);
|
||||
}
|
||||
case "stop" -> stop(context);
|
||||
case "loop" -> {
|
||||
return loop(context, args);
|
||||
}
|
||||
case "list" -> {
|
||||
return list(context, args);
|
||||
}
|
||||
case "skip" -> {
|
||||
return skip(context);
|
||||
}
|
||||
}
|
||||
|
||||
return Component.text("success");
|
||||
}
|
||||
|
||||
public Component play (CommandContext context, String[] args) {
|
||||
final Bot bot = context.bot();
|
||||
final MusicPlayerPlugin player = context.bot().music();
|
||||
|
||||
final String _path = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||
final Path path = Path.of(root.toString(), _path);
|
||||
|
||||
bot.logger().log(path.toString());
|
||||
|
||||
try {
|
||||
if (!path.toString().contains("http")) player.loadSong(path);
|
||||
else player.loadSong(new URL(_path));
|
||||
} catch (MalformedURLException e) {
|
||||
return Component.text("Invalid URL").color(NamedTextColor.RED);
|
||||
}
|
||||
|
||||
return Component.text("success");
|
||||
}
|
||||
|
||||
public void stop (CommandContext context) {
|
||||
final Bot bot = context.bot();
|
||||
bot.music().stopPlaying();
|
||||
bot.music().songQueue().clear();
|
||||
}
|
||||
|
||||
public Component loop (CommandContext context, String[] args) {
|
||||
final Bot bot = context.bot();
|
||||
|
||||
int loop;
|
||||
switch (args[1]) {
|
||||
case "off" -> loop = 0;
|
||||
case "current" -> loop = 1;
|
||||
case "all" -> loop = 2;
|
||||
default -> {
|
||||
return Component.text("Invalid argument");
|
||||
}
|
||||
}
|
||||
|
||||
bot.music().currentSong().looping = loop;
|
||||
|
||||
return Component.text("success");
|
||||
}
|
||||
|
||||
public Component list (CommandContext context, String[] args) {
|
||||
final String prefix = context.bot().chatCommandHandler().prefix();
|
||||
|
||||
final Path _path = Path.of(root.toString(), String.join(" ", args));
|
||||
final Path path = (args.length < 2) ? root : _path;
|
||||
|
||||
final String[] filenames = path.toFile().list();
|
||||
if (filenames == null) return Component.text("Directory doesn't exist").color(NamedTextColor.RED);
|
||||
|
||||
final List<Component> list = new ArrayList<>();
|
||||
int i = 0;
|
||||
for (String filename : filenames) {
|
||||
final String pathString = path.toString();
|
||||
final File file = new File(Paths.get(pathString, filename).toUri());
|
||||
|
||||
Path location;
|
||||
try {
|
||||
location = path;
|
||||
} catch (IllegalArgumentException e) {
|
||||
location = Paths.get(""); // wtf mabe
|
||||
}
|
||||
final String joinedPath = (args.length < 2) ? filename : Paths.get(location.getFileName().toString(), filename).toString();
|
||||
list.add(
|
||||
Component
|
||||
.text(filename, (i++ & 1) == 0 ? NamedTextColor.YELLOW : NamedTextColor.GOLD)
|
||||
.clickEvent(
|
||||
ClickEvent.suggestCommand(
|
||||
prefix +
|
||||
"music" + // ? How do I make this dynamic?
|
||||
(file.isFile() ? " play " : " list ") +
|
||||
joinedPath.replace("'", "\\'")
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
final Component component = Component.join(JoinConfiguration.separator(Component.space()), list);
|
||||
context.sendOutput(component);
|
||||
|
||||
return Component.text("success");
|
||||
}
|
||||
|
||||
public Component skip (CommandContext context) {
|
||||
final MusicPlayerPlugin music = context.bot().music();
|
||||
if (music.currentSong() == null) return Component.text("No song is currently playing").color(NamedTextColor.RED);
|
||||
|
||||
context.sendOutput(
|
||||
Component.empty()
|
||||
.append(Component.text("Skipping "))
|
||||
.append(music.currentSong().name.color(NamedTextColor.GOLD))
|
||||
);
|
||||
|
||||
music.stopPlaying();
|
||||
|
||||
return Component.text("success");
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ public class CommandHandlerPlugin {
|
|||
registerCommand(new TestCommand());
|
||||
registerCommand(new ThrowCommand());
|
||||
registerCommand(new ValidateCommand());
|
||||
registerCommand(new MusicCommand());
|
||||
}
|
||||
|
||||
public void registerCommand (Command command) {
|
||||
|
|
|
@ -3,11 +3,19 @@ package me.chayapak1.chomensbot_mabe.plugins;
|
|||
import com.github.steveice10.mc.protocol.data.game.level.block.CommandBlockMode;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetCommandBlockPacket;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import lombok.Getter;
|
||||
import me.chayapak1.chomensbot_mabe.Bot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CorePlugin extends PositionPlugin.PositionListener {
|
||||
private final Bot bot;
|
||||
|
||||
@Getter private final List<Listener> listeners = new ArrayList<>();
|
||||
|
||||
@Getter private boolean ready = false;
|
||||
|
||||
public final Vector3i coreStart = Vector3i.from(0, 0, 0);
|
||||
public final Vector3i coreEnd = Vector3i.from(15, 2, 15);
|
||||
|
||||
|
@ -80,6 +88,11 @@ public class CorePlugin extends PositionPlugin.PositionListener {
|
|||
bot.position().position().getZ()
|
||||
);
|
||||
refill();
|
||||
|
||||
if (!ready) {
|
||||
ready = true;
|
||||
for (Listener listener : listeners) listener.ready();
|
||||
}
|
||||
}
|
||||
|
||||
public void refill () {
|
||||
|
@ -96,4 +109,10 @@ public class CorePlugin extends PositionPlugin.PositionListener {
|
|||
);
|
||||
bot.chat().send(command);
|
||||
}
|
||||
|
||||
public static class Listener {
|
||||
public void ready () {}
|
||||
}
|
||||
|
||||
public void addListener (Listener listener) { listeners.add(listener); }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
package me.chayapak1.chomensbot_mabe.plugins;
|
||||
|
||||
import com.github.steveice10.packetlib.event.session.DisconnectedEvent;
|
||||
import com.github.steveice10.packetlib.event.session.SessionAdapter;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.chayapak1.chomensbot_mabe.Bot;
|
||||
import me.chayapak1.chomensbot_mabe.song.Note;
|
||||
import me.chayapak1.chomensbot_mabe.song.Song;
|
||||
import me.chayapak1.chomensbot_mabe.song.SongLoaderException;
|
||||
import me.chayapak1.chomensbot_mabe.song.SongLoaderThread;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class MusicPlayerPlugin extends SessionAdapter {
|
||||
private final Bot bot;
|
||||
|
||||
private ScheduledFuture<?> futurePlayTask;
|
||||
|
||||
public static final String SELECTOR = "@a[tag=!nomusic,tag=!chomens_bot_nomusic]";
|
||||
public static File SONG_DIR = new File("songs");
|
||||
static {
|
||||
if (!SONG_DIR.exists()) {
|
||||
SONG_DIR.mkdir();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter @Setter private Song currentSong;
|
||||
@Getter @Setter private LinkedList<Song> songQueue = new LinkedList<>();
|
||||
@Getter @Setter private SongLoaderThread loaderThread;
|
||||
private int ticksUntilPausedActionbar = 20;
|
||||
private final String bossbarName = "chomens_bot:music"; // maybe make this in the config?
|
||||
|
||||
public MusicPlayerPlugin (Bot bot) {
|
||||
this.bot = bot;
|
||||
bot.addListener(this);
|
||||
bot.core().addListener(new CorePlugin.Listener() {
|
||||
public void ready () { coreReady(); }
|
||||
});
|
||||
}
|
||||
|
||||
public void loadSong (Path location) {
|
||||
if (loaderThread != null) {
|
||||
bot.chat().tellraw(Component.translatable("Already loading a song, can't load another", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final SongLoaderThread _loaderThread = new SongLoaderThread(location, bot);
|
||||
bot.chat().tellraw(Component.translatable("Loading %s", Component.text(location.getFileName().toString(), NamedTextColor.GOLD)));
|
||||
_loaderThread.start();
|
||||
loaderThread = _loaderThread;
|
||||
} catch (SongLoaderException e) {
|
||||
e.printStackTrace();
|
||||
bot.chat().tellraw(Component.translatable("Failed to load song: %s", e.message()).color(NamedTextColor.RED));
|
||||
loaderThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void loadSong (URL location) {
|
||||
if (loaderThread != null) {
|
||||
bot.chat().tellraw(Component.translatable("Already loading a song, can't load another", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final SongLoaderThread _loaderThread = new SongLoaderThread(location, bot);
|
||||
bot.chat().tellraw(Component.translatable("Loading %s", Component.text(location.toString(), NamedTextColor.GOLD)));
|
||||
_loaderThread.start();
|
||||
loaderThread = _loaderThread;
|
||||
} catch (SongLoaderException e) {
|
||||
bot.chat().tellraw(Component.translatable("Failed to load song: %s", e.message()).color(NamedTextColor.RED));
|
||||
loaderThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void coreReady () {
|
||||
final Runnable playTask = () -> {
|
||||
if (loaderThread != null && !loaderThread.isAlive()) {
|
||||
if (loaderThread.exception != null) {
|
||||
bot.chat().tellraw(Component.translatable("Failed to load song: %s", loaderThread.exception.message()).color(NamedTextColor.RED));
|
||||
} else {
|
||||
songQueue.add(loaderThread.song);
|
||||
bot.chat().tellraw(Component.translatable("Added %s to the song queue", Component.empty().append(loaderThread.song.name).color(NamedTextColor.GOLD)));
|
||||
}
|
||||
loaderThread = null;
|
||||
}
|
||||
|
||||
if (currentSong == null) {
|
||||
if (songQueue.size() == 0) return;
|
||||
|
||||
currentSong = songQueue.poll();
|
||||
bot.chat().tellraw(Component.translatable("Now playing %s", Component.empty().append(currentSong.name).color(NamedTextColor.GOLD)));
|
||||
currentSong.play();
|
||||
}
|
||||
|
||||
if (currentSong.paused && ticksUntilPausedActionbar-- < 0) return;
|
||||
else ticksUntilPausedActionbar = 20;
|
||||
|
||||
bot.core().run("minecraft:bossbar add " + bossbarName + " \"\"");
|
||||
bot.core().run("minecraft:bossbar set " + bossbarName + " players " + SELECTOR);
|
||||
bot.core().run("minecraft:bossbar set " + bossbarName + " name " + GsonComponentSerializer.gson().serialize(generateBossbar()));
|
||||
bot.core().run("minecraft:bossbar set " + bossbarName + " color yellow");
|
||||
bot.core().run("minecraft:bossbar set " + bossbarName + " visible true");
|
||||
bot.core().run("minecraft:bossbar set " + bossbarName + " value " + (int) Math.floor(currentSong.time));
|
||||
bot.core().run("minecraft:bossbar set " + bossbarName + " max " + currentSong.length);
|
||||
|
||||
if (currentSong.paused) return;
|
||||
|
||||
handlePlaying();
|
||||
|
||||
if (currentSong.finished()) {
|
||||
removeBossbar();
|
||||
bot.chat().tellraw(Component.translatable("Finished playing %s", Component.empty().append(currentSong.name).color(NamedTextColor.GOLD)));
|
||||
currentSong = null;
|
||||
}
|
||||
};
|
||||
|
||||
futurePlayTask = bot.executor().scheduleAtFixedRate(playTask, 50, 50, TimeUnit.MILLISECONDS);
|
||||
|
||||
if (currentSong != null) currentSong.play();
|
||||
}
|
||||
|
||||
public void removeBossbar () {
|
||||
bot.core().run("minecraft:bossbar remove " + bossbarName);
|
||||
}
|
||||
|
||||
public Component generateBossbar () {
|
||||
Component component = Component.empty()
|
||||
.append(Component.empty().append(currentSong.name).color(NamedTextColor.GREEN))
|
||||
.append(Component.text(" | ").color(NamedTextColor.DARK_GRAY))
|
||||
.append(Component.translatable("%s / %s", formatTime(currentSong.time).color(NamedTextColor.GRAY), formatTime(currentSong.length).color(NamedTextColor.GRAY)).color(NamedTextColor.DARK_GRAY))
|
||||
.append(Component.text(" | ").color(NamedTextColor.DARK_GRAY))
|
||||
.append(Component.translatable("%s / %s", Component.text(currentSong.position, NamedTextColor.GRAY), Component.text(currentSong.size(), NamedTextColor.GRAY)).color(NamedTextColor.DARK_GRAY));
|
||||
|
||||
if (currentSong.paused) {
|
||||
return component
|
||||
.append(Component.text(" | ", NamedTextColor.DARK_GRAY))
|
||||
.append(Component.text("Paused", NamedTextColor.GREEN));
|
||||
}
|
||||
|
||||
if (currentSong.looping > 0) {
|
||||
final int looping = currentSong().looping;
|
||||
return component
|
||||
.append(Component.translatable(" | ", NamedTextColor.DARK_GRAY))
|
||||
.append(Component.translatable("Looping " + ((looping == 1) ? "current" : "all"), NamedTextColor.DARK_GREEN));
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
public Component formatTime (long millis) {
|
||||
final int seconds = (int) millis / 1000;
|
||||
|
||||
final String minutePart = String.valueOf(seconds / 60);
|
||||
final String unpaddedSecondPart = String.valueOf(seconds % 60);
|
||||
|
||||
return Component.translatable(
|
||||
"%s:%s",
|
||||
Component.text(minutePart),
|
||||
Component.text(unpaddedSecondPart.length() < 2 ? "0" + unpaddedSecondPart : unpaddedSecondPart)
|
||||
);
|
||||
}
|
||||
|
||||
public void stopPlaying () {
|
||||
currentSong = null;
|
||||
removeBossbar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnected (DisconnectedEvent event) {
|
||||
futurePlayTask.cancel(false);
|
||||
|
||||
if (currentSong != null) currentSong.pause(); // nice.
|
||||
}
|
||||
|
||||
public void handlePlaying () {
|
||||
currentSong.advanceTime();
|
||||
while (currentSong.reachedNextNote()) {
|
||||
final Note note = currentSong.getNextNote();
|
||||
|
||||
final double floatingPitch = Math.pow(2, (note.pitch - 12) / 12.0);
|
||||
|
||||
bot.core().run("minecraft:execute as " + SELECTOR + " at @s run playsound " + note.instrument.sound + " record @s ~ ~ ~ " + note.volume + " " + floatingPitch);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -87,6 +87,12 @@ public class SelfCarePlugin extends SessionAdapter {
|
|||
this.entityId = packet.getEntityId();
|
||||
this.gamemode = packet.getGameMode();
|
||||
|
||||
cspy = false;
|
||||
vanish = false;
|
||||
socialspy = false;
|
||||
muted = false;
|
||||
prefix = false;
|
||||
|
||||
final Runnable task = () -> {
|
||||
final Session session = bot.session();
|
||||
final PacketProtocol protocol = session.getPacketProtocol();
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package me.chayapak1.chomensbot_mabe.song;
|
||||
|
||||
public class Instrument {
|
||||
public static final Instrument HARP = new Instrument(0, "harp", 54);
|
||||
public static final Instrument BASEDRUM = new Instrument(1, "basedrum", 0);
|
||||
public static final Instrument SNARE = new Instrument(2, "snare", 0);
|
||||
public static final Instrument HAT = new Instrument(3, "hat", 0);
|
||||
public static final Instrument BASS = new Instrument(4, "bass", 30);
|
||||
public static final Instrument FLUTE = new Instrument(5, "flute", 66);
|
||||
public static final Instrument BELL = new Instrument(6, "bell", 78);
|
||||
public static final Instrument GUITAR = new Instrument(7, "guitar", 42);
|
||||
public static final Instrument CHIME = new Instrument(8, "chime", 78);
|
||||
public static final Instrument XYLOPHONE = new Instrument(9, "xylophone", 78);
|
||||
public static final Instrument IRON_XYLOPHONE = new Instrument(10, "iron_xylophone", 54);
|
||||
public static final Instrument COW_BELL = new Instrument(11, "cow_bell", 66);
|
||||
public static final Instrument DIDGERIDOO = new Instrument(12, "didgeridoo", 30);
|
||||
public static final Instrument BIT = new Instrument(13, "bit", 54);
|
||||
public static final Instrument BANJO = new Instrument(14, "banjo", 54);
|
||||
public static final Instrument PLING = new Instrument(15, "pling", 54);
|
||||
|
||||
public final int id;
|
||||
public final String name;
|
||||
public final int offset;
|
||||
public final String sound;
|
||||
|
||||
private Instrument (int id, String name, int offset, String sound) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.offset = offset;
|
||||
this.sound = name;
|
||||
}
|
||||
|
||||
private Instrument (int id, String name, int offset) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.offset = offset;
|
||||
this.sound = "minecraft:block.note_block." + name;
|
||||
}
|
||||
|
||||
public static Instrument of (String sound) {
|
||||
return new Instrument(-1, null, 0, sound);
|
||||
}
|
||||
|
||||
private static Instrument[] values = {HARP, BASEDRUM, SNARE, HAT, BASS, FLUTE, BELL, GUITAR, CHIME, XYLOPHONE, IRON_XYLOPHONE, COW_BELL, DIDGERIDOO, BIT, BANJO, PLING};
|
||||
public static Instrument fromId (int id) {
|
||||
return values[id];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,374 @@
|
|||
package me.chayapak1.chomensbot_mabe.song;
|
||||
|
||||
import me.chayapak1.chomensbot_mabe.Bot;
|
||||
import me.chayapak1.chomensbot_mabe.util.DownloadUtilities;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.sound.midi.*;
|
||||
|
||||
public class MidiConverter {
|
||||
public static final int SET_INSTRUMENT = 0xC0;
|
||||
public static final int SET_TEMPO = 0x51;
|
||||
public static final int NOTE_ON = 0x90;
|
||||
public static final int NOTE_OFF = 0x80;
|
||||
|
||||
// public static Song getSongFromUrl(URL url) throws IOException, InvalidMidiDataException, URISyntaxException, NoSuchAlgorithmException, KeyManagementException {
|
||||
// Sequence sequence = MidiSystem.getSequence(DownloadUtilities.DownloadToInputStream(url, 5*1024*1024));
|
||||
// return getSong(sequence, Paths.get(url.toURI().getPath()).getFileName().toString());
|
||||
// }
|
||||
//
|
||||
// public static Song getSongFromFile(File file) throws InvalidMidiDataException, IOException {
|
||||
// Sequence sequence = MidiSystem.getSequence(file);
|
||||
// return getSong(sequence, file.getName());
|
||||
// }
|
||||
|
||||
public static Song getSongFromBytes(byte[] bytes, String name, Bot bot) throws InvalidMidiDataException, IOException {
|
||||
Sequence sequence = MidiSystem.getSequence(new ByteArrayInputStream(bytes));
|
||||
return getSong(sequence, name, bot);
|
||||
}
|
||||
|
||||
public static Song getSong(Sequence sequence, String name, Bot bot) {
|
||||
Song song = new Song(name, bot);
|
||||
|
||||
long tpq = sequence.getResolution();
|
||||
|
||||
ArrayList<MidiEvent> tempoEvents = new ArrayList<>();
|
||||
for (Track track : sequence.getTracks()) {
|
||||
for (int i = 0; i < track.size(); i++) {
|
||||
MidiEvent event = track.get(i);
|
||||
MidiMessage message = event.getMessage();
|
||||
if (message instanceof MetaMessage) {
|
||||
MetaMessage mm = (MetaMessage) message;
|
||||
if (mm.getType() == SET_TEMPO) {
|
||||
tempoEvents.add(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(tempoEvents, (a, b) -> Long.compare(a.getTick(), b.getTick()));
|
||||
|
||||
for (Track track : sequence.getTracks()) {
|
||||
|
||||
long microTime = 0;
|
||||
int[] ids = new int[16];
|
||||
int mpq = 500000;
|
||||
int tempoEventIdx = 0;
|
||||
long prevTick = 0;
|
||||
|
||||
for (int i = 0; i < track.size(); i++) {
|
||||
MidiEvent event = track.get(i);
|
||||
MidiMessage message = event.getMessage();
|
||||
|
||||
while (tempoEventIdx < tempoEvents.size() && event.getTick() > tempoEvents.get(tempoEventIdx).getTick()) {
|
||||
long deltaTick = tempoEvents.get(tempoEventIdx).getTick() - prevTick;
|
||||
prevTick = tempoEvents.get(tempoEventIdx).getTick();
|
||||
microTime += (mpq/tpq) * deltaTick;
|
||||
|
||||
MetaMessage mm = (MetaMessage) tempoEvents.get(tempoEventIdx).getMessage();
|
||||
byte[] data = mm.getData();
|
||||
int new_mpq = (data[2]&0xFF) | ((data[1]&0xFF)<<8) | ((data[0]&0xFF)<<16);
|
||||
if (new_mpq != 0) mpq = new_mpq;
|
||||
tempoEventIdx++;
|
||||
}
|
||||
|
||||
if (message instanceof ShortMessage) {
|
||||
ShortMessage sm = (ShortMessage) message;
|
||||
if (sm.getCommand() == SET_INSTRUMENT) {
|
||||
ids[sm.getChannel()] = sm.getData1();
|
||||
}
|
||||
else if (sm.getCommand() == NOTE_ON) {
|
||||
if (sm.getData2() == 0) continue;
|
||||
int pitch = sm.getData1();
|
||||
int velocity = sm.getData2();
|
||||
long deltaTick = event.getTick() - prevTick;
|
||||
prevTick = event.getTick();
|
||||
microTime += (mpq/tpq) * deltaTick;
|
||||
|
||||
Note note;
|
||||
if (sm.getChannel() == 9) {
|
||||
note = getMidiPercussionNote(pitch, velocity, microTime);
|
||||
}
|
||||
else {
|
||||
note = getMidiInstrumentNote(ids[sm.getChannel()], pitch, velocity, microTime);
|
||||
}
|
||||
if (note != null) {
|
||||
song.add(note);
|
||||
}
|
||||
|
||||
long time = microTime / 1000L;
|
||||
if (time > song.length) {
|
||||
song.length = time;
|
||||
}
|
||||
}
|
||||
else if (sm.getCommand() == NOTE_OFF) {
|
||||
long deltaTick = event.getTick() - prevTick;
|
||||
prevTick = event.getTick();
|
||||
microTime += (mpq/tpq) * deltaTick;
|
||||
long time = microTime / 1000L;
|
||||
if (time > song.length) {
|
||||
song.length = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
song.sort();
|
||||
|
||||
return song;
|
||||
}
|
||||
|
||||
public static Note getMidiInstrumentNote(int midiInstrument, int midiPitch, int velocity, long microTime) {
|
||||
Instrument instrument = null;
|
||||
Instrument[] instrumentList = instrumentMap.get(midiInstrument);
|
||||
if (instrumentList != null) {
|
||||
for (Instrument candidateInstrument : instrumentList) {
|
||||
if (midiPitch >= candidateInstrument.offset && midiPitch <= candidateInstrument.offset+24) {
|
||||
instrument = candidateInstrument;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (instrument == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int pitch = midiPitch-instrument.offset;
|
||||
float volume = (float) velocity / 127.0f;
|
||||
long time = microTime / 1000L;
|
||||
|
||||
return new Note(instrument, pitch, volume, time);
|
||||
}
|
||||
|
||||
private static Note getMidiPercussionNote (int midiPitch, int velocity, long microTime) {
|
||||
if (percussionMap.containsKey(midiPitch)) {
|
||||
int noteId = percussionMap.get(midiPitch);
|
||||
int pitch = noteId % 25;
|
||||
float volume = (float) velocity / 127.0f;
|
||||
Instrument instrument = Instrument.fromId(noteId / 25);
|
||||
long time = microTime / 1000L;
|
||||
|
||||
return new Note(instrument, pitch, volume, time);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static HashMap<Integer, Instrument[]> instrumentMap = new HashMap<>();
|
||||
static {
|
||||
// Piano (HARP BASS BELL)
|
||||
instrumentMap.put(0, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Acoustic Grand Piano
|
||||
instrumentMap.put(1, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Bright Acoustic Piano
|
||||
instrumentMap.put(2, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL}); // Electric Grand Piano
|
||||
instrumentMap.put(3, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Honky-tonk Piano
|
||||
instrumentMap.put(4, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL}); // Electric Piano 1
|
||||
instrumentMap.put(5, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL}); // Electric Piano 2
|
||||
instrumentMap.put(6, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Harpsichord
|
||||
instrumentMap.put(7, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Clavinet
|
||||
|
||||
// Chromatic Percussion (IRON_XYLOPHONE XYLOPHONE BASS)
|
||||
instrumentMap.put(8, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Celesta
|
||||
instrumentMap.put(9, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Glockenspiel
|
||||
instrumentMap.put(10, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Music Box
|
||||
instrumentMap.put(11, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Vibraphone
|
||||
instrumentMap.put(12, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Marimba
|
||||
instrumentMap.put(13, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Xylophone
|
||||
instrumentMap.put(14, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Tubular Bells
|
||||
instrumentMap.put(15, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Dulcimer
|
||||
|
||||
// Organ (BIT DIDGERIDOO BELL)
|
||||
instrumentMap.put(16, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Drawbar Organ
|
||||
instrumentMap.put(17, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Percussive Organ
|
||||
instrumentMap.put(18, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Rock Organ
|
||||
instrumentMap.put(19, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Church Organ
|
||||
instrumentMap.put(20, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Reed Organ
|
||||
instrumentMap.put(21, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Accordian
|
||||
instrumentMap.put(22, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Harmonica
|
||||
instrumentMap.put(23, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Tango Accordian
|
||||
|
||||
// Guitar (BIT DIDGERIDOO BELL)
|
||||
instrumentMap.put(24, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Acoustic Guitar (nylon)
|
||||
instrumentMap.put(25, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Acoustic Guitar (steel)
|
||||
instrumentMap.put(26, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Electric Guitar (jazz)
|
||||
instrumentMap.put(27, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Electric Guitar (clean)
|
||||
instrumentMap.put(28, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Electric Guitar (muted)
|
||||
instrumentMap.put(29, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Overdriven Guitar
|
||||
instrumentMap.put(30, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Distortion Guitar
|
||||
instrumentMap.put(31, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Guitar Harmonics
|
||||
|
||||
// Bass
|
||||
instrumentMap.put(32, new Instrument[]{Instrument.BASS, Instrument.HARP, Instrument.BELL}); // Acoustic Bass
|
||||
instrumentMap.put(33, new Instrument[]{Instrument.BASS, Instrument.HARP, Instrument.BELL}); // Electric Bass (finger)
|
||||
instrumentMap.put(34, new Instrument[]{Instrument.BASS, Instrument.HARP, Instrument.BELL}); // Electric Bass (pick)
|
||||
instrumentMap.put(35, new Instrument[]{Instrument.BASS, Instrument.HARP, Instrument.BELL}); // Fretless Bass
|
||||
instrumentMap.put(36, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Slap Bass 1
|
||||
instrumentMap.put(37, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Slap Bass 2
|
||||
instrumentMap.put(38, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Synth Bass 1
|
||||
instrumentMap.put(39, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Synth Bass 2
|
||||
|
||||
// Strings
|
||||
instrumentMap.put(40, new Instrument[]{Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL}); // Violin
|
||||
instrumentMap.put(41, new Instrument[]{Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL}); // Viola
|
||||
instrumentMap.put(42, new Instrument[]{Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL}); // Cello
|
||||
instrumentMap.put(43, new Instrument[]{Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL}); // Contrabass
|
||||
instrumentMap.put(44, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL}); // Tremolo Strings
|
||||
instrumentMap.put(45, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Pizzicato Strings
|
||||
instrumentMap.put(46, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.CHIME}); // Orchestral Harp
|
||||
instrumentMap.put(47, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Timpani
|
||||
|
||||
// Ensenble
|
||||
instrumentMap.put(48, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // String Ensemble 1
|
||||
instrumentMap.put(49, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // String Ensemble 2
|
||||
instrumentMap.put(50, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Synth Strings 1
|
||||
instrumentMap.put(51, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Synth Strings 2
|
||||
instrumentMap.put(52, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Choir Aahs
|
||||
instrumentMap.put(53, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Voice Oohs
|
||||
instrumentMap.put(54, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Synth Choir
|
||||
instrumentMap.put(55, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Orchestra Hit
|
||||
|
||||
// Brass
|
||||
instrumentMap.put(56, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(57, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(58, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(59, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(60, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(61, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(62, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(63, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
|
||||
// Reed
|
||||
instrumentMap.put(64, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(65, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(66, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(67, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(68, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(69, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(70, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(71, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
|
||||
// Pipe
|
||||
instrumentMap.put(72, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(73, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(74, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(75, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(76, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(77, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(78, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(79, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
|
||||
// Synth Lead
|
||||
instrumentMap.put(80, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(81, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(82, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(83, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(84, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(85, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(86, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(87, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
|
||||
// Synth Pad
|
||||
instrumentMap.put(88, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(89, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(90, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(91, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(92, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(93, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(94, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(95, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
|
||||
// Synth Effects
|
||||
// instrumentMap.put(96, new Instrument[]{});
|
||||
// instrumentMap.put(97, new Instrument[]{});
|
||||
instrumentMap.put(98, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(99, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(100, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(101, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(102, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(103, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
|
||||
// Ethnic
|
||||
instrumentMap.put(104, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(105, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(106, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(107, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(108, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(109, new Instrument[]{Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(110, new Instrument[]{Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(111, new Instrument[]{Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
|
||||
// Percussive
|
||||
instrumentMap.put(112, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(113, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(114, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(115, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(116, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(117, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(118, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(119, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
}
|
||||
|
||||
public static HashMap<Integer, Integer> percussionMap = new HashMap<>();
|
||||
static {
|
||||
percussionMap.put(35, 10 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(36, 6 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(37, 6 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(38, 8 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(39, 6 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(40, 4 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(41, 6 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(42, 22 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(43, 13 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(44, 22 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(45, 15 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(46, 18 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(47, 20 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(48, 23 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(49, 17 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(50, 23 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(51, 24 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(52, 8 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(53, 13 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(54, 18 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(55, 18 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(56, 1 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(57, 13 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(58, 2 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(59, 13 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(60, 9 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(61, 2 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(62, 8 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(63, 22 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(64, 15 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(65, 13 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(66, 8 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(67, 8 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(68, 3 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(69, 20 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(70, 23 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(71, 24 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(72, 24 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(73, 17 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(74, 11 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(75, 18 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(76, 9 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(77, 5 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(78, 22 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(79, 19 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(80, 17 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(81, 22 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(82, 22 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(83, 24 + 25*Instrument.CHIME.id);
|
||||
percussionMap.put(84, 24 + 25*Instrument.CHIME.id);
|
||||
percussionMap.put(85, 21 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(86, 14 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(87, 7 + 25*Instrument.BASEDRUM.id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
package me.chayapak1.chomensbot_mabe.song;
|
||||
|
||||
import me.chayapak1.chomensbot_mabe.Bot;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class NBSConverter {
|
||||
public static Instrument[] instrumentIndex = new Instrument[] {
|
||||
Instrument.HARP,
|
||||
Instrument.BASS,
|
||||
Instrument.BASEDRUM,
|
||||
Instrument.SNARE,
|
||||
Instrument.HAT,
|
||||
Instrument.GUITAR,
|
||||
Instrument.FLUTE,
|
||||
Instrument.BELL,
|
||||
Instrument.CHIME,
|
||||
Instrument.XYLOPHONE,
|
||||
Instrument.IRON_XYLOPHONE,
|
||||
Instrument.COW_BELL,
|
||||
Instrument.DIDGERIDOO,
|
||||
Instrument.BIT,
|
||||
Instrument.BANJO,
|
||||
Instrument.PLING,
|
||||
};
|
||||
|
||||
private static class NBSNote {
|
||||
public int tick;
|
||||
public short layer;
|
||||
public byte instrument;
|
||||
public byte key;
|
||||
public byte velocity = 100;
|
||||
public byte panning = 100;
|
||||
public short pitch = 0;
|
||||
}
|
||||
|
||||
private static class NBSLayer {
|
||||
public String name;
|
||||
public byte lock = 0;
|
||||
public byte volume;
|
||||
public byte stereo = 100;
|
||||
}
|
||||
|
||||
private static class NBSCustomInstrument {
|
||||
public String name;
|
||||
public String file;
|
||||
public byte pitch = 0;
|
||||
public boolean key = false;
|
||||
}
|
||||
|
||||
public static Song getSongFromBytes(byte[] bytes, String fileName, Bot bot) throws IOException {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
short songLength;
|
||||
byte format = 0;
|
||||
byte vanillaInstrumentCount = 0;
|
||||
songLength = buffer.getShort(); // If it's not 0, then it uses the old format
|
||||
if (songLength == 0) {
|
||||
format = buffer.get();
|
||||
}
|
||||
|
||||
if (format >= 1) {
|
||||
vanillaInstrumentCount = buffer.get();
|
||||
}
|
||||
if (format >= 3) {
|
||||
songLength = buffer.getShort();
|
||||
}
|
||||
|
||||
short layerCount = buffer.getShort();
|
||||
String songName = getString(buffer, bytes.length);
|
||||
String songAuthor = getString(buffer, bytes.length);
|
||||
String songOriginalAuthor = getString(buffer, bytes.length);
|
||||
String songDescription = getString(buffer, bytes.length);
|
||||
short tempo = buffer.getShort();
|
||||
byte autoSaving = buffer.get();
|
||||
byte autoSavingDuration = buffer.get();
|
||||
byte timeSignature = buffer.get();
|
||||
int minutesSpent = buffer.getInt();
|
||||
int leftClicks = buffer.getInt();
|
||||
int rightClicks = buffer.getInt();
|
||||
int blocksAdded = buffer.getInt();
|
||||
int blocksRemoved = buffer.getInt();
|
||||
String origFileName = getString(buffer, bytes.length);
|
||||
|
||||
byte loop = 0;
|
||||
byte maxLoopCount = 0;
|
||||
short loopStartTick = 0;
|
||||
if (format >= 4) {
|
||||
loop = buffer.get();
|
||||
maxLoopCount = buffer.get();
|
||||
loopStartTick = buffer.getShort();
|
||||
}
|
||||
|
||||
ArrayList<NBSNote> nbsNotes = new ArrayList<>();
|
||||
short tick = -1;
|
||||
while (true) {
|
||||
int tickJumps = buffer.getShort();
|
||||
if (tickJumps == 0) break;
|
||||
tick += tickJumps;
|
||||
|
||||
short layer = -1;
|
||||
while (true) {
|
||||
int layerJumps = buffer.getShort();
|
||||
if (layerJumps == 0) break;
|
||||
layer += layerJumps;
|
||||
NBSNote note = new NBSNote();
|
||||
note.tick = tick;
|
||||
note.layer = layer;
|
||||
note.instrument = buffer.get();
|
||||
note.key = buffer.get();
|
||||
if (format >= 4) {
|
||||
note.velocity = buffer.get();
|
||||
note.panning = buffer.get();
|
||||
note.pitch = buffer.getShort();
|
||||
}
|
||||
nbsNotes.add(note);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<NBSLayer> nbsLayers = new ArrayList<>();
|
||||
if (buffer.hasRemaining()) {
|
||||
for (int i=0; i<layerCount; i++) {
|
||||
NBSLayer layer = new NBSLayer();
|
||||
layer.name = getString(buffer, bytes.length);
|
||||
if (format >= 4) {
|
||||
layer.lock = buffer.get();
|
||||
}
|
||||
layer.volume = buffer.get();
|
||||
if (format >= 2) {
|
||||
layer.stereo = buffer.get();
|
||||
}
|
||||
nbsLayers.add(layer);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<NBSCustomInstrument> customInstruments = new ArrayList<>();
|
||||
if (buffer.hasRemaining()) {
|
||||
byte customInstrumentCount = buffer.get();
|
||||
for (int i = 0; i < customInstrumentCount; i++) {
|
||||
NBSCustomInstrument customInstrument = new NBSCustomInstrument();
|
||||
customInstrument.name = getString(buffer, bytes.length);
|
||||
customInstrument.file = getString(buffer, bytes.length);
|
||||
customInstrument.pitch = buffer.get();
|
||||
customInstrument.key = buffer.get() == 0 ? false : true;
|
||||
customInstruments.add(customInstrument);
|
||||
}
|
||||
}
|
||||
|
||||
Song song = new Song(songName.trim().length() > 0 ? songName : fileName, bot);
|
||||
if (loop > 0) {
|
||||
song.looping = 1;
|
||||
song.loopPosition = getMilliTime(loopStartTick, tempo);
|
||||
// song.loopCount = maxLoopCount;
|
||||
}
|
||||
for (NBSNote note : nbsNotes) {
|
||||
Instrument instrument;
|
||||
int key = note.key;
|
||||
if (note.instrument < instrumentIndex.length) {
|
||||
instrument = instrumentIndex[note.instrument];
|
||||
} else {
|
||||
int index = note.instrument - instrumentIndex.length;
|
||||
if (index >= customInstruments.size()) continue;
|
||||
NBSCustomInstrument customInstrument = customInstruments.get(index);
|
||||
instrument = Instrument.of(customInstrument.name);
|
||||
// key += customInstrument.pitch;
|
||||
}
|
||||
|
||||
if (key < 33 || key > 57) {
|
||||
continue;
|
||||
}
|
||||
|
||||
byte layerVolume = 100;
|
||||
if (nbsLayers.size() > note.layer) {
|
||||
layerVolume = nbsLayers.get(note.layer).volume;
|
||||
}
|
||||
|
||||
int pitch = key-33;
|
||||
song.add(new Note(instrument, pitch, (float) note.velocity * (float) layerVolume / 10000f, getMilliTime(note.tick, tempo)));
|
||||
}
|
||||
|
||||
song.length = song.get(song.size()-1).time + 50;
|
||||
|
||||
return song;
|
||||
}
|
||||
|
||||
private static String getString (ByteBuffer buffer, int maxSize) throws IOException {
|
||||
int length = buffer.getInt();
|
||||
if (length > maxSize) {
|
||||
throw new IOException("String is too large");
|
||||
}
|
||||
byte arr[] = new byte[length];
|
||||
buffer.get(arr, 0, length);
|
||||
return new String(arr);
|
||||
}
|
||||
|
||||
private static int getMilliTime(int tick, int tempo) {
|
||||
return 1000 * tick * 100 / tempo;
|
||||
}
|
||||
}
|
28
src/main/java/me/chayapak1/chomensbot_mabe/song/Note.java
Normal file
28
src/main/java/me/chayapak1/chomensbot_mabe/song/Note.java
Normal file
|
@ -0,0 +1,28 @@
|
|||
package me.chayapak1.chomensbot_mabe.song;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class Note implements Comparable<Note> {
|
||||
public Instrument instrument;
|
||||
public int pitch;
|
||||
public float volume;
|
||||
public long time;
|
||||
|
||||
@Override
|
||||
public int compareTo(Note other) {
|
||||
if (time < other.time) {
|
||||
return -1;
|
||||
}
|
||||
else if (time > other.time) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int noteId () {
|
||||
return pitch + instrument.id * 25;
|
||||
}
|
||||
}
|
165
src/main/java/me/chayapak1/chomensbot_mabe/song/Song.java
Normal file
165
src/main/java/me/chayapak1/chomensbot_mabe/song/Song.java
Normal file
|
@ -0,0 +1,165 @@
|
|||
package me.chayapak1.chomensbot_mabe.song;
|
||||
|
||||
import me.chayapak1.chomensbot_mabe.Bot;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
public class Song {
|
||||
public ArrayList<Note> notes = new ArrayList<>();
|
||||
public Component name;
|
||||
public int position = 0; // Current note index
|
||||
public int looping = 0; // 0 for no looping, 1 for current loop, 2 for all loops
|
||||
public boolean paused = true;
|
||||
public long startTime = 0; // Start time in millis since unix epoch
|
||||
public long length = 0; // Milliseconds in the song
|
||||
public long time = 0; // Time since start of song
|
||||
public long loopPosition = 0; // Milliseconds into the song to start looping
|
||||
public int loopCount = 0; // Number of times to loop
|
||||
public int currentLoop = 0; // Number of loops so far
|
||||
public int queueIndex = 0;
|
||||
|
||||
private Bot bot;
|
||||
|
||||
public Song (Component name, Bot bot) {
|
||||
this.bot = bot;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Song (String name, Bot bot) {
|
||||
this(Component.text(name), bot);
|
||||
this.bot = bot;
|
||||
}
|
||||
|
||||
public Note get (int i) {
|
||||
return notes.get(i);
|
||||
}
|
||||
|
||||
public void add (Note e) {
|
||||
notes.add(e);
|
||||
}
|
||||
|
||||
public void sort () {
|
||||
Collections.sort(notes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts playing song (does nothing if already playing)
|
||||
*/
|
||||
public void play () {
|
||||
if (paused) {
|
||||
paused = false;
|
||||
startTime = System.currentTimeMillis() - time;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses song (does nothing if already paused)
|
||||
*/
|
||||
public void pause () {
|
||||
if (!paused) {
|
||||
paused = true;
|
||||
// Recalculates time so that the song will continue playing after the exact point it was paused
|
||||
advanceTime();
|
||||
}
|
||||
}
|
||||
|
||||
public void setTime (long t) {
|
||||
time = t;
|
||||
// System.out.println("time is " + time);
|
||||
startTime = System.currentTimeMillis() - time;
|
||||
// System.out.println("start time is " + startTime);
|
||||
position = 0;
|
||||
while (position < notes.size() && notes.get(position).time < t) {
|
||||
position++;
|
||||
}
|
||||
// System.out.println("position is " + position);
|
||||
}
|
||||
|
||||
public void advanceTime () {
|
||||
time = System.currentTimeMillis() - startTime;
|
||||
}
|
||||
|
||||
public boolean reachedNextNote () {
|
||||
if (position < notes.size()) {
|
||||
return notes.get(position).time <= time;
|
||||
} else {
|
||||
if (time > length && shouldLoop()) {
|
||||
loop();
|
||||
if (position < notes.size()) {
|
||||
return notes.get(position).time <= time;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Note getNextNote () {
|
||||
if (position >= notes.size()) {
|
||||
if (shouldLoop()) {
|
||||
loop();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return notes.get(position++);
|
||||
}
|
||||
|
||||
public boolean finished () {
|
||||
return time > length && !shouldLoop();
|
||||
}
|
||||
|
||||
private void loop () {
|
||||
// position = 0;
|
||||
// startTime += length - loopPosition;
|
||||
// time -= length - loopPosition;
|
||||
// while (position < notes.size() && notes.get(position).time < loopPosition) {
|
||||
// position++;
|
||||
// }
|
||||
// currentLoop++;
|
||||
// if (looping == 1) {
|
||||
position = 0;
|
||||
startTime += length - loopPosition;
|
||||
time -= length - loopPosition;
|
||||
while (position < notes.size() && notes.get(position).time < loopPosition) {
|
||||
position++;
|
||||
}
|
||||
// System.out.println("looping is 1 we did all shits here and position is " + position);
|
||||
// } else if (looping == 2) {
|
||||
// position = 0;
|
||||
// setTime(0);
|
||||
// System.out.println("looping is 2 position " + position);
|
||||
// queueIndex = (queueIndex + 1) % bot.music().songQueue().size();
|
||||
// System.out.println("queue INDEX IS " + queueIndex);
|
||||
// System.out.println("BOT SONG QUEUEUE SIZE IS " + bot.music().songQueue().size());
|
||||
// }
|
||||
// System.out.println(currentLoop);
|
||||
currentLoop++;
|
||||
}
|
||||
|
||||
private boolean shouldLoop () {
|
||||
// if (looping) {
|
||||
// if (loopCount == 0) {
|
||||
// return true;
|
||||
// } else {
|
||||
// return currentLoop < loopCount;
|
||||
// }
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
if (looping == 1) {
|
||||
if (loopCount == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return currentLoop < loopCount;
|
||||
}
|
||||
} else return looping == 2;
|
||||
}
|
||||
|
||||
public int size () {
|
||||
return notes.size();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package me.chayapak1.chomensbot_mabe.song;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import lombok.Getter;
|
||||
import me.chayapak1.chomensbot_mabe.util.ComponentUtilities;
|
||||
|
||||
public class SongLoaderException extends Exception {
|
||||
@Getter private final Component message;
|
||||
|
||||
public SongLoaderException (Component message) {
|
||||
super();
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public SongLoaderException (Component message, Throwable cause) {
|
||||
super(null, cause);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage () {
|
||||
return ComponentUtilities.stringify(message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package me.chayapak1.chomensbot_mabe.song;
|
||||
|
||||
import me.chayapak1.chomensbot_mabe.Bot;
|
||||
import me.chayapak1.chomensbot_mabe.plugins.MusicPlayerPlugin;
|
||||
import me.chayapak1.chomensbot_mabe.util.DownloadUtilities;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class SongLoaderThread extends Thread {
|
||||
private String location;
|
||||
private File songPath;
|
||||
private URL songUrl;
|
||||
public SongLoaderException exception;
|
||||
public Song song;
|
||||
|
||||
private Bot bot;
|
||||
|
||||
private boolean isUrl = false;
|
||||
|
||||
public SongLoaderThread (URL location, Bot bot) throws SongLoaderException {
|
||||
this.bot = bot;
|
||||
isUrl = true;
|
||||
System.out.println("its url");
|
||||
songUrl = location;
|
||||
}
|
||||
|
||||
public SongLoaderThread (Path location, Bot bot) throws SongLoaderException {
|
||||
this.bot = bot;
|
||||
isUrl = false;
|
||||
System.out.println("its path");
|
||||
songPath = location.toFile();
|
||||
}
|
||||
|
||||
public void run () {
|
||||
byte[] bytes;
|
||||
String name;
|
||||
try {
|
||||
if (isUrl) {
|
||||
bytes = DownloadUtilities.DownloadToByteArray(songUrl, 10*1024*1024);
|
||||
name = Paths.get(songUrl.toURI().getPath()).getFileName().toString();
|
||||
} else {
|
||||
bytes = Files.readAllBytes(songPath.toPath());
|
||||
name = songPath.getName();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("WHAT THE SUS EXCEPTION YUP ! !! %@%$");
|
||||
e.printStackTrace();
|
||||
exception = new SongLoaderException(Component.text(e.getMessage()), e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
song = MidiConverter.getSongFromBytes(bytes, name, bot);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
if (song == null) {
|
||||
try {
|
||||
song = NBSConverter.getSongFromBytes(bytes, name, bot);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
if (song == null) {
|
||||
exception = new SongLoaderException(Component.translatable("Invalid song format"));
|
||||
}
|
||||
}
|
||||
|
||||
private File getSongFile (String name) {
|
||||
return new File(MusicPlayerPlugin.SONG_DIR, name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package me.chayapak1.chomensbot_mabe.util;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
public class DownloadUtilities {
|
||||
private static class DefaultTrustManager implements X509TrustManager {
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] arg0, String arg1) {}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] arg0, String arg1) {}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DownloadToByteArray(URL url, int maxSize) throws IOException, KeyManagementException, NoSuchAlgorithmException {
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
|
||||
SSLContext.setDefault(ctx);
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setConnectTimeout(5000);
|
||||
conn.setReadTimeout(10000);
|
||||
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0");
|
||||
|
||||
try (BufferedInputStream downloadStream = new BufferedInputStream(conn.getInputStream())) {
|
||||
ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
|
||||
byte[] buf = new byte[1024];
|
||||
int n;
|
||||
int tot = 0;
|
||||
while ((n = downloadStream.read(buf)) > 0) {
|
||||
byteArrayStream.write(buf, 0, n);
|
||||
tot += n;
|
||||
if (tot > maxSize) {
|
||||
throw new IOException("File is too large");
|
||||
}
|
||||
if (Thread.interrupted()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return byteArrayStream.toByteArray();
|
||||
}
|
||||
// Closing a ByteArrayInputStream has no effect, so I do not close it.
|
||||
}
|
||||
|
||||
public static InputStream DownloadToInputStream(URL url, int maxSize) throws KeyManagementException, NoSuchAlgorithmException, IOException {
|
||||
return new ByteArrayInputStream(DownloadToByteArray(url, maxSize));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue