changeset 53:ddbcbd000206

* MuSys, AyuSysConfig, FileSearcher (former FILESEARCHER) and KeyHolder (former KEYHOLDER) are now singletons * ParseMoji moved to TextStream * Some cleaning (0 -> NULL when needed, removal of useless returns, ...)
author thib
date Sun, 19 Apr 2009 11:44:05 +0000
parents 15a18fbe6f21
children d7cde171a1de
files font/font.h font/font_layout.cc font/text.h font/text_stream.cc music2/koedec.cc music2/movie.cc music2/music.cc music2/music.h scn2k/scn2k.h scn2k/scn2k_grp.cc scn2k/scn2k_impl.cc scn2k/scn2k_impl.h scn2k/scn2k_text.cc system/file.cc system/file.h system/system_config.cc system/system_config.h window/picture.cc window/widget.cc xlovesys.cc
diffstat 20 files changed, 609 insertions(+), 496 deletions(-) [+]
line wrap: on
line diff
--- a/font/font.h
+++ b/font/font.h
@@ -107,6 +107,7 @@ namespace XKFont {
 			~HorizLayout();
 			void Layout(::TextStream& stream, ::TextGlyphStream& glyph, std::vector<int>& lineheights, int width);
 			::TextGlyphStream Layout(const char* str, int width, int r=0xff, int g=0xff, int b=0xff);
+			::TextGlyphStream Layout(TextStream ts, int width);
 		private:
 			Font* font;
 			class ::TextHorizLayout* pimpl;
--- a/font/font_layout.cc
+++ b/font/font_layout.cc
@@ -511,6 +511,10 @@ namespace XKFont {
 		TextStream s;
 		s.SetColor(r,gc,b);
 		s.Add(str);
+		return Layout(s, width);
+	}
+
+	TextGlyphStream HorizLayout::Layout(TextStream s, int width) {
 		TextGlyphStream g;
 		vector<int> h;
 		Layout(s, g, h, width);
--- a/font/text.h
+++ b/font/text.h
@@ -51,32 +51,38 @@ struct TextElem {
 	} impl;
 };
 			
-struct TextStream {
-	std::vector<TextElem> container;
-	typedef std::vector<TextElem>::iterator Iterator;
-	enum {sjis, euc} kanji_type;
+class TextStream {
+	public:
+		TextStream(void);
+		TextStream& operator =(const TextStream& from) {
+			container = from.container;
+			kanji_type = from.kanji_type;
+			return *this;
+		}
 
-	std::string Save(void);
-	void Load(const std::string&);
+		static TextStream ParseMoji(const char* str, int r, int g, int b, int size);
+
+		std::string Save(void);
+		void Load(const std::string&);
 
-	void SetSize(double size);
-	void SetColor(unsigned char r, unsigned char g, unsigned char b);
-	void SetDefaultColor(unsigned char r, unsigned char g, unsigned char b);
-	void InsertColor(int begin_pos, int end_pos, unsigned char r, unsigned char g, unsigned char b);
-	void Clear(void);
-	void Add(const char* str);
-	void AddReturn(void);
-	void AddName(const char* name);
-	void AddRuby(const char* str, const char* ruby);
+		void SetSize(double size);
+		void SetColor(unsigned char r, unsigned char g, unsigned char b);
+		void SetDefaultColor(unsigned char r, unsigned char g, unsigned char b);
+		void InsertColor(int begin_pos, int end_pos, unsigned char r, unsigned char g, unsigned char b);
+		void Clear(void);
+		void Add(const char* str);
+		void AddReturn(void);
+		void AddName(const char* name);
+		void AddRuby(const char* str, const char* ruby);
 
-	void RemoveName(char* name, int namelen);
+		void RemoveName(char* name, int namelen);
 
-	TextStream(void);
-	TextStream& operator =(const TextStream& from) {
-		container = from.container;
-		kanji_type = from.kanji_type;
-		return *this;
-	}
+	public:
+		std::vector<TextElem> container;
+		typedef std::vector<TextElem>::iterator Iterator;
+
+		enum {sjis, euc} kanji_type;
+
 };
 
 namespace XKFont {
--- a/font/text_stream.cc
+++ b/font/text_stream.cc
@@ -29,6 +29,8 @@
 #include "codeconv.h"
 #include <string.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include "system/system_config.h"
 
 /************************************************************************
 **
@@ -36,6 +38,84 @@
 **
 */
 
+static char* wstrchr(const char* s, unsigned int chr) {
+	int ws, wc;
+	while(*s != 0) {
+		if (*s < 0 && s[1] != 0) {
+			wc = int((unsigned char)(s[0]))*0x100 + int((unsigned char)(s[1]));
+			ws = 2;
+		} else {
+			wc = (unsigned char)(s[0]);
+			ws = 1;
+		}
+		if (wc == chr) return (char*)s;
+		s += ws;
+	}
+	return NULL;
+}
+
+TextStream TextStream::ParseMoji(const char* str, int def_r, int def_g, int def_b, int def_size) {
+	TextStream ts;
+	ts.kanji_type = TextStream::sjis;
+	ts.SetColor(def_r, def_g, def_b);
+	char* copy_str = new char[strlen(str)+1];
+	char* next_str;
+	char* retptr;
+	int var;
+
+	while( (next_str = wstrchr(str, '#')) != NULL) {
+		int len = next_str - str;
+		strncpy(copy_str, str, len);
+		copy_str[len] = 0;
+		ts.Add(copy_str);
+		str = next_str + 1;
+
+		switch(str[0]) {
+		case '#': // separator
+			str += 1;
+			break;
+		case 'D': case 'd': // return
+			ts.AddReturn();
+			str += 1;
+			break;
+		case 'C': case 'c': // color
+			str += 1;
+			var = strtol(str, &next_str,10);
+			if (var == 0 && str == next_str) { // no parameter
+				ts.SetColor(def_r, def_g, def_b);
+			} else {
+				int r,g,b; char key[1024];
+				sprintf(key, "#COLOR_TABLE.%03d", var);
+				if (AyuSysConfig::GetInstance()->GetParam(key, 3, &r, &g, &b)) { // color not found
+					r = g = b = 0;
+				}
+				ts.SetColor(r, g, b);
+				str = next_str;
+			}
+			break;
+		case 'S': case 's': // size
+			str += 1;
+			var = strtol(str, &next_str, 10);
+			if (var == 0 && str == next_str) { // no parameter
+				ts.SetSize(1);
+			} else {
+				if (def_size == 0) def_size = 20;
+				if (var <= 0) var = 1;
+				ts.SetSize(double(var)/def_size);
+			}
+			break;
+		case 'X': case 'x': // xpos : not supported
+		case 'Y': case 'y': // ypos : not supported
+		default:
+			ts.Add("#");
+			break;
+		}
+	}
+	ts.Add(str);
+	delete[] copy_str;
+	return ts;
+}
+
 TextStream::TextStream(void) {
 	kanji_type = euc;
 }
@@ -95,33 +175,6 @@ void TextStream::Add(const char* str) {
 	TextElem elem;
 	for (; *str; str++) {
 		if (*str >= 0x20) {
-			if (*str == '#') { // Commands
-				str++;
-				char command = (*str)|32;
-				str++;
-				const char *tmp = str;
-				while (isdigit(*str)) {
-					str++;
-				}
-				char *args = new char[str+1-tmp];
-				strncpy(args, tmp, str-tmp);
-				args[str-tmp] = 0;
-				// Different commands:
-				switch(command) {
-					case 'c':
-						/*TODO: int r, g, b; char key[17];
-						sprintf(key, "#COLOR_TABLE.%03d", args);
-						if (config.GetParam(key, 3, &r, &g, &b)) { // color not found
-							r = g = b = 0;
-						}
-						elem.type = TextElem::color;
-						elem.impl.Color.r = r;
-						elem.impl.Color.g = g;
-						elem.impl.Color.b = b;*/
-						break;
-				}
-				delete[] args;
-			}
 			elem.type = TextElem::glyph;
 			elem.impl.Glyph.code = *str;
 		} else if (*str < 0 && str[1] != 0) {
--- a/music2/koedec.cc
+++ b/music2/koedec.cc
@@ -96,6 +96,8 @@ AvgKoeInfo AvgKoeCache::Find(int file_nu
 	info.length = 0;
 	info.offset = 0;
 
+	FileSearcher* file_searcher = FileSearcher::GetInstance();
+
 	list<AvgKoeHead>::iterator it;
 	it = find(cache.begin(), cache.end(), file_number);
 	if (it == cache.end()) {
@@ -103,21 +105,21 @@ AvgKoeInfo AvgKoeCache::Find(int file_nu
 		char fname[100];
 		KoeType type = koe_unknown;
 		sprintf(fname, "z%03d.koe", file_number);
-		ARCINFO* arcinfo = file_searcher.Find(FILESEARCH::KOE,fname,".koe");
+		ARCINFO* arcinfo = file_searcher->Find(FileSearcher::KOE,fname,".koe");
 		if (arcinfo == NULL) {
 			type = koe_nwk;
 			sprintf(fname, "z%04d.nwk", file_number);
-			arcinfo = file_searcher.Find(FILESEARCH::KOE,fname,".nwk");
+			arcinfo = file_searcher->Find(FileSearcher::KOE,fname,".nwk");
 		}
 		if (arcinfo == NULL) {
 			type = koe_ovk;
 			sprintf(fname, "z%04d.ovk", file_number);
-			arcinfo = file_searcher.Find(FILESEARCH::KOE,fname,".ovk");
+			arcinfo = file_searcher->Find(FileSearcher::KOE,fname,".ovk");
 		}
 #if HAVE_LIBVORBISFILE || HAVE_LIBVORBISIDEC
 		if (arcinfo == NULL) {
 			//FIXME: OMG that's ugly, improve it as soon as you can!
-			DIRFILE* koedir = (DIRFILE*) file_searcher.MakeARCFILE((FILESEARCH::ARCTYPE)0, "koe");
+			DIRFILE* koedir = (DIRFILE*) file_searcher->MakeARCFILE((FileSearcher::ARCTYPE)0, "koe");
 			sprintf(fname, "%04d", file_number);
 			char* dirname = koedir->SearchFile(fname);
 			delete koedir;
--- a/music2/movie.cc
+++ b/music2/movie.cc
@@ -71,9 +71,10 @@ void MuSys::PlayMovie(const char* path, 
 }
 
 const char* FindMovieFile(const char* path) {
-	ARCINFO* info = file_searcher.Find(FILESEARCH::MOV, path, "avi");
+	FileSearcher* file_searcher = FileSearcher::GetInstance();
+	ARCINFO* info = file_searcher->Find(FileSearcher::MOV, path, "avi");
 	if (info == NULL)
-		info = file_searcher.Find(FILESEARCH::MOV,path,"mpg");
+		info = file_searcher->Find(FileSearcher::MOV,path,"mpg");
 	if (info == NULL) return NULL;
 	const char* file = info->Path();
 	delete info;
--- a/music2/music.cc
+++ b/music2/music.cc
@@ -34,8 +34,8 @@
 #include <fcntl.h>
 #include <ctype.h>
 #include <signal.h>
-#include"system/system_config.h"
-#include"system/file.h"
+#include "system/system_config.h"
+#include "system/file.h"
 #include "music.h"
 #include <SDL.h>
 #include <SDL_mixer.h>
@@ -43,11 +43,27 @@
 
 using namespace std;
 
-int pcm_enable = 0;
-Mix_Chunk *play_chunk[MIX_PCM_SIZE];
+MuSys * MuSys::_singleton = NULL;
+
+MuSys* MuSys::GetInstance(void)
+{
+	if (_singleton == NULL)
+		_singleton = new MuSys;
+	return _singleton;
+}
 
-MuSys::MuSys(AyuSysConfig& _config) : config(_config), movie_id(-1), music_enable(1) {
+void MuSys::Quit(void)
+{
+	if (_singleton != NULL) {
+		_singleton->FinalizeMusic();
+		delete _singleton;
+		_singleton = NULL;
+	}
+}
+
+MuSys::MuSys() : movie_id(-1), music_enable(1) {
 	int i;
+	config = AyuSysConfig::GetInstance();
 	for (i=0; i<MIX_PCM_SIZE; i++)
 		play_chunk[i] = 0;
 	cdrom_track[0] = 0;
@@ -57,12 +73,12 @@ MuSys::MuSys(AyuSysConfig& _config) : co
 
 // #define delete fprintf(stderr,"smus.cc: %d.",__LINE__), delete
 
-void bgm_start(const char* path, int loop_pt, int * volmod);
-void effec_start(int chn, const char* path, int loop, int fadein_time, int * volmod);
+void bgm_start(const char* path, int loop_pt);
+void effec_start(int chn, const char* path, int loop, int fadein_time);
 void bgm_fadeout(int time);
 
 void MuSys::PlayCDROM(char* name, int play_count) {
-	config.GetParam("#VOLMOD", 4, &volmod[0], &volmod[1], &volmod[2], &volmod[3]);
+	config->GetParam("#VOLMOD", 4, &volmod[0], &volmod[1], &volmod[2], &volmod[3]);
 
 	char wave[128];
 	wave[127] = '\0';
@@ -74,9 +90,10 @@ void MuSys::PlayCDROM(char* name, int pl
 	strcpy(cdrom_track, name);
 
 	/* name -> track */
-	int track =config.track_name.CDTrack(name);
+	int track =config->track_name.CDTrack(name);
 	if (track == -1) track = atoi(name);
-	if (config.track_name.WaveTrack(name) != NULL) strncpy(wave, config.track_name.WaveTrack(name), 127);
+	if (config->track_name.WaveTrack(name) != NULL)
+		strncpy(wave, config->track_name.WaveTrack(name), 127);
 	if (wave[0] == 0 && track != 0) { /* DSTRACK が見つからない場合、CDTRACKを使用する */
 		sprintf(wave, "audio_%02d", track);
 	}
@@ -84,9 +101,9 @@ void MuSys::PlayCDROM(char* name, int pl
 	// BGM 再生
 	if (!pcm_enable) return;
 	if (play_count == 0)
-		bgm_start(wave, -1, volmod);
+		bgm_start(wave, -1);
 	else
-		bgm_start(wave, config.track_name.TrackStart(name), volmod);
+		bgm_start(wave, config->track_name.TrackStart(name));
 	return;
 }
 
@@ -100,16 +117,16 @@ void MuSys::StopCDROM(int time)
 void MuSys::PlaySE(const char* se, int loop_flag, int channel) {
 	if (!pcm_enable) return;
 	if (loop_flag)
-		effec_start(MIX_PCM_EFFEC, se, 10000, 0, volmod);
+		effec_start(MIX_PCM_EFFEC, se, 10000, 0);
 	else
-		effec_start(MIX_PCM_EFFEC, se, 0, 0, volmod);
+		effec_start(MIX_PCM_EFFEC, se, 0, 0);
 	return;
 }
 void MuSys::PlaySE(int number) {
 	if (! pcm_enable) return;
-	const char* se_name = config.track_name.SETrack(number);
+	const char* se_name = config->track_name.SETrack(number);
 	if (se_name == NULL) return;
-	effec_start(MIX_PCM_EFFEC, se_name, 0, 0, volmod);
+	effec_start(MIX_PCM_EFFEC, se_name, 0, 0);
 	return;
 }
 void MuSys::StopSE(int time) {
@@ -148,8 +165,8 @@ void MuSys::InitMusic(void)
 	pcm_enable = 1;
 	Mix_AllocateChannels( MIX_PCM_SIZE);
 	music_enable = 2;
-	return;
 }
+
 void MuSys::FinalizeMusic(void)
 {
 	if (music_enable != 2) return;
@@ -235,8 +252,10 @@ void bgm_fadeout(int time) {
 
 static SDL_RWops* OpenSDLRW(const char* path);
 static WAVFILE* OpenWaveFile(const char* path);
-void bgm_start(const char* path, int loop_pt, int * volmod) {
-	if (! pcm_enable) return;
+void bgm_start(const char* path, int loop_pt) {
+	MuSys* mu = MuSys::GetInstance();
+
+	if (!mu->pcm_enable) return;
 fprintf(stderr,"bgm start %s\n",path);
 	WAVFILE* wav = OpenWaveFile(path);
 	if (wav == NULL) return;
@@ -250,35 +269,41 @@ fprintf(stderr,"bgm start %s\n",path);
 	}
 	wav_playing.wav = wav;
 	wav_playing.loop_pt = loop_pt;
-	wav_playing.volmod = &volmod[0];
+	wav_playing.volmod = mu->volmod;
 	fadetime_total = 0;
 	fadecount = 0;
 	Mix_HookMusic( &(WavChunk::callback), (void*)&wav_playing);
 }
 
-void effec_start(int chn, const char* path, int loop, int fadein_time, int * volmod) {
-	if (! pcm_enable) return;
+void effec_start(int chn, const char* path, int loop, int fadein_time) {
+	MuSys* mu = MuSys::GetInstance();
+
+	if (!mu->pcm_enable) return;
+
 	SDL_RWops* op = OpenSDLRW(path);
 	if (op == NULL) { // ファイルが見付からない
 		return;
 	}
 	Mix_Pause(chn);
 
-	if (play_chunk[chn]) {
-		Mix_FreeChunk(play_chunk[chn]);
+	if (mu->play_chunk[chn] != NULL) {
+		Mix_FreeChunk(mu->play_chunk[chn]);
 	}
-	play_chunk[chn] = Mix_LoadWAV_RW(op, 1);
+	mu->play_chunk[chn] = Mix_LoadWAV_RW(op, 1);
 	if (fadein_time <= 0) {
-		Mix_Volume(chn, volmod[3]*SDL_MIX_MAXVOLUME/255);
-		Mix_PlayChannel(chn, play_chunk[chn], loop);
+		Mix_Volume(chn, mu->volmod[3]*SDL_MIX_MAXVOLUME/255);
+		Mix_PlayChannel(chn, mu->play_chunk[chn], loop);
 	} else {
-		Mix_Volume(chn, volmod[3]*SDL_MIX_MAXVOLUME/255);
-		Mix_FadeInChannel(chn, play_chunk[chn], loop, fadein_time);
+		Mix_Volume(chn, mu->volmod[3]*SDL_MIX_MAXVOLUME/255);
+		Mix_FadeInChannel(chn, mu->play_chunk[chn], loop, fadein_time);
 	}
 }
 
 void MuSys::PlayKoe(const char* path) {
 	if (!pcm_enable) return;
+
+	MuSys* mu = MuSys::GetInstance();
+
 	static char* playing_koedata = NULL;
 	int len = 0;
 	AvgKoeInfo koeinfo;
@@ -286,14 +311,14 @@ void MuSys::PlayKoe(const char* path) {
 
 	Mix_Pause(chn);
 	Mix_HaltChannel(chn); // これで RWop が解放されるはず…
-	if (play_chunk[chn]) {
-		Mix_FreeChunk(play_chunk[chn]);
-		play_chunk[chn] = 0;
+	if (mu->play_chunk[chn] != NULL) {
+		Mix_FreeChunk(mu->play_chunk[chn]);
+		mu->play_chunk[chn] = NULL;
 	}
 
-	if (playing_koedata) {
+	if (playing_koedata != NULL) {
 		free(playing_koedata);
-		playing_koedata = 0;
+		playing_koedata = NULL;
 	}
 
 	koeinfo = OpenKoeFile(path);
@@ -304,9 +329,9 @@ void MuSys::PlayKoe(const char* path) {
 	if (playing_koedata == NULL) {
 		return;
 	}
-	Mix_Volume(chn, volmod[1]*SDL_MIX_MAXVOLUME/255);
-	play_chunk[chn] = Mix_LoadWAV_RW(SDL_RWFromMem(playing_koedata, len+0x2c), 1);
-	Mix_PlayChannel(chn, play_chunk[chn], 0);
+	Mix_Volume(chn, mu->volmod[1]*SDL_MIX_MAXVOLUME/255);
+	mu->play_chunk[chn] = Mix_LoadWAV_RW(SDL_RWFromMem(playing_koedata, len+0x2c), 1);
+	Mix_PlayChannel(chn, mu->play_chunk[chn], 0);
 }
 
 AvgKoeInfo OpenKoeFile(const char* path) {
@@ -324,7 +349,7 @@ AvgKoeInfo OpenKoeFile(const char* path)
 		info = FindKoe(file_no, index);
 	} else { // ファイル
 		int length;
-		ARCINFO* arcinfo = file_searcher.Find(FILESEARCH::KOE, path, ".WPD");
+		ARCINFO* arcinfo = FileSearcher::GetInstance()->Find(FileSearcher::KOE, path, ".WPD");
 		if (arcinfo == NULL) return info;
 		info.stream = arcinfo->OpenFile(&length);
 		info.rate = 22050;
@@ -338,10 +363,11 @@ AvgKoeInfo OpenKoeFile(const char* path)
 
 static SDL_RWops* OpenSDLRW(const char* path) {
 	/* まず wav ファイルを探す */
-	ARCINFO* info = file_searcher.Find(FILESEARCH::WAV, path, ".wav");
+	FileSearcher* file_searcher = FileSearcher::GetInstance();
+	ARCINFO* info = file_searcher->Find(FileSearcher::WAV, path, ".wav");
 	if (info == NULL) {
-		info = file_searcher.Find(FILESEARCH::WAV, path, ".nwa");
-		if (info == NULL) info = file_searcher.Find(FILESEARCH::BGM, path, "nwa");
+		info = file_searcher->Find(FileSearcher::WAV, path, ".nwa");
+		if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "nwa");
 		if (info != NULL) { // read NWA file
 			int dummy;
 			FILE* f = info->OpenFile(&dummy);
@@ -352,8 +378,8 @@ static SDL_RWops* OpenSDLRW(const char* 
 			return SDL_RWFromMem(d, sz);
 		}
 	}
-	if (info == NULL) info = file_searcher.Find(FILESEARCH::BGM, path, "wav");
-	if (info == NULL) info = file_searcher.Find(FILESEARCH::WAV, path, ".ogg");
+	if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "wav");
+	if (info == NULL) info = file_searcher->Find(FileSearcher::WAV, path, ".ogg");
 	if (info != NULL) {
 		int dummy;
 		FILE* f = info->OpenFile(&dummy);
@@ -367,8 +393,9 @@ static SDL_RWops* OpenSDLRW(const char* 
 
 static WAVFILE* OpenWaveFile(const char* path) {
 	/* まず wav ファイルを探す */
-	ARCINFO* info = file_searcher.Find(FILESEARCH::WAV, path, ".wav");
-	if (info == NULL) info = file_searcher.Find(FILESEARCH::BGM, path, "wav");
+	FileSearcher* file_searcher = FileSearcher::GetInstance();
+	ARCINFO* info = file_searcher->Find(FileSearcher::WAV, path, ".wav");
+	if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "wav");
 	if (info != NULL) {
 		int size;
 		FILE* f = info->OpenFile(&size);
@@ -378,8 +405,8 @@ static WAVFILE* OpenWaveFile(const char*
 		return w;
 	}
 	/* 次に nwa ファイル */
-	info = file_searcher.Find(FILESEARCH::WAV, path, ".nwa");
-	if (info == NULL) info = file_searcher.Find(FILESEARCH::BGM, path, "nwa");
+	info = file_searcher->Find(FileSearcher::WAV, path, ".nwa");
+	if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "nwa");
 	if (info != NULL) {
 		int size;
 		FILE* f = info->OpenFile(&size);
@@ -390,8 +417,8 @@ static WAVFILE* OpenWaveFile(const char*
 	}
 
 	/* 次に mp3 ファイル */
-	info = file_searcher.Find(FILESEARCH::WAV, path, ".mp3");
-	if (info == NULL) info = file_searcher.Find(FILESEARCH::BGM, path, "mp3");
+	info = file_searcher->Find(FileSearcher::WAV, path, ".mp3");
+	if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "mp3");
 	if (info != NULL) {
 		int size;
 		FILE* f = info->OpenFile(&size);
@@ -405,8 +432,8 @@ static WAVFILE* OpenWaveFile(const char*
 	}
 
 	/* 次に ogg ファイル */
-	info = file_searcher.Find(FILESEARCH::WAV, path, ".ogg");
-	if (info == NULL) info = file_searcher.Find(FILESEARCH::BGM, path, "ogg");
+	info = file_searcher->Find(FileSearcher::WAV, path, ".ogg");
+	if (info == NULL) info = file_searcher->Find(FileSearcher::BGM, path, "ogg");
 	if (info != NULL) {
 		int size;
 		FILE* f = info->OpenFile(&size);
--- a/music2/music.h
+++ b/music2/music.h
@@ -33,8 +33,9 @@
 #  include "config.h"
 #endif
 
-#include<sys/types.h>
-#include<sys/time.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <SDL_mixer.h>
 
 #define MIX_PCM_BGM	4
 #define MIX_PCM_EFFEC	5
@@ -53,8 +54,6 @@ typedef struct {
 	KoeType type;
 } AvgKoeInfo;
 
-extern int pcm_enable;
-
 /* koedec.cc */
 extern AvgKoeInfo OpenKoeFile(const char* path);
 extern char* decode_koe(AvgKoeInfo info, int* len);
@@ -62,28 +61,40 @@ extern char* decode_koe_nwa(AvgKoeInfo i
 extern const char* MakeWavHeader(int rate, int ch, int bps, int size);
 extern AvgKoeInfo FindKoe(int file_number, int index);
 
-#include<unistd.h>
-struct MuSys {
-	class AyuSysConfig& config;
-	char cdrom_track[128]; char effec_track[128];
-	int movie_id;
-	int music_enable;
-	int volmod[4]; // BGM, KOE, PCM, Se
-	MuSys(AyuSysConfig& _config);
+#include <unistd.h>
 
-	void PlayCDROM(char* name, int play_count);
-	void StopCDROM(int time);
-	void PlaySE(const char* name, int loop_flag=0, int channel=0);
-	void PlaySE(int number);
-	void StopSE(int time = 0);
-	bool IsStopSE(void);
-	void PlayKoe(const char* fname);
-	void StopKoe(int time);
-	void PlayMovie(const char* fname, int x1, int y1, int x2, int y2, int loop_count);
-	void StopMovie(void);
-	bool IsStopMovie(void);
-	void InitMusic(void);
-	void FinalizeMusic(void);
+class MuSys {
+	public:
+		static MuSys* GetInstance(void);
+		static void Quit(void);
+		void PlayCDROM(char* name, int play_count);
+		void StopCDROM(int time);
+		void PlaySE(const char* name, int loop_flag=0, int channel=0);
+		void PlaySE(int number);
+		void StopSE(int time = 0);
+		bool IsStopSE(void);
+		void PlayKoe(const char* fname);
+		void StopKoe(int time);
+		void PlayMovie(const char* fname, int x1, int y1, int x2, int y2, int loop_count);
+		void StopMovie(void);
+		bool IsStopMovie(void);
+		void InitMusic(void);
+		void FinalizeMusic(void);
+
+	private:
+		MuSys();
+
+	public:
+		int volmod[4]; // BGM, KOE, PCM, Se
+		int pcm_enable;
+		Mix_Chunk *play_chunk[MIX_PCM_SIZE];
+
+	private:
+		class AyuSysConfig *config;
+		char cdrom_track[128]; char effec_track[128];
+		int movie_id;
+		int music_enable;
+		static MuSys *_singleton;
 };
 
 #endif /* __MUSIC__ */
--- a/scn2k/scn2k.h
+++ b/scn2k/scn2k.h
@@ -227,7 +227,7 @@ class Text {
 	public:
 		std::vector<BacklogItem> backlog;
 		BacklogItem backlog_item;
-		Text(Event::Container& _event, PicContainer& _parent, AyuSysConfig& config);
+		Text(Event::Container& _event, PicContainer& _parent);
 		~Text();
 		void InitWindow(void);
 		void Exec(Cmd& cmd);
@@ -247,12 +247,12 @@ class Grp {
 	private:
 		class GrpImpl* pimpl;
 	public:
-		Grp(Event::Container& _event, PicContainer& _parent, const Flags& f, std::set<int>& _cgm_data, class MuSys& mu, AyuSysConfig& config);
+		Grp(Event::Container& _event, PicContainer& _parent, const Flags& f, std::set<int>& _cgm_data);
 		~Grp();
 		bool Wait(unsigned int current_time, Cmd& cmd);
 		void Exec(Cmd& cmd);
 		void SetSkipMode(SkipMode mode);
-		void InitSel(AyuSysConfig& config);
+		void InitSel(void);
 		void Save(std::string& str);
 		void Load(const char* str);
 		void SaveSys(std::string& str);
--- a/scn2k/scn2k_grp.cc
+++ b/scn2k/scn2k_grp.cc
@@ -101,7 +101,6 @@ struct GrpObj {
 	void SetClipArea(int x, int y, int width, int height);
 	void GetSrcGeom(int& width, int& height);
 	void SetUpdate(void);
-	TextStream ParseMoji(const char* str, int def_r ,int def_g, int def_b, int def_size);
 	void UpdateMoji(void);
 	void UpdateDigit(void);
 	void UpdateSurface(void);
@@ -177,15 +176,15 @@ class GrpImpl {
 		Surface* Ssurface(int pdt);
 
 		// cgmode 用画像処理関連
-		void LoadCgm(AyuSysConfig& config);
+		void LoadCgm(void);
 		std::map<std::string, int> cgm_info;
 		set<int>& cgm_data;
 		int cgm_size;
 		
-		class MuSys& music;
+		class MuSys *music;
 
 	public:
-		AyuSysConfig& config;
+		AyuSysConfig *config;
 		void LoadSurface(const char* str, int pdt);
 
 	private:
@@ -199,11 +198,11 @@ class GrpImpl {
 		static bool Pressed(int x, int y, void* pointer);
 
 	public:
-		GrpImpl(Event::Container& _event, PicContainer& _parent, const Flags& _flag, set<int>& _cgm_data, class MuSys& mu, AyuSysConfig& config);
+		GrpImpl(Event::Container& _event, PicContainer& _parent, const Flags& _flag, set<int>& _cgm_data);
 		~GrpImpl();
 		bool Wait(unsigned int current_time, Cmd& cmd);
 		void Exec(Cmd& cmd);
-		void InitSel(AyuSysConfig& config);
+		void InitSel(void);
 		void Save(std::string& str);
 		void Load(const char* str);
 		void SaveSys(std::string& str);
@@ -313,7 +312,7 @@ void GrpObj::GetSrcGeom(int& width, int&
 		/* g00 ファイルのヘッダ部分に位置情報は入っている */
 		string path(name);
 		path += ".g00";
-		ARCINFO* info = file_searcher.Find(FILESEARCH::PDT, path.c_str(), "g00");
+		ARCINFO* info = FileSearcher::GetInstance()->Find(FileSearcher::PDT, path.c_str(), "g00");
 		if (info == NULL) { // ファイルが見つからない
 			fprintf(stderr, "GrpObj::GetSrcGeom : Cannot find file %s\n", path.c_str());
 			return;
@@ -453,85 +452,6 @@ void GrpObj::ZoomRotate(void) {
 	pic_parent->Root().DeleteSurface(surface_orig);
 }
 
-static char* wstrchr(const char* s, unsigned int chr) {
-	int ws, wc;
-	while(*s != 0) {
-		if (*s < 0 && s[1] != 0) {
-			wc = int((unsigned char)(s[0]))*0x100 + int((unsigned char)(s[1]));
-			ws = 2;
-		} else {
-			wc = (unsigned char)(s[0]);
-			ws = 1;
-		}
-		if (wc == chr) return (char*)s;
-		s += ws;
-	}
-	return NULL;
-}
-
-//TODO: See why it does nothing with font/text_stream.cc:98
-TextStream GrpObj::ParseMoji(const char* str, int def_r ,int def_g, int def_b, int def_size) { // 制御シーケンス付き文字列をparse
-	TextStream ts;
-	ts.kanji_type = TextStream::sjis;
-	ts.SetColor(def_r, def_g, def_b);
-	char* copy_str = new char[strlen(str)+1];
-	char* next_str;
-	char* retptr;
-	int var;
-
-	while( (next_str = wstrchr(str, '#')) != NULL) {
-		int len = next_str - str;
-		strncpy(copy_str, str, len);
-		copy_str[len] = 0;
-		ts.Add(copy_str);
-		str = next_str + 1;
-
-		switch(str[0]) {
-		case '#': // separator
-			str += 1;
-			break;
-		case 'D': case 'd': // return
-			ts.AddReturn();
-			str += 1;
-			break;
-		case 'C': case 'c': // color
-			str += 1;
-			var = strtol(str, &next_str,10);
-			if (var == 0 && str == next_str) { // no parameter
-				ts.SetColor(def_r, def_g, def_b);
-			} else {
-				int r,g,b; char key[1024];
-				sprintf(key, "#COLOR_TABLE.%03d", var);
-				if (parent_pimpl->config.GetParam(key, 3, &r, &g, &b)) { // color not found
-					r = g = b = 0;
-				}
-				ts.SetColor(r, g, b);
-				str = next_str;
-			}
-			break;
-		case 'S': case 's': // size
-			str += 1;
-			var = strtol(str, &next_str, 10);
-			if (var == 0 && str == next_str) { // no parameter
-				ts.SetSize(1);
-			} else {
-				if (def_size == 0) def_size = 20;
-				if (var <= 0) var = 1;
-				ts.SetSize(double(var)/def_size);
-			}
-			break;
-		case 'X': case 'x': // xpos : not supported
-		case 'Y': case 'y': // ypos : not supported
-		default:
-			ts.Add("#");
-			break;
-		}
-	}
-	ts.Add(str);
-	delete[] copy_str;
-	return ts;
-}
-
 void GrpObj::UpdateMoji(void) { // 文字の大きさ、色などを変更
 	if (print_moji.length() == 0 || print_size <= 2) return;
 	if (pic_parent == 0) return;
@@ -544,7 +464,7 @@ void GrpObj::UpdateMoji(void) { // 文字の大きさ、色などを変更
 		g = print_g;
 		b = print_b;
 	}
-	TextStream ts = ParseMoji(print_moji.c_str(), r, g, b, print_size);
+	TextStream ts = TextStream::ParseMoji(print_moji.c_str(), r, g, b, print_size);
 	TextGlyphStream gs;
 	vector<int> lh;
 	// とりあえず drawable width は充分に大きく(2048)取る
@@ -646,7 +566,7 @@ void GrpObj::CreateGan(Event::Container&
 	/* アニーメション情報 (.GAN ファイル)を求める */
 	string path(gan_name);
 	path += ".gan";
-	ARCINFO* info = file_searcher.Find(FILESEARCH::GAN, path.c_str(), "gan");
+	ARCINFO* info = FileSearcher::GetInstance()->Find(FileSearcher::GAN, path.c_str(), "gan");
 	if (info == NULL) {
 		fprintf(stderr,"GrpObj::CreateGan: Cannot Find 'GAN' file %s\n", path.c_str());
 		return;
@@ -826,23 +746,25 @@ void ScnGrpAnm::Exec(int count) {
 
 #include "music2/music.h"
 
-GrpImpl::GrpImpl(Event::Container& _event, PicContainer& _parent, const Flags& f, set<int>& _cgm_data, class MuSys& _mu, AyuSysConfig& _config) :
+GrpImpl::GrpImpl(Event::Container& _event, PicContainer& _parent, const Flags& f, set<int>& _cgm_data):
 	event(_event),
 	flags(f), 
 	parent(_parent),
 	status(NORMAL),
 	skip_mode(SKIP_NO),
-	music(_mu),
 	cgm_data(_cgm_data),
 	grpobj(this),
-	bs_obj(this),
-	config(_config)
+	bs_obj(this)
 {
 	int i;
 	for (i=0; i<MAXPDT; i++) {
 		ssurface[i] = 0;
 		dsurface[i] = 0;
 	}
+
+	music = MuSys::GetInstance();
+	config = AyuSysConfig::GetInstance();
+
 	screen = parent.create_leaf(Rect(0, 0, parent.Width(), parent.Height()), 0);
 	screen_front = parent.create_leaf(Rect(0, 0, parent.Width(), parent.Height()), 0);
 	surface = parent.Root().NewSurface(parent.Width(), parent.Height(), NO_MASK);
@@ -854,9 +776,10 @@ GrpImpl::GrpImpl(Event::Container& _even
 	screen_front->hide();
 	screen_front->ZMove(screen);
 
-	LoadCgm(config);
+	LoadCgm();
 
-	anm1 = 0; anm2 = 0;
+	anm1 = NULL;
+	anm2 = NULL;
 }
 
 GrpImpl::~GrpImpl() {
@@ -931,22 +854,21 @@ void GrpImpl::LoadSurface(const char* st
 		if (str[0] != 0)
 			fprintf(stderr,"Cannot find surface %d <- '%s'\n",pdt,str);
 	}
-	return;
 }
 
-void GrpImpl::InitSel(AyuSysConfig& config) {
+void GrpImpl::InitSel(void) {
 	int i;
 	int args[16];
 	char key[1024];
 	for (i=0; i<999; i++) {
 		sprintf(key, "#SEL.%03d",i);
-		if (config.GetParam(key, 15, &args[0], &args[1],
+		if (config->GetParam(key, 15, &args[0], &args[1],
 			&args[2], &args[3], &args[4], &args[5], &args[6], &args[7],
 			&args[8], &args[9], &args[10], &args[11], &args[12], &args[13],
 			&args[14])) {
 
 			sprintf(key, "#SELR.%03d", i);
-			if (config.GetParam(key, 16, &args[0], &args[1],
+			if (config->GetParam(key, 16, &args[0], &args[1],
 				&args[2], &args[3], &args[4], &args[5], &args[6], &args[7],
 				&args[8], &args[9], &args[10], &args[11], &args[12], &args[13],
 				&args[14], &args[15]))  continue;
@@ -1255,7 +1177,7 @@ void GrpImpl::SwapObj(int index1, int in
 bool GrpImpl::Pressed(int x, int y, void* pointer) { // マウスクリックでキャンセル
 	GrpImpl* g = (GrpImpl*)pointer;
 	if (g->status == WAIT_MOVIE)
-		g->music.StopMovie();
+		g->music->StopMovie();
 	if (g->status == WAIT_ANM)
 		g->AbortAnm();
 	if (g->status == WAIT_SHAKE && g->anm2 != NULL) {
@@ -1302,11 +1224,11 @@ static unsigned char decode_char[256] = 
 	0xff, 0x00, 0x00, 0x04, 0x00, 0x6a, 0x00, 0x76
 };
 
-void GrpImpl::LoadCgm(AyuSysConfig& config) {
+void GrpImpl::LoadCgm() {
 	/* cgm ファイル読み込み */
-	const char* fname = config.GetParaStr("#CGTABLE_FILE");
+	const char* fname = config->GetParaStr("#CGTABLE_FILE");
 	if (fname == NULL) return;
-	ARCINFO* info = file_searcher.Find(FILESEARCH::ALL, fname, "");
+	ARCINFO* info = FileSearcher::GetInstance()->Find(FileSearcher::ALL, fname, "");
 	if (info == NULL) return;
 	char* data = info->CopyRead();
 	int sz = info->Size();
@@ -1366,7 +1288,7 @@ void GrpImpl::Load(const char* str) {
 	grpobj.clear();
 	
 	bg_name = "";
-	music.StopCDROM(100);
+	music->StopCDROM(100);
 }
 
 void GrpImpl::SaveSys(string& save) {
@@ -1487,11 +1409,11 @@ bool GrpImpl::Wait(unsigned int current_
 		}
 		status = NORMAL;
 	} else if (status == WAIT_SE) {
-		if (music.IsStopSE()) status = NORMAL;
+		if (music->IsStopSE()) status = NORMAL;
 		return true;
 	} else if (status == WAIT_MOVIE) {
-		if (music.IsStopMovie()) {
-			music.StopMovie();
+		if (music->IsStopMovie()) {
+			music->StopMovie();
 			status = NORMAL;
 			screen->ReBlit();
 		}
@@ -1529,7 +1451,7 @@ void GrpImpl::DeleteObjRange(int num_fir
 
 void GrpImpl::Exec(Cmd& cmd) {
 	if (cmd.cmd_type == CMD_TEXTEND) {
-		music.StopKoe(500); // テキスト終了で声を止める
+		music->StopKoe(500); // テキスト終了で声を止める
 		cmd.clear();
 		return;
 	}
@@ -1604,12 +1526,12 @@ void GrpImpl::Exec(Cmd& cmd) {
 			// shake screen
 			char key[1024];
 			sprintf(key, "#SHAKE.%03d", cmd.args[0].value);
-			if (config.SearchParam(key) != 2) {
+			if (config->SearchParam(key) != 2) {
 				fprintf(stderr,"Cannot find shake pattern %d; use default pattern\n",cmd.args[0].value);
 				strcpy(key, "#SHAKE.000"); // default key
 			}
 			int num; const int* pattern;
-			pattern = config.GetParamArray(key, num);
+			pattern = config->GetParamArray(key, num);
 			if (pattern) {
 				StartShake(num, pattern);
 				status = WAIT_SHAKE;
@@ -2092,7 +2014,7 @@ 487 / 8047 : unsupported command; 0x23 -
 				/* 前景色を得る */
 				int cr,cg,cb; char key[1024];
 				sprintf(key, "#COLOR_TABLE.%03d", cmd.args[5].value);
-				if (config.GetParam(key, 3, &cr, &cg, &cb)) { // color not found
+				if (config->GetParam(key, 3, &cr, &cg, &cb)) { // color not found
 					cr = cg = cb = 0;
 				}
 				g.print_r = cr;
@@ -2213,26 +2135,26 @@ 487 / 8047 : unsupported command; 0x23 -
 	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x14) {
 		if (cmd.cmd3 == 0 && cmd.cmd4 == 0) {
 			eprintf("play bgm %s\n",cmd.Str(cmd.args[0]));
-			music.PlayCDROM( (char*)cmd.Str(cmd.args[0]), 10000);
+			music->PlayCDROM( (char*)cmd.Str(cmd.args[0]), 10000);
 			cmd.cmd_type = CMD_SAVECMD_ONCE;
 		}
 		if (cmd.cmd3 == 2 && (cmd.cmd4 == 2 || cmd.cmd4 == 0) ) { /* ??? : ことみシナリオラストの音楽再生 */
 			eprintf("play bgm %s\n",cmd.Str(cmd.args[0]));
-			music.PlayCDROM( (char*)cmd.Str(cmd.args[0]), 1);
+			music->PlayCDROM( (char*)cmd.Str(cmd.args[0]), 1);
 			cmd.cmd_type = CMD_SAVECMD_ONCE;
 		}
 		if (cmd.cmd3 == 0 && cmd.cmd4 == 2) {
 			eprintf("fade bgm %d? and play bgm %s; %d\n",cmd.args[1].value, cmd.Str(cmd.args[0]), cmd.args[2].value);
-			// music.PlayCDROM( (char*)cmd.Str(cmd.args[0]), 10000, cmd.args[2].value);
-			music.PlayCDROM( (char*)cmd.Str(cmd.args[0]), 10000);
+			// music->PlayCDROM( (char*)cmd.Str(cmd.args[0]), 10000, cmd.args[2].value);
+			music->PlayCDROM( (char*)cmd.Str(cmd.args[0]), 10000);
 			cmd.cmd_type = CMD_SAVECMD_ONCE;
 		}
 		if ( (cmd.cmd3 == 5 || cmd.cmd3 == 0x69) && cmd.cmd4 == 0) {
 			if (cmd.cmd3 == 5) {
-				music.StopCDROM(0);
+				music->StopCDROM(0);
 				eprintf("stop bgm\n");
 			} else {
-				music.StopCDROM(cmd.args[0].value);
+				music->StopCDROM(cmd.args[0].value);
 				eprintf("fade bgm %d\n",cmd.args[0].value);
 			}
 			cmd.cmd_type = CMD_SAVECMD_ONCE;
@@ -2242,44 +2164,44 @@ 487 / 8047 : unsupported command; 0x23 -
 		if ((cmd.cmd3 == 2) || (cmd.cmd3 == 0 && (cmd.cmd4 == 1 || cmd.cmd4 == 2)) || (cmd.cmd3 == 0 && cmd.cmd4 == 0)) {
 			eprintf("play SE %s\n",cmd.Str(cmd.args[0]));
 			if (cmd.cmd3 == 2) {
-				music.PlaySE(cmd.Str(cmd.args[0]),1);
+				music->PlaySE(cmd.Str(cmd.args[0]),1);
 				cmd.cmd_type = CMD_SAVECMD_ONCE;
 			} else {
-				music.PlaySE(cmd.Str(cmd.args[0]));
+				music->PlaySE(cmd.Str(cmd.args[0]));
 				cmd.clear();
 			}
 		} else if (cmd.cmd3 == 5) {
 			eprintf("Stop SE\n");
-			music.StopSE();
+			music->StopSE();
 			cmd.cmd_type = CMD_SAVECMD_ONCE;
 		} else if (cmd.cmd3 == 0x69) {
 			eprintf("Stop SE with fade %d\n",cmd.args[0].value);
-			music.StopSE(cmd.args[0].value);
+			music->StopSE(cmd.args[0].value);
 			cmd.cmd_type = CMD_SAVECMD_ONCE;
 		}
 	}
 	if (cmd.cmd1 == 1 && cmd.cmd2 == 4 && (cmd.cmd3 == 0x4bb || cmd.cmd3 == 0x4bc) ) {
 		// 音楽を待ってみる(絶対に違うが)。本来、04-803 に対応してなにかの終わりをwaitするっぽい(風子/智代Ed付近)
 		// EnableSyscom らしいが、よくわからない (rldev)
-//		if (!music.IsStopSE()) status = WAIT_SE;
+//		if (!music->IsStopSE()) status = WAIT_SE;
 		cmd.clear();
 	}
 
 		// 音楽モードで音量を上げるためのコマンド (SetBgmVolume)
 		// とりあえず未実装
 	if (cmd.cmd1 == 1 && cmd.cmd2 == 4 && cmd.cmd3 >= 0x8b6 && cmd.cmd3 <= 0x8b9) { // Set{Bgm,Koe,PCM,Se}VolMod
-		music.volmod[cmd.cmd3-0x8b6] = cmd.args[0].value;
-		config.SetParam("#VOLMOD", 4, music.volmod[0], music.volmod[1], music.volmod[2], music.volmod[3]);
+		music->volmod[cmd.cmd3-0x8b6] = cmd.args[0].value;
+		config->SetParam("#VOLMOD", 4, music->volmod[0], music->volmod[1], music->volmod[2], music->volmod[3]);
 		cmd.clear();
 	}
 	if (cmd.cmd1 == 1 && cmd.cmd2 == 4 && cmd.cmd3 >= 0x91a && cmd.cmd3 <= 0x91d) { // Get{Bgm,Koe,PCM,Se}VolMod
-		cmd.SetSysvar(music.volmod[cmd.cmd3-0x91a]);
+		cmd.SetSysvar(music->volmod[cmd.cmd3-0x91a]);
 	}
 
 	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x16) {
 		if (cmd.cmd3 == 0 && cmd.cmd4 == 0) {
 			eprintf("play SE %d\n",cmd.args[0].value);
-			music.PlaySE(cmd.args[0].value);
+			music->PlaySE(cmd.args[0].value);
 			cmd.clear();
 		}
 	}
@@ -2291,7 +2213,7 @@ 487 / 8047 : unsupported command; 0x23 -
 			}
 			eprintf("\n");
 			char buf[1024]; sprintf(buf, "%d",cmd.args[0].value);
-			if ( !(skip_mode & SKIP_TEXT)) music.PlayKoe(buf);
+			if ( !(skip_mode & SKIP_TEXT)) music->PlayKoe(buf);
 			cmd.clear();
 		}
 	}
@@ -2303,7 +2225,7 @@ 487 / 8047 : unsupported command; 0x23 -
 			int x2 = cmd.args[3].value;
 			int y2 = cmd.args[4].value;
 			eprintf("play movie ; name %s pos %d,%d - %d,%d\n",str,x,y,x2,y2);
-			music.PlayMovie(str, x, y, x2, y2,1);
+			music->PlayMovie(str, x, y, x2, y2,1);
 			status = WAIT_MOVIE;
 			event.RegisterGlobalPressFunc(&Pressed, (void*)this);
 			cmd.clear();
@@ -2318,8 +2240,8 @@ 487 / 8047 : unsupported command; 0x23 -
 **	class Grp
 */
 
-Grp::Grp(Event::Container& _event, PicContainer& _parent, const Flags& f, set<int>& _cgm,class MuSys& mu, AyuSysConfig& config) {
-	pimpl = new GrpImpl(_event, _parent, f, _cgm, mu, config);
+Grp::Grp(Event::Container& _event, PicContainer& _parent, const Flags& f, set<int>& _cgm) {
+	pimpl = new GrpImpl(_event, _parent, f, _cgm);
 }
 
 Grp::~Grp() {
@@ -2338,8 +2260,8 @@ void Grp::SetSkipMode(SkipMode mode) {
 	pimpl->SetSkipMode(mode);
 }
 
-void Grp::InitSel(AyuSysConfig& config) {
-	pimpl->InitSel(config);
+void Grp::InitSel(void) {
+	pimpl->InitSel();
 }
 
 void Grp::Save(std::string& str) {
--- a/scn2k/scn2k_impl.cc
+++ b/scn2k/scn2k_impl.cc
@@ -45,14 +45,15 @@ void kconv_rev(const unsigned char* src,
 string kconv(const string& s);
 string kconv_rev(const string& s);
 
-Scn2k::Scn2k(Event::Container& _event, PicContainer& _parent, class MuSys& mu, AyuSysConfig& _config) :
+Scn2k::Scn2k(Event::Container& _event, PicContainer& _parent) :
 	Event::Time(_event),
 	event(_event),
 	parent(_parent),
-	config(_config),
-	text_exec(_event, _parent, config),
-	grp_exec(_event, _parent, flag, flag.cgm_data, mu, config)
+	text_exec(_event, _parent),
+	grp_exec(_event, _parent, flag, flag.cgm_data)
 {
+	config = AyuSysConfig::GetInstance();
+
 	system_version = 0;
 	skip_mode = SKIP_NO;
 
@@ -83,7 +84,7 @@ Scn2k::Scn2k(Event::Container& _event, P
 
 	LoadSys();
 	text_exec.InitWindow();
-	grp_exec.InitSel(config);
+	grp_exec.InitSel();
 }
 
 Scn2k::~Scn2k() {
@@ -99,8 +100,10 @@ char* Scn2k::OpenScript(int new_scn_numb
 	int offset = 0;
 	int scenario_magic;
 
+	FileSearcher* file_searcher = FileSearcher::GetInstance();
+
 	sprintf(fname, "SEEN%04d.TXT", new_scn_number);
-	ARCINFO* info = file_searcher.Find(FILESEARCH::SCN, fname, "");
+	ARCINFO* info = file_searcher->Find(FileSearcher::SCN, fname, "");
 	if (info == NULL) goto err;
 	data = info->Read();
 
@@ -390,7 +393,7 @@ void Scn2k::ShowCursor(void) {
 	HideCursor();
 	char key[1024];
 	sprintf(key, "#MOUSE_CURSOR.%03d.NAME",mouse_type);
-	const char* name = config.GetParaStr(key);
+	const char* name = config->GetParaStr(key);
 	if (name == NULL || name[0] == 0) mouse_surface = DEFAULT_MOUSECURSOR;
 	else {
 		mouse_surface = parent.Root().NewSurface(name, COLOR_MASK);
@@ -485,7 +488,7 @@ void Scn2k::SysExec(Cmd& cmd) {
 	}
 	if (cmd.cmd_type == CMD_MENUREQ) {
 		int scn=0, pt=0;
-		config.GetParam("#CANCELCALL", 2, &scn, &pt);
+		config->GetParam("#CANCELCALL", 2, &scn, &pt);
 		if (scn) {
 			// 右クリックされたら global call を行う
 			cmd.cmd_type = CMD_OTHER;
@@ -550,7 +553,7 @@ void Scn2k::SysExec(Cmd& cmd) {
 				new_pt = cmd.args[1].value;
 			}
 			if (new_scn == SCN_INFO_MENU) { // menu call
-				config.GetParam("#CANCELCALL", 2, &new_scn, &new_pt);
+				config->GetParam("#CANCELCALL", 2, &new_scn, &new_pt);
 				stack.push_back(StackItem(SCN_INFO, SCN_INFO_MENU)); // menu call を示す特殊な記号
 			} else {
 				int i;
@@ -701,7 +704,7 @@ void Scn2k::SysExec(Cmd& cmd) {
 			cmd.clear();
 		}
 	} else if (cmd.cmd1 == 2 && cmd.cmd2 == 1 && cmd.cmd3 == 12) { // DLL Call
-		const char* regname = config.GetParaStr("#REGNAME");
+		const char* regname = config->GetParaStr("#REGNAME");
 		const char key_lb[] = "KEY\\LittleBusters";//FIXME: too specific to be here?
 		if (strcmp(regname, key_lb) == 0) {
 			DllCall_LB(cmd, flag);
@@ -719,7 +722,7 @@ void Scn2k::SysExec(Cmd& cmd) {
 			const char* name = cmd.Str(cmd.args[0]);
 			if (name == NULL) name = "";
 			window_title = name;
-			const char* config_name = config.GetParaStr("#CAPTION");
+			const char* config_name = config->GetParaStr("#CAPTION");
 			if (config_name == NULL) config_name = "";
 			string setname = kconv(string(config_name) + "  " + window_title);
 			parent.Root().SetWindowCaption(setname.c_str());
@@ -761,7 +764,7 @@ void Scn2k::SysExec(Cmd& cmd) {
 		} else if (cmd.cmd3 == 0x58d) {
         		// 前にロード|セーブされた番号を返す。
         	int lastsave;
-        	config.GetParam("#LASTSAVE", 1, &lastsave);
+        	config->GetParam("#LASTSAVE", 1, &lastsave);
         	flag.SetSys(lastsave-1);
 		} else if (cmd.cmd3 == 0x585) {
         		// 第一引数の記録された日付、タイトルなどが返される
@@ -792,12 +795,12 @@ fprintf(stderr,"StatSave %d:",cmd.args[0
 			Load(cmd);
 		} else if (cmd.cmd3 == 0x4b1 || cmd.cmd3 == 0x4b3) { // menu へ戻る (4b3: バッドエンド)
 			int scn_start;
-			if (config.GetParam("#SEEN_MENU", 1, &scn_start) == 0) {
+			if (config->GetParam("#SEEN_MENU", 1, &scn_start) == 0) {
 				ChangeScript(scn_start, 0);
 				save_scn = 0;
 				save_point = 0;
 				window_title = "";
-				const char* window_title_config = config.GetParaStr("#CAPTION");
+				const char* window_title_config = config->GetParaStr("#CAPTION");
 				if (window_title_config) window_title = window_title_config;
 				parent.Root().SetWindowCaption(kconv(window_title).c_str());
 				stack.clear();
@@ -858,7 +861,7 @@ string Scn2k::MakeSaveFile(void) const {
 		}
 	}
 	// ファイル名を作る
-	const char* regname = config.GetParaStr("#REGNAME");
+	const char* regname = config->GetParaStr("#REGNAME");
 
 	char* fname = new char[strlen(regname)+1];
 	/* レジストリ名をファイル名として有効なものにする */
@@ -892,10 +895,10 @@ void Scn2k::SaveSys(void) {
 	string save;
 	string path = MakeSaveFile();
 	
-	sprintf(buf, "KEY=%s\n", config.GetParaStr("#REGNAME"));
+	sprintf(buf, "KEY=%s\n", config->GetParaStr("#REGNAME"));
 	save += buf;
 	string save_config;
-	config.DiffOriginal(save_config);
+	config->DiffOriginal(save_config);
 	save += "CONFIG=";
 	save += save_config;
 	save += "\n";
@@ -946,7 +949,7 @@ void Scn2k::LoadSys(void) {
 		savedata[sz] = 0;
 		fclose(f);
 
-		sprintf(buf, "KEY=%s\n", config.GetParaStr("#REGNAME"));
+		sprintf(buf, "KEY=%s\n", config->GetParaStr("#REGNAME"));
 		if (strncmp(savedata, buf, strlen(buf)) != 0) {
 			fprintf(stderr,"Invalid header in save file %s: it must be started with \"%s\"\n", path.c_str(), buf);
 		} else  {
@@ -959,7 +962,7 @@ void Scn2k::LoadSys(void) {
 					char* config_copy = new char[l+1];
 					strncpy(config_copy, config_str, l);
 					config_copy[l] = 0;
-					config.PatchOriginal(config_copy);
+					config->PatchOriginal(config_copy);
 					delete[] config_copy;
 				}
 			}
@@ -997,12 +1000,12 @@ void Scn2k::LoadSys(void) {
 	}
 
 	/* 初期化 */
-	int scn_start; config.GetParam("#SEEN_START", 1, &scn_start);
+	int scn_start; config->GetParam("#SEEN_START", 1, &scn_start);
 	ChangeScript(scn_start, 0);
 	save_scn = 0;
 	save_point = 0;
 	window_title = "";
-	const char* window_title_config = config.GetParaStr("#CAPTION");
+	const char* window_title_config = config->GetParaStr("#CAPTION");
 	if (window_title_config) window_title = window_title_config;
 	parent.Root().SetWindowCaption(kconv(window_title).c_str());
 	stack.clear();
@@ -1033,7 +1036,7 @@ bool Scn2k::StatSaveFile(int num, int& y
 	FILE* savefile = fopen(path.c_str(), "rb");
 	if (savefile == NULL) return false;
 	char regname[1024];
-	sprintf(regname, "KEY=%s\n", config.GetParaStr("#REGNAME"));
+	sprintf(regname, "KEY=%s\n", config->GetParaStr("#REGNAME"));
 	fgets(buf,1000,savefile);
 	if (strncmp(regname, buf, strlen(regname)) != 0) {
 		fprintf(stderr,"invalid save file %s (registory name is not %s)\n",path.c_str(),regname);
@@ -1125,7 +1128,7 @@ void Scn2k::Save(Cmd& cmd) {
 
 	/* セーブファイル確認 */
 	
-	sprintf(buf, "KEY=%s\n", config.GetParaStr("#REGNAME")); save += buf;
+	sprintf(buf, "KEY=%s\n", config->GetParaStr("#REGNAME")); save += buf;
 	string save_sys; SaveImpl(save_sys);
 	string save_flag; flag.Save(save_flag);
 	string save_text; text_exec.Save(save_text, false);
@@ -1148,7 +1151,7 @@ void Scn2k::Save(Cmd& cmd) {
 	}
 	fwrite(save.c_str(), save.length(), 1, f);
 	fclose(f);
-	config.SetParam("#LASTSAVE", 1, file_number);
+	config->SetParam("#LASTSAVE", 1, file_number);
 	cmd.clear();
 }
 
@@ -1187,7 +1190,7 @@ void Scn2k::Load(Cmd& cmd) {
 	savedata[sz] = 0;
 	fclose(f);
 
-	sprintf(buf, "KEY=%s\n", config.GetParaStr("#REGNAME"));
+	sprintf(buf, "KEY=%s\n", config->GetParaStr("#REGNAME"));
 	if (strncmp(savedata, buf, strlen(buf)) != 0) {
 		fprintf(stderr,"Invalid header in save file %s: it must be started with \"%s\"\n", path.c_str(), buf);
 		delete[] savedata;
@@ -1275,7 +1278,7 @@ void Scn2k::LoadImpl(const char* save) {
 			char* s = strchr(save, '\n');
 			if (s == NULL) window_title = save;
 			else window_title.assign(save, s-save);
-			const char* config_name = config.GetParaStr("#CAPTION");
+			const char* config_name = config->GetParaStr("#CAPTION");
 			if (config_name == NULL) config_name = "";
 			string setname = kconv(string(config_name)+"  "+window_title);
 			parent.Root().SetWindowCaption(setname.c_str());
@@ -1898,8 +1901,8 @@ Scn2kMenu::Scn2kMenu(MenuType _type, Scn
 	case MENU_SAVE: pimpl = new LoadMenu(*this); break;
 	case MENU_BACKLOG: pimpl = new BacklogMenu(*this, scn_impl, text_exec); break;
 	}
-	return;
 }
+
 Scn2kMenu::~Scn2kMenu() {
 	if (pimpl) delete pimpl;
 	pimpl = NULL;
--- a/scn2k/scn2k_impl.h
+++ b/scn2k/scn2k_impl.h
@@ -73,7 +73,7 @@ class Scn2k : Event::Time {
 	private:
 		Event::Container& event;
 		PicContainer& parent;
-		AyuSysConfig& config;
+		AyuSysConfig *config;
 		WidMouseCursor* mcursor;
 		Flags flag;
 		Text text_exec;
@@ -134,8 +134,9 @@ class Scn2k : Event::Time {
 		void LoadRollback(Cmd& cmd);
 		void SaveSys(void);
 		void LoadSys(void);
+
 	public:
-		Scn2k(Event::Container& _event, PicContainer& _parent, class MuSys& mu, AyuSysConfig& config);
+		Scn2k(Event::Container& _event, PicContainer& _parent);
 		~Scn2k();
 		static char* OpenScript(int scn_number, char*& end, int* call_vec, int& system_version);
 		bool ChangeScript(int scn_number, int call_no);
--- a/scn2k/scn2k_text.cc
+++ b/scn2k/scn2k_text.cc
@@ -93,7 +93,7 @@ struct TextWindow {
 	PicContainer* name_container;
 	PicBase* face;
 	PicBase* face_pics[8];
-	TextWindow(PicContainer& parent, Event::Container& event, int window_no, const AyuSysConfig& config, void* callback);
+	TextWindow(PicContainer& parent, Event::Container& event, int window_no, void* callback);
 	~TextWindow() {
 		if (name_container != NULL) {
 			delete name_container;
@@ -111,8 +111,8 @@ struct TextWindow {
 			wid = NULL;
 		}
 	}
-	Rect WakuSize(PicContainer& pic, int waku_no, const AyuSysConfig& config);
-	void MakeWaku(PicContainer& pic, Event::Container& event, int waku_no,int window_no, bool* use_btn, const AyuSysConfig& config, void* callback);
+	Rect WakuSize(PicContainer& pic, int waku_no);
+	void MakeWaku(PicContainer& pic, Event::Container& event, int waku_no,int window_no, bool* use_btn, void* callback);
 	void show(void) {
 		wid->show();
 		if (name_container && name_visible) name_container->show();
@@ -205,7 +205,7 @@ class TextImpl {
 	public:
 		PicContainer& parent;
 		Event::Container& event;
-		AyuSysConfig& config;
+		AyuSysConfig *config;
 	private:
 		TextWindow* widgets[32];
 		WidTimeCursor* kcursor;
@@ -229,7 +229,7 @@ class TextImpl {
 		static bool PressFunc(int x, int y, void* pointer);
 
 	public:
-		TextImpl(Event::Container& _event, PicContainer& _parent, AyuSysConfig& config, vector<BacklogItem>& parent_backlog, BacklogItem& parent_backlog_item);
+		TextImpl(Event::Container& _event, PicContainer& _parent, vector<BacklogItem>& parent_backlog, BacklogItem& parent_backlog_item);
 		~TextImpl();
 		void InitWindow(void);
 		void SetWindowColor(int r, int g, int b, int a, bool is_transparent);
@@ -252,11 +252,12 @@ class TextImpl {
 **
 **	TextImpl(implementation)
 */
-TextImpl::TextImpl(Event::Container& _event, PicContainer& _parent, AyuSysConfig& _config, vector<BacklogItem>& parent_backlog, BacklogItem& parent_backlog_item) :
+TextImpl::TextImpl(Event::Container& _event, PicContainer& _parent, vector<BacklogItem>& parent_backlog, BacklogItem& parent_backlog_item) :
 	text(0),status(TextImpl::NORMAL), status_saved(TextImpl::NORMAL), status_mask(TextImpl::NORMAL), ruby_text_flag(false),
 	old_time(0), base_time(0), text_window_number(0), text_parsing(false), skip_mode(SKIP_NO), save_selectcount(0), sel_widget(0),
-	backlog_widget(0), backlog(parent_backlog), backlog_item(parent_backlog_item), parent(_parent), event(_event), config(_config),
+	backlog_widget(0), backlog(parent_backlog), backlog_item(parent_backlog_item), parent(_parent), event(_event),
 	kcursor(0), sel_bg1(0), sel_bg2(0), sel_bg_rect(0,0,0,0) {
+	config = AyuSysConfig::GetInstance();
 	int i;
 	for (i=0; i<32; i++) {
 		widgets[i] = 0;
@@ -623,7 +624,7 @@ void TextImpl::show(int num) {
 		int kx, ky, d;
 		char key[1024];
 		sprintf(key, "#WINDOW.%03d.KEYCUR_MOD", text_window_number);
-		config.GetParam(key, 3, &d, &kx, &ky);
+		config->GetParam(key, 3, &d, &kx, &ky);
 		// 正しくない気がする
 		kx += text->wid->Pic()->PosX();
 		ky += text->wid->Pic()->PosY();
@@ -657,8 +658,8 @@ void TextImpl::DrawBacklog(BacklogItem& 
 void TextImpl::CreateSelBG(void) {
 	if (sel_bg1 != NULL || sel_bg2 != NULL) return;
 
-	const char* btnfile1 = config.GetParaStr("#SELBTN.000.NAME");
-	const char* btnfile2 = config.GetParaStr("#SELBTN.000.BACK");
+	const char* btnfile1 = config->GetParaStr("#SELBTN.000.NAME");
+	const char* btnfile2 = config->GetParaStr("#SELBTN.000.BACK");
 	char path[1024];
 	strcpy(path, btnfile1);
 	sel_bg1 = parent.Root().NewSurface(path);
@@ -681,7 +682,7 @@ void TextImpl::CreateSelect(Cmd& cmd) {
 	char key[1024];
 	sprintf(key, "#WINDOW.%03d.SELCOM_USE",text_window_number);
 	int sel_type = 0;
-	if (cmd.cmd3 == 1) config.GetParam(key, 1, &sel_type);
+	if (cmd.cmd3 == 1) config->GetParam(key, 1, &sel_type);
 	else if (cmd.cmd3 == 3) sel_type = 0;
 
 	int sel_size = cmd.args.size() / 2;
@@ -708,19 +709,19 @@ External_select:
 		hide(); // なので、テキストウィンドウは消去
 		int baseposx, baseposy, repposx, repposy, centerx, centery;
 		int mojisize, col1, col2;
-		config.GetParam("#SELBTN.000.CENTERING", 2, &centerx, &centery);
-		config.GetParam("#SELBTN.000.BASEPOS", 2, &baseposx, &baseposy);
-		config.GetParam("#SELBTN.000.REPPOS", 2, &repposx, &repposy);
-		config.GetParam("#SELBTN.000.MOJISIZE", 1, &mojisize);
-		config.GetParam("#SELBTN.000.MOJIDEFAULTCOL", 1, &col1);
-		config.GetParam("#SELBTN.000.MOJISELECTCOL", 1, &col2);
+		config->GetParam("#SELBTN.000.CENTERING", 2, &centerx, &centery);
+		config->GetParam("#SELBTN.000.BASEPOS", 2, &baseposx, &baseposy);
+		config->GetParam("#SELBTN.000.REPPOS", 2, &repposx, &repposy);
+		config->GetParam("#SELBTN.000.MOJISIZE", 1, &mojisize);
+		config->GetParam("#SELBTN.000.MOJIDEFAULTCOL", 1, &col1);
+		config->GetParam("#SELBTN.000.MOJISELECTCOL", 1, &col2);
 		if (col1 == col2) col2 = 1; // CLANNAD でとりあえず。
 		int r, g, b;
 		sprintf(key, "#COLOR_TABLE.%03d", col1);
-		config.GetParam(key, 3, &r, &g, &b);
+		config->GetParam(key, 3, &r, &g, &b);
 		Color fore(r,g,b);
 		sprintf(key, "#COLOR_TABLE.%03d", col2);
-		config.GetParam(key, 3, &r, &g, &b);
+		config->GetParam(key, 3, &r, &g, &b);
 		Color seled(r,g,b);
 
 		/* ウィジット作成 */
@@ -763,7 +764,7 @@ External_select:
 		status = WAIT_SELECT_OUTBOX;
 	} else { // CLANNAD: テキストウィンドウ内に選択肢表示
 		int mojisize;
-		config.GetParam("#SELBTN.000.MOJISIZE", 1, &mojisize);
+		config->GetParam("#SELBTN.000.MOJISIZE", 1, &mojisize);
 		Color fore(0xff,0xff,0xff);
 		Color seled(0xff,0xff,0xff);
 
@@ -1227,9 +1228,9 @@ if (cmd.args.size() != 7)
 			// テキストウィンドウの色設定
 			int r, g, b, a, flag;
 			if (cmd.cmd3 == 0xa39) { // 元設定を取り出す
-				config.GetOriginalParam("#WINDOW_ATTR", 5, &r, &g, &b, &a, &flag);
+				config->GetOriginalParam("#WINDOW_ATTR", 5, &r, &g, &b, &a, &flag);
 			} else {
-				config.GetParam("#WINDOW_ATTR", 5, &r, &g, &b, &a, &flag);
+				config->GetParam("#WINDOW_ATTR", 5, &r, &g, &b, &a, &flag);
 			}
 			if (cmd.cmd3 == 0xa39 || cmd.cmd3 == 0x93f) { // 設定を変数に取り出す
 				if (cmd.args.size() != 5) {
@@ -1257,24 +1258,24 @@ if (cmd.args.size() != 7)
 					flag = cmd.args[4].value;
 					break;
 				}
-				config.SetParam("#WINDOW_ATTR", 5, r, g, b, a, flag);
+				config->SetParam("#WINDOW_ATTR", 5, r, g, b, a, flag);
 				SetWindowColor(r, g, b, a, flag);
 				cmd.clear();
 			}
 		} else if (cmd.cmd3 == 0xa28 || cmd.cmd3 == 0xa29 || cmd.cmd3 == 0xa2c || cmd.cmd3 == 0xa2d || cmd.cmd3 == 0xa2e) {
 			int v = 0;
 			switch(cmd.cmd3) {
-			case 0xa28: case 0xa2d: config.GetOriginalParam("#INIT_MESSAGE_SPEED", 1, &v); break;
-			case 0xa29: config.GetOriginalParam("#INIT_MESSAGE_SPEED_MOD", 1, &v); break;
-			case 0xa2c: config.GetOriginalParam("#MESSAGE_KEY_WAIT_USE", 1, &v); break;
-			case 0xa2e: config.GetOriginalParam("#MESSAGE_KEY_WAIT_TIME", 1, &v); break;
+			case 0xa28: case 0xa2d: config->GetOriginalParam("#INIT_MESSAGE_SPEED", 1, &v); break;
+			case 0xa29: config->GetOriginalParam("#INIT_MESSAGE_SPEED_MOD", 1, &v); break;
+			case 0xa2c: config->GetOriginalParam("#MESSAGE_KEY_WAIT_USE", 1, &v); break;
+			case 0xa2e: config->GetOriginalParam("#MESSAGE_KEY_WAIT_TIME", 1, &v); break;
 			}
 			cmd.SetSysvar(v);
 		} else if (cmd.cmd3 == 0x913 || cmd.cmd3 == 0x914 || cmd.cmd3 == 0x92f || cmd.cmd3 == 0x8af || cmd.cmd3 == 0x8b0 || cmd.cmd3 == 0x8cb) {
 			// テキスト表示速度関連
 			int m, speed;
-			config.GetParam("#INIT_MESSAGE_SPEED", 1, &speed);
-			config.GetParam("#INIT_MESSAGE_SPEED_MOD", 1, &m);
+			config->GetParam("#INIT_MESSAGE_SPEED", 1, &speed);
+			config->GetParam("#INIT_MESSAGE_SPEED_MOD", 1, &m);
 if (cmd.cmd3 == 0x913 || cmd.cmd3 == 0x92f) fprintf(stderr,"TEXT speed %d\n",speed);
 else if (cmd.cmd3 == 0x914) fprintf(stderr,"TEXT mode %d\n",m);
 else if (cmd.cmd3 == 0x8af || cmd.cmd3 == 0x8cb) fprintf(stderr,"TEXT %d, %d <- speed %d\n",m,speed,cmd.args[0].value);
@@ -1286,8 +1287,8 @@ else fprintf(stderr,"TEXT %d, %d <- mode
 				else m = cmd.args[0].value;
 				if (speed < 10) speed = 10;
 				else if (speed > 1000) speed = 1000;
-				config.SetParam("#INIT_MESSAGE_SPEED", 1, speed);
-				config.SetParam("#INIT_MESSAGE_SPEED_MOD", 1, m);
+				config->SetParam("#INIT_MESSAGE_SPEED", 1, speed);
+				config->SetParam("#INIT_MESSAGE_SPEED_MOD", 1, m);
 				if (m) speed = -1;
 				SetTextSpeed(speed);
 				cmd.clear();
@@ -1295,8 +1296,8 @@ else fprintf(stderr,"TEXT %d, %d <- mode
 		} else if (cmd.cmd3 == 0x92e || cmd.cmd3 == 0x930 || cmd.cmd3 == 0x8ca || cmd.cmd3 == 0x8cc) {
 			// テキストオートモード関連
 			int m, wait;
-			config.GetParam("#MESSAGE_KEY_WAIT_USE", 1, &m);
-			config.GetParam("#MESSAGE_KEY_WAIT_TIME", 1, &wait);
+			config->GetParam("#MESSAGE_KEY_WAIT_USE", 1, &m);
+			config->GetParam("#MESSAGE_KEY_WAIT_TIME", 1, &wait);
 if (cmd.cmd3 == 0x92e) fprintf(stderr,"AUTO mode %d\n",m);
 else if (cmd.cmd3 == 0x930) fprintf(stderr,"AUTO wait %d\n",wait);
 else if (cmd.cmd3 == 0x8ca) fprintf(stderr,"AUTO %d,%d <- mode %d\n",m,wait,cmd.args[0].value);
@@ -1309,8 +1310,8 @@ else fprintf(stderr,"AUTO %d,%d <- wait 
 				else wait = cmd.args[1].value;
 				if (wait < 0) wait = 0;
 				else if (wait > 60000) wait = 60000;
-				config.SetParam("#MESSAGE_KEY_WAIT_USE", 1, m);
-				config.SetParam("#MESSAGE_KEY_WAIT_TIME", 1, wait);
+				config->SetParam("#MESSAGE_KEY_WAIT_USE", 1, m);
+				config->SetParam("#MESSAGE_KEY_WAIT_TIME", 1, wait);
 				if (m) SetTextWait(wait);
 				else SetTextWait(-1);
 				cmd.clear();
@@ -1617,7 +1618,7 @@ void TextImpl::SetWindowColor(int r, int
 	for (w=0; w<32; w++) {
 		if (widgets[w] == NULL) continue;
 		sprintf(key, "#WAKU.%03d.000.BACK", w);
-		const char* back = config.GetParaStr(key);
+		const char* back = config->GetParaStr(key);
 		if (back == NULL || back[0] == 0) continue;
 		sprintf(key, "%s.g00", back);
 		Surface* back_s = parent.Root().NewSurface(key);
@@ -1637,16 +1638,16 @@ void TextImpl::SetWindowColor(int r, int
 void TextImpl::SetCursor(int cursor_no) {
 	char key[1024];
 	sprintf(key, "#CURSOR.%03d.NAME", cursor_no);
-	string path = config.GetParaStr(key);
+	string path = config->GetParaStr(key);
 	if (path.length() == 0) return; // 名前なし
 	path += ".pdt";
 	int w,h,cont,speed;
 	sprintf(key, "#CURSOR.%03d.SIZE", cursor_no);
-	config.GetParam(key, 2, &w, &h);
+	config->GetParam(key, 2, &w, &h);
 	sprintf(key, "#CURSOR.%03d.CONT", cursor_no);
-	config.GetParam(key, 1, &cont);
+	config->GetParam(key, 1, &cont);
 	sprintf(key, "#CURSOR.%03d.SPEED", cursor_no);
-	config.GetParam(key, 1, &speed);
+	config->GetParam(key, 1, &speed);
 
 	// speed で1周、cont 回変化
 	if (kcursor != NULL) delete kcursor;
@@ -1741,8 +1742,8 @@ string kconv_rev(const string& s) {
 **
 **	Text
 */
-Text::Text(Event::Container& _event, PicContainer& _parent, AyuSysConfig& config) {
-	pimpl = new TextImpl(_event, _parent, config, backlog, backlog_item);
+Text::Text(Event::Container& _event, PicContainer& _parent) {
+	pimpl = new TextImpl(_event, _parent, backlog, backlog_item);
 }
 
 Text::~Text() {
@@ -1838,10 +1839,10 @@ void BacklogItem::SetSavepos(int p) {
 	pos = p;
 }
 
-Rect TextWindow::WakuSize(PicContainer& pic, int waku_no, const AyuSysConfig& config) {
+Rect TextWindow::WakuSize(PicContainer& pic, int waku_no) {
 	char key[1024];
 	sprintf(key, "#WAKU.%03d.000.NAME", waku_no);
-	const char* name = config.GetParaStr(key);
+	const char* name = AyuSysConfig::GetInstance()->GetParaStr(key);
 	if (name == NULL) return Rect(0,0,0,0);
 	std::string str = name; str += ".g00";
 	Surface* s = pic.Root().NewSurface(str.c_str());
@@ -1851,18 +1852,19 @@ Rect TextWindow::WakuSize(PicContainer& 
 	return r;
 }
 
-void TextWindow::MakeWaku(PicContainer& pic, Event::Container& event, int waku_no, int window_no, bool* use_btn, const AyuSysConfig& config, void* callback) {
+void TextWindow::MakeWaku(PicContainer& pic, Event::Container& event, int waku_no, int window_no, bool* use_btn, void* callback) {
+	AyuSysConfig *config = AyuSysConfig::GetInstance();
 	char key[1024];
 	std::string str;
 	/* 枠を作成 */
 	sprintf(key, "#WAKU.%03d.000.NAME", waku_no);
-	const char* name = config.GetParaStr(key);
+	const char* name = config->GetParaStr(key);
 	if (name != NULL && name[0] == 0) name = NULL;
 	sprintf(key, "#WAKU.%03d.000.BACK", waku_no);
-	const char* back = config.GetParaStr(key);
+	const char* back = config->GetParaStr(key);
 	if (back != NULL && back[0] == 0) back = NULL;
 	sprintf(key, "#WAKU.%03d.000.BTN", waku_no);
-	const char* btn = config.GetParaStr(key);
+	const char* btn = config->GetParaStr(key);
 	if (btn != NULL && btn[0] == 0) btn = NULL;
 
 	if (name == NULL && back == NULL && btn == NULL) return;
@@ -1873,8 +1875,8 @@ void TextWindow::MakeWaku(PicContainer& 
 		int rc, gc, bc, ac, flag;
 		char key[1024];
 		sprintf(key, "#WINDOW.%03d.ATTR", window_no);
-		if (config.GetParam(key, 5, &rc, &gc, &bc, &ac, &flag) == -1) {
-			config.GetParam("#WINDOW_ATTR", 5, &rc, &gc, &bc, &ac, &flag);
+		if (config->GetParam(key, 5, &rc, &gc, &bc, &ac, &flag) == -1) {
+			config->GetParam("#WINDOW_ATTR", 5, &rc, &gc, &bc, &ac, &flag);
 		}
 		Surface* back_s = pic.Root().NewSurface(str.c_str());
 		if (back_s != NULL) {
@@ -1908,7 +1910,7 @@ void TextWindow::MakeWaku(PicContainer& 
 
 	/* ボタンの位置情報を求める */
 	str = btn; str += ".g00";
-	ARCINFO* info = file_searcher.Find(FILESEARCH::PDT, str.c_str(), "g00");
+	ARCINFO* info = FileSearcher::GetInstance()->Find(FileSearcher::PDT, str.c_str(), "g00");
 	if (info == NULL) return; // cannot find file
 	const char* data = info->Read();
 	/* g00 ファイルのヘッダ部分に位置情報は入っている */
@@ -1926,7 +1928,7 @@ void TextWindow::MakeWaku(PicContainer& 
 		}
 		int x, y, w, h;
 		sprintf(key, "#WAKU.%03d.000.%s_BOX", waku_no, btnname[i]);
-		if (config.GetParam(key, 5, 0, &x, &y, &w, &h) == -1) continue;
+		if (config->GetParam(key, 5, 0, &x, &y, &w, &h) == -1) continue;
 		int sx, sy, sdx, sdy, cnt;
 		const char* d = data + 9 + btnpos[i]*24*8;
 		sx = read_little_endian_int(d);
@@ -1942,26 +1944,30 @@ void TextWindow::MakeWaku(PicContainer& 
 	delete info;
 }
 
-TextWindow::TextWindow(PicContainer& parent, Event::Container& event, int win_no, const AyuSysConfig& config, void* callback) :
-	wid(0), name_visible(true),name(0),name_container(0), face(0) {
-	int i; for (i=0; i<8; i++) face_pics[i]=0;
+TextWindow::TextWindow(PicContainer& parent, Event::Container& event, int win_no, void* callback) :
+	wid(0), name_visible(true),name(0),name_container(0), face(0)
+{
+	AyuSysConfig *config = AyuSysConfig::GetInstance();
+	int i;
+	for (i=0; i<8; i++)
+		face_pics[i]=0;
 	char key[1024];
 	bool use_btn[BTNCNT];
 	int size, rep1, rep2, cntw, cnth, mposx, mposy, posd, posx, posy, minx, miny, waku_no, ruby;
-	sprintf(key, "#WINDOW.%03d.MOJI_SIZE", win_no); if (config.GetParam(key, 1, &size) == -1) return;
-	sprintf(key, "#WINDOW.%03d.MOJI_REP", win_no);  if (config.GetParam(key, 2, &rep1, &rep2) == -1) return;
-	sprintf(key, "#WINDOW.%03d.MOJI_CNT", win_no);  if (config.GetParam(key, 2, &cntw, &cnth) == -1) return;
-	sprintf(key, "#WINDOW.%03d.POS", win_no);       if (config.GetParam(key, 3, &posd, &posx, &posy) == -1) return;
-	sprintf(key, "#WINDOW.%03d.MOJI_POS", win_no);  if (config.GetParam(key, 4, &mposy, NULL, &mposx, NULL) == -1) return;
-	sprintf(key, "#WINDOW.%03d.MOJI_MIN", win_no);  if (config.GetParam(key, 2, &minx, &miny) == -1) return;
-	sprintf(key, "#WINDOW.%03d.WAKU_SETNO", win_no);if (config.GetParam(key, 1, &waku_no) == -1) return;
-	sprintf(key, "#WINDOW.%03d.LUBY_SIZE", win_no); if (config.GetParam(key, 1, &ruby) == -1) return;
+	sprintf(key, "#WINDOW.%03d.MOJI_SIZE", win_no); if (config->GetParam(key, 1, &size) == -1) return;
+	sprintf(key, "#WINDOW.%03d.MOJI_REP", win_no);  if (config->GetParam(key, 2, &rep1, &rep2) == -1) return;
+	sprintf(key, "#WINDOW.%03d.MOJI_CNT", win_no);  if (config->GetParam(key, 2, &cntw, &cnth) == -1) return;
+	sprintf(key, "#WINDOW.%03d.POS", win_no);       if (config->GetParam(key, 3, &posd, &posx, &posy) == -1) return;
+	sprintf(key, "#WINDOW.%03d.MOJI_POS", win_no);  if (config->GetParam(key, 4, &mposy, NULL, &mposx, NULL) == -1) return;
+	sprintf(key, "#WINDOW.%03d.MOJI_MIN", win_no);  if (config->GetParam(key, 2, &minx, &miny) == -1) return;
+	sprintf(key, "#WINDOW.%03d.WAKU_SETNO", win_no);if (config->GetParam(key, 1, &waku_no) == -1) return;
+	sprintf(key, "#WINDOW.%03d.LUBY_SIZE", win_no); if (config->GetParam(key, 1, &ruby) == -1) return;
 
 	/* テキストウィジット:画面の右下一杯まで使用 */
 	/* posd == 2 なら画面下にひっつくように配置 */
 	Rect r(0,0);
 	if (posd == 2) {
-		r = WakuSize(parent, waku_no, config);
+		r = WakuSize(parent, waku_no);
 		r = Rect(0, parent.Height()-r.height(), r.width(), parent.Height());
 		posx = 0;
 		posy = parent.Height()-r.height();
@@ -1976,7 +1982,7 @@ TextWindow::TextWindow(PicContainer& par
 	for (i=0; i<8; i++) {
 		int x,y;
 		sprintf(key, "#WINDOW.%03d.FACE.%03d", win_no, i);
-		if (config.GetParam(key, 2, &x, &y) == -1) continue;
+		if (config->GetParam(key, 2, &x, &y) == -1) continue;
 		/* 顔ウィンドウを作成する */
 		if (x >= 0 && y >= 0) {
 			face_pics[i] = wid->PicNode()->create_leaf(Rect(x,y), PicBase::FIT_SURFACE);
@@ -1990,18 +1996,18 @@ TextWindow::TextWindow(PicContainer& par
 	for (i=0; i<BTNCNT; i++) {
 		int num;
 		sprintf(key, "#WINDOW.%03d.%s_USE", win_no, btnname[i]);
-		config.GetParam(key, 1, &num);
+		config->GetParam(key, 1, &num);
 		use_btn[i] = (num==0) ? false : true;
 	}
 	// make name window
 	int shadow, name_mod, name_size, name_min, name_center, name_posx, name_posy, name_mposx, name_mposy;
-	sprintf(key, "#WINDOW.%03d.MOJI_SHADOW", win_no);  config.GetParam(key, 1, &shadow);
-	sprintf(key, "#WINDOW.%03d.NAME_MOD", win_no);  config.GetParam(key, 1, &name_mod);
-	sprintf(key, "#WINDOW.%03d.NAME_MOJI_SIZE", win_no);  config.GetParam(key, 1, &name_size);
-	sprintf(key, "#WINDOW.%03d.NAME_MOJI_MIN", win_no);  config.GetParam(key, 1, &name_min);
-	sprintf(key, "#WINDOW.%03d.NAME_MOJI_POS", win_no);  config.GetParam(key, 2, &name_mposx, &name_mposy);
-	sprintf(key, "#WINDOW.%03d.NAME_CENTERING", win_no);  config.GetParam(key, 1, &name_center);
-	sprintf(key, "#WINDOW.%03d.NAME_POS", win_no);  config.GetParam(key, 2, &name_posx, &name_posy);
+	sprintf(key, "#WINDOW.%03d.MOJI_SHADOW", win_no);  config->GetParam(key, 1, &shadow);
+	sprintf(key, "#WINDOW.%03d.NAME_MOD", win_no);  config->GetParam(key, 1, &name_mod);
+	sprintf(key, "#WINDOW.%03d.NAME_MOJI_SIZE", win_no);  config->GetParam(key, 1, &name_size);
+	sprintf(key, "#WINDOW.%03d.NAME_MOJI_MIN", win_no);  config->GetParam(key, 1, &name_min);
+	sprintf(key, "#WINDOW.%03d.NAME_MOJI_POS", win_no);  config->GetParam(key, 2, &name_mposx, &name_mposy);
+	sprintf(key, "#WINDOW.%03d.NAME_CENTERING", win_no);  config->GetParam(key, 1, &name_center);
+	sprintf(key, "#WINDOW.%03d.NAME_POS", win_no);  config->GetParam(key, 2, &name_posx, &name_posy);
 	// if name_mode==0 name is in the text window
 	// if name_mode == 1 open name window
 	// if name_mode == 2 name is not used
@@ -2010,12 +2016,12 @@ TextWindow::TextWindow(PicContainer& par
 			int w = name_size*name_min; int h = name_size;
 			int name_waku;
 			sprintf(key, "#WINDOW.%03d.NAME_WAKU_SETNO", win_no);
-			if (config.GetParam(key, 1, &name_waku) != -1 && name_waku != -1) {
-				Rect waku_r = WakuSize(parent, name_waku, config);
+			if (config->GetParam(key, 1, &name_waku) != -1 && name_waku != -1) {
+				Rect waku_r = WakuSize(parent, name_waku);
 				waku_r.rmove(r.lx, r.ty); // テキストウィンドウ位置に動かす
 				waku_r.rmove(name_posx, name_posy-waku_r.height()); // NAME_POS へ位置補正
 				name_container = parent.create_node(waku_r, 0);
-				MakeWaku(*name_container, event, name_waku, win_no, 0, config, callback);
+				MakeWaku(*name_container, event, name_waku, win_no, 0, callback);
 				Rect name_r(0,0,w,h);
 				name_r.rmove(name_mposx, name_mposy);
 				name = new WidLabel(name_container, name_r, true, 0, name_size);
@@ -2033,7 +2039,7 @@ TextWindow::TextWindow(PicContainer& par
 			name_container = parent.create_node( Rect(0, 0, 1, 1), 0);
 		}
 	}
-	MakeWaku(*wid->PicNode(), event,waku_no, win_no, use_btn, config, callback);
+	MakeWaku(*wid->PicNode(), event,waku_no, win_no, use_btn, callback);
 }
 
 void TextImpl::InitWindow(void) {
@@ -2042,7 +2048,7 @@ void TextImpl::InitWindow(void) {
 	std::string str;
 
 	for (w=0; w<32; w++) {
-		widgets[w] = new TextWindow(parent, event, w, config, (void*)this);
+		widgets[w] = new TextWindow(parent, event, w, (void*)this);
 		if (widgets[w]->wid == 0) {
 			delete widgets[w];
 			widgets[w] = NULL;
@@ -2052,7 +2058,7 @@ void TextImpl::InitWindow(void) {
 	for (i=0; i<26; i++) {
 		char buf[1024];
 		sprintf(buf, "#NAME.%c", i+'A');
-		const char* s = config.GetParaStr(buf);
+		const char* s = config->GetParaStr(buf);
 		if (s != NULL) replace_name[i] = s;
 	}
 	// replace_name2 : 初期設定
@@ -2065,10 +2071,10 @@ void TextImpl::InitWindow(void) {
 	text = NULL;
 	/* テキスト速度の設定 */
 	int speed, mod, wait, auto_mod;
-	config.GetParam("#INIT_MESSAGE_SPEED", 1, &speed);
-	config.GetParam("#INIT_MESSAGE_SPEED_MOD", 1, &mod);
-	config.GetParam("#MESSAGE_KEY_WAIT_USE", 1, &auto_mod);
-	config.GetParam("#MESSAGE_KEY_WAIT_TIME", 1, &wait);
+	config->GetParam("#INIT_MESSAGE_SPEED", 1, &speed);
+	config->GetParam("#INIT_MESSAGE_SPEED_MOD", 1, &mod);
+	config->GetParam("#MESSAGE_KEY_WAIT_USE", 1, &auto_mod);
+	config->GetParam("#MESSAGE_KEY_WAIT_TIME", 1, &wait);
 	if (mod) speed = -1;
 	if (!auto_mod) wait = -1;
 	SetTextSpeed(speed);
--- a/system/file.cc
+++ b/system/file.cc
@@ -83,18 +83,17 @@ extern "C" {
 
 using namespace std;
 
-FILESEARCH file_searcher;
-KEYHOLDER key_holder;
 // #define delete fprintf(stderr,"file.cc: %d.",__LINE__), delete
 
-/* FILESEARCH class の default の振る舞い */
-FILESEARCH::ARCTYPE FILESEARCH::default_is_archived[TYPEMAX] = {
+/* FileSearcher class の default の振る舞い */
+FileSearcher *FileSearcher::_singleton = NULL;
+FileSearcher::ARCTYPE FileSearcher::default_is_archived[TYPEMAX] = {
 	ATYPE_DIR, ATYPE_DIR, ATYPE_DIR, ATYPE_DIR,
 	ATYPE_ARC, ATYPE_ARC, ATYPE_ARC, ATYPE_ARC,
 	ATYPE_DIR, ATYPE_DIR, ATYPE_DIR, ATYPE_DIR,
 	ATYPE_DIR, ATYPE_DIR
 };
-const char* FILESEARCH::default_dirnames[TYPEMAX] = {
+const char* FileSearcher::default_dirnames[TYPEMAX] = {
 	0, 0, "", "pdt", 
 	"seen.txt", "allanm.anl", "allard.ard", "allcur.cur", 
 	0, 0, "koe", "bgm", "mov", "gan"};
@@ -115,7 +114,11 @@ ARCFILE::ARCFILE(const char* aname) {
 	list_point = 0;
 	filenames_orig = NULL;
 	next = NULL;
-	if (aname[0] == '\0') {arcname=new char[1]; arcname[0]='\0';return;} // NULFILE
+	if (aname[0] == '\0') {
+		arcname = new char[1];
+		arcname[0]='\0';
+		return;
+	} // NULFILE
 	/* ディレクトリか否かのチェック */
 	if (stat(aname,&sb) == -1) { /* error */
 		perror("stat");
@@ -536,16 +539,33 @@ void SCN2kFILE::ListupFiles(int fname_le
 }
 
 /********************************************************
-** KEYHOLDER
+** KeyHolder
 */
-void KEYHOLDER::SetKey(char new_key[16])
+
+KeyHolder* KeyHolder::_singleton = NULL;
+
+KeyHolder* KeyHolder::GetInstance(void)
+{
+	if (_singleton == NULL) _singleton = new KeyHolder;
+	return _singleton;
+}
+
+void KeyHolder::Quit(void)
+{
+	if (_singleton != NULL) {
+		delete _singleton;
+		_singleton = NULL;
+	}
+}
+
+void KeyHolder::SetKey(char new_key[16])
 {
 	unsigned short int i;
 	for (i=0; i < 16; i++)
 		key[i] = new_key[i];
 }
 
-void KEYHOLDER::SetKey2(char new_key[33])
+void KeyHolder::SetKey2(char new_key[33])
 {
 	unsigned short int i;
 	char tmp[3];
@@ -557,7 +577,7 @@ void KEYHOLDER::SetKey2(char new_key[33]
 	}
 }
 
-void KEYHOLDER::GuessKey(char *regname)
+void KeyHolder::GuessKey(char *regname)
 {
 	char key1[16] = {
 		0xa8, 0x28, 0xfd, 0x66,
@@ -582,16 +602,28 @@ void KEYHOLDER::GuessKey(char *regname)
 	}
 }
 
-const char * KEYHOLDER::GetKey(void)
+const char * KeyHolder::GetKey(void)
 {
 	return key;
 }
 
 /********************************************************
-** FILESEARCH クラスの実装
+** FileSearcher クラスの実装
 */
 
-FILESEARCH::FILESEARCH(void) {
+FileSearcher* FileSearcher::GetInstance(void) {
+	if (_singleton == NULL) _singleton = new FileSearcher;
+	return _singleton;
+}
+
+void FileSearcher::Quit(void) {
+	if (_singleton != NULL) {
+		delete _singleton;
+		_singleton = NULL;
+	}
+}
+
+FileSearcher::FileSearcher(void) {
 	int i;
 	root_dir = NULL;
 	dat_dir = NULL;
@@ -601,7 +633,8 @@ FILESEARCH::FILESEARCH(void) {
 		is_archived[i] = default_is_archived[i];
 	}
 }
-FILESEARCH::~FILESEARCH(void) {
+
+FileSearcher::~FileSearcher(void) {
 	int i;
 	for (i=0; i<TYPEMAX; i++) {
 		if (filenames[i] != NULL && filenames[i] != default_dirnames[i]) delete[] filenames[i];
@@ -613,7 +646,7 @@ FILESEARCH::~FILESEARCH(void) {
 	if (root_dir) delete root_dir;
 }
 
-int FILESEARCH::InitRoot(char* root) {
+int FileSearcher::InitRoot(char* root) {
 	/* 必要に応じて ~/ を展開 */
 	if (root[0] == '~' && root[1] == '/') {
 		char* home = getenv("HOME");
@@ -656,7 +689,7 @@ int FILESEARCH::InitRoot(char* root) {
 	return 0;
 }
 
-void FILESEARCH::SetFileInformation(FILETYPE tp, ARCTYPE is_arc, char* filename) {
+void FileSearcher::SetFileInformation(FILETYPE tp, ARCTYPE is_arc, char* filename) {
 	int type = tp;
 	if (type < 0 || type >= TYPEMAX) return;
 	ARCFILE* next_arc = NULL;
@@ -678,7 +711,7 @@ void FILESEARCH::SetFileInformation(FILE
 		searcher[type]->SetNext(next_arc);
 }
 
-void FILESEARCH::AppendFileInformation(FILETYPE tp, ARCTYPE is_arc, char* filename) {
+void FileSearcher::AppendFileInformation(FILETYPE tp, ARCTYPE is_arc, char* filename) {
 	int type = tp;
 	if (type < 0 || type >= TYPEMAX) return;
 	/* searcher がまだ割り当てられてない場合 */
@@ -700,7 +733,7 @@ void FILESEARCH::AppendFileInformation(F
 	cur->SetNext(arc);
 }
 
-ARCFILE* FILESEARCH::MakeARCFILE(ARCTYPE tp, const char* filename) {
+ARCFILE* FileSearcher::MakeARCFILE(ARCTYPE tp, const char* filename) {
 	ARCFILE* arc = NULL;
 	char* file;
 	if (filename == NULL) goto err;
@@ -727,7 +760,7 @@ ARCFILE* FILESEARCH::MakeARCFILE(ARCTYPE
 			else arc = new SCN2kFILE(file);
 			}
 			break;
-		default: fprintf(stderr,"FILESEARCH::MAKEARCFILE : invalid archive type; type %d name %s\n",tp,filename);
+		default: fprintf(stderr,"FileSearcher::MAKEARCFILE : invalid archive type; type %d name %s\n",tp,filename);
 			delete[] file;
 			goto err;
 	}
@@ -738,7 +771,7 @@ err:
 	return arc;
 }
 
-ARCINFO* FILESEARCH::Find(FILETYPE type, const char* fname, const char* ext) {
+ARCINFO* FileSearcher::Find(FILETYPE type, const char* fname, const char* ext) {
 	if (searcher[type] == NULL) {
 		/* searcher 作成 */
 		if (filenames[type] == NULL) {
@@ -746,7 +779,7 @@ ARCINFO* FILESEARCH::Find(FILETYPE type,
 		} else {
 			searcher[type] = MakeARCFILE(is_archived[type], filenames[type]);
 			if (searcher[type] == NULL) {
-				fprintf(stderr,"FILESEARCH::Find : invalid archive type; type %d name %s\n",type,fname);
+				fprintf(stderr,"FileSearcher::Find : invalid archive type; type %d name %s\n",type,fname);
 				return NULL;
 			}
 		}
@@ -754,7 +787,7 @@ ARCINFO* FILESEARCH::Find(FILETYPE type,
 	return searcher[type]->Find(fname,ext);
 }
 
-char** FILESEARCH::ListAll(FILETYPE type) {
+char** FileSearcher::ListAll(FILETYPE type) {
 	/* とりあえず searcher を初期化 */
 	Find(type, "THIS FILENAME MAY NOT EXIST IN THE FILE SYSTEM !!!");
 	if (searcher[type] == NULL) return NULL;
@@ -1503,7 +1536,7 @@ bool ARCINFO2k::ExecExtract(void) {
 		while(lzExtract(Extract_DataType_SCN2k(), char(), s, d, send, dend)) ;
 	}
 	if (read_little_endian_int(data+4) == 0x1adb2) { // Little Busters!
-		const char *decode_key = key_holder.GetKey();
+		const char *decode_key = KeyHolder::GetInstance()->GetKey();
 		int header_size = info.private_data;
 		for (i=0x100; i<=0x200 && header_size+i < info.filesize; i++) {
 			ret_data[header_size+i] ^= decode_key[i&0x0f];
--- a/system/file.h
+++ b/system/file.h
@@ -1,6 +1,6 @@
 /*  file.h  : KANON の圧縮ファイル・PDT ファイル(画像ファイル)の展開の
  *            ためのクラス
- *     class FILESEARCH : ファイルの管理を行う
+ *     class FileSearcher : ファイルの管理を行う
  *     class ARCINFO : 書庫ファイルの中の1つのファイルを扱うクラス
  *     class PDTCONV : PDT ファイルの展開を行う。
  */
@@ -87,7 +87,7 @@ static int write_little_endian_short(cha
 
 
 /*********************************************
-**  FILESEARCH:
+**  FileSearcher:
 **	書庫ファイル/ディレクトリを含め、
 **	全ファイルの管理を行う。
 **
@@ -106,17 +106,28 @@ class SCN2kFILE;
 class ARCINFO;
 class ARCFILE_ATOM;
 
-class KEYHOLDER {
+class KeyHolder {
 	public:
+		static KeyHolder* GetInstance(void);
+		static void Quit(void);
+
 		void SetKey(char[16]);
 		void SetKey2(char[33]);
 		void GuessKey(char*);
+
+	private:
+		KeyHolder(){}
+		~KeyHolder(){}
+
+	public:
 		const char* GetKey(void);
+
 	private:
 		char key[16];
+		static KeyHolder* _singleton;
 };
 
-class FILESEARCH {
+class FileSearcher {
 	public:
 #define TYPEMAX 14
 		enum FILETYPE {
@@ -136,20 +147,11 @@ class FILESEARCH {
 			GAN = 13  /* default : MOV */
 		};
 		enum ARCTYPE {ATYPE_DIR, ATYPE_ARC, ATYPE_SCN2k};
-	private:
-		/* InitRoot() の時点で初期化される変数 */
-		DIRFILE* root_dir;
-		DIRFILE* dat_dir;
-		ARCFILE* searcher[TYPEMAX];
-		/* ファイルの存在位置の information */
-		ARCTYPE is_archived[TYPEMAX];
-		const char* filenames[TYPEMAX];
-		/* デフォルトの information */
-		static ARCTYPE default_is_archived[TYPEMAX];
-		static const char* default_dirnames[TYPEMAX];
+
 	public:
-		FILESEARCH(void);
-		~FILESEARCH();
+		static FileSearcher* GetInstance(void);
+		static void Quit(void);
+
 		/* 初めにゲームのデータがあるディレクトリを設定する必要がある */
 		int InitRoot(char* root);
 		/* ファイルの型ごとの情報をセットする */
@@ -165,6 +167,23 @@ class FILESEARCH {
 		** 末尾は NULL pointer
 		*/
 		char** ListAll(FILETYPE type);
+
+	private:
+		FileSearcher(void);
+		~FileSearcher();
+
+	private:
+		/* InitRoot() の時点で初期化される変数 */
+		DIRFILE* root_dir;
+		DIRFILE* dat_dir;
+		ARCFILE* searcher[TYPEMAX];
+		/* ファイルの存在位置の information */
+		ARCTYPE is_archived[TYPEMAX];
+		const char* filenames[TYPEMAX];
+		/* デフォルトの information */
+		static ARCTYPE default_is_archived[TYPEMAX];
+		static const char* default_dirnames[TYPEMAX];
+		static FileSearcher *_singleton;
 };
 
 class ARCINFO {
@@ -231,7 +250,4 @@ class GRPCONV {
 		void CopyRGB_rev(char* image, const char* from);
 };
 
-extern FILESEARCH file_searcher;
-extern KEYHOLDER key_holder;
-
 #endif // !defined(__KANON_FILE_H__)
--- a/system/system_config.cc
+++ b/system/system_config.cc
@@ -70,6 +70,7 @@ public:
 		else return a.hash < b.hash;
 	}
 };
+
 HashStr::HashStr(const char* s ) {
 	if (s == NULL || s[0] == '\0') {
 		str = NULL;
@@ -676,6 +677,25 @@ void AyuSysConfig::Dump(FILE* f) const {
 ** AyuSysConfig のコンストラクタ:
 ** 全ての config 項目を初期化する
 */
+
+AyuSysConfig * AyuSysConfig::_singleton = NULL;
+
+AyuSysConfig* AyuSysConfig::GetInstance(void)
+{
+	if (_singleton == NULL)
+		_singleton = new AyuSysConfig;
+	return _singleton;
+}
+
+void AyuSysConfig::Quit(void)
+{
+	if (_singleton != NULL) {
+		delete _singleton;
+		_singleton = NULL;
+	}
+}
+
+
 AyuSysConfig::AyuSysConfig(void) {
 	int i;
 
@@ -889,11 +909,13 @@ static inline int SplitVar(const char* s
 
 bool AyuSysConfig::LoadInitFile(void)
 {
+	FileSearcher* file_searcher = FileSearcher::GetInstance();
+
 	char buf[1024]; int i;
 	char* tokens[MAXTOKEN]; int token_deal; int buf_ptr;
 	int numbers[MAXVARS];
 
-	ARCINFO* info = file_searcher.Find(FILESEARCH::ROOT, "gameexe.ini");
+	ARCINFO* info = file_searcher->Find(FileSearcher::ROOT, "gameexe.ini");
 	if (info == NULL) return false;
 	int size = info->Size();
 	unsigned char* buf_orig = (unsigned char*)info->Read();
@@ -1000,24 +1022,24 @@ bool AyuSysConfig::LoadInitFile(void)
 		} else if (strncmp(tokens[0],"#DIRC.",6) == 0) {
 			if (token_deal != 3) goto parse_error;
 			/* ファイル形式の指定 */
-			FILESEARCH::FILETYPE type;
+			FileSearcher::FILETYPE type;
 			char* name = tokens[0]+6;
-			if (strcmp(name, "PDT") == 0) type = FILESEARCH::PDT;
-			else if (strcmp(name, "G00") == 0) type = FILESEARCH::PDT;
-			else if (strcmp(name, "GRP") == 0) type = FILESEARCH::PDT;
-			else if (strcmp(name, "TXT") == 0) type = FILESEARCH::SCN;
-			else if (strcmp(name, "ANM") == 0) type = FILESEARCH::ANM; 
-			else if (strcmp(name, "ARD") == 0) type = FILESEARCH::ARD;
-			else if (strcmp(name, "CUR") == 0) type = FILESEARCH::CUR;
-			else if (strcmp(name, "WAV") == 0) type = FILESEARCH::WAV;
-			else if (strcmp(name, "KOE") == 0) type = FILESEARCH::KOE;
-			else if (strcmp(name, "GAN") == 0) type = FILESEARCH::GAN;
+			if (strcmp(name, "PDT") == 0) type = FileSearcher::PDT;
+			else if (strcmp(name, "G00") == 0) type = FileSearcher::PDT;
+			else if (strcmp(name, "GRP") == 0) type = FileSearcher::PDT;
+			else if (strcmp(name, "TXT") == 0) type = FileSearcher::SCN;
+			else if (strcmp(name, "ANM") == 0) type = FileSearcher::ANM; 
+			else if (strcmp(name, "ARD") == 0) type = FileSearcher::ARD;
+			else if (strcmp(name, "CUR") == 0) type = FileSearcher::CUR;
+			else if (strcmp(name, "WAV") == 0) type = FileSearcher::WAV;
+			else if (strcmp(name, "KOE") == 0) type = FileSearcher::KOE;
+			else if (strcmp(name, "GAN") == 0) type = FileSearcher::GAN;
 			else goto parse_error; /* 他に ALL,ROOT,MID,KOE,BGM。たぶん、存在しない */
 			if (tokens[2][0] == 'N') { /* directory */
-				file_searcher.SetFileInformation(type, FILESEARCH::ATYPE_DIR, tokens[1]);
+				file_searcher->SetFileInformation(type, FileSearcher::ATYPE_DIR, tokens[1]);
 				dprintf(("set file directory; type %s, directory %s\n",name,tokens[1]));
 			} else if (tokens[2][0] == 'P' && tokens[2][1] == ':') { /* アーカイブ */
-				file_searcher.SetFileInformation(type, FILESEARCH::ATYPE_ARC, tokens[2]+2);
+				file_searcher->SetFileInformation(type, FileSearcher::ATYPE_ARC, tokens[2]+2);
 				dprintf(("set file archive; type %s, file %s\n",name,tokens[2]+2));
 			} else goto parse_error;
 			goto parse_end;
@@ -1025,27 +1047,27 @@ bool AyuSysConfig::LoadInitFile(void)
 		if (strncmp(tokens[0],"#ADRC.",6) == 0) {
 			if (token_deal != 3) goto parse_error;
 			/* ファイル形式の指定 */
-			FILESEARCH::FILETYPE type;
+			FileSearcher::FILETYPE type;
 			char* name = tokens[0]+6;
-			if (strcmp(name, "PDT") == 0) type = FILESEARCH::PDT;
-			else if (strcmp(name, "G00") == 0) type = FILESEARCH::PDT;
-			else if (strcmp(name, "GRP") == 0) type = FILESEARCH::PDT;
-			else if (strcmp(name, "TXT") == 0) type = FILESEARCH::SCN;
-			else if (strcmp(name, "ANM") == 0) type = FILESEARCH::ANM; 
-			else if (strcmp(name, "ARD") == 0) type = FILESEARCH::ARD;
-			else if (strcmp(name, "CUR") == 0) type = FILESEARCH::CUR;
-			else if (strcmp(name, "WAV") == 0) type = FILESEARCH::WAV;
-			else if (strcmp(name, "KOE") == 0) type = FILESEARCH::KOE;
-			else if (strcmp(name, "GAN") == 0) type = FILESEARCH::GAN;
+			if (strcmp(name, "PDT") == 0) type = FileSearcher::PDT;
+			else if (strcmp(name, "G00") == 0) type = FileSearcher::PDT;
+			else if (strcmp(name, "GRP") == 0) type = FileSearcher::PDT;
+			else if (strcmp(name, "TXT") == 0) type = FileSearcher::SCN;
+			else if (strcmp(name, "ANM") == 0) type = FileSearcher::ANM; 
+			else if (strcmp(name, "ARD") == 0) type = FileSearcher::ARD;
+			else if (strcmp(name, "CUR") == 0) type = FileSearcher::CUR;
+			else if (strcmp(name, "WAV") == 0) type = FileSearcher::WAV;
+			else if (strcmp(name, "KOE") == 0) type = FileSearcher::KOE;
+			else if (strcmp(name, "GAN") == 0) type = FileSearcher::GAN;
 			else goto parse_error; /* 他に ALL,ROOT,MID,KOE,BGM。たぶん、存在しない */
 			if (tokens[2][0] == 'N') { /* directory */
-				file_searcher.AppendFileInformation(type, FILESEARCH::ATYPE_DIR, tokens[1]);
+				file_searcher->AppendFileInformation(type, FileSearcher::ATYPE_DIR, tokens[1]);
 				dprintf(("set file directory; type %s, directory %s\n",name,tokens[1]));
 			} else if (tokens[2][0] == 'P' && tokens[2][1] == ':') { /* アーカイブ */
-				file_searcher.AppendFileInformation(type, FILESEARCH::ATYPE_ARC, tokens[2]+2);
+				file_searcher->AppendFileInformation(type, FileSearcher::ATYPE_ARC, tokens[2]+2);
 				dprintf(("set file archive; type %s, file %s\n",name,tokens[2]+2));
 			} else if (tokens[2][0] == 'R' && tokens[2][1] == ':') { /* それ散るアーカイブ */
-				file_searcher.AppendFileInformation(type, FILESEARCH::ATYPE_ARC, tokens[2]+2);
+				file_searcher->AppendFileInformation(type, FileSearcher::ATYPE_ARC, tokens[2]+2);
 				dprintf(("set file archive; type %s, file %s\n",name,tokens[2]+2));
 			} else goto parse_error;
 			goto parse_end;
@@ -1053,24 +1075,24 @@ bool AyuSysConfig::LoadInitFile(void)
 		if (strncmp(tokens[0],"#FOLDNAME.",10) == 0) {
 			if (token_deal != 3) goto parse_error;
 			/* ファイル形式の指定 */
-			FILESEARCH::FILETYPE type;
+			FileSearcher::FILETYPE type;
 			char* name = tokens[0]+10;
-			if (strcmp(name, "PDT") == 0) type = FILESEARCH::PDT;
-			else if (strcmp(name, "G00") == 0) type = FILESEARCH::PDT;
-			else if (strcmp(name, "GRP") == 0) type = FILESEARCH::PDT;
-			else if (strcmp(name, "TXT") == 0) type = FILESEARCH::SCN;
-			else if (strcmp(name, "ANM") == 0) type = FILESEARCH::ANM; 
-			else if (strcmp(name, "ARD") == 0) type = FILESEARCH::ARD;
-			else if (strcmp(name, "CUR") == 0) type = FILESEARCH::CUR;
-			else if (strcmp(name, "WAV") == 0) type = FILESEARCH::WAV;
-			else if (strcmp(name, "BGM") == 0) type = FILESEARCH::BGM;
-			else if (strcmp(name, "GAN") == 0) type = FILESEARCH::GAN;
+			if (strcmp(name, "PDT") == 0) type = FileSearcher::PDT;
+			else if (strcmp(name, "G00") == 0) type = FileSearcher::PDT;
+			else if (strcmp(name, "GRP") == 0) type = FileSearcher::PDT;
+			else if (strcmp(name, "TXT") == 0) type = FileSearcher::SCN;
+			else if (strcmp(name, "ANM") == 0) type = FileSearcher::ANM; 
+			else if (strcmp(name, "ARD") == 0) type = FileSearcher::ARD;
+			else if (strcmp(name, "CUR") == 0) type = FileSearcher::CUR;
+			else if (strcmp(name, "WAV") == 0) type = FileSearcher::WAV;
+			else if (strcmp(name, "BGM") == 0) type = FileSearcher::BGM;
+			else if (strcmp(name, "GAN") == 0) type = FileSearcher::GAN;
 			else goto parse_error; /* 他に ALL,ROOT,MID,KOE,BGM。たぶん、存在しない */
 			if (tokens[2][0] == '0') { /* directory */
-				file_searcher.AppendFileInformation(type, FILESEARCH::ATYPE_DIR, tokens[1]);
+				file_searcher->AppendFileInformation(type, FileSearcher::ATYPE_DIR, tokens[1]);
 				dprintf(("set file directory; type %s, directory %s\n",name,tokens[1]));
 			} else if (tokens[2][0] == '1' && tokens[2][1] == ':') { /* アーカイブ */
-				file_searcher.AppendFileInformation(type, FILESEARCH::ATYPE_SCN2k, tokens[2]+2);
+				file_searcher->AppendFileInformation(type, FileSearcher::ATYPE_SCN2k, tokens[2]+2);
 				dprintf(("set file archive; type %s, file %s\n",name,tokens[2]+2));
 			} else goto parse_error;
 			goto parse_end;
--- a/system/system_config.h
+++ b/system/system_config.h
@@ -57,18 +57,10 @@ class TrackName {
 */
 
 class AyuSysConfig {
-	private:
-		int change_flag;
-		int dirty_flag;
-		class AyuSysConfigString* str_config;
-		class AyuSysConfigIntlist* int_config;
+	public:
+		static AyuSysConfig* GetInstance(void);
+		static void Quit(void);
 
-	public:
-		TrackName track_name;
-
-	public:
-		AyuSysConfig(void);
-		~AyuSysConfig();
 		bool LoadInitFile(void);
 		/* パラメータを検索する */
 		/* str なら 1, int なら 2, 見つからないなら 0 */
@@ -87,14 +79,6 @@ class AyuSysConfig {
 		void SetParaStr(const char* name, const char* var); /* str */
 		void SetParam(const char* name, int deal, ...); /* int */
 
-	private:
-		/* 元設定を行う */
-		/* AyuSys からのみ可能 */
-		void SetOrigParaStr(const char* name, const char* var); /* str */
-		void SetOrigParam(const char* name, int para_deal, ...); /* int */
-		void SetOrigParamArray(const char* name, int deal, int* array); /* 上とおなじ */
-
-	public:
 		/* オリジナルの設定関係
 		** SetOriginal : 全ての設定を初めの状態に戻す
 		** DiffOriginal : 初めの状態と現在の状態の変更分を得る
@@ -106,5 +90,24 @@ class AyuSysConfig {
 		const char* PatchOriginal(const char*);
 		/* config の内容を表示する */
 		void Dump(FILE* f) const;
+
+	private:
+		/* 元設定を行う */
+		/* AyuSys からのみ可能 */
+		void SetOrigParaStr(const char* name, const char* var); /* str */
+		void SetOrigParam(const char* name, int para_deal, ...); /* int */
+		void SetOrigParamArray(const char* name, int deal, int* array); /* 上とおなじ */
+		AyuSysConfig(void);
+		~AyuSysConfig();
+
+	public:
+		TrackName track_name;
+
+	private:
+		int change_flag;
+		int dirty_flag;
+		class AyuSysConfigString* str_config;
+		class AyuSysConfigIntlist* int_config;
+		static AyuSysConfig* _singleton;
 };
 
--- a/window/picture.cc
+++ b/window/picture.cc
@@ -337,7 +337,7 @@ void PicBase::SetSurfaceAlphaFile(const 
 
 	/* ファイルを元に alpha 画像を作成する */
 	/* ファイル: パルフェの 'fil' ファイル */
-	ARCINFO* info = file_searcher.Find(FILESEARCH::PDT, file,"fil");
+	ARCINFO* info = FileSearcher::GetInstance()->Find(FileSearcher::PDT, file,"fil");
 	if (info == NULL) return;
 	char* new_alpha = info->CopyRead();
 	int alpha_size = info->Size();
@@ -762,7 +762,7 @@ inline bool FileToSurface::DeleteData(Su
 }
 
 inline Surface* FileToSurface::LoadSurface(string name, char*& mem) {
-	ARCINFO* info = file_searcher.Find(FILESEARCH::PDT, name.c_str(),"pdt");
+	ARCINFO* info = FileSearcher::GetInstance()->Find(FileSearcher::PDT, name.c_str(), "pdt");
 	if (info == NULL) return NULL;
 	GRPCONV* conv = GRPCONV::AssignConverter(info);
 	if (conv == NULL) {
--- a/window/widget.cc
+++ b/window/widget.cc
@@ -486,7 +486,8 @@ TextButton::TextButton(Event::Container&
 	int width = r.width(); int height = r.height();
 	if (width == 0) width = parent->Width() - r.lx;
 
-	TextGlyphStream gs = DefaultLayout(text_size)->Layout(text, width);
+	TextStream ts = TextStream::ParseMoji(text, _fore.r , _fore.g, _fore.b, text_size);
+	TextGlyphStream gs = DefaultLayout(text_size)->Layout(ts, width);
 
 	if (r.width() == 0) { // 文字に合わせてウィジット作成
 		rect_changed = true;
--- a/xlovesys.cc
+++ b/xlovesys.cc
@@ -58,7 +58,7 @@ const char key_lb_new[] = "KEY\\LittleBu
 extern "C" int main(int argc, char* argv[]); /* SDL.h で定義されるので必要ないはずなんだけど…… */
 
 int main(int argc, char *argv[]) {
-	AyuSysConfig config;
+	AyuSysConfig *config = AyuSysConfig::GetInstance();
 	int opt = 0, end = 0, screenmode = 0;
 	char rootPath[1024]  = "/mnt/KEY/CLANNAD";
 	char font[1024]      = "msgothic.ttc";
@@ -113,29 +113,28 @@ int main(int argc, char *argv[]) {
 	printf("  Font      : %s\n", font);
 	printf("\n");
 
-	file_searcher.InitRoot(rootPath);
-	config.LoadInitFile();
-	const char* regname = config.GetParaStr("#REGNAME");
+	FileSearcher::GetInstance()->InitRoot(rootPath);
+	config->LoadInitFile();
+	const char* regname = config->GetParaStr("#REGNAME");
 	if (strcmp(regname, key_lb_orig) == 0) { // "リトルバスターズ! -> LittleBustersに#REGNAMEを変更
-		config.SetParaStr("#REGNAME", key_lb_new);
+		config->SetParaStr("#REGNAME", key_lb_new);
 	}
 	if (xor_key == NULL)
-		key_holder.GuessKey((char*)regname);
+		KeyHolder::GetInstance()->GuessKey((char*)regname);
 	else {
-		key_holder.SetKey2(xor_key);
+		KeyHolder::GetInstance()->SetKey2(xor_key);
 		delete[] xor_key;
 	}
 	SetFont(font);
 
-	MuSys mu(config);
-	mu.InitMusic();
+	MuSys::GetInstance()->InitMusic();
 
 	if(SDL_Init(SDL_INIT_VIDEO)) {
 		printf("Unable to init SDL: %s\n", SDL_GetError());
 		return 1;
 	}
 
-	config.GetParam("#SCREENSIZE_MOD", 1, &screenmode);
+	config->GetParam("#SCREENSIZE_MOD", 1, &screenmode);
 	if (screenmode == 1) {
 		SDL_SetVideoMode(800, 600, 0, videoOptions);
 	} else {
@@ -148,15 +147,17 @@ int main(int argc, char *argv[]) {
 	PicContainer* main_panel = main_sys.root.create_node(Rect(0, 0, main_sys.root.width, main_sys.root.height), 0);
 	main_panel->show();
 	try {
-		Scn2k scn(main_sys.event, *main_panel, mu, config);
+		Scn2k scn(main_sys.event, *main_panel);
 		main_sys.Mainloop();
 	} catch(...) {
 		fprintf(stderr,"System faulted; exit now.\n");
 	}
 	delete main_panel;
 
-
-	mu.FinalizeMusic();
+	MuSys::Quit();
+	KeyHolder::Quit();
+	AyuSysConfig::Quit();
+	FileSearcher::Quit();
 
 	SDL_Quit();
 }