Note block player

This commit is contained in:
Shaun Bennett 2015-12-06 21:12:10 -05:00
parent cbafb2ba91
commit 488895ea53
7 changed files with 412 additions and 1 deletions

View File

@ -0,0 +1,131 @@
package mineplex.core.noteblock;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
/**
* Information about the NBS Format was taken from
* http://www.stuffbydavid.com/mcnbs/format
*/
public class NBSReader
{
public static NoteSong loadSong(String fileName) throws FileNotFoundException
{
return loadSong(new DataInputStream(new FileInputStream(new File(fileName))));
}
public static NoteSong loadSong(DataInputStream stream)
{
try
{
// Header Information
short length = readShort(stream);
short height = readShort(stream);
String name = readString(stream);
String author = readString(stream);
String originalAuthor = readString(stream);
String description = readString(stream);
short tempo = readShort(stream); // Tempo multiplied by 1000
boolean autosave = stream.readBoolean();
byte autosaveDuration = stream.readByte();
byte timeSignature = stream.readByte();
int minutesSpent = readInt(stream);
int leftClicks = readInt(stream);
int rightClicks = readInt(stream);
int blocksAdded = readInt(stream);
int blocksRemoved = readInt(stream);
String midiFileName = readString(stream);
HashMap<Integer, NoteLayer> layerMap = new HashMap<Integer, NoteLayer>();
// Note Block Information
int tick = -1;
int jumps = 0;
while (true)
{
jumps = readShort(stream);
if (jumps == 0)
break;
tick += jumps;
int layer = -1;
while (true)
{
jumps = readShort(stream);
if (jumps == 0)
break;
layer += jumps;
byte instrument = stream.readByte();
byte key = stream.readByte();
Note note = new Note(instrument, key);
NoteLayer noteLayer = layerMap.get(layer);
if (noteLayer == null)
{
noteLayer = new NoteLayer();
layerMap.put(layer, noteLayer);
}
noteLayer.setNote(tick, note);
}
}
// Layer Information
for (int i = 0; i < height; i++)
{
NoteLayer layer = layerMap.get(i);
if (layer != null)
{
layer.setName(readString(stream));
layer.setVolume(stream.readByte());
}
}
System.out.println("[NBSReader] Successfully loaded song " + name + "");
System.out.println("Tempo: " + tempo);
return new NoteSong(length, height, name, tempo, timeSignature, layerMap);
}
catch (IOException e)
{
e.printStackTrace();
}
return null;
}
private static int readInt(DataInputStream stream) throws IOException
{
// For some reason the bytes are in reverse order from stream.readInt()
int ch1 = stream.read();
int ch2 = stream.read();
int ch3 = stream.read();
int ch4 = stream.read();
if ((ch1 | ch2 | ch3 | ch4) < 0)
throw new EOFException();
return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + ch1);
}
private static short readShort(DataInputStream stream) throws IOException
{
// For some reason the bytes are in reverse order from stream.readShort()
int ch1 = stream.read();
int ch2 = stream.read();
if ((ch1 | ch2) < 0)
throw new EOFException();
return (short)((ch2 << 8) + ch1);
}
private static String readString(DataInputStream stream) throws IOException
{
int length = readInt(stream);
char[] string = new char[length];
for (int i = 0; i < length; i++)
{
string[i] = (char) stream.readByte();
}
return new String(string);
}
}

View File

@ -0,0 +1,26 @@
package mineplex.core.noteblock;
/**
* Represents a single note to be played
*/
public class Note
{
private byte _instrument;
private byte _note;
public Note(byte instrument, byte note)
{
_instrument = instrument;
_note = note;
}
public byte getInstrument()
{
return _instrument;
}
public byte getNote()
{
return _note;
}
}

View File

@ -0,0 +1,50 @@
package mineplex.core.noteblock;
import java.util.HashMap;
/**
* Represents a layer of notes in Note Block Studio
*/
public class NoteLayer
{
private HashMap<Integer, Note> _noteMap; // Notes indexed by ticks
private int _volume; // Volume as a percentage 1-100
private String _name;
public NoteLayer()
{
_noteMap = new HashMap<Integer, Note>();
_volume = 100;
_name = "";
}
public int getVolume()
{
return _volume;
}
public void setVolume(int volume)
{
_volume = volume;
}
public String getName()
{
return _name;
}
public void setName(String name)
{
_name = name;
}
public void setNote(int ticks, Note note)
{
_noteMap.put(ticks, note);
}
public Note getNote(int ticks)
{
return _noteMap.get(ticks);
}
}

View File

