残夏 - 霉霉 Cruel Summer - Taylor Swift c++版

/* 代码段1 */
#pragma once
#define _PPIANO_
#include <windows.h>
#include <stdio.h>
#include <vector>
#include <string>
#include <bitset>
#include <fstream>
#include <set>
namespace PPiano
{
struct note
{
INT8 scale;
/*
* scale:
* min: -50
* max: 43
* specially: 127 means rest
*/
float beat;
};
struct key
{
BYTE code;
bool extended;
uint32_t time;
uint32_t delay;
};
class piano
{
private: std::vector <note> score;
private: float beatTime;
private: INT8 initTune;
private: bool mod;
/*
* false means instant while true means sustain
*/
/*
* main code:
* reset
* read
* compile
* play
*/
public: inline void reset()
{
this->beatTime = 0;
this->score.clear();
this->board.clear();
this->tune = 0;
this->mod = false;
this->initTune = 0;
}
public: inline bool read(const std::string & str)
{
/*
* return:
* true means successful
* false means unsuccessful
*/
const size_t && settingPos = str.find("|");
if(settingPos == std::string::npos)
{
fprintf(stderr, "read setting_not_found\n");
return false;
}
const size_t && tunePos = str.find("tune");
if(tunePos == std::string::npos || tunePos > settingPos)
{
fprintf(stderr, "read tune_setting_not_found\n");
return false;
}
if(str[tunePos + 4] ^ '=')
{
fprintf(stderr, "read tune_setting_not_found\n");
return false;
}
const size_t && scaleLength = getScaleLength(str, tunePos + 5);
if(scaleLength == 0)
{
fprintf(stderr, "read tune_setting_not_found\n");
return false;
}
this->initTune = getScale(str.substr(tunePos + 5, scaleLength));
const size_t && beatTimePos = str.find("beatTime");
if(beatTimePos == std::string::npos || beatTimePos > settingPos)
{
fprintf(stderr, "read beatTime_setting_not_found\n");
return false;
}
if(str[beatTimePos + 8] ^ '=')
{
fprintf(stderr, "read beatTime_setting_not_found\n");
return false;
}
const float && beatTimeRead = std::stof(str.substr(beatTimePos + 9));
if(beatTimeRead < 0)
{
fprintf(stderr, "read negative_beatTime::what():%f\n", beatTimeRead);
return false;
}
this->beatTime = beatTimeRead;
const size_t && instantPos = str.find("instant");
const size_t && sustainPos = str.find("sustain");
if((~instantPos && ~sustainPos) || (instantPos != std::string::npos && sustainPos != std::string::npos))
{
fprintf(stderr, "read instant_and_sustain_setting_not_found\n");
return false;
}
this->mod = instantPos == std::string::npos;
/*
* by here is for setting
*/
const size_t && length = str.length();
float beatNow = 0.0f, beatBegin = -1.0f, beatEnd = -1.0f, speed = 1.0f;
std::bitset <10> used, start;
std::set <uint8_t> pass[10];
for(size_t i = settingPos + 1; i ^ length; ++ i)
{
switch(str[i])
{
case '!': /* rest */
if(true)
{
const size_t && beatLength = getBeatLength(str, i + 1);
float beat = getBeat(str.substr(i + 1, beatLength));
if(beatBegin <= beatNow && beatNow < beatEnd) /* speed */
{
const float temp = beat;
beat /= 1.0f - (beat - beatBegin) / (beatEnd - beatBegin) * (1.0f - speed); /* gradually */
beatNow += temp;
}
else
{
beatNow += beat;
speed = 1.0f;
}
i += beatLength;
this->score.push_back({127, beat});
}
break;
case '@': /* teleport target */
if(!isdigit(str[i + 1]))
{
fprintf(stderr, "read unknown_keyword::what():%c ::at():%u\n", str[i + 1], i);
return false;
}
start[str[i + 1] ^ 48] = true;
++ i;
break;
case '%': /* end */
if(true)
{
if(!isdigit(str[i + 1]))
{
fprintf(stderr, "read unknown_keyword::what():%c ::at():%u\n", str[i + 1], i);
return false;
}
const UINT8 && ord = str[i + 1] ^ 48;
if(used[ord] == true)
{
const char temp[] = {'$', str[i + 1], 0};
size_t telePos = str.find(temp);
i = telePos + 1;
}
else
{
++ i;
}
}
break;
case '$': /* loop */
if(true)
{
if(!isdigit(str[i + 1]))
{
fprintf(stderr, "read unknown_keyword::what():%c ::at():%u\n", str[i + 1], i);
return false;
}
const UINT8 && ord = str[i + 1] ^ 48;
for(uint8_t j = 0; j ^ 10; ++ j)
{
if(start[j] && j ^ ord)
{
pass[j].insert(ord);
}
}
start[ord] = false;
if(used[ord] == false)
{
used[ord] = true;
for(auto && it : pass[ord])
{
used[it] = false;
}
const char temp[] = {'@', str[i + 1], 0};
size_t telePos = str.find(temp);
i = telePos == std::string::npos ? settingPos : telePos + 1;
}
else
{
++ i;
}
}
break;
case '~': /* speed control */
if(true)
{
size_t * posPtr = new size_t;
const float && speedRead = std::stof(str.substr(i + 1), posPtr);
i += * posPtr + 1;
if(speedRead < 0)
{
fprintf(stderr, "read nagative_times::what():%f\n", speedRead);
return false;
}
const size_t && beatLength = getBeatLength(str, i);
const float && beat = getBeat(str.substr(i, beatLength));
i += beatLength;
-- i;
beatBegin = beatNow;
beatEnd = beatNow + beat;
speed = speedRead;
}
break;
default:
if(isalpha(str[i])) /* note */
{
const size_t && scaleLength = getScaleLength(str, i);
const INT8 && scale = getScale(str.substr(i, scaleLength));
i += scaleLength;
const size_t && beatLength = getBeatLength(str, i);
float beat = getBeat(str.substr(i, beatLength));
if(beatBegin <= beatNow && beatNow < beatEnd) /* speed */
{
const float temp = beat;
beat /= 1.0f + (beatEnd - beatNow) / (beatEnd - beatBegin) * (speed - 1.0f); /* gradually */
beatNow += temp;
}
else
{
beatNow += beat;
speed = 1.0f;
}
i += beatLength;
-- i;
this->score.push_back({scale, beat});
}
else if(!isspace(str[i]))
{
fprintf(stderr, "read unknown_keyword::what():%c ::at():%u\n", str[i], i);
return false;
}
} /* switch */
} /* for */
return true;
} /* read */
private: static size_t getScaleLength(const std::string & str, const size_t & begin)
{
/* return 0 means unsuccessful */
const size_t && length = str.length();
if(begin >= length)
{
fprintf(stderr, "getScaleLength out_of_range()::what():%u\n", begin);
return 0;
}
if(!isalpha(str[begin]))
return 0;
if(!isdigit(str[begin + 1]) && !(str[begin + 1] == '#') && !(str[begin + 1] == '?'))
return 1;
if(!isdigit(str[begin + 2]) && !(str[begin + 2] == '#') && !(str[begin + 2] == '?'))
return 2;
return 3;
}
private: static INT8 getScale(const std::string && str)
{
/* return 127 means unsuccessful */
INT8 scaleCode = 0;
bool ableToUp = true, ableToDown = true;
const size_t && length = str.length();
if(length > 3 || length == 0)
{
fprintf(stderr, "getScale not_found::what():%s\n", str.c_str());
return 127;
}
switch(str[0])
{
case 'C':
case 'c':
scaleCode = -21 - (bool)isupper(str[0]) * 12;
ableToDown = false;
break;
case 'D':
case 'd':
scaleCode = -19 - (bool)isupper(str[0]) * 12;
break;
case 'E':
case 'e':
scaleCode = -17 - (bool)isupper(str[0]) * 12;
ableToUp = false;
break;
case 'F':
case 'f':
scaleCode = -16 - (bool)isupper(str[0]) * 12;
ableToDown = false;
break;
case 'G':
case 'g':
scaleCode = -14 - (bool)isupper(str[0]) * 12;
break;
case 'A':
case 'a':
scaleCode = -12 - (bool)isupper(str[0]) * 12;
break;
case 'B':
case 'b':
scaleCode = -10 - (bool)isupper(str[0]) * 12;
ableToUp = false;
break;
default:
fprintf(stderr, "getScale not_found::what():%s\n", str.c_str());
return 127;
} /* switch */
if(length > 1)
{
switch(str[1])
{
case '#':
if(ableToUp)
{
++ scaleCode;
}
else
{
fprintf(stderr, "getScale disable_up::what():%s\n", str.c_str());
return 127;
}
break;
case '?':
if(ableToDown)
{
-- scaleCode;
}
else
{
fprintf(stderr, "getScale disable_down::what():%s\n", str.c_str());
return 127;
}
break;
default:
if(isdigit(str[1]) && str[1] <= '5')
{
INT8 times = str[1] ^ 48;
if(isupper(str[0]))
{
times = -times;
}
scaleCode += times * 12;
}
else
{
fprintf(stderr, "getScale not_found::what():%s\n", str.c_str());
return 127;
}
} /* switch */
} /* if */
if(length > 2)
{
if(str[1] == '#' || str[1] == '?')
{
if(isdigit(str[2]) && str[2] <= '5')
{
INT8 times = str[2] ^ 48;
if(isupper(str[0]))
{
times = -times;
}
scaleCode += times * 12;
}
else
{
fprintf(stderr, "getScale not_found::what():%s\n", str.c_str());
return 127;
}
}
else
{
switch(str[2])
{
case '#':
if(ableToUp)
{
++ scaleCode;
}
else
{
fprintf(stderr, "getScale disable_up::what():%s\n", str.c_str());
return 127;
}
break;
case '?':
if(ableToDown)
{
-- scaleCode;
}
else
{
fprintf(stderr, "getScale disable_down::what():%s\n", str.c_str());
return 127;
}
break;
default:
fprintf(stderr, "getScale not_found::what():%s\n", str.c_str());
return 127;
} /* switch */
} /* else */
} /* if */
if(scaleCode < minTone || scaleCode > maxTone)
{
fprintf(stderr, "getScale out_of_range::what():%s\n", str.c_str());
return 127;
}
return scaleCode;
} /* getScale */
private: static size_t getBeatLength(const std::string & str, const size_t & begin)
{
const size_t && length = str.length();
size_t i = begin;
for(; i ^ length; ++ i)
{
if(str[i] != '-' && str[i] != '_' && str[i] != '=' && str[i] != '.' && str[i] != '*' && str[i] != '/' && !isdigit(str[i]))
{
break;
}
}
return i - begin;
}