diff --git a/Encore/include/song/chart.h b/Encore/include/song/chart.h
index 7abcd8b4..34b74cf7 100644
--- a/Encore/include/song/chart.h
+++ b/Encore/include/song/chart.h
@@ -8,7 +8,7 @@ struct Note
 	double len;
 	double heldTime=0.0;
 	int lane;
-	bool lift;
+	bool lift = false;
 	bool hit = false;
 	bool held = false;
 	bool valid = false;
diff --git a/Encore/include/song/song.h b/Encore/include/song/song.h
index 26dad1df..c0a333f5 100644
--- a/Encore/include/song/song.h
+++ b/Encore/include/song/song.h
@@ -109,6 +109,8 @@ class Song
 	//Parts order will always be Drums, Bass, Guitar, Vocals, Plastic Drums, Plastic Bass, Plastic Guitar
 	std::vector<SongPart*> parts{ new SongPart,new SongPart,new SongPart,new SongPart ,new SongPart ,new SongPart ,new SongPart };
 
+	std::vector<std::pair<double, bool>> beatLines; //double time, bool downbeat
+
 	std::vector<std::string> stemsPath{ "","","","","" };
 
 	std::filesystem::path midiPath = "";
@@ -258,5 +260,12 @@ class Song
 		}
 		ifs.close();
 	}
-
+	void parseBeatLines(smf::MidiFile& midiFile, int trkidx, smf::MidiEventList events) {
+		for (int i = 0; i < events.getSize(); i++) {
+			if (events[i].isNoteOn()) {
+				double time = midiFile.getTimeInSeconds(trkidx, i);
+				beatLines.push_back({ time, (int)events[i][1] == 12 });
+			}
+		}
+	}
 };
\ No newline at end of file
diff --git a/Encore/src/main.cpp b/Encore/src/main.cpp
index 950b6d04..da0d376d 100644
--- a/Encore/src/main.cpp
+++ b/Encore/src/main.cpp
@@ -21,10 +21,13 @@ vector<std::string> ArgumentList::arguments;
 bool compareNotes(const Note& a, const Note& b) {
 	return a.time < b.time;
 }
+
 std::vector<int> KEYBINDS_5K{ KEY_D,KEY_F,KEY_J,KEY_K,KEY_L };
 std::vector<int> KEYBINDS_4K{ KEY_D,KEY_F,KEY_J,KEY_K };
 std::vector<int> prev4k = KEYBINDS_4K;
 std::vector<int> prev5k = KEYBINDS_5K;
+bool changing4k = false;
+
 rapidjson::Value vectorToJsonArray(const std::vector<int>& vec, rapidjson::Document::AllocatorType& allocator) {
 	rapidjson::Value array(rapidjson::kArrayType);
 	for (const auto& value : vec) {
@@ -126,6 +129,29 @@ std::string getKeyStr(int keycode)
 		return "UNKNOWN";
 	}
 }
+
+int instrument = 0;
+int diff = 0;
+bool midiLoaded = false;
+bool isPlaying = false;
+bool streamsLoaded = false;
+int selectStage = 0;
+std::vector<Music> loadedStreams;
+int curPlayingSong = 0;
+int curNoteIdx = 0;
+int curODPhrase = 0;
+int curBeatLine = 0;
+
+std::vector<float> bns = { 0.5f,0.75f,1.0f,1.25f,1.5f,1.75f,2.0f };
+int bn = 4;
+std::string bnsButton = "Track Speed 1.5x";
+
+
+std::vector<double> laneTimes = { 0.0,0.0,0.0,0.0,0.0 };
+std::vector<double> liftTimes = { 0.0,0.0,0.0,0.0,0.0 };
+std::vector<bool> heldFrets = { false,false,false,false,false };
+
+
 int main(int argc, char* argv[])
 {
 #ifdef NDEBUG
@@ -158,8 +184,7 @@ int main(int argc, char* argv[])
 	double updateDrawTime = 0.0;
 	double waitTime = 0.0;
 	float deltaTime = 0.0f;
-	int instrument = 0;
-	int diff = 0;
+	
 
 
 	float timeCounter = 0.0f;
@@ -263,23 +288,6 @@ int main(int argc, char* argv[])
 	}
 
 	SongList songList = LoadSongs(songsPath);
-	bool midiLoaded = false;
-	bool isPlaying = false;
-	bool streamsLoaded = false;
-	int selectStage = 0;
-	std::vector<Music> loadedStreams;
-	int curPlayingSong = 0;
-	int curNoteIdx = 0;
-	int curODPhrase = 0;
-
-	////////////////////////////////////
-	//
-	//        BREAKNECK SPEED
-	//
-
-	float bns = 2.0f;
-	bool bn = true;
-	const char* bnsButton = "Breakneck On";
 
 	ChangeDirectory(GetApplicationDirectory());
 
