From a7407edaf81c685d4a389785a405a53a5de4b148 Mon Sep 17 00:00:00 2001
From: Chris Xiong <chirs241097@gmail.com>
Date: Tue, 12 May 2020 00:58:40 +0800
Subject: Format EVERYTHING.

Hopefully this will make the source code less horrendous and actually
readable.

The command used was:
```
astyle --suffix=none --style=allman --attach-extern-c --attach-closing-while --indent-switches --indent-after-parens --pad-oper --pad-header --unpad-paren --align-pointer=name --recursive './*.cpp,*.hpp'
```
---
 visualization/extrasmeltutils.cpp           |  657 ++++----
 visualization/extrasmeltutils.hpp           |  234 +--
 visualization/qmpvirtualpiano3d.cpp         |  426 ++---
 visualization/qmpvirtualpiano3d.hpp         |   20 +-
 visualization/qmpvisualization.cpp          | 2249 +++++++++++++++------------
 visualization/qmpvisualization.hpp          |  188 ++-
 visualization/renderer/main.cpp             |   80 +-
 visualization/renderer/qmppluginapistub.cpp |  220 ++-
 visualization/renderer/qmppluginapistub.hpp |  140 +-
 visualization/renderer/qmpsettingsro.cpp    |  310 ++--
 visualization/renderer/qmpsettingsro.hpp    |  103 +-
 visualization/renderer/qmpvisrendercore.cpp |  463 +++---
 visualization/renderer/qmpvisrendercore.hpp |   67 +-
 13 files changed, 2867 insertions(+), 2290 deletions(-)

(limited to 'visualization')

diff --git a/visualization/extrasmeltutils.cpp b/visualization/extrasmeltutils.cpp
index 2d0a807..ec9f021 100644
--- a/visualization/extrasmeltutils.cpp
+++ b/visualization/extrasmeltutils.cpp
@@ -3,367 +3,494 @@
 #include <algorithm>
 #include <smcolor.hpp>
 #include "extrasmeltutils.hpp"
-SMELT* smEntity3DBuffer::sm=nullptr;
-SMELT* smParticle::sm=nullptr;
-SMELT* smParticleSystem::sm=nullptr;
-smVertex makeVertex(float x,float y,float z,DWORD color,float tx,float ty)
-{smVertex v;v.x=x;v.y=y;v.z=z;v.col=color;v.tx=tx;v.ty=ty;return v;}
-void smEntity3D::addVertices(size_t n,...)
-{
-	va_list vl;va_start(vl,n);
-	for(int i=0;i<n;++i)
-	{
-		smVertex v=va_arg(vl,smVertex);
-		vertices.push_back(v);
-	}
-	va_end(vl);
-}
-void smEntity3D::addIndices(size_t n,...)
-{
-	va_list vl;va_start(vl,n);
-	for(int i=0;i<n;++i)
-	{
-		int idx=va_arg(vl,int);
-		indices.push_back((WORD)idx);
-	}
-	va_end(vl);
+SMELT *smEntity3DBuffer::sm = nullptr;
+SMELT *smParticle::sm = nullptr;
+SMELT *smParticleSystem::sm = nullptr;
+smVertex makeVertex(float x, float y, float z, DWORD color, float tx, float ty)
+{
+    smVertex v;
+    v.x = x;
+    v.y = y;
+    v.z = z;
+    v.col = color;
+    v.tx = tx;
+    v.ty = ty;
+    return v;
+}
+void smEntity3D::addVertices(size_t n, ...)
+{
+    va_list vl;
+    va_start(vl, n);
+    for (int i = 0; i < n; ++i)
+    {
+        smVertex v = va_arg(vl, smVertex);
+        vertices.push_back(v);
+    }
+    va_end(vl);
+}
+void smEntity3D::addIndices(size_t n, ...)
+{
+    va_list vl;
+    va_start(vl, n);
+    for (int i = 0; i < n; ++i)
+    {
+        int idx = va_arg(vl, int);
+        indices.push_back((WORD)idx);
+    }
+    va_end(vl);
 }
 smVertex smEntity3D::vertex(size_t idx)const
 {
-	if(idx>0&&idx<vertices.size())return vertices[idx];
-	return smVertex();
+    if (idx > 0 && idx < vertices.size())
+        return vertices[idx];
+    return smVertex();
 }
 WORD smEntity3D::index(size_t idx)const
 {
-	if(idx>0&&idx<indices.size())return indices[idx];
-	return 0;
+    if (idx > 0 && idx < indices.size())
+        return indices[idx];
+    return 0;
 }
-void smEntity3D::setVertex(size_t idx,smVertex v)
+void smEntity3D::setVertex(size_t idx, smVertex v)
 {
-	if(idx>0&&idx<vertices.size())vertices[idx]=v;
+    if (idx > 0 && idx < vertices.size())
+        vertices[idx] = v;
 }
-void smEntity3D::setIndex(size_t idx,WORD i)
+void smEntity3D::setIndex(size_t idx, WORD i)
 {
-	if(idx>0&&idx<indices.size())indices[idx]=i;
+    if (idx > 0 && idx < indices.size())
+        indices[idx] = i;
 }
 
-smEntity3D smEntity3D::cube(smvec3d a,smvec3d b,DWORD color,int faces)
-{
-	smEntity3D ret;
-	ret.addVertices(8,
-		makeVertex(a.x,a.y,a.z,color,0,0),makeVertex(b.x,a.y,a.z,color,0,0),
-		makeVertex(b.x,b.y,a.z,color,0,0),makeVertex(a.x,b.y,a.z,color,0,0),
-		makeVertex(a.x,a.y,b.z,color,0,0),makeVertex(b.x,a.y,b.z,color,0,0),
-		makeVertex(b.x,b.y,b.z,color,0,0),makeVertex(a.x,b.y,b.z,color,0,0));
-	if(faces&0x1)//a.z
-		ret.addIndices(6, 0,1,3, 1,2,3);
-	if(faces&0x2)//b.z
-		ret.addIndices(6, 4,5,7, 5,6,7);
-	if(faces&0x4)//a.x
-		ret.addIndices(6, 0,3,7, 0,4,7);
-	if(faces&0x8)//b.x
-		ret.addIndices(6, 1,2,6, 1,5,6);
-	if(faces&0x10)//a.y
-		ret.addIndices(6, 0,1,4, 1,4,5);
-	if(faces&0x20)//b.y
-		ret.addIndices(6, 2,3,7, 2,6,7);
-	return ret;
+smEntity3D smEntity3D::cube(smvec3d a, smvec3d b, DWORD color, int faces)
+{
+    smEntity3D ret;
+    ret.addVertices(8,
+        makeVertex(a.x, a.y, a.z, color, 0, 0), makeVertex(b.x, a.y, a.z, color, 0, 0),
+        makeVertex(b.x, b.y, a.z, color, 0, 0), makeVertex(a.x, b.y, a.z, color, 0, 0),
+        makeVertex(a.x, a.y, b.z, color, 0, 0), makeVertex(b.x, a.y, b.z, color, 0, 0),
+        makeVertex(b.x, b.y, b.z, color, 0, 0), makeVertex(a.x, b.y, b.z, color, 0, 0));
+    if (faces & 0x1) //a.z
+        ret.addIndices(6, 0, 1, 3, 1, 2, 3);
+    if (faces & 0x2) //b.z
+        ret.addIndices(6, 4, 5, 7, 5, 6, 7);
+    if (faces & 0x4) //a.x
+        ret.addIndices(6, 0, 3, 7, 0, 4, 7);
+    if (faces & 0x8) //b.x
+        ret.addIndices(6, 1, 2, 6, 1, 5, 6);
+    if (faces & 0x10) //a.y
+        ret.addIndices(6, 0, 1, 4, 1, 4, 5);
+    if (faces & 0x20) //b.y
+        ret.addIndices(6, 2, 3, 7, 2, 6, 7);
+    return ret;
 }
 smEntity3DBuffer::smEntity3DBuffer()
 {
-	sm=smGetInterface(SMELT_APILEVEL);
-	vertices.clear();indices.clear();
+    sm = smGetInterface(SMELT_APILEVEL);
+    vertices.clear();
+    indices.clear();
 }
-void smEntity3DBuffer::addTransformedEntity(smEntity3D *entity,smMatrix t,smvec3d p)
+void smEntity3DBuffer::addTransformedEntity(smEntity3D *entity, smMatrix t, smvec3d p)
 {
-	if(entity->vertices.size()+vertices.size()>4000)drawBatch();
-	for(unsigned i=0;i<entity->indices.size();++i)
-	indices.push_back(entity->indices[i]+vertices.size());
-	for(unsigned i=0;i<entity->vertices.size();++i)
-	{
-		smvec3d tp=smvec3d(entity->vertices[i].x,entity->vertices[i].y,entity->vertices[i].z);
-		tp=t*tp;tp=tp+p;vertices.push_back(makeVertex(tp.x,tp.y,tp.z,entity->vertices[i].col,entity->vertices[i].tx,entity->vertices[i].ty));
-	}
+    if (entity->vertices.size() + vertices.size() > 4000)
+        drawBatch();
+    for (unsigned i = 0; i < entity->indices.size(); ++i)
+        indices.push_back(entity->indices[i] + vertices.size());
+    for (unsigned i = 0; i < entity->vertices.size(); ++i)
+    {
+        smvec3d tp = smvec3d(entity->vertices[i].x, entity->vertices[i].y, entity->vertices[i].z);
+        tp = t * tp;
+        tp = tp + p;
+        vertices.push_back(makeVertex(tp.x, tp.y, tp.z, entity->vertices[i].col, entity->vertices[i].tx, entity->vertices[i].ty));
+    }
 }
 void smEntity3DBuffer::drawBatch()
 {
-	if(!vertices.size())return;
-	sm->smDrawCustomIndexedVertices(&vertices[0],&indices[0],vertices.size(),indices.size(),BLEND_ALPHABLEND,0);
-	vertices.clear();indices.clear();
+    if (!vertices.size())
+        return;
+    sm->smDrawCustomIndexedVertices(&vertices[0], &indices[0], vertices.size(), indices.size(), BLEND_ALPHABLEND, 0);
+    vertices.clear();
+    indices.clear();
 }
 smParticle::smParticle()
-{sm=smGetInterface(SMELT_APILEVEL);dead=false;clifespan=0;}
-smParticle::~smParticle(){sm->smRelease();}
+{
+    sm = smGetInterface(SMELT_APILEVEL);
+    dead = false;
+    clifespan = 0;
+}
+smParticle::~smParticle()
+{
+    sm->smRelease();
+}
 void smParticle::render()
-{sm->smRenderQuad(&q);}
+{
+    sm->smRenderQuad(&q);
+}
 void smParticle::update()
 {
-	clifespan+=sm->smGetDelta();if(clifespan>lifespan){dead=true;return;}
-	vel=vel+accel;pos=pos+vel;rotv=rotv+rota;rot=rot+rotv;
-	size=clifespan/lifespan*(finalsize-initsize)+initsize;
-	smColorRGBA fc(finalcolor),ic(initcolor),cc;
-	cc.a=clifespan/lifespan*(fc.a-ic.a)+ic.a;
-	cc.r=clifespan/lifespan*(fc.r-ic.r)+ic.r;
-	cc.g=clifespan/lifespan*(fc.g-ic.g)+ic.g;
-	cc.b=clifespan/lifespan*(fc.b-ic.b)+ic.b;
-	color=cc.getHWColor();
-	for(int i=0;i<4;++i)q.v[i].col=color;
-	smMatrix m;m.loadIdentity();
-	if(lookat)m.lookat(pos,lookatpos,smvec3d(0,0,1));else
-	{m.rotate(rot.x,1,0,0);m.rotate(rot.y,0,1,0);m.rotate(rot.z,0,0,1);}
-	smvec3d v0=m*smvec3d(-size,-size,0),v1=m*smvec3d(size,-size,0);
-	smvec3d v2=m*smvec3d(size,size,0),v3=m*smvec3d(-size,size,0);
-	q.v[0].x=v0.x+pos.x;q.v[0].y=v0.y+pos.y;q.v[0].z=v0.z+pos.z;
-	q.v[1].x=v1.x+pos.x;q.v[1].y=v1.y+pos.y;q.v[1].z=v1.z+pos.z;
-	q.v[2].x=v2.x+pos.x;q.v[2].y=v2.y+pos.y;q.v[2].z=v2.z+pos.z;
-	q.v[3].x=v3.x+pos.x;q.v[3].y=v3.y+pos.y;q.v[3].z=v3.z+pos.z;
+    clifespan += sm->smGetDelta();
+    if (clifespan > lifespan)
+    {
+        dead = true;
+        return;
+    }
+    vel = vel + accel;
+    pos = pos + vel;
+    rotv = rotv + rota;
+    rot = rot + rotv;
+    size = clifespan / lifespan * (finalsize - initsize) + initsize;
+    smColorRGBA fc(finalcolor), ic(initcolor), cc;
+    cc.a = clifespan / lifespan * (fc.a - ic.a) + ic.a;
+    cc.r = clifespan / lifespan * (fc.r - ic.r) + ic.r;
+    cc.g = clifespan / lifespan * (fc.g - ic.g) + ic.g;
+    cc.b = clifespan / lifespan * (fc.b - ic.b) + ic.b;
+    color = cc.getHWColor();
+    for (int i = 0; i < 4; ++i)
+        q.v[i].col = color;
+    smMatrix m;
+    m.loadIdentity();
+    if (lookat)
+        m.lookat(pos, lookatpos, smvec3d(0, 0, 1));
+    else
+    {
+        m.rotate(rot.x, 1, 0, 0);
+        m.rotate(rot.y, 0, 1, 0);
+        m.rotate(rot.z, 0, 0, 1);
+    }
+    smvec3d v0 = m * smvec3d(-size, -size, 0), v1 = m * smvec3d(size, -size, 0);
+    smvec3d v2 = m * smvec3d(size, size, 0), v3 = m * smvec3d(-size, size, 0);
+    q.v[0].x = v0.x + pos.x;
+    q.v[0].y = v0.y + pos.y;
+    q.v[0].z = v0.z + pos.z;
+    q.v[1].x = v1.x + pos.x;
+    q.v[1].y = v1.y + pos.y;
+    q.v[1].z = v1.z + pos.z;
+    q.v[2].x = v2.x + pos.x;
+    q.v[2].y = v2.y + pos.y;
+    q.v[2].z = v2.z + pos.z;
+    q.v[3].x = v3.x + pos.x;
+    q.v[3].y = v3.y + pos.y;
+    q.v[3].z = v3.z + pos.z;
 }
 smParticleSystem::smParticleSystem()
-{sm=smGetInterface(SMELT_APILEVEL);particles.clear();posGenerator=nullptr;active=false;}
+{
+    sm = smGetInterface(SMELT_APILEVEL);
+    particles.clear();
+    posGenerator = nullptr;
+    active = false;
+}
 smParticleSystem::~smParticleSystem()
-{for(unsigned i=0;i<particles.size();++i)delete particles[i];particles.clear();}
+{
+    for (unsigned i = 0; i < particles.size(); ++i)
+        delete particles[i];
+    particles.clear();
+}
 void smParticleSystem::setParticleSystemInfo(smParticleSystemInfo _psinfo)
-{psinfo=_psinfo;}
-void smParticleSystem::setPos(smvec3d _pos){pos=_pos;}
+{
+    psinfo = _psinfo;
+}
+void smParticleSystem::setPos(smvec3d _pos)
+{
+    pos = _pos;
+}
 void smParticleSystem::setPSEmissionPosGen(smPSEmissionPositionGenerator *_gen)
-{posGenerator=_gen;}
-void smParticleSystem::setPSLookAt(smvec3d at){lookat=true;lookatpos=at;}
-void smParticleSystem::unsetPSLookAt(){lookat=false;}
+{
+    posGenerator = _gen;
+}
+void smParticleSystem::setPSLookAt(smvec3d at)
+{
+    lookat = true;
+    lookatpos = at;
+}
+void smParticleSystem::unsetPSLookAt()
+{
+    lookat = false;
+}
 void smParticleSystem::startPS()
-{active=true;nemdelay=0;re.setSeed(time(nullptr));}
+{
+    active = true;
+    nemdelay = 0;
+    re.setSeed(time(nullptr));
+}
 void smParticleSystem::stopPS()
-{active=false;}
+{
+    active = false;
+}
 void smParticleSystem::updatePS()
 {
-	cemdelay+=sm->smGetDelta();
-	if(active&&cemdelay>nemdelay&&(int)particles.size()<psinfo.maxcount)
-	{
-		int ec=re.nextInt(psinfo.emissioncount-psinfo.ecvar,psinfo.emissioncount+psinfo.ecvar);
-		for(int i=0;i<ec;++i)
-		{
-			smParticle *p=new smParticle();
-			p->pos=pos+(posGenerator?posGenerator->genPos():smvec3d(0,0,0));
-			p->vel=smvec3d(
-				re.nextDouble(psinfo.vel.x-psinfo.velvar.x,psinfo.vel.x+psinfo.velvar.x),
-				re.nextDouble(psinfo.vel.y-psinfo.velvar.y,psinfo.vel.y+psinfo.velvar.y),
-				re.nextDouble(psinfo.vel.z-psinfo.velvar.z,psinfo.vel.z+psinfo.velvar.z));
-			p->accel=smvec3d(
-				re.nextDouble(psinfo.acc.x-psinfo.accvar.x,psinfo.acc.x+psinfo.accvar.x),
-				re.nextDouble(psinfo.acc.y-psinfo.accvar.y,psinfo.acc.y+psinfo.accvar.y),
-				re.nextDouble(psinfo.acc.z-psinfo.accvar.z,psinfo.acc.z+psinfo.accvar.z));
-			p->rotv=smvec3d(
-				re.nextDouble(psinfo.rotv.x-psinfo.rotvvar.x,psinfo.rotv.x+psinfo.rotvvar.x),
-				re.nextDouble(psinfo.rotv.y-psinfo.rotvvar.y,psinfo.rotv.y+psinfo.rotvvar.y),
-				re.nextDouble(psinfo.rotv.z-psinfo.rotvvar.z,psinfo.rotv.z+psinfo.rotvvar.z));
-			p->rota=smvec3d(
-				re.nextDouble(psinfo.rota.x-psinfo.rotavar.x,psinfo.rota.x+psinfo.rotavar.x),
-				re.nextDouble(psinfo.rota.y-psinfo.rotavar.y,psinfo.rota.y+psinfo.rotavar.y),
-				re.nextDouble(psinfo.rota.z-psinfo.rotavar.z,psinfo.rota.z+psinfo.rotavar.z));
-			p->rot=smvec3d(0,0,0);if(lookat)p->lookat=true,p->lookatpos=lookatpos;else p->lookat=false;
-			p->lifespan=re.nextDouble(psinfo.lifespan-psinfo.lifespanvar,psinfo.lifespan+psinfo.lifespanvar);
-			p->initsize=re.nextDouble(psinfo.initsize-psinfo.initsizevar,psinfo.initsize+psinfo.initsizevar);
-			p->finalsize=re.nextDouble(psinfo.finalsize-psinfo.finalsizevar,psinfo.finalsize+psinfo.finalsizevar);
-			p->size=p->initsize;
-			p->initcolor=ARGB(
-				re.nextInt(GETA(psinfo.initcolor)-GETA(psinfo.initcolorvar),GETA(psinfo.initcolor)+GETA(psinfo.initcolorvar)),
-				re.nextInt(GETR(psinfo.initcolor)-GETR(psinfo.initcolorvar),GETR(psinfo.initcolor)+GETR(psinfo.initcolorvar)),
-				re.nextInt(GETG(psinfo.initcolor)-GETG(psinfo.initcolorvar),GETG(psinfo.initcolor)+GETG(psinfo.initcolorvar)),
-				re.nextInt(GETB(psinfo.initcolor)-GETB(psinfo.initcolorvar),GETB(psinfo.initcolor)+GETB(psinfo.initcolorvar)));
-			p->finalcolor=ARGB(
-				re.nextInt(GETA(psinfo.finalcolor)-GETA(psinfo.finalcolorvar),GETA(psinfo.finalcolor)+GETA(psinfo.finalcolorvar)),
-				re.nextInt(GETR(psinfo.finalcolor)-GETR(psinfo.finalcolorvar),GETR(psinfo.finalcolor)+GETR(psinfo.finalcolorvar)),
-				re.nextInt(GETG(psinfo.finalcolor)-GETG(psinfo.finalcolorvar),GETG(psinfo.finalcolor)+GETG(psinfo.finalcolorvar)),
-				re.nextInt(GETB(psinfo.finalcolor)-GETB(psinfo.finalcolorvar),GETB(psinfo.finalcolor)+GETB(psinfo.finalcolorvar)));
-			p->color=p->initcolor;p->q.tex=psinfo.texture;p->q.blend=psinfo.blend;
-			p->q.v[0].tx=p->q.v[3].tx=0;p->q.v[0].ty=p->q.v[1].ty=0;
-			p->q.v[1].tx=p->q.v[2].tx=1;p->q.v[2].ty=p->q.v[3].ty=1;
-			particles.push_back(p);
-		}
-		cemdelay=0;
-		nemdelay=re.nextDouble(psinfo.emissiondelay-psinfo.edvar,psinfo.emissiondelay+psinfo.edvar);
-	}
-	for(unsigned i=0,j;i<particles.size()&&!particles[i]->dead;++i)
-	{
-		particles[i]->update();
-		if(particles[i]->dead)
-		{
-			for(j=particles.size()-1;j>i&&particles[j]->dead;--j);
-			std::swap(particles[i],particles[j]);
-		}
-	}
-	while(!particles.empty()&&particles.back()->dead)
-	{delete particles.back();particles.back()=nullptr;particles.pop_back();}
+    cemdelay += sm->smGetDelta();
+    if (active && cemdelay > nemdelay && (int)particles.size() < psinfo.maxcount)
+    {
+        int ec = re.nextInt(psinfo.emissioncount - psinfo.ecvar, psinfo.emissioncount + psinfo.ecvar);
+        for (int i = 0; i < ec; ++i)
+        {
+            smParticle *p = new smParticle();
+            p->pos = pos + (posGenerator ? posGenerator->genPos() : smvec3d(0, 0, 0));
+            p->vel = smvec3d(
+                    re.nextDouble(psinfo.vel.x - psinfo.velvar.x, psinfo.vel.x + psinfo.velvar.x),
+                    re.nextDouble(psinfo.vel.y - psinfo.velvar.y, psinfo.vel.y + psinfo.velvar.y),
+                    re.nextDouble(psinfo.vel.z - psinfo.velvar.z, psinfo.vel.z + psinfo.velvar.z));
+            p->accel = smvec3d(
+                    re.nextDouble(psinfo.acc.x - psinfo.accvar.x, psinfo.acc.x + psinfo.accvar.x),
+                    re.nextDouble(psinfo.acc.y - psinfo.accvar.y, psinfo.acc.y + psinfo.accvar.y),
+                    re.nextDouble(psinfo.acc.z - psinfo.accvar.z, psinfo.acc.z + psinfo.accvar.z));
+            p->rotv = smvec3d(
+                    re.nextDouble(psinfo.rotv.x - psinfo.rotvvar.x, psinfo.rotv.x + psinfo.rotvvar.x),
+                    re.nextDouble(psinfo.rotv.y - psinfo.rotvvar.y, psinfo.rotv.y + psinfo.rotvvar.y),
+                    re.nextDouble(psinfo.rotv.z - psinfo.rotvvar.z, psinfo.rotv.z + psinfo.rotvvar.z));
+            p->rota = smvec3d(
+                    re.nextDouble(psinfo.rota.x - psinfo.rotavar.x, psinfo.rota.x + psinfo.rotavar.x),
+                    re.nextDouble(psinfo.rota.y - psinfo.rotavar.y, psinfo.rota.y + psinfo.rotavar.y),
+                    re.nextDouble(psinfo.rota.z - psinfo.rotavar.z, psinfo.rota.z + psinfo.rotavar.z));
+            p->rot = smvec3d(0, 0, 0);
+            if (lookat)
+                p->lookat = true, p->lookatpos = lookatpos;
+            else p->lookat = false;
+            p->lifespan = re.nextDouble(psinfo.lifespan - psinfo.lifespanvar, psinfo.lifespan + psinfo.lifespanvar);
+            p->initsize = re.nextDouble(psinfo.initsize - psinfo.initsizevar, psinfo.initsize + psinfo.initsizevar);
+            p->finalsize = re.nextDouble(psinfo.finalsize - psinfo.finalsizevar, psinfo.finalsize + psinfo.finalsizevar);
+            p->size = p->initsize;
+            p->initcolor = ARGB(
+                    re.nextInt(GETA(psinfo.initcolor) - GETA(psinfo.initcolorvar), GETA(psinfo.initcolor) + GETA(psinfo.initcolorvar)),
+                    re.nextInt(GETR(psinfo.initcolor) - GETR(psinfo.initcolorvar), GETR(psinfo.initcolor) + GETR(psinfo.initcolorvar)),
+                    re.nextInt(GETG(psinfo.initcolor) - GETG(psinfo.initcolorvar), GETG(psinfo.initcolor) + GETG(psinfo.initcolorvar)),
+                    re.nextInt(GETB(psinfo.initcolor) - GETB(psinfo.initcolorvar), GETB(psinfo.initcolor) + GETB(psinfo.initcolorvar)));
+            p->finalcolor = ARGB(
+                    re.nextInt(GETA(psinfo.finalcolor) - GETA(psinfo.finalcolorvar), GETA(psinfo.finalcolor) + GETA(psinfo.finalcolorvar)),
+                    re.nextInt(GETR(psinfo.finalcolor) - GETR(psinfo.finalcolorvar), GETR(psinfo.finalcolor) + GETR(psinfo.finalcolorvar)),
+                    re.nextInt(GETG(psinfo.finalcolor) - GETG(psinfo.finalcolorvar), GETG(psinfo.finalcolor) + GETG(psinfo.finalcolorvar)),
+                    re.nextInt(GETB(psinfo.finalcolor) - GETB(psinfo.finalcolorvar), GETB(psinfo.finalcolor) + GETB(psinfo.finalcolorvar)));
+            p->color = p->initcolor;
+            p->q.tex = psinfo.texture;
+            p->q.blend = psinfo.blend;
+            p->q.v[0].tx = p->q.v[3].tx = 0;
+            p->q.v[0].ty = p->q.v[1].ty = 0;
+            p->q.v[1].tx = p->q.v[2].tx = 1;
+            p->q.v[2].ty = p->q.v[3].ty = 1;
+            particles.push_back(p);
+        }
+        cemdelay = 0;
+        nemdelay = re.nextDouble(psinfo.emissiondelay - psinfo.edvar, psinfo.emissiondelay + psinfo.edvar);
+    }
+    for (unsigned i = 0, j; i < particles.size() && !particles[i]->dead; ++i)
+    {
+        particles[i]->update();
+        if (particles[i]->dead)
+        {
+            for (j = particles.size() - 1; j > i && particles[j]->dead; --j);
+            std::swap(particles[i], particles[j]);
+        }
+    }
+    while (!particles.empty() && particles.back()->dead)
+    {
+        delete particles.back();
+        particles.back() = nullptr;
+        particles.pop_back();
+    }
 }
 void smParticleSystem::renderPS()
-{for(unsigned i=0;i<particles.size();++i)particles[i]->render();}
+{
+    for (unsigned i = 0; i < particles.size(); ++i)
+        particles[i]->render();
+}
 
 smColor::smColor()
-{r=g=b=h=s=v=a=0;}
+{
+    r = g = b = h = s = v = a = 0;
+}
 
 void smColor::update_rgb()
 {
-	auto f=[this](float n){
-		float k=fmodf(n+6.0f*this->h,6.0f);
-		return this->v-this->v*this->s*max(0.0f,min(1.0f,min(k,4.0f-k)));
-	};
-	r=f(5);
-	g=f(3);
-	b=f(1);
+    auto f = [this](float n)
+    {
+        float k = fmodf(n + 6.0f * this->h, 6.0f);
+        return this->v - this->v * this->s * max(0.0f, min(1.0f, min(k, 4.0f - k)));
+    };
+    r = f(5);
+    g = f(3);
+    b = f(1);
 }
 void smColor::update_hsv()
 {
-	v=max(r,max(g,b));
-	float vm=min(r,min(g,b));
-	float chroma=v-vm;
-	if(v-vm<EPSF)h=0;
-	else if(v-r<EPSF)h=(0.0f+(g-b)/chroma)/6.0f;
-	else if(v-g<EPSF)h=(2.0f+(b-r)/chroma)/6.0f;
-	else if(v-b<EPSF)h=(4.0f+(r-g)/chroma)/6.0f;
-	if(v<EPSF)s=0;else s=chroma/v;
+    v = max(r, max(g, b));
+    float vm = min(r, min(g, b));
+    float chroma = v - vm;
+    if (v - vm < EPSF)
+        h = 0;
+    else if (v - r < EPSF)
+        h = (0.0f + (g - b) / chroma) / 6.0f;
+    else if (v - g < EPSF)
+        h = (2.0f + (b - r) / chroma) / 6.0f;
+    else if (v - b < EPSF)
+        h = (4.0f + (r - g) / chroma) / 6.0f;
+    if (v < EPSF)
+        s = 0;
+    else s = chroma / v;
 }
 
 void smColor::clamp(bool hsv)
 {
-	if(hsv)
-	{
-		h=min(1.0f,max(0.0f,h));
-		s=min(1.0f,max(0.0f,s));
-		v=min(1.0f,max(0.0f,v));
-		update_rgb();
-	}
-	else
-	{
-		r=min(1.0f,max(0.0f,r));
-		g=min(1.0f,max(0.0f,g));
-		b=min(1.0f,max(0.0f,b));
-		update_hsv();
-	}
+    if (hsv)
+    {
+        h = min(1.0f, max(0.0f, h));
+        s = min(1.0f, max(0.0f, s));
+        v = min(1.0f, max(0.0f, v));
+        update_rgb();
+    }
+    else
+    {
+        r = min(1.0f, max(0.0f, r));
+        g = min(1.0f, max(0.0f, g));
+        b = min(1.0f, max(0.0f, b));
+        update_hsv();
+    }
 }
 float smColor::alpha()const
-{return a;}
+{
+    return a;
+}
 float smColor::red()const
-{return r;}
+{
+    return r;
+}
 float smColor::green()const
-{return g;}
+{
+    return g;
+}
 float smColor::blue()const
-{return b;}
+{
+    return b;
+}
 float smColor::hue()const
-{return h;}
+{
+    return h;
+}
 float smColor::saturation()const
-{return s;}
+{
+    return s;
+}
 float smColor::hslSaturation()const
 {
-	float l=lightness();
-	if(fabsf(l)<EPSF||fabsf(l-1)<EPSF)return 0;
-	return (v-l)/min(l,1-l);
+    float l = lightness();
+    if (fabsf(l) < EPSF || fabsf(l - 1) < EPSF)
+        return 0;
+    return (v - l) / min(l, 1 - l);
 }
 float smColor::value()const
-{return v;}
+{
+    return v;
+}
 float smColor::lightness()const
-{return v-v*s/2;}
+{
+    return v - v * s / 2;
+}
 
 void smColor::setAlpha(float alpha)
-{a=alpha;}
+{
+    a = alpha;
+}
 void smColor::setRed(float red)
 {
-	if(fabsf(r-red)>EPSF)
-	{
-		r=red;
-		update_hsv();
-	}
+    if (fabsf(r - red) > EPSF)
+    {
+        r = red;
+        update_hsv();
+    }
 }
 void smColor::setGreen(float green)
 {
-	if(fabsf(g-green)>EPSF)
-	{
-		g=green;
-		update_hsv();
-	}
+    if (fabsf(g - green) > EPSF)
+    {
+        g = green;
+        update_hsv();
+    }
 }
 void smColor::setBlue(float blue)
 {
-	if(fabsf(b-blue)>EPSF)
-	{
-		b=blue;
-		update_hsv();
-	}
+    if (fabsf(b - blue) > EPSF)
+    {
+        b = blue;
+        update_hsv();
+    }
 }
 void smColor::setHue(float hue)
 {
-	if(fabsf(h-hue)>EPSF)
-	{
-		h=hue;
-		update_rgb();
-	}
+    if (fabsf(h - hue) > EPSF)
+    {
+        h = hue;
+        update_rgb();
+    }
 }
 void smColor::setSaturation(float saturation)
 {
-	if(fabsf(s-saturation)>EPSF)
-	{
-		s=saturation;
-		update_rgb();
-	}
+    if (fabsf(s - saturation) > EPSF)
+    {
+        s = saturation;
+        update_rgb();
+    }
 }
 void smColor::setHSLSaturation(float saturation)
 {
-	float ss=hslSaturation();
-	float l=lightness();
-	if(fabsf(ss-saturation)>EPSF)
-	{
-		ss=saturation;
-		v=l+ss*min(l,1-l);
-		if(v<EPSF)s=0;
-		else s=2-2*l/v;
-		update_rgb();
-	}
+    float ss = hslSaturation();
+    float l = lightness();
+    if (fabsf(ss - saturation) > EPSF)
+    {
+        ss = saturation;
+        v = l + ss * min(l, 1 - l);
+        if (v < EPSF)
+            s = 0;
+        else s = 2 - 2 * l / v;
+        update_rgb();
+    }
 }
 void smColor::setValue(float value)
 {
-	if(fabsf(v-value)>EPSF)
-	{
-		v=value;
-		update_rgb();
-	}
+    if (fabsf(v - value) > EPSF)
+    {
+        v = value;
+        update_rgb();
+    }
 }
 void smColor::setLightness(float lightness)
 {
-	float ss=hslSaturation();
-	float l=this->lightness();
-	if(fabsf(l-lightness)>EPSF)
-	{
-		l=lightness;
-		v=l+ss*min(l,1-l);
-		if(v<EPSF)s=0;
-		else s=2-2*l/v;
-		update_rgb();
-	}
+    float ss = hslSaturation();
+    float l = this->lightness();
+    if (fabsf(l - lightness) > EPSF)
+    {
+        l = lightness;
+        v = l + ss * min(l, 1 - l);
+        if (v < EPSF)
+            s = 0;
+        else s = 2 - 2 * l / v;
+        update_rgb();
+    }
 }
 smColor smColor::lighter(int factor)
 {
-	smColor ret(*this);
-	ret.setValue(v*(factor/100.0f));
-	ret.clamp(true);
-	return ret;
+    smColor ret(*this);
+    ret.setValue(v * (factor / 100.0f));
+    ret.clamp(true);
+    return ret;
 }
 smColor smColor::darker(int factor)
 {
-	smColor ret(*this);
-	ret.setValue(factor?(v/(factor/100.0f)):1.);
-	ret.clamp(true);
-	return ret;
+    smColor ret(*this);
+    ret.setValue(factor ? (v / (factor / 100.0f)) : 1.);
+    ret.clamp(true);
+    return ret;
 }
 
 uint32_t smColor::toHWColor()
 {
-	return RGBA(r*255,g*255,b*255,a*255);
+    return RGBA(r * 255, g * 255, b * 255, a * 255);
 }
 smColor smColor::fromHWColor(uint32_t color)
 {
-	smColor ret;
-	ret.r=GETR(color)/255.0f;
-	ret.g=GETG(color)/255.0f;
-	ret.b=GETB(color)/255.0f;
-	ret.a=GETA(color)/255.0f;
-	ret.update_hsv();
-	return ret;
+    smColor ret;
+    ret.r = GETR(color) / 255.0f;
+    ret.g = GETG(color) / 255.0f;
+    ret.b = GETB(color) / 255.0f;
+    ret.a = GETA(color) / 255.0f;
+    ret.update_hsv();
+    return ret;
 }
diff --git a/visualization/extrasmeltutils.hpp b/visualization/extrasmeltutils.hpp
index 3cea3fc..ca36415 100644
--- a/visualization/extrasmeltutils.hpp
+++ b/visualization/extrasmeltutils.hpp
@@ -13,134 +13,152 @@
 #define EPSF 1e-6f
 class smEntity3D
 {
-	friend class smEntity3DBuffer;
-	private:
-		std::vector<smVertex> vertices;
-		std::vector<WORD> indices;
-	public:
-		smEntity3D(){vertices.clear();indices.clear();}
-		void addVertices(size_t n,...);
-		void addIndices(size_t n,...);
-		smVertex vertex(size_t idx)const;
-		WORD index(size_t idx)const;
-		void setVertex(size_t idx,smVertex v);
-		void setIndex(size_t idx,WORD i);
-		static smEntity3D cube(smvec3d tl,smvec3d br,DWORD color,int faces=63);
+    friend class smEntity3DBuffer;
+private:
+    std::vector<smVertex> vertices;
+    std::vector<WORD> indices;
+public:
+    smEntity3D()
+    {
+        vertices.clear();
+        indices.clear();
+    }
+    void addVertices(size_t n, ...);
+    void addIndices(size_t n, ...);
+    smVertex vertex(size_t idx)const;
+    WORD index(size_t idx)const;
+    void setVertex(size_t idx, smVertex v);
+    void setIndex(size_t idx, WORD i);
+    static smEntity3D cube(smvec3d tl, smvec3d br, DWORD color, int faces = 63);
 };
 class smEntity3DBuffer
 {
-	private:
-		std::vector<smVertex> vertices;
-		std::vector<WORD> indices;
-		static SMELT* sm;
-	public:
-		smEntity3DBuffer();
-		~smEntity3DBuffer(){sm->smRelease();}
-		void addTransformedEntity(smEntity3D *entity,smMatrix t,smvec3d p);
-		void drawBatch();
+private:
+    std::vector<smVertex> vertices;
+    std::vector<WORD> indices;
+    static SMELT *sm;
+public:
+    smEntity3DBuffer();
+    ~smEntity3DBuffer()
+    {
+        sm->smRelease();
+    }
+    void addTransformedEntity(smEntity3D *entity, smMatrix t, smvec3d p);
+    void drawBatch();
 
 };
 class smColor
 {
-	private:
-		float r,g,b,h,s,v,a;
-		void update_rgb();
-		void update_hsv();
-	public:
-		smColor();
-		void clamp(bool hsv);
-		float alpha()const;
-		float red()const;
-		float green()const;
-		float blue()const;
-		float hue()const;
-		float saturation()const;
-		float hslSaturation()const;
-		float value()const;
-		float lightness()const;
-		void setAlpha(float alpha);
-		void setRed(float red);
-		void setGreen(float green);
-		void setBlue(float blue);
-		void setHue(float hue);
-		void setSaturation(float saturation);
-		void setHSLSaturation(float saturation);
-		void setValue(float value);
-		void setLightness(float lightness);
-		smColor lighter(int factor);
-		smColor darker(int factor);
-		uint32_t toHWColor();
-		static smColor fromHWColor(uint32_t color);
+private:
+    float r, g, b, h, s, v, a;
+    void update_rgb();
+    void update_hsv();
+public:
+    smColor();
+    void clamp(bool hsv);
+    float alpha()const;
+    float red()const;
+    float green()const;
+    float blue()const;
+    float hue()const;
+    float saturation()const;
+    float hslSaturation()const;
+    float value()const;
+    float lightness()const;
+    void setAlpha(float alpha);
+    void setRed(float red);
+    void setGreen(float green);
+    void setBlue(float blue);
+    void setHue(float hue);
+    void setSaturation(float saturation);
+    void setHSLSaturation(float saturation);
+    void setValue(float value);
+    void setLightness(float lightness);
+    smColor lighter(int factor);
+    smColor darker(int factor);
+    uint32_t toHWColor();
+    static smColor fromHWColor(uint32_t color);
 };
 class smPSEmissionPositionGenerator
 {
-	public:
-		virtual smvec3d genPos(){return smvec3d(0,0,0);}
+public:
+    virtual smvec3d genPos()
+    {
+        return smvec3d(0, 0, 0);
+    }
 };
-class smXLinePSGenerator:public smPSEmissionPositionGenerator
+class smXLinePSGenerator: public smPSEmissionPositionGenerator
 {
-	private:
-		smRandomEngine re;
-		double var;
-	public:
-		smXLinePSGenerator(double _var){re.setSeed(time(nullptr));var=_var;}
-		smvec3d genPos(){return smvec3d(re.nextDouble(-var,var),0,0);}
+private:
+    smRandomEngine re;
+    double var;
+public:
+    smXLinePSGenerator(double _var)
+    {
+        re.setSeed(time(nullptr));
+        var = _var;
+    }
+    smvec3d genPos()
+    {
+        return smvec3d(re.nextDouble(-var, var), 0, 0);
+    }
 };
 class smParticleSystemInfo
 {
-	public:
-		smvec3d vel,velvar,acc,accvar;
-		smvec3d rotv,rotvvar,rota,rotavar;
-		double lifespan,lifespanvar;
-		int maxcount,emissioncount,ecvar;
-		double emissiondelay,edvar;
-		double initsize,initsizevar;
-		double finalsize,finalsizevar;
-		DWORD initcolor,initcolorvar;
-		DWORD finalcolor,finalcolorvar;
-		SMTEX texture;int blend;
+public:
+    smvec3d vel, velvar, acc, accvar;
+    smvec3d rotv, rotvvar, rota, rotavar;
+    double lifespan, lifespanvar;
+    int maxcount, emissioncount, ecvar;
+    double emissiondelay, edvar;
+    double initsize, initsizevar;
+    double finalsize, finalsizevar;
+    DWORD initcolor, initcolorvar;
+    DWORD finalcolor, finalcolorvar;
+    SMTEX texture;
+    int blend;
 };
 class smParticle
 {
-	friend class smParticleSystem;
-	private:
-		static SMELT* sm;
-		smvec3d pos,rot,lookatpos;
-		smvec3d vel,accel,rotv,rota;
-		double lifespan,clifespan;
-		double initsize,finalsize,size;
-		DWORD color,initcolor,finalcolor;
-		smQuad q;
-		bool dead,lookat;
-	public:
-		smParticle();
-		~smParticle();
-		void render();
-		void update();
+    friend class smParticleSystem;
+private:
+    static SMELT *sm;
+    smvec3d pos, rot, lookatpos;
+    smvec3d vel, accel, rotv, rota;
+    double lifespan, clifespan;
+    double initsize, finalsize, size;
+    DWORD color, initcolor, finalcolor;
+    smQuad q;
+    bool dead, lookat;
+public:
+    smParticle();
+    ~smParticle();
+    void render();
+    void update();
 };
 class smParticleSystem
 {
-	private:
-		static SMELT* sm;
-		std::vector<smParticle*> particles;
-		smParticleSystemInfo psinfo;
-		smvec3d pos,lookatpos;
-		smRandomEngine re;
-		smPSEmissionPositionGenerator* posGenerator;
-		bool active,lookat;
-		double cemdelay,nemdelay;
-	public:
-		smParticleSystem();
-		~smParticleSystem();
-		void setParticleSystemInfo(smParticleSystemInfo _psinfo);
-		void setPos(smvec3d _pos);
-		void setPSEmissionPosGen(smPSEmissionPositionGenerator* _gen);
-		void setPSLookAt(smvec3d at);
-		void unsetPSLookAt();
-		void startPS();
-		void stopPS();
-		void updatePS();
-		void renderPS();
+private:
+    static SMELT *sm;
+    std::vector<smParticle *> particles;
+    smParticleSystemInfo psinfo;
+    smvec3d pos, lookatpos;
+    smRandomEngine re;
+    smPSEmissionPositionGenerator *posGenerator;
+    bool active, lookat;
+    double cemdelay, nemdelay;
+public:
+    smParticleSystem();
+    ~smParticleSystem();
+    void setParticleSystemInfo(smParticleSystemInfo _psinfo);
+    void setPos(smvec3d _pos);
+    void setPSEmissionPosGen(smPSEmissionPositionGenerator *_gen);
+    void setPSLookAt(smvec3d at);
+    void unsetPSLookAt();
+    void startPS();
+    void stopPS();
+    void updatePS();
+    void renderPS();
 };
-extern smVertex makeVertex(float x,float y,float z,DWORD color,float tx,float ty);
+extern smVertex makeVertex(float x, float y, float z, DWORD color, float tx, float ty);
 #endif // EXTRASMELTUTILS_H
diff --git a/visualization/qmpvirtualpiano3d.cpp b/visualization/qmpvirtualpiano3d.cpp
index 0fbf75f..4ee7460 100644
--- a/visualization/qmpvirtualpiano3d.cpp
+++ b/visualization/qmpvirtualpiano3d.cpp
@@ -1,219 +1,249 @@
 #include <cstring>
 #include "qmpvirtualpiano3d.hpp"
 #define configureVertex(v,sub,_x,_y,_z) v[sub].x=_x,v[sub].y=_y,v[sub].z=_z;
-const double gap[]={WK_TALWIDTH/2*0.92,WK_TALWIDTH/2*1.23,WK_TALWIDTH/2*1.2,
-				   WK_TALWIDTH/2*0.95,WK_TALWIDTH*1.1,WK_TALWIDTH/2*0.95,
-				   WK_TALWIDTH/2*1.2,WK_TALWIDTH/2*1.15,WK_TALWIDTH/2*1,
-				   WK_TALWIDTH/2*1.3,WK_TALWIDTH/2*0.85,WK_TALWIDTH*1.1};
+const double gap[] = {WK_TALWIDTH / 2 * 0.92, WK_TALWIDTH / 2 * 1.23, WK_TALWIDTH / 2 * 1.2,
+        WK_TALWIDTH / 2 * 0.95, WK_TALWIDTH * 1.1, WK_TALWIDTH / 2 * 0.95,
+        WK_TALWIDTH / 2 * 1.2, WK_TALWIDTH / 2 * 1.15, WK_TALWIDTH / 2 * 1,
+        WK_TALWIDTH / 2 * 1.3, WK_TALWIDTH / 2 * 0.85, WK_TALWIDTH * 1.1
+    };
 qmpVirtualPiano3D::qmpVirtualPiano3D()
 {
-	ebuf=new smEntity3DBuffer();buildKeys();memset(traveld,0,sizeof(traveld));
+    ebuf = new smEntity3DBuffer();
+    buildKeys();
+    memset(traveld, 0, sizeof(traveld));
 }
 qmpVirtualPiano3D::~qmpVirtualPiano3D()
 {
-	delete wkcf;delete wkeb;delete wkd;delete wkg;delete wka;delete bk;
-	wkcf=wkeb=wkd=wkg=wka=bk=nullptr;delete ebuf;ebuf=nullptr;
+    delete wkcf;
+    delete wkeb;
+    delete wkd;
+    delete wkg;
+    delete wka;
+    delete bk;
+    wkcf = wkeb = wkd = wkg = wka = bk = nullptr;
+    delete ebuf;
+    ebuf = nullptr;
 }
 void qmpVirtualPiano3D::render(smvec3d p)
 {
-	p.x-=WK_TALWIDTH*37*1.075;
-	for(int i=0;i<128;++i)
-	{
-		smMatrix m;m.loadIdentity();m.rotate(-0.2*traveld[i],1,0,0);
-		switch(i%12)
-		{
-			case 0:case 5:
-				if(wkcf)ebuf->addTransformedEntity(wkcf,m,p);
-			break;
-			case 2:
-				if(wkd)ebuf->addTransformedEntity(wkd,m,p);
-			break;
-			case 4:case 11:
-				if(wkeb)ebuf->addTransformedEntity(wkeb,m,p);
-			break;
-			case 7:
-				if(wkg)ebuf->addTransformedEntity(wkg,m,p);
-			break;
-			case 9:
-				if(wka)ebuf->addTransformedEntity(wka,m,p);
-			break;
-			case 1:case 3:case 6:case 8:case 10:
-				if(bk)ebuf->addTransformedEntity(bk,m,p);
-			break;
-		}
-		p.x+=gap[i%12];
-	}
-	ebuf->drawBatch();
+    p.x -= WK_TALWIDTH * 37 * 1.075;
+    for (int i = 0; i < 128; ++i)
+    {
+        smMatrix m;
+        m.loadIdentity();
+        m.rotate(-0.2 * traveld[i], 1, 0, 0);
+        switch (i % 12)
+        {
+            case 0:
+            case 5:
+                if (wkcf)
+                    ebuf->addTransformedEntity(wkcf, m, p);
+                break;
+            case 2:
+                if (wkd)
+                    ebuf->addTransformedEntity(wkd, m, p);
+                break;
+            case 4:
+            case 11:
+                if (wkeb)
+                    ebuf->addTransformedEntity(wkeb, m, p);
+                break;
+            case 7:
+                if (wkg)
+                    ebuf->addTransformedEntity(wkg, m, p);
+                break;
+            case 9:
+                if (wka)
+                    ebuf->addTransformedEntity(wka, m, p);
+                break;
+            case 1:
+            case 3:
+            case 6:
+            case 8:
+            case 10:
+                if (bk)
+                    ebuf->addTransformedEntity(bk, m, p);
+                break;
+        }
+        p.x += gap[i % 12];
+    }
+    ebuf->drawBatch();
+}
+void qmpVirtualPiano3D::setKeyTravelDist(int k, double td)
+{
+    traveld[k] = td;
 }
-void qmpVirtualPiano3D::setKeyTravelDist(int k,double td)
-{traveld[k]=td;}
 
 void qmpVirtualPiano3D::buildKeys()
 {
-	wkcf=new smEntity3D();wkeb=new smEntity3D();wkd=new smEntity3D();
-	wkg=new smEntity3D();wka=new smEntity3D();bk=new smEntity3D();
-	wkcf->addVertices(19,
-		makeVertex(-WK_TALWIDTH/2,0,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_PREWIDTH,0,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0),////
-		makeVertex(-WK_TALWIDTH/2,0,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_PREWIDTH,0,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,0,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_PREWIDTH,0,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_PREWIDTH,WK_PRELEN,0,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0));
-	wkcf->addIndices(48,
-		0,1,3, 1,2,3, 3,4,6, 4,5,6,
-		7,8,13, 8,13,14, 8,14,15, 8,9,15,
-		9,10,15, 10,15,16, 10,11,17, 10,16,17,
-		11,12,18, 11,17,18, 18,12,13, 12,13,7);
+    wkcf = new smEntity3D();
+    wkeb = new smEntity3D();
+    wkd = new smEntity3D();
+    wkg = new smEntity3D();
+    wka = new smEntity3D();
+    bk = new smEntity3D();
+    wkcf->addVertices(19,
+        makeVertex(-WK_TALWIDTH / 2, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_PREWIDTH, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0), ////
+        makeVertex(-WK_TALWIDTH / 2, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_PREWIDTH, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, 0, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_PREWIDTH, 0, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_PREWIDTH, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0));
+    wkcf->addIndices(48,
+        0, 1, 3, 1, 2, 3, 3, 4, 6, 4, 5, 6,
+        7, 8, 13, 8, 13, 14, 8, 14, 15, 8, 9, 15,
+        9, 10, 15, 10, 15, 16, 10, 11, 17, 10, 16, 17,
+        11, 12, 18, 11, 17, 18, 18, 12, 13, 12, 13, 7);
 
-	wkeb->addVertices(19,
-		makeVertex( WK_TALWIDTH/2,0,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2-WK_PREWIDTH,0,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2-WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0),////
-		makeVertex( WK_TALWIDTH/2,0,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2-WK_PREWIDTH,0,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2-WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,0,0,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2-WK_PREWIDTH,0,0,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2-WK_PREWIDTH,WK_PRELEN,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0));
-	wkeb->addIndices(48,
-		0,1,3, 1,2,3, 3,4,6, 4,5,6,
-		7,8,13, 8,13,14, 8,14,15, 8,9,15,
-		9,10,15, 10,15,16, 10,11,17, 10,16,17,
-		11,12,18, 11,17,18, 18,12,13, 12,13,7);
+    wkeb->addVertices(19,
+        makeVertex(WK_TALWIDTH / 2, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_PREWIDTH, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0), ////
+        makeVertex(WK_TALWIDTH / 2, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_PREWIDTH, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, 0, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_PREWIDTH, 0, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_PREWIDTH, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0));
+    wkeb->addIndices(48,
+        0, 1, 3, 1, 2, 3, 3, 4, 6, 4, 5, 6,
+        7, 8, 13, 8, 13, 14, 8, 14, 15, 8, 9, 15,
+        9, 10, 15, 10, 15, 16, 10, 11, 17, 10, 16, 17,
+        11, 12, 18, 11, 17, 18, 18, 12, 13, 12, 13, 7);
 
-	wkd->addVertices(24,
-		makeVertex(-WK_TALWIDTH/2+(WK_TALWIDTH-WK_PREWIDTH)/2,0,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2-(WK_TALWIDTH-WK_PREWIDTH)/2,0,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2-(WK_TALWIDTH-WK_PREWIDTH)/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2+(WK_TALWIDTH-WK_PREWIDTH)/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),////
-		makeVertex(-WK_TALWIDTH/2+(WK_TALWIDTH-WK_PREWIDTH)/2,0,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2-(WK_TALWIDTH-WK_PREWIDTH)/2,0,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2-(WK_TALWIDTH-WK_PREWIDTH)/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2+(WK_TALWIDTH-WK_PREWIDTH)/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),////
-		makeVertex(-WK_TALWIDTH/2+(WK_TALWIDTH-WK_PREWIDTH)/2,0,0,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2-(WK_TALWIDTH-WK_PREWIDTH)/2,0,0,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2-(WK_TALWIDTH-WK_PREWIDTH)/2,WK_PRELEN,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2+(WK_TALWIDTH-WK_PREWIDTH)/2,WK_PRELEN,0,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0));
-	wkd->addIndices(60,
-		0,1,2, 0,2,3, 4,5,6, 4,6,7,
-		8,9,16, 9,16,17, 9,10,18, 9,17,18,
-		10,12,18, 12,18,19, 12,13,20, 12,19,20,
-		13,14,21, 13,20,21, 14,15,21, 15,21,22,
-		15,11,22, 11,22,23, 11,23,8, 23,16,8);
+    wkd->addVertices(24,
+        makeVertex(-WK_TALWIDTH / 2 + (WK_TALWIDTH - WK_PREWIDTH) / 2, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - (WK_TALWIDTH - WK_PREWIDTH) / 2, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - (WK_TALWIDTH - WK_PREWIDTH) / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + (WK_TALWIDTH - WK_PREWIDTH) / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), ////
+        makeVertex(-WK_TALWIDTH / 2 + (WK_TALWIDTH - WK_PREWIDTH) / 2, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - (WK_TALWIDTH - WK_PREWIDTH) / 2, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - (WK_TALWIDTH - WK_PREWIDTH) / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + (WK_TALWIDTH - WK_PREWIDTH) / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), ////
+        makeVertex(-WK_TALWIDTH / 2 + (WK_TALWIDTH - WK_PREWIDTH) / 2, 0, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - (WK_TALWIDTH - WK_PREWIDTH) / 2, 0, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - (WK_TALWIDTH - WK_PREWIDTH) / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + (WK_TALWIDTH - WK_PREWIDTH) / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0));
+    wkd->addIndices(60,
+        0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7,
+        8, 9, 16, 9, 16, 17, 9, 10, 18, 9, 17, 18,
+        10, 12, 18, 12, 18, 19, 12, 13, 20, 12, 19, 20,
+        13, 14, 21, 13, 20, 21, 14, 15, 21, 15, 21, 22,
+        15, 11, 22, 11, 22, 23, 11, 23, 8, 23, 16, 8);
 
-	wkg->addVertices(24,
-		makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12,0,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12+WK_PREWIDTH,0,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12+WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),////
-		makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12,0,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12+WK_PREWIDTH,0,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12+WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),////
-		makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12,0,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12+WK_PREWIDTH,0,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12+WK_PREWIDTH,WK_PRELEN,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2+WK_WING+WK_TALWIDTH/12,WK_PRELEN,0,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0));
-	wkg->addIndices(60,
-		0,1,2, 0,2,3, 4,5,6, 4,6,7,
-		8,9,16, 9,16,17, 9,10,18, 9,17,18,
-		10,12,18, 12,18,19, 12,13,20, 12,19,20,
-		13,14,21, 13,20,21, 14,15,21, 15,21,22,
-		15,11,22, 11,22,23, 11,23,8, 23,16,8);
+    wkg->addVertices(24,
+        makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12 + WK_PREWIDTH, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12 + WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), ////
+        makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12 + WK_PREWIDTH, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12 + WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), ////
+        makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12, 0, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12 + WK_PREWIDTH, 0, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12 + WK_PREWIDTH, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2 + WK_WING + WK_TALWIDTH / 12, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0));
+    wkg->addIndices(60,
+        0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7,
+        8, 9, 16, 9, 16, 17, 9, 10, 18, 9, 17, 18,
+        10, 12, 18, 12, 18, 19, 12, 13, 20, 12, 19, 20,
+        13, 14, 21, 13, 20, 21, 14, 15, 21, 15, 21, 22,
+        15, 11, 22, 11, 22, 23, 11, 23, 8, 23, 16, 8);
 
