diff --git a/source/ChartingState.hx b/source/ChartingState.hx
index 31e1025c9..92098668c 100644
--- a/source/ChartingState.hx
+++ b/source/ChartingState.hx
@@ -19,6 +19,7 @@ import flixel.addons.ui.FlxUITooltip.FlxUITooltipStyle;
 import flixel.graphics.tile.FlxDrawTrianglesItem.DrawData;
 import flixel.group.FlxGroup.FlxTypedGroup;
 import flixel.group.FlxGroup;
+import flixel.input.gamepad.id.SwitchJoyconLeftID;
 import flixel.math.FlxMath;
 import flixel.math.FlxPoint;
 import flixel.system.FlxSound;
@@ -351,6 +352,7 @@ class ChartingState extends MusicBeatState
 	}
 
 	var stepperSusLength:FlxUINumericStepper;
+	var stepperPerNoteSpeed:FlxUINumericStepper;
 
 	function addNoteUI():Void
 	{
@@ -361,9 +363,17 @@ class ChartingState extends MusicBeatState
 		stepperSusLength.value = 0;
 		stepperSusLength.name = 'note_susLength';
 
+		stepperPerNoteSpeed = new FlxUINumericStepper(10, 40, 0.1, 1, 0.01, 100, 2);
+		stepperPerNoteSpeed.value = 1;
+		stepperPerNoteSpeed.name = "note_PerNoteSpeed";
+
+		var noteSpeedName:FlxText = new FlxText(40, stepperPerNoteSpeed.y, 0, "Note Speed Multiplier");
+
 		var applyLength:FlxButton = new FlxButton(100, 10, 'Apply');
 
 		tab_group_note.add(stepperSusLength);
+		tab_group_note.add(stepperPerNoteSpeed);
+		tab_group_note.add(noteSpeedName);
 		tab_group_note.add(applyLength);
 
 		UI_box.addGroup(tab_group_note);
@@ -402,11 +412,11 @@ class ChartingState extends MusicBeatState
 		musSpec.x += 70;
 		musSpec.daHeight = FlxG.height / 2;
 		musSpec.scrollFactor.set();
-		musSpec.visType = FREQUENCIES;
+		// musSpec.visType = FREQUENCIES;
 		add(musSpec);
 
 		// trace(audioBuf.data.length);
-		playheadTest = new FlxSprite(0, 0).makeGraphic(2, 255, FlxColor.RED);
+		playheadTest = new FlxSprite(0, 0).makeGraphic(2, 60, FlxColor.RED);
 		playheadTest.scrollFactor.set();
 		add(playheadTest);
 
@@ -419,13 +429,13 @@ class ChartingState extends MusicBeatState
 		add(staticSpecGrp);
 
 		var aBoy:ABotVis = new ABotVis(FlxG.sound.music);
-		add(aBoy);
+		// add(aBoy);
 
 		for (index => voc in vocals.members)
 		{
 			var vocalSpec:SpectogramSprite = new SpectogramSprite(voc, FlxG.random.color(0xFFAAAAAA, FlxColor.WHITE, 100));
 			vocalSpec.x = 70 - (50 * index);
-			vocalSpec.visType = FREQUENCIES;
+			// vocalSpec.visType = FREQUENCIES;
 			vocalSpec.daHeight = musSpec.daHeight;
 			vocalSpec.y = vocalSpec.daHeight;
 			vocalSpec.scrollFactor.set();
@@ -794,13 +804,21 @@ class ChartingState extends MusicBeatState
 				vocals.time = FlxG.sound.music.time;
 			}
 
+			if (FlxG.keys.justReleased.S)
+			{
+				FlxG.sound.music.pause();
+				vocals.pause();
+
+				#if HAS_PITCH
+				FlxG.sound.music.pitch = 1;
+				vocals.pitch = 1;
+				#end
+			}
+
 			if (!FlxG.keys.pressed.SHIFT)
 			{
 				if (FlxG.keys.pressed.W || FlxG.keys.pressed.S)
 				{
-					FlxG.sound.music.pause();
-					vocals.pause();
-
 					var daTime:Float = 700 * FlxG.elapsed;
 
 					if (FlxG.keys.pressed.CONTROL)
@@ -808,31 +826,58 @@ class ChartingState extends MusicBeatState
 
 					if (FlxG.keys.pressed.W)
 					{
+						FlxG.sound.music.pause();
+						vocals.pause();
 						FlxG.sound.music.time -= daTime;
+						vocals.time = FlxG.sound.music.time;
 					}
 					else
-						FlxG.sound.music.time += daTime;
+					{
+						if (FlxG.keys.justPressed.S)
+						{
+							FlxG.sound.music.play();
+							vocals.play();
 
-					vocals.time = FlxG.sound.music.time;
+							#if HAS_PITCH
+							FlxG.sound.music.pitch = 0.5;
+							vocals.pitch = 0.5;
+							#end
+						}
+					}
+					// FlxG.sound.music.time += daTime;
+
+					// vocals.time = FlxG.sound.music.time;
 				}
 			}
 			else
 			{
 				if (FlxG.keys.justPressed.W || FlxG.keys.justPressed.S)
 				{
-					FlxG.sound.music.pause();
-					vocals.pause();
-
 					var daTime:Float = Conductor.stepCrochet * 2;
 
 					if (FlxG.keys.justPressed.W)
 					{
+						FlxG.sound.music.pause();
+						vocals.pause();
+
 						FlxG.sound.music.time -= daTime;
+						vocals.time = FlxG.sound.music.time;
 					}
 					else
-						FlxG.sound.music.time += daTime;
+					{
+						if (FlxG.keys.justPressed.S)
+						{
+							// FlxG.sound.music.time += daTime;
 
-					vocals.time = FlxG.sound.music.time;
+							FlxG.sound.music.play();
+							vocals.play();
+
+							#if HAS_PITCH
+							FlxG.sound.music.pitch = 0.2;
+							vocals.pitch = 0.2;
+							#end
+						}
+					}
 				}
 			}
 		}