@ -0,0 +1,88 @@
package mineplex.core.noteblock;
import org.bukkit.entity.Player;
import mineplex.core.common.util.UtilServer;
public class NotePlayer
{
private final NoteSong _song;
private final long _sleepMs;
private volatile boolean _loop;
private volatile int _tick;
private volatile boolean _finished;
public NotePlayer(NoteSong song, boolean loop)
{
_song = song;
_sleepMs = (long) (1000 / (song.getTempo() / 100D));
_loop = loop;
_tick = 0;
_finished = false;
startThread();
}
private void startThread()
{
Thread thread = new Thread(new Runnable()
{
@Override
public void run()
{
long startTime = System.currentTimeMillis();
while (!_finished)
{
_tick++;
if (_tick > _song.getLength())
{
if (_loop)
{
_tick = 1;
}
else
{
_finished = true;
return;
}
}
playTick(_tick);
try
{
Thread.sleep(_sleepMs);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
});
thread.start();
}
private void playTick(int tick)
{
for (NoteLayer layer : _song.getLayers())
{
Note note = layer.getNote(tick);
if (note != null)
{
float volume = layer.getVolume() / 100F;
for (Player player : UtilServer.getPlayers())
{
player.playSound(player.getEyeLocation(), UtilNote.getInstrumentSound(note.getInstrument()), volume, (float) UtilNote.getPitch(note.getNote() - 33));
}
}
}
}
public void cancel()
{
_finished = true;
}
}

View File

@ -0,0 +1,57 @@
package mineplex.core.noteblock;
import java.util.Collection;
import java.util.HashMap;
public class NoteSong
{
// Song Data
private short _length;
private short _height;
private String _name;
private short _tempo;
private byte _timeSignature;
// Layer Data
private HashMap<Integer, NoteLayer> _layerMap;
public NoteSong(short length, short height, String name, short tempo, byte timeSignature, HashMap<Integer, NoteLayer> layerMap)
{
_length = length;
_height = height;
_name = name;
_tempo = tempo;
_timeSignature = timeSignature;
_layerMap = layerMap;
}
public short getLength()
{
return _length;
}
public short getHeight()
{
return _height;
}
public String getName()
{
return _name;
}
public short getTempo()
{
return _tempo;
}
public byte getTimeSignature()
{
return _timeSignature;
}
public Collection<NoteLayer> getLayers()
{
return _layerMap.values();
}
}

View File

@ -0,0 +1,42 @@
package mineplex.core.noteblock;
import org.bukkit.Sound;
/**
* See http://minecraft.gamepedia.com/Note_Block for information about pitches
*/
public class UtilNote
{
private static final double[] PITCH = { 0.5, 0.53, 0.56, 0.6, 0.63, 0.67, 0.7, 0.76, 0.8, 0.84, 0.9, 0.94, 1.0,
1.06, 1.12, 1.18, 1.26, 1.34, 1.42, 1.5, 1.6, 1.68, 1.78, 1.88, 2.0 };
public static Sound getInstrumentSound(byte instrument)
{
switch (instrument)
{
case 0:
return Sound.NOTE_PIANO;
case 1:
return Sound.NOTE_BASS_GUITAR;
case 2:
return Sound.NOTE_BASS_DRUM;
case 3:
return Sound.NOTE_SNARE_DRUM;
case 4:
return Sound.NOTE_STICKS;
default:
return Sound.NOTE_PIANO;
}
}
public static double getPitch(int note)
{
if (note >= 0 && note < PITCH.length)
{
return PITCH[note];
}
return 0.0;
}
}

View File

@ -1,5 +1,6 @@
package mineplex.hub; package mineplex.hub;
import java.io.FileNotFoundException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -34,6 +35,9 @@ import mineplex.core.hologram.HologramManager;
import mineplex.core.inventory.InventoryManager; import mineplex.core.inventory.InventoryManager;
import mineplex.core.message.PrivateMessageEvent; import mineplex.core.message.PrivateMessageEvent;
import mineplex.core.mount.MountManager; import mineplex.core.mount.MountManager;
import mineplex.core.noteblock.NBSReader;
import mineplex.core.noteblock.NotePlayer;
import mineplex.core.noteblock.NoteSong;
import mineplex.core.notifier.NotificationManager; import mineplex.core.notifier.NotificationManager;
import mineplex.core.npc.NpcManager; import mineplex.core.npc.NpcManager;
import mineplex.core.packethandler.PacketHandler; import mineplex.core.packethandler.PacketHandler;
@ -219,7 +223,6 @@ public class HubManager extends MiniClientPlugin<HubClient>
((CraftWorld)Bukkit.getWorlds().get(0)).getHandle().pvpMode = true; ((CraftWorld)Bukkit.getWorlds().get(0)).getHandle().pvpMode = true;
new BonusManager(plugin, clientManager, serverStatusManager, donationManager, pollManager , npcManager, hologramManager, statsManager, _inventoryManager, petManager, giveawayManager); new BonusManager(plugin, clientManager, serverStatusManager, donationManager, pollManager , npcManager, hologramManager, statsManager, _inventoryManager, petManager, giveawayManager);
// _halloweenManager = new HalloweenSpookinessManager(this); // _halloweenManager = new HalloweenSpookinessManager(this);
@ -229,6 +232,20 @@ public class HubManager extends MiniClientPlugin<HubClient>
_serverName = getPlugin().getConfig().getString("serverstatus.name"); _serverName = getPlugin().getConfig().getString("serverstatus.name");
_serverName = _serverName.substring(0, Math.min(16, _serverName.length())); _serverName = _serverName.substring(0, Math.min(16, _serverName.length()));
// try
// {
// NoteSong song = NBSReader.loadSong("songs/LetItGo.nbs");
// if (song != null)
// {
// NotePlayer player = new NotePlayer(song, true);
// }
// }
// catch (FileNotFoundException e)
// {
// e.printStackTrace();
// System.out.println("FAILED TO LOAD SONG!!");
// }
} }
@Override @Override