-	wka->addVertices(24,
-		makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24-WK_PREWIDTH,0,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24,0,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24-WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN+WK_WING,WK_HEIGHT,0xFFFFFFFF,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFFFFFFF,0,0),////
-		makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24-WK_PREWIDTH,0,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24,0,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24-WK_PREWIDTH,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,WK_HEIGHT,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN,WK_HEIGHT,0xFFCCCCCC,0,0),////
-		makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24-WK_PREWIDTH,0,0,0xFFCCCCCC,0,0),
-		makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24,0,0,0xFFCCCCCC,0,0),
-		makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24,WK_PRELEN,0,0xFFCCCCCC,0,0),
-		makeVertex(WK_TALWIDTH/2-WK_WING-WK_TALWIDTH/24-WK_PREWIDTH,WK_PRELEN,0,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0),
-		makeVertex( WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN+WK_TALLEN,0,0xFFCCCCCC,0,0),
-		makeVertex(-WK_TALWIDTH/2,WK_PRELEN,0,0xFFCCCCCC,0,0));
-	wka->addIndices(60,
-		0,1,2, 0,2,3, 4,5,6, 4,6,7,
-		8,9,16, 9,16,17, 9,10,18, 9,17,18,
-		10,12,18, 12,18,19, 12,13,20, 12,19,20,
-		13,14,21, 13,20,21, 14,15,21, 15,21,22,
-		15,11,22, 11,22,23, 11,23,8, 23,16,8);
+    wka->addVertices(24,
+        makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24 - WK_PREWIDTH, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24, 0, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24 - WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN + WK_WING, WK_HEIGHT, 0xFFFFFFFF, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFFFFFFF, 0, 0), ////
+        makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24 - WK_PREWIDTH, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24, 0, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24 - WK_PREWIDTH, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, WK_HEIGHT, 0xFFCCCCCC, 0, 0), ////
+        makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24 - WK_PREWIDTH, 0, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24, 0, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2 - WK_WING - WK_TALWIDTH / 24 - WK_PREWIDTH, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN + WK_TALLEN, 0, 0xFFCCCCCC, 0, 0),
+        makeVertex(-WK_TALWIDTH / 2, WK_PRELEN, 0, 0xFFCCCCCC, 0, 0));
+    wka->addIndices(60,
+        0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7,
+        8, 9, 16, 9, 16, 17, 9, 10, 18, 9, 17, 18,
+        10, 12, 18, 12, 18, 19, 12, 13, 20, 12, 19, 20,
+        13, 14, 21, 13, 20, 21, 14, 15, 21, 15, 21, 22,
+        15, 11, 22, 11, 22, 23, 11, 23, 8, 23, 16, 8);
 
-	bk->addVertices(10,
-		makeVertex(-BK_WIDTH/2,0,BK_HEIGHT+BK_BOTTOM,0xFF000000,0,0),
-		makeVertex( BK_WIDTH/2,0,BK_HEIGHT+BK_BOTTOM,0xFF000000,0,0),
-		makeVertex( BK_WIDTH/2,BK_PRELEN,BK_HEIGHT+BK_BOTTOM,0xFF000000,0,0),
-		makeVertex(-BK_WIDTH/2,BK_PRELEN,BK_HEIGHT+BK_BOTTOM,0xFF000000,0,0),
-		makeVertex(-BK_WIDTH/2,WK_PRELEN*0.995,BK_DBOTTOM+BK_BOTTOM,0xFF000000,0,0),
-		makeVertex( BK_WIDTH/2,WK_PRELEN*0.995,BK_DBOTTOM+BK_BOTTOM,0xFF000000,0,0),
-		makeVertex( BK_WIDTH/2,WK_PRELEN*0.995,BK_BOTTOM,0xFF000000,0,0),
-		makeVertex(-BK_WIDTH/2,WK_PRELEN*0.995,BK_BOTTOM,0xFF000000,0,0),
-		makeVertex(-BK_WIDTH/2,0,BK_BOTTOM,0xFF000000,0,0),
-		makeVertex( BK_WIDTH/2,0,BK_BOTTOM,0xFF000000,0,0));
-	bk->addIndices(48,
-		0,1,3, 1,2,3, 2,3,4, 2,4,5,
-		4,5,7, 5,6,7, 6,7,8, 6,8,9,
-		0,1,8, 1,8,9, 2,5,6, 2,6,9,
-		2,9,1, 3,4,7, 3,7,8, 3,8,0);
+    bk->addVertices(10,
+        makeVertex(-BK_WIDTH / 2, 0, BK_HEIGHT + BK_BOTTOM, 0xFF000000, 0, 0),
+        makeVertex(BK_WIDTH / 2, 0, BK_HEIGHT + BK_BOTTOM, 0xFF000000, 0, 0),
+        makeVertex(BK_WIDTH / 2, BK_PRELEN, BK_HEIGHT + BK_BOTTOM, 0xFF000000, 0, 0),
+        makeVertex(-BK_WIDTH / 2, BK_PRELEN, BK_HEIGHT + BK_BOTTOM, 0xFF000000, 0, 0),
+        makeVertex(-BK_WIDTH / 2, WK_PRELEN * 0.995, BK_DBOTTOM + BK_BOTTOM, 0xFF000000, 0, 0),
+        makeVertex(BK_WIDTH / 2, WK_PRELEN * 0.995, BK_DBOTTOM + BK_BOTTOM, 0xFF000000, 0, 0),
+        makeVertex(BK_WIDTH / 2, WK_PRELEN * 0.995, BK_BOTTOM, 0xFF000000, 0, 0),
+        makeVertex(-BK_WIDTH / 2, WK_PRELEN * 0.995, BK_BOTTOM, 0xFF000000, 0, 0),
+        makeVertex(-BK_WIDTH / 2, 0, BK_BOTTOM, 0xFF000000, 0, 0),
+        makeVertex(BK_WIDTH / 2, 0, BK_BOTTOM, 0xFF000000, 0, 0));
+    bk->addIndices(48,
+        0, 1, 3, 1, 2, 3, 2, 3, 4, 2, 4, 5,
+        4, 5, 7, 5, 6, 7, 6, 7, 8, 6, 8, 9,
+        0, 1, 8, 1, 8, 9, 2, 5, 6, 2, 6, 9,
+        2, 9, 1, 3, 4, 7, 3, 7, 8, 3, 8, 0);
 }
diff --git a/visualization/qmpvirtualpiano3d.hpp b/visualization/qmpvirtualpiano3d.hpp
index cecd992..d00212a 100644
--- a/visualization/qmpvirtualpiano3d.hpp
+++ b/visualization/qmpvirtualpiano3d.hpp
@@ -16,15 +16,15 @@
 #define BK_DBOTTOM 1.
 class qmpVirtualPiano3D
 {
-	private:
-		smEntity3D *wkcf,*wkeb,*wkd,*wkg,*wka,*bk;
-		smEntity3DBuffer *ebuf;
-		void buildKeys();
-		double traveld[128];
-	public:
-		qmpVirtualPiano3D();
-		~qmpVirtualPiano3D();
-		void render(smvec3d p);
-		void setKeyTravelDist(int k,double td);
+private:
+    smEntity3D *wkcf, *wkeb, *wkd, *wkg, *wka, *bk;
+    smEntity3DBuffer *ebuf;
+    void buildKeys();
+    double traveld[128];
+public:
+    qmpVirtualPiano3D();
+    ~qmpVirtualPiano3D();
+    void render(smvec3d p);
+    void setKeyTravelDist(int k, double td);
 };
 #endif // QMPVIRTUALPIANO3D_H
diff --git a/visualization/qmpvisualization.cpp b/visualization/qmpvisualization.cpp
index 09f80d6..0f73b8a 100644
--- a/visualization/qmpvisualization.cpp
+++ b/visualization/qmpvisualization.cpp
@@ -6,1018 +6,1341 @@
 #include <set>
 #include "qmpvisualization.hpp"
 
-int viewdist=100;
-int notestretch=100;//length of quarter note
-int minnotelength=100;
-int noteappearance=1,showpiano=1,stairpiano=1,savevp=1,showlabel=1;
-int wwidth=800,wheight=600,wsupersample=1,wmultisample=0,showparticle=1;
-int horizontal=1,flat=0,osdpos=0,fontsize=16,showmeasure=1;
-int fov=60,vsync=1,tfps=60,usespectrum=0;
-DWORD chkrtint=0xFF999999;
-const wchar_t* minors=L"abebbbf c g d a e b f#c#g#d#a#";
-const wchar_t* majors=L"CbGbDbAbEbBbF C G D A E B F#C#";
-double fpoffsets[]={1,18,28,50,55,82,98,109,130,137,161,164,191};
-double froffsets[]={0,18,33,50,65,82,98,113,130,145,161,176,191};
-DWORD iccolors[]={0XFFFF0000,0XFFFF8000,0XFFFFBF00,0XFFF0F000,
-				  0XFFB2EE00,0XFF80FF00,0XFF00FF00,0XFF00EEB2,
-				  0XFF00EEEE,0XFF333333,0XFF00BFFF,0XFF007FFF,
-				  0XFF0000FF,0XFF7F00FF,0XFFBF00FF,0XFFFF00BF};
-DWORD accolors[]={0XFFFF9999,0XFFFFCC99,0XFFFFF4D4,0XFFFFFFDD,
-				  0XFFF0FFC2,0XFFDDFFBB,0XFFBBFFBB,0XFFAAFFEA,
-				  0XFFBBFFFF,0XFF999999,0XFF99EEFF,0XFF99CCFF,
-				  0XFF9999FF,0XFFCC99FF,0XFFEE99FF,0XFFFF99EE};
+int viewdist = 100;
+int notestretch = 100; //length of quarter note
+int minnotelength = 100;
+int noteappearance = 1, showpiano = 1, stairpiano = 1, savevp = 1, showlabel = 1;
+int wwidth = 800, wheight = 600, wsupersample = 1, wmultisample = 0, showparticle = 1;
+int horizontal = 1, flat = 0, osdpos = 0, fontsize = 16, showmeasure = 1;
+int fov = 60, vsync = 1, tfps = 60, usespectrum = 0;
+DWORD chkrtint = 0xFF999999;
+const wchar_t *minors = L"abebbbf c g d a e b f#c#g#d#a#";
+const wchar_t *majors = L"CbGbDbAbEbBbF C G D A E B F#C#";
+double fpoffsets[] = {1, 18, 28, 50, 55, 82, 98, 109, 130, 137, 161, 164, 191};
+double froffsets[] = {0, 18, 33, 50, 65, 82, 98, 113, 130, 145, 161, 176, 191};
+DWORD iccolors[] = {0XFFFF0000, 0XFFFF8000, 0XFFFFBF00, 0XFFF0F000,
+        0XFFB2EE00, 0XFF80FF00, 0XFF00FF00, 0XFF00EEB2,
+        0XFF00EEEE, 0XFF333333, 0XFF00BFFF, 0XFF007FFF,
+        0XFF0000FF, 0XFF7F00FF, 0XFFBF00FF, 0XFFFF00BF
+    };
+DWORD accolors[] = {0XFFFF9999, 0XFFFFCC99, 0XFFFFF4D4, 0XFFFFFFDD,
+        0XFFF0FFC2, 0XFFDDFFBB, 0XFFBBFFBB, 0XFFAAFFEA,
+        0XFFBBFFFF, 0XFF999999, 0XFF99EEFF, 0XFF99CCFF,
+        0XFF9999FF, 0XFFCC99FF, 0XFFEE99FF, 0XFFFF99EE
+    };
 
