diff --git a/osufs/osufs/fontenc.c b/osufs/osufs/fontenc.c
index a7ed4f37f59b681d277682d5128d40c64ec2808a..247d7252a103e06675f51097d7a41eccc6cf8ee2 100644
--- a/osufs/osufs/fontenc.c
+++ b/osufs/osufs/fontenc.c
@@ -77,3 +77,43 @@ uint32_t font_write(const char *filename, int ptsize, mdev *dev, uint32_t addr)
 	return addr;
 }
 
+uint32_t font_score_write(const char *dirname, mdev *dev, uint32_t addr) {
+
+#define FONT_IMPORT_GLYPH(chr, filename)\
+strcpy(fname, filename);\
+w = -1;\
+fnt.font[chr-' '] = addr;\
+addr = img_write_dither64(cbuf, dev, addr, &(w), &(h));\
+fnt.widths[chr-' '] = w;
+	
+	osu_font fnt;
+	memset(&fnt, 0, sizeof(fnt));
+	char cbuf[1024], *fname = cbuf + strlen(dirname);
+	strncpy(cbuf, dirname, 1024);
+	*fname = '/';
+	fname++;
+	
+	fnt.height = 36;
+	uint16_t w, h = fnt.height;
+
+	FONT_IMPORT_GLYPH('0', "score-0.png")
+	FONT_IMPORT_GLYPH('1', "score-1.png")
+	FONT_IMPORT_GLYPH('2', "score-2.png")
+	FONT_IMPORT_GLYPH('3', "score-3.png")
+	FONT_IMPORT_GLYPH('4', "score-4.png")
+	FONT_IMPORT_GLYPH('5', "score-5.png")
+	FONT_IMPORT_GLYPH('6', "score-6.png")
+	FONT_IMPORT_GLYPH('7', "score-7.png")
+	FONT_IMPORT_GLYPH('8', "score-8.png")
+	FONT_IMPORT_GLYPH('9', "score-9.png")
+	FONT_IMPORT_GLYPH(',', "score-comma.png")
+	FONT_IMPORT_GLYPH('.', "score-dot.png")
+	FONT_IMPORT_GLYPH('%', "score-percent.png")
+	FONT_IMPORT_GLYPH('x', "score-x.png")
+
+	
+	blkio_write(dev, addr++, &fnt);
+	strncpy(fnt.magic, "oFNT", 4);
+	
+	return addr;
+}
diff --git a/osufs/osufs/fontenc.h b/osufs/osufs/fontenc.h
index fb8e8bd0a5a6d9ac64bf3394fc0023d52acb3e75..e51c01379c2ec3cd6f9ba8ceea916a486a030ded 100644
--- a/osufs/osufs/fontenc.h
+++ b/osufs/osufs/fontenc.h
@@ -17,7 +17,8 @@ extern "C" {
 #include "blkio.h"
 	
 	uint32_t font_write(const char *filename, int ptsize, mdev *dev, uint32_t addr);
-	
+	uint32_t font_score_write(const char *dirname, mdev *dev, uint32_t addr);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/osufs/osufs/imgenc.c b/osufs/osufs/imgenc.c
index 66f3163d9f94c3bcb169efeadd427f546fe8ae58..e2ca880410860e1c4f2c1ac269f07a48666abfc8 100644
--- a/osufs/osufs/imgenc.c
+++ b/osufs/osufs/imgenc.c
@@ -67,7 +67,7 @@ uint32_t img_write_dither128(const char *filename, mdev *dev, uint32_t addr) {
 	
 	// Dump image, row major
 	printf("Saving pixels in %s\n", filename);
-	size_t bufsize = png_get_rowbytes(img.png_ptr, img.info_ptr) * img.height;
+	ssize_t bufsize = png_get_rowbytes(img.png_ptr, img.info_ptr) * img.height;
 	size_t bufptr = 0;
 	while (bufsize > 0) {
 		blkio_write(dev, addr++, img.row_pointers[0]+bufptr);
@@ -80,7 +80,85 @@ uint32_t img_write_dither128(const char *filename, mdev *dev, uint32_t addr) {
 	return addr;
 }
 
-uint32_t img_write_rgb16(const char *filename, mdev *dev, uint32_t addr, uint16_t *w, uint16_t *h) {
+uint32_t img_write_dither64(const char *filename, mdev *dev, uint32_t addr,
+							uint16_t *w, uint16_t *h) {
+	char cbuf[1024];
+	int ret;
+	
+	int w_signed = *w==0xffff ? -1 : *w, h_signed = *h==0xffff ? -1 : *h;
+	
+	system("rm -f /tmp/source.png /tmp/plt.png /tmp/dither.png");
+	
+	// Resize
+	sprintf(cbuf, "ffmpeg -loglevel error -i \"%s\" -vf \"scale=%d:%d\" /tmp/source.png", filename, w_signed, h_signed);
+	ret = system(cbuf);
+	if (ret != 0) {
+		fprintf(stderr, "ffmpeg resize failed with exit code: %d\n", ret);
+		return addr;
+	}
+	
+	// PaletteGen
+	ret = system("ffmpeg -loglevel error -i /tmp/source.png -vf \"palettegen=max_colors=64\" /tmp/plt.png");
+	if (ret != 0) {
+		fprintf(stderr, "ffmpeg palettegen failed with exit code: %d\n", ret);
+		return addr;
+	}
+	
+	// Dithering
+	ret = system("ffmpeg -loglevel error -i /tmp/source.png -i /tmp/plt.png -lavfi \"paletteuse=dither=floyd_steinberg\" -y /tmp/dither.png");
+	if (ret != 0) {
+		fprintf(stderr, "ffmpeg dithering failed with exit code: %d\n", ret);
+	}
+	
+	
+	PNGImage img = pngimg_read("/tmp/dither.png");
+	if (img.color_type != PNG_COLOR_TYPE_PALETTE) {
+		fprintf(stderr, "Internal Error: dithered image is not index!\n");
+		return addr;
+	}
+	
+	png_colorp plt;
+	int nplt;
+	if (!png_get_PLTE(img.png_ptr, img.info_ptr, &plt, &nplt)) {
+		fprintf(stderr, "Internal Error: failed to read palette!\n");
+		return addr;
+	}
+	
+	// Dump palette
+	uint8_t buf[512], *pltbuf = buf + 3;
+	buf[0] = 'P';
+	buf[1] = 'L';
+	buf[2] = 'T';
+	for (int i=0; i<64; i++) {
+		pltbuf[i*3+0] = plt[0xff-i].red;
+		pltbuf[i*3+1] = plt[0xff-i].green;
+		pltbuf[i*3+2] = plt[0xff-i].blue;
+	}
+	blkio_write(dev, addr++, buf);
+	
+	// Dump image, row major
+	*w = img.width;
+	*h = img.height;
+	printf("Saving pixels in %s\n", filename);
+	ssize_t bufsize = png_get_rowbytes(img.png_ptr, img.info_ptr) * img.height;
+	size_t bufptr = 0;
+	uint8_t pixbuf[512];
+	while (bufsize > 0) {
+		for (int i=0; i<512 && bufsize>0; i++) {
+			pixbuf[i] = 0xff - (img.row_pointers[0]+bufptr)[i];
+			bufsize--;
+		}
+		blkio_write(dev, addr++, pixbuf);
+		bufptr += 512;
+	}
+	
+	pngimg_release(&img);
+	
+	return addr;
+}
+
+uint32_t img_write_rgb16(const char *filename, mdev *dev, uint32_t addr,
+						 uint16_t *w, uint16_t *h) {
 	char cbuf[1024];
 	int ret;
 	
diff --git a/osufs/osufs/imgenc.h b/osufs/osufs/imgenc.h
index 1f49ea13d561d890a627f56b3a5651d3c3befda2..f0a0e948708398d20c34e233e81df70dee0cec0f 100644
--- a/osufs/osufs/imgenc.h
+++ b/osufs/osufs/imgenc.h
@@ -17,7 +17,10 @@ extern "C" {
 #include "blkio.h"
 	
 	uint32_t img_write_dither128(const char *filename, mdev *dev, uint32_t addr);
-	uint32_t img_write_rgb16(const char *filename, mdev *dev, uint32_t addr, uint16_t *w, uint16_t *h);
+	uint32_t img_write_dither64(const char *filename, mdev *dev, uint32_t addr,
+								uint16_t *w, uint16_t *h);
+	uint32_t img_write_rgb16(const char *filename, mdev *dev, uint32_t addr,
+							 uint16_t *w, uint16_t *h);
 
 #ifdef __cplusplus
 }
diff --git a/osufs/osufs/main.cpp b/osufs/osufs/main.cpp
index bada42e0ef0d3c8dba7be556ceedcfb5fbafa365..28f3b5c51fa640a9e9e01b994d46b124ae5f6a49 100644
--- a/osufs/osufs/main.cpp
+++ b/osufs/osufs/main.cpp
@@ -29,8 +29,10 @@ int main(int argc, char *argv[]) {
 	// Self-checks
 	assert(sizeof(osu_meta) == 512 && "Invalid osu_meta struct size");
 	assert(sizeof(osu_song) == 512 && "Invalid osu_song struct size");
+	assert(sizeof(osu_font) == 512 && "Invalid osu_font struct size");
 	assert(sizeof(elem_hit_circle) == 32 && "Invalid elem_hit_circle size");
 	assert(sizeof(elem_spinner) == 32 && "Invalid elem_spinner size");
+	assert(sizeof(osu_storyboard) == 2097152 && "Invalid osu_storyboard size");
 
 	mdev *dev = blkio_open(argv[1]);
 	if (!dev) {
diff --git a/osufs/osufs/osu.cpp b/osufs/osufs/osu.cpp
index 85a03135f158144caffd0630359f89109dc67a01..3f592265e831d62289f47fbd46002c20bb5416fa 100644
--- a/osufs/osufs/osu.cpp
+++ b/osufs/osufs/osu.cpp
@@ -39,6 +39,13 @@ meta-> entry ## _w = w;\
 meta-> entry ## _h = h;\
 addr = img_write_rgb16(cbuf, dev, addr, &(meta-> entry ## _w), &(meta-> entry ## _h));
 	
+#define SKIN_IMPORT_IMAGE_DITHER64(entry, filename, w, h)\
+strcpy(fname, filename);\
+meta-> entry = addr;\
+meta-> entry ## _w = w;\
+meta-> entry ## _h = h;\
+addr = img_write_dither64(cbuf, dev, addr, &(meta-> entry ## _w), &(meta-> entry ## _h));
+	
 	char cbuf[1024], *fname;
 	uint32_t addr = meta->available_block;
 
@@ -98,16 +105,16 @@ addr = img_write_rgb16(cbuf, dev, addr, &(meta-> entry ## _w), &(meta-> entry ##
 	SKIN_IMPORT_IMAGE(pause_continue, "pause-continue.png", 235, -1)
 	SKIN_IMPORT_IMAGE(pause_retry, "pause-retry.png", 235, -1)
 
-	SKIN_IMPORT_IMAGE(ranking_ss, "ranking-X.png", 160, -1)
-	SKIN_IMPORT_IMAGE(ranking_s, "ranking-S.png", 160, -1)
-	SKIN_IMPORT_IMAGE(ranking_a, "ranking-A.png", 160, -1)
-	SKIN_IMPORT_IMAGE(ranking_b, "ranking-B.png", 160, -1)
-	SKIN_IMPORT_IMAGE(ranking_c, "ranking-C.png", 160, -1)
-	SKIN_IMPORT_IMAGE(ranking_d, "ranking-D.png", 160, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_ss, "ranking-X.png", 160, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_s, "ranking-S.png", 160, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_a, "ranking-A.png", 160, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_b, "ranking-B.png", 160, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_c, "ranking-C.png", 160, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_d, "ranking-D.png", 160, -1)
+	
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_title, "ranking-title.png", 240, -1)
+	SKIN_IMPORT_IMAGE_DITHER64(ranking_panel, "ranking-panel.png", 378, -1)
 	
-//	SKIN_IMPORT_IMAGE(ranking_title, "ranking-title.png", 240, -1)
-//	SKIN_IMPORT_IMAGE(ranking_panel, "ranking-panel.png", 378, -1)
-
 	meta->selection_w = 48;
 	meta->selection_h = 56;
 	meta->selection_mod = addr;
@@ -148,6 +155,10 @@ addr = img_write_rgb16(cbuf, dev, addr, &(meta-> entry ## _w), &(meta-> entry ##
 
 	#pragma clang diagnostic pop
 	
+	// Score fonts
+	addr = font_score_write(dirname, dev, addr);
+	meta->font_score = addr-1;
+	
 	// Update meta addr
 	meta->available_block = addr;
 }
@@ -265,6 +276,15 @@ osu_song osu_read_osu(const char *filename, mdev *dev, osu_meta *meta,
 		void(0);
 	}
 
+	uint32_t addr = meta->available_block;
+	uint8_t *sbbuf = (uint8_t *) ret.storyboard;
+	ret.beatmap_begin = addr;
+	ret.beatmap_len = 4096;
+	for (int i=0; i<4096; i++) {
+		blkio_write(dev, addr++, sbbuf+512*i);
+	}
+	meta->available_block = addr;
+	
 	strncpy(ret.magic, "BEAT", 4);
 
 	printf("Parsing done. Performing sanity check...\n");
@@ -281,7 +301,7 @@ int osu_parse_general(char *line, osu_song *song,
 		return 1;
 	}
 	// AudioFilename (String) specifies the location of the audio file relative to the current folder.
-	if (0 && strcasecmp(key, "AudioFilename") == 0) {
+	if (strcasecmp(key, "AudioFilename") == 0) {
 		if (cont->fs.find(val) == cont->fs.end()) {
 			printf("Allocating storage for audio %s\n", val);
 			uint32_t addr = meta->available_block;
@@ -481,7 +501,6 @@ int osu_parse_difficulty(char *line, osu_song *song,
 int osu_parse_events(char *line, osu_song *song,
 					 mdev *dev, osu_meta *meta, osu_dir *cont) {
 	// Events section is in CSV format
-	return 0;
 	switch (line[0]) {
 		case '0': {
 			// Background image
diff --git a/osufs/osufs/osu_object_analyze/osu_object_includes.h b/osufs/osufs/osu_object_analyze/osu_object_includes.h
index 3dd16acf3500335e65e1fdd359cc12548d298d40..eb1752a1660bbbf885a857d32ad03b400bb06d39 100644
--- a/osufs/osufs/osu_object_analyze/osu_object_includes.h
+++ b/osufs/osufs/osu_object_analyze/osu_object_includes.h
@@ -17,7 +17,7 @@ typedef struct __attribute__((__packed__)) hit_circle_t{
 	uint16_t approach_rate;
 	uint16_t gradient_color1;
 	uint16_t gradient_color2;
-	uint8_t gradient_direction;
+	uint8_t hit_sound;
 	char type;
 } elem_hit_circle;
 
diff --git a/osufs/osufs/osu_object_analyze/osu_object_parser.cpp b/osufs/osufs/osu_object_analyze/osu_object_parser.cpp
index 4f91e350ce94f7e79e87dfe168c9784ceb7dfe24..bdadffa5369db3f6ab15e694e8b34f011d1f32ce 100644
--- a/osufs/osufs/osu_object_analyze/osu_object_parser.cpp
+++ b/osufs/osufs/osu_object_analyze/osu_object_parser.cpp
@@ -62,7 +62,7 @@ int osu_parse_hit_object(char* line, osu_song* song){
 	
 	//hit sound 
 	//elemn->hit_sound = stoi(v[4]); //
-//	elemn->hit_sound = 1; // TODO
+	sscanf(v[4].c_str(),"%c",&(elemn->hit_sound)); // 
 
 	//handle timing stuff
 	int temp_c = 0;
@@ -79,15 +79,20 @@ int osu_parse_hit_object(char* line, osu_song* song){
 	}
 	//update count and data block
 	if (!song->storyboard){
-		song->storyboard = (uint8_t *) malloc(4+4+32*temp_c);
-		*((uint32_t*)(song->storyboard)) = 0b01110010011001010110000101101100;
+		song->storyboard = (osu_storyboard*) malloc(sizeof(osu_storyboard));
+		/**((uint32_t*)(song->storyboard)) = 0b01110010011001010110000101101100;
 		*((uint32_t*)(song->storyboard)+1) = temp_c;
-		memcpy(song->storyboard+8,elemn,32*temp_c);
+		memcpy(song->storyboard+8,elemn,32*temp_c);*/
+		song->storyboard->magic = 0b01110010011001010110000101101100;
+		song->storyboard->object_number = temp_c;
 	}else{
-		song->storyboard = (uint8_t *) realloc(song->storyboard,4+4+
+		/*song->storyboard = (uint8_t *) realloc(song->storyboard,4+4+
 			32*(temp_c+(*((uint32_t*)(song->storyboard)+1))));
 		memcpy(song->storyboard+8+32*(*((uint32_t*)(song->storyboard)+1)),elemn,32*temp_c);
-		*((uint32_t*)(song->storyboard)+1) += temp_c;
+		*((uint32_t*)(song->storyboard)+1) += temp_c;*/
+		memcpy(song->storyboard->object_list,
+			   elemn,temp_c*sizeof(elem_hit_circle));
+		song->storyboard->object_number += temp_c;
 	}
 	free(elemn);
 	return 0;
diff --git a/osufs/osufs/osufs.h b/osufs/osufs/osufs.h
index a4b2458c5295aad0cc84876f89f4f3ffbc592321..2b260c3205ace6cb5c90af1d4d8b518e359a9705 100644
--- a/osufs/osufs/osufs.h
+++ b/osufs/osufs/osufs.h
@@ -16,7 +16,7 @@ extern "C" {
 #include <stdio.h>
 #include <inttypes.h>
 #include "blkio.h"
-
+#include "osu_object_analyze/osu_object_includes.h"
 
 	typedef struct __attribute__((__packed__)) osu_meta_t {
 		char magic[4];							// 0   - 3
@@ -209,6 +209,13 @@ extern "C" {
 		char _padding[27];						// 486 - 511
 	} osu_font;
 	
+	typedef struct __attribute__((__packed__)) storyboard_t {
+		uint32_t magic;							//4
+		uint32_t object_number;					//4
+		elem_hit_circle object_list[65535];		//fill a total of 4096 blocks
+		char _padding[24];						//32-8 = 24
+	} osu_storyboard;
+
 	typedef struct __attribute__((__packed__)) osu_song_t {
 		char magic[4];							// 0   - 3
 		uint32_t cover_begin, cover_len;		// 4   - 11
@@ -228,7 +235,7 @@ extern "C" {
 		uint16_t stack_leniency;				// 78  - 79
 
 		//for analyze side only
-		uint8_t *storyboard;					// 80 - 87
+		osu_storyboard *storyboard;					// 80 - 87
 		uint8_t combo_colors_count;				// 88
 		uint8_t combo_colors_start;				// 89
 		uint8_t combo_slider_color[3];			// 90 - 92
@@ -241,7 +248,8 @@ extern "C" {
 		char creator[32];						// 448 - 479
 		char version[32];						// 480 - 511
 	} osu_song;
-	
+
+
 	osu_meta osu_read_meta(mdev *dev);
 	osu_song osu_read_song(mdev *dev, int idx);
 	void osu_write_meta(mdev *dev, osu_meta *meta);