#include "Synth.h" Sound::Sound() { op[0].duration = 250; op[0].volume = 100; } String Aformat(double x) { return (int)x == x ? AsString(x) : x < 100000 ? Format("%.2f", x) : Format("%g", x); } String FMOP::Save() const { String r; auto Put = [&](char c, double val, double def) { if(val != def) r << c << Aformat(val); }; Put('L', duration, 99000); Put('V', volume, 0); Put('f', f, 1); Put('r', fdrift, 0); Put('A', attack, 100); Put('D', decay, 100); Put('S', sustain, 100); Put('R', release, 100); return r + decode(waveform, WAVEFORM_SQUARE, "Q", WAVEFORM_TRIANGLE, "T", WAVEFORM_SAWTOOTH, "W", WAVEFORM_BROWN, "B", WAVEFORM_WHITE, "N", WAVEFORM_SIN, "", ~("w" + AsString(waveform - WAVEFORM_FIRSTSAMPLE))); } const char * FMOP::Load(const char *s) { auto Get = [&](double& r) { try { CParser p(s); if(p.IsDouble()) r = p.ReadDouble(); s = p.GetPtr(); } catch(CParser::Error) {} }; while(*s) { if(*s == ':') { s++; break; } switch(*s++) { case 'L': Get(duration); break; case 'V': Get(volume); break; case 'f': Get(f); break; case 'r': Get(fdrift); break; case 'A': Get(attack); break; case 'D': Get(decay); break; case 'S': Get(sustain); break; case 'R': Get(release); break; case 'Q': waveform = WAVEFORM_SQUARE; break; case 'T': waveform = WAVEFORM_TRIANGLE; break; case 'W': waveform = WAVEFORM_SAWTOOTH; break; case 'B': waveform = WAVEFORM_BROWN; break; case 'N': waveform = WAVEFORM_WHITE; break; case 'w': double w; Get(w); waveform = clamp(WAVEFORM_FIRSTSAMPLE + (int)w, (int)WAVEFORM_FIRSTSAMPLE, (int)WAVEFORM_LASTSAMPLE); } } return s; } String Sound::Save() const { String r; r << Aformat(f) << ':'; for(int i = 0; i < OPCOUNT; i++) { if(i) r << ':'; r << op[i].Save(); } return r; } void Sound::Load(const char *s) { try { CParser p(s); if(p.IsDouble()) f = p.ReadDouble(); p.Char(':'); s = p.GetPtr(); for(int i = 0; i < OPCOUNT; i++) s = op[i].Load(s); } catch(CParser::Error) {} }