-std::set<BYTE> sustaininst={16,17,18,19,20,21,22,23,
-							40,41,42,43,44,45,48,49,
-							50,51,52,53,54,56,57,58,
-							59,60,61,62,63,64,65,66,
-							67,68,69,70,71,72,73,74,
-							75,76,77,78,79,80,81,82,
-							83,84,85,86,87,89,90,91,
-							92,93,94,95,97,101,109,110,111};
+std::set<BYTE> sustaininst = {16, 17, 18, 19, 20, 21, 22, 23,
+                   40, 41, 42, 43, 44, 45, 48, 49,
+                   50, 51, 52, 53, 54, 56, 57, 58,
+                   59, 60, 61, 62, 63, 64, 65, 66,
+                   67, 68, 69, 70, 71, 72, 73, 74,
+                   75, 76, 77, 78, 79, 80, 81, 82,
+                   83, 84, 85, 86, 87, 89, 90, 91,
+                   92, 93, 94, 95, 97, 101, 109, 110, 111
+               };
 
-bool cmp(MidiVisualEvent* a,MidiVisualEvent* b)
+bool cmp(MidiVisualEvent *a, MidiVisualEvent *b)
 {
-	if(a->tcs<b->tcs)return true;if(a->tcs>b->tcs)return false;
-	if(a->tce<b->tce)return true;return false;
+    if (a->tcs < b->tcs)
+        return true;
+    if (a->tcs > b->tcs)
+        return false;
+    if (a->tce < b->tce)
+        return true;
+    return false;
 }
 void qmpVisualization::showThread()
 {
-	wwidth=api->getOptionInt("Visualization/wwidth");
-	wheight=api->getOptionInt("Visualization/wheight");
-	wsupersample=api->getOptionInt("Visualization/supersampling");
-	wmultisample=api->getOptionInt("Visualization/multisampling");
-	fov=api->getOptionInt("Visualization/fov");
-	noteappearance=api->getOptionBool("Visualization/3dnotes");
-	showpiano=api->getOptionBool("Visualization/showpiano");
-	stairpiano=api->getOptionBool("Visualization/stairpiano");
-	showlabel=api->getOptionBool("Visualization/showlabel");
-	showparticle=api->getOptionBool("Visualization/showparticle");
-	horizontal=api->getOptionBool("Visualization/horizontal");
-	flat=api->getOptionBool("Visualization/flat");
-	showmeasure=api->getOptionBool("Visualization/showmeasure");
-	savevp=api->getOptionBool("Visualization/savevp");
-	vsync=api->getOptionBool("Visualization/vsync");
-	tfps=api->getOptionInt("Visualization/tfps");
-	osdpos=api->getOptionEnumInt("Visualization/osdpos");
-	fontsize=api->getOptionInt("Visualization/fontsize");
-	viewdist=api->getOptionInt("Visualization/viewdist");
-	notestretch=api->getOptionInt("Visualization/notestretch");
-	minnotelength=api->getOptionInt("Visualization/minnotelen");
-	chkrtint=api->getOptionUint("Visualization/chkrtint");
-	usespectrum=api->getOptionBool("Visualization/usespectrum");
-	for(int i=0;i<16;++i)
-	{
-		accolors[i]=api->getOptionUint("Visualization/chActiveColor"+std::to_string(i));
-		iccolors[i]=api->getOptionUint("Visualization/chInactiveColor"+std::to_string(i));
-	}
-	sm=smGetInterface(SMELT_APILEVEL);
-	sm->smVidMode(wwidth,wheight,true,!hidewindow);
-	sm->smUpdateFunc(h);sm->smQuitFunc(closeh);
-	sm->smWinTitle("QMidiPlayer Visualization");
-	sm->smSetFPS(vsync?FPS_VSYNC:tfps);
-	sm->smNoSuspend(true);
-	sm->smInit();shouldclose=false;
-	sm->smTextureOpt(TPOT_POT,TFLT_LINEAR);
-	chequer=sm->smTextureLoad("chequerboard.png");if(!chequer)
-	chequer=sm->smTextureLoad("/usr/share/qmidiplayer/img/chequerboard.png");
-	pianotex=sm->smTextureLoad("kb_128.png");if(!pianotex)
-	pianotex=sm->smTextureLoad("/usr/share/qmidiplayer/img/kb_128.png");
-	particletex=sm->smTextureLoad("particle.png");if(!particletex)
-	particletex=sm->smTextureLoad("/usr/share/qmidiplayer/img/particle.png");
-	bgtex=sm->smTextureLoad(api->getOptionString("Visualization/background").c_str());
-	if(rendermode)
-		fbcont=new DWORD[wwidth*wheight];
-	if(showparticle&&!horizontal)
-	{
-		smParticleSystemInfo psinfo;
-		psinfo.acc=smvec3d(0,0,-0.05);psinfo.accvar=smvec3d(0,0,0.005);
-		psinfo.vel=smvec3d(0,0,0.5);psinfo.velvar=smvec3d(0.1,0.1,0.2);
-		psinfo.rotv=psinfo.rota=psinfo.rotavar=smvec3d(0,0,0);psinfo.rotvvar=smvec3d(0.04,0.04,0.04);
-		psinfo.lifespan=1;psinfo.lifespanvar=0.5;psinfo.maxcount=1000;psinfo.emissioncount=5;psinfo.ecvar=2;
-		psinfo.emissiondelay=0.1;psinfo.edvar=0;psinfo.initsize=0.8;psinfo.initsizevar=0.1;
-		psinfo.finalsize=0.1;psinfo.finalsizevar=0.05;psinfo.initcolor=0xFFFFFFFF;psinfo.finalcolor=0x00FFFFFF;
-		psinfo.initcolorvar=psinfo.finalcolorvar=0;psinfo.texture=particletex;psinfo.blend=BLEND_ALPHAADD;
-		psepg=new smXLinePSGenerator(.6);
-		for(int i=0;i<16;++i)for(int j=0;j<128;++j)
-		{
-			pss[i][j]=new smParticleSystem();
-			pss[i][j]->setPSEmissionPosGen(psepg);
-			psinfo.initcolor=accolors[i];psinfo.finalcolor=SETA(accolors[i],0);
-			pss[i][j]->setParticleSystemInfo(psinfo);
-			pss[i][j]->setPos(smvec3d(0.756*((double)j-64)+.48,(stairpiano?(56-i*7.):(64-i*8.)),stairpiano*i*2+0.1));
-		}
-	}else memset(pss,0,sizeof(pss));
-	if(showpiano&&!horizontal)for(int i=0;i<16;++i)p3d[i]=new qmpVirtualPiano3D();
-	memset(traveld,0,sizeof(traveld));
-	nebuf=new smEntity3DBuffer();
-	tdscn=sm->smTargetCreate(wwidth*wsupersample,wheight*wsupersample,wmultisample);
-	tdparticles=sm->smTargetCreate(wwidth*wsupersample,wheight*wsupersample,wmultisample);
-	if(!api->getOptionString("Visualization/font2").length()||!font.loadTTF(api->getOptionString("Visualization/font2").c_str(),fontsize))
-	if(!font.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf",fontsize))
-	if(!font.loadTTF("/usr/share/fonts/gnu-free/FreeMono.otf",fontsize))
-	if(!font.loadTTF((std::string(getenv("windir")?getenv("windir"):"")+"/Fonts/cour.ttf").c_str(),fontsize))
-	fprintf(stderr,"W: Font load failed.\n");
-	if(!api->getOptionString("Visualization/font2").length()||!fonthdpi.loadTTF(api->getOptionString("Visualization/font2").c_str(),180))
-	if(!fonthdpi.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf",180))
-	if(!fonthdpi.loadTTF("/usr/share/fonts/gnu-free/FreeMono.otf",180))
-	if(!fonthdpi.loadTTF((std::string(getenv("windir")?getenv("windir"):"")+"/Fonts/cour.ttf").c_str(),180))
-	fprintf(stderr,"W: Font load failed.\n");
-	if(!api->getOptionString("Visualization/font1").length()||!font2.loadTTF(api->getOptionString("Visualization/font1").c_str(),fontsize))
-	if(!font2.loadTTF("/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",fontsize))
-	if(!font2.loadTTF("/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc",fontsize))
-	if(!font2.loadTTF((std::string(getenv("windir")?getenv("windir"):"")+"/Fonts/msyh.ttc").c_str(),fontsize))
-	if(!font2.loadTTF((std::string(getenv("windir")?getenv("windir"):"")+"/Fonts/segoeui.ttf").c_str(),fontsize))
-	fprintf(stderr,"W: Font load failed.\n");
-	if(pos[0]<-1e8)
-	{
-		if(horizontal)
-		{
-			pos[0]=-20;pos[1]=45;pos[2]=0;
-			rot[0]=0;rot[1]=90;rot[2]=90;
-		}
-		else
-		{
-			pos[0]=0;pos[1]=120;pos[2]=70;
-			rot[0]=0;rot[1]=75;rot[2]=90;
-		}
-	}
-	debug=false;
-	ctk=api->getCurrentTimeStamp();
-	lst=std::chrono::steady_clock::now();
-	sm->smMainLoop();
-	sm->smFinale();
+    wwidth = api->getOptionInt("Visualization/wwidth");
+    wheight = api->getOptionInt("Visualization/wheight");
+    wsupersample = api->getOptionInt("Visualization/supersampling");
+    wmultisample = api->getOptionInt("Visualization/multisampling");
+    fov = api->getOptionInt("Visualization/fov");
+    noteappearance = api->getOptionBool("Visualization/3dnotes");
+    showpiano = api->getOptionBool("Visualization/showpiano");
+    stairpiano = api->getOptionBool("Visualization/stairpiano");
+    showlabel = api->getOptionBool("Visualization/showlabel");
+    showparticle = api->getOptionBool("Visualization/showparticle");
+    horizontal = api->getOptionBool("Visualization/horizontal");
+    flat = api->getOptionBool("Visualization/flat");
+    showmeasure = api->getOptionBool("Visualization/showmeasure");
+    savevp = api->getOptionBool("Visualization/savevp");
+    vsync = api->getOptionBool("Visualization/vsync");
+    tfps = api->getOptionInt("Visualization/tfps");
+    osdpos = api->getOptionEnumInt("Visualization/osdpos");
+    fontsize = api->getOptionInt("Visualization/fontsize");
+    viewdist = api->getOptionInt("Visualization/viewdist");
+    notestretch = api->getOptionInt("Visualization/notestretch");
+    minnotelength = api->getOptionInt("Visualization/minnotelen");
+    chkrtint = api->getOptionUint("Visualization/chkrtint");
+    usespectrum = api->getOptionBool("Visualization/usespectrum");
+    for (int i = 0; i < 16; ++i)
+    {
+        accolors[i] = api->getOptionUint("Visualization/chActiveColor" + std::to_string(i));
+        iccolors[i] = api->getOptionUint("Visualization/chInactiveColor" + std::to_string(i));
+    }
+    sm = smGetInterface(SMELT_APILEVEL);
+    sm->smVidMode(wwidth, wheight, true, !hidewindow);
+    sm->smUpdateFunc(h);
+    sm->smQuitFunc(closeh);
+    sm->smWinTitle("QMidiPlayer Visualization");
+    sm->smSetFPS(vsync ? FPS_VSYNC : tfps);
+    sm->smNoSuspend(true);
+    sm->smInit();
+    shouldclose = false;
+    sm->smTextureOpt(TPOT_POT, TFLT_LINEAR);
+    chequer = sm->smTextureLoad("chequerboard.png");
+    if (!chequer)
+        chequer = sm->smTextureLoad("/usr/share/qmidiplayer/img/chequerboard.png");
+    pianotex = sm->smTextureLoad("kb_128.png");
+    if (!pianotex)
+        pianotex = sm->smTextureLoad("/usr/share/qmidiplayer/img/kb_128.png");
+    particletex = sm->smTextureLoad("particle.png");
+    if (!particletex)
+        particletex = sm->smTextureLoad("/usr/share/qmidiplayer/img/particle.png");
+    bgtex = sm->smTextureLoad(api->getOptionString("Visualization/background").c_str());
+    if (rendermode)
+        fbcont = new DWORD[wwidth * wheight];
+    if (showparticle && !horizontal)
+    {
+        smParticleSystemInfo psinfo;
+        psinfo.acc = smvec3d(0, 0, -0.05);
+        psinfo.accvar = smvec3d(0, 0, 0.005);
+        psinfo.vel = smvec3d(0, 0, 0.5);
+        psinfo.velvar = smvec3d(0.1, 0.1, 0.2);
+        psinfo.rotv = psinfo.rota = psinfo.rotavar = smvec3d(0, 0, 0);
+        psinfo.rotvvar = smvec3d(0.04, 0.04, 0.04);
+        psinfo.lifespan = 1;
+        psinfo.lifespanvar = 0.5;
+        psinfo.maxcount = 1000;
+        psinfo.emissioncount = 5;
+        psinfo.ecvar = 2;
+        psinfo.emissiondelay = 0.1;
+        psinfo.edvar = 0;
+        psinfo.initsize = 0.8;
+        psinfo.initsizevar = 0.1;
+        psinfo.finalsize = 0.1;
+        psinfo.finalsizevar = 0.05;
+        psinfo.initcolor = 0xFFFFFFFF;
+        psinfo.finalcolor = 0x00FFFFFF;
+        psinfo.initcolorvar = psinfo.finalcolorvar = 0;
+        psinfo.texture = particletex;
+        psinfo.blend = BLEND_ALPHAADD;
+        psepg = new smXLinePSGenerator(.6);
+        for (int i = 0; i < 16; ++i)
+            for (int j = 0; j < 128; ++j)
+            {
+                pss[i][j] = new smParticleSystem();
+                pss[i][j]->setPSEmissionPosGen(psepg);
+                psinfo.initcolor = accolors[i];
+                psinfo.finalcolor = SETA(accolors[i], 0);
+                pss[i][j]->setParticleSystemInfo(psinfo);
+                pss[i][j]->setPos(smvec3d(0.756 * ((double)j - 64) + .48, (stairpiano ? (56 - i * 7.) : (64 - i * 8.)), stairpiano * i * 2 + 0.1));
+            }
+    }
+    else memset(pss, 0, sizeof(pss));
+    if (showpiano && !horizontal)
+        for (int i = 0; i < 16; ++i)
+            p3d[i] = new qmpVirtualPiano3D();
+    memset(traveld, 0, sizeof(traveld));
+    nebuf = new smEntity3DBuffer();
+    tdscn = sm->smTargetCreate(wwidth * wsupersample, wheight * wsupersample, wmultisample);
+    tdparticles = sm->smTargetCreate(wwidth * wsupersample, wheight * wsupersample, wmultisample);
+    if (!api->getOptionString("Visualization/font2").length() || !font.loadTTF(api->getOptionString("Visualization/font2").c_str(), fontsize))
+        if (!font.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf", fontsize))
+            if (!font.loadTTF("/usr/share/fonts/gnu-free/FreeMono.otf", fontsize))
+                if (!font.loadTTF((std::string(getenv("windir") ? getenv("windir") : "") + "/Fonts/cour.ttf").c_str(), fontsize))
+                    fprintf(stderr, "W: Font load failed.\n");
+    if (!api->getOptionString("Visualization/font2").length() || !fonthdpi.loadTTF(api->getOptionString("Visualization/font2").c_str(), 180))
+        if (!fonthdpi.loadTTF("/usr/share/fonts/truetype/freefont/FreeMono.ttf", 180))
+            if (!fonthdpi.loadTTF("/usr/share/fonts/gnu-free/FreeMono.otf", 180))
+                if (!fonthdpi.loadTTF((std::string(getenv("windir") ? getenv("windir") : "") + "/Fonts/cour.ttf").c_str(), 180))
+                    fprintf(stderr, "W: Font load failed.\n");
+    if (!api->getOptionString("Visualization/font1").length() || !font2.loadTTF(api->getOptionString("Visualization/font1").c_str(), fontsize))
+        if (!font2.loadTTF("/usr/share/fonts/truetype/wqy/wqy-microhei.ttc", fontsize))
+            if (!font2.loadTTF("/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc", fontsize))
+                if (!font2.loadTTF((std::string(getenv("windir") ? getenv("windir") : "") + "/Fonts/msyh.ttc").c_str(), fontsize))
+                    if (!font2.loadTTF((std::string(getenv("windir") ? getenv("windir") : "") + "/Fonts/segoeui.ttf").c_str(), fontsize))
+                        fprintf(stderr, "W: Font load failed.\n");
+    if (pos[0] < -1e8)
+    {
+        if (horizontal)
+        {
+            pos[0] = -20;
+            pos[1] = 45;
+            pos[2] = 0;
+            rot[0] = 0;
+            rot[1] = 90;
+            rot[2] = 90;
+        }
+        else
+        {
+            pos[0] = 0;
+            pos[1] = 120;
+            pos[2] = 70;
+            rot[0] = 0;
+            rot[1] = 75;
+            rot[2] = 90;
+        }
+    }
+    debug = false;
+    ctk = api->getCurrentTimeStamp();
+    lst = std::chrono::steady_clock::now();
+    sm->smMainLoop();
+    sm->smFinale();
 }
 void qmpVisualization::show()
 {
-	rendererTh=new std::thread(&qmpVisualization::showThread,this);
+    rendererTh = new std::thread(&qmpVisualization::showThread, this);
 }
 void qmpVisualization::close()
 {
-	shouldclose=true;
-	if(rendererTh)
-	{
-		rendererTh->join();
-		delete rendererTh;
-		rendererTh=nullptr;
-	}else return;
+    shouldclose = true;
+    if (rendererTh)
+    {
+        rendererTh->join();
+        delete rendererTh;
+        rendererTh = nullptr;
+    }
+    else return;
 
-	if(showpiano&&!horizontal)for(int i=0;i<16;++i)delete p3d[i];
-	if(showparticle&&!horizontal)for(int i=0;i>16;++i)for(int j=0;j<128;++j){delete pss[i][j];pss[i][j]=0;}
-	delete nebuf;
-	if(savevp)
-	{
-		api->setOptionDouble("Visualization/px",pos[0]);
-		api->setOptionDouble("Visualization/py",pos[1]);
-		api->setOptionDouble("Visualization/pz",pos[2]);
-		api->setOptionDouble("Visualization/rx",rot[0]);
-		api->setOptionDouble("Visualization/ry",rot[1]);
-		api->setOptionDouble("Visualization/rz",rot[2]);
-	}
-	if(rendermode)
-		delete[] fbcont;
-	font.releaseTTF();
-	font2.releaseTTF();
-	fonthdpi.releaseTTF();
-	sm->smTextureFree(chequer);
-	sm->smTextureFree(pianotex);
-	sm->smTextureFree(particletex);
-	if(bgtex)sm->smTextureFree(bgtex);
-	sm->smTargetFree(tdscn);
-	sm->smTargetFree(tdparticles);
-	sm->smRelease();
+    if (showpiano && !horizontal)
+        for (int i = 0; i < 16; ++i)
+            delete p3d[i];
+    if (showparticle && !horizontal)
+        for (int i = 0; i > 16; ++i)
+            for (int j = 0; j < 128; ++j)
+            {
+                delete pss[i][j];
+                pss[i][j] = 0;
+            }
+    delete nebuf;
+    if (savevp)
+    {
+        api->setOptionDouble("Visualization/px", pos[0]);
+        api->setOptionDouble("Visualization/py", pos[1]);
+        api->setOptionDouble("Visualization/pz", pos[2]);
+        api->setOptionDouble("Visualization/rx", rot[0]);
+        api->setOptionDouble("Visualization/ry", rot[1]);
+        api->setOptionDouble("Visualization/rz", rot[2]);
+    }
+    if (rendermode)
+        delete[] fbcont;
+    font.releaseTTF();
+    font2.releaseTTF();
+    fonthdpi.releaseTTF();
+    sm->smTextureFree(chequer);
+    sm->smTextureFree(pianotex);
+    sm->smTextureFree(particletex);
+    if (bgtex)
+        sm->smTextureFree(bgtex);
+    sm->smTargetFree(tdscn);
+    sm->smTargetFree(tdparticles);
+    sm->smRelease();
 }
 void qmpVisualization::reset()
 {
-	for(unsigned i=0;i<pool.size();++i)delete pool[i];
-	pool.clear();elb=ctk=lstk=cfr=0;tspool.clear();
-	cts=0x0402;cks=0;ctp=500000;
-	for(int i=0;i<16;++i)
-	{cpbr[i]=2;cpw[i]=8192;}
-	for(int i=0;i<16;++i)for(int j=0;j<128;++j)
-	{
-		if(showparticle&&!horizontal&&pss[i][j])pss[i][j]->stopPS();
-		while(!pendingt[i][j].empty())pendingt[i][j].pop();
-		while(!pendingv[i][j].empty())pendingv[i][j].pop();
-	}
+    for (unsigned i = 0; i < pool.size(); ++i)
+        delete pool[i];
+    pool.clear();
+    elb = ctk = lstk = cfr = 0;
+    tspool.clear();
+    cts = 0x0402;
+    cks = 0;
+    ctp = 500000;
+    for (int i = 0; i < 16; ++i)
+    {
+        cpbr[i] = 2;
+        cpw[i] = 8192;
+    }
+    for (int i = 0; i < 16; ++i)
+        for (int j = 0; j < 128; ++j)
+        {
+            if (showparticle && !horizontal && pss[i][j])
+                pss[i][j]->stopPS();
+            while (!pendingt[i][j].empty())
+                pendingt[i][j].pop();
+            while (!pendingv[i][j].empty())
+                pendingv[i][j].pop();
+        }
 }
 
-void qmpVisualization::switchToRenderMode(void(*frameCallback)(void*,size_t,uint32_t,uint32_t),bool _hidewindow)
+void qmpVisualization::switchToRenderMode(void(*frameCallback)(void *, size_t, uint32_t, uint32_t), bool _hidewindow)
 {
-	rendermode=true;
-	framecb=frameCallback;
-	hidewindow=_hidewindow;
+    rendermode = true;
+    framecb = frameCallback;
+    hidewindow = _hidewindow;
+}
+void qmpVisualization::start()
+{
+    playing = true;
+}
+void qmpVisualization::stop()
+{
+    playing = false;
+}
+void qmpVisualization::pause()
+{
+    playing = !playing;
 }
-void qmpVisualization::start(){playing=true;}
-void qmpVisualization::stop(){playing=false;}
-void qmpVisualization::pause(){playing=!playing;}
 void qmpVisualization::updateVisualization3D()
 {
-	smQuad q;
-	if(!rendermode)
-	{
-		if(sm->smGetKeyState(SMK_D))pos[0]+=cos(smMath::deg2rad(rot[2]-90)),pos[1]+=sin(smMath::deg2rad(rot[2]-90));
-		if(sm->smGetKeyState(SMK_A))pos[0]-=cos(smMath::deg2rad(rot[2]-90)),pos[1]-=sin(smMath::deg2rad(rot[2]-90));
-		if(sm->smGetKeyState(SMK_S))pos[0]+=cos(smMath::deg2rad(rot[2])),pos[1]+=sin(smMath::deg2rad(rot[2]));
-		if(sm->smGetKeyState(SMK_W))pos[0]-=cos(smMath::deg2rad(rot[2])),pos[1]-=sin(smMath::deg2rad(rot[2]));
-		if(sm->smGetKeyState(SMK_Q))pos[2]+=1;
-		if(sm->smGetKeyState(SMK_E))pos[2]-=1;
-		if(sm->smGetKeyState(SMK_R))
-		{
-			if(horizontal)
-			{
-				pos[0]=-20;pos[1]=45;pos[2]=0;
-				rot[0]=0;rot[1]=90;rot[2]=90;
-			}
-			else
-			{
-				pos[0]=0;pos[1]=120;pos[2]=70;
-				rot[0]=0;rot[1]=75;rot[2]=90;
-			}
-		}
-		if(sm->smGetKeyState(SMK_LBUTTON)==SMKST_HIT)
-		sm->smSetMouseGrab(true),sm->smGetMouse2f(&lastx,&lasty);
-		if(sm->smGetKeyState(SMK_LBUTTON)==SMKST_KEEP)
-		{
-			float x,y;
-			sm->smGetMouse2f(&x,&y);
-			rot[1]-=(y-lasty)*0.01;
-			rot[2]+=(x-lastx)*0.01;
-			while(rot[1]>360)rot[1]-=360;
-			while(rot[1]<0)rot[1]+=360;
-			while(rot[2]>360)rot[2]-=360;
-			while(rot[2]<0)rot[2]+=360;
-		}
-		if(sm->smGetKeyState(SMK_LBUTTON)==SMKST_RELEASE)
-		{
-			sm->smSetMouseGrab(false);
-			sm->smSetMouse2f(wwidth/2,wheight/2);
-		}
-		if(sm->smGetKeyState(SMK_I))rot[1]+=1;
-		if(sm->smGetKeyState(SMK_K))rot[1]-=1;
-		if(sm->smGetKeyState(SMK_L))rot[0]+=1;
-		if(sm->smGetKeyState(SMK_J))rot[0]-=1;
-		if(sm->smGetKeyState(SMK_U))rot[2]+=1;
-		if(sm->smGetKeyState(SMK_O))rot[2]-=1;
-	}
-	for(int i=0;i<4;++i)
-	{q.v[i].col=chkrtint;q.v[i].z=(showpiano&&!horizontal)?-5:0;}
-	q.tex=chequer;q.blend=BLEND_ALPHABLEND;
-	q.v[0].x=q.v[3].x=-120;q.v[1].x=q.v[2].x=120;
-	q.v[0].y=q.v[1].y=-120;q.v[2].y=q.v[3].y=120;
-	if(horizontal)
-	{
-		for(int i=0;i<4;++i)q.v[i].x=-20;
-		q.v[0].y=q.v[3].y=-120;q.v[1].y=q.v[2].y=120;
-		q.v[0].z=q.v[1].z=-120;q.v[2].z=q.v[3].z=120;
-	}
-	q.v[0].tx=q.v[3].tx=0;q.v[1].tx=q.v[2].tx=30;
-	q.v[0].ty=q.v[1].ty=0;q.v[2].ty=q.v[3].ty=30;
-	sm->smRenderBegin3D(fov,true,tdscn);
-	sm->sm3DCamera6f2v(pos,rot);
-	sm->smClrscr(0,1,1);
-	sm->smRenderQuad(&q);
-	double lpt=(double)notestretch/api->getDivision()/10.*(horizontal?0.25:1);
-	memcpy(lastnotestatus,notestatus,sizeof(notestatus));
-	memset(notestatus,0,sizeof(notestatus));
-	for(uint32_t i=elb;i<pool.size();++i)
-	{
-		if(((double)pool[i]->tcs-ctk)*lpt>viewdist*2)break;
-		if(fabs((double)pool[i]->tcs-ctk)*lpt<viewdist*2||fabs((double)pool[i]->tce-ctk)*lpt<viewdist*2)
-		{
-			if(pool[i]->ch==999){
-				smvec3d a(0.63*(-64)+.1-10,(stairpiano?(56-0*7.):(64-0*8.))+10,((double)pool[i]->tcs-ctk)*lpt-minnotelength*.005);
-				smvec3d b(0.63*64+.7+10,(stairpiano?(56-15*7.):(64-15*8.))+.4-10,((double)pool[i]->tcs-ctk)*lpt+minnotelength*.005);
-				if(horizontal){
-					a=smvec3d(((double)pool[i]->tcs-ctk)*lpt-20-minnotelength*.001,(16- 0*2.)+2.4,0.63*(-64)+.1);
-					b=smvec3d(((double)pool[i]->tcs-ctk)*lpt-20+minnotelength*.001,(16-15*2.)+0.4,0.63*64+.7);
-				}
-				smMatrix I;I.loadIdentity();
-				smEntity3D c=smEntity3D::cube(a,b,0xFF000000,horizontal?51:60);
-				if(stairpiano&&showpiano&&!horizontal)
-				{
-					std::vector<size_t> il={2,3,6,7};
-					for(size_t ti:il)
-					{
-						smVertex t=c.vertex(ti);
-						t.z+=30;
-						c.setVertex(ti,t);
-					}
-				}
-				if(showmeasure)
-					nebuf->addTransformedEntity(&c,I,smvec3d(0,0,0));
-				continue;
-			}
-			if(pool[i]->ch>=990)continue;
-			if(api->getChannelMask(pool[i]->ch))continue;
-			smvec3d a(0.63*((double)pool[i]->key-64)+.1,(stairpiano?(56-pool[i]->ch*7.):(64-pool[i]->ch*8.)),((double)pool[i]->tce-ctk)*lpt+(stairpiano&&showpiano&&!horizontal)*pool[i]->ch*2.);
-			smvec3d b(0.63*((double)pool[i]->key-64)+.7,(stairpiano?(56-pool[i]->ch*7.):(64-pool[i]->ch*8.))+.4,((double)pool[i]->tcs-ctk)*lpt+(stairpiano&&showpiano&&!horizontal)*pool[i]->ch*2.);
-			bool isnoteon=pool[i]->tcs<=ctk&&pool[i]->tce>=ctk;
-			double pb=((int)cpw[pool[i]->ch]-8192)/8192.*cpbr[pool[i]->ch];
-			if(isnoteon)
-			{
-				a.x=0.63*((double)pool[i]->key-64+pb)+.1;
-				b.x=0.63*((double)pool[i]->key-64+pb)+.7;
-			}
-			notestatus[pool[i]->ch][pool[i]->key]|=isnoteon;a.x*=1.2;b.x*=1.2;
-			if(horizontal)
-			{
-				a=smvec3d(((double)pool[i]->tcs-ctk)*lpt-20,(16-pool[i]->ch*2.),0.63*((double)pool[i]->key-64)+.1);
-				b=smvec3d(((double)pool[i]->tce-ctk)*lpt-20,(16-pool[i]->ch*2.)+.4,0.63*((double)pool[i]->key-64)+.7);
-				if(isnoteon)
-				{
-					a.z=0.63*((double)pool[i]->key-64+pb)+.1;
-					b.z=0.63*((double)pool[i]->key-64+pb)+.7;
-				}
-			}
-			if(showparticle&&!horizontal)
-			{
-				if(notestatus[pool[i]->ch][pool[i]->key]&&!lastnotestatus[pool[i]->ch][pool[i]->key])
-				{
-					pss[pool[i]->ch][pool[i]->key]->startPS();
-					pss[pool[i]->ch][pool[i]->key]->setPos(smvec3d(0.756*((double)pool[i]->key-64)+.48,(stairpiano?(56-pool[i]->ch*7.):(64-pool[i]->ch*8.)),stairpiano*pool[i]->ch*2+0.1));
-				}
-				else pss[pool[i]->ch][pool[i]->key]->stopPS();
-			}
-			if(((double)pool[i]->tce-pool[i]->tcs)*lpt<minnotelength*(horizontal?0.0025:0.01))
-			{
-				if(horizontal)
-					a.x=((double)pool[i]->tcs-ctk)*lpt-minnotelength/400.-20;
-				else
-					a.z=((double)pool[i]->tcs-ctk)*lpt-minnotelength/100.+stairpiano*pool[i]->ch*2;
-			}
-			if(usespectrum)
-			{
-				if(notestatus[pool[i]->ch][pool[i]->key]&&!lastnotestatus[pool[i]->ch][pool[i]->key])
-					spectra[pool[i]->ch][pool[i]->key]=pool[i]->vel*(api->getChannelCC(pool[i]->ch,7)/127.);
-			}
-			else
-			{
-				smColor col=smColor::fromHWColor(isnoteon?accolors[pool[i]->ch]:iccolors[pool[i]->ch]);
-				drawCube(a,b,col.lighter(37+pool[i]->vel/2).toHWColor(),0);
-			}
-		}
-	}
-	if(usespectrum&&playing)
-	for(int i=0;i<16;++i)for(int j=0;j<128;++j)
-	{
-		if(sustaininst.find(api->getChannelPreset(i))!=sustaininst.end())
-		{
-			if(!notestatus[i][j]&&spectra[i][j])
-				spectra[i][j]=.95*spectra[i][j];
-		}else if(spectra[i][j])spectra[i][j]=.95*spectra[i][j];
-		if(spectrar[i][j]<spectra[i][j]*0.9)spectrar[i][j]+=spectra[i][j]*0.2;
-		else spectrar[i][j]=spectra[i][j];
-		if(spectrar[i][j])
-		{
-			double pb=((int)cpw[i]-8192)/8192.*cpbr[i];
-			smvec3d a(0.756*((double)j-64+pb)+.12,
-					  (stairpiano?(56-i*7.):(64-i*8.)),
-					  spectrar[i][j]*1.2*(1+0.02*sin(sm->smGetTime()*32))+(stairpiano&&showpiano&&!horizontal)*i*2.);
-			smvec3d b(0.756*((double)j-64+pb)+.84,
-					  (stairpiano?(56-i*7.):(64-i*8.))+.4,
-					  (stairpiano&&showpiano&&!horizontal)*i*2.);
-			drawCube(a,b,SETA(iccolors[i],204),0);
-		}
-	}
-	nebuf->drawBatch();
-	if(showpiano&&!horizontal)
-	for(int i=0;i<16;++i)
-	{
-		for(int j=0;j<128;++j)
-		{
-			if(notestatus[i][j])
-			if(traveld[i][j]<10)traveld[i][j]+=2;else traveld[i][j]=10;
-			else
-			if(traveld[i][j]>0)traveld[i][j]-=2;else traveld[i][j]=0;
-			p3d[i]->setKeyTravelDist(j,traveld[i][j]/10.);
-		}
-		double pb=((int)cpw[i]-8192)/8192.*cpbr[i];
-		p3d[i]->render(smvec3d(0.756*pb,stairpiano?55-i*7:62-i*8,stairpiano*i*2));
-	}
-	for(int i=0;i<16;++i)
-		if(showlabel)
-		{
-			std::string s=api->getChannelPresetString(i);
-			wchar_t ws[1024];mbstowcs(ws,s.c_str(),1024);
-			fonthdpi.updateString(ws);
-			fonthdpi.render(-49,stairpiano?56-i*7:63-i*8,stairpiano*i*2+0.1,0xFFFFFFFF,ALIGN_RIGHT,.008,0.01);
-			fonthdpi.render(-49.05,stairpiano?56.05-i*7:63.05-i*8,stairpiano*i*2+0.2,0xFF000000,ALIGN_RIGHT,.008,0.01);
-		}
-	while(pool.size()&&elb<pool.size()&&((double)ctk-pool[elb]->tce)*lpt>viewdist*2)++elb;
-	sm->smRenderEnd();
-	if(showparticle&&!horizontal)
-	{
-		sm->smRenderBegin3D(fov,false,tdparticles);
-		sm->sm3DCamera6f2v(pos,rot);
-		sm->smClrscr(0,1,1);
-		for(int i=0;i<16;++i)for(int j=0;j<128;++j)
-		{
-			pss[i][j]->setPSLookAt(smvec3d(pos[0],pos[1],pos[2]));
-			pss[i][j]->updatePS();pss[i][j]->renderPS();
-		}
-		sm->smRenderEnd();
-	}
+    smQuad q;
+    if (!rendermode)
+    {
+        if (sm->smGetKeyState(SMK_D))
+            pos[0] += cos(smMath::deg2rad(rot[2] - 90)), pos[1] += sin(smMath::deg2rad(rot[2] - 90));
+        if (sm->smGetKeyState(SMK_A))
+            pos[0] -= cos(smMath::deg2rad(rot[2] - 90)), pos[1] -= sin(smMath::deg2rad(rot[2] - 90));
+        if (sm->smGetKeyState(SMK_S))
+            pos[0] += cos(smMath::deg2rad(rot[2])), pos[1] += sin(smMath::deg2rad(rot[2]));
+        if (sm->smGetKeyState(SMK_W))
+            pos[0] -= cos(smMath::deg2rad(rot[2])), pos[1] -= sin(smMath::deg2rad(rot[2]));
+        if (sm->smGetKeyState(SMK_Q))
+            pos[2] += 1;
+        if (sm->smGetKeyState(SMK_E))
+            pos[2] -= 1;
+        if (sm->smGetKeyState(SMK_R))
+        {
+            if (horizontal)
+            {
+                pos[0] = -20;
+                pos[1] = 45;
+                pos[2] = 0;
+                rot[0] = 0;
+                rot[1] = 90;
+                rot[2] = 90;
+            }
+            else
+            {
+                pos[0] = 0;
+                pos[1] = 120;
+                pos[2] = 70;
+                rot[0] = 0;
+                rot[1] = 75;
+                rot[2] = 90;
+            }
+        }
+        if (sm->smGetKeyState(SMK_LBUTTON) == SMKST_HIT)
+            sm->smSetMouseGrab(true), sm->smGetMouse2f(&lastx, &lasty);
+        if (sm->smGetKeyState(SMK_LBUTTON) == SMKST_KEEP)
+        {
+            float x, y;
+            sm->smGetMouse2f(&x, &y);
+            rot[1] -= (y - lasty) * 0.01;
+            rot[2] += (x - lastx) * 0.01;
+            while (rot[1] > 360)
+                rot[1] -= 360;
+            while (rot[1] < 0)
+                rot[1] += 360;
+            while (rot[2] > 360)
+                rot[2] -= 360;
+            while (rot[2] < 0)
+                rot[2] += 360;
+        }
+        if (sm->smGetKeyState(SMK_LBUTTON) == SMKST_RELEASE)
+        {
+            sm->smSetMouseGrab(false);
+            sm->smSetMouse2f(wwidth / 2, wheight / 2);
+        }
+        if (sm->smGetKeyState(SMK_I))
+            rot[1] += 1;
+        if (sm->smGetKeyState(SMK_K))
+            rot[1] -= 1;
+        if (sm->smGetKeyState(SMK_L))
+            rot[0] += 1;
+        if (sm->smGetKeyState(SMK_J))
+            rot[0] -= 1;
+        if (sm->smGetKeyState(SMK_U))
+            rot[2] += 1;
+        if (sm->smGetKeyState(SMK_O))
+            rot[2] -= 1;
+    }
+    for (int i = 0; i < 4; ++i)
+    {
+        q.v[i].col = chkrtint;
+        q.v[i].z = (showpiano && !horizontal) ? -5 : 0;
+    }
+    q.tex = chequer;
+    q.blend = BLEND_ALPHABLEND;
+    q.v[0].x = q.v[3].x = -120;
+    q.v[1].x = q.v[2].x = 120;
+    q.v[0].y = q.v[1].y = -120;
+    q.v[2].y = q.v[3].y = 120;
+    if (horizontal)
+    {
+        for (int i = 0; i < 4; ++i)
+            q.v[i].x = -20;
+        q.v[0].y = q.v[3].y = -120;
+        q.v[1].y = q.v[2].y = 120;
+        q.v[0].z = q.v[1].z = -120;
+        q.v[2].z = q.v[3].z = 120;
+    }
+    q.v[0].tx = q.v[3].tx = 0;
+    q.v[1].tx = q.v[2].tx = 30;
+    q.v[0].ty = q.v[1].ty = 0;
+    q.v[2].ty = q.v[3].ty = 30;
+    sm->smRenderBegin3D(fov, true, tdscn);
+    sm->sm3DCamera6f2v(pos, rot);
+    sm->smClrscr(0, 1, 1);
+    sm->smRenderQuad(&q);
+    double lpt = (double)notestretch / api->getDivision() / 10.*(horizontal ? 0.25 : 1);
+    memcpy(lastnotestatus, notestatus, sizeof(notestatus));
+    memset(notestatus, 0, sizeof(notestatus));
+    for (uint32_t i = elb; i < pool.size(); ++i)
+    {
+        if (((double)pool[i]->tcs - ctk)*lpt > viewdist * 2)
+            break;
+        if (fabs((double)pool[i]->tcs - ctk)*lpt < viewdist * 2 || fabs((double)pool[i]->tce - ctk)*lpt < viewdist * 2)
+        {
+            if (pool[i]->ch == 999)
+            {
+                smvec3d a(0.63 * (-64) + .1 - 10, (stairpiano ? (56 - 0 * 7.) : (64 - 0 * 8.)) + 10, ((double)pool[i]->tcs - ctk)*lpt - minnotelength * .005);
+                smvec3d b(0.63 * 64 + .7 + 10, (stairpiano ? (56 - 15 * 7.) : (64 - 15 * 8.)) + .4 - 10, ((double)pool[i]->tcs - ctk)*lpt + minnotelength * .005);
+                if (horizontal)
+                {
+                    a = smvec3d(((double)pool[i]->tcs - ctk) * lpt - 20 - minnotelength * .001, (16 - 0 * 2.) + 2.4, 0.63 * (-64) + .1);
+                    b = smvec3d(((double)pool[i]->tcs - ctk) * lpt - 20 + minnotelength * .001, (16 - 15 * 2.) + 0.4, 0.63 * 64 + .7);
+                }
+                smMatrix I;
+                I.loadIdentity();
+                smEntity3D c = smEntity3D::cube(a, b, 0xFF000000, horizontal ? 51 : 60);
+                if (stairpiano && showpiano && !horizontal)
+                {
+                    std::vector<size_t> il = {2, 3, 6, 7};
+                    for (size_t ti : il)
+                    {
+                        smVertex t = c.vertex(ti);
+                        t.z += 30;
+                        c.setVertex(ti, t);
+                    }
+                }
+                if (showmeasure)
+                    nebuf->addTransformedEntity(&c, I, smvec3d(0, 0, 0));
+                continue;
+            }
+            if (pool[i]->ch >= 990)
+                continue;
+            if (api->getChannelMask(pool[i]->ch))
+                continue;
+            smvec3d a(0.63 * ((double)pool[i]->key - 64) + .1, (stairpiano ? (56 - pool[i]->ch * 7.) : (64 - pool[i]->ch * 8.)), ((double)pool[i]->tce - ctk)*lpt + (stairpiano && showpiano && !horizontal)*pool[i]->ch * 2.);
+            smvec3d b(0.63 * ((double)pool[i]->key - 64) + .7, (stairpiano ? (56 - pool[i]->ch * 7.) : (64 - pool[i]->ch * 8.)) + .4, ((double)pool[i]->tcs - ctk)*lpt + (stairpiano && showpiano && !horizontal)*pool[i]->ch * 2.);
+            bool isnoteon = pool[i]->tcs <= ctk && pool[i]->tce >= ctk;
+            double pb = ((int)cpw[pool[i]->ch] - 8192) / 8192.*cpbr[pool[i]->ch];
+            if (isnoteon)
+            {
+                a.x = 0.63 * ((double)pool[i]->key - 64 + pb) + .1;
+                b.x = 0.63 * ((double)pool[i]->key - 64 + pb) + .7;
+            }
+            notestatus[pool[i]->ch][pool[i]->key] |= isnoteon;
+            a.x *= 1.2;
+            b.x *= 1.2;
+            if (horizontal)
+            {
+                a = smvec3d(((double)pool[i]->tcs - ctk) * lpt - 20, (16 - pool[i]->ch * 2.), 0.63 * ((double)pool[i]->key - 64) + .1);
+                b = smvec3d(((double)pool[i]->tce - ctk) * lpt - 20, (16 - pool[i]->ch * 2.) + .4, 0.63 * ((double)pool[i]->key - 64) + .7);
+                if (isnoteon)
+                {
+                    a.z = 0.63 * ((double)pool[i]->key - 64 + pb) + .1;
+                    b.z = 0.63 * ((double)pool[i]->key - 64 + pb) + .7;
+                }
+            }
+            if (showparticle && !horizontal)
+            {
+                if (notestatus[pool[i]->ch][pool[i]->key] && !lastnotestatus[pool[i]->ch][pool[i]->key])
+                {
+                    pss[pool[i]->ch][pool[i]->key]->startPS();
+                    pss[pool[i]->ch][pool[i]->key]->setPos(smvec3d(0.756 * ((double)pool[i]->key - 64) + .48, (stairpiano ? (56 - pool[i]->ch * 7.) : (64 - pool[i]->ch * 8.)), stairpiano * pool[i]->ch * 2 + 0.1));
+                }
+                else pss[pool[i]->ch][pool[i]->key]->stopPS();
+            }
+            if (((double)pool[i]->tce - pool[i]->tcs)*lpt < minnotelength * (horizontal ? 0.0025 : 0.01))
+            {
+                if (horizontal)
+                    a.x = ((double)pool[i]->tcs - ctk) * lpt - minnotelength / 400. - 20;
+                else
+                    a.z = ((double)pool[i]->tcs - ctk) * lpt - minnotelength / 100. + stairpiano * pool[i]->ch * 2;
+            }
+            if (usespectrum)
+            {
+                if (notestatus[pool[i]->ch][pool[i]->key] && !lastnotestatus[pool[i]->ch][pool[i]->key])
+                    spectra[pool[i]->ch][pool[i]->key] = pool[i]->vel * (api->getChannelCC(pool[i]->ch, 7) / 127.);
+            }
+            else
+            {
+                smColor col = smColor::fromHWColor(isnoteon ? accolors[pool[i]->ch] : iccolors[pool[i]->ch]);
+                drawCube(a, b, col.lighter(37 + pool[i]->vel / 2).toHWColor(), 0);
+            }
+        }
+    }
+    if (usespectrum && playing)
+        for (int i = 0; i < 16; ++i)
+            for (int j = 0; j < 128; ++j)
+            {
+                if (sustaininst.find(api->getChannelPreset(i)) != sustaininst.end())
+                {
+                    if (!notestatus[i][j] && spectra[i][j])
+                        spectra[i][j] = .95 * spectra[i][j];
+                }
+                else if (spectra[i][j])
+                    spectra[i][j] = .95 * spectra[i][j];
+                if (spectrar[i][j] < spectra[i][j] * 0.9)
+                    spectrar[i][j] += spectra[i][j] * 0.2;
+                else spectrar[i][j] = spectra[i][j];
+                if (spectrar[i][j])
+                {
+                    double pb = ((int)cpw[i] - 8192) / 8192.*cpbr[i];
+                    smvec3d a(0.756 * ((double)j - 64 + pb) + .12,
+                        (stairpiano ? (56 - i * 7.) : (64 - i * 8.)),
+                        spectrar[i][j] * 1.2 * (1 + 0.02 * sin(sm->smGetTime() * 32)) + (stairpiano && showpiano && !horizontal)*i * 2.);
+                    smvec3d b(0.756 * ((double)j - 64 + pb) + .84,
+                        (stairpiano ? (56 - i * 7.) : (64 - i * 8.)) + .4,
+                        (stairpiano && showpiano && !horizontal)*i * 2.);
+                    drawCube(a, b, SETA(iccolors[i], 204), 0);
+                }
+            }
+    nebuf->drawBatch();
+    if (showpiano && !horizontal)
+        for (int i = 0; i < 16; ++i)
+        {
+            for (int j = 0; j < 128; ++j)
+            {
+                if (notestatus[i][j])
+                    if (traveld[i][j] < 10)
+                        traveld[i][j] += 2;
+                    else traveld[i][j] = 10;
+                else if (traveld[i][j] > 0)
+                    traveld[i][j] -= 2;
+                else traveld[i][j] = 0;
+                p3d[i]->setKeyTravelDist(j, traveld[i][j] / 10.);
+            }
+            double pb = ((int)cpw[i] - 8192) / 8192.*cpbr[i];
+            p3d[i]->render(smvec3d(0.756 * pb, stairpiano ? 55 - i * 7 : 62 - i * 8, stairpiano * i * 2));
+        }
+    for (int i = 0; i < 16; ++i)
+        if (showlabel)
+        {
+            std::string s = api->getChannelPresetString(i);
+            wchar_t ws[1024];
+            mbstowcs(ws, s.c_str(), 1024);
+            fonthdpi.updateString(ws);
+            fonthdpi.render(-49, stairpiano ? 56 - i * 7 : 63 - i * 8, stairpiano * i * 2 + 0.1, 0xFFFFFFFF, ALIGN_RIGHT, .008, 0.01);
+            fonthdpi.render(-49.05, stairpiano ? 56.05 - i * 7 : 63.05 - i * 8, stairpiano * i * 2 + 0.2, 0xFF000000, ALIGN_RIGHT, .008, 0.01);
+        }
+    while (pool.size() && elb < pool.size() && ((double)ctk - pool[elb]->tce)*lpt > viewdist * 2)++elb;
+    sm->smRenderEnd();
+    if (showparticle && !horizontal)
+    {
+        sm->smRenderBegin3D(fov, false, tdparticles);
+        sm->sm3DCamera6f2v(pos, rot);
+        sm->smClrscr(0, 1, 1);
+        for (int i = 0; i < 16; ++i)
+            for (int j = 0; j < 128; ++j)
+            {
+                pss[i][j]->setPSLookAt(smvec3d(pos[0], pos[1], pos[2]));
+                pss[i][j]->updatePS();
+                pss[i][j]->renderPS();
+            }
+        sm->smRenderEnd();
+    }
 }
 void qmpVisualization::updateVisualization2D()
 {
-	double lpt=-(double)notestretch/api->getDivision()/2.;
-	memset(notestatus,0,sizeof(notestatus));
-	double notew=wwidth/128,nh=showpiano?wwidth/2048.*172.:0;
-	if(horizontal){notew=wheight/128;nh=showpiano?wheight/2048.*172.:0;lpt=-lpt;}
-	smQuad nq;nq.blend=BLEND_ALPHABLEND;nq.tex=0;
-	for(int i=0;i<4;++i)nq.v[i].z=0,nq.v[i].tx=nq.v[i].ty=0;
-	for(uint32_t i=elb;i<pool.size();++i)
-	{
-		bool upperbound=((double)pool[i]->tcs-ctk)*lpt+wheight-nh<0;
-		bool lowerbound=fabs((double)pool[i]->tce-ctk)*lpt+wheight-nh<wheight;
-		if(horizontal)
-		{
-			upperbound=((double)pool[i]->tcs-ctk)*lpt+nh>wwidth;
-			lowerbound=fabs((double)pool[i]->tce-ctk)*lpt+nh>0;
-		}
-		if(upperbound)break;
-		if(!upperbound||lowerbound)
-		{
-			if(pool[i]->ch==999){
-				smvec2d a(0,((double)pool[i]->tcs-ctk)*lpt+wheight-nh-minnotelength*0.02);
-				smvec2d b(wwidth,((double)pool[i]->tcs-ctk)*lpt+wheight-nh);
-				if(horizontal)
-				{
-					a=smvec2d(((double)pool[i]->tcs-ctk)*lpt+nh-minnotelength*0.02,0);
-					b=smvec2d(((double)pool[i]->tcs-ctk)*lpt+nh,wheight);
-				}
-				nq.v[0].x=nq.v[3].x=a.x;nq.v[0].y=nq.v[1].y=a.y;
-				nq.v[1].x=nq.v[2].x=b.x;nq.v[2].y=nq.v[3].y=b.y;
-				for(int j=0;j<4;++j)nq.v[j].col=0xC0000000;
-				if(showmeasure)sm->smRenderQuad(&nq);
-				continue;
-			}
-			if(pool[i]->ch>=990)continue;
-			if(api->getChannelMask(pool[i]->ch))continue;
-			smvec2d a((froffsets[12]*(pool[i]->key/12)+froffsets[pool[i]->key%12])*wwidth/2048.,((double)pool[i]->tce-ctk)*lpt+wheight-nh);
-			smvec2d b(a.x+notew*0.9,((double)pool[i]->tcs-ctk)*lpt+wheight-nh);
-			if(horizontal)
-			{
-				a=smvec2d(((double)pool[i]->tce-ctk)*lpt+nh,(froffsets[12]*(pool[i]->key/12)+froffsets[pool[i]->key%12])*wheight/2048.);
-				b=smvec2d(((double)pool[i]->tcs-ctk)*lpt+nh,a.y+notew*0.9);
-			}
-			bool isnoteon=pool[i]->tcs<=ctk&&pool[i]->tce>=ctk;
-			if(isnoteon)
-			{
-				double pb=((int)cpw[pool[i]->ch]-8192)/8192.*cpbr[pool[i]->ch];
-				uint32_t newkey=pool[i]->key+(int)floor(pb);
-				double fpb=pb-floor(pb);
-				if(horizontal)
-				{
-					a.y=(froffsets[12]*(newkey/12)+froffsets[newkey%12])*wheight/2048.+notew*fpb;
-					b.y=a.y+notew*0.9;
-				}
-				else
-				{
-					a.x=(froffsets[12]*(newkey/12)+froffsets[newkey%12])*wwidth/2048.+notew*fpb;
-					b.x=a.x+notew*0.9;
-				}
-			}
-			if(horizontal)a.y=wheight-a.y,b.y=wheight-b.y;
-			notestatus[pool[i]->ch][pool[i]->key]|=isnoteon;
-			if(horizontal)
-			{
-				if(((double)pool[i]->tce-pool[i]->tcs)*lpt<minnotelength*0.04)
-					a.x=((double)pool[i]->tcs-ctk)*lpt+nh-minnotelength*0.04;
-			}
-			else
-			{
-				if(((double)pool[i]->tcs-pool[i]->tce)*lpt<minnotelength*0.04)
-					a.y=((double)pool[i]->tcs-ctk)*lpt+wheight-nh-minnotelength*0.04;
-			}
-			nq.v[0].x=nq.v[3].x=a.x;nq.v[0].y=nq.v[1].y=a.y;
-			nq.v[1].x=nq.v[2].x=b.x;nq.v[2].y=nq.v[3].y=b.y;
-			for(int j=0;j<4;++j)
-			nq.v[j].col=SETA(isnoteon?accolors[pool[i]->ch]:iccolors[pool[i]->ch],int(pool[i]->vel*1.6+(isnoteon?52:32)));
-			if(usespectrum)
-			{
-				if(notestatus[pool[i]->ch][pool[i]->key]&&!lastnotestatus[pool[i]->ch][pool[i]->key])
-					spectra[pool[i]->ch][pool[i]->key]=pool[i]->vel*(api->getChannelCC(pool[i]->ch,7)/127.);
-			}else sm->smRenderQuad(&nq);
-		}
-	}
-	if(horizontal)
-	while(pool.size()&&elb<pool.size()&&fabs((double)pool[elb]->tce-ctk)*lpt+nh<0)++elb;
-	else
-	while(pool.size()&&elb<pool.size()&&fabs((double)pool[elb]->tce-ctk)*lpt+wheight-nh>wheight)++elb;
-	smQuad q;
-	q.tex=pianotex;q.blend=BLEND_ALPHABLEND;
-	for(int i=0;i<4;++i)q.v[i].col=0xFFFFFFFF,q.v[i].z=0;
-	q.v[0].ty=q.v[3].ty=0;q.v[1].ty=q.v[2].ty=172./256.;
-	q.v[0].tx=q.v[1].tx=0;q.v[2].tx=q.v[3].tx=1.;
-	q.v[0].x=q.v[1].x=0;q.v[2].x=q.v[3].x=wwidth;
-	q.v[0].y=q.v[3].y=wheight-nh;q.v[1].y=q.v[2].y=wheight;
-	if(horizontal)
-	{
-		q.v[0].tx=q.v[3].tx=0;q.v[1].tx=q.v[2].tx=1;
-		q.v[0].ty=q.v[1].ty=0;q.v[2].ty=q.v[3].ty=172./256.;
-		q.v[0].x=q.v[1].x=nh;q.v[2].x=q.v[3].x=0;
-		q.v[0].y=q.v[3].y=wheight;q.v[1].y=q.v[2].y=0;
-	}
-	sm->smRenderQuad(&q);
-	for(int i=0,j;i<128;++i)
-	{
-		DWORD c=0;for(j=0;j<16;++j)if(notestatus[j][i]){c=SETA(iccolors[j],0xFF);break;}
-		if(horizontal)
-		{
-			q.v[0].y=q.v[1].y=(fpoffsets[12]*(i/12)+fpoffsets[i%12])*wheight/2048.;
-			q.v[2].y=q.v[3].y=q.v[0].y;
-			q.v[0].x=q.v[3].x=nh;q.v[1].x=q.v[2].x=0;
-		}
-		else
-		{
-			q.v[0].x=q.v[1].x=(fpoffsets[12]*(i/12)+fpoffsets[i%12])*wwidth/2048.;
-			q.v[2].x=q.v[3].x=q.v[0].x;
-			q.v[0].y=q.v[3].y=wheight-nh;q.v[1].y=q.v[2].y=wheight;
-		}
-		if(!c)continue;for(int j=0;j<4;++j)q.v[j].col=c;
-		switch(i%12)
-		{
-			case 1:case 3:case 6:case 8:case 10:
-				if(horizontal)
-				{
-					q.v[1].x=q.v[2].x=nh-115*wheight/2048.;
-					q.v[2].y+=15.*wheight/2048;q.v[3].y+=15.*wheight/2048;
-				}
-				else
-				{
-					q.v[1].y=q.v[2].y=wheight-nh+115*wwidth/2048.;
-					q.v[2].x+=15.*wwidth/2048;q.v[3].x+=15.*wwidth/2048;
-				}
-				q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-15/256.;
-				q.v[0].tx=q.v[3].tx=1344/2048.;q.v[1].tx=q.v[2].tx=1459/2048.;
-			break;
-			case 0:
-				if(horizontal)
-				{q.v[2].y+=27.*wheight/2048;q.v[3].y+=27.*wheight/2048;}
-				else
-				{q.v[2].x+=27.*wwidth/2048;q.v[3].x+=27.*wwidth/2048;}
-				q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-27/256.;
-				q.v[0].tx=q.v[3].tx=0/2048.;q.v[1].tx=q.v[2].tx=172/2048.;
-			break;
-			case 2:
-				if(horizontal)
-				{q.v[2].y+=29.*wheight/2048;q.v[3].y+=29.*wheight/2048;}
-				else
-				{q.v[2].x+=29.*wwidth/2048;q.v[3].x+=29.*wwidth/2048;}
-				q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-29/256.;
-				q.v[0].tx=q.v[3].tx=192/2048.;q.v[1].tx=q.v[2].tx=364/2048.;
-			break;
-			case 4:
-				if(horizontal)
-				{q.v[2].y+=28.*wheight/2048;q.v[3].y+=28.*wheight/2048;}
-				else
-				{q.v[2].x+=28.*wwidth/2048;q.v[3].x+=28.*wwidth/2048;}
-				q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-28/256.;
-				q.v[0].tx=q.v[3].tx=384/2048.;q.v[1].tx=q.v[2].tx=556/2048.;
-			break;
-			case 5:
-				if(horizontal)
-				{q.v[2].y+=28.*wheight/2048;q.v[3].y+=28.*wheight/2048;}
-				else
-				{q.v[2].x+=28.*wwidth/2048;q.v[3].x+=28.*wwidth/2048;}
-				q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-28/256.;
-				q.v[0].tx=q.v[3].tx=576/2048.;q.v[1].tx=q.v[2].tx=748/2048.;
-			break;
-			case 7:
-				if(horizontal)
-				{q.v[2].y+=29.*wheight/2048;q.v[3].y+=29.*wheight/2048;}
-				else
-				{q.v[2].x+=29.*wwidth/2048;q.v[3].x+=29.*wwidth/2048;}
-				q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-29/256.;
-				q.v[0].tx=q.v[3].tx=768/2048.;q.v[1].tx=q.v[2].tx=940/2048.;
-			break;
-			case 9:
-				if(horizontal)
-				{q.v[2].y+=28.*wheight/2048;q.v[3].y+=28.*wheight/2048;}
-				else
-				{q.v[2].x+=28.*wwidth/2048;q.v[3].x+=28.*wwidth/2048;}
-				q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-28/256.;
-				q.v[0].tx=q.v[3].tx=960/2048.;q.v[1].tx=q.v[2].tx=1132/2048.;
-			break;
-			case 11:
-				if(horizontal)
-				{q.v[2].y+=28.*wheight/2048;q.v[3].y+=28.*wheight/2048;}
-				else
-				{q.v[2].x+=28.*wwidth/2048;q.v[3].x+=28.*wwidth/2048;}
-				q.v[0].ty=q.v[1].ty=1.;q.v[2].ty=q.v[3].ty=1.-28/256.;
-				q.v[0].tx=q.v[3].tx=1152/2048.;q.v[1].tx=q.v[2].tx=1324/2048.;
-			break;
-		}
-		if(horizontal)for(int j=0;j<4;++j)q.v[j].y=wheight-q.v[j].y;
-		sm->smRenderQuad(&q);
-	}
-	if(usespectrum&&playing)
-	for(int i=0;i<16;++i)for(int j=0;j<128;++j)
-	{
-		if(sustaininst.find(api->getChannelPreset(i))!=sustaininst.end())
-		{
-			if(!notestatus[i][j]&&spectra[i][j])
-				spectra[i][j]=.95*spectra[i][j];
-		}else if(spectra[i][j])spectra[i][j]=.95*spectra[i][j];
-		if(spectrar[i][j]<spectra[i][j]*0.9)spectrar[i][j]+=spectra[i][j]*0.2;
-		else spectrar[i][j]=spectra[i][j];
-		if(spectrar[i][j])
-		{
-			smvec2d a((froffsets[12]*(j/12)+froffsets[j%12])*wwidth/2048.,spectrar[i][j]/-128.*(wheight-nh)*(1+0.02*sin(sm->smGetTime()*32))+wheight-nh);
-			smvec2d b(a.x+notew*0.9,lpt+wheight-nh);
-			double pb=((int)cpw[i]-8192)/8192.*cpbr[i];
-			uint32_t newkey=j+(int)floor(pb);
-			double fpb=pb-floor(pb);
-			if(horizontal)
-			{
-				a=smvec2d(spectrar[i][j]/128.*(wwidth-nh)*(1+0.02*sin(sm->smGetTime()*32))+nh,(froffsets[12]*(j/12)+froffsets[j%12])*wheight/2048.);
-				b=smvec2d(nh,a.y+notew*0.9);
-				a.y=(froffsets[12]*(newkey/12)+froffsets[newkey%12])*wheight/2048.+notew*fpb;
-				b.y=a.y+notew*0.9;
-				a.y=wheight-a.y;b.y=wheight-b.y;
-			}
-			else
-			{
-				a.x=(froffsets[12]*(newkey/12)+froffsets[newkey%12])*wwidth/2048.+notew*fpb;
-				b.x=a.x+notew*0.9;
-			}
-			nq.v[0].x=nq.v[3].x=a.x;nq.v[0].y=nq.v[1].y=a.y;
-			nq.v[1].x=nq.v[2].x=b.x;nq.v[2].y=nq.v[3].y=b.y;for(int j=0;j<4;++j)
-			nq.v[j].col=SETA(iccolors[i],204);
-			sm->smRenderQuad(&nq);
-		}
-	}
+    double lpt = -(double)notestretch / api->getDivision() / 2.;
+    memset(notestatus, 0, sizeof(notestatus));
+    double notew = wwidth / 128, nh = showpiano ? wwidth / 2048.*172. : 0;
+    if (horizontal)
+    {
+        notew = wheight / 128;
+        nh = showpiano ? wheight / 2048.*172. : 0;
+        lpt = -lpt;
+    }
+    smQuad nq;
+    nq.blend = BLEND_ALPHABLEND;
+    nq.tex = 0;
+    for (int i = 0; i < 4; ++i)
+        nq.v[i].z = 0, nq.v[i].tx = nq.v[i].ty = 0;
+    for (uint32_t i = elb; i < pool.size(); ++i)
+    {
+        bool upperbound = ((double)pool[i]->tcs - ctk) * lpt + wheight - nh < 0;
+        bool lowerbound = fabs((double)pool[i]->tce - ctk) * lpt + wheight - nh < wheight;
+        if (horizontal)
+        {
+            upperbound = ((double)pool[i]->tcs - ctk) * lpt + nh > wwidth;
+            lowerbound = fabs((double)pool[i]->tce - ctk) * lpt + nh > 0;
+        }
+        if (upperbound)
+            break;
+        if (!upperbound || lowerbound)
+        {
+            if (pool[i]->ch == 999)
+            {
+                smvec2d a(0, ((double)pool[i]->tcs - ctk)*lpt + wheight - nh - minnotelength * 0.02);
+                smvec2d b(wwidth, ((double)pool[i]->tcs - ctk)*lpt + wheight - nh);
+                if (horizontal)
+                {
+                    a = smvec2d(((double)pool[i]->tcs - ctk) * lpt + nh - minnotelength * 0.02, 0);
+                    b = smvec2d(((double)pool[i]->tcs - ctk) * lpt + nh, wheight);
+                }
+                nq.v[0].x = nq.v[3].x = a.x;
+                nq.v[0].y = nq.v[1].y = a.y;
+                nq.v[1].x = nq.v[2].x = b.x;
+                nq.v[2].y = nq.v[3].y = b.y;
+                for (int j = 0; j < 4; ++j)
+                    nq.v[j].col = 0xC0000000;
+                if (showmeasure)
+                    sm->smRenderQuad(&nq);
+                continue;
+            }
+            if (pool[i]->ch >= 990)
+                continue;
+            if (api->getChannelMask(pool[i]->ch))
+                continue;
+            smvec2d a((froffsets[12] * (pool[i]->key / 12) + froffsets[pool[i]->key % 12])*wwidth / 2048., ((double)pool[i]->tce - ctk)*lpt + wheight - nh);
+            smvec2d b(a.x + notew * 0.9, ((double)pool[i]->tcs - ctk)*lpt + wheight - nh);
+            if (horizontal)
+            {
+                a = smvec2d(((double)pool[i]->tce - ctk) * lpt + nh, (froffsets[12] * (pool[i]->key / 12) + froffsets[pool[i]->key % 12]) * wheight / 2048.);
+                b = smvec2d(((double)pool[i]->tcs - ctk) * lpt + nh, a.y + notew * 0.9);
+            }
+            bool isnoteon = pool[i]->tcs <= ctk && pool[i]->tce >= ctk;
+            if (isnoteon)
+            {
+                double pb = ((int)cpw[pool[i]->ch] - 8192) / 8192.*cpbr[pool[i]->ch];
+                uint32_t newkey = pool[i]->key + (int)floor(pb);
+                double fpb = pb - floor(pb);
+                if (horizontal)
+                {
+                    a.y = (froffsets[12] * (newkey / 12) + froffsets[newkey % 12]) * wheight / 2048. + notew * fpb;
+                    b.y = a.y + notew * 0.9;
+                }
+                else
+                {
+                    a.x = (froffsets[12] * (newkey / 12) + froffsets[newkey % 12]) * wwidth / 2048. + notew * fpb;
+                    b.x = a.x + notew * 0.9;
+                }
+            }
+            if (horizontal)
+                a.y = wheight - a.y, b.y = wheight - b.y;
+            notestatus[pool[i]->ch][pool[i]->key] |= isnoteon;
+            if (horizontal)
+            {
+                if (((double)pool[i]->tce - pool[i]->tcs)*lpt < minnotelength * 0.04)
+                    a.x = ((double)pool[i]->tcs - ctk) * lpt + nh - minnotelength * 0.04;
+            }
+            else
+            {
+                if (((double)pool[i]->tcs - pool[i]->tce)*lpt < minnotelength * 0.04)
+                    a.y = ((double)pool[i]->tcs - ctk) * lpt + wheight - nh - minnotelength * 0.04;
+            }
+            nq.v[0].x = nq.v[3].x = a.x;
+            nq.v[0].y = nq.v[1].y = a.y;
+            nq.v[1].x = nq.v[2].x = b.x;
+            nq.v[2].y = nq.v[3].y = b.y;
+            for (int j = 0; j < 4; ++j)
+                nq.v[j].col = SETA(isnoteon ? accolors[pool[i]->ch] : iccolors[pool[i]->ch], int(pool[i]->vel * 1.6 + (isnoteon ? 52 : 32)));
+            if (usespectrum)
+            {
+                if (notestatus[pool[i]->ch][pool[i]->key] && !lastnotestatus[pool[i]->ch][pool[i]->key])
+                    spectra[pool[i]->ch][pool[i]->key] = pool[i]->vel * (api->getChannelCC(pool[i]->ch, 7) / 127.);
+            }
+            else sm->smRenderQuad(&nq);
+        }
+    }
+    if (horizontal)
+        while (pool.size() && elb < pool.size() && fabs((double)pool[elb]->tce - ctk)*lpt + nh < 0)++elb;
+    else
+        while (pool.size() && elb < pool.size() && fabs((double)pool[elb]->tce - ctk)*lpt + wheight - nh > wheight)++elb;
+    smQuad q;
+    q.tex = pianotex;
+    q.blend = BLEND_ALPHABLEND;
+    for (int i = 0; i < 4; ++i)
+        q.v[i].col = 0xFFFFFFFF, q.v[i].z = 0;
+    q.v[0].ty = q.v[3].ty = 0;
+    q.v[1].ty = q.v[2].ty = 172. / 256.;
+    q.v[0].tx = q.v[1].tx = 0;
+    q.v[2].tx = q.v[3].tx = 1.;
+    q.v[0].x = q.v[1].x = 0;
+    q.v[2].x = q.v[3].x = wwidth;
+    q.v[0].y = q.v[3].y = wheight - nh;
+    q.v[1].y = q.v[2].y = wheight;
+    if (horizontal)
+    {
+        q.v[0].tx = q.v[3].tx = 0;
+        q.v[1].tx = q.v[2].tx = 1;
+        q.v[0].ty = q.v[1].ty = 0;
+        q.v[2].ty = q.v[3].ty = 172. / 256.;
+        q.v[0].x = q.v[1].x = nh;
+        q.v[2].x = q.v[3].x = 0;
+        q.v[0].y = q.v[3].y = wheight;
+        q.v[1].y = q.v[2].y = 0;
+    }
+    sm->smRenderQuad(&q);
+    for (int i = 0, j; i < 128; ++i)
+    {
+        DWORD c = 0;
+        for (j = 0; j < 16; ++j)
+            if (notestatus[j][i])
+            {
+                c = SETA(iccolors[j], 0xFF);
+                break;
+            }
+        if (horizontal)
+        {
+            q.v[0].y = q.v[1].y = (fpoffsets[12] * (i / 12) + fpoffsets[i % 12]) * wheight / 2048.;
+            q.v[2].y = q.v[3].y = q.v[0].y;
+            q.v[0].x = q.v[3].x = nh;
+            q.v[1].x = q.v[2].x = 0;
+        }
+        else
+        {
+            q.v[0].x = q.v[1].x = (fpoffsets[12] * (i / 12) + fpoffsets[i % 12]) * wwidth / 2048.;
+            q.v[2].x = q.v[3].x = q.v[0].x;
+            q.v[0].y = q.v[3].y = wheight - nh;
+            q.v[1].y = q.v[2].y = wheight;
+        }
+        if (!c)
+            continue;
+        for (int j = 0; j < 4; ++j)
+            q.v[j].col = c;
+        switch (i % 12)
+        {
+            case 1:
+            case 3:
+            case 6:
+            case 8:
+            case 10:
+                if (horizontal)
+                {
+                    q.v[1].x = q.v[2].x = nh - 115 * wheight / 2048.;
+                    q.v[2].y += 15.*wheight / 2048;
+                    q.v[3].y += 15.*wheight / 2048;
+                }
+                else
+                {
+                    q.v[1].y = q.v[2].y = wheight - nh + 115 * wwidth / 2048.;
+                    q.v[2].x += 15.*wwidth / 2048;
+                    q.v[3].x += 15.*wwidth / 2048;
+                }
+                q.v[0].ty = q.v[1].ty = 1.;
+                q.v[2].ty = q.v[3].ty = 1. - 15 / 256.;
+                q.v[0].tx = q.v[3].tx = 1344 / 2048.;
+                q.v[1].tx = q.v[2].tx = 1459 / 2048.;
+                break;
+            case 0:
+                if (horizontal)
+                {
+                    q.v[2].y += 27.*wheight / 2048;
+                    q.v[3].y += 27.*wheight / 2048;
+                }
+                else
+                {
+                    q.v[2].x += 27.*wwidth / 2048;
+                    q.v[3].x += 27.*wwidth / 2048;
+                }
+                q.v[0].ty = q.v[1].ty = 1.;
+                q.v[2].ty = q.v[3].ty = 1. - 27 / 256.;
+                q.v[0].tx = q.v[3].tx = 0 / 2048.;
+                q.v[1].tx = q.v[2].tx = 172 / 2048.;
+                break;
+            case 2:
+                if (horizontal)
+                {
+                    q.v[2].y += 29.*wheight / 2048;
+                    q.v[3].y += 29.*wheight / 2048;
+                }
+                else
+                {
+                    q.v[2].x += 29.*wwidth / 2048;
+                    q.v[3].x += 29.*wwidth / 2048;
+                }
+                q.v[0].ty = q.v[1].ty = 1.;
+                q.v[2].ty = q.v[3].ty = 1. - 29 / 256.;
+                q.v[0].tx = q.v[3].tx = 192 / 2048.;
+                q.v[1].tx = q.v[2].tx = 364 / 2048.;
+                break;
+            case 4:
+                if (horizontal)
+                {
+                    q.v[2].y += 28.*wheight / 2048;
+                    q.v[3].y += 28.*wheight / 2048;
+                }
+                else
+                {
+                    q.v[2].x += 28.*wwidth / 2048;
+                    q.v[3].x += 28.*wwidth / 2048;
+                }
+                q.v[0].ty = q.v[1].ty = 1.;
+                q.v[2].ty = q.v[3].ty = 1. - 28 / 256.;
+                q.v[0].tx = q.v[3].tx = 384 / 2048.;
+                q.v[1].tx = q.v[2].tx = 556 / 2048.;
+                break;
+            case 5:
+                if (horizontal)
+                {
+                    q.v[2].y += 28.*wheight / 2048;
+                    q.v[3].y += 28.*wheight / 2048;
+                }
+                else
+                {
+                    q.v[2].x += 28.*wwidth / 2048;
+                    q.v[3].x += 28.*wwidth / 2048;
+                }
+                q.v[0].ty = q.v[1].ty = 1.;
+                q.v[2].ty = q.v[3].ty = 1. - 28 / 256.;
+                q.v[0].tx = q.v[3].tx = 576 / 2048.;
+                q.v[1].tx = q.v[2].tx = 748 / 2048.;
+                break;
+            case 7:
+                if (horizontal)
+                {
+                    q.v[2].y += 29.*wheight / 2048;
+                    q.v[3].y += 29.*wheight / 2048;
+                }
+                else
+                {
+                    q.v[2].x += 29.*wwidth / 2048;
+                    q.v[3].x += 29.*wwidth / 2048;
+                }
+                q.v[0].ty = q.v[1].ty = 1.;
+                q.v[2].ty = q.v[3].ty = 1. - 29 / 256.;
+                q.v[0].tx = q.v[3].tx = 768 / 2048.;
+                q.v[1].tx = q.v[2].tx = 940 / 2048.;
+                break;
+            case 9:
+                if (horizontal)
+                {
+                    q.v[2].y += 28.*wheight / 2048;
+                    q.v[3].y += 28.*wheight / 2048;
+                }
+                else
+                {
+                    q.v[2].x += 28.*wwidth / 2048;
+                    q.v[3].x += 28.*wwidth / 2048;
+                }
+                q.v[0].ty = q.v[1].ty = 1.;
+                q.v[2].ty = q.v[3].ty = 1. - 28 / 256.;
+                q.v[0].tx = q.v[3].tx = 960 / 2048.;
+                q.v[1].tx = q.v[2].tx = 1132 / 2048.;
+                break;
+            case 11:
+                if (horizontal)
+                {
+                    q.v[2].y += 28.*wheight / 2048;
+                    q.v[3].y += 28.*wheight / 2048;
+                }
+                else
+                {
+                    q.v[2].x += 28.*wwidth / 2048;
+                    q.v[3].x += 28.*wwidth / 2048;
+                }
+                q.v[0].ty = q.v[1].ty = 1.;
+                q.v[2].ty = q.v[3].ty = 1. - 28 / 256.;
+                q.v[0].tx = q.v[3].tx = 1152 / 2048.;
+                q.v[1].tx = q.v[2].tx = 1324 / 2048.;
+                break;
+        }
+        if (horizontal)
+            for (int j = 0; j < 4; ++j)
+                q.v[j].y = wheight - q.v[j].y;
+        sm->smRenderQuad(&q);
+    }
+    if (usespectrum && playing)
+        for (int i = 0; i < 16; ++i)
+            for (int j = 0; j < 128; ++j)
+            {
+                if (sustaininst.find(api->getChannelPreset(i)) != sustaininst.end())
+                {
+                    if (!notestatus[i][j] && spectra[i][j])
+                        spectra[i][j] = .95 * spectra[i][j];
+                }
+                else if (spectra[i][j])
+                    spectra[i][j] = .95 * spectra[i][j];
+                if (spectrar[i][j] < spectra[i][j] * 0.9)
+                    spectrar[i][j] += spectra[i][j] * 0.2;
+                else spectrar[i][j] = spectra[i][j];
+                if (spectrar[i][j])
+                {
+                    smvec2d a((froffsets[12] * (j / 12) + froffsets[j % 12])*wwidth / 2048., spectrar[i][j] / -128.*(wheight - nh) * (1 + 0.02 * sin(sm->smGetTime() * 32)) + wheight - nh);
+                    smvec2d b(a.x + notew * 0.9, lpt + wheight - nh);
+                    double pb = ((int)cpw[i] - 8192) / 8192.*cpbr[i];
+                    uint32_t newkey = j + (int)floor(pb);
+                    double fpb = pb - floor(pb);
+                    if (horizontal)
+                    {
+                        a = smvec2d(spectrar[i][j] / 128.*(wwidth - nh) * (1 + 0.02 * sin(sm->smGetTime() * 32)) + nh, (froffsets[12] * (j / 12) + froffsets[j % 12]) * wheight / 2048.);
+                        b = smvec2d(nh, a.y + notew * 0.9);
+                        a.y = (froffsets[12] * (newkey / 12) + froffsets[newkey % 12]) * wheight / 2048. + notew * fpb;
+                        b.y = a.y + notew * 0.9;
+                        a.y = wheight - a.y;
+                        b.y = wheight - b.y;
+                    }
+                    else
+                    {
+                        a.x = (froffsets[12] * (newkey / 12) + froffsets[newkey % 12]) * wwidth / 2048. + notew * fpb;
+                        b.x = a.x + notew * 0.9;
+                    }
+                    nq.v[0].x = nq.v[3].x = a.x;
+                    nq.v[0].y = nq.v[1].y = a.y;
+                    nq.v[1].x = nq.v[2].x = b.x;
+                    nq.v[2].y = nq.v[3].y = b.y;
+                    for (int j = 0; j < 4; ++j)
+                        nq.v[j].col = SETA(iccolors[i], 204);
+                    sm->smRenderQuad(&nq);
+                }
+            }
 }
 bool qmpVisualization::update()
 {
-	smQuad q;
-	if(!rendermode)
-	{
-		if(sm->smGetKeyState(SMK_RIGHT)==SMKST_HIT)
-			api->playerSeek(api->getCurrentPlaybackPercentage()+(sm->smGetKeyState(SMK_SHIFT)?5:1));
-		if(sm->smGetKeyState(SMK_LEFT)==SMKST_HIT)
-			api->playerSeek(api->getCurrentPlaybackPercentage()-(sm->smGetKeyState(SMK_SHIFT)?5:1));
-		if(sm->smGetKeyState(SMK_B)==SMKST_HIT)
-			debug^=1;
-	}
-	if(playing)
-	{
-		if(rendermode)
-		{
-			ctk=1e6*(cfr)/tfps/ctp*api->getDivision()+lstk;
-			++cfr;
-		}
-		else
-			ctk=lstk+std::chrono::duration_cast<std::chrono::duration<double,std::micro>>(std::chrono::steady_clock::now()-lst).count()/api->getRawTempo()*api->getDivision();
-	}
-	if(!flat)
-		updateVisualization3D();
-	sm->smRenderBegin2D();
-	sm->smClrscr(0xFF666666);q.blend=BLEND_ALPHABLEND;
-	for(int i=0;i<4;++i){q.v[i].col=0xFFFFFFFF;q.v[i].z=0;}
-	if(bgtex)
-	{
-		q.tex=bgtex;
-		q.v[0].x=q.v[3].x=0;q.v[1].x=q.v[2].x=wwidth;
-		q.v[0].y=q.v[1].y=0;q.v[2].y=q.v[3].y=wheight;
-		q.v[0].tx=q.v[3].tx=0;q.v[1].tx=q.v[2].tx=1;
-		q.v[0].ty=q.v[1].ty=0;q.v[2].ty=q.v[3].ty=1;
-		sm->smRenderQuad(&q);
-	}
-	if(flat)
-		updateVisualization2D();
-	else
-	{
-		q.tex=sm->smTargetTexture(tdscn);
-		q.v[0].tx=q.v[3].tx=0;q.v[1].tx=q.v[2].tx=1;
-		q.v[0].ty=q.v[1].ty=0;q.v[2].ty=q.v[3].ty=1;
-		q.v[0].x=q.v[1].x=0;q.v[2].x=q.v[3].x=wwidth;
-		q.v[0].y=q.v[3].y=0;q.v[1].y=q.v[2].y=wheight;
-		sm->smRenderQuad(&q);
-		if(showparticle&&!horizontal)
-		{
-			q.tex=sm->smTargetTexture(tdparticles);
-			sm->smRenderQuad(&q);
-		}
-	}
-	if(osdpos==4){sm->smRenderEnd();return shouldclose;}
-	uint32_t ltpc=~0u;
-	for(uint32_t i=elb;i<pool.size();++i)
-	{
-		if(pool[i]->tcs>ctk)break;
-		if(pool[i]->ch==998)cts=pool[i]->key;
-		if(pool[i]->ch==997)cks=pool[i]->key;
-		if(pool[i]->ch==996)
-			ltpc=i;
-		if(pool[i]->ch==995)cpbr[pool[i]->vel]=pool[i]->key;
-		if(pool[i]->ch==994)cpw[pool[i]->vel]=pool[i]->key;
-	}
-	if(~ltpc&&ctp!=pool[ltpc]->key)
-	{
-		ctp=pool[ltpc]->key;
-		if(rendermode)
-		{
-			lstk=pool[ltpc]->tcs;
-			cfr=1;
-		}
-	}
-	int t,r;t=cks;r=(int8_t)((t>>8)&0xFF)+7;t&=0xFF;
-	std::wstring ts(t?minors:majors,2*r,2);
-	int step=int(1.33*fontsize);
-	int xp=(osdpos&1)?wwidth-step-1:1;
-	int yp=osdpos<2?wheight-step*5-4:step+4;
-	int align=osdpos&1?ALIGN_RIGHT:ALIGN_LEFT;
-	font2.updateString(L"Title: %ls",api->getWTitle().c_str());
-	font2.render(xp,yp,0.5,0xFFFFFFFF,align);
-	font2.render(xp-1,yp-1,0.5,0xFF000000,align);
-	font.updateString(L"Time Sig: %d/%d",cts>>8,1<<(cts&0xFF));
-	font.render(xp,yp+=step,0.5,0xFFFFFFFF,align);
-	font.render(xp-1,yp-1,0.5,0xFF000000,align);
-	font.updateString(L"Key Sig: %ls",ts.c_str());
-	font.render(xp,yp+=step,0.5,0xFFFFFFFF,align);
-	font.render(xp-1,yp-1,0.5,0xFF000000,align);
-	font.updateString(L"Tempo: %.2f",60./(ctp/1e6));
-	font.render(xp,yp+=step,0.5,0xFFFFFFFF,align);
-	font.render(xp-1,yp-1,0.5,0xFF000000,align);
-	font.updateString(L"Current tick: %d",ctk);
-	font.render(xp,yp+=step,0.5,0xFFFFFFFF,align);
-	font.render(xp-1,yp-1,0.5,0xFF000000,align);
-	if(!rendermode)
-	{
-		font.updateString(L"FPS: %.2f",sm->smGetFPS());
-		font.render(xp,yp+=step,0.5,0xFFFFFFFF,align);
-		font.render(xp-1,yp-1,0.5,0xFF000000,align);
-	}
-	if(debug)
-	{
-		int dosdpos=(osdpos+1)%4;
-		xp=(dosdpos&1)?wwidth-step-1:1;
-		yp=dosdpos<2?wheight-step*5-4:step+4;
-		align=dosdpos&1?ALIGN_RIGHT:ALIGN_LEFT;
-		std::string tstr;
-		tstr=std::string(sm->smGetOSInfo());
-		font.updateString(L"OS: %ls",std::wstring({std::begin(tstr),std::end(tstr)}).c_str());
-		font.render(xp,yp,0.5,0xFFFFFFFF,align);
-		font.render(xp-1,yp-1,0.5,0xFF000000,align);
-		tstr=std::string(sm->smGetCPUModel());
-		font.updateString(L"CPU: %ls",std::wstring({std::begin(tstr),std::end(tstr)}).c_str());
-		font.render(xp,yp+=step,0.5,0xFFFFFFFF,align);
-		font.render(xp-1,yp-1,0.5,0xFF000000,align);
-		tstr=std::string(sm->smGetDispDriver());
-		font.updateString(L"Display %ls",std::wstring({std::begin(tstr),std::end(tstr)}).c_str());
-		font.render(xp,yp+=3*step,0.5,0xFFFFFFFF,align);
-		font.render(xp-1,yp-1,0.5,0xFF000000,align);
-	}
-	sm->smRenderEnd();
-	if(rendermode)
-	{
-		if(ctk>api->getMaxTick())
-			framecb(nullptr,0,ctk,api->getMaxTick());
-		else
-		{
-			sm->smPixelCopy(0,0,wwidth,wheight,4*wwidth*wheight,fbcont);
-			framecb(fbcont,4*wwidth*wheight,ctk,api->getMaxTick());
-		}
-	}
-	return shouldclose;
+    smQuad q;
+    if (!rendermode)
+    {
+        if (sm->smGetKeyState(SMK_RIGHT) == SMKST_HIT)
+            api->playerSeek(api->getCurrentPlaybackPercentage() + (sm->smGetKeyState(SMK_SHIFT) ? 5 : 1));
+        if (sm->smGetKeyState(SMK_LEFT) == SMKST_HIT)
+            api->playerSeek(api->getCurrentPlaybackPercentage() - (sm->smGetKeyState(SMK_SHIFT) ? 5 : 1));
+        if (sm->smGetKeyState(SMK_B) == SMKST_HIT)
+            debug ^= 1;
+    }
+    if (playing)
+    {
+        if (rendermode)
+        {
+            ctk = 1e6 * (cfr) / tfps / ctp * api->getDivision() + lstk;
+            ++cfr;
+        }
+        else
+            ctk = lstk + std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(std::chrono::steady_clock::now() - lst).count() / api->getRawTempo() * api->getDivision();
+    }
+    if (!flat)
+        updateVisualization3D();
+    sm->smRenderBegin2D();
+    sm->smClrscr(0xFF666666);
+    q.blend = BLEND_ALPHABLEND;
+    for (int i = 0; i < 4; ++i)
+    {
+        q.v[i].col = 0xFFFFFFFF;
+        q.v[i].z = 0;
+    }
+    if (bgtex)
+    {
+        q.tex = bgtex;
+        q.v[0].x = q.v[3].x = 0;
+        q.v[1].x = q.v[2].x = wwidth;
+        q.v[0].y = q.v[1].y = 0;
+        q.v[2].y = q.v[3].y = wheight;
+        q.v[0].tx = q.v[3].tx = 0;
+        q.v[1].tx = q.v[2].tx = 1;
+        q.v[0].ty = q.v[1].ty = 0;
+        q.v[2].ty = q.v[3].ty = 1;
+        sm->smRenderQuad(&q);
+    }
+    if (flat)
+        updateVisualization2D();
+    else
+    {
+        q.tex = sm->smTargetTexture(tdscn);
+        q.v[0].tx = q.v[3].tx = 0;
+        q.v[1].tx = q.v[2].tx = 1;
+        q.v[0].ty = q.v[1].ty = 0;
+        q.v[2].ty = q.v[3].ty = 1;
+        q.v[0].x = q.v[1].x = 0;
+        q.v[2].x = q.v[3].x = wwidth;
+        q.v[0].y = q.v[3].y = 0;
+        q.v[1].y = q.v[2].y = wheight;
+        sm->smRenderQuad(&q);
+        if (showparticle && !horizontal)
+        {
+            q.tex = sm->smTargetTexture(tdparticles);
+            sm->smRenderQuad(&q);
+        }
+    }
+    if (osdpos == 4)
+    {
+        sm->smRenderEnd();
+        return shouldclose;
+    }
+    uint32_t ltpc = ~0u;
+    for (uint32_t i = elb; i < pool.size(); ++i)
+    {
+        if (pool[i]->tcs > ctk)
+            break;
+        if (pool[i]->ch == 998)
+            cts = pool[i]->key;
+        if (pool[i]->ch == 997)
+            cks = pool[i]->key;
+        if (pool[i]->ch == 996)
+            ltpc = i;
+        if (pool[i]->ch == 995)
+            cpbr[pool[i]->vel] = pool[i]->key;
+        if (pool[i]->ch == 994)
+            cpw[pool[i]->vel] = pool[i]->key;
+    }
+    if (~ltpc && ctp != pool[ltpc]->key)
+    {
+        ctp = pool[ltpc]->key;
+        if (rendermode)
+        {
+            lstk = pool[ltpc]->tcs;
+            cfr = 1;
+        }
+    }
+    int t, r;
+    t = cks;
+    r = (int8_t)((t >> 8) & 0xFF) + 7;
+    t &= 0xFF;
+    std::wstring ts(t ? minors : majors, 2 * r, 2);
+    int step = int(1.33 * fontsize);
+    int xp = (osdpos & 1) ? wwidth - step - 1 : 1;
+    int yp = osdpos < 2 ? wheight - step * 5 - 4 : step + 4;
+    int align = osdpos & 1 ? ALIGN_RIGHT : ALIGN_LEFT;
+    font2.updateString(L"Title: %ls", api->getWTitle().c_str());
+    font2.render(xp, yp, 0.5, 0xFFFFFFFF, align);
+    font2.render(xp - 1, yp - 1, 0.5, 0xFF000000, align);
+    font.updateString(L"Time Sig: %d/%d", cts >> 8, 1 << (cts & 0xFF));
+    font.render(xp, yp += step, 0.5, 0xFFFFFFFF, align);
+    font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align);
+    font.updateString(L"Key Sig: %ls", ts.c_str());
+    font.render(xp, yp += step, 0.5, 0xFFFFFFFF, align);
+    font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align);
+    font.updateString(L"Tempo: %.2f", 60. / (ctp / 1e6));
+    font.render(xp, yp += step, 0.5, 0xFFFFFFFF, align);
+    font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align);
+    font.updateString(L"Current tick: %d", ctk);
+    font.render(xp, yp += step, 0.5, 0xFFFFFFFF, align);
+    font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align);
+    if (!rendermode)
+    {
+        font.updateString(L"FPS: %.2f", sm->smGetFPS());
+        font.render(xp, yp += step, 0.5, 0xFFFFFFFF, align);
+        font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align);
+    }
+    if (debug)
+    {
+        int dosdpos = (osdpos + 1) % 4;
+        xp = (dosdpos & 1) ? wwidth - step - 1 : 1;
+        yp = dosdpos < 2 ? wheight - step * 5 - 4 : step + 4;
+        align = dosdpos & 1 ? ALIGN_RIGHT : ALIGN_LEFT;
+        std::string tstr;
+        tstr = std::string(sm->smGetOSInfo());
+        font.updateString(L"OS: %ls", std::wstring({std::begin(tstr), std::end(tstr)}).c_str());
+        font.render(xp, yp, 0.5, 0xFFFFFFFF, align);
+        font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align);
+        tstr = std::string(sm->smGetCPUModel());
+        font.updateString(L"CPU: %ls", std::wstring({std::begin(tstr), std::end(tstr)}).c_str());
+        font.render(xp, yp += step, 0.5, 0xFFFFFFFF, align);
+        font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align);
+        tstr = std::string(sm->smGetDispDriver());
+        font.updateString(L"Display %ls", std::wstring({std::begin(tstr), std::end(tstr)}).c_str());
+        font.render(xp, yp += 3 * step, 0.5, 0xFFFFFFFF, align);
+        font.render(xp - 1, yp - 1, 0.5, 0xFF000000, align);
+    }
+    sm->smRenderEnd();
+    if (rendermode)
+    {
+        if (ctk > api->getMaxTick())
+            framecb(nullptr, 0, ctk, api->getMaxTick());
+        else
+        {
+            sm->smPixelCopy(0, 0, wwidth, wheight, 4 * wwidth * wheight, fbcont);
+            framecb(fbcont, 4 * wwidth * wheight, ctk, api->getMaxTick());
+        }
+    }
+    return shouldclose;
 }
 
