diff --git a/src/main/java/dev/adventurecraft/awakening/common/AC_GuiMusicSheet.java b/src/main/java/dev/adventurecraft/awakening/common/AC_GuiMusicSheet.java index 306a4f21..fecea367 100644 --- a/src/main/java/dev/adventurecraft/awakening/common/AC_GuiMusicSheet.java +++ b/src/main/java/dev/adventurecraft/awakening/common/AC_GuiMusicSheet.java @@ -1,5 +1,7 @@ package dev.adventurecraft.awakening.common; +import dev.adventurecraft.awakening.common.instruments.IInstrumentConfig; +import dev.adventurecraft.awakening.common.instruments.Note; import dev.adventurecraft.awakening.extension.client.gui.screen.ExScreen; import dev.adventurecraft.awakening.extension.world.ExWorld; import it.unimi.dsi.fastutil.ints.IntArrayList; @@ -10,27 +12,32 @@ public class AC_GuiMusicSheet extends Screen { - private String instrument; - private IntArrayList notesPlayed; + private final IInstrumentConfig instrument; + private final IntArrayList notesPlayed; private String notesPlayedString; private int spaceTaken; private AC_MusicScriptEntry songPlayed; private long timeToFade; - public AC_GuiMusicSheet(String instrument) { + public AC_GuiMusicSheet(IInstrumentConfig instrument) { this.instrument = instrument; this.notesPlayed = new IntArrayList(); this.notesPlayedString = ""; this.songPlayed = null; } - @Override - public void tick() { - } - - @Override - public void initVanillaScreen() { - } + public static final Note[] keyboardNotes = { + new Note('D', -1), // Keyboard 1 + new Note('E', -1), + new Note('F', -1), + new Note('G', -1), + new Note('A', 0), + new Note('B', 0), + new Note('C', 0), + new Note('D', 0), + new Note('E', 0), + new Note('F', 0), // Keyboard 0 + }; @Override protected void keyPressed(char character, int key) { @@ -65,7 +72,6 @@ protected void keyPressed(char character, int key) { int totalSpaceTaken = this.spaceTaken + NOTE_SIZE; - if (totalSpaceTaken >= MAX_NOTE_SPACE) { this.notesPlayed.clear(); this.notesPlayedString = ""; @@ -75,36 +81,17 @@ protected void keyPressed(char character, int key) { this.spaceTaken += NOTE_SIZE; this.notesPlayed.add(key); - if (key == Keyboard.KEY_1) { - MusicPlayer.playNoteFromEntity(this.client.world, this.client.player, this.instrument, 'D', shiftDown, 0.5F, 1.0F); - this.notesPlayedString = this.notesPlayedString + "1"; - } else if (key == Keyboard.KEY_2) { - MusicPlayer.playNoteFromEntity(this.client.world, this.client.player, this.instrument, 'E', false, 0.5F, 1.0F); - this.notesPlayedString = this.notesPlayedString + "2"; - } else if (key == Keyboard.KEY_3) { - MusicPlayer.playNoteFromEntity(this.client.world, this.client.player, this.instrument, 'F', shiftDown, 0.5F, 1.0F); - this.notesPlayedString = this.notesPlayedString + "3"; - } else if (key == Keyboard.KEY_4) { - MusicPlayer.playNoteFromEntity(this.client.world, this.client.player, this.instrument, 'G', shiftDown, 0.5F, 1.0F); - this.notesPlayedString = this.notesPlayedString + "4"; - } else if (key == Keyboard.KEY_5) { - MusicPlayer.playNoteFromEntity(this.client.world, this.client.player, this.instrument, 'A', shiftDown, 1.0F, 1.0F); - this.notesPlayedString = this.notesPlayedString + "5"; - } else if (key == Keyboard.KEY_6) { - MusicPlayer.playNoteFromEntity(this.client.world, this.client.player, this.instrument, 'B', false, 1.0F, 1.0F); - this.notesPlayedString = this.notesPlayedString + "6"; - } else if (key == Keyboard.KEY_7) { - MusicPlayer.playNoteFromEntity(this.client.world, this.client.player, this.instrument, 'C', shiftDown, 1.0F, 1.0F); - this.notesPlayedString = this.notesPlayedString + "7"; - } else if (key == Keyboard.KEY_8) { - MusicPlayer.playNoteFromEntity(this.client.world, this.client.player, this.instrument, 'D', shiftDown, 1.0F, 1.0F); - this.notesPlayedString = this.notesPlayedString + "8"; - } else if (key == Keyboard.KEY_9) { - MusicPlayer.playNoteFromEntity(this.client.world, this.client.player, this.instrument, 'E', false, 1.0F, 1.0F); - this.notesPlayedString = this.notesPlayedString + "9"; - } else if (key == Keyboard.KEY_0) { - MusicPlayer.playNoteFromEntity(this.client.world, this.client.player, this.instrument, 'F', shiftDown, 1.0F, 1.0F); - this.notesPlayedString = this.notesPlayedString + "0"; + Note noteToPlay = keyboardNotes[key - Keyboard.KEY_1]; + this.notesPlayedString += Keyboard.getKeyName(key); + + + if (noteToPlay != null) { + int totalShiftValue = this.instrument.getTuning(); + if (noteIsSharp) + totalShiftValue += 1; + noteToPlay = noteToPlay.withShiftedValue(totalShiftValue); + + MusicPlayer.playNoteFromEntity(this.client.player, this.instrument, noteToPlay, 1F); } AC_MusicScriptEntry entry = ((ExWorld) this.client.world).getMusicScripts().executeMusic(this.notesPlayedString); @@ -173,8 +160,8 @@ private void drawSharp(int x, int note) { this.blit((this.width - 205) / 2 + 36 + x, this.height - 59 - 2 - 48 + 46 - (note - 2) * 4 - 5, 16, 64, 12, 17); } - public static void showUI(String var0) { - Minecraft.instance.openScreen(new AC_GuiMusicSheet(var0)); + public static void showUI(IInstrumentConfig instrumentConfig) { + Minecraft.instance.openScreen(new AC_GuiMusicSheet(instrumentConfig)); } @Override diff --git a/src/main/java/dev/adventurecraft/awakening/common/AC_ItemInstrument.java b/src/main/java/dev/adventurecraft/awakening/common/AC_ItemInstrument.java index 3c4549d9..5f2193c3 100644 --- a/src/main/java/dev/adventurecraft/awakening/common/AC_ItemInstrument.java +++ b/src/main/java/dev/adventurecraft/awakening/common/AC_ItemInstrument.java @@ -1,6 +1,8 @@ package dev.adventurecraft.awakening.common; -import dev.adventurecraft.awakening.extension.entity.block.ExSignBlockEntity; +import dev.adventurecraft.awakening.common.instruments.IInstrumentConfig; +import dev.adventurecraft.awakening.common.instruments.SimpleInstrumentConfig; +import dev.adventurecraft.awakening.extension.entity.block.ExSongContainer; import net.minecraft.block.Block; import net.minecraft.entity.block.SignBlockEntity; import net.minecraft.entity.player.PlayerEntity; @@ -10,26 +12,60 @@ public class AC_ItemInstrument extends Item { - String instrument; - protected AC_ItemInstrument(int var1, String var2) { - super(var1); - this.instrument = var2; + /** + * The sound's URI. + * To play, for example, resources/newsound/note/harp.ogg, the instrument would be "note.harp". + */ + IInstrumentConfig instrument; + + /** + * Creates a new instrument item. + * + * @param itemId The ID of the item. + * @param instrumentUri The instrument's sound URI. Default tuning is +3 + */ + protected AC_ItemInstrument(int itemId, String instrumentUri) { + super(itemId); + this.instrument = new SimpleInstrumentConfig(instrumentUri); + } + + /** + * Creates a new instrument item. + * + * @param itemId The ID of the item. + * @param instrumentUri The instrument's sound URI. + * @param noteOffset The offset of the instrument to be tuned to match with the pentagram + */ + protected AC_ItemInstrument(int itemId, String instrumentUri, int noteOffset) { + super(itemId); + this.instrument = new SimpleInstrumentConfig(instrumentUri, noteOffset); + } + + /** + * Creates a new instrument item. + * + * @param itemId The ID of the item. + * @param instrumentConfig The instrument config that the instrument will use + */ + protected AC_ItemInstrument(int itemId, IInstrumentConfig instrumentConfig) { + super(itemId); + this.instrument = instrumentConfig; } @Override - public boolean useOnBlock(ItemStack var1, PlayerEntity var2, World world, int targetBlockX, int targetBlockY, int targetBlockZ, int var7) { - if (world.getBlockId(targetBlockX, targetBlockY, targetBlockZ) == Block.STANDING_SIGN.id) { - var targetSign = (SignBlockEntity) world.getBlockEntity(targetBlockX, targetBlockY, targetBlockZ); - ((ExSignBlockEntity) targetSign).playSong(this.instrument); + public boolean useOnBlock(ItemStack stack, PlayerEntity player, World world, int x, int y, int z, int side) { + if (world.getBlockId(x, y, z) == Block.STANDING_SIGN.id) { + var targetSign = (SignBlockEntity) world.getBlockEntity(x, y, z); + ((ExSongContainer) targetSign).playSong(this.instrument); } return false; } @Override - public ItemStack use(ItemStack var1, World var2, PlayerEntity var3) { + public ItemStack use(ItemStack stack, World world, PlayerEntity player) { AC_GuiMusicSheet.showUI(this.instrument); - return var1; + return stack; } } diff --git a/src/main/java/dev/adventurecraft/awakening/common/MusicPlayer.java b/src/main/java/dev/adventurecraft/awakening/common/MusicPlayer.java index 67c4dcf2..3a53a40f 100644 --- a/src/main/java/dev/adventurecraft/awakening/common/MusicPlayer.java +++ b/src/main/java/dev/adventurecraft/awakening/common/MusicPlayer.java @@ -1,143 +1,38 @@ package dev.adventurecraft.awakening.common; +import dev.adventurecraft.awakening.common.instruments.IInstrumentConfig; +import dev.adventurecraft.awakening.common.instruments.Note; import net.minecraft.entity.Entity; import net.minecraft.world.World; public class MusicPlayer { - /** - * @param world The world in which the note will be played - * @param sourceEntity The entity from which the location will be taken to play the note - * @param instrumentString The instrument name from which the sound will be taken - * @param noteChar The note character from A to G - * @param isSharp Whether the note should be played half a step higher - * @param basePitchModifier How much should the pitch be altered for the given note - * @param volume The volume of this note + * @param world The world where the sound will be played + * @param x The X position in said world + * @param y The Y position in said world + * @param z The Z position in said world + * @param instrumentConfig The instrument to be used to play the note + * @param note The note to be played + * @param volume The volume that the note will be played at */ - public static void playNoteFromEntity(World world, Entity sourceEntity, String instrumentString, char noteChar, boolean isSharp, float basePitchModifier, float volume) { - playNote(world, sourceEntity.x, sourceEntity.y, sourceEntity.z, instrumentString, noteChar, isSharp, basePitchModifier, volume); + public static void playNote(World world, double x, double y, double z, IInstrumentConfig instrumentConfig, Note note, float volume) { + playNote(world, x, y, z, instrumentConfig.getSoundString(note), instrumentConfig.getPitchModifier() * note.getPitch(), instrumentConfig.getVolumeModifier() * volume); } /** - * @param targetWorld The world in which the note will be played - * @param worldXPos The X position of the sound - * @param worldYPos The Y position of the sound - * @param worldZPos The Z position of the sound - * @param instrumentString The instrument name from which the sound will be taken - * @param noteChar The note character from A to G - * @param isSharp Whether the note should be played half a step higher - * @param basePitchModifier How much should the pitch be altered for the given note - * @param volume The volume of this note + * @param world The world where the sound will be played + * @param x The X position in said world + * @param y The Y position in said world + * @param z The Z position in said world + * @param soundURI The instrument to be used on playing the note + * @param pitchMod The note to be played + * @param volume The volume that the note will be played at */ - public static void playNote(World targetWorld, double worldXPos, double worldYPos, double worldZPos, String instrumentString, char noteChar, boolean isSharp, float basePitchModifier, float volume) { - float noteFrequency = 1.189207F; // Mod to F# to be A - switch (noteChar) { // Mod to A to be whatever note was played - case 'A': - break; - case 'B': - noteFrequency *= 1.122462F; - break; - case 'C': - noteFrequency *= 1.189207F; - break; - case 'D': - noteFrequency *= 1.33484F; - break; - case 'E': - noteFrequency *= 1.498307F; - break; - case 'F': - noteFrequency *= 1.587401F; - break; - case 'G': - noteFrequency *= 1.781797F; - break; - default: - return; - } - - if (isSharp) { - noteFrequency = (float) ((double) noteFrequency * 1.059463D); // Mod to the note that was played to give it half a step upwards - } - - targetWorld.playSound(worldXPos, worldYPos, worldZPos, instrumentString, volume, noteFrequency * basePitchModifier); - } - - /** - * @param targetWorld The world where the note will be played - * @param worldXPos The x position in the world where the note will be played - * @param worldYPos The y position in the world where the note will be played - * @param worldZPos The z position in the world where the note will be played - * @param instrumentString The instrument that will be played - * @param songString The string that contains the song - * @param noteIndex The note to be played - * @param volume The volume in which the song will be played - */ - public static void playNoteFromSong(World targetWorld, double worldXPos, double worldYPos, double worldZPos, String instrumentString, String songString, int noteIndex, float volume) { - int stringIterationIndex = 0; // Current index on the string iteration - int noteIterationIndex = 0; // Current note of the song - boolean isFlat = false; - boolean isSharp = false; - char noteToPlay = 'A'; - - float basePitchModifier; - char iterationChar; - - // Count the octave changes before up to the current note - for (basePitchModifier = 1.0F; noteIterationIndex <= noteIndex && stringIterationIndex < songString.length(); ++stringIterationIndex) { - iterationChar = songString.charAt(stringIterationIndex); - if (iterationChar == '+') { // Increase the octave of the note - basePitchModifier *= 2.0F; - } else if (iterationChar == '-') { // Lower the octave of the note - basePitchModifier *= 0.5F; - } else if (iterationChar != '#' && iterationChar != 'b') { // Ignore sharps and flats - noteToPlay = iterationChar; // Set this as the current note - ++noteIterationIndex; - } - } - - - // Check the next character for a sharp or a flat (if it can exist) - if (stringIterationIndex < songString.length()) { - iterationChar = songString.charAt(stringIterationIndex); - if (iterationChar == '#') { - isSharp = true; - } else if (iterationChar == 'b') { - isFlat = true; - } - } - - // Translate all flats to sharps instead, by reducing its char value (or rolling over if it's A, the lowest ASCII). - if (isFlat) { - if (noteToPlay == 'A') { - basePitchModifier *= 0.5F; - noteToPlay = 'G'; - } else { - --noteToPlay; - } - - isSharp = true; - } - - // Finally play that note - playNote(targetWorld, worldXPos, worldYPos, worldZPos, instrumentString, noteToPlay, isSharp, basePitchModifier, volume); + public static void playNote(World world, double x, double y, double z, String soundURI, float pitchMod, float volume) { + world.playSound(x, y, z, soundURI, volume, pitchMod); } - /** - * @param songString The string representation of the song - * @return the amount of notes in the string - */ - public static int countNotes(String songString) { - int i = 0; - - int noteCount; - for (noteCount = 0; i < songString.length(); ++i) { - char currentNote = songString.charAt(i); - if (currentNote != '+' && currentNote != '-' && currentNote != '#' && currentNote != 'b') { - ++noteCount; - } - } - - return noteCount; + public static void playNoteFromEntity(Entity entity, IInstrumentConfig instrumentConfig, Note note, float volume) { + playNote(entity.world, entity.x, entity.y, entity.z, instrumentConfig, note, volume); } } diff --git a/src/main/java/dev/adventurecraft/awakening/common/instruments/IInstrumentConfig.java b/src/main/java/dev/adventurecraft/awakening/common/instruments/IInstrumentConfig.java new file mode 100644 index 00000000..37856eab --- /dev/null +++ b/src/main/java/dev/adventurecraft/awakening/common/instruments/IInstrumentConfig.java @@ -0,0 +1,11 @@ +package dev.adventurecraft.awakening.common.instruments; + +public interface IInstrumentConfig { + String getSoundString(Note note); + + float getPitchModifier(); + + float getVolumeModifier(); + + int getTuning(); +} diff --git a/src/main/java/dev/adventurecraft/awakening/common/instruments/Note.java b/src/main/java/dev/adventurecraft/awakening/common/instruments/Note.java new file mode 100644 index 00000000..67c72596 --- /dev/null +++ b/src/main/java/dev/adventurecraft/awakening/common/instruments/Note.java @@ -0,0 +1,105 @@ +package dev.adventurecraft.awakening.common.instruments; + +/** + * Represents a frequency of a standard note. + * A note of value 3 and octave 4 is the middle C. + */ +public class Note { + + /** + * Precalculated values 0 to 11 of note coefficients. + * Wikipedia Link + */ + private static final double[] noteCoefficient = { + 1, + 1.0594630943592952646D, + 1.122462048309372981514422431964D, + 1.1892071150027210668460489434449D, + 1.25992104989487316494880113073D, + 1.3348398541700343650713174535376D, + 1.4142135623730950491074314305706D, + 1.4983070768766814991771910314151D, + 1.5874010519681994752092850851889D, + 1.6817928305074290866076380551132D, + 1.7817974362806786101224718638408D, + 1.8877486253633869940320418208842D, + }; + + /** + * A list that maps the characters 'A' through 'G' to a base 0 note. + */ + private static final int[] charToNote = {0, 2, 3, 5, 7, 8, 10}; + + private int value; + + /** + * The octave of the note. + */ + public int octave; + + private static final int baseOctave = 4; + + /** + * Creates a note starting out from the 4th octave. + * + * @param value The value of the note. + */ + public Note(int value) { + this(value, baseOctave); + } + + + /** + * @param sourceChar The note's source character. 'A' for 0. + * Invalid chars are set to 0. + */ + public Note(char sourceChar, int octave) { + this((sourceChar >= 'A' && sourceChar <= 'G') ? (charToNote[sourceChar - 'A']) : 0, octave); + } + + public Note(int value, int octave) { + this.octave = octave; + this.setValue(value); + } + + + /** + * @return The change in pitch of the note to be played + */ + public float getPitch() { + float product = (float) Math.pow(2, octave); + return (float) (noteCoefficient[this.getValue()] * product); + } + + public void shiftValue(int amount) { + this.setValue(this.getValue() + amount); + } + + public Note withShiftedValue(int amount) { + return new Note(this.getValue() + amount, this.octave); + } + + /** + * The value of the note. + * 0 for A + * 1 for A# + * 2 for D + * 10 for G + * and 11 for G# + */ + public int getValue() { + return value; + } + + public void setValue(int value) { + while (value < 0) { + value += 12; + octave -= 1; + } + while (value > 11) { + value -= 12; + octave += 1; + } + this.value = value; + } +} diff --git a/src/main/java/dev/adventurecraft/awakening/common/instruments/SimpleInstrumentConfig.java b/src/main/java/dev/adventurecraft/awakening/common/instruments/SimpleInstrumentConfig.java new file mode 100644 index 00000000..7bdc260f --- /dev/null +++ b/src/main/java/dev/adventurecraft/awakening/common/instruments/SimpleInstrumentConfig.java @@ -0,0 +1,36 @@ +package dev.adventurecraft.awakening.common.instruments; + +public class SimpleInstrumentConfig implements IInstrumentConfig { + + public final String soundURI; + public final int tuning; + + public SimpleInstrumentConfig(String soundURI) { + this(soundURI, 3); + } + + public SimpleInstrumentConfig(String soundURI, int sampleNote) { + this.soundURI = soundURI; + this.tuning = sampleNote; + } + + @Override + public String getSoundString(Note note) { + return soundURI; + } + + @Override + public float getPitchModifier() { + return 1; + } + + @Override + public float getVolumeModifier() { + return 1; + } + + @Override + public int getTuning() { + return tuning; + } +} diff --git a/src/main/java/dev/adventurecraft/awakening/common/instruments/Song.java b/src/main/java/dev/adventurecraft/awakening/common/instruments/Song.java new file mode 100644 index 00000000..625e37f1 --- /dev/null +++ b/src/main/java/dev/adventurecraft/awakening/common/instruments/Song.java @@ -0,0 +1,76 @@ +package dev.adventurecraft.awakening.common.instruments; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * A list of notes that can be played. + */ +public class Song implements Iterable { + + private static final char SHARP = '#'; + private static final char FLAT = 'b'; + private static final char RAISE_OCTAVE = '+'; + private static final char LOWER_OCTAVE = '-'; + + /** + * A list of notes. If a given note is null it is not meant to be played. + */ + private final List notes; + + public Song(String sourceString, int baseShift) { + // Initialize the list + this.notes = new ArrayList<>(); + int currentOctave = 0; + int noteCount = 0; + // Loop through the chars of the song + for (int i = 0; i < sourceString.length(); i++) { + char currentChar = sourceString.charAt(i); + + if (charIsANote(currentChar)) { + Note newNote = new Note(currentChar, currentOctave); + newNote.shiftValue(baseShift); + this.notes.add(newNote); + noteCount++; + } else { + switch (currentChar) { + case RAISE_OCTAVE -> currentOctave += 1; + case LOWER_OCTAVE -> currentOctave -= 1; + case SHARP -> { + if (noteCount > 0) { + this.notes.get(noteCount - 1).shiftValue(1); + } + } + case FLAT -> { + if (noteCount > 0) { + this.notes.get(noteCount - 1).shiftValue(-1); + } + } + default -> this.notes.add(null); + } + } + } + } + + /** + * @param checkChar The char to be checked + * @return Whether the character represents a note (A-G) + */ + private boolean charIsANote(char checkChar) { + return checkChar >= 'A' && checkChar <= 'G'; + } + + /** + * Returns an iterator over elements of type {@code T}. + * + * @return an Iterator. + */ + @NotNull + @Override + public Iterator iterator() { + return notes.iterator(); + } +} diff --git a/src/main/java/dev/adventurecraft/awakening/extension/entity/block/ExSignBlockEntity.java b/src/main/java/dev/adventurecraft/awakening/extension/entity/block/ExSignBlockEntity.java deleted file mode 100644 index 3aca7e20..00000000 --- a/src/main/java/dev/adventurecraft/awakening/extension/entity/block/ExSignBlockEntity.java +++ /dev/null @@ -1,6 +0,0 @@ -package dev.adventurecraft.awakening.extension.entity.block; - -public interface ExSignBlockEntity { - - void playSong(String instrumentString); -} diff --git a/src/main/java/dev/adventurecraft/awakening/extension/entity/block/ExSongContainer.java b/src/main/java/dev/adventurecraft/awakening/extension/entity/block/ExSongContainer.java new file mode 100644 index 00000000..2d8f9776 --- /dev/null +++ b/src/main/java/dev/adventurecraft/awakening/extension/entity/block/ExSongContainer.java @@ -0,0 +1,15 @@ +package dev.adventurecraft.awakening.extension.entity.block; + +import dev.adventurecraft.awakening.common.instruments.IInstrumentConfig; + +public interface ExSongContainer { + + /** + * Plays the stored song with the given instrument string. + * + * @param instrumentUri the instrument's uri, the sound from the files that will be played. + */ + void playSong(IInstrumentConfig instrumentUri); + + String getSong(); +} diff --git a/src/main/java/dev/adventurecraft/awakening/mixin/entity/block/MixinSignBlockEntity.java b/src/main/java/dev/adventurecraft/awakening/mixin/entity/block/MixinSignBlockEntity.java index c53df0a2..55519d8d 100644 --- a/src/main/java/dev/adventurecraft/awakening/mixin/entity/block/MixinSignBlockEntity.java +++ b/src/main/java/dev/adventurecraft/awakening/mixin/entity/block/MixinSignBlockEntity.java @@ -1,22 +1,28 @@ package dev.adventurecraft.awakening.mixin.entity.block; import dev.adventurecraft.awakening.common.MusicPlayer; -import dev.adventurecraft.awakening.extension.entity.block.ExSignBlockEntity; +import dev.adventurecraft.awakening.common.instruments.IInstrumentConfig; +import dev.adventurecraft.awakening.common.instruments.Note; +import dev.adventurecraft.awakening.common.instruments.Song; +import dev.adventurecraft.awakening.extension.entity.block.ExSongContainer; import net.minecraft.entity.BlockEntity; import net.minecraft.entity.block.SignBlockEntity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import java.util.Iterator; + @Mixin(SignBlockEntity.class) -public abstract class MixinSignBlockEntity extends BlockEntity implements ExSignBlockEntity { +public abstract class MixinSignBlockEntity extends BlockEntity implements ExSongContainer { @Shadow public String[] text; public boolean playSong; - public String instrument; - public int onNote; + public IInstrumentConfig instrument; public int tickSinceStart; + public Iterator songIterator; + @Override public void tick() { if (!this.playSong) { @@ -24,12 +30,11 @@ public void tick() { } if (this.tickSinceStart % 10 == 0) { - String signContents = this.text[0] + this.text[1] + this.text[2] + this.text[3]; - if (this.onNote < MusicPlayer.countNotes(signContents)) { - MusicPlayer.playNoteFromSong(this.world, this.x, this.y, this.z, this.instrument, signContents, this.onNote, 1.0F); - ++this.onNote; - } else { - this.playSong = false; + if (!songIterator.hasNext()) this.playSong = false; + else { + Note currentNote = songIterator.next(); + if (currentNote != null) + MusicPlayer.playNote(this.world, this.x, this.y, this.z, this.instrument, currentNote, 1.0F); } } @@ -37,10 +42,16 @@ public void tick() { } @Override - public void playSong(String instrumentString) { + public void playSong(IInstrumentConfig instrumentConfig) { this.playSong = true; - this.instrument = instrumentString; + this.instrument = instrumentConfig; this.tickSinceStart = 0; - this.onNote = 0; + + Song songToPlay = new Song(getSong(), instrumentConfig.getTuning()); + this.songIterator = songToPlay.iterator(); + } + + public String getSong() { + return this.text[0] + this.text[1] + this.text[2] + this.text[3]; } }