@@ -1013,6 +1058,9 @@ class ChartingState extends MusicBeatState
 		}
 		leftIcon.setGraphicSize(0, 45);
 		rightIcon.setGraphicSize(0, 45);
+
+		leftIcon.height *= 0.6;
+		rightIcon.height *= 0.6;
 	}
 
 	function updateNoteUI():Void
diff --git a/source/FlxSwf.hx b/source/FlxSwf.hx
new file mode 100644
index 000000000..48d0eff11
--- /dev/null
+++ b/source/FlxSwf.hx
@@ -0,0 +1,44 @@
+package;
+
+import flixel.FlxCamera;
+import flixel.FlxSprite;
+import flixel.graphics.tile.FlxDrawBaseItem;
+import openfl.display.MovieClip;
+
+class FlxSwf extends FlxSprite
+{
+	public var swf:MovieClip;
+
+	public function new()
+	{
+		super();
+	}
+
+	override function draw()
+	{
+		for (camera in cameras)
+		{
+			if (!camera.visible || !camera.exists)
+				continue;
+
+			getScreenPosition(_point, camera).subtractPoint(offset);
+			// assume no render blit for now
+			// use camera.canvas
+			// camera.canvas.graphics.
+		}
+	}
+}
+
+class FlxDrawSwfItem extends FlxDrawBaseItem<FlxDrawSwfItem>
+{
+	public function new()
+	{
+		super();
+		type = FlxDrawItemType.TILES;
+	}
+
+	override function render(camera:FlxCamera)
+	{
+		super.render(camera);
+	}
+}
diff --git a/source/Note.hx b/source/Note.hx
index 84efa89a3..12e3ea5e8 100644
--- a/source/Note.hx
+++ b/source/Note.hx
@@ -50,6 +50,9 @@ class Note extends FlxSprite
 	public static var GOOD_THRESHOLD:Float = 0.55; // 	91.67ms	, 5.5 frames
 	public static var SICK_THRESHOLD:Float = 0.2; // 	33.33ms	, 2 frames
 
+	public var noteSpeedMulti:Float = 1;
+	public var pastHalfWay:Bool = false;
+
 	// anything below sick threshold is sick
 	public static var arrowColors:Array<Float> = [1, 1, 1, 1];
 
@@ -232,6 +235,12 @@ class Note extends FlxSprite
 			}
 			else
 			{
+				if (!pastHalfWay && strumTime <= Conductor.songPosition)
+				{
+					pastHalfWay = true;
+					noteSpeedMulti *= 2;
+				}
+
 				if (strumTime > Conductor.songPosition - HIT_WINDOW)
 				{ // * 0.5 if sustain note, so u have to keep holding it closer to all the way thru!
 					if (strumTime < Conductor.songPosition + (HIT_WINDOW * (isSustainNote ? 0.5 : 1)))
diff --git a/source/PlayState.hx b/source/PlayState.hx
index 6359ff80d..cc4075232 100644
--- a/source/PlayState.hx
+++ b/source/PlayState.hx
@@ -2144,7 +2144,7 @@ class PlayState extends MusicBeatState
 				var strumLineMid = strumLine.y + Note.swagWidth / 2;
 
 				if (daNote.followsTime)
-					daNote.y = (Conductor.songPosition - daNote.strumTime) * (0.45 * FlxMath.roundDecimal(SongLoad.getSpeed(), 2));
+					daNote.y = (Conductor.songPosition - daNote.strumTime) * (0.45 * FlxMath.roundDecimal(SongLoad.getSpeed(), 2) * daNote.noteSpeedMulti);
 
 				if (PreferencesMenu.getPref('downscroll'))
 				{
diff --git a/source/TitleState.hx b/source/TitleState.hx
index 811e03284..084f7e3c5 100644
--- a/source/TitleState.hx
+++ b/source/TitleState.hx
@@ -278,6 +278,16 @@ class TitleState extends MusicBeatState
 
 	override function update(elapsed:Float)
 	{
+		trace(FlxG.renderBlit);
+
+		#if HAS_PITCH
+		if (FlxG.keys.pressed.UP)
+			FlxG.sound.music.pitch += 0.5 * elapsed;
+
+		if (FlxG.keys.pressed.DOWN)
+			FlxG.sound.music.pitch -= 0.5 * elapsed;
+		#end
+
 		/* if (FlxG.onMobile)
 			{
 				if (gfDance != null)
diff --git a/source/VoicesGroup.hx b/source/VoicesGroup.hx
index 426e2fe2e..459b952da 100644
--- a/source/VoicesGroup.hx
+++ b/source/VoicesGroup.hx
@@ -9,6 +9,8 @@ class VoicesGroup extends FlxTypedGroup<FlxSound>
 
 	public var volume(default, set):Float = 1;
 
+	public var pitch(default, set):Float = 1;
+
 	// make it a group that you add to?
 	public function new(song:String, ?files:Array<String>, ?needsVoices:Bool = true)
 	{
@@ -80,4 +82,15 @@ class VoicesGroup extends FlxTypedGroup<FlxSound>
 
 		return volume;
 	}
+
+	function set_pitch(val:Float):Float
+	{
+		#if HAS_PITCH
+		forEachAlive(function(snd)
+		{
+			snd.pitch = val;
+		});
+		#end
+		return val;
+	}
 }