@@ -305,8 +313,6 @@ int main(int argc, char* argv[])
 	expertHighway.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
 	emhHighway.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = highwayTexture;
 	emhHighway.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
-	// expertHighway.materials[1].maps[MATERIAL_MAP_ALBEDO].texture = sidesTexture;
-	// expertHighway.materials[1].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
 	Model noteModel = LoadModel((directory / "Assets/note.obj").string().c_str());
 	Texture2D noteTexture = LoadTexture((directory / "Assets/note_d.png").string().c_str());
 	Texture2D emitTexture = LoadTexture((directory / "Assets/note_e.png").string().c_str());
@@ -325,10 +331,7 @@ int main(int argc, char* argv[])
 	liftModel.materials[0].maps[MATERIAL_MAP_ALBEDO].color = Color{ 172,82,217,127 };
 	Model liftModelOD = LoadModel((directory / "Assets/lift.obj").string().c_str());
 	liftModelOD.materials[0].maps[MATERIAL_MAP_ALBEDO].color = Color{ 217, 183, 82 ,127 };
-	std::vector<double> laneTimes = { 0.0,0.0,0.0,0.0,0.0 };
-	std::vector<double> liftTimes = { 0.0,0.0,0.0,0.0,0.0 };
-	std::vector<bool> heldFrets = { false,false,false,false,false };
-	bool changing4k = false;
+	
 	
 	while (!WindowShouldClose())
 	{ 
@@ -432,41 +435,32 @@ int main(int argc, char* argv[])
 
 			}
 			else if (selectStage == 0) {
-
+				streamsLoaded = false;
 				midiLoaded = false;
 				float curSong = 0.0f;
-				for (Song song : songList.songs) {
-					if (GuiButton({ (float)GetScreenWidth() - 100,0,100,60}, "Keybinds")) {
-						selectStage = -1;
+				if (GuiButton({ (float)GetScreenWidth() - 100,0,100,60 }, "Keybinds")) {
+					selectStage = -1;
+				}
+				if (GuiButton({ (float)GetScreenWidth() - 100,60,100,60 }, "Fullscreen")) {
+					windowToggle = !windowToggle;
+					ToggleBorderlessWindowed();
+					if (windowToggle) {
+						SetWindowPosition(50, 50);
+						SetWindowSize(1600, 800);
 					}
+					else {
+						SetWindowSize(1920, 1080);
+					};
+				}
+				if (GuiButton({ (float)GetScreenWidth() - 150,120,150,60 }, bnsButton.c_str())) {
+					if (bn == 6) bn = 0; else bn++;
+					bnsButton = "Track Speed "+std::to_string(bns[bn])+"x";
+				}
+				for (Song song : songList.songs) {
 					if (GuiButton({ 0,0 + (60 * curSong),300,60 }, "")) {
 						curPlayingSong = (int)curSong;
 						selectStage = 1;
 					}
-					if (GuiButton({ (float)GetScreenWidth() - 100,60,100,60 }, "Fullscreen")) {
-						windowToggle = !windowToggle;
-						ToggleBorderlessWindowed();
-						if (windowToggle) {
-							SetWindowPosition(50, 50);
-							SetWindowSize(1600, 800);
-						}
-						else {
-							SetWindowSize(1920, 1080);
-						};
-					}
-					if (GuiButton({ (float)GetScreenWidth() - 100,120,100,60}, bnsButton)) {
-						if (!bn) {
-							bns = 2.0f;
-							bn = true;
-							bnsButton = "Breakneck On";
-						}
-						else
-						{
-							bns = 1.0f;
-							bn = false;
-							bnsButton = "Breakneck Off";
-						};
-					}
 					DrawTextureEx(song.albumArt, Vector2{ 5,(60 * curSong) + 5 }, 0.0f, 0.1f, RAYWHITE);
 
 					DrawText(song.title.c_str(), 60, (60 * curSong) + 5, 20, BLACK);
@@ -490,18 +484,22 @@ int main(int argc, char* argv[])
 										}
 										SongParts songPart = partFromString(trackName);
 										std::cout << "TRACKNAME " << trackName << ": " << int(songPart) << std::endl;
-										if (songPart != SongParts::Invalid) {
-											songList.songs[curPlayingSong].parts[(int)songPart]->hasPart = true;
-											std::string diffstr = "ESY: ";
-											for (int diff = 0; diff < 4; diff++) {
-												Chart newChart;
-												newChart.parseNotes(midiFile, i, midiFile[i], diff);
-												std::sort(newChart.notes.begin(), newChart.notes.end(), compareNotes);
-												if (diff == 1) diffstr = "MED: ";
-												else if (diff == 2) diffstr = "HRD: ";
-												else if (diff == 3) diffstr = "EXP: ";
-												songList.songs[curPlayingSong].parts[(int)songPart]->charts.push_back(newChart);
-												std::cout << trackName << " " << diffstr << newChart.notes.size() << std::endl;
+										if (trackName == "BEAT")
+											songList.songs[curPlayingSong].parseBeatLines(midiFile, i, midiFile[i]);
+										else {
+											if (songPart != SongParts::Invalid) {
+												songList.songs[curPlayingSong].parts[(int)songPart]->hasPart = true;
+												std::string diffstr = "ESY: ";
+												for (int diff = 0; diff < 4; diff++) {
+													Chart newChart;
+													newChart.parseNotes(midiFile, i, midiFile[i], diff);
+													std::sort(newChart.notes.begin(), newChart.notes.end(), compareNotes);
+													if (diff == 1) diffstr = "MED: ";
+													else if (diff == 2) diffstr = "HRD: ";
+													else if (diff == 3) diffstr = "EXP: ";
+													songList.songs[curPlayingSong].parts[(int)songPart]->charts.push_back(newChart);
+													std::cout << trackName << " " << diffstr << newChart.notes.size() << std::endl;
+												}
 											}
 										}
 									}
@@ -591,25 +589,36 @@ int main(int argc, char* argv[])
 						}
 						else {
 							DrawModel(smasherReg, Vector3{ diffDistance - (i + 2), 0, 0 }, 1.0f, WHITE);
-							
+
 						}
 					}
 					for (int i = 0; i < 3; i++) {
 						DrawLine3D(Vector3{ lineDistance - i, 0.05f, 0 }, Vector3{ lineDistance - i, 0.05f, 20 }, Color{ 255,255,255,255 });
 					}
 				}
-				
-				
+				if (songList.songs[curPlayingSong].beatLines.size() >= 0) {
+					for (int i = curBeatLine; i < songList.songs[curPlayingSong].beatLines.size(); i++) {
+						double relTime = (songList.songs[curPlayingSong].beatLines[i].first - musicTime) * bns[bn];
+						if (relTime > 1.5)
+							break;
+						float radius = songList.songs[curPlayingSong].beatLines[i].second ? 0.05f : 0.025f;
+						DrawCylinderEx(Vector3{ -diffDistance-0.5f,0,2.5f + (12.5f * (float)relTime) }, Vector3{ diffDistance + 0.5f,0,2.5f + (12.5f * (float)relTime) }, radius, radius, 4, WHITE);
+
+						if (relTime < -1 && curBeatLine < songList.songs[curPlayingSong].beatLines.size())
+							curBeatLine++;
+
+					}
+				}
 				// DrawTriangle3D(Vector3{ 2.5f,0.0f,0.0f }, Vector3{ -2.5f,0.0f,0.0f }, Vector3{ -2.5f,0.0f,20.0f }, BLACK);
 				// DrawTriangle3D(Vector3{ 2.5f,0.0f,0.0f }, Vector3{ -2.5f,0.0f,20.0f }, Vector3{ 2.5f,0.0f,20.0f }, BLACK);
 				
 				// DrawLine3D(Vector3{ 2.5f, 0.05f, 2.0f }, Vector3{ -2.5f, 0.05f, 2.0f}, WHITE);
-				Chart& dmsExpert = songList.songs[curPlayingSong].parts[instrument]->charts[diff];
-				if (dmsExpert.odPhrases.size() > 0 && curODPhrase < dmsExpert.odPhrases.size()) {
-					if (dmsExpert.notes[curNoteIdx].time+dmsExpert.notes[curNoteIdx].len > dmsExpert.odPhrases[curODPhrase].end && curODPhrase < dmsExpert.odPhrases.size()) curODPhrase++;
+				Chart& curChart = songList.songs[curPlayingSong].parts[instrument]->charts[diff];
+				if (curChart.odPhrases.size() > 0) {
+					if (curChart.notes[curNoteIdx].time+curChart.notes[curNoteIdx].len > curChart.odPhrases[curODPhrase].end && curODPhrase < curChart.odPhrases.size()-1) curODPhrase++;
 				}
-				for (int i = curNoteIdx; i < dmsExpert.notes.size(); i++) {
-					Note& curNote = dmsExpert.notes[i];
+				for (int i = curNoteIdx; i < curChart.notes.size(); i++) {
+					Note& curNote = curChart.notes[i];
 					if (curNote.lift == true) {
 						if (curNote.time - 0.075 < liftTimes[curNote.lane] && curNote.time + 0.075 > laneTimes[curNote.lane]) {
 							curNote.hit = true;
@@ -618,20 +627,20 @@ int main(int argc, char* argv[])
 					else {
 						if (curNote.time - 0.075 < laneTimes[curNote.lane] && curNote.time + 0.075 > laneTimes[curNote.lane]) {
 							curNote.hit = true;
-							if ((curNote.len * bns) > 0.25) {
+							if ((curNote.len * bns[bn]) > 0.25) {
 								curNote.held = true;
 							}
 						}
-						if (laneTimes[curNote.lane] == 0.0 && (curNote.len * bns) > 0.25) {
+						if (laneTimes[curNote.lane] == 0.0 && (curNote.len * bns[bn]) > 0.25) {
 							curNote.held = false;
 						}
 					}
 					
-					double relTime = (curNote.time - musicTime) * bns;
-					double relEnd = ((curNote.time + curNote.len) - musicTime) * bns;
+					double relTime = (curNote.time - musicTime) * bns[bn];
+					double relEnd = ((curNote.time + curNote.len) - musicTime) * bns[bn];
 					bool od = false;
-					if (dmsExpert.odPhrases.size() > 0 && curODPhrase < dmsExpert.odPhrases.size()) {
-						if (curNote.time >= dmsExpert.odPhrases[curODPhrase].start && curNote.time <= dmsExpert.odPhrases[curODPhrase].end) {
+					if (curChart.odPhrases.size() > 0) {
+						if (curNote.time >= curChart.odPhrases[curODPhrase].start && curNote.time <= curChart.odPhrases[curODPhrase].end) {
 							od = true;
 						}
 
@@ -651,9 +660,9 @@ int main(int argc, char* argv[])
 					}
 					else {
 						// sustains
-						if ((curNote.len * bns)> 0.25) {
+						if ((curNote.len * bns[bn])> 0.25) {
 							if (curNote.hit == true && curNote.held == true) {
-								if (curNote.heldTime < (curNote.len * bns)) {
+								if (curNote.heldTime < (curNote.len * bns[bn])) {
 									curNote.heldTime = 0.0 - relTime;
 									if (relTime < 0.0) relTime = 0.0;
 								}
@@ -672,16 +681,19 @@ int main(int argc, char* argv[])
 								DrawLine3D(Vector3{ diffDistance - (1.0f * curNote.lane),0.05f,2.5f + (12.5f * (float)relTime) }, Vector3{ diffDistance - (1.0f * curNote.lane),0.05f,2.5f + (12.5f * (float)relEnd) }, Color{ 172,82,217,255 });
 						}
 						// regular notes
-						if (((curNote.len * bns) >=0.25 && (curNote.held==true||curNote.hit==false)) || ((curNote.len * bns)<0.25 && curNote.hit==false)) {
+						if (((curNote.len * bns[bn]) >=0.25 && (curNote.held==true||curNote.hit==false)) || ((curNote.len * bns[bn])<0.25 && curNote.hit==false)) {
 							if (od == true)
 								DrawModel(noteModelOD, Vector3{ diffDistance - (1.0f * curNote.lane),0,2.5f + (12.5f * (float)relTime) }, 1.0f, WHITE);
 							else
 								DrawModel(noteModel, Vector3{ diffDistance - (1.0f * curNote.lane),0,2.5f + (12.5f * (float)relTime) }, 1.0f, WHITE);
 						}
 					}
-					if (relEnd < -1 && curNoteIdx < dmsExpert.notes.size()) curNoteIdx = i + 1;
+					if (relEnd < -1 && curNoteIdx < curChart.notes.size()) curNoteIdx = i + 1;
 
 				}
+				DrawLine3D(Vector3{ -diffDistance - 0.5f,0,2.5f + (12.5f * 0.075f*bns[bn])}, Vector3{diffDistance + 0.5f,0,2.5f + (12.5f * 0.075f * bns[bn] )}, Color{0,255,0,255});
+				DrawLine3D(Vector3{ -diffDistance - 0.5f,0,2.5f - (12.5f * 0.075f * bns[bn]) }, Vector3{ diffDistance + 0.5f,0,2.5f - (12.5f * 0.075f * bns[bn] )}, Color{ 0,255,0,255 });
+				
 				EndMode3D();
 			}