fard
This commit is contained in:
parent
d1dbd01df9
commit
95a818e7b0
Binary file not shown.
38897
javascript/classes.js
38897
javascript/classes.js
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -18,10 +18,10 @@ public class GuiScreenModules extends GuiScreen {
|
||||||
this.iteminfo = new GuiTextField(this.fontRenderer, this.width / 2 - 98, this.height / 6 + 24, 195, 20);
|
this.iteminfo = new GuiTextField(this.fontRenderer, this.width / 2 - 98, this.height / 6 + 24, 195, 20);
|
||||||
this.iteminfo.setFocused(true);
|
this.iteminfo.setFocused(true);
|
||||||
this.iteminfo.setText("383");
|
this.iteminfo.setText("383");
|
||||||
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 6 + 124, "Give"));
|
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 6 + 52, "Give"));
|
||||||
this.buttonList.add(new GuiButton(2, this.width / 2 - 100, this.height / 6 + 100, "Toggle Notebot"));
|
this.buttonList.add(new GuiButton(2, this.width / 2 - 100, this.height / 6 + 76, "Toggle Notebot"));
|
||||||
this.buttonList.add(new GuiButton(3, this.width / 2 - 100, this.height / 6 + 76, "Toggle Legit mode"));
|
this.buttonList.add(new GuiButton(3, this.width / 2 - 100, this.height / 6 + 100, "Toggle Legit mode"));
|
||||||
this.buttonList.add(new GuiButton(4, this.width / 2 - 100, this.height / 6 + 52, "Toggle Flight"));
|
this.buttonList.add(new GuiButton(4, this.width / 2 - 100, this.height / 6 + 124, "Toggle Flight"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onGuiClosed() {
|
public void onGuiClosed() {
|
||||||
|
@ -57,7 +57,7 @@ public class GuiScreenModules extends GuiScreen {
|
||||||
NoteblockPlayer.thr = new Thread(new Runnable() {
|
NoteblockPlayer.thr = new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
EaglerAdapter.openFileChooser("nbs", "application/nbs");
|
EaglerAdapter.openFileChooser("nbs", ".nbs,.mid,.midi");
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
while(!EaglerAdapter.isFocused()){
|
while(!EaglerAdapter.isFocused()){
|
||||||
|
@ -70,7 +70,7 @@ public class GuiScreenModules extends GuiScreen {
|
||||||
String name = EaglerAdapter.getFileChooserResultName();
|
String name = EaglerAdapter.getFileChooserResultName();
|
||||||
NoteblockPlayer.songdata = b;
|
NoteblockPlayer.songdata = b;
|
||||||
mc.thePlayer.sendChatToPlayer("Playing \""+name+"\" on notebot!");
|
mc.thePlayer.sendChatToPlayer("Playing \""+name+"\" on notebot!");
|
||||||
NoteblockPlayer.play();
|
NoteblockPlayer.play((name.toLowerCase().endsWith(".nbs")?NoteblockPlayer.loadSong():me.ayunami2000.ayunAudioStreamer.MidiConverter.midiToTxt()).split("\n"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
228
src/main/java/me/ayunami2000/ayuncraft/MidiConverter.java
Normal file
228
src/main/java/me/ayunami2000/ayuncraft/MidiConverter.java
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
package me.ayunami2000.ayunAudioStreamer;
|
||||||
|
|
||||||
|
import me.ayunami2000.ayuncraft.NoteblockPlayer;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import javax.sound.midi.MetaMessage;
|
||||||
|
import javax.sound.midi.MidiEvent;
|
||||||
|
import javax.sound.midi.MidiMessage;
|
||||||
|
import javax.sound.midi.MidiSystem;
|
||||||
|
import javax.sound.midi.Sequence;
|
||||||
|
import javax.sound.midi.ShortMessage;
|
||||||
|
import javax.sound.midi.Track;
|
||||||
|
|
||||||
|
public class MidiConverter {
|
||||||
|
public static int[] instrument_offsets = new int[] {
|
||||||
|
54, //harp
|
||||||
|
0, //basedrum
|
||||||
|
0, //snare
|
||||||
|
0, //hat
|
||||||
|
30, //bass
|
||||||
|
66, //flute
|
||||||
|
78, //bell
|
||||||
|
42, //guitar
|
||||||
|
78, //chime
|
||||||
|
78, //xylophone
|
||||||
|
54, //iron xylophone
|
||||||
|
66, //cow bell
|
||||||
|
30, //didgeridoo
|
||||||
|
54, //bit
|
||||||
|
54, //banjo
|
||||||
|
54, //electric piano
|
||||||
|
};
|
||||||
|
|
||||||
|
public static String midiToTxt() {
|
||||||
|
String midiTxtSong = "";
|
||||||
|
try {
|
||||||
|
BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(NoteblockPlayer.songdata));
|
||||||
|
TreeMap<Long, ArrayList<Integer>> noteMap = MidiConverter.getMidi(bis);
|
||||||
|
for (Map.Entry<Long, ArrayList<Integer>> entry : noteMap.entrySet()) {
|
||||||
|
for (int i=0;i<entry.getValue().size();i++) {
|
||||||
|
long time = entry.getKey();
|
||||||
|
int note = entry.getValue().get(i);
|
||||||
|
int velocity = velocityMap.get(entry.getKey()).get(i);
|
||||||
|
midiTxtSong += ((int) Math.floor(20.0*time/1000.0)) + ":" + (note % 25) + ":" + ((int) Math.floor(note / 25)) + ":" + velocity + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (midiTxtSong.endsWith("\n")) midiTxtSong = midiTxtSong.substring(0, midiTxtSong.length() - 1);
|
||||||
|
}catch(Exception e){}
|
||||||
|
return midiTxtSong;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TreeMap<Long, ArrayList<Integer>> noteMap;
|
||||||
|
public static TreeMap<Long, ArrayList<Integer>> velocityMap;
|
||||||
|
|
||||||
|
public static TreeMap<Long, ArrayList<Integer>> getMidi(BufferedInputStream downloadStream) throws Exception {
|
||||||
|
noteMap = new TreeMap<>();
|
||||||
|
velocityMap = new TreeMap<>();
|
||||||
|
|
||||||
|
Sequence sequence = MidiSystem.getSequence(downloadStream);
|
||||||
|
|
||||||
|
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() == 0x51) { //SET_TEMPO
|
||||||
|
tempoEvents.add(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(tempoEvents, new Comparator<MidiEvent>() {
|
||||||
|
@Override
|
||||||
|
public int compare(MidiEvent a, MidiEvent b) {
|
||||||
|
return (Long.valueOf(a.getTick())).compareTo(b.getTick());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (Track track : sequence.getTracks()) {
|
||||||
|
|
||||||
|
long microTime = 0;
|
||||||
|
int[] instrumentIds = new int[16];
|
||||||
|
//int apparent_mpq = (int) (sequence.getMicrosecondLength()/sequence.getTickLength()*tpq);
|
||||||
|
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() == ShortMessage.PROGRAM_CHANGE) {
|
||||||
|
instrumentIds[sm.getChannel()] = sm.getData1();
|
||||||
|
}
|
||||||
|
else if (sm.getCommand() == ShortMessage.NOTE_ON) {
|
||||||
|
if (sm.getData2() == 0) continue;
|
||||||
|
int key = sm.getData1();
|
||||||
|
int velocity = sm.getData2();
|
||||||
|
long deltaTick = event.getTick() - prevTick;
|
||||||
|
prevTick = event.getTick();
|
||||||
|
microTime += (mpq/tpq) * deltaTick;
|
||||||
|
if (sm.getChannel() == 9) {
|
||||||
|
processMidiNote(128, key, velocity, microTime);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
processMidiNote(instrumentIds[sm.getChannel()], key, velocity, microTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadStream.close();
|
||||||
|
|
||||||
|
return noteMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void processMidiNote(int midiInstrument, int midiPitch, int midiVelocity, long microTime) {
|
||||||
|
int[] noteData=noteConv(midiInstrument,midiPitch);
|
||||||
|
|
||||||
|
long milliTime = microTime / 1000;
|
||||||
|
if (noteData[0] >= 0) {
|
||||||
|
int noteId = (noteData[1]-instrument_offsets[noteData[0]]) + noteData[0]*25;
|
||||||
|
|
||||||
|
if (!noteMap.containsKey(milliTime)) {
|
||||||
|
noteMap.put(milliTime, new ArrayList<Integer>());
|
||||||
|
velocityMap.put(milliTime, new ArrayList<Integer>());
|
||||||
|
}
|
||||||
|
if (!noteMap.get(milliTime).contains(noteId)) {
|
||||||
|
noteMap.get(milliTime).add(noteId);
|
||||||
|
velocityMap.get(milliTime).add(midiVelocity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] noteConv(int midiInstrument, int midiPitch) {
|
||||||
|
int minecraftInstrument = -1;
|
||||||
|
if ((midiInstrument >= 0 && midiInstrument <= 7) || (midiInstrument >= 24 && midiInstrument <= 31)) { //normal
|
||||||
|
if (midiPitch >= 54 && midiPitch <= 78) {
|
||||||
|
minecraftInstrument = 0; //piano
|
||||||
|
}
|
||||||
|
else if (midiPitch >= 30 && midiPitch <= 54) {
|
||||||
|
minecraftInstrument = 4; //bass
|
||||||
|
}
|
||||||
|
else if (midiPitch >= 78 && midiPitch <= 102) {
|
||||||
|
minecraftInstrument = 6; //bells
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (midiInstrument >= 8 && midiInstrument <= 15) { //chromatic percussion
|
||||||
|
if (midiPitch >= 54 && midiPitch <= 78) {
|
||||||
|
minecraftInstrument = 10; //iron xylophone
|
||||||
|
}
|
||||||
|
else if (midiPitch >= 78 && midiPitch <= 102) {
|
||||||
|
minecraftInstrument = 9; //xylophone
|
||||||
|
}
|
||||||
|
else if (midiPitch >= 30 && midiPitch <= 54) {
|
||||||
|
minecraftInstrument = 4; //bass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((midiInstrument >= 16 && midiInstrument <= 23) || (midiInstrument >= 32 && midiInstrument <= 71) || (midiInstrument >= 80 && midiInstrument <= 111)) { //synth
|
||||||
|
if (midiPitch >= 54 && midiPitch <= 78) {
|
||||||
|
minecraftInstrument = 13; //bit
|
||||||
|
}
|
||||||
|
else if (midiPitch >= 30 && midiPitch <= 54) { //didgeridoo
|
||||||
|
minecraftInstrument = 12;
|
||||||
|
}
|
||||||
|
else if (midiPitch >= 78 && midiPitch <= 102) { //bells
|
||||||
|
minecraftInstrument = 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((midiInstrument >= 72 && midiInstrument <= 79)) { //woodwind
|
||||||
|
if (midiPitch >= 66 && midiPitch <= 90) {
|
||||||
|
minecraftInstrument = 5; //flute
|
||||||
|
}
|
||||||
|
else if (midiPitch >= 30 && midiPitch <= 54) { //didgeridoo
|
||||||
|
minecraftInstrument = 12;
|
||||||
|
}
|
||||||
|
else if (midiPitch >= 54 && midiPitch <= 78) {
|
||||||
|
minecraftInstrument = 13; //bit
|
||||||
|
}
|
||||||
|
else if (midiPitch >= 78 && midiPitch <= 102) { //bells
|
||||||
|
minecraftInstrument = 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (midiInstrument == 128) {
|
||||||
|
if (midiPitch == 35 || midiPitch == 36 || midiPitch == 41 || midiPitch == 43 || midiPitch == 45 || midiPitch == 57) {
|
||||||
|
minecraftInstrument = 1; //bass drum
|
||||||
|
}
|
||||||
|
else if (midiPitch == 38 || midiPitch == 39 || midiPitch == 40 || midiPitch == 54 || midiPitch == 69 || midiPitch == 70 || midiPitch == 73 || midiPitch == 74 || midiPitch == 78 || midiPitch == 79) {
|
||||||
|
minecraftInstrument = 2; //snare
|
||||||
|
}
|
||||||
|
else if (midiPitch == 37 || midiPitch == 42 || midiPitch == 44 || midiPitch == 46 || midiPitch == 49 || midiPitch == 51 || midiPitch == 52 || midiPitch == 55 || midiPitch == 57 || midiPitch == 59) {
|
||||||
|
minecraftInstrument = 3; //hat
|
||||||
|
}
|
||||||
|
midiPitch = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new int[]{minecraftInstrument,midiPitch};
|
||||||
|
}
|
||||||
|
}
|
|
@ -74,10 +74,9 @@ public class NoteblockPlayer {
|
||||||
mc.thePlayer.rotationPitch=pitch%360.0F;
|
mc.thePlayer.rotationPitch=pitch%360.0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void play(){
|
public static void play(String[] songLines){
|
||||||
playingSong=false;
|
playingSong=false;
|
||||||
playing=true;
|
playing=true;
|
||||||
String[] songLines=loadSong().split("\n");
|
|
||||||
HashMap<Integer, HashMap<Integer, Vec3>> songBlocks=songLinesToBlocks(songLines);
|
HashMap<Integer, HashMap<Integer, Vec3>> songBlocks=songLinesToBlocks(songLines);
|
||||||
if(playing)placeAndTuneNoteblocks(songBlocks);
|
if(playing)placeAndTuneNoteblocks(songBlocks);
|
||||||
if(playing) {
|
if(playing) {
|
||||||
|
|
|
@ -15,13 +15,20 @@ public enum Instrument {
|
||||||
FLUTE (6),
|
FLUTE (6),
|
||||||
BELL (7),
|
BELL (7),
|
||||||
CHIME (8),
|
CHIME (8),
|
||||||
XYLOPHONE (9);
|
XYLOPHONE (9),
|
||||||
|
IRON_XYLOPHONE (10),
|
||||||
|
COW_BELL (11),
|
||||||
|
DIDGERIDOO (12),
|
||||||
|
BIT (13),
|
||||||
|
BANJO (14),
|
||||||
|
PLING (15),
|
||||||
|
CUSTOM (-1);
|
||||||
|
|
||||||
private final int ID;
|
private final int ID;
|
||||||
private Instrument(int ID) {
|
private Instrument(int ID) {
|
||||||
this.ID = ID;
|
this.ID = ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an ID of the instrument to be written in NBS files.
|
* Returns an ID of the instrument to be written in NBS files.
|
||||||
* @return The ID.
|
* @return The ID.
|
||||||
|
@ -29,26 +36,32 @@ public enum Instrument {
|
||||||
public int getID() {
|
public int getID() {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines the instrument from its NBS file ID.
|
* Determines the instrument from its NBS file ID.
|
||||||
* @param ID The instrument ID (0-9).
|
* @param ID The instrument ID (0-15).
|
||||||
* @return The corresponding instrument.
|
* @return The corresponding instrument.
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
*/
|
*/
|
||||||
public static Instrument fromID(int ID) throws IllegalArgumentException {
|
public static Instrument fromID(int ID) throws IllegalArgumentException {
|
||||||
switch (ID) {
|
switch (ID) {
|
||||||
case 0: return HARP;
|
case 0: return HARP;
|
||||||
case 1: return BASS;
|
case 1: return BASS;
|
||||||
case 2: return DRUM;
|
case 2: return DRUM;
|
||||||
case 3: return SNARE;
|
case 3: return SNARE;
|
||||||
case 4: return CLICK;
|
case 4: return CLICK;
|
||||||
case 5: return GUITAR;
|
case 5: return GUITAR;
|
||||||
case 6: return FLUTE;
|
case 6: return FLUTE;
|
||||||
case 7: return BELL;
|
case 7: return BELL;
|
||||||
case 8: return CHIME;
|
case 8: return CHIME;
|
||||||
case 9: return XYLOPHONE;
|
case 9: return XYLOPHONE;
|
||||||
default: throw new IllegalArgumentException("ID must be from 1 to 9.");
|
case 10: return IRON_XYLOPHONE;
|
||||||
|
case 11: return COW_BELL;
|
||||||
|
case 12: return DIDGERIDOO;
|
||||||
|
case 13: return BIT;
|
||||||
|
case 14: return BANJO;
|
||||||
|
case 15: return PLING;
|
||||||
|
default: return CUSTOM;//throw new IllegalArgumentException("ID must be from 0 to 15.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,17 +8,29 @@ package me.ayunami2000.ayuncraft.nbsapi;
|
||||||
public class Note {
|
public class Note {
|
||||||
private Instrument instrument;
|
private Instrument instrument;
|
||||||
private byte pitch;
|
private byte pitch;
|
||||||
|
private byte velocity;
|
||||||
|
private int panning;
|
||||||
|
private short precisePitch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A note in a song.
|
* A note in a song.
|
||||||
* @param instrument The instrument of the note.
|
* @param instrument The instrument of the note.
|
||||||
* @param pitch The pitch of the note (0-87).
|
* @param pitch The pitch of the note (0-87).
|
||||||
|
* @param velocity The velocity of the note (0-100).
|
||||||
|
* @param panning The panning of the note (0-100).
|
||||||
|
* @param precisePitch The precise pitch of the note (-32767-32767).
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
*/
|
*/
|
||||||
public Note(Instrument instrument, byte pitch) throws IllegalArgumentException {
|
public Note(Instrument instrument, byte pitch, byte velocity, int panning, short precisePitch) throws IllegalArgumentException {
|
||||||
if (pitch < 0 || pitch > 87) throw new IllegalArgumentException("Pitch must be from 0 to 87.");
|
if (pitch < 0 || pitch > 87) throw new IllegalArgumentException("Pitch must be from 0 to 87.");
|
||||||
|
if (velocity < 0 || velocity > 100) throw new IllegalArgumentException("Velocity must be from 0 to 100.");
|
||||||
|
if (panning < 0 || panning > 200) throw new IllegalArgumentException("Panning must be from 0 to 100.");
|
||||||
|
if (precisePitch < -32767 || precisePitch > 32767) throw new IllegalArgumentException("Precise pitch must be from -32767 to 32767.");
|
||||||
setInstrument(instrument);
|
setInstrument(instrument);
|
||||||
setPitch(pitch);
|
setPitch(pitch);
|
||||||
|
setVelocity(velocity);
|
||||||
|
setPanning(panning);
|
||||||
|
setPrecisePitch(precisePitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instrument getInstrument() {
|
public Instrument getInstrument() {
|
||||||
|
@ -37,4 +49,31 @@ public class Note {
|
||||||
if (pitch < 0 || pitch > 87) throw new IllegalArgumentException("Pitch must be from 0 to 87.");
|
if (pitch < 0 || pitch > 87) throw new IllegalArgumentException("Pitch must be from 0 to 87.");
|
||||||
this.pitch = pitch;
|
this.pitch = pitch;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public byte getVelocity() {
|
||||||
|
return velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVelocity(byte velocity) throws IllegalArgumentException {
|
||||||
|
if (velocity < 0 || velocity > 100) throw new IllegalArgumentException("Velocity must be from 0 to 100.");
|
||||||
|
this.velocity = velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPanning() {
|
||||||
|
return panning;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPanning(int panning) throws IllegalArgumentException {
|
||||||
|
if (panning < 0 || panning > 200) throw new IllegalArgumentException("Panning must be from 0 to 100.");
|
||||||
|
this.panning = panning;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getPrecisePitch() {
|
||||||
|
return precisePitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrecisePitch(short precisePitch) throws IllegalArgumentException {
|
||||||
|
if (precisePitch < -32767 || precisePitch > 32767) throw new IllegalArgumentException("Precise pitch must be from -32767 to 32767.");
|
||||||
|
this.precisePitch = precisePitch;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
package me.ayunami2000.ayuncraft.nbsapi;
|
package me.ayunami2000.ayuncraft.nbsapi;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
|
@ -26,12 +28,13 @@ public class Song {
|
||||||
private int blocksRemoved;
|
private int blocksRemoved;
|
||||||
private String MidiSchematicFile;
|
private String MidiSchematicFile;
|
||||||
private List<Layer> songBoard;
|
private List<Layer> songBoard;
|
||||||
|
private boolean isONBS=false;
|
||||||
|
|
||||||
private ByteArrayInputStream instream;
|
private ByteArrayInputStream instream;
|
||||||
private DataInputStream in;
|
private DataInputStream in;
|
||||||
private FileOutputStream outstream;
|
private FileOutputStream outstream;
|
||||||
private DataOutputStream out;
|
private DataOutputStream out;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a new song with the given information.
|
* Builds a new song with the given information.
|
||||||
* @param length
|
* @param length
|
||||||
|
@ -49,6 +52,7 @@ public class Song {
|
||||||
* @param blocksAdded
|
* @param blocksAdded
|
||||||
* @param blocksRemoved
|
* @param blocksRemoved
|
||||||
* @param MidiSchematicFile
|
* @param MidiSchematicFile
|
||||||
|
* @param isONBS
|
||||||
* @param songBoard
|
* @param songBoard
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
*/
|
*/
|
||||||
|
@ -68,6 +72,7 @@ public class Song {
|
||||||
int blocksAdded,
|
int blocksAdded,
|
||||||
int blocksRemoved,
|
int blocksRemoved,
|
||||||
String MidiSchematicFile,
|
String MidiSchematicFile,
|
||||||
|
boolean isONBS,
|
||||||
List<Layer> songBoard) throws IllegalArgumentException {
|
List<Layer> songBoard) throws IllegalArgumentException {
|
||||||
setLength(length);
|
setLength(length);
|
||||||
setName(name);
|
setName(name);
|
||||||
|
@ -84,17 +89,24 @@ public class Song {
|
||||||
setBlocksRemoved(blocksRemoved);
|
setBlocksRemoved(blocksRemoved);
|
||||||
setMidiSchematicFile(MidiSchematicFile);
|
setMidiSchematicFile(MidiSchematicFile);
|
||||||
changeSongBoardTo(songBoard);
|
changeSongBoardTo(songBoard);
|
||||||
|
setIsONBS(isONBS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a song from a byte array.
|
* Reads a song from a file.
|
||||||
* @param fromBytes The byte array that should be read.
|
* @param fromBytes The file that should be read.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public Song(byte[] fromBytes) throws IOException {
|
public Song(byte[] fromBytes) throws IOException {
|
||||||
instream = new ByteArrayInputStream(fromBytes);
|
instream = new ByteArrayInputStream(fromBytes);
|
||||||
in = new DataInputStream(instream);
|
in = new DataInputStream(instream);
|
||||||
setLength(readShort());
|
setLength(readShort());
|
||||||
|
setIsONBS(length==0);
|
||||||
|
if(isONBS){
|
||||||
|
byte onbsVersion=in.readByte();
|
||||||
|
byte vanillaInstrumentCount=in.readByte();
|
||||||
|
setLength(readShort());
|
||||||
|
}
|
||||||
setHeight(readShort());
|
setHeight(readShort());
|
||||||
setName(readString());
|
setName(readString());
|
||||||
setAuthor(readString());
|
setAuthor(readString());
|
||||||
|
@ -110,7 +122,12 @@ public class Song {
|
||||||
setBlocksAdded(readInt());
|
setBlocksAdded(readInt());
|
||||||
setBlocksRemoved(readInt());
|
setBlocksRemoved(readInt());
|
||||||
setMidiSchematicFile(readString());
|
setMidiSchematicFile(readString());
|
||||||
|
if(isONBS){
|
||||||
|
byte loop=in.readByte();
|
||||||
|
byte maxLoopCount=in.readByte();
|
||||||
|
short loopStartTick=readShort();
|
||||||
|
}
|
||||||
|
|
||||||
songBoard = new ArrayList<Layer>();
|
songBoard = new ArrayList<Layer>();
|
||||||
for (int i = 0; i < height; i++) songBoard.add(new Layer("",(byte) 100));
|
for (int i = 0; i < height; i++) songBoard.add(new Layer("",(byte) 100));
|
||||||
int tick = -1;
|
int tick = -1;
|
||||||
|
@ -126,17 +143,23 @@ public class Song {
|
||||||
while (songBoard.size() < layer+1) {
|
while (songBoard.size() < layer+1) {
|
||||||
songBoard.add(new Layer("",(byte) 100));
|
songBoard.add(new Layer("",(byte) 100));
|
||||||
}
|
}
|
||||||
songBoard.get(layer).setNote(tick, new Note(Instrument.fromID(in.readByte()), in.readByte()));
|
songBoard.get(layer).setNote(tick, new Note(Instrument.fromID(in.readByte()), in.readByte(), isONBS ? in.readByte() : 100, isONBS ? (in.readByte() & 0xFF) : 100, isONBS ? ByteBuffer.allocate(8).order(ByteOrder.BIG_ENDIAN).putShort(in.readShort()).order(ByteOrder.LITTLE_ENDIAN).getShort(0) : 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < getHeight(); i++) {
|
for (int i = 0; i < getHeight(); i++) {
|
||||||
songBoard.get(i).setName(readString());
|
songBoard.get(i).setName(readString());
|
||||||
songBoard.get(i).setVolume(in.readByte());
|
if(isONBS){
|
||||||
|
byte lock=in.readByte();
|
||||||
|
songBoard.get(i).setVolume(in.readByte());
|
||||||
|
byte stereo=in.readByte();
|
||||||
|
}else{
|
||||||
|
songBoard.get(i).setVolume(in.readByte());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
in.close();
|
in.close();
|
||||||
instream.close();
|
instream.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the song to the specific file.
|
* Writes the song to the specific file.
|
||||||
* @param toFile The file to write to.
|
* @param toFile The file to write to.
|
||||||
|
@ -153,7 +176,7 @@ public class Song {
|
||||||
}
|
}
|
||||||
setLength((short) Math.max(1, maxLength));
|
setLength((short) Math.max(1, maxLength));
|
||||||
setHeight((short) songBoard.size());
|
setHeight((short) songBoard.size());
|
||||||
|
|
||||||
outstream = new FileOutputStream(toFile);
|
outstream = new FileOutputStream(toFile);
|
||||||
out = new DataOutputStream(outstream);
|
out = new DataOutputStream(outstream);
|
||||||
writeShort(length);
|
writeShort(length);
|
||||||
|
@ -172,7 +195,7 @@ public class Song {
|
||||||
writeInt(blocksAdded);
|
writeInt(blocksAdded);
|
||||||
writeInt(blocksRemoved);
|
writeInt(blocksRemoved);
|
||||||
writeString(MidiSchematicFile);
|
writeString(MidiSchematicFile);
|
||||||
|
|
||||||
List<WritableNote> noteList = Utils.convertToWritable(songBoard);
|
List<WritableNote> noteList = Utils.convertToWritable(songBoard);
|
||||||
int oldTick = -1;
|
int oldTick = -1;
|
||||||
int oldLayer = -1;
|
int oldLayer = -1;
|
||||||
|
@ -190,17 +213,17 @@ public class Song {
|
||||||
}
|
}
|
||||||
writeShort((short)0);
|
writeShort((short)0);
|
||||||
writeShort((short)0);
|
writeShort((short)0);
|
||||||
|
|
||||||
for (Layer l : songBoard) {
|
for (Layer l : songBoard) {
|
||||||
writeString(l.getName());
|
writeString(l.getName());
|
||||||
out.writeByte(l.getVolume());
|
out.writeByte(l.getVolume());
|
||||||
}
|
}
|
||||||
|
|
||||||
out.writeByte(0);
|
out.writeByte(0);
|
||||||
out.close();
|
out.close();
|
||||||
outstream.close();
|
outstream.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getLength() {
|
public short getLength() {
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
@ -244,7 +267,8 @@ public class Song {
|
||||||
}
|
}
|
||||||
public void setTempo(short tempo) throws IllegalArgumentException {
|
public void setTempo(short tempo) throws IllegalArgumentException {
|
||||||
if (tempo < 25) throw new IllegalArgumentException("Tempo is too small!");
|
if (tempo < 25) throw new IllegalArgumentException("Tempo is too small!");
|
||||||
if (tempo%25 != 0) throw new IllegalArgumentException("Tempo must be a multiplication of 25.");
|
//if (tempo%25 != 0) throw new IllegalArgumentException("Tempo must be a multiplication of 25.");
|
||||||
|
if (tempo%25 != 0) tempo = (short) (25*(tempo/25));
|
||||||
this.tempo = tempo;
|
this.tempo = tempo;
|
||||||
}
|
}
|
||||||
public boolean isAutoSaveEnabled() {
|
public boolean isAutoSaveEnabled() {
|
||||||
|
@ -308,6 +332,12 @@ public class Song {
|
||||||
public void setMidiSchematicFile(String midiSchematicFile) {
|
public void setMidiSchematicFile(String midiSchematicFile) {
|
||||||
MidiSchematicFile = midiSchematicFile;
|
MidiSchematicFile = midiSchematicFile;
|
||||||
}
|
}
|
||||||
|
public void setIsONBS(boolean bool){
|
||||||
|
this.isONBS=bool;
|
||||||
|
}
|
||||||
|
public boolean getIsONBS(){
|
||||||
|
return isONBS;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Layer> getSongBoard() {
|
public List<Layer> getSongBoard() {
|
||||||
return songBoard;
|
return songBoard;
|
||||||
|
@ -316,52 +346,52 @@ public class Song {
|
||||||
public void changeSongBoardTo(List<Layer> songBoard) {
|
public void changeSongBoardTo(List<Layer> songBoard) {
|
||||||
this.songBoard = songBoard;
|
this.songBoard = songBoard;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The code below is imported from xxmicloxx's NoteBlockAPI (LGPL 3.0).
|
// The code below is imported from xxmicloxx's NoteBlockAPI (LGPL 3.0).
|
||||||
|
|
||||||
private short readShort() throws IOException {
|
private short readShort() throws IOException {
|
||||||
int byte1 = in.readUnsignedByte();
|
int byte1 = in.readUnsignedByte();
|
||||||
int byte2 = in.readUnsignedByte();
|
int byte2 = in.readUnsignedByte();
|
||||||
return (short) (byte1 + (byte2 << 8));
|
return (short) (byte1 + (byte2 << 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readInt() throws IOException {
|
private int readInt() throws IOException {
|
||||||
int byte1 = in.readUnsignedByte();
|
int byte1 = in.readUnsignedByte();
|
||||||
int byte2 = in.readUnsignedByte();
|
int byte2 = in.readUnsignedByte();
|
||||||
int byte3 = in.readUnsignedByte();
|
int byte3 = in.readUnsignedByte();
|
||||||
int byte4 = in.readUnsignedByte();
|
int byte4 = in.readUnsignedByte();
|
||||||
return (byte1 + (byte2 << 8) + (byte3 << 16) + (byte4 << 24));
|
return (byte1 + (byte2 << 8) + (byte3 << 16) + (byte4 << 24));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String readString() throws IOException {
|
private String readString() throws IOException {
|
||||||
int length = readInt();
|
int length = readInt();
|
||||||
StringBuilder sb = new StringBuilder(length);
|
StringBuilder sb = new StringBuilder(length);
|
||||||
for (; length > 0; --length) {
|
for (; length > 0; --length) {
|
||||||
char c = (char) in.readByte();
|
char c = (char) in.readByte();
|
||||||
if (c == (char) 0x0D) {
|
if (c == (char) 0x0D) {
|
||||||
c = ' ';
|
c = ' ';
|
||||||
}
|
}
|
||||||
sb.append(c);
|
sb.append(c);
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// End of inported code.
|
// End of inported code.
|
||||||
|
|
||||||
private void writeShort(short num) throws IOException {
|
private void writeShort(short num) throws IOException {
|
||||||
out.writeByte(num%256);
|
out.writeByte(num%256);
|
||||||
out.writeByte(num/256);
|
out.writeByte(num/256);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeInt(int num) throws IOException {
|
private void writeInt(int num) throws IOException {
|
||||||
out.writeByte(num%256);
|
out.writeByte(num%256);
|
||||||
out.writeByte(num%65536/256);
|
out.writeByte(num%65536/256);
|
||||||
out.writeByte(num%16777216/65536);
|
out.writeByte(num%16777216/65536);
|
||||||
out.writeByte(num/16777216);
|
out.writeByte(num/16777216);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeString(String str) throws IOException {
|
private void writeString(String str) throws IOException {
|
||||||
writeInt(str.length());
|
writeInt(str.length());
|
||||||
out.writeBytes(str);
|
out.writeBytes(str);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -37,12 +37,7 @@ public class Utils {
|
||||||
thisTick.add(new WritableNote(n.getInstrument(), n.getPitch(), currentLayer, i));
|
thisTick.add(new WritableNote(n.getInstrument(), n.getPitch(), currentLayer, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(thisTick, new Comparator<WritableNote>() {
|
Collections.sort(thisTick, Comparator.comparing(WritableNote::getLayer));
|
||||||
@Override
|
|
||||||
public int compare(WritableNote note1, WritableNote note2) {
|
|
||||||
return Integer.compare(note1.getLayer(), note2.getLayer());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
result.addAll(thisTick);
|
result.addAll(thisTick);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user