├── .gitignore ├── LICENSE ├── README.md ├── _config.yml ├── pom.xml └── src └── main ├── java └── com │ └── xxmicloxx │ └── NoteBlockAPI │ ├── FadeType.java │ ├── Instrument.java │ ├── Interpolator.java │ ├── Layer.java │ ├── NBSDecoder.java │ ├── Note.java │ ├── NoteBlockPlayerMain.java │ ├── NoteBlockSongPlayer.java │ ├── NotePitch.java │ ├── PositionSongPlayer.java │ ├── RadioSongPlayer.java │ ├── Song.java │ ├── SongDestroyingEvent.java │ ├── SongEndEvent.java │ ├── SongPlayer.java │ └── SongStoppedEvent.java └── resources └── plugin.yml /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## General 3 | ################# 4 | 5 | .classpath 6 | .project 7 | .settings/ 8 | target/ 9 | /target 10 | .gitattributes 11 | *.iml 12 | *.idea 13 | *.ida 14 | /idea 15 | idea/ 16 | /ida 17 | ida/ 18 | dependency-reduced-pom.xml 19 | 20 | ################# 21 | ## Eclipse 22 | ################# 23 | 24 | *.pydevproject 25 | .project 26 | .metadata 27 | bin/ 28 | tmp/ 29 | *.tmp 30 | *.bak 31 | *.swp 32 | *~.nib 33 | local.properties 34 | .classpath 35 | .settings/ 36 | .loadpath 37 | 38 | # External tool builders 39 | .externalToolBuilders/ 40 | 41 | # Locally stored "Eclipse launch configurations" 42 | *.launch 43 | 44 | # CDT-specific 45 | .cproject 46 | 47 | # PDT-specific 48 | .buildpath 49 | 50 | 51 | ################# 52 | ## Visual Studio 53 | ################# 54 | 55 | ## Ignore Visual Studio temporary files, build results, and 56 | ## files generated by popular Visual Studio add-ons. 57 | 58 | # User-specific files 59 | *.suo 60 | *.user 61 | *.sln.docstates 62 | 63 | # Build results 64 | 65 | [Dd]ebug/ 66 | [Rr]elease/ 67 | x64/ 68 | build/ 69 | [Bb]in/ 70 | [Oo]bj/ 71 | 72 | # MSTest test Results 73 | [Tt]est[Rr]esult*/ 74 | [Bb]uild[Ll]og.* 75 | 76 | *_i.c 77 | *_p.c 78 | *.ilk 79 | *.meta 80 | *.obj 81 | *.pch 82 | *.pdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *.log 93 | *.vspscc 94 | *.vssscc 95 | .builds 96 | *.pidb 97 | *.log 98 | *.scc 99 | 100 | # Visual C++ cache files 101 | ipch/ 102 | *.aps 103 | *.ncb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | 108 | # Visual Studio profiler 109 | *.psess 110 | *.vsp 111 | *.vspx 112 | 113 | # Guidance Automation Toolkit 114 | *.gpState 115 | 116 | # ReSharper is a .NET coding add-in 117 | _ReSharper*/ 118 | *.[Rr]e[Ss]harper 119 | 120 | # TeamCity is a build add-in 121 | _TeamCity* 122 | 123 | # DotCover is a Code Coverage Tool 124 | *.dotCover 125 | 126 | # NCrunch 127 | *.ncrunch* 128 | .*crunch*.local.xml 129 | 130 | # Installshield output folder 131 | [Ee]xpress/ 132 | 133 | # DocProject is a documentation generator add-in 134 | DocProject/buildhelp/ 135 | DocProject/Help/*.HxT 136 | DocProject/Help/*.HxC 137 | DocProject/Help/*.hhc 138 | DocProject/Help/*.hhk 139 | DocProject/Help/*.hhp 140 | DocProject/Help/Html2 141 | DocProject/Help/html 142 | 143 | # Click-Once directory 144 | publish/ 145 | 146 | # Publish Web Output 147 | *.Publish.xml 148 | *.pubxml 149 | 150 | # NuGet Packages Directory 151 | #packages/ 152 | 153 | # Windows Azure Build Output 154 | csx 155 | *.build.csdef 156 | 157 | # Windows Store app package directory 158 | AppPackages/ 159 | 160 | # Others 161 | sql/ 162 | *.Cache 163 | ClientBin/ 164 | [Ss]tyle[Cc]op.* 165 | ~$* 166 | *~ 167 | *.dbmdl 168 | *.[Pp]ublish.xml 169 | *.pfx 170 | *.publishsettings 171 | 172 | # RIA/Silverlight projects 173 | Generated_Code/ 174 | 175 | # Backup & report files from converting an old project file to a newer 176 | # Visual Studio version. Backup files are not needed, because we have git ;-) 177 | _UpgradeReport_Files/ 178 | Backup*/ 179 | UpgradeLog*.XML 180 | UpgradeLog*.htm 181 | 182 | # SQL Server files 183 | App_Data/*.mdf 184 | App_Data/*.ldf 185 | 186 | ############# 187 | ## Windows detritus 188 | ############# 189 | 190 | # Windows image file caches 191 | Thumbs.db 192 | ehthumbs.db 193 | 194 | # Folder config file 195 | Desktop.ini 196 | 197 | # Recycle Bin used on file shares 198 | $RECYCLE.BIN/ 199 | 200 | # Mac crap 201 | .DS_Store 202 | 203 | 204 | ############# 205 | ## Python 206 | ############# 207 | 208 | *.py[co] 209 | 210 | # Packages 211 | *.egg 212 | *.egg-info 213 | dist/ 214 | build/ 215 | eggs/ 216 | parts/ 217 | var/ 218 | sdist/ 219 | develop-eggs/ 220 | .installed.cfg 221 | 222 | # Installer logs 223 | pip-log.txt 224 | 225 | # Unit test / coverage reports 226 | .coverage 227 | .tox 228 | 229 | #Translations 230 | *.mo 231 | 232 | #Mr Developer 233 | .mr.developer.cfg 234 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | NoteBlockAPI 2 | ============ 3 | 4 | See http://dev.bukkit.org/bukkit-plugins/noteblockapi/ for more info about NoteBlockAPI 5 | 6 | See "LICENSE" for license :) 7 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.xxmicloxx 8 | NoteBlockAPI 9 | 1.9.0 10 | 11 | 12 | spigot-repo 13 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/ 14 | 15 | 16 | 17 | 18 | org.bukkit 19 | bukkit 20 | 1.12-R0.1-SNAPSHOT 21 | provided 22 | 23 | 24 | 25 | 26 | sinndev-repo 27 | Releases 28 | http://repo.sinndev.com/content/repositories/releases/ 29 | 30 | 31 | sinndev-repo 32 | Snapshots 33 | http://repo.sinndev.com/content/repositories/snapshots/ 34 | 35 | 36 | 37 | 38 | 39 | org.apache.maven.plugins 40 | maven-compiler-plugin 41 | 3.1 42 | 43 | 1.7 44 | 1.7 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/FadeType.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | public enum FadeType { 4 | FADE_LINEAR 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/Instrument.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | import org.bukkit.Sound; 4 | 5 | public class Instrument { 6 | 7 | public static Sound getInstrument(byte instrument) { 8 | switch (instrument) { 9 | case 0: 10 | return Sound.BLOCK_NOTE_HARP; 11 | case 1: 12 | return Sound.BLOCK_NOTE_BASS; 13 | case 2: 14 | return Sound.BLOCK_NOTE_BASEDRUM; 15 | case 3: 16 | return Sound.BLOCK_NOTE_SNARE; 17 | case 4: 18 | return Sound.BLOCK_NOTE_HAT; 19 | case 5: 20 | return Sound.BLOCK_NOTE_GUITAR; 21 | case 6: 22 | return Sound.BLOCK_NOTE_FLUTE; 23 | case 7: 24 | return Sound.BLOCK_NOTE_BELL; 25 | case 8: 26 | return Sound.BLOCK_NOTE_CHIME; 27 | case 9: 28 | return Sound.BLOCK_NOTE_XYLOPHONE; 29 | default: 30 | return Sound.BLOCK_NOTE_HARP; 31 | } 32 | } 33 | 34 | public static org.bukkit.Instrument getBukkitInstrument(byte instrument) { 35 | switch (instrument) { 36 | case 0: 37 | return org.bukkit.Instrument.PIANO; 38 | case 1: 39 | return org.bukkit.Instrument.BASS_GUITAR; 40 | case 2: 41 | return org.bukkit.Instrument.BASS_DRUM; 42 | case 3: 43 | return org.bukkit.Instrument.SNARE_DRUM; 44 | case 4: 45 | return org.bukkit.Instrument.STICKS; 46 | case 5: 47 | return org.bukkit.Instrument.GUITAR; 48 | case 6: 49 | return org.bukkit.Instrument.FLUTE; 50 | case 7: 51 | return org.bukkit.Instrument.BELL; 52 | case 8: 53 | return org.bukkit.Instrument.CHIME; 54 | case 9: 55 | return org.bukkit.Instrument.XYLOPHONE; 56 | default: 57 | return org.bukkit.Instrument.PIANO; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/Interpolator.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | *

Static methods for doing useful math


7 | * 8 | * @author : $Author: brian $ 9 | * @version : $Revision: 1.1 $ 10 | *

11 | *


12 | * The Monterey Bay Aquarium Research Institute (MBARI) provides this 13 | * documentation and code "as is", with no warranty, express or 14 | * implied, of its quality or consistency. It is provided without support and 15 | * without obligation on the part of MBARI to assist in its use, correction, 16 | * modification, or enhancement. This information should not be published or 17 | * distributed to third parties without specific written permission from 18 | * MBARI.


19 | *

20 | * Copyright 2002 MBARI.
21 | * MBARI Proprietary Information. All rights reserved.



22 | */ 23 | public class Interpolator { 24 | 25 | public static double[] interpLinear(double[] x, double[] y, double[] xi) throws IllegalArgumentException { 26 | 27 | if (x.length != y.length) { 28 | throw new IllegalArgumentException("X and Y must be the same length"); 29 | } 30 | if (x.length == 1) { 31 | throw new IllegalArgumentException("X must contain more than one value"); 32 | } 33 | double[] dx = new double[x.length - 1]; 34 | double[] dy = new double[x.length - 1]; 35 | double[] slope = new double[x.length - 1]; 36 | double[] intercept = new double[x.length - 1]; 37 | 38 | // Calculate the line equation (i.e. slope and intercept) between each point 39 | for (int i = 0; i < x.length - 1; i++) { 40 | dx[i] = x[i + 1] - x[i]; 41 | if (dx[i] == 0) { 42 | throw new IllegalArgumentException("X must be montotonic. A duplicate " + "x-value was found"); 43 | } 44 | if (dx[i] < 0) { 45 | throw new IllegalArgumentException("X must be sorted"); 46 | } 47 | dy[i] = y[i + 1] - y[i]; 48 | slope[i] = dy[i] / dx[i]; 49 | intercept[i] = y[i] - x[i] * slope[i]; 50 | } 51 | 52 | // Perform the interpolation here 53 | double[] yi = new double[xi.length]; 54 | for (int i = 0; i < xi.length; i++) { 55 | if ((xi[i] > x[x.length - 1]) || (xi[i] < x[0])) { 56 | yi[i] = Double.NaN; 57 | } else { 58 | int loc = Arrays.binarySearch(x, xi[i]); 59 | if (loc < -1) { 60 | loc = -loc - 2; 61 | yi[i] = slope[loc] * xi[i] + intercept[loc]; 62 | } else { 63 | yi[i] = y[loc]; 64 | } 65 | } 66 | } 67 | 68 | return yi; 69 | } 70 | 71 | public static double[] interpLinear(long[] x, double[] y, long[] xi) throws IllegalArgumentException { 72 | 73 | double[] xd = new double[x.length]; 74 | for (int i = 0; i < x.length; i++) { 75 | xd[i] = (double) x[i]; 76 | } 77 | 78 | double[] xid = new double[xi.length]; 79 | for (int i = 0; i < xi.length; i++) { 80 | xid[i] = (double) xi[i]; 81 | } 82 | 83 | return interpLinear(xd, y, xid); 84 | } 85 | 86 | public static double interpLinear(double[] xy, double xx) { 87 | if (xy.length % 2 != 0) { 88 | throw new IllegalArgumentException("XY must be divisible by two."); 89 | } 90 | double[] x = new double[xy.length/2]; 91 | double[] y = new double[x.length]; 92 | for (int i = 0; i < xy.length; i++) { 93 | if (i % 2 == 0) { 94 | x[i/2] = xy[i]; 95 | } else { 96 | y[i/2] = xy[i]; 97 | } 98 | } 99 | return interpLinear(x, y, new double[] {xx})[0]; 100 | } 101 | } -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/Layer.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | import java.util.HashMap; 4 | 5 | public class Layer { 6 | 7 | private HashMap hashMap = new HashMap(); 8 | private byte volume = 100; 9 | private String name = ""; 10 | 11 | public HashMap getHashMap() { 12 | return hashMap; 13 | } 14 | 15 | public void setHashMap(HashMap hashMap) { 16 | this.hashMap = hashMap; 17 | } 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public void setName(String name) { 24 | this.name = name; 25 | } 26 | 27 | public Note getNote(int tick) { 28 | return hashMap.get(tick); 29 | } 30 | 31 | public void setNote(int tick, Note note) { 32 | hashMap.put(tick, note); 33 | } 34 | 35 | public byte getVolume() { 36 | return volume; 37 | } 38 | 39 | public void setVolume(byte volume) { 40 | this.volume = volume; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/NBSDecoder.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | import java.io.*; 4 | import java.util.HashMap; 5 | 6 | public class NBSDecoder { 7 | 8 | public static Song parse(File decodeFile) { 9 | try { 10 | return parse(new FileInputStream(decodeFile), decodeFile); 11 | } catch (FileNotFoundException e) { 12 | e.printStackTrace(); 13 | } 14 | return null; 15 | } 16 | 17 | public static Song parse(InputStream inputStream) { 18 | return parse(inputStream, null); // Source is unknown -> no file 19 | } 20 | 21 | private static Song parse(InputStream inputStream, File decodeFile) { 22 | HashMap layerHashMap = new HashMap(); 23 | try { 24 | DataInputStream dis = new DataInputStream(inputStream); 25 | short length = readShort(dis); 26 | short songHeight = readShort(dis); 27 | String title = readString(dis); 28 | String author = readString(dis); 29 | readString(dis); 30 | String description = readString(dis); 31 | float speed = readShort(dis) / 100f; 32 | dis.readBoolean(); // auto-save 33 | dis.readByte(); // auto-save duration 34 | dis.readByte(); // x/4ths, time signature 35 | readInt(dis); // minutes spent on project 36 | readInt(dis); // left clicks (why?) 37 | readInt(dis); // right clicks (why?) 38 | readInt(dis); // blocks added 39 | readInt(dis); // blocks removed 40 | readString(dis); // .mid/.schematic file name 41 | short tick = -1; 42 | while (true) { 43 | short jumpTicks = readShort(dis); // jumps till next tick 44 | //System.out.println("Jumps to next tick: " + jumpTicks); 45 | if (jumpTicks == 0) { 46 | break; 47 | } 48 | tick += jumpTicks; 49 | //System.out.println("Tick: " + tick); 50 | short layer = -1; 51 | while (true) { 52 | short jumpLayers = readShort(dis); // jumps till next layer 53 | if (jumpLayers == 0) { 54 | break; 55 | } 56 | layer += jumpLayers; 57 | //System.out.println("Layer: " + layer); 58 | setNote(layer, tick, dis.readByte() /* instrument */, dis.readByte() /* note */, layerHashMap); 59 | } 60 | } 61 | for (int i = 0; i < songHeight; i++) { 62 | Layer l = layerHashMap.get(i); 63 | if (l != null) { 64 | l.setName(readString(dis)); 65 | l.setVolume(dis.readByte()); 66 | } 67 | } 68 | return new Song(speed, layerHashMap, songHeight, length, title, author, description, decodeFile); 69 | } catch (FileNotFoundException e) { 70 | e.printStackTrace(); 71 | } catch (IOException e) { 72 | e.printStackTrace(); 73 | } 74 | return null; 75 | } 76 | 77 | private static void setNote(int layer, int ticks, byte instrument, byte key, HashMap layerHashMap) { 78 | Layer l = layerHashMap.get(layer); 79 | if (l == null) { 80 | l = new Layer(); 81 | layerHashMap.put(layer, l); 82 | } 83 | l.setNote(ticks, new Note(instrument, key)); 84 | } 85 | 86 | private static short readShort(DataInputStream dis) throws IOException { 87 | int byte1 = dis.readUnsignedByte(); 88 | int byte2 = dis.readUnsignedByte(); 89 | return (short) (byte1 + (byte2 << 8)); 90 | } 91 | 92 | private static int readInt(DataInputStream dis) throws IOException { 93 | int byte1 = dis.readUnsignedByte(); 94 | int byte2 = dis.readUnsignedByte(); 95 | int byte3 = dis.readUnsignedByte(); 96 | int byte4 = dis.readUnsignedByte(); 97 | return (byte1 + (byte2 << 8) + (byte3 << 16) + (byte4 << 24)); 98 | } 99 | 100 | private static String readString(DataInputStream dis) throws IOException { 101 | int length = readInt(dis); 102 | StringBuilder sb = new StringBuilder(length); 103 | for (; length > 0; --length) { 104 | char c = (char) dis.readByte(); 105 | if (c == (char) 0x0D) { 106 | c = ' '; 107 | } 108 | sb.append(c); 109 | } 110 | return sb.toString(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/Note.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | public class Note { 4 | 5 | private byte instrument; 6 | private byte key; 7 | 8 | public Note(byte instrument, byte key) { 9 | this.instrument = instrument; 10 | this.key = key; 11 | } 12 | 13 | public byte getInstrument() { 14 | return instrument; 15 | } 16 | 17 | public void setInstrument(byte instrument) { 18 | this.instrument = instrument; 19 | } 20 | 21 | public byte getKey() { 22 | return key; 23 | } 24 | 25 | public void setKey(byte key) { 26 | this.key = key; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/NoteBlockPlayerMain.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.plugin.java.JavaPlugin; 6 | 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | 10 | public class NoteBlockPlayerMain extends JavaPlugin { 11 | 12 | public static NoteBlockPlayerMain plugin; 13 | public HashMap> playingSongs = new HashMap>(); 14 | public HashMap playerVolume = new HashMap(); 15 | 16 | public static boolean isReceivingSong(Player p) { 17 | return ((plugin.playingSongs.get(p.getName()) != null) && (!plugin.playingSongs.get(p.getName()).isEmpty())); 18 | } 19 | 20 | public static void stopPlaying(Player p) { 21 | if (plugin.playingSongs.get(p.getName()) == null) { 22 | return; 23 | } 24 | for (SongPlayer s : plugin.playingSongs.get(p.getName())) { 25 | s.removePlayer(p); 26 | } 27 | } 28 | 29 | public static void setPlayerVolume(Player p, byte volume) { 30 | plugin.playerVolume.put(p.getName(), volume); 31 | } 32 | 33 | public static byte getPlayerVolume(Player p) { 34 | Byte b = plugin.playerVolume.get(p.getName()); 35 | if (b == null) { 36 | b = 100; 37 | plugin.playerVolume.put(p.getName(), b); 38 | } 39 | return b; 40 | } 41 | 42 | @Override 43 | public void onEnable() { 44 | plugin = this; 45 | } 46 | 47 | @Override 48 | public void onDisable() { 49 | Bukkit.getScheduler().cancelTasks(this); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/NoteBlockSongPlayer.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | import org.bukkit.Material; 4 | import org.bukkit.block.Block; 5 | import org.bukkit.entity.Player; 6 | 7 | /** 8 | * Created with IntelliJ IDEA. 9 | * User: ml 10 | * Date: 07.12.13 11 | * Time: 12:56 12 | */ 13 | public class NoteBlockSongPlayer extends SongPlayer { 14 | private Block noteBlock; 15 | 16 | public NoteBlockSongPlayer(Song song) { 17 | super(song); 18 | } 19 | 20 | public Block getNoteBlock() { 21 | return noteBlock; 22 | } 23 | 24 | public void setNoteBlock(Block noteBlock) { 25 | this.noteBlock = noteBlock; 26 | } 27 | 28 | @Override 29 | public void playTick(Player p, int tick) { 30 | if (noteBlock.getType() != Material.NOTE_BLOCK) { 31 | return; 32 | } 33 | if (!p.getWorld().getName().equals(noteBlock.getWorld().getName())) { 34 | // not in same world 35 | return; 36 | } 37 | byte playerVolume = NoteBlockPlayerMain.getPlayerVolume(p); 38 | 39 | for (Layer l : song.getLayerHashMap().values()) { 40 | Note note = l.getNote(tick); 41 | if (note == null) { 42 | continue; 43 | } 44 | p.playNote(noteBlock.getLocation(), Instrument.getBukkitInstrument(note.getInstrument()), 45 | new org.bukkit.Note(note.getKey() - 33)); 46 | p.playSound(noteBlock.getLocation(), 47 | Instrument.getInstrument(note.getInstrument()), 48 | (l.getVolume() * (int) volume * (int) playerVolume) / 1000000f, 49 | NotePitch.getPitch(note.getKey() - 33)); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/NotePitch.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | public enum NotePitch { 4 | 5 | NOTE_0(0, 0.5F), 6 | NOTE_1(1, 0.53F), 7 | NOTE_2(2, 0.56F), 8 | NOTE_3(3, 0.6F), 9 | NOTE_4(4, 0.63F), 10 | NOTE_5(5, 0.67F), 11 | NOTE_6(6, 0.7F), 12 | NOTE_7(7, 0.76F), 13 | NOTE_8(8, 0.8F), 14 | NOTE_9(9, 0.84F), 15 | NOTE_10(10, 0.9F), 16 | NOTE_11(11, 0.94F), 17 | NOTE_12(12, 1.0F), 18 | NOTE_13(13, 1.06F), 19 | NOTE_14(14, 1.12F), 20 | NOTE_15(15, 1.18F), 21 | NOTE_16(16, 1.26F), 22 | NOTE_17(17, 1.34F), 23 | NOTE_18(18, 1.42F), 24 | NOTE_19(19, 1.5F), 25 | NOTE_20(20, 1.6F), 26 | NOTE_21(21, 1.68F), 27 | NOTE_22(22, 1.78F), 28 | NOTE_23(23, 1.88F), 29 | NOTE_24(24, 2.0F); 30 | 31 | public int note; 32 | public float pitch; 33 | 34 | private NotePitch(int note, float pitch) { 35 | this.note = note; 36 | this.pitch = pitch; 37 | } 38 | 39 | public static float getPitch(int note) { 40 | for (NotePitch notePitch : values()) { 41 | if (notePitch.note == note) { 42 | return notePitch.pitch; 43 | } 44 | } 45 | 46 | return 0.0F; 47 | } 48 | } -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/PositionSongPlayer.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.entity.Player; 5 | 6 | public class PositionSongPlayer extends SongPlayer { 7 | 8 | private Location targetLocation; 9 | 10 | public PositionSongPlayer(Song song) { 11 | super(song); 12 | } 13 | 14 | public Location getTargetLocation() { 15 | return targetLocation; 16 | } 17 | 18 | public void setTargetLocation(Location targetLocation) { 19 | this.targetLocation = targetLocation; 20 | } 21 | 22 | @Override 23 | public void playTick(Player p, int tick) { 24 | if (!p.getWorld().getName().equals(targetLocation.getWorld().getName())) { 25 | // not in same world 26 | return; 27 | } 28 | byte playerVolume = NoteBlockPlayerMain.getPlayerVolume(p); 29 | 30 | for (Layer l : song.getLayerHashMap().values()) { 31 | Note note = l.getNote(tick); 32 | if (note == null) { 33 | continue; 34 | } 35 | p.playSound(targetLocation, 36 | Instrument.getInstrument(note.getInstrument()), 37 | (l.getVolume() * (int) volume * (int) playerVolume) / 1000000f, 38 | NotePitch.getPitch(note.getKey() - 33)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/RadioSongPlayer.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | public class RadioSongPlayer extends SongPlayer { 6 | 7 | public RadioSongPlayer(Song song) { 8 | super(song); 9 | } 10 | 11 | @Override 12 | public void playTick(Player p, int tick) { 13 | byte playerVolume = NoteBlockPlayerMain.getPlayerVolume(p); 14 | 15 | for (Layer l : song.getLayerHashMap().values()) { 16 | Note note = l.getNote(tick); 17 | if (note == null) { 18 | continue; 19 | } 20 | p.playSound(p.getEyeLocation(), 21 | Instrument.getInstrument(note.getInstrument()), 22 | (l.getVolume() * (int) volume * (int) playerVolume) / 1000000f, 23 | NotePitch.getPitch(note.getKey() - 33)); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/Song.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | import java.io.File; 4 | import java.util.HashMap; 5 | 6 | public class Song { 7 | 8 | private HashMap layerHashMap = new HashMap(); 9 | private short songHeight; 10 | private short length; 11 | private String title; 12 | private File path; 13 | private String author; 14 | private String description; 15 | private float speed; 16 | private float delay; 17 | 18 | public Song(Song other) { 19 | this.speed = other.getSpeed(); 20 | delay = 20 / speed; 21 | this.layerHashMap = other.getLayerHashMap(); 22 | this.songHeight = other.getSongHeight(); 23 | this.length = other.getLength(); 24 | this.title = other.getTitle(); 25 | this.author = other.getAuthor(); 26 | this.description = other.getDescription(); 27 | this.path = other.getPath(); 28 | } 29 | 30 | public Song(float speed, HashMap layerHashMap, 31 | short songHeight, final short length, String title, String author, 32 | String description, File path) { 33 | this.speed = speed; 34 | delay = 20 / speed; 35 | this.layerHashMap = layerHashMap; 36 | this.songHeight = songHeight; 37 | this.length = length; 38 | this.title = title; 39 | this.author = author; 40 | this.description = description; 41 | this.path = path; 42 | } 43 | 44 | public HashMap getLayerHashMap() { 45 | return layerHashMap; 46 | } 47 | 48 | public short getSongHeight() { 49 | return songHeight; 50 | } 51 | 52 | public short getLength() { 53 | return length; 54 | } 55 | 56 | public String getTitle() { 57 | return title; 58 | } 59 | 60 | public String getAuthor() { 61 | return author; 62 | } 63 | 64 | public File getPath() { 65 | return path; 66 | } 67 | 68 | public String getDescription() { 69 | return description; 70 | } 71 | 72 | public float getSpeed() { 73 | return speed; 74 | } 75 | 76 | public float getDelay() { 77 | return delay; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/SongDestroyingEvent.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | import org.bukkit.event.Cancellable; 4 | import org.bukkit.event.Event; 5 | import org.bukkit.event.HandlerList; 6 | 7 | public class SongDestroyingEvent extends Event implements Cancellable { 8 | 9 | private static final HandlerList handlers = new HandlerList(); 10 | private SongPlayer song; 11 | private boolean cancelled = false; 12 | 13 | public SongDestroyingEvent(SongPlayer song) { 14 | this.song = song; 15 | } 16 | 17 | public static HandlerList getHandlerList() { 18 | return handlers; 19 | } 20 | 21 | public SongPlayer getSongPlayer() { 22 | return song; 23 | } 24 | 25 | public HandlerList getHandlers() { 26 | return handlers; 27 | } 28 | 29 | @Override 30 | public boolean isCancelled() { 31 | return cancelled; 32 | } 33 | 34 | @Override 35 | public void setCancelled(boolean arg0) { 36 | cancelled = arg0; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/SongEndEvent.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | import org.bukkit.event.Event; 4 | import org.bukkit.event.HandlerList; 5 | 6 | public class SongEndEvent extends Event { 7 | 8 | private static final HandlerList handlers = new HandlerList(); 9 | private SongPlayer song; 10 | 11 | public SongEndEvent(SongPlayer song) { 12 | this.song = song; 13 | } 14 | 15 | public static HandlerList getHandlerList() { 16 | return handlers; 17 | } 18 | 19 | public SongPlayer getSongPlayer() { 20 | return song; 21 | } 22 | 23 | public HandlerList getHandlers() { 24 | return handlers; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/SongPlayer.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.entity.Player; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collections; 8 | import java.util.List; 9 | 10 | public abstract class SongPlayer { 11 | 12 | protected Song song; 13 | protected boolean playing = false; 14 | protected short tick = -1; 15 | protected ArrayList playerList = new ArrayList(); 16 | protected boolean loop; 17 | protected boolean autoDestroy = false; 18 | protected boolean destroyed = false; 19 | protected Thread playerThread; 20 | protected byte fadeTarget = 100; 21 | protected byte volume = 100; 22 | protected byte fadeStart = volume; 23 | protected int fadeDuration = 60; 24 | protected int fadeDone = 0; 25 | protected FadeType fadeType = FadeType.FADE_LINEAR; 26 | 27 | public SongPlayer(Song song) { 28 | this.song = song; 29 | createThread(); 30 | } 31 | 32 | public FadeType getFadeType() { 33 | return fadeType; 34 | } 35 | 36 | public void setFadeType(FadeType fadeType) { 37 | this.fadeType = fadeType; 38 | } 39 | 40 | public byte getFadeTarget() { 41 | return fadeTarget; 42 | } 43 | 44 | public void setFadeTarget(byte fadeTarget) { 45 | this.fadeTarget = fadeTarget; 46 | } 47 | 48 | public byte getFadeStart() { 49 | return fadeStart; 50 | } 51 | 52 | public void setFadeStart(byte fadeStart) { 53 | this.fadeStart = fadeStart; 54 | } 55 | 56 | public int getFadeDuration() { 57 | return fadeDuration; 58 | } 59 | 60 | public void setFadeDuration(int fadeDuration) { 61 | this.fadeDuration = fadeDuration; 62 | } 63 | 64 | public int getFadeDone() { 65 | return fadeDone; 66 | } 67 | 68 | public void setFadeDone(int fadeDone) { 69 | this.fadeDone = fadeDone; 70 | } 71 | 72 | protected void calculateFade() { 73 | if (fadeDone == fadeDuration) { 74 | return; // no fade today 75 | } 76 | double targetVolume = Interpolator.interpLinear(new double[]{0, fadeStart, fadeDuration, fadeTarget}, fadeDone); 77 | setVolume((byte) targetVolume); 78 | fadeDone++; 79 | } 80 | 81 | protected void createThread() { 82 | playerThread = new Thread(new Runnable() { 83 | @Override 84 | public void run() { 85 | while (!destroyed) { 86 | long startTime = System.currentTimeMillis(); 87 | synchronized (SongPlayer.this) { 88 | if (playing) { 89 | calculateFade(); 90 | tick++; 91 | if (tick > song.getLength()) { 92 | if(loop){ 93 | tick = 0; 94 | continue; 95 | } 96 | playing = false; 97 | tick = -1; 98 | SongEndEvent event = new SongEndEvent(SongPlayer.this); 99 | Bukkit.getPluginManager().callEvent(event); 100 | if (autoDestroy) { 101 | destroy(); 102 | return; 103 | } 104 | } 105 | for (String s : playerList) { 106 | Player p = Bukkit.getPlayerExact(s); 107 | if (p == null) { 108 | // offline... 109 | continue; 110 | } 111 | playTick(p, tick); 112 | } 113 | } 114 | } 115 | long duration = System.currentTimeMillis() - startTime; 116 | float delayMillis = song.getDelay() * 50; 117 | if (duration < delayMillis) { 118 | try { 119 | Thread.sleep((long) (delayMillis - duration)); 120 | } catch (InterruptedException e) { 121 | // do nothing 122 | } 123 | } 124 | } 125 | } 126 | }); 127 | playerThread.setPriority(Thread.MAX_PRIORITY); 128 | playerThread.start(); 129 | } 130 | 131 | public List getPlayerList() { 132 | return Collections.unmodifiableList(playerList); 133 | } 134 | 135 | public void addPlayer(Player p) { 136 | synchronized (this) { 137 | if (!playerList.contains(p.getName())) { 138 | playerList.add(p.getName()); 139 | ArrayList songs = NoteBlockPlayerMain.plugin.playingSongs 140 | .get(p.getName()); 141 | if (songs == null) { 142 | songs = new ArrayList(); 143 | } 144 | songs.add(this); 145 | NoteBlockPlayerMain.plugin.playingSongs.put(p.getName(), songs); 146 | } 147 | } 148 | } 149 | public void setLoop(boolean loop) { 150 | synchronized (this) 151 | { 152 | this.loop = loop; 153 | } 154 | } 155 | 156 | public boolean isLoop() { 157 | synchronized (this) 158 | { 159 | return this.loop; 160 | } 161 | } 162 | public boolean getAutoDestroy() { 163 | synchronized (this) { 164 | return autoDestroy; 165 | } 166 | } 167 | 168 | public void setAutoDestroy(boolean value) { 169 | synchronized (this) { 170 | autoDestroy = value; 171 | } 172 | } 173 | 174 | public abstract void playTick(Player p, int tick); 175 | 176 | public void destroy() { 177 | synchronized (this) { 178 | SongDestroyingEvent event = new SongDestroyingEvent(this); 179 | Bukkit.getPluginManager().callEvent(event); 180 | //Bukkit.getScheduler().cancelTask(threadId); 181 | if (event.isCancelled()) { 182 | return; 183 | } 184 | destroyed = true; 185 | playing = false; 186 | setTick((short) -1); 187 | } 188 | } 189 | 190 | public boolean isPlaying() { 191 | return playing; 192 | } 193 | 194 | public void setPlaying(boolean playing) { 195 | this.playing = playing; 196 | if (!playing) { 197 | SongStoppedEvent event = new SongStoppedEvent(this); 198 | Bukkit.getPluginManager().callEvent(event); 199 | } 200 | } 201 | 202 | public short getTick() { 203 | return tick; 204 | } 205 | 206 | public void setTick(short tick) { 207 | this.tick = tick; 208 | } 209 | 210 | public void removePlayer(Player p) { 211 | synchronized (this) { 212 | playerList.remove(p.getName()); 213 | if (NoteBlockPlayerMain.plugin.playingSongs.get(p.getName()) == null) { 214 | return; 215 | } 216 | ArrayList songs = new ArrayList( 217 | NoteBlockPlayerMain.plugin.playingSongs.get(p.getName())); 218 | songs.remove(this); 219 | NoteBlockPlayerMain.plugin.playingSongs.put(p.getName(), songs); 220 | if (playerList.isEmpty() && autoDestroy) { 221 | SongEndEvent event = new SongEndEvent(this); 222 | Bukkit.getPluginManager().callEvent(event); 223 | destroy(); 224 | } 225 | } 226 | } 227 | 228 | public byte getVolume() { 229 | return volume; 230 | } 231 | 232 | public void setVolume(byte volume) { 233 | this.volume = volume; 234 | } 235 | 236 | public Song getSong() { 237 | return song; 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /src/main/java/com/xxmicloxx/NoteBlockAPI/SongStoppedEvent.java: -------------------------------------------------------------------------------- 1 | package com.xxmicloxx.NoteBlockAPI; 2 | 3 | import org.bukkit.event.Event; 4 | import org.bukkit.event.HandlerList; 5 | 6 | public class SongStoppedEvent extends Event { 7 | 8 | private static final HandlerList handlers = new HandlerList(); 9 | private SongPlayer song; 10 | 11 | public SongStoppedEvent(SongPlayer song) { 12 | this.song = song; 13 | } 14 | 15 | public static HandlerList getHandlerList() { 16 | return handlers; 17 | } 18 | 19 | public SongPlayer getSongPlayer() { 20 | return song; 21 | } 22 | 23 | public HandlerList getHandlers() { 24 | return handlers; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: NoteBlockAPI 2 | 3 | main: com.xxmicloxx.NoteBlockAPI.NoteBlockPlayerMain 4 | version: 1.9.0 5 | 6 | description: a developer interface to play nbs-files ingame 7 | authors: [xxmicloxx, michidk] --------------------------------------------------------------------------------