-void qmpVisualization::drawCube(smvec3d a,smvec3d b,DWORD col,SMTEX tex,int faces)
+void qmpVisualization::drawCube(smvec3d a, smvec3d b, DWORD col, SMTEX tex, int faces)
 {
-	smQuad q;q.blend=BLEND_ALPHABLEND;
-	q.tex=tex;for(int i=0;i<4;++i)q.v[i].col=col;
-	if(noteappearance==1)
-	{
-		smMatrix I;I.loadIdentity();smEntity3D c=smEntity3D::cube(a,b,col,faces);
-		nebuf->addTransformedEntity(&c,I,smvec3d(0,0,0));
-	}
-	else
-	{
-		q.v[0].x=a.x;q.v[0].y=b.y;q.v[0].z=a.z;
-		q.v[1].x=b.x;q.v[1].y=b.y;q.v[1].z=a.z;
-		q.v[2].x=b.x;q.v[2].y=b.y;q.v[2].z=b.z;
-		q.v[3].x=a.x;q.v[3].y=b.y;q.v[3].z=b.z;
-		sm->smRenderQuad(&q);
-	}
+    smQuad q;
+    q.blend = BLEND_ALPHABLEND;
+    q.tex = tex;
+    for (int i = 0; i < 4; ++i)
+        q.v[i].col = col;
+    if (noteappearance == 1)
+    {
+        smMatrix I;
+        I.loadIdentity();
+        smEntity3D c = smEntity3D::cube(a, b, col, faces);
+        nebuf->addTransformedEntity(&c, I, smvec3d(0, 0, 0));
+    }
+    else
+    {
+        q.v[0].x = a.x;
+        q.v[0].y = b.y;
+        q.v[0].z = a.z;
+        q.v[1].x = b.x;
+        q.v[1].y = b.y;
+        q.v[1].z = a.z;
+        q.v[2].x = b.x;
+        q.v[2].y = b.y;
+        q.v[2].z = b.z;
+        q.v[3].x = a.x;
+        q.v[3].y = b.y;
+        q.v[3].z = b.z;
+        sm->smRenderQuad(&q);
+    }
 }
 
