--- a/net/minecraft/world/level/block/NoteBlock.java
+++ b/net/minecraft/world/level/block/NoteBlock.java
@@ -20,6 +20,7 @@
 import net.minecraft.world.item.context.BlockPlaceContext;
 import net.minecraft.world.level.Level;
 import net.minecraft.world.level.LevelAccessor;
+import net.minecraft.world.level.block.entity.BlockEntity;
 import net.minecraft.world.level.block.entity.SkullBlockEntity;
 import net.minecraft.world.level.block.state.BlockBehaviour;
 import net.minecraft.world.level.block.state.BlockState;
@@ -33,6 +34,7 @@
 import net.minecraft.world.phys.BlockHitResult;
 
 public class NoteBlock extends Block {
+
     public static final MapCodec<NoteBlock> CODEC = simpleCodec(NoteBlock::new);
     public static final EnumProperty<NoteBlockInstrument> INSTRUMENT = BlockStateProperties.NOTEBLOCK_INSTRUMENT;
     public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
@@ -41,68 +43,75 @@
 
     @Override
     public MapCodec<NoteBlock> codec() {
-        return CODEC;
+        return NoteBlock.CODEC;
     }
 
     public NoteBlock(BlockBehaviour.Properties settings) {
         super(settings);
-        this.registerDefaultState(
-            this.stateDefinition
-                .any()
-                .setValue(INSTRUMENT, NoteBlockInstrument.HARP)
-                .setValue(NOTE, Integer.valueOf(0))
-                .setValue(POWERED, Boolean.valueOf(false))
-        );
+        this.registerDefaultState((BlockState) ((BlockState) ((BlockState) ((BlockState) this.stateDefinition.any()).setValue(NoteBlock.INSTRUMENT, NoteBlockInstrument.HARP)).setValue(NoteBlock.NOTE, 0)).setValue(NoteBlock.POWERED, false));
     }
 
     private BlockState setInstrument(LevelAccessor world, BlockPos pos, BlockState state) {
-        NoteBlockInstrument noteBlockInstrument = world.getBlockState(pos.above()).instrument();
-        if (noteBlockInstrument.worksAboveNoteBlock()) {
-            return state.setValue(INSTRUMENT, noteBlockInstrument);
+        NoteBlockInstrument blockpropertyinstrument = world.getBlockState(pos.above()).instrument();
+
+        if (blockpropertyinstrument.worksAboveNoteBlock()) {
+            return (BlockState) state.setValue(NoteBlock.INSTRUMENT, blockpropertyinstrument);
         } else {
-            NoteBlockInstrument noteBlockInstrument2 = world.getBlockState(pos.below()).instrument();
-            NoteBlockInstrument noteBlockInstrument3 = noteBlockInstrument2.worksAboveNoteBlock() ? NoteBlockInstrument.HARP : noteBlockInstrument2;
-            return state.setValue(INSTRUMENT, noteBlockInstrument3);
+            NoteBlockInstrument blockpropertyinstrument1 = world.getBlockState(pos.below()).instrument();
+            NoteBlockInstrument blockpropertyinstrument2 = blockpropertyinstrument1.worksAboveNoteBlock() ? NoteBlockInstrument.HARP : blockpropertyinstrument1;
+
+            return (BlockState) state.setValue(NoteBlock.INSTRUMENT, blockpropertyinstrument2);
         }
     }
 
     @Override
     public BlockState getStateForPlacement(BlockPlaceContext ctx) {
+        if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return this.defaultBlockState(); // Paper - place without considering instrument
         return this.setInstrument(ctx.getLevel(), ctx.getClickedPos(), this.defaultBlockState());
     }
 
     @Override
     protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
-        boolean bl = direction.getAxis() == Direction.Axis.Y;
-        return bl ? this.setInstrument(world, pos, state) : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
+        if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return state; // Paper - prevent noteblock instrument from updating
+        boolean flag = direction.getAxis() == Direction.Axis.Y;
+
+        return flag ? this.setInstrument(world, pos, state) : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
     }
 
     @Override
     protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) {
-        boolean bl = world.hasNeighborSignal(pos);
-        if (bl != state.getValue(POWERED)) {
-            if (bl) {
-                this.playNote(null, state, world, pos);
+        if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return; // Paper - prevent noteblock powered-state from updating
+        boolean flag1 = world.hasNeighborSignal(pos);
+
+        if (flag1 != (Boolean) state.getValue(NoteBlock.POWERED)) {
+            if (flag1) {
+                this.playNote((Entity) null, state, world, pos);
+                state = world.getBlockState(pos); // CraftBukkit - SPIGOT-5617: update in case changed in event
             }
 
-            world.setBlock(pos, state.setValue(POWERED, Boolean.valueOf(bl)), 3);
+            world.setBlock(pos, (BlockState) state.setValue(NoteBlock.POWERED, flag1), 3);
         }
+
     }
 
     private void playNote(@Nullable Entity entity, BlockState state, Level world, BlockPos pos) {
-        if (state.getValue(INSTRUMENT).worksAboveNoteBlock() || world.getBlockState(pos.above()).isAir()) {
+        if (((NoteBlockInstrument) state.getValue(NoteBlock.INSTRUMENT)).worksAboveNoteBlock() || world.getBlockState(pos.above()).isAir()) {
+            // CraftBukkit start
+            // org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, state.getValue(NoteBlock.INSTRUMENT), state.getValue(NoteBlock.NOTE));
+            // if (event.isCancelled()) {
+            //     return;
+            // }
+            // CraftBukkit end
+            // Paper - move NotePlayEvent call to fix instrument/note changes; TODO any way to cancel the game event?
             world.blockEvent(pos, this, 0, 0);
-            world.gameEvent(entity, GameEvent.NOTE_BLOCK_PLAY, pos);
+            world.gameEvent(entity, (Holder) GameEvent.NOTE_BLOCK_PLAY, pos);
         }
+
     }
 
     @Override
-    protected ItemInteractionResult useItemOn(
-        ItemStack stack, BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit
-    ) {
-        return stack.is(ItemTags.NOTE_BLOCK_TOP_INSTRUMENTS) && hit.getDirection() == Direction.UP
-            ? ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION
-            : super.useItemOn(stack, state, world, pos, player, hand, hit);
+    protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
+        return stack.is(ItemTags.NOTE_BLOCK_TOP_INSTRUMENTS) && hit.getDirection() == Direction.UP ? ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION : super.useItemOn(stack, state, world, pos, player, hand, hit);
     }
 
     @Override
@@ -110,7 +119,7 @@
         if (world.isClientSide) {
             return InteractionResult.SUCCESS;
         } else {
-            state = state.cycle(NOTE);
+            if (!io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) state = (BlockState) state.cycle(NoteBlock.NOTE); // Paper - prevent noteblock note from updating
             world.setBlock(pos, state, 3);
             this.playNote(player, state, world, pos);
             player.awardStat(Stats.TUNE_NOTEBLOCK);
@@ -127,46 +136,58 @@
     }
 
     public static float getPitchFromNote(int note) {
-        return (float)Math.pow(2.0, (double)(note - 12) / 12.0);
+        return (float) Math.pow(2.0D, (double) (note - 12) / 12.0D);
     }
 
     @Override
     protected boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) {
-        NoteBlockInstrument noteBlockInstrument = state.getValue(INSTRUMENT);
+        NoteBlockInstrument blockpropertyinstrument = (NoteBlockInstrument) state.getValue(NoteBlock.INSTRUMENT);
+        // Paper start - move NotePlayEvent call to fix instrument/note changes
+        org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, blockpropertyinstrument, state.getValue(NOTE));
+        if (event.isCancelled()) return false;
+        // Paper end - move NotePlayEvent call to fix instrument/note changes
         float f;
-        if (noteBlockInstrument.isTunable()) {
-            int i = state.getValue(NOTE);
-            f = getPitchFromNote(i);
-            world.addParticle(ParticleTypes.NOTE, (double)pos.getX() + 0.5, (double)pos.getY() + 1.2, (double)pos.getZ() + 0.5, (double)i / 24.0, 0.0, 0.0);
+
+        if (blockpropertyinstrument.isTunable()) {
+            int k = event.getNote().getId(); // Paper - move NotePlayEvent call to fix instrument/note changes
+
+            f = NoteBlock.getPitchFromNote(k);
+            world.addParticle(ParticleTypes.NOTE, (double) pos.getX() + 0.5D, (double) pos.getY() + 1.2D, (double) pos.getZ() + 0.5D, (double) k / 24.0D, 0.0D, 0.0D);
         } else {
             f = 1.0F;
         }
 
-        Holder<SoundEvent> holder;
-        if (noteBlockInstrument.hasCustomSound()) {
-            ResourceLocation resourceLocation = this.getCustomSoundId(world, pos);
-            if (resourceLocation == null) {
+        Holder holder;
+
+        if (blockpropertyinstrument.hasCustomSound()) {
+            ResourceLocation minecraftkey = this.getCustomSoundId(world, pos);
+
+            if (minecraftkey == null) {
                 return false;
             }
 
-            holder = Holder.direct(SoundEvent.createVariableRangeEvent(resourceLocation));
+            holder = Holder.direct(SoundEvent.createVariableRangeEvent(minecraftkey));
         } else {
-            holder = noteBlockInstrument.getSoundEvent();
+            holder = org.bukkit.craftbukkit.block.data.CraftBlockData.toNMS(event.getInstrument(), NoteBlockInstrument.class).getSoundEvent(); // Paper - move NotePlayEvent call to fix instrument/note changes
         }
 
-        world.playSeededSound(
-            null, (double)pos.getX() + 0.5, (double)pos.getY() + 0.5, (double)pos.getZ() + 0.5, holder, SoundSource.RECORDS, 3.0F, f, world.random.nextLong()
-        );
+        world.playSeededSound((Player) null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, holder, SoundSource.RECORDS, 3.0F, f, world.random.nextLong());
         return true;
     }
 
     @Nullable
     private ResourceLocation getCustomSoundId(Level world, BlockPos pos) {
-        return world.getBlockEntity(pos.above()) instanceof SkullBlockEntity skullBlockEntity ? skullBlockEntity.getNoteBlockSound() : null;
+        BlockEntity tileentity = world.getBlockEntity(pos.above());
+
+        if (tileentity instanceof SkullBlockEntity tileentityskull) {
+            return tileentityskull.getNoteBlockSound();
+        } else {
+            return null;
+        }
     }
 
     @Override
     protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
-        builder.add(INSTRUMENT, POWERED, NOTE);
+        builder.add(NoteBlock.INSTRUMENT, NoteBlock.POWERED, NoteBlock.NOTE);
     }
 }