-qmpVisualization* qmpVisualization::inst=nullptr;
+qmpVisualization *qmpVisualization::inst = nullptr;
 
-qmpVisualization::qmpVisualization(qmpPluginAPI* _api)
+qmpVisualization::qmpVisualization(qmpPluginAPI *_api)
 {
-	api=_api;
-	inst=this;
-	rendermode=false;
-	hidewindow=false;
+    api = _api;
+    inst = this;
+    rendermode = false;
+    hidewindow = false;
 }
 qmpVisualization::~qmpVisualization()
 {
-	api=nullptr;
-	inst=nullptr;
+    api = nullptr;
+    inst = nullptr;
 }
 void qmpVisualization::init()
 {
-	h=new CMidiVisualHandler(this);
-	closeh=new CloseHandler(this);
-	rendererTh=nullptr;playing=false;
-	memset(rpnid,0xFF,sizeof(rpnid));
-	memset(rpnval,0xFF,sizeof(rpnval));
-	memset(spectra,0,sizeof(spectra));
-	memset(spectrar,0,sizeof(spectrar));
-	api->registerFunctionality(this,"Visualization","Visualization",api->isDarkTheme()?":/img/visualization_i.svg":":/img/visualization.svg",0,true);
-	uihb=api->registerUIHook("main.start",[this](const void*,void*){this->start();},nullptr);
-	uihs=api->registerUIHook("main.stop",[this](const void*,void*){this->stop();},nullptr);
-	uihp=api->registerUIHook("main.pause",[this](const void*,void*){this->pause();},nullptr);
-	uihr=api->registerUIHook("main.reset",[this](const void*,void*){this->reset();},nullptr);
-	uihk=api->registerUIHook("main.seek",[this](const void*,void*){
-		cts=api->getTimeSig();
-		cks=api->getKeySig();
-		ctp=api->getRawTempo();
-		for(int i=0;i<16;++i)
-		api->getPitchBendRaw(i,&cpw[i],&cpbr[i]);
-	},nullptr);
-	herh=api->registerEventReadHandler(
-		[this](const void *ee,void*){
-			const SEvent* e=(const SEvent*)ee;
-			switch(e->type&0xF0)
-			{
-				case 0x80:
-					this->pushNoteOff(e->time,e->type&0x0F,e->p1);
-				break;
-				case 0x90:
-					if(e->p2)
-					this->pushNoteOn(e->time,e->type&0x0F,e->p1,e->p2);
-					else
-					this->pushNoteOff(e->time,e->type&0x0F,e->p1);
-				break;
-				case 0xB0:
-					if(e->p1==100)rpnid[e->type&0x0F]=e->p2;
-					if(e->p1==6)rpnval[e->type&0x0F]=e->p2;
-					if(~rpnid[e->type&0x0F]&&~rpnval[e->type&0x0F])
-					{
-						if(rpnid[e->type&0x0F]==0)
-							this->pool.push_back(new MidiVisualEvent{e->time,e->time,rpnval[e->type&0x0F],e->type&0x0Fu,995});
-						rpnval[e->type&0x0F]=~0u;
-					}
-				break;
-				case 0xE0:
-					this->pool.push_back(new MidiVisualEvent{e->time,e->time,(e->p1|(e->p2<<7))&0x3FFFu,e->type&0x0Fu,994});
-				break;
-				case 0xF0:
-					if(e->type==0xFF&&e->p1==0x58)
-					{
-						this->tspool.push_back(std::make_pair(e->time,(e->str[0]<<24)|(e->str[1]<<16)));
-						this->pool.push_back(new MidiVisualEvent{e->time,e->time,(e->str[0]&0xffu)<<8|(e->str[1]&0xffu),0,998});
-					}
-					else if(e->type==0xFF&&e->p1==0x59)
-						this->pool.push_back(new MidiVisualEvent{e->time,e->time,(e->str[0]&0xffu)<<8|(e->str[1]&0xffu),0,997});
-					else if(e->type==0xFF&&e->p1==0x51)
-						this->pool.push_back(new MidiVisualEvent{e->time,e->time,(e->str[0]&0xffu)<<16|(e->str[1]&0xffu)<<8|(e->str[2]&0xffu),0,996});
-				break;
-			}
-		}
-	,nullptr);
-	heh=api->registerEventHandler(
-		[this](const void*,void*){
-			if(this->ctk>this->api->getCurrentTimeStamp()+this->api->getDivision()/3)
-				this->elb=0;
-			/*if(abs((int)this->ctk-(int)this->api->getCurrentTimeStamp())>this->api->getDivision()/4)
-				fprintf(stderr,"Visualization: out of sync! %u vs %u ad: %u\n",this->ctk,this->api->getCurrentTimeStamp());*/
-			this->ctk=this->api->getCurrentTimeStamp();
-			this->lstk=this->ctk;
-			this->lst=std::chrono::steady_clock::now();
-		}
-	,nullptr);
-	hfrf=api->registerFileReadFinishHook(
-		[this](const void*,void*){
-			memset(rpnval,0xFF,sizeof(rpnval));
-			memset(rpnid,0xFF,sizeof(rpnid));
-			std::sort(this->tspool.begin(),this->tspool.end());
-			for(uint32_t tk=0,n=4,s=0;tk<=this->api->getMaxTick();){
-				while(tk<(s>=this->tspool.size()?this->api->getMaxTick():this->tspool[s].first)){
-					this->pool.push_back(new MidiVisualEvent{tk,tk,0,0,999});
-					tk+=n*this->api->getDivision();
-				}
-				tk=(s>=this->tspool.size()?this->api->getMaxTick():this->tspool[s].first);
-				if(tk==this->api->getMaxTick()){
-					this->pool.push_back(new MidiVisualEvent{tk,tk,0,0,999});
-					++tk;break;
-				}
-				else n=this->tspool[s++].second>>24;
-			}
-			std::sort(this->pool.begin(),this->pool.end(),cmp);
-		}
-	,nullptr);
-	api->registerOptionBool("Visualization-Appearance","Show Piano","Visualization/showpiano",true);
-	api->registerOptionBool("Visualization-Appearance","3D Notes","Visualization/3dnotes",true);
-	api->registerOptionBool("Visualization-Appearance","Arrange channels on a stair","Visualization/stairpiano",true);
-	api->registerOptionBool("Visualization-Appearance","Show channel labels","Visualization/showlabel",true);
-	api->registerOptionBool("Visualization-Appearance","Show Particles","Visualization/showparticle",false);
-	api->registerOptionBool("Visualization-Appearance","Horizontal Visualization","Visualization/horizontal",false);
-	api->registerOptionBool("Visualization-Appearance","2D Visualization","Visualization/flat",false);
-	api->registerOptionBool("Visualization-Appearance","Show Measure Indicator","Visualization/showmeasure",true);
-	api->registerOptionBool("Visualization-Appearance","Use spectrum instead of piano roll","Visualization/usespectrum",false);
-	api->registerOptionBool("Visualization-Video","Enable VSync","Visualization/vsync",true);
-	api->registerOptionBool("Visualization-Video","Save Viewport","Visualization/savevp",true);
-	api->registerOptionInt("Visualization-Video","Window Width","Visualization/wwidth",320,3200,800);
-	api->registerOptionInt("Visualization-Video","Window Height","Visualization/wheight",320,3200,600);
-	api->registerOptionInt("Visualization-Video","Target FPS","Visualization/tfps",5,1000,60);
-	api->registerOptionInt("Visualization-Video","Supersampling","Visualization/supersampling",1,16,0);
-	api->registerOptionInt("Visualization-Video","Multisampling","Visualization/multisampling",0,16,0);
-	api->registerOptionInt("Visualization-Video","FOV","Visualization/fov",30,180,60);
-	std::vector<std::string> tv;tv.push_back("Bottom left");tv.push_back("Bottom right");tv.push_back("Top left");tv.push_back("Top right");tv.push_back("Hidden");
-	api->registerOptionEnumInt("Visualization-Video","OSD Position","Visualization/osdpos",tv,0);
-	api->registerOptionInt("Visualization-Video","Font Size","Visualization/fontsize",6,180,16);
-	api->registerOptionString("Visualization-Video","Custom Sans Font","Visualization/font1","",true);
-	api->registerOptionString("Visualization-Video","Custom Monospace Font","Visualization/font2","",true);
-	api->registerOptionInt("Visualization-Appearance","View distance","Visualization/viewdist",20,1000,100);
-	api->registerOptionInt("Visualization-Appearance","Note stretch","Visualization/notestretch",20,500,100);
-	api->registerOptionInt("Visualization-Appearance","Minimum note length","Visualization/minnotelen",20,500,100);
-	api->registerOptionUint("Visualization-Appearance","Chequer board tint (AARRGGBB)","Visualization/chkrtint",0,0xFFFFFFFF,0xFF999999);
-	api->registerOptionString("Visualization-Appearance","Background Image","Visualization/background","",true);
-	api->registerOptionDouble("","","Visualization/px",-999999999,999999999,-1e9);
-	api->registerOptionDouble("","","Visualization/py",-999999999,999999999,-1e9);
-	api->registerOptionDouble("","","Visualization/pz",-999999999,999999999,-1e9);
-	api->registerOptionDouble("","","Visualization/rx",-999999999,999999999,-1e9);
-	api->registerOptionDouble("","","Visualization/ry",-999999999,999999999,-1e9);
-	api->registerOptionDouble("","","Visualization/rz",-999999999,999999999,-1e9);
-	for(int i=0;i<16;++i)
-	{
-		api->registerOptionUint("","","Visualization/chActiveColor"+std::to_string(i),0,0xFFFFFFFF,accolors[i]);
-		api->registerOptionUint("","","Visualization/chInactiveColor"+std::to_string(i),0,0xFFFFFFFF,iccolors[i]);
-	}
-	wwidth=api->getOptionInt("Visualization/wwidth");
-	wheight=api->getOptionInt("Visualization/wheight");
-	wsupersample=api->getOptionInt("Visualization/supersampling");
-	wmultisample=api->getOptionInt("Visualization/multisampling");
-	fov=api->getOptionInt("Visualization/fov");
-	noteappearance=api->getOptionBool("Visualization/3dnotes");
-	showpiano=api->getOptionBool("Visualization/showpiano");
-	stairpiano=api->getOptionBool("Visualization/stairpiano");
-	showlabel=api->getOptionBool("Visualization/showlabel");
-	showparticle=api->getOptionBool("Visualization/showparticle");
-	horizontal=api->getOptionBool("Visualization/horizontal");
-	flat=api->getOptionBool("Visualization/flat");
-	savevp=api->getOptionBool("Visualization/savevp");
-	vsync=api->getOptionBool("Visualization/vsync");
-	tfps=api->getOptionInt("Visualization/tfps");
-	osdpos=api->getOptionEnumInt("Visualization/osdpos");
-	fontsize=api->getOptionInt("Visualization/fontsize");
-	viewdist=api->getOptionInt("Visualization/viewdist");
-	notestretch=api->getOptionInt("Visualization/notestretch");
-	minnotelength=api->getOptionInt("Visualization/minnotelen");
-	chkrtint=api->getOptionUint("Visualization/chkrtint");
-	for(int i=0;i<16;++i)
-	{
-		accolors[i]=api->getOptionUint("Visualization/chActiveColor"+std::to_string(i));
-		iccolors[i]=api->getOptionUint("Visualization/chInactiveColor"+std::to_string(i));
-	}
-	if(savevp)
-	{
-		pos[0]=api->getOptionDouble("Visualization/px");
-		pos[1]=api->getOptionDouble("Visualization/py");
-		pos[2]=api->getOptionDouble("Visualization/pz");
-		rot[0]=api->getOptionDouble("Visualization/rx");
-		rot[1]=api->getOptionDouble("Visualization/ry");
-		rot[2]=api->getOptionDouble("Visualization/rz");
-	}
-	memset(pss,0,sizeof(pss));
+    h = new CMidiVisualHandler(this);
+    closeh = new CloseHandler(this);
+    rendererTh = nullptr;
+    playing = false;
+    memset(rpnid, 0xFF, sizeof(rpnid));
+    memset(rpnval, 0xFF, sizeof(rpnval));
+    memset(spectra, 0, sizeof(spectra));
+    memset(spectrar, 0, sizeof(spectrar));
+    api->registerFunctionality(this, "Visualization", "Visualization", api->isDarkTheme() ? ":/img/visualization_i.svg" : ":/img/visualization.svg", 0, true);
+    uihb = api->registerUIHook("main.start", [this](const void *, void *)
+    {
+        this->start();
+    }, nullptr);
+    uihs = api->registerUIHook("main.stop", [this](const void *, void *)
+    {
+        this->stop();
+    }, nullptr);
+    uihp = api->registerUIHook("main.pause", [this](const void *, void *)
+    {
+        this->pause();
+    }, nullptr);
+    uihr = api->registerUIHook("main.reset", [this](const void *, void *)
+    {
+        this->reset();
+    }, nullptr);
+    uihk = api->registerUIHook("main.seek", [this](const void *, void *)
+    {
+        cts = api->getTimeSig();
+        cks = api->getKeySig();
+        ctp = api->getRawTempo();
+        for (int i = 0; i < 16; ++i)
+            api->getPitchBendRaw(i, &cpw[i], &cpbr[i]);
+    }, nullptr);
+    herh = api->registerEventReadHandler(
+            [this](const void *ee, void *)
+    {
+        const SEvent *e = (const SEvent *)ee;
+        switch (e->type & 0xF0)
+        {
+            case 0x80:
+                this->pushNoteOff(e->time, e->type & 0x0F, e->p1);
+                break;
+            case 0x90:
+                if (e->p2)
+                    this->pushNoteOn(e->time, e->type & 0x0F, e->p1, e->p2);
+                else
+                    this->pushNoteOff(e->time, e->type & 0x0F, e->p1);
+                break;
+            case 0xB0:
+                if (e->p1 == 100)
+                    rpnid[e->type & 0x0F] = e->p2;
+                if (e->p1 == 6)
+                    rpnval[e->type & 0x0F] = e->p2;
+                if (~rpnid[e->type & 0x0F] && ~rpnval[e->type & 0x0F])
+                {
+                    if (rpnid[e->type & 0x0F] == 0)
+                        this->pool.push_back(new MidiVisualEvent{e->time, e->time, rpnval[e->type & 0x0F], e->type & 0x0Fu, 995});
+                    rpnval[e->type & 0x0F] = ~0u;
+                }
+                break;
+            case 0xE0:
+                this->pool.push_back(new MidiVisualEvent{e->time, e->time, (e->p1 | (e->p2 << 7)) & 0x3FFFu, e->type & 0x0Fu, 994});
+                break;
+            case 0xF0:
+                if (e->type == 0xFF && e->p1 == 0x58)
+                {
+                    this->tspool.push_back(std::make_pair(e->time, (e->str[0] << 24) | (e->str[1] << 16)));
+                    this->pool.push_back(new MidiVisualEvent{e->time, e->time, (e->str[0] & 0xffu) << 8 | (e->str[1] & 0xffu), 0, 998});
+                }
+                else if (e->type == 0xFF && e->p1 == 0x59)
+                    this->pool.push_back(new MidiVisualEvent{e->time, e->time, (e->str[0] & 0xffu) << 8 | (e->str[1] & 0xffu), 0, 997});
+                else if (e->type == 0xFF && e->p1 == 0x51)
+                    this->pool.push_back(new MidiVisualEvent{e->time, e->time, (e->str[0] & 0xffu) << 16 | (e->str[1] & 0xffu) << 8 | (e->str[2] & 0xffu), 0, 996});
+                break;
+        }
+    }
+    , nullptr);
+    heh = api->registerEventHandler(
+            [this](const void *, void *)
+    {
+        if (this->ctk > this->api->getCurrentTimeStamp() + this->api->getDivision() / 3)
+            this->elb = 0;
+        /*if(abs((int)this->ctk-(int)this->api->getCurrentTimeStamp())>this->api->getDivision()/4)
+            fprintf(stderr,"Visualization: out of sync! %u vs %u ad: %u\n",this->ctk,this->api->getCurrentTimeStamp());*/
+        this->ctk = this->api->getCurrentTimeStamp();
+        this->lstk = this->ctk;
+        this->lst = std::chrono::steady_clock::now();
+    }
+    , nullptr);
+    hfrf = api->registerFileReadFinishHook(
+            [this](const void *, void *)
+    {
+        memset(rpnval, 0xFF, sizeof(rpnval));
+        memset(rpnid, 0xFF, sizeof(rpnid));
+        std::sort(this->tspool.begin(), this->tspool.end());
+        for (uint32_t tk = 0, n = 4, s = 0; tk <= this->api->getMaxTick();)
+        {
+            while (tk < (s >= this->tspool.size() ? this->api->getMaxTick() : this->tspool[s].first))
+            {
+                this->pool.push_back(new MidiVisualEvent{tk, tk, 0, 0, 999});
+                tk += n * this->api->getDivision();
+            }
+            tk = (s >= this->tspool.size() ? this->api->getMaxTick() : this->tspool[s].first);
+            if (tk == this->api->getMaxTick())
+            {
+                this->pool.push_back(new MidiVisualEvent{tk, tk, 0, 0, 999});
+                ++tk;
+                break;
+            }
+            else n = this->tspool[s++].second >> 24;
+        }
+        std::sort(this->pool.begin(), this->pool.end(), cmp);
+    }
+    , nullptr);
+    api->registerOptionBool("Visualization-Appearance", "Show Piano", "Visualization/showpiano", true);
+    api->registerOptionBool("Visualization-Appearance", "3D Notes", "Visualization/3dnotes", true);
+    api->registerOptionBool("Visualization-Appearance", "Arrange channels on a stair", "Visualization/stairpiano", true);
+    api->registerOptionBool("Visualization-Appearance", "Show channel labels", "Visualization/showlabel", true);
+    api->registerOptionBool("Visualization-Appearance", "Show Particles", "Visualization/showparticle", false);
+    api->registerOptionBool("Visualization-Appearance", "Horizontal Visualization", "Visualization/horizontal", false);
+    api->registerOptionBool("Visualization-Appearance", "2D Visualization", "Visualization/flat", false);
+    api->registerOptionBool("Visualization-Appearance", "Show Measure Indicator", "Visualization/showmeasure", true);
+    api->registerOptionBool("Visualization-Appearance", "Use spectrum instead of piano roll", "Visualization/usespectrum", false);
+    api->registerOptionBool("Visualization-Video", "Enable VSync", "Visualization/vsync", true);
+    api->registerOptionBool("Visualization-Video", "Save Viewport", "Visualization/savevp", true);
+    api->registerOptionInt("Visualization-Video", "Window Width", "Visualization/wwidth", 320, 3200, 800);
+    api->registerOptionInt("Visualization-Video", "Window Height", "Visualization/wheight", 320, 3200, 600);
+    api->registerOptionInt("Visualization-Video", "Target FPS", "Visualization/tfps", 5, 1000, 60);
+    api->registerOptionInt("Visualization-Video", "Supersampling", "Visualization/supersampling", 1, 16, 0);
+    api->registerOptionInt("Visualization-Video", "Multisampling", "Visualization/multisampling", 0, 16, 0);
+    api->registerOptionInt("Visualization-Video", "FOV", "Visualization/fov", 30, 180, 60);
+    std::vector<std::string> tv;
+    tv.push_back("Bottom left");
+    tv.push_back("Bottom right");
+    tv.push_back("Top left");
+    tv.push_back("Top right");
+    tv.push_back("Hidden");
+    api->registerOptionEnumInt("Visualization-Video", "OSD Position", "Visualization/osdpos", tv, 0);
+    api->registerOptionInt("Visualization-Video", "Font Size", "Visualization/fontsize", 6, 180, 16);
+    api->registerOptionString("Visualization-Video", "Custom Sans Font", "Visualization/font1", "", true);
+    api->registerOptionString("Visualization-Video", "Custom Monospace Font", "Visualization/font2", "", true);
+    api->registerOptionInt("Visualization-Appearance", "View distance", "Visualization/viewdist", 20, 1000, 100);
+    api->registerOptionInt("Visualization-Appearance", "Note stretch", "Visualization/notestretch", 20, 500, 100);
+    api->registerOptionInt("Visualization-Appearance", "Minimum note length", "Visualization/minnotelen", 20, 500, 100);
+    api->registerOptionUint("Visualization-Appearance", "Chequer board tint (AARRGGBB)", "Visualization/chkrtint", 0, 0xFFFFFFFF, 0xFF999999);
+    api->registerOptionString("Visualization-Appearance", "Background Image", "Visualization/background", "", true);
+    api->registerOptionDouble("", "", "Visualization/px", -999999999, 999999999, -1e9);
+    api->registerOptionDouble("", "", "Visualization/py", -999999999, 999999999, -1e9);
+    api->registerOptionDouble("", "", "Visualization/pz", -999999999, 999999999, -1e9);
+    api->registerOptionDouble("", "", "Visualization/rx", -999999999, 999999999, -1e9);
+    api->registerOptionDouble("", "", "Visualization/ry", -999999999, 999999999, -1e9);
+    api->registerOptionDouble("", "", "Visualization/rz", -999999999, 999999999, -1e9);
+    for (int i = 0; i < 16; ++i)
+    {
+        api->registerOptionUint("", "", "Visualization/chActiveColor" + std::to_string(i), 0, 0xFFFFFFFF, accolors[i]);
+        api->registerOptionUint("", "", "Visualization/chInactiveColor" + std::to_string(i), 0, 0xFFFFFFFF, iccolors[i]);
+    }
+    wwidth = api->getOptionInt("Visualization/wwidth");
+    wheight = api->getOptionInt("Visualization/wheight");
+    wsupersample = api->getOptionInt("Visualization/supersampling");
+    wmultisample = api->getOptionInt("Visualization/multisampling");
+    fov = api->getOptionInt("Visualization/fov");
+    noteappearance = api->getOptionBool("Visualization/3dnotes");
+    showpiano = api->getOptionBool("Visualization/showpiano");
+    stairpiano = api->getOptionBool("Visualization/stairpiano");
+    showlabel = api->getOptionBool("Visualization/showlabel");
+    showparticle = api->getOptionBool("Visualization/showparticle");
+    horizontal = api->getOptionBool("Visualization/horizontal");
+    flat = api->getOptionBool("Visualization/flat");
+    savevp = api->getOptionBool("Visualization/savevp");
+    vsync = api->getOptionBool("Visualization/vsync");
+    tfps = api->getOptionInt("Visualization/tfps");
+    osdpos = api->getOptionEnumInt("Visualization/osdpos");
+    fontsize = api->getOptionInt("Visualization/fontsize");
+    viewdist = api->getOptionInt("Visualization/viewdist");
+    notestretch = api->getOptionInt("Visualization/notestretch");
+    minnotelength = api->getOptionInt("Visualization/minnotelen");
+    chkrtint = api->getOptionUint("Visualization/chkrtint");
+    for (int i = 0; i < 16; ++i)
+    {
+        accolors[i] = api->getOptionUint("Visualization/chActiveColor" + std::to_string(i));
+        iccolors[i] = api->getOptionUint("Visualization/chInactiveColor" + std::to_string(i));
+    }
+    if (savevp)
+    {
+        pos[0] = api->getOptionDouble("Visualization/px");
+        pos[1] = api->getOptionDouble("Visualization/py");
+        pos[2] = api->getOptionDouble("Visualization/pz");
+        rot[0] = api->getOptionDouble("Visualization/rx");
+        rot[1] = api->getOptionDouble("Visualization/ry");
+        rot[2] = api->getOptionDouble("Visualization/rz");
+    }
+    memset(pss, 0, sizeof(pss));
 }
 void qmpVisualization::deinit()
 {
-	if(!api)return;close();tspool.clear();
-	for(unsigned i=0;i<pool.size();++i)delete pool[i];pool.clear();
-	api->unregisterUIHook("main.start",uihb);
-	api->unregisterUIHook("main.stop",uihs);
-	api->unregisterUIHook("main.pause",uihp);
-	api->unregisterUIHook("main.reset",uihr);
-	api->unregisterFunctionality("Visualization");
-	api->unregisterEventReadHandler(herh);
-	api->unregisterEventHandler(heh);
-	api->unregisterFileReadFinishHook(hfrf);
-	delete h;delete closeh;
+    if (!api)
+        return;
+    close();
+    tspool.clear();
+    for (unsigned i = 0; i < pool.size(); ++i)
+        delete pool[i];
+    pool.clear();
+    api->unregisterUIHook("main.start", uihb);
+    api->unregisterUIHook("main.stop", uihs);
+    api->unregisterUIHook("main.pause", uihp);
+    api->unregisterUIHook("main.reset", uihr);
+    api->unregisterFunctionality("Visualization");
+    api->unregisterEventReadHandler(herh);
+    api->unregisterEventHandler(heh);
+    api->unregisterFileReadFinishHook(hfrf);
+    delete h;
+    delete closeh;
+}
+const char *qmpVisualization::pluginGetName()
+{
+    return "QMidiPlayer Default Visualization Plugin";
+}
+const char *qmpVisualization::pluginGetVersion()
+{
+    return PLUGIN_VERSION;
 }
-const char* qmpVisualization::pluginGetName()
-{return "QMidiPlayer Default Visualization Plugin";}
-const char* qmpVisualization::pluginGetVersion()
-{return PLUGIN_VERSION;}
 
 qmpVisualization *qmpVisualization::instance()
-{return inst;}
+{
+    return inst;
+}
 
-void qmpVisualization::pushNoteOn(uint32_t tc,uint32_t ch,uint32_t key,uint32_t vel)
+void qmpVisualization::pushNoteOn(uint32_t tc, uint32_t ch, uint32_t key, uint32_t vel)
 {
-	pendingt[ch][key].push(tc);
-	pendingv[ch][key].push(vel);
+    pendingt[ch][key].push(tc);
+    pendingv[ch][key].push(vel);
 }
-void qmpVisualization::pushNoteOff(uint32_t tc,uint32_t ch,uint32_t key)
+void qmpVisualization::pushNoteOff(uint32_t tc, uint32_t ch, uint32_t key)
 {
-	if(pendingt[ch][key].size()<1)return;
-	MidiVisualEvent *ne=new MidiVisualEvent();
-	ne->tcs=pendingt[ch][key].top();pendingt[ch][key].pop();
-	ne->tce=tc;ne->ch=ch;ne->key=key;
-	ne->vel=pendingv[ch][key].top();pendingv[ch][key].pop();
-	pool.push_back(ne);
+    if (pendingt[ch][key].size() < 1)
+        return;
+    MidiVisualEvent *ne = new MidiVisualEvent();
+    ne->tcs = pendingt[ch][key].top();
+    pendingt[ch][key].pop();
+    ne->tce = tc;
+    ne->ch = ch;
+    ne->key = key;
+    ne->vel = pendingv[ch][key].top();
+    pendingv[ch][key].pop();
+    pool.push_back(ne);
 }
diff --git a/visualization/qmpvisualization.hpp b/visualization/qmpvisualization.hpp
index 8a8d832..c0bc067 100644
--- a/visualization/qmpvisualization.hpp
+++ b/visualization/qmpvisualization.hpp
@@ -15,105 +15,121 @@
 class qmpVisualization;
 struct MidiVisualEvent
 {
-	uint32_t tcs,tce;
-	uint32_t key,vel;
-	uint32_t ch;
+    uint32_t tcs, tce;
+    uint32_t key, vel;
+    uint32_t ch;
 };
-class qmpVisualization:public qmpPluginIntf,public qmpFuncBaseIntf
+class qmpVisualization: public qmpPluginIntf, public qmpFuncBaseIntf
 {
-	friend class CloseHandler;
-	private:
-		qmpPluginAPI* api;
-		std::thread* rendererTh;
-		std::vector<MidiVisualEvent*>pool;
-		smHandler *h,*closeh;
-		std::stack<uint32_t> pendingt[16][128],pendingv[16][128];
-		SMELT *sm;
-		SMTRG tdscn,tdparticles;
-		SMTEX chequer,bgtex,particletex,pianotex;
-		smTTFont font,font2,fonthdpi;
-		qmpVirtualPiano3D* p3d[16];
-		smEntity3DBuffer* nebuf;
-		smParticleSystem* pss[16][128];
-		smPSEmissionPositionGenerator* psepg;
-		float pos[3],rot[3],lastx,lasty;
-		uint32_t ctc,ctk,elb,lstk,cfr;
-		uint32_t cts,cks,ctp,cpbr[16],cpw[16];
-		uint32_t rpnid[16],rpnval[16];
-		std::chrono::steady_clock::time_point lst;
-		double etps;
-		bool shouldclose,playing,debug;
-		bool rendermode,hidewindow;
-		int herh,heh,hfrf;
-		int uihb,uihs,uihp,uihr,uihk;
-		void(*framecb)(void*,size_t,uint32_t,uint32_t);
-		DWORD* fbcont;
-		std::vector<std::pair<uint32_t,uint32_t>>tspool;
-		int traveld[16][128];bool notestatus[16][128],lastnotestatus[16][128];
-		int spectra[16][128],spectrar[16][128];
-		void drawCube(smvec3d a,smvec3d b,DWORD col,SMTEX tex,int faces=63);
-		void showThread();
-		void pushNoteOn(uint32_t tc,uint32_t ch,uint32_t key,uint32_t vel);
-		void pushNoteOff(uint32_t tc,uint32_t ch,uint32_t key);
-		void updateVisualization3D();
-		void updateVisualization2D();
+    friend class CloseHandler;
+private:
+    qmpPluginAPI *api;
+    std::thread *rendererTh;
+    std::vector<MidiVisualEvent *>pool;
+    smHandler *h, *closeh;
+    std::stack<uint32_t> pendingt[16][128], pendingv[16][128];
+    SMELT *sm;
+    SMTRG tdscn, tdparticles;
+    SMTEX chequer, bgtex, particletex, pianotex;
+    smTTFont font, font2, fonthdpi;
+    qmpVirtualPiano3D *p3d[16];
+    smEntity3DBuffer *nebuf;
+    smParticleSystem *pss[16][128];
+    smPSEmissionPositionGenerator *psepg;
+    float pos[3], rot[3], lastx, lasty;
+    uint32_t ctc, ctk, elb, lstk, cfr;
+    uint32_t cts, cks, ctp, cpbr[16], cpw[16];
+    uint32_t rpnid[16], rpnval[16];
+    std::chrono::steady_clock::time_point lst;
+    double etps;
+    bool shouldclose, playing, debug;
+    bool rendermode, hidewindow;
+    int herh, heh, hfrf;
+    int uihb, uihs, uihp, uihr, uihk;
+    void(*framecb)(void *, size_t, uint32_t, uint32_t);
+    DWORD *fbcont;
+    std::vector<std::pair<uint32_t, uint32_t>>tspool;
+    int traveld[16][128];
+    bool notestatus[16][128], lastnotestatus[16][128];
+    int spectra[16][128], spectrar[16][128];
+    void drawCube(smvec3d a, smvec3d b, DWORD col, SMTEX tex, int faces = 63);
+    void showThread();
+    void pushNoteOn(uint32_t tc, uint32_t ch, uint32_t key, uint32_t vel);
+    void pushNoteOff(uint32_t tc, uint32_t ch, uint32_t key);
+    void updateVisualization3D();
+    void updateVisualization2D();
 
-		static qmpVisualization* inst;
-	public:
-		qmpVisualization(qmpPluginAPI* _api);
-		~qmpVisualization();
-		void show();
-		void close();
-		bool update();
-		void start();
-		void stop();
-		void pause();
-		void reset();
-		void switchToRenderMode(void(*frameCallback)(void*,size_t,uint32_t,uint32_t),bool _hidewindow);
+    static qmpVisualization *inst;
+public:
+    qmpVisualization(qmpPluginAPI *_api);
+    ~qmpVisualization();
+    void show();
+    void close();
+    bool update();
+    void start();
+    void stop();
+    void pause();
+    void reset();
+    void switchToRenderMode(void(*frameCallback)(void *, size_t, uint32_t, uint32_t), bool _hidewindow);
 
-		void init();
-		void deinit();
-		const char* pluginGetName();
-		const char* pluginGetVersion();
+    void init();
+    void deinit();
+    const char *pluginGetName();
+    const char *pluginGetVersion();
 
-		static qmpVisualization* instance();
+    static qmpVisualization *instance();
 };
 
-class CMidiVisualHandler:public smHandler
+class CMidiVisualHandler: public smHandler
 {
-	private:
-		qmpVisualization *p;
-	public:
-		CMidiVisualHandler(qmpVisualization* par){p=par;}
-		bool handlerFunc(){return p->update();}
+private:
+    qmpVisualization *p;
+public:
+    CMidiVisualHandler(qmpVisualization *par)
+    {
+        p = par;
+    }
+    bool handlerFunc()
+    {
+        return p->update();
+    }
 };
 
-class CloseHandler:public smHandler
+class CloseHandler: public smHandler
 {
-	private:
-		qmpVisualization *p;
-	public:
-		CloseHandler(qmpVisualization* par){p=par;}
-	public:
-		bool handlerFunc()
-		{
-			std::thread ([this]{
-			p->api->setFuncState("Visualization",false);
-			p->close();}).detach();
-			return false;
-		}
+private:
+    qmpVisualization *p;
+public:
+    CloseHandler(qmpVisualization *par)
+    {
+        p = par;
+    }
+public:
+    bool handlerFunc()
+    {
+        std::thread([this]
+        {
+            p->api->setFuncState("Visualization", false);
+            p->close();
+        }).detach();
+        return false;
+    }
 };
 
-extern "C"{
-	EXPORTSYM qmpPluginIntf* qmpPluginGetInterface(qmpPluginAPI* api)
-	{return new qmpVisualization(api);}
-	EXPORTSYM const char* qmpPluginGetAPIRev()
-	{return QMP_PLUGIN_API_REV;}
-	EXPORTSYM void switchToRenderMode(void(*frameCallback)(void*,size_t,uint32_t,uint32_t),bool hidewindow)
-	{
-		if(qmpVisualization::instance())
-			qmpVisualization::instance()->switchToRenderMode(frameCallback,hidewindow);
-	}
+extern "C" {
+    EXPORTSYM qmpPluginIntf *qmpPluginGetInterface(qmpPluginAPI *api)
+    {
+        return new qmpVisualization(api);
+    }
+    EXPORTSYM const char *qmpPluginGetAPIRev()
+    {
+        return QMP_PLUGIN_API_REV;
+    }
+    EXPORTSYM void switchToRenderMode(void(*frameCallback)(void *, size_t, uint32_t, uint32_t), bool hidewindow)
+    {
+        if (qmpVisualization::instance())
+            qmpVisualization::instance()->switchToRenderMode(frameCallback, hidewindow);
+    }
 }
 
 #endif // QMPVISUALIZATION_H
diff --git a/visualization/renderer/main.cpp b/visualization/renderer/main.cpp
index c651c54..7f25578 100644
--- a/visualization/renderer/main.cpp
+++ b/visualization/renderer/main.cpp
@@ -4,44 +4,46 @@
 #include "qmpvisrendercore.hpp"
 #include "qmpsettingsro.hpp"
 
-int main(int argc,char **argv)
+int main(int argc, char **argv)
 {
-	QCoreApplication::setApplicationName("qmpvisrender");
-	QCoreApplication::setApplicationVersion("0.0.0");
-	QCoreApplication a(argc,argv);
-	QCommandLineParser clp;
-	clp.setApplicationDescription("Renderer a visualization of a midi file.");
-	clp.addHelpOption();
-	clp.addVersionOption();
-	clp.addOption({{"f","output-file"},"File name of the output file.","filename","output.mp4"});
-	clp.addOption({
-		"receiver",
-		"Specify a program and its arguments to process the rendered frames. Supports parameter substitution. See documentation for details.",
-		"command",
-		"ffmpeg %i -vf vflip -pix_fmt yuv420p -c:v libx264 -preset slow -crf 22 %o"
-	});
-	clp.addOption({
-		{"e","receiver-execution"},
-		"Execution mode of the receiver command. Valid options are 'one-shot' and 'per-frame'",
-		"mode",
-		"one-shot"
-	});
-	clp.addOption({{"s","show-window"},"Do not hide the visualization window."});
-	clp.addOption({{"c","config"},"Load options from the configuration file.","qmprc file"});
-	clp.addOption({{"o","option"},"Set option for the visualization module.","key-value pair"});
-	clp.addOption({"list-options","Show a list of recognized options and quit."});
-	clp.addPositionalArgument("file","MIDI file to render");
-	clp.process(a.arguments());
-	qmpVisRenderCore core(&clp);
-	if(clp.positionalArguments().empty()&&!clp.isSet("list-options"))
-		clp.showHelp(1);
-	core.loadSettings();
-	if(!core.loadVisualizationLibrary())
-		return 1;
-	if(clp.positionalArguments().size())
-		core.setMIDIFile(clp.positionalArguments().front().toStdString().c_str());
-	core.startRender();
-	int retval=a.exec();
-	core.unloadVisualizationLibrary();
-	return retval;
+    QCoreApplication::setApplicationName("qmpvisrender");
+    QCoreApplication::setApplicationVersion("0.0.0");
+    QCoreApplication a(argc, argv);
+    QCommandLineParser clp;
+    clp.setApplicationDescription("Renderer a visualization of a midi file.");
+    clp.addHelpOption();
+    clp.addVersionOption();
+    clp.addOption({{"f", "output-file"}, "File name of the output file.", "filename", "output.mp4"});
+    clp.addOption(
+    {
+        "receiver",
+        "Specify a program and its arguments to process the rendered frames. Supports parameter substitution. See documentation for details.",
+        "command",
+        "ffmpeg %i -vf vflip -pix_fmt yuv420p -c:v libx264 -preset slow -crf 22 %o"
+    });
+    clp.addOption(
+    {
+        {"e", "receiver-execution"},
+        "Execution mode of the receiver command. Valid options are 'one-shot' and 'per-frame'",
+        "mode",
+        "one-shot"
+    });
+    clp.addOption({{"s", "show-window"}, "Do not hide the visualization window."});
+    clp.addOption({{"c", "config"}, "Load options from the configuration file.", "qmprc file"});
+    clp.addOption({{"o", "option"}, "Set option for the visualization module.", "key-value pair"});
+    clp.addOption({"list-options", "Show a list of recognized options and quit."});
+    clp.addPositionalArgument("file", "MIDI file to render");
+    clp.process(a.arguments());
+    qmpVisRenderCore core(&clp);
+    if (clp.positionalArguments().empty() && !clp.isSet("list-options"))
+        clp.showHelp(1);
+    core.loadSettings();
+    if (!core.loadVisualizationLibrary())
+        return 1;
+    if (clp.positionalArguments().size())
+        core.setMIDIFile(clp.positionalArguments().front().toStdString().c_str());
+    core.startRender();
+    int retval = a.exec();
+    core.unloadVisualizationLibrary();
+    return retval;
 }
diff --git a/visualization/renderer/qmppluginapistub.cpp b/visualization/renderer/qmppluginapistub.cpp
index 1be4880..b84a2b6 100644
--- a/visualization/renderer/qmppluginapistub.cpp
+++ b/visualization/renderer/qmppluginapistub.cpp
@@ -6,197 +6,245 @@
 #include <QTextCodec>
 
 qmpPluginAPIStub::qmpPluginAPIStub(qmpVisRenderCore *_core):
-	core(_core)
+    core(_core)
 {
 }
 
 qmpPluginAPIStub::~qmpPluginAPIStub()
 {
-	core=nullptr;
+    core = nullptr;
 }
 
 uint32_t qmpPluginAPIStub::getDivision()
 {
-	return core->player->getDivision();
+    return core->player->getDivision();
+}
+uint32_t qmpPluginAPIStub::getRawTempo()
+{
+    return 0;
+}
+double qmpPluginAPIStub::getRealTempo()
+{
+    return 0;
+}
+uint32_t qmpPluginAPIStub::getTimeSig()
+{
+    return 0;
+}
+int qmpPluginAPIStub::getKeySig()
+{
+    return 0;
+}
+uint32_t qmpPluginAPIStub::getNoteCount()
+{
+    return 0;
 }
-uint32_t qmpPluginAPIStub::getRawTempo(){return 0;}
-double qmpPluginAPIStub::getRealTempo(){return 0;}
-uint32_t qmpPluginAPIStub::getTimeSig(){return 0;}
-int qmpPluginAPIStub::getKeySig(){return 0;}
-uint32_t qmpPluginAPIStub::getNoteCount(){return 0;}
 uint32_t qmpPluginAPIStub::getMaxTick()
 {
-	return core->player->getMaxTick();
-}
-uint32_t qmpPluginAPIStub::getCurrentPolyphone(){return 0;}
-uint32_t qmpPluginAPIStub::getMaxPolyphone(){return 0;}
-uint32_t qmpPluginAPIStub::getCurrentTimeStamp(){return 0;}
-uint32_t qmpPluginAPIStub::getCurrentPlaybackPercentage(){return 0;}
-int qmpPluginAPIStub::getChannelCC(int ch, int cc){return 0;}
-int qmpPluginAPIStub::getChannelPreset(int ch){return 0;}
-void qmpPluginAPIStub::playerSeek(uint32_t percentage){}
-double qmpPluginAPIStub::getPitchBend(int ch){return 0;}
-void qmpPluginAPIStub::getPitchBendRaw(int ch,uint32_t *pb,uint32_t *pbr){}
-bool qmpPluginAPIStub::getChannelMask(int ch){return 0;}
+    return core->player->getMaxTick();
+}
+uint32_t qmpPluginAPIStub::getCurrentPolyphone()
+{
+    return 0;
+}
+uint32_t qmpPluginAPIStub::getMaxPolyphone()
+{
+    return 0;
+}
+uint32_t qmpPluginAPIStub::getCurrentTimeStamp()
+{
+    return 0;
+}
+uint32_t qmpPluginAPIStub::getCurrentPlaybackPercentage()
+{
+    return 0;
+}
+int qmpPluginAPIStub::getChannelCC(int ch, int cc)
+{
+    return 0;
+}
+int qmpPluginAPIStub::getChannelPreset(int ch)
+{
+    return 0;
+}
+void qmpPluginAPIStub::playerSeek(uint32_t percentage) {}
+double qmpPluginAPIStub::getPitchBend(int ch)
+{
+    return 0;
+}
+void qmpPluginAPIStub::getPitchBendRaw(int ch, uint32_t *pb, uint32_t *pbr) {}
+bool qmpPluginAPIStub::getChannelMask(int ch)
+{
+    return 0;
+}
 std::string qmpPluginAPIStub::getTitle()
 {
-	if(core->settings()->getOptionEnumIntOptName("Midi/TextEncoding")=="Unicode")
-		return std::string(core->player->getTitle());
-	return QTextCodec::codecForName(
-				core->settings()->getOptionEnumIntOptName("Midi/TextEncoding").c_str())->
-			toUnicode(core->player->getTitle()).toStdString();
+    if (core->settings()->getOptionEnumIntOptName("Midi/TextEncoding") == "Unicode")
+        return std::string(core->player->getTitle());
+    return QTextCodec::codecForName(
+            core->settings()->getOptionEnumIntOptName("Midi/TextEncoding").c_str())->
+        toUnicode(core->player->getTitle()).toStdString();
 }
 std::wstring qmpPluginAPIStub::getWTitle()
 {
-	if(core->settings()->getOptionEnumIntOptName("Midi/TextEncoding")=="Unicode")
-		return QString(core->player->getTitle()).toStdWString();
-	return QTextCodec::codecForName(
-				core->settings()->getOptionEnumIntOptName("Midi/TextEncoding").c_str())->
-			toUnicode(core->player->getTitle()).toStdWString();
-}
-std::string qmpPluginAPIStub::getChannelPresetString(int ch){return std::string();}
-bool qmpPluginAPIStub::isDarkTheme(){return false;}
-void *qmpPluginAPIStub::getMainWindow(){return nullptr;}
-void qmpPluginAPIStub::discardCurrentEvent(){}
-void qmpPluginAPIStub::commitEventChange(SEvent d){}
-void qmpPluginAPIStub::callEventReaderCB(SEvent d){}
-void qmpPluginAPIStub::setFuncState(std::string name,bool state){}
+    if (core->settings()->getOptionEnumIntOptName("Midi/TextEncoding") == "Unicode")
+        return QString(core->player->getTitle()).toStdWString();
+    return QTextCodec::codecForName(
+            core->settings()->getOptionEnumIntOptName("Midi/TextEncoding").c_str())->
+        toUnicode(core->player->getTitle()).toStdWString();
+}
+std::string qmpPluginAPIStub::getChannelPresetString(int ch)
+{
+    return std::string();
+}
+bool qmpPluginAPIStub::isDarkTheme()
+{
+    return false;
+}
+void *qmpPluginAPIStub::getMainWindow()
+{
+    return nullptr;
+}
+void qmpPluginAPIStub::discardCurrentEvent() {}
+void qmpPluginAPIStub::commitEventChange(SEvent d) {}
+void qmpPluginAPIStub::callEventReaderCB(SEvent d) {}
+void qmpPluginAPIStub::setFuncState(std::string name, bool state) {}
 void qmpPluginAPIStub::setFuncEnabled(std::string name, bool enable)
 {}
 void qmpPluginAPIStub::registerFunctionality(qmpFuncBaseIntf *i, std::string name, std::string desc, const char *icon, int iconlen, bool checkable)
 {
-	if(name=="Visualization")
-		core->vf=i;
+    if (name == "Visualization")
+        core->vf = i;
 }
 void qmpPluginAPIStub::unregisterFunctionality(std::string name)
 {
-	if(name=="Visualization")
-		core->vf=nullptr;
+    if (name == "Visualization")
+        core->vf = nullptr;
 }
 
-int qmpPluginAPIStub::registerUIHook(std::string e, ICallBack *cb, void *userdat){}
+int qmpPluginAPIStub::registerUIHook(std::string e, ICallBack *cb, void *userdat) {}
 int qmpPluginAPIStub::registerUIHook(std::string e, callback_t cb, void *userdat)
 {
-	if(e=="main.start")
-		core->startcb=cb;
-	if(e=="main.reset")
-		core->resetcb=cb;
-	return 0;
+    if (e == "main.start")
+        core->startcb = cb;
+    if (e == "main.reset")
+        core->resetcb = cb;
+    return 0;
 }
 void qmpPluginAPIStub::unregisterUIHook(std::string e, int hook)
 {
-	if(e=="main.start")
-		core->startcb=nullptr;
-	if(e=="main.reset")
-		core->resetcb=nullptr;
+    if (e == "main.start")
+        core->startcb = nullptr;
+    if (e == "main.reset")
+        core->resetcb = nullptr;
 }
 
-void qmpPluginAPIStub::registerMidiOutDevice(qmpMidiOutDevice *dev, std::string name){}
-void qmpPluginAPIStub::unregisterMidiOutDevice(std::string name){}
+void qmpPluginAPIStub::registerMidiOutDevice(qmpMidiOutDevice *dev, std::string name) {}
+void qmpPluginAPIStub::unregisterMidiOutDevice(std::string name) {}
 
-int qmpPluginAPIStub::registerEventReaderIntf(ICallBack *cb, void *userdata){}
-void qmpPluginAPIStub::unregisterEventReaderIntf(int intfhandle){}
-int qmpPluginAPIStub::registerEventHandlerIntf(ICallBack *cb, void *userdata){}
-void qmpPluginAPIStub::unregisterEventHandlerIntf(int intfhandle){}
-int qmpPluginAPIStub::registerFileReadFinishedHandlerIntf(ICallBack *cb, void *userdata){}
-void qmpPluginAPIStub::unregisterFileReadFinishedHandlerIntf(int intfhandle){}
+int qmpPluginAPIStub::registerEventReaderIntf(ICallBack *cb, void *userdata) {}
+void qmpPluginAPIStub::unregisterEventReaderIntf(int intfhandle) {}
+int qmpPluginAPIStub::registerEventHandlerIntf(ICallBack *cb, void *userdata) {}
+void qmpPluginAPIStub::unregisterEventHandlerIntf(int intfhandle) {}
+int qmpPluginAPIStub::registerFileReadFinishedHandlerIntf(ICallBack *cb, void *userdata) {}
+void qmpPluginAPIStub::unregisterFileReadFinishedHandlerIntf(int intfhandle) {}
 
-int qmpPluginAPIStub::registerEventHandler(callback_t cb, void *userdata, bool post){}
-void qmpPluginAPIStub::unregisterEventHandler(int id){}
+int qmpPluginAPIStub::registerEventHandler(callback_t cb, void *userdata, bool post) {}
+void qmpPluginAPIStub::unregisterEventHandler(int id) {}
 int qmpPluginAPIStub::registerEventReadHandler(callback_t cb, void *userdata)
 {
-	return core->player->registerEventReadHandler(cb,userdata);
+    return core->player->registerEventReadHandler(cb, userdata);
 }
 void qmpPluginAPIStub::unregisterEventReadHandler(int id)
 {
-	core->player->unregisterEventReadHandler(id);
+    core->player->unregisterEventReadHandler(id);
 }
 int qmpPluginAPIStub::registerFileReadFinishHook(callback_t cb, void *userdata)
 {
-	return core->player->registerFileReadFinishHook(cb,userdata);
+    return core->player->registerFileReadFinishHook(cb, userdata);
 }
 void qmpPluginAPIStub::unregisterFileReadFinishHook(int id)
 {
-	core->player->unregisterFileReadFinishHook(id);
+    core->player->unregisterFileReadFinishHook(id);
 }
 
-void qmpPluginAPIStub::registerFileReader(qmpFileReader *reader, std::string name){}
-void qmpPluginAPIStub::unregisterFileReader(std::string name){}
+void qmpPluginAPIStub::registerFileReader(qmpFileReader *reader, std::string name) {}
+void qmpPluginAPIStub::unregisterFileReader(std::string name) {}
 
 void qmpPluginAPIStub::registerOptionInt(std::string tab, std::string desc, std::string key, int min, int max, int defaultval)
 {
-	core->settings()->registerOptionInt(tab,desc,key,min,max,defaultval);
+    core->settings()->registerOptionInt(tab, desc, key, min, max, defaultval);
 }
 int qmpPluginAPIStub::getOptionInt(std::string key)
 {
-	return core->settings()->getOptionInt(key);
+    return core->settings()->getOptionInt(key);
 }
 void qmpPluginAPIStub::setOptionInt(std::string key, int val)
 {
-	core->settings()->setOptionInt(key,val);
+    core->settings()->setOptionInt(key, val);
 }
 
 void qmpPluginAPIStub::registerOptionUint(std::string tab, std::string desc, std::string key, unsigned min, unsigned max, unsigned defaultval)
 {
-	core->settings()->registerOptionUint(tab,desc,key,min,max,defaultval);
+    core->settings()->registerOptionUint(tab, desc, key, min, max, defaultval);
 }
 unsigned qmpPluginAPIStub::getOptionUint(std::string key)
 {
-	return core->settings()->getOptionUint(key);
+    return core->settings()->getOptionUint(key);
 }
 void qmpPluginAPIStub::setOptionUint(std::string key, unsigned val)
 {
-	return core->settings()->setOptionUint(key,val);
+    return core->settings()->setOptionUint(key, val);
 }
 
 void qmpPluginAPIStub::registerOptionBool(std::string tab, std::string desc, std::string key, bool defaultval)
 {
-	core->settings()->registerOptionBool(tab,desc,key,defaultval);
+    core->settings()->registerOptionBool(tab, desc, key, defaultval);
 }
 bool qmpPluginAPIStub::getOptionBool(std::string key)
 {
-	return core->settings()->getOptionBool(key);
+    return core->settings()->getOptionBool(key);
 }
 void qmpPluginAPIStub::setOptionBool(std::string key, bool val)
 {
-	core->settings()->setOptionBool(key,val);
+    core->settings()->setOptionBool(key, val);
 }
 
 void qmpPluginAPIStub::registerOptionDouble(std::string tab, std::string desc, std::string key, double min, double max, double defaultval)
 {
-	core->settings()->registerOptionDouble(tab,desc,key,min,max,defaultval);
+    core->settings()->registerOptionDouble(tab, desc, key, min, max, defaultval);
 }
 double qmpPluginAPIStub::getOptionDouble(std::string key)
 {
-	return core->settings()->getOptionDouble(key);
+    return core->settings()->getOptionDouble(key);
 }
 void qmpPluginAPIStub::setOptionDouble(std::string key, double val)
 {
-	core->settings()->setOptionDouble(key,val);
+    core->settings()->setOptionDouble(key, val);
 }
 
 void qmpPluginAPIStub::registerOptionString(std::string tab, std::string desc, std::string key, std::string defaultval, bool ispath)
 {
-	core->settings()->registerOptionString(tab,desc,key,defaultval,ispath);
+    core->settings()->registerOptionString(tab, desc, key, defaultval, ispath);
 }
 std::string qmpPluginAPIStub::getOptionString(std::string key)
 {
-	return core->settings()->getOptionString(key);
+    return core->settings()->getOptionString(key);
 }
 void qmpPluginAPIStub::setOptionString(std::string key, std::string val)
 {
-	core->settings()->setOptionString(key,val);
+    core->settings()->setOptionString(key, val);
 }
 
 void qmpPluginAPIStub::registerOptionEnumInt(std::string tab, std::string desc, std::string key, std::vector<std::string> options, int defaultval)
 {
-	core->settings()->registerOptionEnumInt(tab,desc,key,options,defaultval);
+    core->settings()->registerOptionEnumInt(tab, desc, key, options, defaultval);
 }
 int qmpPluginAPIStub::getOptionEnumInt(std::string key)
 {
-	return core->settings()->getOptionEnumInt(key);
+    return core->settings()->getOptionEnumInt(key);
 }
 void qmpPluginAPIStub::setOptionEnumInt(std::string key, int val)
 {
-	core->settings()->setOptionEnumInt(key,val);
+    core->settings()->setOptionEnumInt(key, val);
 }
diff --git a/visualization/renderer/qmppluginapistub.hpp b/visualization/renderer/qmppluginapistub.hpp
index d96cfca..4a9024d 100644
--- a/visualization/renderer/qmppluginapistub.hpp
+++ b/visualization/renderer/qmppluginapistub.hpp
@@ -4,82 +4,82 @@
 #include "qmpcorepublic.hpp"
 
 class qmpVisRenderCore;
-class qmpPluginAPIStub:public qmpPluginAPI
+class qmpPluginAPIStub: public qmpPluginAPI
 {
 public:
-	qmpPluginAPIStub(qmpVisRenderCore *_core);
-	~qmpPluginAPIStub();
-	uint32_t getDivision();
-	uint32_t getRawTempo();
-	double getRealTempo();
-	uint32_t getTimeSig();
-	int getKeySig();
-	uint32_t getNoteCount();
-	uint32_t getMaxTick();
-	uint32_t getCurrentPolyphone();
-	uint32_t getMaxPolyphone();
-	uint32_t getCurrentTimeStamp();
-	uint32_t getCurrentPlaybackPercentage();
-	int getChannelCC(int ch,int cc);
-	int getChannelPreset(int ch);
-	void playerSeek(uint32_t percentage);
-	double getPitchBend(int ch);
-	void getPitchBendRaw(int ch,uint32_t *pb,uint32_t *pbr);
-	bool getChannelMask(int ch);
-	std::string getTitle();
-	std::wstring getWTitle();
-	std::string getChannelPresetString(int ch);
-	bool isDarkTheme();
-	void* getMainWindow();
+    qmpPluginAPIStub(qmpVisRenderCore *_core);
+    ~qmpPluginAPIStub();
+    uint32_t getDivision();
+    uint32_t getRawTempo();
+    double getRealTempo();
+    uint32_t getTimeSig();
+    int getKeySig();
+    uint32_t getNoteCount();
+    uint32_t getMaxTick();
+    uint32_t getCurrentPolyphone();
+    uint32_t getMaxPolyphone();
+    uint32_t getCurrentTimeStamp();
+    uint32_t getCurrentPlaybackPercentage();
+    int getChannelCC(int ch, int cc);
+    int getChannelPreset(int ch);
+    void playerSeek(uint32_t percentage);
+    double getPitchBend(int ch);
+    void getPitchBendRaw(int ch, uint32_t *pb, uint32_t *pbr);
+    bool getChannelMask(int ch);
+    std::string getTitle();
+    std::wstring getWTitle();
+    std::string getChannelPresetString(int ch);
+    bool isDarkTheme();
+    void *getMainWindow();
 
-	void discardCurrentEvent();
-	void commitEventChange(SEvent d);
-	void callEventReaderCB(SEvent d);
-	void setFuncState(std::string name,bool state);
-	void setFuncEnabled(std::string name,bool enable);
+    void discardCurrentEvent();
+    void commitEventChange(SEvent d);
+    void callEventReaderCB(SEvent d);
+    void setFuncState(std::string name, bool state);
+    void setFuncEnabled(std::string name, bool enable);
 
-	void registerFunctionality(qmpFuncBaseIntf* i,std::string name,std::string desc,const char* icon,int iconlen,bool checkable);
-	void unregisterFunctionality(std::string name);
-	int registerUIHook(std::string e,ICallBack* cb,void* userdat);
-	int registerUIHook(std::string e,callback_t cb,void* userdat);
-	void unregisterUIHook(std::string e,int hook);
-	void registerMidiOutDevice(qmpMidiOutDevice* dev,std::string name);
-	void unregisterMidiOutDevice(std::string name);
-	int registerEventReaderIntf(ICallBack* cb,void* userdata);
-	void unregisterEventReaderIntf(int intfhandle);
-	int registerEventHandlerIntf(ICallBack* cb,void* userdata);
-	void unregisterEventHandlerIntf(int intfhandle);
-	int registerFileReadFinishedHandlerIntf(ICallBack* cb,void* userdata);
-	void unregisterFileReadFinishedHandlerIntf(int intfhandle);
-	int registerEventHandler(callback_t cb,void *userdata,bool post=false);
-	void unregisterEventHandler(int id);
-	int registerEventReadHandler(callback_t cb,void *userdata);
-	void unregisterEventReadHandler(int id);
-	int registerFileReadFinishHook(callback_t cb,void *userdata);
-	void unregisterFileReadFinishHook(int id);
-	void registerFileReader(qmpFileReader* reader,std::string name);
-	void unregisterFileReader(std::string name);
+    void registerFunctionality(qmpFuncBaseIntf *i, std::string name, std::string desc, const char *icon, int iconlen, bool checkable);
+    void unregisterFunctionality(std::string name);
+    int registerUIHook(std::string e, ICallBack *cb, void *userdat);
+    int registerUIHook(std::string e, callback_t cb, void *userdat);
+    void unregisterUIHook(std::string e, int hook);
+    void registerMidiOutDevice(qmpMidiOutDevice *dev, std::string name);
+    void unregisterMidiOutDevice(std::string name);
+    int registerEventReaderIntf(ICallBack *cb, void *userdata);
+    void unregisterEventReaderIntf(int intfhandle);
+    int registerEventHandlerIntf(ICallBack *cb, void *userdata);
+    void unregisterEventHandlerIntf(int intfhandle);
+    int registerFileReadFinishedHandlerIntf(ICallBack *cb, void *userdata);
+    void unregisterFileReadFinishedHandlerIntf(int intfhandle);
+    int registerEventHandler(callback_t cb, void *userdata, bool post = false);
+    void unregisterEventHandler(int id);
+    int registerEventReadHandler(callback_t cb, void *userdata);
+    void unregisterEventReadHandler(int id);
+    int registerFileReadFinishHook(callback_t cb, void *userdata);
+    void unregisterFileReadFinishHook(int id);
+    void registerFileReader(qmpFileReader *reader, std::string name);
+    void unregisterFileReader(std::string name);
 
-	void registerOptionInt(std::string tab,std::string desc,std::string key,int min,int max,int defaultval);
-	int getOptionInt(std::string key);
-	void setOptionInt(std::string key,int val);
-	void registerOptionUint(std::string tab,std::string desc,std::string key,unsigned min,unsigned max,unsigned defaultval);
-	unsigned getOptionUint(std::string key);
-	void setOptionUint(std::string key,unsigned val);
-	void registerOptionBool(std::string tab,std::string desc,std::string key,bool defaultval);
-	bool getOptionBool(std::string key);
-	void setOptionBool(std::string key,bool val);
-	void registerOptionDouble(std::string tab,std::string desc,std::string key,double min,double max,double defaultval);
-	double getOptionDouble(std::string key);
-	void setOptionDouble(std::string key,double val);
-	void registerOptionString(std::string tab,std::string desc,std::string key,std::string defaultval,bool ispath=false);
-	std::string getOptionString(std::string key);
-	void setOptionString(std::string key,std::string val);
-	void registerOptionEnumInt(std::string tab,std::string desc,std::string key,std::vector<std::string> options,int defaultval);
-	int getOptionEnumInt(std::string key);
-	void setOptionEnumInt(std::string key,int val);
+    void registerOptionInt(std::string tab, std::string desc, std::string key, int min, int max, int defaultval);
+    int getOptionInt(std::string key);
+    void setOptionInt(std::string key, int val);
+    void registerOptionUint(std::string tab, std::string desc, std::string key, unsigned min, unsigned max, unsigned defaultval);
+    unsigned getOptionUint(std::string key);
+    void setOptionUint(std::string key, unsigned val);
+    void registerOptionBool(std::string tab, std::string desc, std::string key, bool defaultval);
+    bool getOptionBool(std::string key);
+    void setOptionBool(std::string key, bool val);
+    void registerOptionDouble(std::string tab, std::string desc, std::string key, double min, double max, double defaultval);
+    double getOptionDouble(std::string key);
+    void setOptionDouble(std::string key, double val);
+    void registerOptionString(std::string tab, std::string desc, std::string key, std::string defaultval, bool ispath = false);
+    std::string getOptionString(std::string key);
+    void setOptionString(std::string key, std::string val);
+    void registerOptionEnumInt(std::string tab, std::string desc, std::string key, std::vector<std::string> options, int defaultval);
+    int getOptionEnumInt(std::string key);
+    void setOptionEnumInt(std::string key, int val);
 private:
-	qmpVisRenderCore* core;
+    qmpVisRenderCore *core;
 };
 
 #endif // QMPPLUGINAPISTUB_HPP
diff --git a/visualization/renderer/qmpsettingsro.cpp b/visualization/renderer/qmpsettingsro.cpp
index 034f073..67dc257 100644
--- a/visualization/renderer/qmpsettingsro.cpp
+++ b/visualization/renderer/qmpsettingsro.cpp
@@ -9,218 +9,218 @@ qmpSettingsRO::qmpSettingsRO()
 {
 }
 
-void qmpSettingsRO::registerOptionInt(std::string tab,std::string desc,std::string key,int min,int max,int defaultval)
+void qmpSettingsRO::registerOptionInt(std::string tab, std::string desc, std::string key, int min, int max, int defaultval)
 {
-	Q_UNUSED(tab)
-	optionlist.push_back(key);
-	options[key]=qmpOptionR(desc,qmpOptionR::ParameterType::parameter_int,defaultval,min,max);
+    Q_UNUSED(tab)
+    optionlist.push_back(key);
+    options[key] = qmpOptionR(desc, qmpOptionR::ParameterType::parameter_int, defaultval, min, max);
 }
 int qmpSettingsRO::getOptionInt(std::string key)
 {
-	if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_int)
-		return settings.value(QString(key.c_str()),options[key].defaultval).toInt();
-	return options[key].defaultval.toInt();
+    if (options.find(key) != options.end() && options[key].type == qmpOptionR::ParameterType::parameter_int)
+        return settings.value(QString(key.c_str()), options[key].defaultval).toInt();
+    return options[key].defaultval.toInt();
 }
-void qmpSettingsRO::setOptionInt(std::string key,int val)
+void qmpSettingsRO::setOptionInt(std::string key, int val)
 {
-	if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_int)
-		settings.insert(QString(key.c_str()),val);
+    if (options.find(key) != options.end() && options[key].type == qmpOptionR::ParameterType::parameter_int)
+        settings.insert(QString(key.c_str()), val);
 }
 
-void qmpSettingsRO::registerOptionUint(std::string tab,std::string desc,std::string key,unsigned min,unsigned max,unsigned defaultval)
+void qmpSettingsRO::registerOptionUint(std::string tab, std::string desc, std::string key, unsigned min, unsigned max, unsigned defaultval)
 {
-	Q_UNUSED(tab)
-	optionlist.push_back(key);
-	options[key]=qmpOptionR(desc,qmpOptionR::ParameterType::parameter_uint,defaultval,min,max);
+    Q_UNUSED(tab)
+    optionlist.push_back(key);
+    options[key] = qmpOptionR(desc, qmpOptionR::ParameterType::parameter_uint, defaultval, min, max);
 }
 unsigned qmpSettingsRO::getOptionUint(std::string key)
 {
-	if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_uint)
-		return settings.value(QString(key.c_str()),options[key].defaultval).toUInt();
-	return options[key].defaultval.toUInt();
+    if (options.find(key) != options.end() && options[key].type == qmpOptionR::ParameterType::parameter_uint)
+        return settings.value(QString(key.c_str()), options[key].defaultval).toUInt();
+    return options[key].defaultval.toUInt();
 }
-void qmpSettingsRO::setOptionUint(std::string key,unsigned val)
+void qmpSettingsRO::setOptionUint(std::string key, unsigned val)
 {
-	if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_uint)
-		settings.insert(QString(key.c_str()),val);
+    if (options.find(key) != options.end() && options[key].type == qmpOptionR::ParameterType::parameter_uint)
+        settings.insert(QString(key.c_str()), val);
 }
 
-void qmpSettingsRO::registerOptionBool(std::string tab,std::string desc,std::string key,bool defaultval)
+void qmpSettingsRO::registerOptionBool(std::string tab, std::string desc, std::string key, bool defaultval)
 {
-	Q_UNUSED(tab)
-	optionlist.push_back(key);
-	options[key]=qmpOptionR(desc,qmpOptionR::ParameterType::parameter_bool,defaultval);
+    Q_UNUSED(tab)
+    optionlist.push_back(key);
+    options[key] = qmpOptionR(desc, qmpOptionR::ParameterType::parameter_bool, defaultval);
 }
 bool qmpSettingsRO::getOptionBool(std::string key)
 {
-	if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_bool)
-		return settings.value(QString(key.c_str()),options[key].defaultval).toBool();
-	return options[key].defaultval.toBool();
+    if (options.find(key) != options.end() && options[key].type == qmpOptionR::ParameterType::parameter_bool)
+        return settings.value(QString(key.c_str()), options[key].defaultval).toBool();
+    return options[key].defaultval.toBool();
 }
-void qmpSettingsRO::setOptionBool(std::string key,bool val)
+void qmpSettingsRO::setOptionBool(std::string key, bool val)
 {
-	if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_bool)
-		settings.insert(QString(key.c_str()),val);
+    if (options.find(key) != options.end() && options[key].type == qmpOptionR::ParameterType::parameter_bool)
+        settings.insert(QString(key.c_str()), val);
 }
 
-void qmpSettingsRO::registerOptionDouble(std::string tab,std::string desc,std::string key,double min,double max,double defaultval)
+void qmpSettingsRO::registerOptionDouble(std::string tab, std::string desc, std::string key, double min, double max, double defaultval)
 {
-	Q_UNUSED(tab)
-	optionlist.push_back(key);
-	options[key]=qmpOptionR(desc,qmpOptionR::ParameterType::parameter_double,defaultval,min,max);
+    Q_UNUSED(tab)
+    optionlist.push_back(key);
+    options[key] = qmpOptionR(desc, qmpOptionR::ParameterType::parameter_double, defaultval, min, max);
 }
 double qmpSettingsRO::getOptionDouble(std::string key)
 {
-	if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_double)
-		return settings.value(QString(key.c_str()),options[key].defaultval).toDouble();
-	return options[key].defaultval.toDouble();
+    if (options.find(key) != options.end() && options[key].type == qmpOptionR::ParameterType::parameter_double)
+        return settings.value(QString(key.c_str()), options[key].defaultval).toDouble();
+    return options[key].defaultval.toDouble();
 }
-void qmpSettingsRO::setOptionDouble(std::string key,double val)
+void qmpSettingsRO::setOptionDouble(std::string key, double val)
 {
-	if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_double)
-		settings.insert(QString(key.c_str()),val);
+    if (options.find(key) != options.end() && options[key].type == qmpOptionR::ParameterType::parameter_double)
+        settings.insert(QString(key.c_str()), val);
 }
 
-void qmpSettingsRO::registerOptionString(std::string tab,std::string desc,std::string key,std::string defaultval,bool is_url)
+void qmpSettingsRO::registerOptionString(std::string tab, std::string desc, std::string key, std::string defaultval, bool is_url)
 {
-	Q_UNUSED(tab)
-	optionlist.push_back(key);
-	options[key]=qmpOptionR(desc,
-		is_url?qmpOptionR::ParameterType::parameter_url:qmpOptionR::ParameterType::parameter_str,
-		QString(defaultval.c_str()));
+    Q_UNUSED(tab)
+    optionlist.push_back(key);
+    options[key] = qmpOptionR(desc,
+            is_url ? qmpOptionR::ParameterType::parameter_url : qmpOptionR::ParameterType::parameter_str,
+            QString(defaultval.c_str()));
 }
 std::string qmpSettingsRO::getOptionString(std::string key)
 {
-	if(options.find(key)!=options.end()&&
-		(options[key].type==qmpOptionR::ParameterType::parameter_str||options[key].type==qmpOptionR::ParameterType::parameter_url))
-		return settings.value(QString(key.c_str()),options[key].defaultval).toString().toStdString();
-	return options[key].defaultval.toString().toStdString();
+    if (options.find(key) != options.end() &&
+        (options[key].type == qmpOptionR::ParameterType::parameter_str || options[key].type == qmpOptionR::ParameterType::parameter_url))
+        return settings.value(QString(key.c_str()), options[key].defaultval).toString().toStdString();
+    return options[key].defaultval.toString().toStdString();
 }
-void qmpSettingsRO::setOptionString(std::string key,std::string val)
+void qmpSettingsRO::setOptionString(std::string key, std::string val)
 {
-	if(options.find(key)!=options.end()&&
-		(options[key].type==qmpOptionR::ParameterType::parameter_str||options[key].type==qmpOptionR::ParameterType::parameter_url))
-		settings.insert(QString(key.c_str()),QString(val.c_str()));
+    if (options.find(key) != options.end() &&
+        (options[key].type == qmpOptionR::ParameterType::parameter_str || options[key].type == qmpOptionR::ParameterType::parameter_url))
+        settings.insert(QString(key.c_str()), QString(val.c_str()));
 }
 
-void qmpSettingsRO::registerOptionEnumInt(std::string tab,std::string desc,std::string key,std::vector<std::string> enumlist,int defaultval)
+void qmpSettingsRO::registerOptionEnumInt(std::string tab, std::string desc, std::string key, std::vector<std::string> enumlist, int defaultval)
 {
-	Q_UNUSED(tab)
-	optionlist.push_back(key);
-	options[key]=qmpOptionR(desc,qmpOptionR::ParameterType::parameter_enum,defaultval);
-	options[key].enumlist=enumlist;
+    Q_UNUSED(tab)
+    optionlist.push_back(key);
+    options[key] = qmpOptionR(desc, qmpOptionR::ParameterType::parameter_enum, defaultval);
+    options[key].enumlist = enumlist;
 }
 int qmpSettingsRO::getOptionEnumInt(std::string key)
 {
-	if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_enum)
-	{
-		std::string curitm=settings.value(QString(key.c_str()),options[key].defaultval).toString().toStdString();
-		auto curidx=std::find(options[key].enumlist.begin(),options[key].enumlist.end(),curitm);
-		if(curidx!=options[key].enumlist.end())
-			return static_cast<int>(curidx-options[key].enumlist.begin());
-		else
-		{
-			return options[key].defaultval.toInt();
-		}
-	}
-	return options[key].defaultval.toInt();
+    if (options.find(key) != options.end() && options[key].type == qmpOptionR::ParameterType::parameter_enum)
+    {
+        std::string curitm = settings.value(QString(key.c_str()), options[key].defaultval).toString().toStdString();
+        auto curidx = std::find(options[key].enumlist.begin(), options[key].enumlist.end(), curitm);
+        if (curidx != options[key].enumlist.end())
+            return static_cast<int>(curidx - options[key].enumlist.begin());
+        else
+        {
+            return options[key].defaultval.toInt();
+        }
+    }
+    return options[key].defaultval.toInt();
 }
 std::string qmpSettingsRO::getOptionEnumIntOptName(std::string key)
 {
-	if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_enum)
-	{
-		std::string curitm=settings.value(QString(key.c_str()),options[key].defaultval).toString().toStdString();
-		auto curidx=std::find(options[key].enumlist.begin(),options[key].enumlist.end(),curitm);
-		if(curidx!=options[key].enumlist.end())
-			return curitm;
-		else
-		{
-			return options[key].enumlist[static_cast<size_t>(options[key].defaultval.toInt())];
-		}
-	}
-	return options[key].enumlist[static_cast<size_t>(options[key].defaultval.toInt())];
-}
-void qmpSettingsRO::setOptionEnumInt(std::string key,int val)
-{
-	if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_enum)
-	{
-		if(static_cast<size_t>(val)<options[key].enumlist.size())
-			settings.insert(QString(key.c_str()),QString(options[key].enumlist[static_cast<size_t>(val)].c_str()));
-	}
-}
-void qmpSettingsRO::setOptionEnumIntOptName(std::string key,std::string valname)
-{
-	if(options.find(key)!=options.end()&&options[key].type==qmpOptionR::ParameterType::parameter_enum)
-	{
-		auto curidx=std::find(options[key].enumlist.begin(),options[key].enumlist.end(),valname);
-		if(curidx!=options[key].enumlist.end())
-			settings.insert(QString(key.c_str()),QString(valname.c_str()));
-	}
+    if (options.find(key) != options.end() && options[key].type == qmpOptionR::ParameterType::parameter_enum)
+    {
+        std::string curitm = settings.value(QString(key.c_str()), options[key].defaultval).toString().toStdString();
+        auto curidx = std::find(options[key].enumlist.begin(), options[key].enumlist.end(), curitm);
+        if (curidx != options[key].enumlist.end())
+            return curitm;
+        else
+        {
+            return options[key].enumlist[static_cast<size_t>(options[key].defaultval.toInt())];
+        }
+    }
+    return options[key].enumlist[static_cast<size_t>(options[key].defaultval.toInt())];
+}
+void qmpSettingsRO::setOptionEnumInt(std::string key, int val)
+{
+    if (options.find(key) != options.end() && options[key].type == qmpOptionR::ParameterType::parameter_enum)
+    {
+        if (static_cast<size_t>(val) < options[key].enumlist.size())
+            settings.insert(QString(key.c_str()), QString(options[key].enumlist[static_cast<size_t>(val)].c_str()));
+    }
+}
+void qmpSettingsRO::setOptionEnumIntOptName(std::string key, std::string valname)
+{
+    if (options.find(key) != options.end() && options[key].type == qmpOptionR::ParameterType::parameter_enum)
+    {
+        auto curidx = std::find(options[key].enumlist.begin(), options[key].enumlist.end(), valname);
+        if (curidx != options[key].enumlist.end())
+            settings.insert(QString(key.c_str()), QString(valname.c_str()));
+    }
 }
 
 void qmpSettingsRO::load(const char *path)
 {
-	QScopedPointer<QSettings> qsettings(new QSettings(path,QSettings::Format::IniFormat));
-	settings.clear();
-	for(QString&k:qsettings->allKeys())
-	{
-		settings.insert(k,qsettings->value(k));
-	}
+    QScopedPointer<QSettings> qsettings(new QSettings(path, QSettings::Format::IniFormat));
+    settings.clear();
+    for (QString &k : qsettings->allKeys())
+    {
+        settings.insert(k, qsettings->value(k));
+    }
 }
 
 void qmpSettingsRO::setopt(std::string key, std::string val)
 {
-	settings.insert(QString(key.c_str()),QString(val.c_str()));
-	if(key.find("Visualization/")!=0)
-		settings.insert("Visualization/"+QString(key.c_str()),QString(val.c_str()));
+    settings.insert(QString(key.c_str()), QString(val.c_str()));
+    if (key.find("Visualization/") != 0)
+        settings.insert("Visualization/" + QString(key.c_str()), QString(val.c_str()));
 }
 
 void qmpSettingsRO::listopt()
 {
-	for(auto&k:optionlist)
-	{
-		printf("Option key: %s\n",k.c_str());
-		if(options[k].desc.length())
-			printf("Description: %s\n",options[k].desc.c_str());
-		switch(options[k].type)
-		{
-			case qmpOptionR::ParameterType::parameter_int:
-				printf("Type: int\n");
-				printf("Range: [%d,%d]\n",options[k].minv.toInt(),options[k].maxv.toInt());
-				printf("Default value: %d\n",options[k].defaultval.toInt());
-			break;
-			case qmpOptionR::ParameterType::parameter_uint:
-				printf("Type: uint\n");
-				printf("Range: [%u,%u]\n",options[k].minv.toUInt(),options[k].maxv.toUInt());
-				printf("Default value: %u\n",options[k].defaultval.toUInt());
-			break;
-			case qmpOptionR::ParameterType::parameter_double:
-				printf("Type: double\n");
-				printf("Range: [%.2f,%.2f]\n",options[k].minv.toDouble(),options[k].maxv.toDouble());
-				printf("Default value: %.f2\n",options[k].defaultval.toDouble());
-			break;
-			case qmpOptionR::ParameterType::parameter_bool:
-				printf("Type: bool\n");
-				printf("Default value: %s\n",options[k].defaultval.toBool()?"true":"false");
-			break;
-			case qmpOptionR::ParameterType::parameter_str:
-				printf("Type: str\n");
-				printf("Default value: %s\n",options[k].defaultval.toString().toStdString().c_str());
-			break;
-			case qmpOptionR::ParameterType::parameter_url:
-				printf("Type: url\n");
-				printf("Default value: %s\n",options[k].defaultval.toString().toStdString().c_str());
-			break;
-			case qmpOptionR::ParameterType::parameter_enum:
-				printf("Type: enum\n");
-				printf("Possible values: ");
-				for(size_t i=0;i<options[k].enumlist.size();++i)
-					printf("%s%s",options[k].enumlist[i].c_str(),i==options[k].enumlist.size()-1?"\n":", ");
-				printf("Default value: %s\n",options[k].enumlist[options[k].defaultval.toInt()].c_str());
-			break;
-			default:
-				printf("Type: unknown\n");
-		}
-		puts("");
-	}
+    for (auto &k : optionlist)
+    {
+        printf("Option key: %s\n", k.c_str());
+        if (options[k].desc.length())
+            printf("Description: %s\n", options[k].desc.c_str());
+        switch (options[k].type)
+        {
+            case qmpOptionR::ParameterType::parameter_int:
+                printf("Type: int\n");
+                printf("Range: [%d,%d]\n", options[k].minv.toInt(), options[k].maxv.toInt());
+                printf("Default value: %d\n", options[k].defaultval.toInt());
+                break;
+            case qmpOptionR::ParameterType::parameter_uint:
+                printf("Type: uint\n");
+                printf("Range: [%u,%u]\n", options[k].minv.toUInt(), options[k].maxv.toUInt());
+                printf("Default value: %u\n", options[k].defaultval.toUInt());
+                break;
+            case qmpOptionR::ParameterType::parameter_double:
+                printf("Type: double\n");
+                printf("Range: [%.2f,%.2f]\n", options[k].minv.toDouble(), options[k].maxv.toDouble());
+                printf("Default value: %.f2\n", options[k].defaultval.toDouble());
+                break;
+            case qmpOptionR::ParameterType::parameter_bool:
+                printf("Type: bool\n");
+                printf("Default value: %s\n", options[k].defaultval.toBool() ? "true" : "false");
+                break;
+            case qmpOptionR::ParameterType::parameter_str:
+                printf("Type: str\n");
+                printf("Default value: %s\n", options[k].defaultval.toString().toStdString().c_str());
+                break;
+            case qmpOptionR::ParameterType::parameter_url:
+                printf("Type: url\n");
+                printf("Default value: %s\n", options[k].defaultval.toString().toStdString().c_str());
+                break;
+            case qmpOptionR::ParameterType::parameter_enum:
+                printf("Type: enum\n");
+                printf("Possible values: ");
+                for (size_t i = 0; i < options[k].enumlist.size(); ++i)
+                    printf("%s%s", options[k].enumlist[i].c_str(), i == options[k].enumlist.size() - 1 ? "\n" : ", ");
+                printf("Default value: %s\n", options[k].enumlist[options[k].defaultval.toInt()].c_str());
+                break;
+            default:
+                printf("Type: unknown\n");
+        }
+        puts("");
+    }
 }
diff --git a/visualization/renderer/qmpsettingsro.hpp b/visualization/renderer/qmpsettingsro.hpp
index c5dd8af..1a3927b 100644
--- a/visualization/renderer/qmpsettingsro.hpp
+++ b/visualization/renderer/qmpsettingsro.hpp
@@ -10,66 +10,67 @@
 
 struct qmpOptionR
 {
-	enum ParameterType{
-		parameter_int=0,
-		parameter_uint,
-		parameter_bool,
-		parameter_double,
-		parameter_str,
-		parameter_enum,
-		parameter_url,
-		parameter_custom=0x100
-	};
+    enum ParameterType
+    {
+        parameter_int = 0,
+        parameter_uint,
+        parameter_bool,
+        parameter_double,
+        parameter_str,
+        parameter_enum,
+        parameter_url,
+        parameter_custom = 0x100
+    };
 
-	std::string desc;
-	ParameterType type;
-	QVariant defaultval,minv,maxv;
-	std::vector<std::string> enumlist;
+    std::string desc;
+    ParameterType type;
+    QVariant defaultval, minv, maxv;
+    std::vector<std::string> enumlist;
 
-	qmpOptionR(){}
-	qmpOptionR(
-			std::string _desc,
-			ParameterType _t,QVariant _def=QVariant(),
-			QVariant _min=QVariant(),QVariant _max=QVariant()):
-		desc(_desc),
-		type(_t),
-		defaultval(_def),
-		minv(_min),
-		maxv(_max){}
+    qmpOptionR() {}
+    qmpOptionR(
+        std::string _desc,
+        ParameterType _t, QVariant _def = QVariant(),
+        QVariant _min = QVariant(), QVariant _max = QVariant()):
+        desc(_desc),
+        type(_t),
+        defaultval(_def),
+        minv(_min),
+        maxv(_max) {}
 };
 
 class qmpSettingsRO
 {
 public:
-	qmpSettingsRO();
-	void registerOptionInt(std::string tab,std::string desc,std::string key,int min,int max,int defaultval);
-	int getOptionInt(std::string key);
-	void setOptionInt(std::string key,int val);
-	void registerOptionUint(std::string tab,std::string desc,std::string key,unsigned min,unsigned max,unsigned defaultval);
-	unsigned getOptionUint(std::string key);
-	void setOptionUint(std::string key,unsigned val);
-	void registerOptionBool(std::string tab,std::string desc,std::string key,bool defaultval);
-	bool getOptionBool(std::string key);
-	void setOptionBool(std::string key,bool val);
-	void registerOptionDouble(std::string tab,std::string desc,std::string key,double min,double max,double defaultval);
-	double getOptionDouble(std::string key);
-	void setOptionDouble(std::string key,double val);
-	void registerOptionString(std::string tab,std::string desc,std::string key,std::string defaultval,bool is_url);
-	std::string getOptionString(std::string key);
-	void setOptionString(std::string key,std::string val);
-	void registerOptionEnumInt(std::string tab,std::string desc,std::string key,std::vector<std::string> enumlist,int defaultval);
-	int getOptionEnumInt(std::string key);
-	std::string getOptionEnumIntOptName(std::string key);
-	void setOptionEnumInt(std::string key,int val);
-	void setOptionEnumIntOptName(std::string key,std::string valname);
+    qmpSettingsRO();
+    void registerOptionInt(std::string tab, std::string desc, std::string key, int min, int max, int defaultval);
+    int getOptionInt(std::string key);
+    void setOptionInt(std::string key, int val);
+    void registerOptionUint(std::string tab, std::string desc, std::string key, unsigned min, unsigned max, unsigned defaultval);
+    unsigned getOptionUint(std::string key);
+    void setOptionUint(std::string key, unsigned val);
+    void registerOptionBool(std::string tab, std::string desc, std::string key, bool defaultval);
+    bool getOptionBool(std::string key);
+    void setOptionBool(std::string key, bool val);
+    void registerOptionDouble(std::string tab, std::string desc, std::string key, double min, double max, double defaultval);
+    double getOptionDouble(std::string key);
+    void setOptionDouble(std::string key, double val);
+    void registerOptionString(std::string tab, std::string desc, std::string key, std::string defaultval, bool is_url);
+    std::string getOptionString(std::string key);
+    void setOptionString(std::string key, std::string val);
+    void registerOptionEnumInt(std::string tab, std::string desc, std::string key, std::vector<std::string> enumlist, int defaultval);
+    int getOptionEnumInt(std::string key);
+    std::string getOptionEnumIntOptName(std::string key);
+    void setOptionEnumInt(std::string key, int val);
+    void setOptionEnumIntOptName(std::string key, std::string valname);
 
-	void load(const char* path);
-	void setopt(std::string key,std::string val);
-	void listopt();
+    void load(const char *path);
+    void setopt(std::string key, std::string val);
+    void listopt();
 private:
-	std::map<std::string,qmpOptionR> options;
-	std::vector<std::string> optionlist;
-	QVariantMap settings;
+    std::map<std::string, qmpOptionR> options;
+    std::vector<std::string> optionlist;
+    QVariantMap settings;
 };
 
 #endif
diff --git a/visualization/renderer/qmpvisrendercore.cpp b/visualization/renderer/qmpvisrendercore.cpp
index b12ed91..9d58206 100644
--- a/visualization/renderer/qmpvisrendercore.cpp
+++ b/visualization/renderer/qmpvisrendercore.cpp
@@ -19,262 +19,271 @@
 #include <QCommandLineParser>
 #include <QDebug>
 #include <QThread>
-qmpVisRenderCore *qmpVisRenderCore::inst=nullptr;
+qmpVisRenderCore *qmpVisRenderCore::inst = nullptr;
 
-qmpVisRenderCore::qmpVisRenderCore(QCommandLineParser *_clp):QObject(nullptr),clp(_clp)
+qmpVisRenderCore::qmpVisRenderCore(QCommandLineParser *_clp): QObject(nullptr), clp(_clp)
 {
-	inst=this;
-	player=new CMidiPlayer();
-	api=new qmpPluginAPIStub(this);
-	msettings=new qmpSettingsRO();
-	frameno=0;
-	msettings->registerOptionEnumInt("MIDI","Text encoding","Midi/TextEncoding",{"Unicode","Big5","Big5-HKSCS","CP949","EUC-JP","EUC-KR","GB18030","KOI8-R","KOI8-U","Macintosh","Shift-JIS"},0);
+    inst = this;
+    player = new CMidiPlayer();
+    api = new qmpPluginAPIStub(this);
+    msettings = new qmpSettingsRO();
+    frameno = 0;
+    msettings->registerOptionEnumInt("MIDI", "Text encoding", "Midi/TextEncoding", {"Unicode", "Big5", "Big5-HKSCS", "CP949", "EUC-JP", "EUC-KR", "GB18030", "KOI8-R", "KOI8-U", "Macintosh", "Shift-JIS"}, 0);
 }
 
 bool qmpVisRenderCore::loadVisualizationLibrary()
 {
 #ifdef _WIN32
-	std::vector<std::wstring> libpath={
-		QCoreApplication::applicationDirPath().toStdWString()+L"/plugins/libvisualization.dll",
-		L"libvisualization.dll",
-		L"../libvisualization.dll"//for debugging only...?
-	};
+    std::vector<std::wstring> libpath =
+    {
+        QCoreApplication::applicationDirPath().toStdWString() + L"/plugins/libvisualization.dll",
+        L"libvisualization.dll",
+        L"../libvisualization.dll"//for debugging only...?
+    };
 #else
-	std::vector<std::string> libpath={
-		QCoreApplication::applicationDirPath().toStdString()+"/plugins/libvisualization.so",
-		QT_STRINGIFY(INSTALL_PREFIX)+std::string("/lib/qmidiplayer/libvisualization.so"),
-		"../libvisualization.so"//for debugging only
-	};
+    std::vector<std::string> libpath =
+    {
+        QCoreApplication::applicationDirPath().toStdString() + "/plugins/libvisualization.so",
+        QT_STRINGIFY(INSTALL_PREFIX) + std::string("/lib/qmidiplayer/libvisualization.so"),
+        "../libvisualization.so"//for debugging only
+    };
 #endif
-	for(auto&l:libpath)
-	{
-		mp=dlopen(l.c_str(),RTLD_LAZY);
-		if(mp)break;
-	}
-	if(!mp)
-	{
-		fprintf(stderr,"failed to load the visualization module!\n");
-		return false;
-	}
-	GetInterface_func getintf=reinterpret_cast<GetInterface_func>(dlsym(mp,"qmpPluginGetInterface"));
-	SwitchMode_func switchmode=reinterpret_cast<SwitchMode_func>(dlsym(mp,"switchToRenderMode"));
-	vf=nullptr;
-	vp=getintf(api);
-	switchmode(&qmpVisRenderCore::framefunc,!clp->isSet("show-window"));
-	vp->init();
-	resetcb(nullptr,nullptr);
-	if(clp->isSet("list-options"))
-	{
-		msettings->listopt();
-		exit(0);
-	}
-	return true;
+    for (auto &l : libpath)
+    {
+        mp = dlopen(l.c_str(), RTLD_LAZY);
+        if (mp)
+            break;
+    }
+    if (!mp)
+    {
+        fprintf(stderr, "failed to load the visualization module!\n");
+        return false;
+    }
+    GetInterface_func getintf = reinterpret_cast<GetInterface_func>(dlsym(mp, "qmpPluginGetInterface"));
+    SwitchMode_func switchmode = reinterpret_cast<SwitchMode_func>(dlsym(mp, "switchToRenderMode"));
+    vf = nullptr;
+    vp = getintf(api);
+    switchmode(&qmpVisRenderCore::framefunc, !clp->isSet("show-window"));
+    vp->init();
+    resetcb(nullptr, nullptr);
+    if (clp->isSet("list-options"))
+    {
+        msettings->listopt();
+        exit(0);
+    }
+    return true;
 }
 
 void qmpVisRenderCore::unloadVisualizationLibrary()
 {
-	vp->deinit();
-	dlclose(mp);
+    vp->deinit();
+    dlclose(mp);
 }
 
 void qmpVisRenderCore::loadSettings()
 {
-	if(clp->isSet("config"))
-		msettings->load(clp->value("config").toStdString().c_str());
-	for(auto &o:clp->values("option"))
-	{
-		int sp=o.indexOf('=');
-		if(!~sp)
-		{
-			qDebug("invalid option pair: %s",o.toStdString().c_str());
-			continue;
-		}
-		QString key=o.left(sp);
-		QString value=o.mid(sp+1);
-		msettings->setopt(key.toStdString(),value.toStdString());
-	}
+    if (clp->isSet("config"))
+        msettings->load(clp->value("config").toStdString().c_str());
+    for (auto &o : clp->values("option"))
+    {
+        int sp = o.indexOf('=');
+        if (!~sp)
+        {
+            qDebug("invalid option pair: %s", o.toStdString().c_str());
+            continue;
+        }
+        QString key = o.left(sp);
+        QString value = o.mid(sp + 1);
+        msettings->setopt(key.toStdString(), value.toStdString());
+    }
 }
 
 void qmpVisRenderCore::setMIDIFile(const char *url)
 {
-	player->playerLoadFile(url);
+    player->playerLoadFile(url);
 }
 
 void qmpVisRenderCore::startRender()
 {
-	assert(vf);
-	subst={
-		{'w',QString::number(msettings->getOptionInt("Visualization/wwidth"))},
-		{'h',QString::number(msettings->getOptionInt("Visualization/wheight"))},
-		{'r',QString::number(msettings->getOptionInt("Visualization/tfps"))},
-		{'i',
-			QStringList()
-				<<"-f"<<"rawvideo"
-				<<"-pixel_format"<<"rgba"
-				<<"-video_size"<<QString("%1x%2").arg(msettings->getOptionInt("Visualization/wwidth")).arg(msettings->getOptionInt("Visualization/wheight"))
-				<<"-framerate"<<QString::number(msettings->getOptionInt("Visualization/tfps"))
-				<<"-i"<<"pipe:"
-		},
-		{'o',clp->value("output-file")}
-	};
-	if(clp->value("receiver-execution")=="per-frame")
-	{
-		subst['o']=clp->value("output-file").replace("%f",QString("%1").arg(frameno,6,10,QChar('0')));
-		oneshot=false;
-	}
-	else
-	{
-		oneshot=true;
-		if(clp->value("receiver-execution")!="one-shot")
-			qWarning("Invalid value set for --receiver-execution. Using default value.");
-	}
-	rxproc=new QProcess();
-	QStringList arguments=process_arguments(clp->value("receiver"),subst);
-	assert(arguments.length()>0);
-	rxproc->setProgram(arguments.front());
-	arguments.pop_front();
-	rxproc->setArguments(arguments);
-	frameconn=connect(this,&qmpVisRenderCore::frameRendered,this,
-	[this](void* px,size_t sz,uint32_t c,uint32_t t)
-	{
-		if(sz)
-		{
-			if(!oneshot)
-			{
-				subst['f']=QString("%1").arg(frameno,6,10,QChar('0'));
-				subst['o']=clp->value("output-file").replace("%f",QString("%1").arg(frameno,6,10,QChar('0')));
-				frameno++;
-				QStringList arguments=process_arguments(clp->value("receiver"),subst);
-				arguments.pop_front();
-				rxproc->setArguments(arguments);
-				rxproc->start();
-				rxproc->waitForStarted();
-			}
-			if(!rxproc->isOpen())return;
-			rxproc->write(static_cast<const char*>(px),static_cast<qint64>(sz));
-			while(rxproc->bytesToWrite()>(oneshot?(1<<26):0))
-				rxproc->waitForBytesWritten();
-			if(!oneshot)
-			{
-				rxproc->closeWriteChannel();
-				rxproc->waitForFinished(-1);
-			}
-		}
-		fprintf(stderr,"Rendered tick %u of %u, %.2f%% done.\r",c,t,std::min(100.,100.*c/t));
-		if(c>t)
-		{
-			this->rxproc->closeWriteChannel();
-			disconnect(frameconn);
-			qApp->exit(0);
-		}
-	},Qt::ConnectionType::BlockingQueuedConnection);
-	connect(rxproc,QOverload<int,QProcess::ExitStatus>::of(&QProcess::finished),
-			[this](int x,QProcess::ExitStatus st){
-				qDebug("%s",this->rxproc->readAllStandardError().data());
-				if(oneshot)
-				{
-					disconnect(frameconn);
-					if(x||st==QProcess::ExitStatus::CrashExit)
-						qApp->exit(1);
-					else
-						qApp->exit(0);
-				}
-	});
-	QMetaObject::invokeMethod(this,[this](){
-		if(oneshot)
-			rxproc->start();
-		vf->show();
-		startcb(nullptr,nullptr);
-	},Qt::ConnectionType::QueuedConnection);
+    assert(vf);
+    subst =
+    {
+        {'w', QString::number(msettings->getOptionInt("Visualization/wwidth"))},
+        {'h', QString::number(msettings->getOptionInt("Visualization/wheight"))},
+        {'r', QString::number(msettings->getOptionInt("Visualization/tfps"))},
+        {
+            'i',
+            QStringList()
+                    << "-f" << "rawvideo"
+                        << "-pixel_format" << "rgba"
+                        << "-video_size" << QString("%1x%2").arg(msettings->getOptionInt("Visualization/wwidth")).arg(msettings->getOptionInt("Visualization/wheight"))
+                        << "-framerate" << QString::number(msettings->getOptionInt("Visualization/tfps"))
+                        << "-i" << "pipe:"
+        },
+        {'o', clp->value("output-file")}
+    };
+    if (clp->value("receiver-execution") == "per-frame")
+    {
+        subst['o'] = clp->value("output-file").replace("%f", QString("%1").arg(frameno, 6, 10, QChar('0')));
+        oneshot = false;
+    }
+    else
+    {
+        oneshot = true;
+        if (clp->value("receiver-execution") != "one-shot")
+            qWarning("Invalid value set for --receiver-execution. Using default value.");
+    }
+    rxproc = new QProcess();
+    QStringList arguments = process_arguments(clp->value("receiver"), subst);
+    assert(arguments.length() > 0);
+    rxproc->setProgram(arguments.front());
+    arguments.pop_front();
+    rxproc->setArguments(arguments);
+    frameconn = connect(this, &qmpVisRenderCore::frameRendered, this,
+            [this](void *px, size_t sz, uint32_t c, uint32_t t)
+    {
+        if (sz)
+        {
+            if (!oneshot)
+            {
+                subst['f'] = QString("%1").arg(frameno, 6, 10, QChar('0'));
+                subst['o'] = clp->value("output-file").replace("%f", QString("%1").arg(frameno, 6, 10, QChar('0')));
+                frameno++;
+                QStringList arguments = process_arguments(clp->value("receiver"), subst);
+                arguments.pop_front();
+                rxproc->setArguments(arguments);
+                rxproc->start();
+                rxproc->waitForStarted();
+            }
+            if (!rxproc->isOpen())
+                return;
+            rxproc->write(static_cast<const char *>(px), static_cast<qint64>(sz));
+            while (rxproc->bytesToWrite() > (oneshot ? (1 << 26) : 0))
+                rxproc->waitForBytesWritten();
+            if (!oneshot)
+            {
+                rxproc->closeWriteChannel();
+                rxproc->waitForFinished(-1);
+            }
+        }
+        fprintf(stderr, "Rendered tick %u of %u, %.2f%% done.\r", c, t, std::min(100., 100.*c / t));
+        if (c > t)
+        {
+            this->rxproc->closeWriteChannel();
+            disconnect(frameconn);
+            qApp->exit(0);
+        }
+    }, Qt::ConnectionType::BlockingQueuedConnection);
+    connect(rxproc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
+        [this](int x, QProcess::ExitStatus st)
+    {
+        qDebug("%s", this->rxproc->readAllStandardError().data());
+        if (oneshot)
+        {
+            disconnect(frameconn);
+            if (x || st == QProcess::ExitStatus::CrashExit)
+                qApp->exit(1);
+            else
+                qApp->exit(0);
+        }
+    });
+    QMetaObject::invokeMethod(this, [this]()
+    {
+        if (oneshot)
+            rxproc->start();
+        vf->show();
+        startcb(nullptr, nullptr);
+    }, Qt::ConnectionType::QueuedConnection);
 }
 
-QStringList qmpVisRenderCore::process_arguments(QString a,QMap<QChar,QVariant> subst)
+QStringList qmpVisRenderCore::process_arguments(QString a, QMap<QChar, QVariant> subst)
 {
-	QStringList ret;
-	QString buf;
-	bool escaped=false;
-	bool substi=false;
-	for(int i=0;i<a.length();++i)
-	{
-		if(a[i]=='%')
-		{
-			if(escaped)
-			{
-				buf+='%';
-				escaped=false;
-			}
-			else if(substi)
-			{
-				buf+='%';
-				substi=false;
-			}
-			else substi=true;
-		}
-		else if(a[i]=='\\')
-		{
-			if(substi)
-			{
-				buf+='%';
-				substi=false;
-			}
-			if(escaped)
-			{
-				buf+='\\';
-				escaped=false;
-			}
-			else escaped=true;
-		}
-		else if(a[i]==' ')
-		{
-			if(substi)
-			{
-				buf+='%';
-				substi=false;
-			}
-			if(escaped)buf+=' ';
-			else
-			{
-				if(buf.length())
-					ret.append(buf);
-				buf.clear();
-			}
-			escaped=false;
-		}
-		else
-		{
-			if(substi&&subst.contains(a[i]))
-			{
-				if(subst[a[i]].canConvert(QMetaType::QString))
-					buf+=subst[a[i]].toString();
-				else
-				{
-					if(buf.length())
-					{
-						ret.append(buf);
-						buf.clear();
-					}
-					for(auto &it:subst[a[i]].toStringList())
-						ret.append(it);
-				}
-				substi=false;
-			}
-			else
-			{
-				if(escaped)
-				{
-					buf+='\\';
-					escaped=false;
-				}
-				buf+=a[i];
-			}
-		}
-	}
-	if(buf.length())
-		ret.append(buf);
-	return ret;
+    QStringList ret;
+    QString buf;
+    bool escaped = false;
+    bool substi = false;
+    for (int i = 0; i < a.length(); ++i)
+    {
+        if (a[i] == '%')
+        {
+            if (escaped)
+            {
+                buf += '%';
+                escaped = false;
+            }
+            else if (substi)
+            {
+                buf += '%';
+                substi = false;
+            }
+            else substi = true;
+        }
+        else if (a[i] == '\\')
+        {
+            if (substi)
+            {
+                buf += '%';
+                substi = false;
+            }
+            if (escaped)
+            {
+                buf += '\\';
+                escaped = false;
+            }
+            else escaped = true;
+        }
+        else if (a[i] == ' ')
+        {
+            if (substi)
+            {
+                buf += '%';
+                substi = false;
+            }
+            if (escaped)
+                buf += ' ';
+            else
+            {
+                if (buf.length())
+                    ret.append(buf);
+                buf.clear();
+            }
+            escaped = false;
+        }
+        else
+        {
+            if (substi && subst.contains(a[i]))
+            {
+                if (subst[a[i]].canConvert(QMetaType::QString))
+                    buf += subst[a[i]].toString();
+                else
+                {
+                    if (buf.length())
+                    {
+                        ret.append(buf);
+                        buf.clear();
+                    }
+                    for (auto &it : subst[a[i]].toStringList())
+                        ret.append(it);
+                }
+                substi = false;
+            }
+            else
+            {
+                if (escaped)
+                {
+                    buf += '\\';
+                    escaped = false;
+                }
+                buf += a[i];
+            }
+        }
+    }
+    if (buf.length())
+        ret.append(buf);
+    return ret;
 }
 
-void qmpVisRenderCore::framefunc(void *px, size_t sz,uint32_t curf,uint32_t totf)
+void qmpVisRenderCore::framefunc(void *px, size_t sz, uint32_t curf, uint32_t totf)
 {
-	emit inst->frameRendered(px,sz,curf,totf);
+    emit inst->frameRendered(px, sz, curf, totf);
 }
diff --git a/visualization/renderer/qmpvisrendercore.hpp b/visualization/renderer/qmpvisrendercore.hpp
index 71eeaed..ba978f4 100644
--- a/visualization/renderer/qmpvisrendercore.hpp
+++ b/visualization/renderer/qmpvisrendercore.hpp
@@ -15,44 +15,47 @@ class QCommandLineParser;
 
 class QProcess;
 
-class qmpVisRenderCore:public QObject
+class qmpVisRenderCore: public QObject
 {
-	Q_OBJECT
+    Q_OBJECT
 public:
-	qmpVisRenderCore(QCommandLineParser *_clp);
-	bool loadVisualizationLibrary();
-	void unloadVisualizationLibrary();
-	void loadSettings();
-	void setMIDIFile(const char* url);
-	void startRender();
-
-	qmpSettingsRO* settings(){return msettings;}
+    qmpVisRenderCore(QCommandLineParser *_clp);
+    bool loadVisualizationLibrary();
+    void unloadVisualizationLibrary();
+    void loadSettings();
+    void setMIDIFile(const char *url);
+    void startRender();
+
+    qmpSettingsRO *settings()
+    {
+        return msettings;
+    }
 
 signals:
-	void frameRendered(void* px,size_t sz,uint32_t current_tick,uint32_t total_ticks);
+    void frameRendered(void *px, size_t sz, uint32_t current_tick, uint32_t total_ticks);
 
 private:
-	qmpPluginIntf *vp;
-	qmpFuncBaseIntf *vf;
-	callback_t startcb;
-	callback_t resetcb;
-	void *mp;
-	qmpPluginAPIStub *api;
-	CMidiPlayer *player;
-	qmpSettingsRO *msettings;
-	QProcess *rxproc;
-	QMap<QChar,QVariant> subst;
-	QCommandLineParser *clp;
-	QStringList process_arguments(QString a, QMap<QChar,QVariant> subst);
-	int frameno;
-	bool oneshot;
-	QMetaObject::Connection frameconn;
-	typedef qmpPluginIntf*(*GetInterface_func)(qmpPluginAPI*);
-	typedef void(*SwitchMode_func)(void(*frameCallback)(void*,size_t,uint32_t,uint32_t),bool hidewindow);
-
-	friend class qmpPluginAPIStub;
-	static void framefunc(void* px, size_t sz, uint32_t curf, uint32_t totf);
-	static qmpVisRenderCore *inst;
+    qmpPluginIntf *vp;
+    qmpFuncBaseIntf *vf;
+    callback_t startcb;
+    callback_t resetcb;
+    void *mp;
+    qmpPluginAPIStub *api;
+    CMidiPlayer *player;
+    qmpSettingsRO *msettings;
+    QProcess *rxproc;
+    QMap<QChar, QVariant> subst;
+    QCommandLineParser *clp;
+    QStringList process_arguments(QString a, QMap<QChar, QVariant> subst);
+    int frameno;
+    bool oneshot;
+    QMetaObject::Connection frameconn;
+    typedef qmpPluginIntf *(*GetInterface_func)(qmpPluginAPI *);
+    typedef void(*SwitchMode_func)(void(*frameCallback)(void *, size_t, uint32_t, uint32_t), bool hidewindow);
+
+    friend class qmpPluginAPIStub;
+    static void framefunc(void *px, size_t sz, uint32_t curf, uint32_t totf);
+    static qmpVisRenderCore *inst;
 };
 
 #endif // QMPVISRENDERCORE_HPP
-- 
cgit v1.2.3