diff options
| -rw-r--r-- | fft/fft.c | 154 | ||||
| -rw-r--r-- | fft/fft.h | 35 | ||||
| -rw-r--r-- | fft/fftwindow.h | 1026 | ||||
| -rw-r--r-- | fmdriver/fmdriver.h | 8 | ||||
| -rw-r--r-- | fmdriver/fmdriver_fmp.c | 10 | ||||
| -rw-r--r-- | fmdriver/fmdriver_pmd.c | 13 | ||||
| -rw-r--r-- | fmdsp/fmdsp-vramlookup-neon.s | 5 | ||||
| -rw-r--r-- | fmdsp/fmdsp.c | 371 | ||||
| -rw-r--r-- | fmdsp/fmdsp.h | 14 | ||||
| -rw-r--r-- | fmdsp/fmdsp_platform_info.h | 9 | ||||
| -rw-r--r-- | fmdsp/fmdsp_platform_unix.c | 44 | ||||
| -rw-r--r-- | fmdsp/fmdsp_platform_win.c | 57 | ||||
| -rw-r--r-- | fmdsp/fmdsp_sprites.h | 405 | ||||
| -rw-r--r-- | fmdsp/font_fmdsp_small_data.h | 15 | ||||
| -rw-r--r-- | gtk/Makefile.am | 4 | ||||
| -rw-r--r-- | gtk/fmplayer.xpm | 2 | ||||
| -rw-r--r-- | gtk/fmplayer32.xpm | 2 | ||||
| -rw-r--r-- | gtk/main.c | 23 | ||||
| -rw-r--r-- | libopna/opna.c | 2 | ||||
| -rw-r--r-- | libopna/opna.h | 1 | ||||
| -rw-r--r-- | win32/amd64/Makefile | 1 | ||||
| -rw-r--r-- | win32/fmplayer.mak | 4 | ||||
| -rw-r--r-- | win32/main.c | 25 | ||||
| -rw-r--r-- | win32/wavewrite.c | 6 | ||||
| -rw-r--r-- | win32/x86/Makefile | 1 | 
25 files changed, 2162 insertions, 75 deletions
| diff --git a/fft/fft.c b/fft/fft.c new file mode 100644 index 0000000..69c0971 --- /dev/null +++ b/fft/fft.c @@ -0,0 +1,154 @@ +#include "fft.h" +#include <math.h> +#include <string.h> + +void fft_write(struct fmplayer_fft_data *data, const int16_t *buf, unsigned len) { +  if (len > FFTLEN) { +    unsigned discard = FFTLEN - len; +    buf += discard*2; +    len = FFTLEN; +  } +  unsigned towrite = FFTLEN - data->ind; +  if (towrite > len) towrite = len; +  for (unsigned i = 0; i < towrite; i++) { +    data->buf[data->ind+i] = ((uint32_t)buf[2*i+0] + buf[2*i+1]) / 2; +  } +  data->ind = (data->ind + towrite) % FFTLEN; +  buf += towrite*2; +  len -= towrite; + +  for (unsigned i = 0; i < len; i++) { +    data->buf[i] = ((uint32_t)buf[2*i+0] + buf[2*i+1]) / 2; +  } +  data->ind = (data->ind + len) % FFTLEN; +} + +static const uint16_t fftfreqtab[FFTDISPLEN+1] = { +      0, +     18,    19,    21,    22,    23,    25,    26,    28,    29,    31, +     33,    35,    37,    39,    42,    44,    47,    50,    53,    56, +     59,    63,    66,    70,    75,    79,    84,    89,    94,   100, +    106,   112,   119,   126,   133,   141,   150,   158,   168,   178, +    189,   200,   212,   224,   238,   252,   267,   283,   300,   317, +    336,   356,   378,   400,   424,   449,   476,   504,   534,   566, +    600,   635,   673,   713,   756,   801,   848,   899,   952,  1009, +}; + +enum { +  HFFTLENBIT = 12, +  HFFTLEN = 1<<HFFTLENBIT, +}; + +static uint16_t window[FFTLEN]; +static float tritab[FFTLEN + FFTLEN/4]; + +void fft_init_table(void) { +  const double pi = acos(0.0) * 2.0; +  double alpha = 0.54; +  double beta = 1.0 - alpha; +  for (unsigned i = 0; i < FFTLEN; i++) { +    double v = alpha - beta * cos(2.0*pi*i/(FFTLEN-1)); +    window[i] = v * (1<<16); +  } +  for (unsigned i = 0; i < (FFTLEN + FFTLEN/4); i++) { +    tritab[i] = sin(2.0*pi*i/FFTLEN); +  } +} + +static float coscalc(unsigned i) { +  return tritab[(i & (FFTLEN-1)) + FFTLEN/4]; +} + +static float sincalc(unsigned i) { +  return tritab[i & (FFTLEN-1)]; +} + +static float ar(unsigned i) { +  return 0.5f*(1.0f-sincalc(i)); +} + +static float ai(unsigned i) { +  return -0.5f*coscalc(i); +} + +static float br(unsigned i) { +  return 0.5f*(1.0f+sincalc(i)); +} + +static float bi(unsigned i) { +  return 0.5f*coscalc(i); +} + +static void fft_real(float *fftbuf) { +  unsigned b = 0; +  for (unsigned i = 0; i < HFFTLEN; i++) { +    unsigned ii = 0; +    for (unsigned bit = 0; bit < HFFTLENBIT; bit++) { +      ii |= ((i >> bit) & 1u) << (HFFTLENBIT-bit-1); +    } +    fftbuf[(!b)*FFTLEN+i*2+0] = fftbuf[b*FFTLEN+ii*2+0]; +    fftbuf[(!b)*FFTLEN+i*2+1] = fftbuf[b*FFTLEN+ii*2+1]; +  } +  b = !b; +  for (unsigned bit = 0; bit < HFFTLENBIT; bit++) { +    for (unsigned i = 0; i < HFFTLEN; i++) { +      unsigned ei = i & ~(1u<<bit); +      unsigned oi = i | (1u<<bit); +      float are = fftbuf[b*FFTLEN+oi*2+0]; +      float aim = fftbuf[b*FFTLEN+oi*2+1]; +      float bre = coscalc(i<<(HFFTLENBIT-bit)); +      float bim = sincalc(i<<(HFFTLENBIT-bit)); +      float cre = are*bre - aim*bim; +      float cim = are*bim + aim*bre; +      fftbuf[(!b)*FFTLEN+i*2+0] = fftbuf[b*FFTLEN+ei*2+0] + cre; +      fftbuf[(!b)*FFTLEN+i*2+1] = fftbuf[b*FFTLEN+ei*2+1] + cim; +    } +    b = !b; +  } +  for (unsigned i = 0; i < HFFTLEN; i++) { +    float xr = fftbuf[b*FFTLEN+i*2+0]; +    float rxr = fftbuf[b*FFTLEN+0]; +    if (i) rxr = fftbuf[b*FFTLEN+(HFFTLEN-i)*2+0]; +    float xi = fftbuf[b*FFTLEN+i*2+1]; +    float rxi = fftbuf[b*FFTLEN+1]; +    if (i) rxi = fftbuf[b*FFTLEN+(HFFTLEN-i)*2+1]; +    fftbuf[(!b)*FFTLEN+i*2+0] = xr * ar(i) - xi * ai(i) + rxr * br(i) + rxi * bi(i); +    fftbuf[(!b)*FFTLEN+i*2+1] = xi * ar(i) + xr * ai(i) + rxr * bi(i) - rxi * br(i); +  } +  if (!b) { +    memcpy(fftbuf, fftbuf+FFTLEN, FFTLEN*sizeof(fftbuf[0])); +  } +} + +void fft_calc(struct fmplayer_fft_disp_data *ddata, struct fmplayer_fft_input_data *idata) { +  for (int i = 0; i < FFTLEN; i++) { +    int fi = (i + idata->fdata.ind) % FFTLEN; +    idata->work[i] = (((int32_t)idata->fdata.buf[fi]) * window[i]) >> 16; +  } +  for (int i = 0; i < FFTLEN; i++) { +    idata->fwork[i] = ((float)idata->work[i])/32768; +  } +  fft_real(idata->fwork); +  for (int i = 1; i < FFTLEN/2; i++) { +    float re = idata->fwork[i*2]; +    float im = idata->fwork[i*2+1]; +    idata->fwork[i] = sqrtf((re*re) + (im*im)); +  } +  for (int i = 0; i < FFTLEN/2; i++) { +    idata->fwork[i] = idata->fwork[i] / sqrtf(FFTLEN); +  } +  float dbuf[FFTDISPLEN]; +  for (int i = 0; i < FFTDISPLEN; i++) { +    dbuf[i] = 0.0f; +    for (int j = fftfreqtab[i]; j < fftfreqtab[i+1]; j++) { +      dbuf[i] += idata->fwork[j]; +    } +    dbuf[i] /= fftfreqtab[i+1] - fftfreqtab[i]; +  } +  for (int i = 0; i < FFTDISPLEN; i++) { +    float res = (dbuf[i] > (1.0f / 256)) ? (4.0f*log2f(dbuf[i]) + 32.0f) : 0.0f; +    if (res > 31.0f) res = 31.0f; +    if (res < 0.0f) res = 0.0f; +    ddata->buf[i] = res; +  } +} diff --git a/fft/fft.h b/fft/fft.h new file mode 100644 index 0000000..b446739 --- /dev/null +++ b/fft/fft.h @@ -0,0 +1,35 @@ +#ifndef MYON_FMPLAYER_FFT_FFT_H_INCLUDED +#define MYON_FMPLAYER_FFT_FFT_H_INCLUDED + +#include <stdint.h> + +enum { +  FFTLEN = 8192, +  FFTDISPLEN = 70, +}; + +struct fmplayer_fft_data { +  int16_t buf[FFTLEN]; +  unsigned ind; +}; + +struct fmplayer_fft_input_data { +  struct fmplayer_fft_data fdata; +  int16_t work[FFTLEN]; +  double dwork[FFTLEN]; +  float fwork[FFTLEN*2]; +}; + +struct fmplayer_fft_disp_data { +  // 0 - 31 +  // 4 per 6db +  uint8_t buf[FFTDISPLEN]; +}; + +void fft_init_table(void); + +void fft_write(struct fmplayer_fft_data *data, const int16_t *buf, unsigned len); + +void fft_calc(struct fmplayer_fft_disp_data *ddata, struct fmplayer_fft_input_data *idata); + +#endif // MYON_FMPLAYER_FFT_FFT_H_INCLUDED diff --git a/fft/fftwindow.h b/fft/fftwindow.h new file mode 100644 index 0000000..7dd26dc --- /dev/null +++ b/fft/fftwindow.h @@ -0,0 +1,1026 @@ +static const uint16_t window[8192] = { +   5242,  5242,  5242,  5242,  5243,  5243,  5243,  5243, +   5243,  5243,  5243,  5243,  5244,  5244,  5244,  5244, +   5245,  5245,  5245,  5246,  5246,  5246,  5247,  5247, +   5247,  5248,  5248,  5249,  5249,  5250,  5250,  5251, +   5251,  5252,  5253,  5253,  5254,  5255,  5255,  5256, +   5257,  5257,  5258,  5259,  5260,  5260,  5261,  5262, +   5263,  5264,  5265,  5265,  5266,  5267,  5268,  5269, +   5270,  5271,  5272,  5273,  5274,  5275,  5276,  5278, +   5279,  5280,  5281,  5282,  5283,  5285,  5286,  5287, +   5288,  5290,  5291,  5292,  5294,  5295,  5296,  5298, +   5299,  5301,  5302,  5303,  5305,  5306,  5308,  5309, +   5311,  5313,  5314,  5316,  5317,  5319,  5321,  5322, +   5324,  5326,  5328,  5329,  5331,  5333,  5335,  5336, +   5338,  5340,  5342,  5344,  5346,  5348,  5350,  5352, +   5354,  5356,  5358,  5360,  5362,  5364,  5366,  5368, +   5370,  5372,  5374,  5376,  5379,  5381,  5383,  5385, +   5388,  5390,  5392,  5394,  5397,  5399,  5401,  5404, +   5406,  5409,  5411,  5414,  5416,  5419,  5421,  5424, +   5426,  5429,  5431,  5434,  5436,  5439,  5442,  5444, +   5447,  5450,  5452,  5455,  5458,  5461,  5464,  5466, +   5469,  5472,  5475,  5478,  5481,  5484,  5486,  5489, +   5492,  5495,  5498,  5501,  5504,  5507,  5511,  5514, +   5517,  5520,  5523,  5526,  5529,  5532,  5536,  5539, +   5542,  5545,  5549,  5552,  5555,  5559,  5562,  5565, +   5569,  5572,  5576,  5579,  5582,  5586,  5589,  5593, +   5596,  5600,  5604,  5607,  5611,  5614,  5618,  5622, +   5625,  5629,  5633,  5636,  5640,  5644,  5648,  5651, +   5655,  5659,  5663,  5667,  5671,  5675,  5678,  5682, +   5686,  5690,  5694,  5698,  5702,  5706,  5710,  5714, +   5719,  5723,  5727,  5731,  5735,  5739,  5743,  5748, +   5752,  5756,  5760,  5765,  5769,  5773,  5778,  5782, +   5786,  5791,  5795,  5799,  5804,  5808,  5813,  5817, +   5822,  5826,  5831,  5835,  5840,  5845,  5849,  5854, +   5858,  5863,  5868,  5872,  5877,  5882,  5887,  5891, +   5896,  5901,  5906,  5911,  5915,  5920,  5925,  5930, +   5935,  5940,  5945,  5950,  5955,  5960,  5965,  5970, +   5975,  5980,  5985,  5990,  5995,  6001,  6006,  6011, +   6016,  6021,  6027,  6032,  6037,  6042,  6048,  6053, +   6058,  6064,  6069,  6074,  6080,  6085,  6091,  6096, +   6102,  6107,  6113,  6118,  6124,  6129,  6135,  6140, +   6146,  6152,  6157,  6163,  6169,  6174,  6180,  6186, +   6192,  6197,  6203,  6209,  6215,  6221,  6226,  6232, +   6238,  6244,  6250,  6256,  6262,  6268,  6274,  6280, +   6286,  6292,  6298,  6304,  6310,  6316,  6322,  6329, +   6335,  6341,  6347,  6353,  6359,  6366,  6372,  6378, +   6385,  6391,  6397,  6404,  6410,  6416,  6423,  6429, +   6436,  6442,  6448,  6455,  6461,  6468,  6475,  6481, +   6488,  6494,  6501,  6507,  6514,  6521,  6527,  6534, +   6541,  6548,  6554,  6561,  6568,  6575,  6581,  6588, +   6595,  6602,  6609,  6616,  6623,  6630,  6636,  6643, +   6650,  6657,  6664,  6671,  6678,  6686,  6693,  6700, +   6707,  6714,  6721,  6728,  6735,  6743,  6750,  6757, +   6764,  6772,  6779,  6786,  6793,  6801,  6808,  6815, +   6823,  6830,  6838,  6845,  6853,  6860,  6868,  6875, +   6883,  6890,  6898,  6905,  6913,  6920,  6928,  6936, +   6943,  6951,  6959,  6966,  6974,  6982,  6990,  6997, +   7005,  7013,  7021,  7029,  7036,  7044,  7052,  7060, +   7068,  7076,  7084,  7092,  7100,  7108,  7116,  7124, +   7132,  7140,  7148,  7156,  7164,  7172,  7180,  7189, +   7197,  7205,  7213,  7221,  7230,  7238,  7246,  7255, +   7263,  7271,  7280,  7288,  7296,  7305,  7313,  7322, +   7330,  7338,  7347,  7355,  7364,  7373,  7381,  7390, +   7398,  7407,  7415,  7424,  7433,  7441,  7450,  7459, +   7467,  7476,  7485,  7494,  7502,  7511,  7520,  7529, +   7538,  7547,  7555,  7564,  7573,  7582,  7591,  7600, +   7609,  7618,  7627,  7636,  7645,  7654,  7663,  7672, +   7681,  7691,  7700,  7709,  7718,  7727,  7736,  7746, +   7755,  7764,  7773,  7783,  7792,  7801,  7811,  7820, +   7829,  7839,  7848,  7857,  7867,  7876,  7886,  7895, +   7905,  7914,  7924,  7933,  7943,  7952,  7962,  7972, +   7981,  7991,  8001,  8010,  8020,  8030,  8039,  8049, +   8059,  8069,  8078,  8088,  8098,  8108,  8118,  8128, +   8137,  8147,  8157,  8167,  8177,  8187,  8197,  8207, +   8217,  8227,  8237,  8247,  8257,  8267,  8277,  8288, +   8298,  8308,  8318,  8328,  8338,  8349,  8359,  8369, +   8379,  8390,  8400,  8410,  8421,  8431,  8441,  8452, +   8462,  8472,  8483,  8493,  8504,  8514,  8525,  8535, +   8546,  8556,  8567,  8577,  8588,  8599,  8609,  8620, +   8630,  8641,  8652,  8662,  8673,  8684,  8695,  8705, +   8716,  8727,  8738,  8749,  8759,  8770,  8781,  8792, +   8803,  8814,  8825,  8836,  8847,  8858,  8869,  8880, +   8891,  8902,  8913,  8924,  8935,  8946,  8957,  8968, +   8979,  8990,  9002,  9013,  9024,  9035,  9047,  9058, +   9069,  9080,  9092,  9103,  9114,  9126,  9137,  9148, +   9160,  9171,  9183,  9194,  9205,  9217,  9228,  9240, +   9251,  9263,  9275,  9286,  9298,  9309,  9321,  9332, +   9344,  9356,  9367,  9379,  9391,  9403,  9414,  9426, +   9438,  9450,  9461,  9473,  9485,  9497,  9509,  9521, +   9532,  9544,  9556,  9568,  9580,  9592,  9604,  9616, +   9628,  9640,  9652,  9664,  9676,  9688,  9700,  9712, +   9725,  9737,  9749,  9761,  9773,  9785,  9798,  9810, +   9822,  9834,  9847,  9859,  9871,  9884,  9896,  9908, +   9921,  9933,  9945,  9958,  9970,  9983,  9995, 10008, +  10020, 10033, 10045, 10058, 10070, 10083, 10095, 10108, +  10121, 10133, 10146, 10158, 10171, 10184, 10196, 10209, +  10222, 10235, 10247, 10260, 10273, 10286, 10299, 10311, +  10324, 10337, 10350, 10363, 10376, 10389, 10402, 10414, +  10427, 10440, 10453, 10466, 10479, 10492, 10506, 10519, +  10532, 10545, 10558, 10571, 10584, 10597, 10610, 10624, +  10637, 10650, 10663, 10676, 10690, 10703, 10716, 10730, +  10743, 10756, 10770, 10783, 10796, 10810, 10823, 10836, +  10850, 10863, 10877, 10890, 10904, 10917, 10931, 10944, +  10958, 10971, 10985, 10999, 11012, 11026, 11039, 11053, +  11067, 11080, 11094, 11108, 11121, 11135, 11149, 11163, +  11176, 11190, 11204, 11218, 11232, 11245, 11259, 11273, +  11287, 11301, 11315, 11329, 11343, 11357, 11371, 11385, +  11399, 11413, 11427, 11441, 11455, 11469, 11483, 11497, +  11511, 11525, 11539, 11554, 11568, 11582, 11596, 11610, +  11625, 11639, 11653, 11667, 11682, 11696, 11710, 11724, +  11739, 11753, 11767, 11782, 11796, 11811, 11825, 11840, +  11854, 11868, 11883, 11897, 11912, 11926, 11941, 11955, +  11970, 11985, 11999, 12014, 12028, 12043, 12058, 12072, +  12087, 12102, 12116, 12131, 12146, 12160, 12175, 12190, +  12205, 12220, 12234, 12249, 12264, 12279, 12294, 12309, +  12323, 12338, 12353, 12368, 12383, 12398, 12413, 12428, +  12443, 12458, 12473, 12488, 12503, 12518, 12533, 12548, +  12563, 12579, 12594, 12609, 12624, 12639, 12654, 12669, +  12685, 12700, 12715, 12730, 12746, 12761, 12776, 12792, +  12807, 12822, 12837, 12853, 12868, 12884, 12899, 12914, +  12930, 12945, 12961, 12976, 12992, 13007, 13023, 13038, +  13054, 13069, 13085, 13100, 13116, 13131, 13147, 13163, +  13178, 13194, 13210, 13225, 13241, 13257, 13272, 13288, +  13304, 13320, 13335, 13351, 13367, 13383, 13398, 13414, +  13430, 13446, 13462, 13478, 13494, 13510, 13525, 13541, +  13557, 13573, 13589, 13605, 13621, 13637, 13653, 13669, +  13685, 13701, 13717, 13734, 13750, 13766, 13782, 13798, +  13814, 13830, 13846, 13863, 13879, 13895, 13911, 13927, +  13944, 13960, 13976, 13993, 14009, 14025, 14041, 14058, +  14074, 14091, 14107, 14123, 14140, 14156, 14172, 14189, +  14205, 14222, 14238, 14255, 14271, 14288, 14304, 14321, +  14337, 14354, 14371, 14387, 14404, 14420, 14437, 14454, +  14470, 14487, 14504, 14520, 14537, 14554, 14570, 14587, +  14604, 14621, 14637, 14654, 14671, 14688, 14705, 14721, +  14738, 14755, 14772, 14789, 14806, 14823, 14840, 14856, +  14873, 14890, 14907, 14924, 14941, 14958, 14975, 14992, +  15009, 15026, 15043, 15060, 15078, 15095, 15112, 15129, +  15146, 15163, 15180, 15197, 15215, 15232, 15249, 15266, +  15283, 15301, 15318, 15335, 15353, 15370, 15387, 15404, +  15422, 15439, 15456, 15474, 15491, 15508, 15526, 15543, +  15561, 15578, 15596, 15613, 15630, 15648, 15665, 15683, +  15700, 15718, 15735, 15753, 15771, 15788, 15806, 15823, +  15841, 15858, 15876, 15894, 15911, 15929, 15947, 15964, +  15982, 16000, 16018, 16035, 16053, 16071, 16088, 16106, +  16124, 16142, 16160, 16177, 16195, 16213, 16231, 16249, +  16267, 16285, 16302, 16320, 16338, 16356, 16374, 16392, +  16410, 16428, 16446, 16464, 16482, 16500, 16518, 16536, +  16554, 16572, 16590, 16608, 16626, 16645, 16663, 16681, +  16699, 16717, 16735, 16753, 16772, 16790, 16808, 16826, +  16844, 16863, 16881, 16899, 16917, 16936, 16954, 16972, +  16991, 17009, 17027, 17046, 17064, 17082, 17101, 17119, +  17138, 17156, 17174, 17193, 17211, 17230, 17248, 17267, +  17285, 17304, 17322, 17341, 17359, 17378, 17396, 17415, +  17433, 17452, 17471, 17489, 17508, 17526, 17545, 17564, +  17582, 17601, 17620, 17638, 17657, 17676, 17695, 17713, +  17732, 17751, 17769, 17788, 17807, 17826, 17845, 17863, +  17882, 17901, 17920, 17939, 17958, 17977, 17995, 18014, +  18033, 18052, 18071, 18090, 18109, 18128, 18147, 18166, +  18185, 18204, 18223, 18242, 18261, 18280, 18299, 18318, +  18337, 18356, 18375, 18394, 18413, 18432, 18452, 18471, +  18490, 18509, 18528, 18547, 18567, 18586, 18605, 18624, +  18643, 18663, 18682, 18701, 18720, 18740, 18759, 18778, +  18798, 18817, 18836, 18856, 18875, 18894, 18914, 18933, +  18952, 18972, 18991, 19011, 19030, 19049, 19069, 19088, +  19108, 19127, 19147, 19166, 19186, 19205, 19225, 19244, +  19264, 19283, 19303, 19322, 19342, 19362, 19381, 19401, +  19420, 19440, 19460, 19479, 19499, 19519, 19538, 19558, +  19578, 19597, 19617, 19637, 19656, 19676, 19696, 19716, +  19735, 19755, 19775, 19795, 19814, 19834, 19854, 19874, +  19894, 19914, 19933, 19953, 19973, 19993, 20013, 20033, +  20053, 20073, 20093, 20113, 20132, 20152, 20172, 20192, +  20212, 20232, 20252, 20272, 20292, 20312, 20332, 20352, +  20372, 20392, 20413, 20433, 20453, 20473, 20493, 20513, +  20533, 20553, 20573, 20594, 20614, 20634, 20654, 20674, +  20694, 20715, 20735, 20755, 20775, 20795, 20816, 20836, +  20856, 20876, 20897, 20917, 20937, 20958, 20978, 20998, +  21019, 21039, 21059, 21080, 21100, 21120, 21141, 21161, +  21181, 21202, 21222, 21243, 21263, 21284, 21304, 21324, +  21345, 21365, 21386, 21406, 21427, 21447, 21468, 21488, +  21509, 21529, 21550, 21570, 21591, 21612, 21632, 21653, +  21673, 21694, 21715, 21735, 21756, 21776, 21797, 21818, +  21838, 21859, 21880, 21900, 21921, 21942, 21962, 21983, +  22004, 22025, 22045, 22066, 22087, 22108, 22128, 22149, +  22170, 22191, 22211, 22232, 22253, 22274, 22295, 22316, +  22336, 22357, 22378, 22399, 22420, 22441, 22462, 22482, +  22503, 22524, 22545, 22566, 22587, 22608, 22629, 22650, +  22671, 22692, 22713, 22734, 22755, 22776, 22797, 22818, +  22839, 22860, 22881, 22902, 22923, 22944, 22965, 22986, +  23007, 23028, 23049, 23071, 23092, 23113, 23134, 23155, +  23176, 23197, 23218, 23240, 23261, 23282, 23303, 23324, +  23346, 23367, 23388, 23409, 23430, 23452, 23473, 23494, +  23515, 23537, 23558, 23579, 23600, 23622, 23643, 23664, +  23686, 23707, 23728, 23750, 23771, 23792, 23814, 23835, +  23856, 23878, 23899, 23920, 23942, 23963, 23985, 24006, +  24028, 24049, 24070, 24092, 24113, 24135, 24156, 24178, +  24199, 24221, 24242, 24264, 24285, 24307, 24328, 24350, +  24371, 24393, 24414, 24436, 24457, 24479, 24500, 24522, +  24543, 24565, 24587, 24608, 24630, 24651, 24673, 24695, +  24716, 24738, 24760, 24781, 24803, 24825, 24846, 24868, +  24890, 24911, 24933, 24955, 24976, 24998, 25020, 25041, +  25063, 25085, 25107, 25128, 25150, 25172, 25194, 25215, +  25237, 25259, 25281, 25302, 25324, 25346, 25368, 25390, +  25412, 25433, 25455, 25477, 25499, 25521, 25543, 25564, +  25586, 25608, 25630, 25652, 25674, 25696, 25718, 25739, +  25761, 25783, 25805, 25827, 25849, 25871, 25893, 25915, +  25937, 25959, 25981, 26003, 26025, 26047, 26069, 26091, +  26113, 26135, 26157, 26179, 26201, 26223, 26245, 26267, +  26289, 26311, 26333, 26355, 26377, 26399, 26421, 26443, +  26465, 26488, 26510, 26532, 26554, 26576, 26598, 26620, +  26642, 26664, 26687, 26709, 26731, 26753, 26775, 26797, +  26820, 26842, 26864, 26886, 26908, 26930, 26953, 26975, +  26997, 27019, 27042, 27064, 27086, 27108, 27130, 27153, +  27175, 27197, 27219, 27242, 27264, 27286, 27309, 27331, +  27353, 27375, 27398, 27420, 27442, 27465, 27487, 27509, +  27532, 27554, 27576, 27599, 27621, 27643, 27666, 27688, +  27710, 27733, 27755, 27777, 27800, 27822, 27845, 27867, +  27889, 27912, 27934, 27957, 27979, 28001, 28024, 28046, +  28069, 28091, 28114, 28136, 28158, 28181, 28203, 28226, +  28248, 28271, 28293, 28316, 28338, 28361, 28383, 28406, +  28428, 28451, 28473, 28496, 28518, 28541, 28563, 28586, +  28608, 28631, 28653, 28676, 28698, 28721, 28744, 28766, +  28789, 28811, 28834, 28856, 28879, 28902, 28924, 28947, +  28969, 28992, 29014, 29037, 29060, 29082, 29105, 29128, +  29150, 29173, 29195, 29218, 29241, 29263, 29286, 29309, +  29331, 29354, 29377, 29399, 29422, 29445, 29467, 29490, +  29513, 29535, 29558, 29581, 29603, 29626, 29649, 29671, +  29694, 29717, 29740, 29762, 29785, 29808, 29830, 29853, +  29876, 29899, 29921, 29944, 29967, 29990, 30012, 30035, +  30058, 30081, 30103, 30126, 30149, 30172, 30195, 30217, +  30240, 30263, 30286, 30308, 30331, 30354, 30377, 30400, +  30422, 30445, 30468, 30491, 30514, 30537, 30559, 30582, +  30605, 30628, 30651, 30674, 30696, 30719, 30742, 30765, +  30788, 30811, 30833, 30856, 30879, 30902, 30925, 30948, +  30971, 30994, 31016, 31039, 31062, 31085, 31108, 31131, +  31154, 31177, 31200, 31222, 31245, 31268, 31291, 31314, +  31337, 31360, 31383, 31406, 31429, 31452, 31475, 31497, +  31520, 31543, 31566, 31589, 31612, 31635, 31658, 31681, +  31704, 31727, 31750, 31773, 31796, 31819, 31842, 31865, +  31888, 31911, 31934, 31957, 31980, 32003, 32025, 32048, +  32071, 32094, 32117, 32140, 32163, 32186, 32209, 32232, +  32255, 32278, 32301, 32324, 32347, 32370, 32393, 32416, +  32439, 32462, 32485, 32509, 32532, 32555, 32578, 32601, +  32624, 32647, 32670, 32693, 32716, 32739, 32762, 32785, +  32808, 32831, 32854, 32877, 32900, 32923, 32946, 32969, +  32992, 33015, 33038, 33061, 33084, 33108, 33131, 33154, +  33177, 33200, 33223, 33246, 33269, 33292, 33315, 33338, +  33361, 33384, 33407, 33430, 33454, 33477, 33500, 33523, +  33546, 33569, 33592, 33615, 33638, 33661, 33684, 33707, +  33731, 33754, 33777, 33800, 33823, 33846, 33869, 33892, +  33915, 33938, 33962, 33985, 34008, 34031, 34054, 34077, +  34100, 34123, 34146, 34169, 34193, 34216, 34239, 34262, +  34285, 34308, 34331, 34354, 34377, 34401, 34424, 34447, +  34470, 34493, 34516, 34539, 34562, 34585, 34609, 34632, +  34655, 34678, 34701, 34724, 34747, 34770, 34794, 34817, +  34840, 34863, 34886, 34909, 34932, 34955, 34978, 35002, +  35025, 35048, 35071, 35094, 35117, 35140, 35163, 35187, +  35210, 35233, 35256, 35279, 35302, 35325, 35348, 35372, +  35395, 35418, 35441, 35464, 35487, 35510, 35533, 35557, +  35580, 35603, 35626, 35649, 35672, 35695, 35718, 35742, +  35765, 35788, 35811, 35834, 35857, 35880, 35903, 35927, +  35950, 35973, 35996, 36019, 36042, 36065, 36088, 36112, +  36135, 36158, 36181, 36204, 36227, 36250, 36273, 36296, +  36320, 36343, 36366, 36389, 36412, 36435, 36458, 36481, +  36504, 36528, 36551, 36574, 36597, 36620, 36643, 36666, +  36689, 36712, 36736, 36759, 36782, 36805, 36828, 36851, +  36874, 36897, 36920, 36943, 36966, 36990, 37013, 37036, +  37059, 37082, 37105, 37128, 37151, 37174, 37197, 37220, +  37244, 37267, 37290, 37313, 37336, 37359, 37382, 37405, +  37428, 37451, 37474, 37497, 37520, 37544, 37567, 37590, +  37613, 37636, 37659, 37682, 37705, 37728, 37751, 37774, +  37797, 37820, 37843, 37866, 37889, 37912, 37935, 37958, +  37982, 38005, 38028, 38051, 38074, 38097, 38120, 38143, +  38166, 38189, 38212, 38235, 38258, 38281, 38304, 38327, +  38350, 38373, 38396, 38419, 38442, 38465, 38488, 38511, +  38534, 38557, 38580, 38603, 38626, 38649, 38672, 38695, +  38718, 38741, 38764, 38787, 38810, 38833, 38856, 38879, +  38902, 38925, 38948, 38971, 38994, 39017, 39039, 39062, +  39085, 39108, 39131, 39154, 39177, 39200, 39223, 39246, +  39269, 39292, 39315, 39338, 39361, 39384, 39406, 39429, +  39452, 39475, 39498, 39521, 39544, 39567, 39590, 39613, +  39636, 39658, 39681, 39704, 39727, 39750, 39773, 39796, +  39819, 39841, 39864, 39887, 39910, 39933, 39956, 39979, +  40002, 40024, 40047, 40070, 40093, 40116, 40139, 40161, +  40184, 40207, 40230, 40253, 40276, 40298, 40321, 40344, +  40367, 40390, 40412, 40435, 40458, 40481, 40504, 40526, +  40549, 40572, 40595, 40618, 40640, 40663, 40686, 40709, +  40731, 40754, 40777, 40800, 40822, 40845, 40868, 40891, +  40913, 40936, 40959, 40981, 41004, 41027, 41050, 41072, +  41095, 41118, 41140, 41163, 41186, 41209, 41231, 41254, +  41277, 41299, 41322, 41345, 41367, 41390, 41413, 41435, +  41458, 41481, 41503, 41526, 41549, 41571, 41594, 41616, +  41639, 41662, 41684, 41707, 41730, 41752, 41775, 41797, +  41820, 41842, 41865, 41888, 41910, 41933, 41955, 41978, +  42001, 42023, 42046, 42068, 42091, 42113, 42136, 42158, +  42181, 42203, 42226, 42248, 42271, 42293, 42316, 42339, +  42361, 42384, 42406, 42428, 42451, 42473, 42496, 42518, +  42541, 42563, 42586, 42608, 42631, 42653, 42676, 42698, +  42720, 42743, 42765, 42788, 42810, 42833, 42855, 42877, +  42900, 42922, 42945, 42967, 42989, 43012, 43034, 43056, +  43079, 43101, 43123, 43146, 43168, 43191, 43213, 43235, +  43258, 43280, 43302, 43324, 43347, 43369, 43391, 43414, +  43436, 43458, 43481, 43503, 43525, 43547, 43570, 43592, +  43614, 43636, 43659, 43681, 43703, 43725, 43747, 43770, +  43792, 43814, 43836, 43859, 43881, 43903, 43925, 43947, +  43969, 43992, 44014, 44036, 44058, 44080, 44102, 44124, +  44147, 44169, 44191, 44213, 44235, 44257, 44279, 44301, +  44323, 44346, 44368, 44390, 44412, 44434, 44456, 44478, +  44500, 44522, 44544, 44566, 44588, 44610, 44632, 44654, +  44676, 44698, 44720, 44742, 44764, 44786, 44808, 44830, +  44852, 44874, 44896, 44918, 44940, 44962, 44984, 45006, +  45027, 45049, 45071, 45093, 45115, 45137, 45159, 45181, +  45203, 45224, 45246, 45268, 45290, 45312, 45334, 45355, +  45377, 45399, 45421, 45443, 45465, 45486, 45508, 45530, +  45552, 45573, 45595, 45617, 45639, 45660, 45682, 45704, +  45726, 45747, 45769, 45791, 45812, 45834, 45856, 45878, +  45899, 45921, 45943, 45964, 45986, 46008, 46029, 46051, +  46072, 46094, 46116, 46137, 46159, 46180, 46202, 46224, +  46245, 46267, 46288, 46310, 46331, 46353, 46375, 46396, +  46418, 46439, 46461, 46482, 46504, 46525, 46547, 46568, +  46590, 46611, 46632, 46654, 46675, 46697, 46718, 46740, +  46761, 46783, 46804, 46825, 46847, 46868, 46889, 46911, +  46932, 46954, 46975, 46996, 47018, 47039, 47060, 47082, +  47103, 47124, 47145, 47167, 47188, 47209, 47231, 47252, +  47273, 47294, 47316, 47337, 47358, 47379, 47401, 47422, +  47443, 47464, 47485, 47506, 47528, 47549, 47570, 47591, +  47612, 47633, 47655, 47676, 47697, 47718, 47739, 47760, +  47781, 47802, 47823, 47844, 47865, 47886, 47907, 47929, +  47950, 47971, 47992, 48013, 48034, 48055, 48076, 48097, +  48117, 48138, 48159, 48180, 48201, 48222, 48243, 48264, +  48285, 48306, 48327, 48348, 48368, 48389, 48410, 48431, +  48452, 48473, 48494, 48514, 48535, 48556, 48577, 48598, +  48618, 48639, 48660, 48681, 48701, 48722, 48743, 48764, +  48784, 48805, 48826, 48847, 48867, 48888, 48909, 48929, +  48950, 48971, 48991, 49012, 49032, 49053, 49074, 49094, +  49115, 49135, 49156, 49177, 49197, 49218, 49238, 49259, +  49279, 49300, 49320, 49341, 49361, 49382, 49402, 49423, +  49443, 49464, 49484, 49505, 49525, 49545, 49566, 49586, +  49607, 49627, 49647, 49668, 49688, 49708, 49729, 49749, +  49769, 49790, 49810, 49830, 49851, 49871, 49891, 49912, +  49932, 49952, 49972, 49993, 50013, 50033, 50053, 50073, +  50094, 50114, 50134, 50154, 50174, 50194, 50215, 50235, +  50255, 50275, 50295, 50315, 50335, 50355, 50375, 50395, +  50415, 50436, 50456, 50476, 50496, 50516, 50536, 50556, +  50576, 50596, 50615, 50635, 50655, 50675, 50695, 50715, +  50735, 50755, 50775, 50795, 50815, 50834, 50854, 50874, +  50894, 50914, 50934, 50953, 50973, 50993, 51013, 51033, +  51052, 51072, 51092, 51112, 51131, 51151, 51171, 51190, +  51210, 51230, 51250, 51269, 51289, 51308, 51328, 51348, +  51367, 51387, 51407, 51426, 51446, 51465, 51485, 51504, +  51524, 51543, 51563, 51582, 51602, 51621, 51641, 51660, +  51680, 51699, 51719, 51738, 51758, 51777, 51796, 51816, +  51835, 51855, 51874, 51893, 51913, 51932, 51951, 51971, +  51990, 52009, 52029, 52048, 52067, 52086, 52106, 52125, +  52144, 52163, 52183, 52202, 52221, 52240, 52259, 52278, +  52298, 52317, 52336, 52355, 52374, 52393, 52412, 52431, +  52450, 52469, 52489, 52508, 52527, 52546, 52565, 52584, +  52603, 52622, 52641, 52660, 52678, 52697, 52716, 52735, +  52754, 52773, 52792, 52811, 52830, 52849, 52867, 52886, +  52905, 52924, 52943, 52961, 52980, 52999, 53018, 53037, +  53055, 53074, 53093, 53111, 53130, 53149, 53168, 53186, +  53205, 53224, 53242, 53261, 53279, 53298, 53317, 53335, +  53354, 53372, 53391, 53409, 53428, 53446, 53465, 53483, +  53502, 53520, 53539, 53557, 53576, 53594, 53613, 53631, +  53650, 53668, 53686, 53705, 53723, 53741, 53760, 53778, +  53796, 53815, 53833, 53851, 53870, 53888, 53906, 53924, +  53943, 53961, 53979, 53997, 54015, 54034, 54052, 54070, +  54088, 54106, 54124, 54142, 54160, 54179, 54197, 54215, +  54233, 54251, 54269, 54287, 54305, 54323, 54341, 54359, +  54377, 54395, 54413, 54431, 54449, 54466, 54484, 54502, +  54520, 54538, 54556, 54574, 54592, 54609, 54627, 54645, +  54663, 54681, 54698, 54716, 54734, 54752, 54769, 54787, +  54805, 54822, 54840, 54858, 54875, 54893, 54911, 54928, +  54946, 54963, 54981, 54999, 55016, 55034, 55051, 55069, +  55086, 55104, 55121, 55139, 55156, 55174, 55191, 55208, +  55226, 55243, 55261, 55278, 55295, 55313, 55330, 55347, +  55365, 55382, 55399, 55417, 55434, 55451, 55469, 55486, +  55503, 55520, 55537, 55555, 55572, 55589, 55606, 55623, +  55640, 55658, 55675, 55692, 55709, 55726, 55743, 55760, +  55777, 55794, 55811, 55828, 55845, 55862, 55879, 55896, +  55913, 55930, 55947, 55964, 55981, 55998, 56014, 56031, +  56048, 56065, 56082, 56099, 56115, 56132, 56149, 56166, +  56182, 56199, 56216, 56233, 56249, 56266, 56283, 56299, +  56316, 56333, 56349, 56366, 56382, 56399, 56416, 56432, +  56449, 56465, 56482, 56498, 56515, 56531, 56548, 56564, +  56581, 56597, 56614, 56630, 56646, 56663, 56679, 56696, +  56712, 56728, 56745, 56761, 56777, 56793, 56810, 56826, +  56842, 56859, 56875, 56891, 56907, 56923, 56940, 56956, +  56972, 56988, 57004, 57020, 57036, 57052, 57068, 57085, +  57101, 57117, 57133, 57149, 57165, 57181, 57197, 57213, +  57229, 57244, 57260, 57276, 57292, 57308, 57324, 57340, +  57356, 57371, 57387, 57403, 57419, 57435, 57450, 57466, +  57482, 57498, 57513, 57529, 57545, 57560, 57576, 57592, +  57607, 57623, 57639, 57654, 57670, 57685, 57701, 57716, +  57732, 57748, 57763, 57779, 57794, 57809, 57825, 57840, +  57856, 57871, 57887, 57902, 57917, 57933, 57948, 57963, +  57979, 57994, 58009, 58025, 58040, 58055, 58070, 58086, +  58101, 58116, 58131, 58146, 58162, 58177, 58192, 58207, +  58222, 58237, 58252, 58267, 58282, 58297, 58312, 58327, +  58342, 58357, 58372, 58387, 58402, 58417, 58432, 58447, +  58462, 58477, 58492, 58506, 58521, 58536, 58551, 58566, +  58581, 58595, 58610, 58625, 58640, 58654, 58669, 58684, +  58698, 58713, 58728, 58742, 58757, 58771, 58786, 58801, +  58815, 58830, 58844, 58859, 58873, 58888, 58902, 58917, +  58931, 58946, 58960, 58974, 58989, 59003, 59018, 59032, +  59046, 59061, 59075, 59089, 59103, 59118, 59132, 59146, +  59160, 59175, 59189, 59203, 59217, 59231, 59246, 59260, +  59274, 59288, 59302, 59316, 59330, 59344, 59358, 59372, +  59386, 59400, 59414, 59428, 59442, 59456, 59470, 59484, +  59498, 59512, 59525, 59539, 59553, 59567, 59581, 59595, +  59608, 59622, 59636, 59650, 59663, 59677, 59691, 59704, +  59718, 59732, 59745, 59759, 59773, 59786, 59800, 59813, +  59827, 59840, 59854, 59867, 59881, 59894, 59908, 59921, +  59935, 59948, 59962, 59975, 59988, 60002, 60015, 60028, +  60042, 60055, 60068, 60082, 60095, 60108, 60121, 60134, +  60148, 60161, 60174, 60187, 60200, 60213, 60227, 60240, +  60253, 60266, 60279, 60292, 60305, 60318, 60331, 60344, +  60357, 60370, 60383, 60396, 60409, 60422, 60434, 60447, +  60460, 60473, 60486, 60499, 60511, 60524, 60537, 60550, +  60562, 60575, 60588, 60600, 60613, 60626, 60638, 60651, +  60664, 60676, 60689, 60701, 60714, 60727, 60739, 60752, +  60764, 60777, 60789, 60801, 60814, 60826, 60839, 60851, +  60863, 60876, 60888, 60900, 60913, 60925, 60937, 60950, +  60962, 60974, 60986, 60999, 61011, 61023, 61035, 61047, +  61059, 61071, 61084, 61096, 61108, 61120, 61132, 61144, +  61156, 61168, 61180, 61192, 61204, 61216, 61228, 61240, +  61251, 61263, 61275, 61287, 61299, 61311, 61322, 61334, +  61346, 61358, 61369, 61381, 61393, 61405, 61416, 61428, +  61440, 61451, 61463, 61474, 61486, 61498, 61509, 61521, +  61532, 61544, 61555, 61567, 61578, 61590, 61601, 61612, +  61624, 61635, 61647, 61658, 61669, 61681, 61692, 61703, +  61714, 61726, 61737, 61748, 61759, 61771, 61782, 61793, +  61804, 61815, 61826, 61837, 61849, 61860, 61871, 61882, +  61893, 61904, 61915, 61926, 61937, 61948, 61959, 61970, +  61980, 61991, 62002, 62013, 62024, 62035, 62046, 62056, +  62067, 62078, 62089, 62099, 62110, 62121, 62131, 62142, +  62153, 62163, 62174, 62185, 62195, 62206, 62216, 62227, +  62237, 62248, 62258, 62269, 62279, 62290, 62300, 62311, +  62321, 62331, 62342, 62352, 62362, 62373, 62383, 62393, +  62404, 62414, 62424, 62434, 62445, 62455, 62465, 62475, +  62485, 62495, 62505, 62516, 62526, 62536, 62546, 62556, +  62566, 62576, 62586, 62596, 62606, 62616, 62626, 62635, +  62645, 62655, 62665, 62675, 62685, 62695, 62704, 62714, +  62724, 62734, 62743, 62753, 62763, 62772, 62782, 62792, +  62801, 62811, 62821, 62830, 62840, 62849, 62859, 62868, +  62878, 62887, 62897, 62906, 62916, 62925, 62935, 62944, +  62953, 62963, 62972, 62981, 62991, 63000, 63009, 63018, +  63028, 63037, 63046, 63055, 63064, 63074, 63083, 63092, +  63101, 63110, 63119, 63128, 63137, 63146, 63155, 63164, +  63173, 63182, 63191, 63200, 63209, 63218, 63227, 63236, +  63245, 63253, 63262, 63271, 63280, 63289, 63297, 63306, +  63315, 63324, 63332, 63341, 63350, 63358, 63367, 63375, +  63384, 63393, 63401, 63410, 63418, 63427, 63435, 63444, +  63452, 63461, 63469, 63477, 63486, 63494, 63502, 63511, +  63519, 63527, 63536, 63544, 63552, 63561, 63569, 63577, +  63585, 63593, 63601, 63610, 63618, 63626, 63634, 63642, +  63650, 63658, 63666, 63674, 63682, 63690, 63698, 63706, +  63714, 63722, 63730, 63738, 63745, 63753, 63761, 63769, +  63777, 63784, 63792, 63800, 63808, 63815, 63823, 63831, +  63838, 63846, 63854, 63861, 63869, 63876, 63884, 63892, +  63899, 63907, 63914, 63922, 63929, 63936, 63944, 63951, +  63959, 63966, 63973, 63981, 63988, 63995, 64003, 64010, +  64017, 64024, 64032, 64039, 64046, 64053, 64060, 64068, +  64075, 64082, 64089, 64096, 64103, 64110, 64117, 64124, +  64131, 64138, 64145, 64152, 64159, 64166, 64173, 64179, +  64186, 64193, 64200, 64207, 64213, 64220, 64227, 64234, +  64240, 64247, 64254, 64260, 64267, 64274, 64280, 64287, +  64294, 64300, 64307, 64313, 64320, 64326, 64333, 64339, +  64346, 64352, 64358, 64365, 64371, 64377, 64384, 64390, +  64396, 64403, 64409, 64415, 64422, 64428, 64434, 64440, +  64446, 64452, 64459, 64465, 64471, 64477, 64483, 64489, +  64495, 64501, 64507, 64513, 64519, 64525, 64531, 64537, +  64543, 64549, 64554, 64560, 64566, 64572, 64578, 64583, +  64589, 64595, 64601, 64606, 64612, 64618, 64623, 64629, +  64635, 64640, 64646, 64651, 64657, 64662, 64668, 64673, +  64679, 64684, 64690, 64695, 64701, 64706, 64711, 64717, +  64722, 64728, 64733, 64738, 64743, 64749, 64754, 64759, +  64764, 64770, 64775, 64780, 64785, 64790, 64795, 64800, +  64805, 64810, 64815, 64820, 64825, 64830, 64835, 64840, +  64845, 64850, 64855, 64860, 64865, 64870, 64874, 64879, +  64884, 64889, 64894, 64898, 64903, 64908, 64912, 64917, +  64922, 64926, 64931, 64936, 64940, 64945, 64949, 64954, +  64958, 64963, 64967, 64972, 64976, 64981, 64985, 64989, +  64994, 64998, 65003, 65007, 65011, 65015, 65020, 65024, +  65028, 65032, 65037, 65041, 65045, 65049, 65053, 65057, +  65061, 65065, 65070, 65074, 65078, 65082, 65086, 65090, +  65094, 65097, 65101, 65105, 65109, 65113, 65117, 65121, +  65125, 65128, 65132, 65136, 65140, 65143, 65147, 65151, +  65154, 65158, 65162, 65165, 65169, 65173, 65176, 65180, +  65183, 65187, 65190, 65194, 65197, 65201, 65204, 65207, +  65211, 65214, 65218, 65221, 65224, 65228, 65231, 65234, +  65237, 65241, 65244, 65247, 65250, 65253, 65256, 65260, +  65263, 65266, 65269, 65272, 65275, 65278, 65281, 65284, +  65287, 65290, 65293, 65296, 65299, 65302, 65304, 65307, +  65310, 65313, 65316, 65319, 65321, 65324, 65327, 65329, +  65332, 65335, 65337, 65340, 65343, 65345, 65348, 65350, +  65353, 65356, 65358, 65361, 65363, 65366, 65368, 65370, +  65373, 65375, 65378, 65380, 65382, 65385, 65387, 65389, +  65391, 65394, 65396, 65398, 65400, 65403, 65405, 65407, +  65409, 65411, 65413, 65415, 65417, 65419, 65421, 65423, +  65425, 65427, 65429, 65431, 65433, 65435, 65437, 65439, +  65441, 65442, 65444, 65446, 65448, 65449, 65451, 65453, +  65455, 65456, 65458, 65460, 65461, 65463, 65464, 65466, +  65468, 65469, 65471, 65472, 65474, 65475, 65477, 65478, +  65479, 65481, 65482, 65484, 65485, 65486, 65488, 65489, +  65490, 65491, 65493, 65494, 65495, 65496, 65497, 65499, +  65500, 65501, 65502, 65503, 65504, 65505, 65506, 65507, +  65508, 65509, 65510, 65511, 65512, 65513, 65514, 65515, +  65515, 65516, 65517, 65518, 65519, 65519, 65520, 65521, +  65522, 65522, 65523, 65524, 65524, 65525, 65526, 65526, +  65527, 65527, 65528, 65528, 65529, 65529, 65530, 65530, +  65531, 65531, 65531, 65532, 65532, 65532, 65533, 65533, +  65533, 65534, 65534, 65534, 65534, 65535, 65535, 65535, +  65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, +  65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, +  65535, 65535, 65535, 65534, 65534, 65534, 65534, 65533, +  65533, 65533, 65532, 65532, 65532, 65531, 65531, 65531, +  65530, 65530, 65529, 65529, 65528, 65528, 65527, 65527, +  65526, 65526, 65525, 65524, 65524, 65523, 65522, 65522, +  65521, 65520, 65519, 65519, 65518, 65517, 65516, 65515, +  65515, 65514, 65513, 65512, 65511, 65510, 65509, 65508, +  65507, 65506, 65505, 65504, 65503, 65502, 65501, 65500, +  65499, 65497, 65496, 65495, 65494, 65493, 65491, 65490, +  65489, 65488, 65486, 65485, 65484, 65482, 65481, 65479, +  65478, 65477, 65475, 65474, 65472, 65471, 65469, 65468, +  65466, 65464, 65463, 65461, 65460, 65458, 65456, 65455, +  65453, 65451, 65449, 65448, 65446, 65444, 65442, 65441, +  65439, 65437, 65435, 65433, 65431, 65429, 65427, 65425, +  65423, 65421, 65419, 65417, 65415, 65413, 65411, 65409, +  65407, 65405, 65403, 65400, 65398, 65396, 65394, 65391, +  65389, 65387, 65385, 65382, 65380, 65378, 65375, 65373, +  65370, 65368, 65366, 65363, 65361, 65358, 65356, 65353, +  65350, 65348, 65345, 65343, 65340, 65337, 65335, 65332, +  65329, 65327, 65324, 65321, 65319, 65316, 65313, 65310, +  65307, 65304, 65302, 65299, 65296, 65293, 65290, 65287, +  65284, 65281, 65278, 65275, 65272, 65269, 65266, 65263, +  65260, 65256, 65253, 65250, 65247, 65244, 65241, 65237, +  65234, 65231, 65228, 65224, 65221, 65218, 65214, 65211, +  65207, 65204, 65201, 65197, 65194, 65190, 65187, 65183, +  65180, 65176, 65173, 65169, 65165, 65162, 65158, 65154, +  65151, 65147, 65143, 65140, 65136, 65132, 65128, 65125, +  65121, 65117, 65113, 65109, 65105, 65101, 65097, 65094, +  65090, 65086, 65082, 65078, 65074, 65070, 65065, 65061, +  65057, 65053, 65049, 65045, 65041, 65037, 65032, 65028, +  65024, 65020, 65015, 65011, 65007, 65003, 64998, 64994, +  64989, 64985, 64981, 64976, 64972, 64967, 64963, 64958, +  64954, 64949, 64945, 64940, 64936, 64931, 64926, 64922, +  64917, 64912, 64908, 64903, 64898, 64894, 64889, 64884, +  64879, 64874, 64870, 64865, 64860, 64855, 64850, 64845, +  64840, 64835, 64830, 64825, 64820, 64815, 64810, 64805, +  64800, 64795, 64790, 64785, 64780, 64775, 64770, 64764, +  64759, 64754, 64749, 64743, 64738, 64733, 64728, 64722, +  64717, 64711, 64706, 64701, 64695, 64690, 64684, 64679, +  64673, 64668, 64662, 64657, 64651, 64646, 64640, 64635, +  64629, 64623, 64618, 64612, 64606, 64601, 64595, 64589, +  64583, 64578, 64572, 64566, 64560, 64554, 64549, 64543, +  64537, 64531, 64525, 64519, 64513, 64507, 64501, 64495, +  64489, 64483, 64477, 64471, 64465, 64459, 64452, 64446, +  64440, 64434, 64428, 64422, 64415, 64409, 64403, 64396, +  64390, 64384, 64377, 64371, 64365, 64358, 64352, 64346, +  64339, 64333, 64326, 64320, 64313, 64307, 64300, 64294, +  64287, 64280, 64274, 64267, 64260, 64254, 64247, 64240, +  64234, 64227, 64220, 64213, 64207, 64200, 64193, 64186, +  64179, 64173, 64166, 64159, 64152, 64145, 64138, 64131, +  64124, 64117, 64110, 64103, 64096, 64089, 64082, 64075, +  64068, 64060, 64053, 64046, 64039, 64032, 64024, 64017, +  64010, 64003, 63995, 63988, 63981, 63973, 63966, 63959, +  63951, 63944, 63936, 63929, 63922, 63914, 63907, 63899, +  63892, 63884, 63876, 63869, 63861, 63854, 63846, 63838, +  63831, 63823, 63815, 63808, 63800, 63792, 63784, 63777, +  63769, 63761, 63753, 63745, 63738, 63730, 63722, 63714, +  63706, 63698, 63690, 63682, 63674, 63666, 63658, 63650, +  63642, 63634, 63626, 63618, 63610, 63601, 63593, 63585, +  63577, 63569, 63561, 63552, 63544, 63536, 63527, 63519, +  63511, 63502, 63494, 63486, 63477, 63469, 63461, 63452, +  63444, 63435, 63427, 63418, 63410, 63401, 63393, 63384, +  63375, 63367, 63358, 63350, 63341, 63332, 63324, 63315, +  63306, 63297, 63289, 63280, 63271, 63262, 63253, 63245, +  63236, 63227, 63218, 63209, 63200, 63191, 63182, 63173, +  63164, 63155, 63146, 63137, 63128, 63119, 63110, 63101, +  63092, 63083, 63074, 63064, 63055, 63046, 63037, 63028, +  63018, 63009, 63000, 62991, 62981, 62972, 62963, 62953, +  62944, 62935, 62925, 62916, 62906, 62897, 62887, 62878, +  62868, 62859, 62849, 62840, 62830, 62821, 62811, 62801, +  62792, 62782, 62772, 62763, 62753, 62743, 62734, 62724, +  62714, 62704, 62695, 62685, 62675, 62665, 62655, 62645, +  62635, 62626, 62616, 62606, 62596, 62586, 62576, 62566, +  62556, 62546, 62536, 62526, 62516, 62505, 62495, 62485, +  62475, 62465, 62455, 62445, 62434, 62424, 62414, 62404, +  62393, 62383, 62373, 62362, 62352, 62342, 62331, 62321, +  62311, 62300, 62290, 62279, 62269, 62258, 62248, 62237, +  62227, 62216, 62206, 62195, 62185, 62174, 62163, 62153, +  62142, 62131, 62121, 62110, 62099, 62089, 62078, 62067, +  62056, 62046, 62035, 62024, 62013, 62002, 61991, 61980, +  61970, 61959, 61948, 61937, 61926, 61915, 61904, 61893, +  61882, 61871, 61860, 61849, 61837, 61826, 61815, 61804, +  61793, 61782, 61771, 61759, 61748, 61737, 61726, 61714, +  61703, 61692, 61681, 61669, 61658, 61647, 61635, 61624, +  61612, 61601, 61590, 61578, 61567, 61555, 61544, 61532, +  61521, 61509, 61498, 61486, 61474, 61463, 61451, 61440, +  61428, 61416, 61405, 61393, 61381, 61369, 61358, 61346, +  61334, 61322, 61311, 61299, 61287, 61275, 61263, 61251, +  61240, 61228, 61216, 61204, 61192, 61180, 61168, 61156, +  61144, 61132, 61120, 61108, 61096, 61084, 61071, 61059, +  61047, 61035, 61023, 61011, 60999, 60986, 60974, 60962, +  60950, 60937, 60925, 60913, 60900, 60888, 60876, 60863, +  60851, 60839, 60826, 60814, 60801, 60789, 60777, 60764, +  60752, 60739, 60727, 60714, 60701, 60689, 60676, 60664, +  60651, 60638, 60626, 60613, 60600, 60588, 60575, 60562, +  60550, 60537, 60524, 60511, 60499, 60486, 60473, 60460, +  60447, 60434, 60422, 60409, 60396, 60383, 60370, 60357, +  60344, 60331, 60318, 60305, 60292, 60279, 60266, 60253, +  60240, 60227, 60213, 60200, 60187, 60174, 60161, 60148, +  60134, 60121, 60108, 60095, 60082, 60068, 60055, 60042, +  60028, 60015, 60002, 59988, 59975, 59962, 59948, 59935, +  59921, 59908, 59894, 59881, 59867, 59854, 59840, 59827, +  59813, 59800, 59786, 59773, 59759, 59745, 59732, 59718, +  59704, 59691, 59677, 59663, 59650, 59636, 59622, 59608, +  59595, 59581, 59567, 59553, 59539, 59525, 59512, 59498, +  59484, 59470, 59456, 59442, 59428, 59414, 59400, 59386, +  59372, 59358, 59344, 59330, 59316, 59302, 59288, 59274, +  59260, 59246, 59231, 59217, 59203, 59189, 59175, 59160, +  59146, 59132, 59118, 59103, 59089, 59075, 59061, 59046, +  59032, 59018, 59003, 58989, 58974, 58960, 58946, 58931, +  58917, 58902, 58888, 58873, 58859, 58844, 58830, 58815, +  58801, 58786, 58771, 58757, 58742, 58728, 58713, 58698, +  58684, 58669, 58654, 58640, 58625, 58610, 58595, 58581, +  58566, 58551, 58536, 58521, 58506, 58492, 58477, 58462, +  58447, 58432, 58417, 58402, 58387, 58372, 58357, 58342, +  58327, 58312, 58297, 58282, 58267, 58252, 58237, 58222, +  58207, 58192, 58177, 58162, 58146, 58131, 58116, 58101, +  58086, 58070, 58055, 58040, 58025, 58009, 57994, 57979, +  57963, 57948, 57933, 57917, 57902, 57887, 57871, 57856, +  57840, 57825, 57809, 57794, 57779, 57763, 57748, 57732, +  57716, 57701, 57685, 57670, 57654, 57639, 57623, 57607, +  57592, 57576, 57560, 57545, 57529, 57513, 57498, 57482, +  57466, 57450, 57435, 57419, 57403, 57387, 57371, 57356, +  57340, 57324, 57308, 57292, 57276, 57260, 57244, 57229, +  57213, 57197, 57181, 57165, 57149, 57133, 57117, 57101, +  57085, 57068, 57052, 57036, 57020, 57004, 56988, 56972, +  56956, 56940, 56923, 56907, 56891, 56875, 56859, 56842, +  56826, 56810, 56793, 56777, 56761, 56745, 56728, 56712, +  56696, 56679, 56663, 56646, 56630, 56614, 56597, 56581, +  56564, 56548, 56531, 56515, 56498, 56482, 56465, 56449, +  56432, 56416, 56399, 56382, 56366, 56349, 56333, 56316, +  56299, 56283, 56266, 56249, 56233, 56216, 56199, 56182, +  56166, 56149, 56132, 56115, 56099, 56082, 56065, 56048, +  56031, 56014, 55998, 55981, 55964, 55947, 55930, 55913, +  55896, 55879, 55862, 55845, 55828, 55811, 55794, 55777, +  55760, 55743, 55726, 55709, 55692, 55675, 55658, 55640, +  55623, 55606, 55589, 55572, 55555, 55537, 55520, 55503, +  55486, 55469, 55451, 55434, 55417, 55399, 55382, 55365, +  55347, 55330, 55313, 55295, 55278, 55261, 55243, 55226, +  55208, 55191, 55174, 55156, 55139, 55121, 55104, 55086, +  55069, 55051, 55034, 55016, 54999, 54981, 54963, 54946, +  54928, 54911, 54893, 54875, 54858, 54840, 54822, 54805, +  54787, 54769, 54752, 54734, 54716, 54698, 54681, 54663, +  54645, 54627, 54609, 54592, 54574, 54556, 54538, 54520, +  54502, 54484, 54466, 54449, 54431, 54413, 54395, 54377, +  54359, 54341, 54323, 54305, 54287, 54269, 54251, 54233, +  54215, 54197, 54179, 54160, 54142, 54124, 54106, 54088, +  54070, 54052, 54034, 54015, 53997, 53979, 53961, 53943, +  53924, 53906, 53888, 53870, 53851, 53833, 53815, 53796, +  53778, 53760, 53741, 53723, 53705, 53686, 53668, 53650, +  53631, 53613, 53594, 53576, 53557, 53539, 53520, 53502, +  53483, 53465, 53446, 53428, 53409, 53391, 53372, 53354, +  53335, 53317, 53298, 53279, 53261, 53242, 53224, 53205, +  53186, 53168, 53149, 53130, 53111, 53093, 53074, 53055, +  53037, 53018, 52999, 52980, 52961, 52943, 52924, 52905, +  52886, 52867, 52849, 52830, 52811, 52792, 52773, 52754, +  52735, 52716, 52697, 52678, 52660, 52641, 52622, 52603, +  52584, 52565, 52546, 52527, 52508, 52489, 52469, 52450, +  52431, 52412, 52393, 52374, 52355, 52336, 52317, 52298, +  52278, 52259, 52240, 52221, 52202, 52183, 52163, 52144, +  52125, 52106, 52086, 52067, 52048, 52029, 52009, 51990, +  51971, 51951, 51932, 51913, 51893, 51874, 51855, 51835, +  51816, 51796, 51777, 51758, 51738, 51719, 51699, 51680, +  51660, 51641, 51621, 51602, 51582, 51563, 51543, 51524, +  51504, 51485, 51465, 51446, 51426, 51407, 51387, 51367, +  51348, 51328, 51308, 51289, 51269, 51250, 51230, 51210, +  51190, 51171, 51151, 51131, 51112, 51092, 51072, 51052, +  51033, 51013, 50993, 50973, 50953, 50934, 50914, 50894, +  50874, 50854, 50834, 50815, 50795, 50775, 50755, 50735, +  50715, 50695, 50675, 50655, 50635, 50615, 50596, 50576, +  50556, 50536, 50516, 50496, 50476, 50456, 50436, 50415, +  50395, 50375, 50355, 50335, 50315, 50295, 50275, 50255, +  50235, 50215, 50194, 50174, 50154, 50134, 50114, 50094, +  50073, 50053, 50033, 50013, 49993, 49972, 49952, 49932, +  49912, 49891, 49871, 49851, 49830, 49810, 49790, 49769, +  49749, 49729, 49708, 49688, 49668, 49647, 49627, 49607, +  49586, 49566, 49545, 49525, 49505, 49484, 49464, 49443, +  49423, 49402, 49382, 49361, 49341, 49320, 49300, 49279, +  49259, 49238, 49218, 49197, 49177, 49156, 49135, 49115, +  49094, 49074, 49053, 49032, 49012, 48991, 48971, 48950, +  48929, 48909, 48888, 48867, 48847, 48826, 48805, 48784, +  48764, 48743, 48722, 48701, 48681, 48660, 48639, 48618, +  48598, 48577, 48556, 48535, 48514, 48494, 48473, 48452, +  48431, 48410, 48389, 48368, 48348, 48327, 48306, 48285, +  48264, 48243, 48222, 48201, 48180, 48159, 48138, 48117, +  48097, 48076, 48055, 48034, 48013, 47992, 47971, 47950, +  47929, 47907, 47886, 47865, 47844, 47823, 47802, 47781, +  47760, 47739, 47718, 47697, 47676, 47655, 47633, 47612, +  47591, 47570, 47549, 47528, 47506, 47485, 47464, 47443, +  47422, 47401, 47379, 47358, 47337, 47316, 47294, 47273, +  47252, 47231, 47209, 47188, 47167, 47145, 47124, 47103, +  47082, 47060, 47039, 47018, 46996, 46975, 46954, 46932, +  46911, 46889, 46868, 46847, 46825, 46804, 46783, 46761, +  46740, 46718, 46697, 46675, 46654, 46632, 46611, 46590, +  46568, 46547, 46525, 46504, 46482, 46461, 46439, 46418, +  46396, 46375, 46353, 46331, 46310, 46288, 46267, 46245, +  46224, 46202, 46180, 46159, 46137, 46116, 46094, 46072, +  46051, 46029, 46008, 45986, 45964, 45943, 45921, 45899, +  45878, 45856, 45834, 45812, 45791, 45769, 45747, 45726, +  45704, 45682, 45660, 45639, 45617, 45595, 45573, 45552, +  45530, 45508, 45486, 45465, 45443, 45421, 45399, 45377, +  45355, 45334, 45312, 45290, 45268, 45246, 45224, 45203, +  45181, 45159, 45137, 45115, 45093, 45071, 45049, 45027, +  45006, 44984, 44962, 44940, 44918, 44896, 44874, 44852, +  44830, 44808, 44786, 44764, 44742, 44720, 44698, 44676, +  44654, 44632, 44610, 44588, 44566, 44544, 44522, 44500, +  44478, 44456, 44434, 44412, 44390, 44368, 44346, 44323, +  44301, 44279, 44257, 44235, 44213, 44191, 44169, 44147, +  44124, 44102, 44080, 44058, 44036, 44014, 43992, 43969, +  43947, 43925, 43903, 43881, 43859, 43836, 43814, 43792, +  43770, 43747, 43725, 43703, 43681, 43659, 43636, 43614, +  43592, 43570, 43547, 43525, 43503, 43481, 43458, 43436, +  43414, 43391, 43369, 43347, 43324, 43302, 43280, 43258, +  43235, 43213, 43191, 43168, 43146, 43123, 43101, 43079, +  43056, 43034, 43012, 42989, 42967, 42945, 42922, 42900, +  42877, 42855, 42833, 42810, 42788, 42765, 42743, 42720, +  42698, 42676, 42653, 42631, 42608, 42586, 42563, 42541, +  42518, 42496, 42473, 42451, 42428, 42406, 42384, 42361, +  42339, 42316, 42293, 42271, 42248, 42226, 42203, 42181, +  42158, 42136, 42113, 42091, 42068, 42046, 42023, 42001, +  41978, 41955, 41933, 41910, 41888, 41865, 41842, 41820, +  41797, 41775, 41752, 41730, 41707, 41684, 41662, 41639, +  41616, 41594, 41571, 41549, 41526, 41503, 41481, 41458, +  41435, 41413, 41390, 41367, 41345, 41322, 41299, 41277, +  41254, 41231, 41209, 41186, 41163, 41140, 41118, 41095, +  41072, 41050, 41027, 41004, 40981, 40959, 40936, 40913, +  40891, 40868, 40845, 40822, 40800, 40777, 40754, 40731, +  40709, 40686, 40663, 40640, 40618, 40595, 40572, 40549, +  40526, 40504, 40481, 40458, 40435, 40412, 40390, 40367, +  40344, 40321, 40298, 40276, 40253, 40230, 40207, 40184, +  40161, 40139, 40116, 40093, 40070, 40047, 40024, 40002, +  39979, 39956, 39933, 39910, 39887, 39864, 39841, 39819, +  39796, 39773, 39750, 39727, 39704, 39681, 39658, 39636, +  39613, 39590, 39567, 39544, 39521, 39498, 39475, 39452, +  39429, 39406, 39384, 39361, 39338, 39315, 39292, 39269, +  39246, 39223, 39200, 39177, 39154, 39131, 39108, 39085, +  39062, 39039, 39017, 38994, 38971, 38948, 38925, 38902, +  38879, 38856, 38833, 38810, 38787, 38764, 38741, 38718, +  38695, 38672, 38649, 38626, 38603, 38580, 38557, 38534, +  38511, 38488, 38465, 38442, 38419, 38396, 38373, 38350, +  38327, 38304, 38281, 38258, 38235, 38212, 38189, 38166, +  38143, 38120, 38097, 38074, 38051, 38028, 38005, 37982, +  37958, 37935, 37912, 37889, 37866, 37843, 37820, 37797, +  37774, 37751, 37728, 37705, 37682, 37659, 37636, 37613, +  37590, 37567, 37544, 37520, 37497, 37474, 37451, 37428, +  37405, 37382, 37359, 37336, 37313, 37290, 37267, 37244, +  37220, 37197, 37174, 37151, 37128, 37105, 37082, 37059, +  37036, 37013, 36990, 36966, 36943, 36920, 36897, 36874, +  36851, 36828, 36805, 36782, 36759, 36736, 36712, 36689, +  36666, 36643, 36620, 36597, 36574, 36551, 36528, 36504, +  36481, 36458, 36435, 36412, 36389, 36366, 36343, 36320, +  36296, 36273, 36250, 36227, 36204, 36181, 36158, 36135, +  36112, 36088, 36065, 36042, 36019, 35996, 35973, 35950, +  35927, 35903, 35880, 35857, 35834, 35811, 35788, 35765, +  35742, 35718, 35695, 35672, 35649, 35626, 35603, 35580, +  35557, 35533, 35510, 35487, 35464, 35441, 35418, 35395, +  35372, 35348, 35325, 35302, 35279, 35256, 35233, 35210, +  35187, 35163, 35140, 35117, 35094, 35071, 35048, 35025, +  35002, 34978, 34955, 34932, 34909, 34886, 34863, 34840, +  34817, 34794, 34770, 34747, 34724, 34701, 34678, 34655, +  34632, 34609, 34585, 34562, 34539, 34516, 34493, 34470, +  34447, 34424, 34401, 34377, 34354, 34331, 34308, 34285, +  34262, 34239, 34216, 34193, 34169, 34146, 34123, 34100, +  34077, 34054, 34031, 34008, 33985, 33962, 33938, 33915, +  33892, 33869, 33846, 33823, 33800, 33777, 33754, 33731, +  33707, 33684, 33661, 33638, 33615, 33592, 33569, 33546, +  33523, 33500, 33477, 33454, 33430, 33407, 33384, 33361, +  33338, 33315, 33292, 33269, 33246, 33223, 33200, 33177, +  33154, 33131, 33108, 33084, 33061, 33038, 33015, 32992, +  32969, 32946, 32923, 32900, 32877, 32854, 32831, 32808, +  32785, 32762, 32739, 32716, 32693, 32670, 32647, 32624, +  32601, 32578, 32555, 32532, 32509, 32485, 32462, 32439, +  32416, 32393, 32370, 32347, 32324, 32301, 32278, 32255, +  32232, 32209, 32186, 32163, 32140, 32117, 32094, 32071, +  32048, 32025, 32003, 31980, 31957, 31934, 31911, 31888, +  31865, 31842, 31819, 31796, 31773, 31750, 31727, 31704, +  31681, 31658, 31635, 31612, 31589, 31566, 31543, 31520, +  31497, 31475, 31452, 31429, 31406, 31383, 31360, 31337, +  31314, 31291, 31268, 31245, 31222, 31200, 31177, 31154, +  31131, 31108, 31085, 31062, 31039, 31016, 30994, 30971, +  30948, 30925, 30902, 30879, 30856, 30833, 30811, 30788, +  30765, 30742, 30719, 30696, 30674, 30651, 30628, 30605, +  30582, 30559, 30537, 30514, 30491, 30468, 30445, 30422, +  30400, 30377, 30354, 30331, 30308, 30286, 30263, 30240, +  30217, 30195, 30172, 30149, 30126, 30103, 30081, 30058, +  30035, 30012, 29990, 29967, 29944, 29921, 29899, 29876, +  29853, 29830, 29808, 29785, 29762, 29740, 29717, 29694, +  29671, 29649, 29626, 29603, 29581, 29558, 29535, 29513, +  29490, 29467, 29445, 29422, 29399, 29377, 29354, 29331, +  29309, 29286, 29263, 29241, 29218, 29195, 29173, 29150, +  29128, 29105, 29082, 29060, 29037, 29014, 28992, 28969, +  28947, 28924, 28902, 28879, 28856, 28834, 28811, 28789, +  28766, 28744, 28721, 28698, 28676, 28653, 28631, 28608, +  28586, 28563, 28541, 28518, 28496, 28473, 28451, 28428, +  28406, 28383, 28361, 28338, 28316, 28293, 28271, 28248, +  28226, 28203, 28181, 28158, 28136, 28114, 28091, 28069, +  28046, 28024, 28001, 27979, 27957, 27934, 27912, 27889, +  27867, 27845, 27822, 27800, 27777, 27755, 27733, 27710, +  27688, 27666, 27643, 27621, 27599, 27576, 27554, 27532, +  27509, 27487, 27465, 27442, 27420, 27398, 27375, 27353, +  27331, 27309, 27286, 27264, 27242, 27219, 27197, 27175, +  27153, 27130, 27108, 27086, 27064, 27042, 27019, 26997, +  26975, 26953, 26930, 26908, 26886, 26864, 26842, 26820, +  26797, 26775, 26753, 26731, 26709, 26687, 26664, 26642, +  26620, 26598, 26576, 26554, 26532, 26510, 26488, 26465, +  26443, 26421, 26399, 26377, 26355, 26333, 26311, 26289, +  26267, 26245, 26223, 26201, 26179, 26157, 26135, 26113, +  26091, 26069, 26047, 26025, 26003, 25981, 25959, 25937, +  25915, 25893, 25871, 25849, 25827, 25805, 25783, 25761, +  25739, 25718, 25696, 25674, 25652, 25630, 25608, 25586, +  25564, 25543, 25521, 25499, 25477, 25455, 25433, 25412, +  25390, 25368, 25346, 25324, 25302, 25281, 25259, 25237, +  25215, 25194, 25172, 25150, 25128, 25107, 25085, 25063, +  25041, 25020, 24998, 24976, 24955, 24933, 24911, 24890, +  24868, 24846, 24825, 24803, 24781, 24760, 24738, 24716, +  24695, 24673, 24651, 24630, 24608, 24587, 24565, 24543, +  24522, 24500, 24479, 24457, 24436, 24414, 24393, 24371, +  24350, 24328, 24307, 24285, 24264, 24242, 24221, 24199, +  24178, 24156, 24135, 24113, 24092, 24070, 24049, 24028, +  24006, 23985, 23963, 23942, 23920, 23899, 23878, 23856, +  23835, 23814, 23792, 23771, 23750, 23728, 23707, 23686, +  23664, 23643, 23622, 23600, 23579, 23558, 23537, 23515, +  23494, 23473, 23452, 23430, 23409, 23388, 23367, 23346, +  23324, 23303, 23282, 23261, 23240, 23218, 23197, 23176, +  23155, 23134, 23113, 23092, 23071, 23049, 23028, 23007, +  22986, 22965, 22944, 22923, 22902, 22881, 22860, 22839, +  22818, 22797, 22776, 22755, 22734, 22713, 22692, 22671, +  22650, 22629, 22608, 22587, 22566, 22545, 22524, 22503, +  22482, 22462, 22441, 22420, 22399, 22378, 22357, 22336, +  22316, 22295, 22274, 22253, 22232, 22211, 22191, 22170, +  22149, 22128, 22108, 22087, 22066, 22045, 22025, 22004, +  21983, 21962, 21942, 21921, 21900, 21880, 21859, 21838, +  21818, 21797, 21776, 21756, 21735, 21715, 21694, 21673, +  21653, 21632, 21612, 21591, 21570, 21550, 21529, 21509, +  21488, 21468, 21447, 21427, 21406, 21386, 21365, 21345, +  21324, 21304, 21284, 21263, 21243, 21222, 21202, 21181, +  21161, 21141, 21120, 21100, 21080, 21059, 21039, 21019, +  20998, 20978, 20958, 20937, 20917, 20897, 20876, 20856, +  20836, 20816, 20795, 20775, 20755, 20735, 20715, 20694, +  20674, 20654, 20634, 20614, 20594, 20573, 20553, 20533, +  20513, 20493, 20473, 20453, 20433, 20413, 20392, 20372, +  20352, 20332, 20312, 20292, 20272, 20252, 20232, 20212, +  20192, 20172, 20152, 20132, 20113, 20093, 20073, 20053, +  20033, 20013, 19993, 19973, 19953, 19933, 19914, 19894, +  19874, 19854, 19834, 19814, 19795, 19775, 19755, 19735, +  19716, 19696, 19676, 19656, 19637, 19617, 19597, 19578, +  19558, 19538, 19519, 19499, 19479, 19460, 19440, 19420, +  19401, 19381, 19362, 19342, 19322, 19303, 19283, 19264, +  19244, 19225, 19205, 19186, 19166, 19147, 19127, 19108, +  19088, 19069, 19049, 19030, 19011, 18991, 18972, 18952, +  18933, 18914, 18894, 18875, 18856, 18836, 18817, 18798, +  18778, 18759, 18740, 18720, 18701, 18682, 18663, 18643, +  18624, 18605, 18586, 18567, 18547, 18528, 18509, 18490, +  18471, 18452, 18432, 18413, 18394, 18375, 18356, 18337, +  18318, 18299, 18280, 18261, 18242, 18223, 18204, 18185, +  18166, 18147, 18128, 18109, 18090, 18071, 18052, 18033, +  18014, 17995, 17977, 17958, 17939, 17920, 17901, 17882, +  17863, 17845, 17826, 17807, 17788, 17769, 17751, 17732, +  17713, 17695, 17676, 17657, 17638, 17620, 17601, 17582, +  17564, 17545, 17526, 17508, 17489, 17471, 17452, 17433, +  17415, 17396, 17378, 17359, 17341, 17322, 17304, 17285, +  17267, 17248, 17230, 17211, 17193, 17174, 17156, 17138, +  17119, 17101, 17082, 17064, 17046, 17027, 17009, 16991, +  16972, 16954, 16936, 16917, 16899, 16881, 16863, 16844, +  16826, 16808, 16790, 16772, 16753, 16735, 16717, 16699, +  16681, 16663, 16645, 16626, 16608, 16590, 16572, 16554, +  16536, 16518, 16500, 16482, 16464, 16446, 16428, 16410, +  16392, 16374, 16356, 16338, 16320, 16302, 16285, 16267, +  16249, 16231, 16213, 16195, 16177, 16160, 16142, 16124, +  16106, 16088, 16071, 16053, 16035, 16018, 16000, 15982, +  15964, 15947, 15929, 15911, 15894, 15876, 15858, 15841, +  15823, 15806, 15788, 15771, 15753, 15735, 15718, 15700, +  15683, 15665, 15648, 15630, 15613, 15596, 15578, 15561, +  15543, 15526, 15508, 15491, 15474, 15456, 15439, 15422, +  15404, 15387, 15370, 15353, 15335, 15318, 15301, 15283, +  15266, 15249, 15232, 15215, 15197, 15180, 15163, 15146, +  15129, 15112, 15095, 15078, 15060, 15043, 15026, 15009, +  14992, 14975, 14958, 14941, 14924, 14907, 14890, 14873, +  14856, 14840, 14823, 14806, 14789, 14772, 14755, 14738, +  14721, 14705, 14688, 14671, 14654, 14637, 14621, 14604, +  14587, 14570, 14554, 14537, 14520, 14504, 14487, 14470, +  14454, 14437, 14420, 14404, 14387, 14371, 14354, 14337, +  14321, 14304, 14288, 14271, 14255, 14238, 14222, 14205, +  14189, 14172, 14156, 14140, 14123, 14107, 14091, 14074, +  14058, 14041, 14025, 14009, 13993, 13976, 13960, 13944, +  13927, 13911, 13895, 13879, 13863, 13846, 13830, 13814, +  13798, 13782, 13766, 13750, 13734, 13717, 13701, 13685, +  13669, 13653, 13637, 13621, 13605, 13589, 13573, 13557, +  13541, 13525, 13510, 13494, 13478, 13462, 13446, 13430, +  13414, 13398, 13383, 13367, 13351, 13335, 13320, 13304, +  13288, 13272, 13257, 13241, 13225, 13210, 13194, 13178, +  13163, 13147, 13131, 13116, 13100, 13085, 13069, 13054, +  13038, 13023, 13007, 12992, 12976, 12961, 12945, 12930, +  12914, 12899, 12884, 12868, 12853, 12837, 12822, 12807, +  12792, 12776, 12761, 12746, 12730, 12715, 12700, 12685, +  12669, 12654, 12639, 12624, 12609, 12594, 12579, 12563, +  12548, 12533, 12518, 12503, 12488, 12473, 12458, 12443, +  12428, 12413, 12398, 12383, 12368, 12353, 12338, 12323, +  12309, 12294, 12279, 12264, 12249, 12234, 12220, 12205, +  12190, 12175, 12160, 12146, 12131, 12116, 12102, 12087, +  12072, 12058, 12043, 12028, 12014, 11999, 11985, 11970, +  11955, 11941, 11926, 11912, 11897, 11883, 11868, 11854, +  11840, 11825, 11811, 11796, 11782, 11767, 11753, 11739, +  11724, 11710, 11696, 11682, 11667, 11653, 11639, 11625, +  11610, 11596, 11582, 11568, 11554, 11539, 11525, 11511, +  11497, 11483, 11469, 11455, 11441, 11427, 11413, 11399, +  11385, 11371, 11357, 11343, 11329, 11315, 11301, 11287, +  11273, 11259, 11245, 11232, 11218, 11204, 11190, 11176, +  11163, 11149, 11135, 11121, 11108, 11094, 11080, 11067, +  11053, 11039, 11026, 11012, 10999, 10985, 10971, 10958, +  10944, 10931, 10917, 10904, 10890, 10877, 10863, 10850, +  10836, 10823, 10810, 10796, 10783, 10770, 10756, 10743, +  10730, 10716, 10703, 10690, 10676, 10663, 10650, 10637, +  10624, 10610, 10597, 10584, 10571, 10558, 10545, 10532, +  10519, 10506, 10492, 10479, 10466, 10453, 10440, 10427, +  10414, 10402, 10389, 10376, 10363, 10350, 10337, 10324, +  10311, 10299, 10286, 10273, 10260, 10247, 10235, 10222, +  10209, 10196, 10184, 10171, 10158, 10146, 10133, 10121, +  10108, 10095, 10083, 10070, 10058, 10045, 10033, 10020, +  10008,  9995,  9983,  9970,  9958,  9945,  9933,  9921, +   9908,  9896,  9884,  9871,  9859,  9847,  9834,  9822, +   9810,  9798,  9785,  9773,  9761,  9749,  9737,  9725, +   9712,  9700,  9688,  9676,  9664,  9652,  9640,  9628, +   9616,  9604,  9592,  9580,  9568,  9556,  9544,  9532, +   9521,  9509,  9497,  9485,  9473,  9461,  9450,  9438, +   9426,  9414,  9403,  9391,  9379,  9367,  9356,  9344, +   9332,  9321,  9309,  9298,  9286,  9275,  9263,  9251, +   9240,  9228,  9217,  9205,  9194,  9183,  9171,  9160, +   9148,  9137,  9126,  9114,  9103,  9092,  9080,  9069, +   9058,  9047,  9035,  9024,  9013,  9002,  8990,  8979, +   8968,  8957,  8946,  8935,  8924,  8913,  8902,  8891, +   8880,  8869,  8858,  8847,  8836,  8825,  8814,  8803, +   8792,  8781,  8770,  8759,  8749,  8738,  8727,  8716, +   8705,  8695,  8684,  8673,  8662,  8652,  8641,  8630, +   8620,  8609,  8599,  8588,  8577,  8567,  8556,  8546, +   8535,  8525,  8514,  8504,  8493,  8483,  8472,  8462, +   8452,  8441,  8431,  8421,  8410,  8400,  8390,  8379, +   8369,  8359,  8349,  8338,  8328,  8318,  8308,  8298, +   8288,  8277,  8267,  8257,  8247,  8237,  8227,  8217, +   8207,  8197,  8187,  8177,  8167,  8157,  8147,  8137, +   8128,  8118,  8108,  8098,  8088,  8078,  8069,  8059, +   8049,  8039,  8030,  8020,  8010,  8001,  7991,  7981, +   7972,  7962,  7952,  7943,  7933,  7924,  7914,  7905, +   7895,  7886,  7876,  7867,  7857,  7848,  7839,  7829, +   7820,  7811,  7801,  7792,  7783,  7773,  7764,  7755, +   7746,  7736,  7727,  7718,  7709,  7700,  7691,  7681, +   7672,  7663,  7654,  7645,  7636,  7627,  7618,  7609, +   7600,  7591,  7582,  7573,  7564,  7555,  7547,  7538, +   7529,  7520,  7511,  7502,  7494,  7485,  7476,  7467, +   7459,  7450,  7441,  7433,  7424,  7415,  7407,  7398, +   7390,  7381,  7373,  7364,  7355,  7347,  7338,  7330, +   7322,  7313,  7305,  7296,  7288,  7280,  7271,  7263, +   7255,  7246,  7238,  7230,  7221,  7213,  7205,  7197, +   7189,  7180,  7172,  7164,  7156,  7148,  7140,  7132, +   7124,  7116,  7108,  7100,  7092,  7084,  7076,  7068, +   7060,  7052,  7044,  7036,  7029,  7021,  7013,  7005, +   6997,  6990,  6982,  6974,  6966,  6959,  6951,  6943, +   6936,  6928,  6920,  6913,  6905,  6898,  6890,  6883, +   6875,  6868,  6860,  6853,  6845,  6838,  6830,  6823, +   6815,  6808,  6801,  6793,  6786,  6779,  6772,  6764, +   6757,  6750,  6743,  6735,  6728,  6721,  6714,  6707, +   6700,  6693,  6686,  6678,  6671,  6664,  6657,  6650, +   6643,  6636,  6630,  6623,  6616,  6609,  6602,  6595, +   6588,  6581,  6575,  6568,  6561,  6554,  6548,  6541, +   6534,  6527,  6521,  6514,  6507,  6501,  6494,  6488, +   6481,  6475,  6468,  6461,  6455,  6448,  6442,  6436, +   6429,  6423,  6416,  6410,  6404,  6397,  6391,  6385, +   6378,  6372,  6366,  6359,  6353,  6347,  6341,  6335, +   6329,  6322,  6316,  6310,  6304,  6298,  6292,  6286, +   6280,  6274,  6268,  6262,  6256,  6250,  6244,  6238, +   6232,  6226,  6221,  6215,  6209,  6203,  6197,  6192, +   6186,  6180,  6174,  6169,  6163,  6157,  6152,  6146, +   6140,  6135,  6129,  6124,  6118,  6113,  6107,  6102, +   6096,  6091,  6085,  6080,  6074,  6069,  6064,  6058, +   6053,  6048,  6042,  6037,  6032,  6027,  6021,  6016, +   6011,  6006,  6001,  5995,  5990,  5985,  5980,  5975, +   5970,  5965,  5960,  5955,  5950,  5945,  5940,  5935, +   5930,  5925,  5920,  5915,  5911,  5906,  5901,  5896, +   5891,  5887,  5882,  5877,  5872,  5868,  5863,  5858, +   5854,  5849,  5845,  5840,  5835,  5831,  5826,  5822, +   5817,  5813,  5808,  5804,  5799,  5795,  5791,  5786, +   5782,  5778,  5773,  5769,  5765,  5760,  5756,  5752, +   5748,  5743,  5739,  5735,  5731,  5727,  5723,  5719, +   5714,  5710,  5706,  5702,  5698,  5694,  5690,  5686, +   5682,  5678,  5675,  5671,  5667,  5663,  5659,  5655, +   5651,  5648,  5644,  5640,  5636,  5633,  5629,  5625, +   5622,  5618,  5614,  5611,  5607,  5604,  5600,  5596, +   5593,  5589,  5586,  5582,  5579,  5576,  5572,  5569, +   5565,  5562,  5559,  5555,  5552,  5549,  5545,  5542, +   5539,  5536,  5532,  5529,  5526,  5523,  5520,  5517, +   5514,  5511,  5507,  5504,  5501,  5498,  5495,  5492, +   5489,  5486,  5484,  5481,  5478,  5475,  5472,  5469, +   5466,  5464,  5461,  5458,  5455,  5452,  5450,  5447, +   5444,  5442,  5439,  5436,  5434,  5431,  5429,  5426, +   5424,  5421,  5419,  5416,  5414,  5411,  5409,  5406, +   5404,  5401,  5399,  5397,  5394,  5392,  5390,  5388, +   5385,  5383,  5381,  5379,  5376,  5374,  5372,  5370, +   5368,  5366,  5364,  5362,  5360,  5358,  5356,  5354, +   5352,  5350,  5348,  5346,  5344,  5342,  5340,  5338, +   5336,  5335,  5333,  5331,  5329,  5328,  5326,  5324, +   5322,  5321,  5319,  5317,  5316,  5314,  5313,  5311, +   5309,  5308,  5306,  5305,  5303,  5302,  5301,  5299, +   5298,  5296,  5295,  5294,  5292,  5291,  5290,  5288, +   5287,  5286,  5285,  5283,  5282,  5281,  5280,  5279, +   5278,  5276,  5275,  5274,  5273,  5272,  5271,  5270, +   5269,  5268,  5267,  5266,  5265,  5265,  5264,  5263, +   5262,  5261,  5260,  5260,  5259,  5258,  5257,  5257, +   5256,  5255,  5255,  5254,  5253,  5253,  5252,  5251, +   5251,  5250,  5250,  5249,  5249,  5248,  5248,  5247, +   5247,  5247,  5246,  5246,  5246,  5245,  5245,  5245, +   5244,  5244,  5244,  5244,  5243,  5243,  5243,  5243, +   5243,  5243,  5243,  5243,  5242,  5242,  5242,  5242, +}; diff --git a/fmdriver/fmdriver.h b/fmdriver/fmdriver.h index aebe27e..b31c31e 100644 --- a/fmdriver/fmdriver.h +++ b/fmdriver/fmdriver.h @@ -101,11 +101,17 @@ struct fmdriver_work {    uint8_t ssg_noise_freq;    struct fmdriver_track_status track_status[FMDRIVER_TRACK_NUM];    uint8_t loop_cnt; +  // timerb value +  uint8_t timerb;    // current timerb count    uint32_t timerb_cnt; -  // loop length +  // current timerb count, reset on loop +  uint32_t timerb_cnt_loop; +  // loop length, calculated before playing    uint32_t loop_timerb_cnt;    // fm3ex part map +  bool playing; +  bool paused;  };  #endif // MYON_FMDRIVER_H_INCLUDED diff --git a/fmdriver/fmdriver_fmp.c b/fmdriver/fmdriver_fmp.c index 41d0a48..5e01089 100644 --- a/fmdriver/fmdriver_fmp.c +++ b/fmdriver/fmdriver_fmp.c @@ -304,6 +304,7 @@ static bool fmp_cmd62_tempo(struct fmdriver_work *work,    uint8_t tempo = fmp_part_cmdload(fmp, part);
    fmp->timerb_bak = tempo;
    fmp->timerb = tempo;
 +  work->timerb = fmp->timerb;
    fmp_set_tempo(work, fmp);
    return true;
  }
 @@ -876,6 +877,7 @@ static bool fmp_cmd74_loop(struct fmdriver_work *work,      // 248c
      fmp->loop_cnt++;
      work->loop_cnt = fmp->loop_cnt;
 +    work->timerb_cnt_loop = 0;
      fmp->part_loop_bit = fmp->part_playing_bit;
      // al=2; 1b64();
    }
 @@ -2854,6 +2856,7 @@ static void fmp_timerb(struct fmdriver_work *work, struct driver_fmp *fmp) {    if (fmp->status.stopped) {
      // TODO: stopped
      // jmp 18c7
 +    work->playing = false;
    }
    // 1829
    if (!--fmp->clock_divider) {
 @@ -2989,6 +2992,7 @@ static void fmp_init_parts(struct fmdriver_work *work,    // work->opna_writereg(work, 0x110, 0x80);
    fmp->timerb = 0xca;
 +  work->timerb = fmp->timerb;
    fmp->timerb_bak = 0xca;
    // 3c79
 @@ -3150,7 +3154,10 @@ static void fmp_opna_interrupt(struct fmdriver_work *work) {    struct driver_fmp *fmp = (struct driver_fmp *)work->driver;
    if (work->opna_status(work, 0) & 0x02) {
      fmp_timerb(work, fmp);
 -    work->timerb_cnt++;
 +    if (work->playing) {
 +      work->timerb_cnt++;
 +      work->timerb_cnt_loop++;
 +    }
    }
  }
 @@ -3495,6 +3502,7 @@ void fmp_init(struct fmdriver_work *work, struct driver_fmp *fmp) {    fmp_work_status_init(work, fmp);
    fmdriver_fillpcmname(work->pcmname[0], fmp->pvi_name);
    fmdriver_fillpcmname(work->pcmname[1], fmp->ppz_name);
 +  work->playing = true;
  }
  // 4235
 diff --git a/fmdriver/fmdriver_pmd.c b/fmdriver/fmdriver_pmd.c index 14459a5..ac2cad2 100644 --- a/fmdriver/fmdriver_pmd.c +++ b/fmdriver/fmdriver_pmd.c @@ -353,8 +353,8 @@ static void pmd_calc_tempo_rev(    int timerb = 0;    if (tempo) {      timerb = 0x112c / tempo; -    if (0x112c % tempo) timerb++;      timerb = 0x100 - timerb; +    if ((0x112c % tempo) & 0x80) timerb--;      if (timerb < 0) timerb = 0;    }    pmd->timerb = timerb; @@ -377,6 +377,7 @@ static void pmd_reset_timer(    struct driver_pmd *pmd  ) {    pmd->timerb = 200; +  work->timerb = pmd->timerb;    pmd->timerb_bak = pmd->timerb;    pmd_calc_tempo(pmd);    pmd_timerb_write(work, pmd); @@ -2345,6 +2346,7 @@ static void pmd_cmdfc_tempo(      pmd->tempo_bak = tempo;      pmd_calc_tempo_rev(pmd);    } +  work->timerb = pmd->timerb;  }  // 236b @@ -5537,9 +5539,12 @@ static void pmd_proc_parts(    }    // 130d    if (!pmd->loop.looped || !pmd->loop.ended || pmd->loop.env) { +    work->timerb_cnt_loop = 0;      if (++pmd->status2 == 0xff) pmd->status2 = 1;    } else {      pmd->status2 = 0xff; +    // stop +    work->playing = false;    }    work->loop_cnt = pmd->status2;  } @@ -5627,7 +5632,10 @@ static void pmd_timer(    }    if (status & 2) {      pmd_timerb(work, pmd); -    work->timerb_cnt++; +    if (work->playing) { +      work->timerb_cnt++; +      work->timerb_cnt_loop++; +    }    }  } @@ -5887,6 +5895,7 @@ void pmd_init(struct fmdriver_work *work,    }    fmdriver_fillpcmname(work->pcmname[0], pmd->ppcfile);    fmdriver_fillpcmname(work->pcmname[1], pmd->ppzfile); +  work->playing = true;  }  enum { diff --git a/fmdsp/fmdsp-vramlookup-neon.s b/fmdsp/fmdsp-vramlookup-neon.s index 3cfb957..c5d6db2 100644 --- a/fmdsp/fmdsp-vramlookup-neon.s +++ b/fmdsp/fmdsp-vramlookup-neon.s @@ -22,9 +22,8 @@ fmdsp_vramlookup_neon:    push {lr}  @ load palette    vld3.8 {d26, d28, d30}, [r2]! -  vld1.8 {d27}, [r2]! -  vld1.8 {d29}, [r2]! -  vld1.8 {d31}, [r2]! +  vld3.8 {d27[0], d29[0], d31[0]}, [r2]! +  vld3.8 {d27[1], d29[1], d31[1]}, [r2]!    mov r14, #400  .loopcol: diff --git a/fmdsp/fmdsp.c b/fmdsp/fmdsp.c index fdec110..8f3499e 100644 --- a/fmdsp/fmdsp.c +++ b/fmdsp/fmdsp.c @@ -4,6 +4,8 @@  #include "fmdriver/fmdriver.h"  #include <stdio.h>  #include "libopna/opna.h" +#include "fmdsp_platform_info.h" +#include "version.h"  fmdsp_vramlookup_type fmdsp_vramlookup_func = fmdsp_vramlookup_c; @@ -45,7 +47,7 @@ void fmdsp_init(struct fmdsp *fmdsp, const struct fmdsp_font *font98) {      fmdsp->target_palette[i] = s_palettes[0][i];    }    fmdsp->font98 = font98; -  fmdsp->style = FMDSP_DISPSTYLE_DEFAULT; +  fmdsp->style = FMDSP_DISPSTYLE_ORIGINAL;    fmdsp->style_updated = true;  } @@ -225,6 +227,7 @@ static void fmdsp_track_init_13(struct fmdsp *fmdsp,      }    }  } +  static void fmdsp_track_init_10(struct fmdsp *fmdsp,                                  uint8_t *vram) {    for (int y = 0; y < TRACK_H*FMDSP_TRACK_DISP_CNT_DEFAULT; y++) { @@ -234,7 +237,7 @@ static void fmdsp_track_init_10(struct fmdsp *fmdsp,    }    for (int i = 0; i < FMDSP_TRACK_DISP_CNT_DEFAULT; i++) {      int t; -    if (fmdsp->style == FMDSP_DISPSTYLE_DEFAULT) t = track_disp_table_default[i]; +    if (fmdsp->style == FMDSP_DISPSTYLE_DEFAULT || fmdsp->style == FMDSP_DISPSTYLE_ORIGINAL) t = track_disp_table_default[i];      else if (fmdsp->style == FMDSP_DISPSTYLE_OPN) t = track_disp_table_opn[i];      else t = track_disp_table_ppz8[i];      if (t < 0) continue; @@ -270,6 +273,133 @@ static void fmdsp_track_init_10(struct fmdsp *fmdsp,                  s_bar, BAR_W, BAR_H, 3);      }    } +  if (fmdsp->style == FMDSP_DISPSTYLE_ORIGINAL) { +    vramblit(vram, LOGO_FM_X, LOGO_Y, s_logo_fm, LOGO_FM_W, LOGO_H); +    vramblit(vram, LOGO_DS_X, LOGO_Y, s_logo_ds, LOGO_DS_W, LOGO_H); +    vramblit(vram, LOGO_P_X, LOGO_Y, s_logo_p, LOGO_P_W, LOGO_H); +    fmdsp_putline("MUS", vram, &font_fmdsp_small, TOP_MUS_X, TOP_MUSIC_Y, 2, true); +    fmdsp_putline("IC", vram, &font_fmdsp_small, TOP_IC_X, TOP_MUSIC_Y, 2, true); +    fmdsp_putline("F", vram, &font_fmdsp_small, TOP_F_X, TOP_MUSIC_Y, 2, true); +    fmdsp_putline("ILE", vram, &font_fmdsp_small, TOP_ILE_X, TOP_MUSIC_Y, 2, true); +    fmdsp_putline("SELECTOR", vram, &font_fmdsp_small, TOP_SELECTOR_X, TOP_MUSIC_Y, 2, true); +    fmdsp_putline("&", vram, &font_fmdsp_small, TOP_AND_X, TOP_MUSIC_Y, 2, true); +    fmdsp_putline("STATUS", vram, &font_fmdsp_small, TOP_STATUS_X, TOP_MUSIC_Y, 2, true); +    fmdsp_putline("D", vram, &font_fmdsp_small, TOP_D_X, TOP_MUSIC_Y, 2, true); +    fmdsp_putline("ISPLAY", vram, &font_fmdsp_small, TOP_ISPLAY_X, TOP_MUSIC_Y, 2, true); +    vramblit(vram, TOP_VER_X, VER_Y, s_ver, VER_W, VER_H); +    fmdsp_putline(FMPLAYER_VERSION_0 ".", vram, &font_fmdsp_small, VER_0_X, TOP_MUSIC_Y, 2, true); +    fmdsp_putline(FMPLAYER_VERSION_1 ".", vram, &font_fmdsp_small, VER_1_X, TOP_MUSIC_Y, 2, true); +    fmdsp_putline(FMPLAYER_VERSION_2, vram, &font_fmdsp_small, VER_2_X, TOP_MUSIC_Y, 2, true); +     +    vramblit(vram, TOP_MUS_X, TOP_TEXT_Y, s_text, TOP_TEXT_W, TOP_TEXT_H); + +    fmdsp_putline("DR", vram, &font_fmdsp_small, DRIVER_TEXT_X, DRIVER_TEXT_Y, 7, true); +    fmdsp_putline("IVER", vram, &font_fmdsp_small, DRIVER_TEXT_2_X, DRIVER_TEXT_Y, 7, true); +    vramblit_color(vram, DRIVER_TRI_X, DRIVER_TRI_Y, s_filebar_tri, FILEBAR_TRI_W, FILEBAR_TRI_H, 7); +    vramblit(vram, CURL_LEFT_X, CURL_Y, s_curl_left, CURL_W, CURL_H); +    vramblit(vram, CURL_RIGHT_X, CURL_Y, s_curl_right, CURL_W, CURL_H); + +    for (int x = 0; x < 82; x++) { +      vram[14*PC98_W+312+x] = 2; +    } +    for (int x = 0; x < 239; x++) { +      vram[14*PC98_W+395+x] = 7; +    } +    for (int x = 0; x < TIME_BAR_W; x++) { +      for (int y = 0; y < TIME_BAR_H; y++) { +        vram[(TIME_Y-2+y)*PC98_W+TIME_BAR_X+x] = 2; +        vram[(CLOCK_Y-2+y)*PC98_W+TIME_BAR_X+x] = 2; +        vram[(TIMERB_Y-2+y)*PC98_W+TIME_BAR_X+x] = 2; +        vram[(LOOPCNT_Y-2+y)*PC98_W+TIME_BAR_X+x] = 2; +        vram[(VOLDOWN_Y-2+y)*PC98_W+TIME_BAR_X+x] = 2; +        vram[(PGMNUM_Y-2+y)*PC98_W+TIME_BAR_X+x] = 2; +      } +    } +    for (int i = 0; i < 6; i++) { +      vramblit(vram, TIME_TRI_X, TIME_Y+8+19*i, s_filebar_tri, FILEBAR_TRI_W, FILEBAR_TRI_H); +    } +    fmdsp_putline("PASSED", vram, &font_fmdsp_small, TIME_TEXT_X, TIME_Y-2, 2, true); +    fmdsp_putline("T", vram, &font_fmdsp_small, TIME_TEXT_X+11, TIME_Y+5, 2, true); +    fmdsp_putline("IME", vram, &font_fmdsp_small, TIME_TEXT_X+15, TIME_Y+5, 2, true); +    fmdsp_putline("CLOCK", vram, &font_fmdsp_small, TIME_TEXT_X, CLOCK_Y-2, 2, true); +    fmdsp_putline(" COUNT", vram, &font_fmdsp_small, TIME_TEXT_X, CLOCK_Y+5, 2, true); +    fmdsp_putline("T", vram, &font_fmdsp_small, TIME_TEXT_X, TIMERB_Y-2, 2, true); +    fmdsp_putline("IMER", vram, &font_fmdsp_small, TIME_TEXT_X+4, TIMERB_Y-2, 2, true); +    fmdsp_putline(" CYCLE", vram, &font_fmdsp_small, TIME_TEXT_X, TIMERB_Y+5, 2, true); +    fmdsp_putline("LOOP", vram, &font_fmdsp_small, TIME_TEXT_X, LOOPCNT_Y-2, 2, true); +    fmdsp_putline(" COUNT", vram, &font_fmdsp_small, TIME_TEXT_X, LOOPCNT_Y+5, 2, true); +    fmdsp_putline("VOLUME", vram, &font_fmdsp_small, TIME_TEXT_X, VOLDOWN_Y-2, 2, true); +    fmdsp_putline("  DOWN", vram, &font_fmdsp_small, TIME_TEXT_X, VOLDOWN_Y+5, 2, true); +    fmdsp_putline("PGM", vram, &font_fmdsp_small, TIME_TEXT_X, PGMNUM_Y-2, 2, true); +    fmdsp_putline("NUMBER", vram, &font_fmdsp_small, TIME_TEXT_X, PGMNUM_Y+5, 2, true); + +    for (int x = 0; x < TIME_BAR_W; x++) { +      for (int y = 0; y < TIME_BAR_H; y++) { +        vram[(CPU_Y+y)*PC98_W+CPU_BAR_X+x] = 2; +      } +    } +    fmdsp_putline("CPU", vram, &font_fmdsp_small, CPU_X, CPU_Y, 2, true); +    fmdsp_putline("POWER", vram, &font_fmdsp_small, CPU_X+17, CPU_Y, 2, true); +    fmdsp_putline("COUNT", vram, &font_fmdsp_small, CPU_X+17, CPU_Y+7, 2, true); +    vramblit(vram, CPU_TRI_X, CPU_TRI_Y, s_filebar_tri, FILEBAR_TRI_W, FILEBAR_TRI_H); +    for (int x = 0; x < TIME_BAR_W; x++) { +      for (int y = 0; y < TIME_BAR_H; y++) { +        vram[(CPU_Y+y)*PC98_W+FPS_BAR_X+x] = 2; +      } +    } +    fmdsp_putline("FRAMES", vram, &font_fmdsp_small, FPS_X, CPU_Y, 2, true); +    fmdsp_putline("PER", vram, &font_fmdsp_small, FPS_X+32, CPU_Y, 2, true); +    fmdsp_putline("SECOND", vram, &font_fmdsp_small, FPS_X+17, CPU_Y+7, 2, true); +    vramblit(vram, FPS_TRI_X, CPU_TRI_Y, s_filebar_tri, FILEBAR_TRI_W, FILEBAR_TRI_H); +    for (int x = 0; x < 322; x++) { +      vram[132*PC98_W+312+x] = 7; +    } +    fmdsp_putline("SENS", vram, &font_fmdsp_small, SPECTRUM_X-40, SPECTRUM_Y-6, 7, true); +    fmdsp_putline("-48", vram, &font_fmdsp_small, SPECTRUM_X-19, SPECTRUM_Y-6, 7, true); +    fmdsp_putline("0", vram, &font_fmdsp_small, SPECTRUM_X-9, SPECTRUM_Y-63, 7, true); +    fmdsp_putline("dB", vram, &font_fmdsp_small, SPECTRUM_X-14, SPECTRUM_Y-71, 7, true); +    fmdsp_putline("SPECTRUM", vram, &font_fmdsp_small, SPECTRUM_X+197, SPECTRUM_Y-71, 7, true); +    fmdsp_putline("ANAL", vram, &font_fmdsp_small, SPECTRUM_X+241, SPECTRUM_Y-71, 7, true); +    fmdsp_putline("YzER", vram, &font_fmdsp_small, SPECTRUM_X+260, SPECTRUM_Y-71, 7, true); +    for (int y = 0; y < 63; y++) { +      vram[(SPECTRUM_Y-y)*PC98_W+SPECTRUM_X-2] = 2; +      if (!(y % 2)) { +        vram[(SPECTRUM_Y-y)*PC98_W+SPECTRUM_X-3] = 2; +      } +      if (!(y % 8)) { +        vram[(SPECTRUM_Y-y)*PC98_W+SPECTRUM_X-4] = 2; +      } +    } +    fmdsp_putline("FREQ", vram, &font_fmdsp_small, SPECTRUM_X-24, SPECTRUM_Y+1, 1, true); +    for (int x = 0; x < 17; x++) { +      vram[(SPECTRUM_Y+4)*PC98_W+SPECTRUM_X+1+2*x] = 1; +    } +    fmdsp_putline("250", vram, &font_fmdsp_small, SPECTRUM_X+36, SPECTRUM_Y+1, 1, true); +    for (int x = 0; x < 15; x++) { +      vram[(SPECTRUM_Y+4)*PC98_W+SPECTRUM_X+52+2*x] = 1; +    } +    fmdsp_putline("500", vram, &font_fmdsp_small, SPECTRUM_X+83, SPECTRUM_Y+1, 1, true); +    for (int x = 0; x < 17; x++) { +      vram[(SPECTRUM_Y+4)*PC98_W+SPECTRUM_X+99+2*x] = 1; +    } +    fmdsp_putline("1", vram, &font_fmdsp_small, SPECTRUM_X+133, SPECTRUM_Y+1, 1, true); +    fmdsp_putline("k", vram, &font_fmdsp_small, SPECTRUM_X+133+6, SPECTRUM_Y+1, 1, true); +    for (int x = 0; x < 19; x++) { +      vram[(SPECTRUM_Y+4)*PC98_W+SPECTRUM_X+144+2*x] = 1; +    } +    fmdsp_putline("2k", vram, &font_fmdsp_small, SPECTRUM_X+183, SPECTRUM_Y+1, 1, true); +    for (int x = 0; x < 18; x++) { +      vram[(SPECTRUM_Y+4)*PC98_W+SPECTRUM_X+193+2*x] = 1; +    } +    fmdsp_putline("4k", vram, &font_fmdsp_small, SPECTRUM_X+230, SPECTRUM_Y+1, 1, true); +    for (int x = 0; x < 20; x++) { +      vram[(SPECTRUM_Y+4)*PC98_W+SPECTRUM_X+240+2*x] = 1; +    } +    fmdsp_putline("ON/OFF", vram, &font_fmdsp_small, LEVEL_TEXT_X, LEVEL_TEXT_Y, 1, true); +    fmdsp_putline("PANPOT", vram, &font_fmdsp_small, LEVEL_TEXT_X, LEVEL_TEXT_Y+8, 1, true); +    fmdsp_putline("PROGRAM", vram, &font_fmdsp_small, LEVEL_TEXT_X-5, LEVEL_TEXT_Y+16, 1, true); +    fmdsp_putline("KEYCODE", vram, &font_fmdsp_small, LEVEL_TEXT_X-5, LEVEL_TEXT_Y+23, 1, true); +  }  }  void fmdsp_vram_init(struct fmdsp *fmdsp, @@ -551,7 +681,8 @@ static void fmdsp_track_without_key(    fmdsp_putline("TN:", vram, &font_fmdsp_small, TDETAIL_TN_X, y+6, 1, true);    snprintf(numbuf, sizeof(numbuf), "%03d", track->tonenum);    fmdsp_putline(numbuf, vram, &font_fmdsp_small, TDETAIL_TN_V_X, y+6, 1, true); -  fmdsp_putline("VL:", vram, &font_fmdsp_small, TDETAIL_VL_X, y+6, 1, true); +  fmdsp_putline("Vl", vram, &font_fmdsp_small, TDETAIL_VL_X, y+6, 1, true); +  fmdsp_putline(":", vram, &font_fmdsp_small, TDETAIL_VL_C_X, y+6, 1, true);    snprintf(numbuf, sizeof(numbuf), "%03d", track->volume);    fmdsp_putline(numbuf, vram, &font_fmdsp_small, TDETAIL_VL_V_X, y+6, 1, true);    fmdsp_putline("GT:", vram, &font_fmdsp_small, TDETAIL_GT_X, y+6, 1, true); @@ -583,45 +714,50 @@ static void fmdsp_track_without_key(  static void fmdsp_update_10(struct fmdsp *fmdsp,                    const struct fmdriver_work *work,                    const struct opna *opna, -                  uint8_t *vram) { -  for (int y = 0; y < 320; y++) { -    for (int x = 320; x < PC98_W; x++) { -      vram[y*PC98_W+x] = 0; +                  uint8_t *vram, +                  struct fmplayer_fft_input_data *idata) { +  if (fmdsp->style != FMDSP_DISPSTYLE_ORIGINAL) { +    for (int y = 0; y < 320; y++) { +      for (int x = 320; x < PC98_W; x++) { +        vram[y*PC98_W+x] = 0; +      }      }    }    for (int it = 0; it < FMDSP_TRACK_DISP_CNT_DEFAULT; it++) {      int t; -    if (fmdsp->style == FMDSP_DISPSTYLE_DEFAULT) t = track_disp_table_default[it]; +    if (fmdsp->style == FMDSP_DISPSTYLE_DEFAULT || fmdsp->style == FMDSP_DISPSTYLE_ORIGINAL) t = track_disp_table_default[it];      else if (fmdsp->style == FMDSP_DISPSTYLE_OPN) t = track_disp_table_opn[it];      else t = track_disp_table_ppz8[it];      if (t < 0) continue;      const struct fmdriver_track_status *track = &work->track_status[t]; -    if (((track->info == FMDRIVER_TRACK_INFO_PPZ8) -         || (track->info == FMDRIVER_TRACK_INFO_PDZF)) -        && track->ppz8_ch) { -      fmdsp_track_info_ppz8(work->ppz8, track->ppz8_ch-1, -                            320, TRACK_H*it+6, vram); -    } else { -      switch (track_type_table[t].type) { -      case FMDRIVER_TRACKTYPE_FM: -        fmdsp_track_info_fm(opna, -                            track_type_table[t].num-1, -                            track->info == FMDRIVER_TRACK_INFO_FM3EX ? track->fmslotmask : 0, -                            320, TRACK_H*it+6, vram); -        break; -      case FMDRIVER_TRACKTYPE_SSG: -        fmdsp_track_info_ssg(opna, -                            track_type_table[t].num-1, -                            320, TRACK_H*it+6, vram); -        break; -      case FMDRIVER_TRACKTYPE_ADPCM: -        fmdsp_track_info_adpcm(opna, 320, TRACK_H*it+6, vram); -        break; -      case FMDRIVER_TRACKTYPE_PPZ8: -        fmdsp_track_info_ppz8(work->ppz8, track_type_table[t].num-1, +    if (fmdsp->style != FMDSP_DISPSTYLE_ORIGINAL) { +      if (((track->info == FMDRIVER_TRACK_INFO_PPZ8) +          || (track->info == FMDRIVER_TRACK_INFO_PDZF)) +          && track->ppz8_ch) { +        fmdsp_track_info_ppz8(work->ppz8, track->ppz8_ch-1,                                320, TRACK_H*it+6, vram); -        break; +      } else { +        switch (track_type_table[t].type) { +        case FMDRIVER_TRACKTYPE_FM: +          fmdsp_track_info_fm(opna, +                              track_type_table[t].num-1, +                              track->info == FMDRIVER_TRACK_INFO_FM3EX ? track->fmslotmask : 0, +                              320, TRACK_H*it+6, vram); +          break; +        case FMDRIVER_TRACKTYPE_SSG: +          fmdsp_track_info_ssg(opna, +                              track_type_table[t].num-1, +                              320, TRACK_H*it+6, vram); +          break; +        case FMDRIVER_TRACKTYPE_ADPCM: +          fmdsp_track_info_adpcm(opna, 320, TRACK_H*it+6, vram); +          break; +        case FMDRIVER_TRACKTYPE_PPZ8: +          fmdsp_track_info_ppz8(work->ppz8, track_type_table[t].num-1, +                                320, TRACK_H*it+6, vram); +          break; +        }        }      }      fmdsp_track_without_key(fmdsp, work, track, t, TRACK_H*it, vram); @@ -642,6 +778,167 @@ static void fmdsp_update_10(struct fmdsp *fmdsp,        }      }    } +  if (fmdsp->style == FMDSP_DISPSTYLE_ORIGINAL) { +    // control status +    bool playing = work->playing && !work->paused; +    bool stopped = !work->playing; +    bool paused = work->paused; +    vramblit_color(vram, PLAY_X, PLAY_Y, s_play, PLAY_W, PLAY_H, playing ? 2 : 3); +    vramblit_color(vram, STOP_X, STOP_Y, s_stop, STOP_W, STOP_H, stopped ? 2 : 3); +    vramblit_color(vram, PAUSE_X, PAUSE_Y, s_pause, PAUSE_W, PAUSE_H, paused ? 2 : 3); +    vramblit(vram, FADE_X, FADE_Y, s_fade, FADE_W, FADE_H); +    vramblit(vram, FF_X, FF_Y, s_ff, FF_W, FF_H); +    vramblit(vram, REW_X, REW_Y, s_rew, REW_W, REW_H); +    vramblit(vram, FLOPPY_X, FLOPPY_Y, s_floppy, FLOPPY_W, FLOPPY_H); +    const uint8_t *num[8]; +    // passed time +    { +      uint64_t frames = opna->generated_frames; +      int ssec = (int)(frames % 55467u) * 100 / 55467; +      uint64_t sec = frames / 55467u; +      uint64_t min = sec / 60u; +      sec %= 60u; +      num[0] = s_num[(min/10)%10]; +      num[1] = s_num[min%10]; +      vramblit(vram, TIME_X+NUM_W*0, TIME_Y, num[0], NUM_W, NUM_H); +      vramblit(vram, TIME_X+NUM_W*1, TIME_Y, num[1], NUM_W, NUM_H); +      vramblit(vram, TIME_X+NUM_W*2, TIME_Y, s_num_colon[sec%2u], NUM_W, NUM_H); +      num[0] = s_num[(sec/10)%10]; +      num[1] = s_num[sec%10]; +      vramblit(vram, TIME_X+NUM_W*3, TIME_Y, num[0], NUM_W, NUM_H); +      vramblit(vram, TIME_X+NUM_W*4, TIME_Y, num[1], NUM_W, NUM_H); +      vramblit(vram, TIME_X+NUM_W*5, TIME_Y, s_num_bar, NUM_W, NUM_H); +      num[0] = s_num[(ssec/10)%10]; +      num[1] = s_num[ssec%10]; +      vramblit(vram, TIME_X+NUM_W*6, TIME_Y, num[0], NUM_W, NUM_H); +      vramblit(vram, TIME_X+NUM_W*7, TIME_Y, num[1], NUM_W, NUM_H); +    } +    // clock count +    { +      uint64_t clock = work->timerb_cnt; +      for (int i = 0; i < 8; i++) { +        num[7-i] = s_num[clock%10u]; +        clock /= 10u; +      } +      for (int i = 0; i < 8; i++) { +        vramblit(vram, TIME_X+NUM_W*i, CLOCK_Y, num[i], NUM_W, NUM_H); +      } +    } +    // timerb +    { +      uint8_t timerb = work->timerb; +      for (int i = 0; i < 3; i++) { +        num[2-i] = s_num[timerb%10]; +        timerb /= 10; +      } +      for (int i = 0; i < 3; i++) { +        vramblit(vram, TIME_X+NUM_W*(5+i), TIMERB_Y, num[i], NUM_W, NUM_H); +      } +    } +    // loop count +    { +      uint8_t loop = work->loop_cnt; +      for (int i = 0; i < 4; i++) { +        num[3-i] = s_num[loop%10]; +        loop /= 10; +      } +      for (int i = 0; i < 4; i++) { +        vramblit(vram, TIME_X+NUM_W*(4+i), LOOPCNT_Y, num[i], NUM_W, NUM_H); +      } +    } +    // +    int pos = 0; +    if (work->loop_timerb_cnt) pos = work->timerb_cnt_loop * (72+1-4) / work->loop_timerb_cnt; +    for (int x = 0; x < 72; x++) { +      if (x == 0 || x == 36 || x == 71) { +        vram[(70-2)*PC98_W+352+x*2] = 7; +      } else if (!(x % 9)) { +        vram[(70-2)*PC98_W+352+x*2] = 3; +      } +      uint8_t c = 3; +      if (work->playing && ((pos <= x) && (x < (pos+4)))) c = 2; +      for (int y = 0; y < 4; y++) { +        vram[(70+y)*PC98_W+352+x*2] = c; +      } +    } +    for (int x = 0; x < 16; x++) { +      for (int y = 0; y < 4; y++) { +        vram[(70+y)*PC98_W+496+x] = work->loop_cnt ? 7 : 3; +      } +    } +    // cpu +    int cpuusage = fmdsp->cpuusage; +    for (int i = 0; i < 3; i++) { +      num[2-i] = s_num[cpuusage % 10]; +      cpuusage /= 10; +    } +    for (int i = 0; i < 3; i++) { +      vramblit(vram, CPU_NUM_X+NUM_W*i, CPU_NUM_Y, num[i], NUM_W, NUM_H); +    } +    // fps +    int fps = fmdsp->fps; +    for (int i = 0; i < 3; i++) { +      num[2-i] = s_num[fps % 10]; +      fps /= 10; +    } +    for (int i = 0; i < 3; i++) { +      vramblit(vram, FPS_NUM_X+NUM_W*i, CPU_NUM_Y, num[i], NUM_W, NUM_H); +    } +    // circle +    for (int y = 0; y < CIRCLE_H; y++) { +      for (int x = 0; x < CIRCLE_W; x++) { +        int c = 0; +        int clock = (work->timerb_cnt / 8) % 8; +        int p; +        if ((p = s_circle[y*CIRCLE_W+x])) { +          c = (work->playing && (!work->paused || (fmdsp->framecnt % 60) < 30) && (p == (clock + 1))) ? 2 : 3; +        } +        vram[(CIRCLE_Y+y)*PC98_W+CIRCLE_X+x] = c; +      } +    } +    // fft +    struct fmplayer_fft_disp_data ddata; +    fft_calc(&ddata, idata); +    for (int x = 0; x < FFTDISPLEN; x++) { +      for (int y = 0; y < 32; y++) { +        int px = SPECTRUM_X+x*4; +        int py = SPECTRUM_Y-y*2; +        int c = y < ddata.buf[x] ? 2 : 3; +        vram[py*PC98_W+px+0] = c; +        vram[py*PC98_W+px+1] = c; +        vram[py*PC98_W+px+2] = c; +      } +    } +    for (int i = 0; i < FFTDISPLEN; i++) { +      if (fmdsp->fftdata[i] <= ddata.buf[i]) { +        fmdsp->fftdata[i] = ddata.buf[i]; +        fmdsp->fftcnt[i] = 30; +      } else { +        if (fmdsp->fftcnt[i]) { +          fmdsp->fftcnt[i]--; +        } else { +          if (fmdsp->fftdata[i]) { +            if (fmdsp->fftdropdiv[i]) { +              fmdsp->fftdropdiv[i]--; +            } else { +              static const uint8_t divtab[16] = { +                32, 16, 8, 8, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, +              }; +              fmdsp->fftdropdiv[i] = divtab[fmdsp->fftdata[i] / 2]; +              fmdsp->fftdata[i]--; +            } +          } +        } +      } +    } +    for (int x = 0; x < FFTDISPLEN; x++) { +      int px = SPECTRUM_X+x*4; +      int py = SPECTRUM_Y-fmdsp->fftdata[x]*2; +      vram[py*PC98_W+px+0] = 7; +      vram[py*PC98_W+px+1] = 7; +      vram[py*PC98_W+px+2] = 7; +    } +  }  }  static void fmdsp_update_13(struct fmdsp *fmdsp,                    const struct fmdriver_work *work, @@ -701,7 +998,8 @@ static void fmdsp_update_13(struct fmdsp *fmdsp,  void fmdsp_update(struct fmdsp *fmdsp,                    const struct fmdriver_work *work,                    const struct opna *opna, -                  uint8_t *vram) { +                  uint8_t *vram, +                  struct fmplayer_fft_input_data *idata) {    if (fmdsp->style_updated) {      if (fmdsp->style == FMDSP_DISPSTYLE_13) {        fmdsp_track_init_13(fmdsp, vram); @@ -739,9 +1037,14 @@ void fmdsp_update(struct fmdsp *fmdsp,    if (fmdsp->style == FMDSP_DISPSTYLE_13) {      fmdsp_update_13(fmdsp, work, opna, vram);    } else { -    fmdsp_update_10(fmdsp, work, opna, vram); +    fmdsp_update_10(fmdsp, work, opna, vram, idata);    }    fmdsp_palette_fade(fmdsp); +  if (!(fmdsp->framecnt % 30)) { +    fmdsp->cpuusage = fmdsp_cpu_usage(); +    fmdsp->fps = fmdsp_fps_30(); +  } +  fmdsp->framecnt++;  }  void fmdsp_vrampalette(struct fmdsp *fmdsp, const uint8_t *vram, uint8_t *vram32, int stride) { diff --git a/fmdsp/fmdsp.h b/fmdsp/fmdsp.h index 1aba5d9..6a98707 100644 --- a/fmdsp/fmdsp.h +++ b/fmdsp/fmdsp.h @@ -5,6 +5,7 @@  #include <stdbool.h>  #include "font.h"  #include "fmdriver/fmdriver.h" +#include "fft/fft.h"  #ifdef __cplusplus  extern "C" { @@ -18,10 +19,11 @@ enum {  };  enum { -  FMDSP_PALETTE_COLORS = 9 +  FMDSP_PALETTE_COLORS = 10  };  enum FMDSP_DISPSTYLE { +  FMDSP_DISPSTYLE_ORIGINAL,    FMDSP_DISPSTYLE_DEFAULT,    FMDSP_DISPSTYLE_OPN,    FMDSP_DISPSTYLE_PPZ8, @@ -36,6 +38,12 @@ struct fmdsp {    enum FMDSP_DISPSTYLE style;    bool style_updated;    bool masked[FMDRIVER_TRACK_NUM]; +  uint8_t fftdata[FFTDISPLEN]; +  uint8_t fftcnt[FFTDISPLEN]; +  uint8_t fftdropdiv[FFTDISPLEN]; +  uint64_t framecnt; +  int cpuusage; +  int fps;  };  struct fmdriver_work; @@ -44,7 +52,9 @@ void fmdsp_vram_init(struct fmdsp *fmdsp,                       struct fmdriver_work *work,                       uint8_t *vram);  void fmdsp_update(struct fmdsp *fmdsp, const struct fmdriver_work *work, -                  const struct opna *opna, uint8_t *vram); +                  const struct opna *opna, uint8_t *vram, +                  struct fmplayer_fft_input_data *idata +                 );  void fmdsp_vrampalette(struct fmdsp *fmdsp, const uint8_t *vram, uint8_t *vram32, int stride);  void fmdsp_font_from_fontrom(uint8_t *font, const uint8_t *fontrom);  void fmdsp_palette_set(struct fmdsp *fmdsp, int p); diff --git a/fmdsp/fmdsp_platform_info.h b/fmdsp/fmdsp_platform_info.h new file mode 100644 index 0000000..9afb2d6 --- /dev/null +++ b/fmdsp/fmdsp_platform_info.h @@ -0,0 +1,9 @@ +#ifndef MYON_FMPLAYER_FMDSP_PLATFORM_INFO_H_INCLUDED +#define MYON_FMPLAYER_FMDSP_PLATFORM_INFO_H_INCLUDED + +int fmdsp_cpu_usage(void); + +// call once per 30 frames to obtain fps +int fmdsp_fps_30(void); + +#endif // MYON_FMPLAYER_FMDSP_PLATFORM_INFO_H_INCLUDED diff --git a/fmdsp/fmdsp_platform_unix.c b/fmdsp/fmdsp_platform_unix.c new file mode 100644 index 0000000..446cee7 --- /dev/null +++ b/fmdsp/fmdsp_platform_unix.c @@ -0,0 +1,44 @@ +#include "fmdsp_platform_info.h" +#include <sys/times.h> +#include <time.h> +#include <limits.h> +#include <stdint.h> + +static struct { +  clock_t lastall; +  clock_t lastcpu; +  struct timespec lasttimespec; +} g; + +int fmdsp_cpu_usage(void) { +  struct tms tmsbuf; +  clock_t all = times(&tmsbuf); +  clock_t cpu = tmsbuf.tms_utime + tmsbuf.tms_stime; +  clock_t percentage = 0; +  clock_t alld = all - g.lastall; +  clock_t cpud = cpu - g.lastcpu; +  if (alld) percentage = cpud * 100 / alld; +  g.lastall = all; +  g.lastcpu = cpu; +  if (!g.lastall) percentage = 0; +  if (percentage > INT_MAX) percentage = INT_MAX; +  if (percentage < 0) percentage = 0; +  return percentage; +} + +int fmdsp_fps_30(void) { +  struct timespec time; +  clock_gettime(CLOCK_MONOTONIC, &time); +  uint64_t fps = 0; +  if (g.lasttimespec.tv_sec || g.lasttimespec.tv_nsec) { +    uint64_t diffns = time.tv_sec - g.lasttimespec.tv_sec; +    diffns *= 1000000000ull; +    diffns += time.tv_nsec - g.lasttimespec.tv_nsec; +    if (diffns) { +      fps = 30ull * 1000000000ull / diffns; +    } +  } +  g.lasttimespec = time; +  if (fps > INT_MAX) fps = INT_MAX; +  return fps; +} diff --git a/fmdsp/fmdsp_platform_win.c b/fmdsp/fmdsp_platform_win.c new file mode 100644 index 0000000..3dc4074 --- /dev/null +++ b/fmdsp/fmdsp_platform_win.c @@ -0,0 +1,57 @@ +#include "fmdsp_platform_info.h" +#include <stdint.h> +#include <limits.h> +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +static struct { +  HANDLE currproc; +  uint64_t lastall; +  uint64_t lastcpu; +  uint64_t lastfpstime; +} g; + +int fmdsp_cpu_usage(void) { +  if (!g.currproc) g.currproc = GetCurrentProcess(); +  FILETIME ft_sys, ft_creat, ft_exit, ft_kern, ft_user; +  GetSystemTimeAsFileTime(&ft_sys); +  GetProcessTimes(g.currproc, &ft_creat, &ft_exit, &ft_kern, &ft_user); +  uint64_t all = ft_sys.dwHighDateTime; +  all <<= 32; +  all |= ft_sys.dwLowDateTime; +  uint64_t kern = ft_kern.dwHighDateTime; +  kern <<= 32; +  kern |= ft_kern.dwLowDateTime; +  uint64_t user = ft_user.dwHighDateTime; +  user <<= 32; +  user |= ft_user.dwLowDateTime; +  uint64_t cpu = kern + user; +  uint64_t alld = all - g.lastall; +  uint64_t cpud = cpu - g.lastcpu; +  int percentage = 0; +  if (alld) percentage = cpud * 100 / alld; +  g.lastall = all; +  g.lastcpu = cpu; +  if (!g.lastall) return 0; +  if (percentage > INT_MAX) percentage = INT_MAX; +  if (percentage < 0) percentage = 0; +  return percentage; +} + +int fmdsp_fps_30(void) { +  FILETIME ft; +  GetSystemTimeAsFileTime(&ft); +  uint64_t time = ft.dwHighDateTime; +  time <<= 32; +  time |= ft.dwLowDateTime; +  uint64_t fps = 0; +  if (g.lastfpstime) { +    uint64_t diff = time - g.lastfpstime; +    if (diff) { +      fps = 30ull * 10000000ull / diff; +    } +  } +  g.lastfpstime = time; +  if (fps > INT_MAX) fps = INT_MAX; +  return fps; +} diff --git a/fmdsp/fmdsp_sprites.h b/fmdsp/fmdsp_sprites.h index cb011a6..d9d71ac 100644 --- a/fmdsp/fmdsp_sprites.h +++ b/fmdsp/fmdsp_sprites.h @@ -3,36 +3,37 @@ enum {    TRACK_H_S = 24,    TNAME_W = 26,    TNAME_H = 5, -  TINFO_X = 48, -  TDETAIL_X = 69, +  TINFO_X = 47, +  TDETAIL_X = 67,    TDETAIL_KN_V_X = TDETAIL_X+13, -  TDETAIL_TN_X = TDETAIL_KN_V_X+27, +  TDETAIL_TN_X = TDETAIL_KN_V_X+28,    TDETAIL_TN_V_X = TDETAIL_TN_X+13,    TDETAIL_VL_X = TDETAIL_TN_V_X+20, -  TDETAIL_VL_V_X = TDETAIL_VL_X+13, -  TDETAIL_GT_X = TDETAIL_VL_V_X+20, +  TDETAIL_VL_C_X = TDETAIL_VL_X+9, +  TDETAIL_VL_V_X = TDETAIL_VL_X+12, +  TDETAIL_GT_X = TDETAIL_VL_V_X+19,    TDETAIL_GT_V_X = TDETAIL_GT_X+13, -  TDETAIL_DT_X = TDETAIL_GT_V_X+20, +  TDETAIL_DT_X = TDETAIL_GT_V_X+23,    TDETAIL_DT_S_X = TDETAIL_DT_X+12, -  TDETAIL_DT_V_X = TDETAIL_DT_S_X+4, -  TDETAIL_M_X = 250, +  TDETAIL_DT_V_X = TDETAIL_DT_S_X+5, +  TDETAIL_M_X = 249,    TDETAIL_M_V_X = TDETAIL_M_X+8,    NUM_X = 31,    NUM_W = 8,    NUM_H = 11, -  KEY_X = 8, +  KEY_X = 7,    KEY_Y = 14,    KEY_W = 35,    KEY_H = 17,    KEY_S_OFFSET = KEY_W*4,    KEY_H_S = KEY_H - 8, -  KEY_LEFT_X = 1, +  KEY_LEFT_X = 0,    KEY_LEFT_W = 6,    KEY_LEFT_S_OFFSET = KEY_LEFT_W*4,    KEY_RIGHT_W = 11,    KEY_RIGHT_S_OFFSET = KEY_RIGHT_W*4,    KEY_OCTAVES = 8, -  BAR_L_X = 68, +  BAR_L_X = 66,    BAR_L_W = 14,    BAR_X = BAR_L_X + BAR_L_W,    BAR_Y = 1, @@ -45,8 +46,8 @@ enum {    PLAYING_Y = 324,    PLAYING_W = 72,    PLAYING_H = 9, -  FILEBAR_X = 80, -  FILEBAR_MUS_X = FILEBAR_X + 5, +  FILEBAR_X = 78, +  FILEBAR_MUS_X = FILEBAR_X + 6,    FILEBAR_IC_X = FILEBAR_MUS_X + 14,    FILEBAR_F_X = FILEBAR_IC_X + 11,    FILEBAR_ILE_X = FILEBAR_F_X + 4, @@ -67,6 +68,104 @@ enum {    PCM2FILENAME_X = PCM2FILETRI_X + 8,    DT_SIGN_W = 3,    DT_SIGN_H = 3, +  SPECTRUM_X = 352, +  SPECTRUM_Y = 207, +  CPU_Y = 115, +  CPU_X = 320, +  CPU_BAR_X = CPU_X-6, +  CPU_NUM_X = CPU_X+56, +  CPU_NUM_Y = CPU_Y+2, +  CPU_TRI_X = CPU_X+43, +  CPU_TRI_Y = CPU_Y+10, +  FPS_X = CPU_X+100, +  FPS_BAR_X = FPS_X-6, +  FPS_NUM_X = FPS_X+61, +  FPS_TRI_X = FPS_X+48, +  TIME_TEXT_X = 530, +  TIME_X = TIME_TEXT_X+38, +  TIME_BAR_X = TIME_TEXT_X-6, +  TIME_TRI_X = TIME_TEXT_X+31, +  TIME_BAR_W = 3, +  TIME_BAR_H = 14, +  TIME_Y = 22, +  CLOCK_Y = TIME_Y+19, +  TIMERB_Y = CLOCK_Y+19, +  LOOPCNT_Y = TIMERB_Y+19, +  VOLDOWN_Y = LOOPCNT_Y+19, +  PGMNUM_Y = VOLDOWN_Y+19, +  LOGO_NUM = 1, +  LOGO_Y = 1, +  LOGO_FM_W = 31, +  LOGO_DS_W = 32, +  LOGO_P_W = 15, +  LOGO_H = 12, +  LOGO_FM_X = 312, +  LOGO_DS_X = LOGO_FM_X+LOGO_FM_W+2, +  LOGO_P_X = LOGO_DS_X+LOGO_DS_W+2, +  CIRCLE_W = 31, +  CIRCLE_H = 31, +  CIRCLE_X = 312, +  CIRCLE_Y = 70, +  TOP_MUS_X = 397, +  TOP_MUSIC_Y = 7, +  TOP_IC_X = TOP_MUS_X+14, +  TOP_F_X = TOP_IC_X+12, +  TOP_ILE_X = TOP_F_X+4, +  TOP_SELECTOR_X = TOP_ILE_X+17, +  TOP_AND_X = TOP_SELECTOR_X+42, +  TOP_STATUS_X = TOP_AND_X+7, +  TOP_D_X = TOP_STATUS_X+32, +  TOP_ISPLAY_X = TOP_D_X+4, +  TOP_VER_X = TOP_ISPLAY_X+32, +  TOP_TEXT_W = 231, +  TOP_TEXT_H = 5, +  TOP_TEXT_Y = TOP_MUSIC_Y-6, +  VER_W = 13, +  VER_H = 5, +  VER_Y = 8, +  VER_0_X = TOP_VER_X+15, +  VER_1_X = VER_0_X+7, +  VER_2_X = VER_1_X+7, +  DRIVER_TEXT_X = 312, +  DRIVER_TEXT_Y = 27, +  DRIVER_TEXT_2_X = DRIVER_TEXT_X+9, +  DRIVER_TRI_X = DRIVER_TEXT_2_X+26, +  DRIVER_TRI_Y = DRIVER_TEXT_Y+3, +  CURL_W = 11, +  CURL_H = 11, +  CURL_LEFT_X = 347, +  CURL_RIGHT_X = 509, +  CURL_Y = 80, +  PLAY_W = 30, +  PLAY_H = 7, +  PLAY_X = 354, +  PLAY_Y = 77, +  STOP_W = 31, +  STOP_H = 7, +  STOP_X = 393, +  STOP_Y = 77, +  PAUSE_W = 37, +  PAUSE_H = 7, +  PAUSE_X = 433, +  PAUSE_Y = 77, +  FADE_W = 31, +  FADE_H = 7, +  FADE_X = 481, +  FADE_Y = 77, +  FF_W = 20, +  FF_H = 7, +  FF_X = 360, +  FF_Y = 87, +  REW_W = 26, +  REW_H = 7, +  REW_X = 392, +  REW_Y = 87, +  FLOPPY_W = 74, +  FLOPPY_H = 7, +  FLOPPY_X = 432, +  FLOPPY_Y = 87, +  LEVEL_TEXT_X = 318, +  LEVEL_TEXT_Y = 290,  };  enum { @@ -100,6 +199,7 @@ static const uint8_t s_palettes[PALETTE_NUM][FMDSP_PALETTE_COLORS*3] = {      136, 255, 68,      51, 51, 238,      0, 187, 255, +    68, 102, 170,    },    {      0, 0, 0, @@ -111,6 +211,7 @@ static const uint8_t s_palettes[PALETTE_NUM][FMDSP_PALETTE_COLORS*3] = {      153, 255, 119,      102, 85, 255,      0, 204, 255, +    85, 119, 170,    },    {      0, 0, 0, @@ -122,6 +223,7 @@ static const uint8_t s_palettes[PALETTE_NUM][FMDSP_PALETTE_COLORS*3] = {      255, 221, 85,      255, 102, 0,      255, 85, 0, +    170, 119, 85,    },    {      0, 0, 0, @@ -133,6 +235,7 @@ static const uint8_t s_palettes[PALETTE_NUM][FMDSP_PALETTE_COLORS*3] = {      119, 255, 34,      136, 68, 221,      0, 187, 255, +    136, 102, 187,    },    {      0, 0, 0, @@ -144,6 +247,7 @@ static const uint8_t s_palettes[PALETTE_NUM][FMDSP_PALETTE_COLORS*3] = {      255, 68, 0,      85, 85, 255,      255, 119, 255, +    119, 119, 187,    },    {      0, 0, 0, @@ -155,6 +259,7 @@ static const uint8_t s_palettes[PALETTE_NUM][FMDSP_PALETTE_COLORS*3] = {      255, 221, 0,      255, 0, 51,      255, 0, 51, +    170, 136, 0,    },    {      102, 170, 238, @@ -166,6 +271,7 @@ static const uint8_t s_palettes[PALETTE_NUM][FMDSP_PALETTE_COLORS*3] = {      0, 51, 136,      34, 102, 187,      0, 85, 204, +    68, 136, 255,    },    {      0, 0, 0, @@ -177,6 +283,7 @@ static const uint8_t s_palettes[PALETTE_NUM][FMDSP_PALETTE_COLORS*3] = {      85, 255, 68,      34, 17, 255,      0, 170, 255, +    68, 85, 170,    },    {      LCDB(255), @@ -188,6 +295,7 @@ static const uint8_t s_palettes[PALETTE_NUM][FMDSP_PALETTE_COLORS*3] = {      LCDB(218),      LCDB(109),      LCDB(218), +    LCDB(0),    },    {      LCD(255), @@ -199,6 +307,7 @@ static const uint8_t s_palettes[PALETTE_NUM][FMDSP_PALETTE_COLORS*3] = {      LCD(0),      LCD(109),      LCD(0), +    LCD(0),    },  }; @@ -356,6 +465,50 @@ static const uint8_t s_num[11][NUM_W*NUM_H] = {      0, 0, 3, 3, 3, 0, 0, 0,    }  }; + +static const uint8_t s_num_colon[2][NUM_W*NUM_H] = { +  { +    0, 0, 0, 0, 0, 0, 0, 0, +    0, 0, 0, 0, 0, 0, 0, 0, +    0, 0, 0, 0, 2, 0, 0, 0, +    0, 0, 0, 0, 2, 0, 0, 0, +    0, 0, 0, 0, 0, 0, 0, 0, +    0, 0, 0, 0, 0, 0, 0, 0, +    0, 0, 0, 0, 0, 0, 0, 0, +    0, 0, 0, 2, 0, 0, 0, 0, +    0, 0, 0, 2, 0, 0, 0, 0, +    0, 0, 0, 0, 0, 0, 0, 0, +    0, 0, 0, 0, 0, 0, 0, 0, +  }, +  { +    0, 0, 0, 0, 0, 0, 0, 0, +    0, 0, 0, 0, 0, 0, 0, 0, +    0, 0, 0, 0, 3, 0, 0, 0, +    0, 0, 0, 0, 3, 0, 0, 0, +    0, 0, 0, 0, 0, 0, 0, 0, +    0, 0, 0, 0, 0, 0, 0, 0, +    0, 0, 0, 0, 0, 0, 0, 0, +    0, 0, 0, 3, 0, 0, 0, 0, +    0, 0, 0, 3, 0, 0, 0, 0, +    0, 0, 0, 0, 0, 0, 0, 0, +    0, 0, 0, 0, 0, 0, 0, 0, +  }, +}; + +static const uint8_t s_num_bar[NUM_W*NUM_H] = { +  0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 2, 2, 2, 0, 0, 0, +}; +  static const uint8_t s_key_bg[KEY_W*KEY_H] = {    4,4,4,0,0,0,4,4,0,0,0,4,4,4,0,4,4,4,0,0,0,4,4,0,0,0,4,4,0,0,0,4,4,4,0,    4,4,4,0,0,0,4,4,0,0,0,4,4,4,0,4,4,4,0,0,0,4,4,0,0,0,4,4,0,0,0,4,4,4,0, @@ -488,3 +641,229 @@ static const uint8_t s_dt_sign[3][DT_SIGN_W*DT_SIGN_H] = {      0, 1, 0,    }  }; + +static const uint8_t s_logo_fm[LOGO_FM_W*LOGO_H] = { +  0,9,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,9,2,2,2,0,0,0,0,0,2,2,2,9,0, +  9,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,9,2,2,2,2,2,0,0,0,2,2,2,2,2,9, +  2,2,2,9,3,3,3,3,3,3,3,3,3,3,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +  2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,2,2,2,2,2,0,0,2,2,2, +  2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,2,2,2,0,0,0,2,2,2, +  2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,2,2,2, +  2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,2,2,2, +  2,2,2,3,3,3,3,3,3,3,3,3,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,2,2,2, +  2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,2,2,2, +  2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,2,2,2, +  2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,2,2,2, +  2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,2,2,2, +}; + +static const uint8_t s_logo_ds[LOGO_DS_W*LOGO_H] = { +  2,2,2,2,2,2,2,2,2,2,2,2,9,0,0,0,0,0,9,2,2,2,2,2,2,2,2,2,2,2,2,2, +  2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,9,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +  2,2,2,3,3,3,3,3,3,3,3,9,2,2,9,0,0,2,2,2,9,3,3,3,3,3,3,3,3,3,3,3, +  2,2,2,0,0,0,0,0,0,0,0,0,2,2,2,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0, +  2,2,2,0,0,0,0,0,0,0,0,0,2,2,2,0,0,2,2,2,9,0,0,0,0,0,0,0,0,0,0,0, +  2,2,2,0,0,0,0,0,0,0,0,0,2,2,2,0,0,9,2,2,2,2,2,2,2,2,2,2,2,2,9,0, +  2,2,2,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,9,2,2,2,2,2,2,2,2,2,2,2,2,9, +  2,2,2,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,3,3,3,3,3,3,3,3,9,2,2,2, +  2,2,2,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2, +  2,2,2,0,0,0,0,0,0,0,0,9,2,2,9,0,0,0,0,0,0,0,0,0,0,0,0,0,9,2,2,2, +  2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,9, +  2,2,2,2,2,2,2,2,2,2,2,2,9,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,9,0, +}; + +static const uint8_t s_logo_p[LOGO_P_W*LOGO_H] = { +  2,2,2,2,2,2,2,2,2,2,2,2,2,9,0, +  2,2,2,2,2,2,2,2,2,2,2,2,2,2,9, +  2,2,2,3,3,3,3,3,3,3,3,9,2,2,2, +  2,2,2,0,0,0,0,0,0,0,0,0,2,2,2, +  2,2,2,0,0,0,0,0,0,0,0,9,2,2,2, +  2,2,2,2,2,2,2,2,2,2,2,2,2,2,9, +  2,2,2,2,2,2,2,2,2,2,2,2,2,9,0, +  2,2,2,3,3,3,3,3,3,3,3,3,3,0,0, +  2,2,2,0,0,0,0,0,0,0,0,0,0,0,0, +  2,2,2,0,0,0,0,0,0,0,0,0,0,0,0, +  2,2,2,0,0,0,0,0,0,0,0,0,0,0,0, +  2,2,2,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +static const uint8_t s_circle[CIRCLE_W*CIRCLE_H] = { +  0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +  0,0,0,0,0,0,0,0,0,0,8,0,0,0,1,0,1,0,0,0,2,0,0,0,0,0,0,0,0,0,0, +  0,0,0,0,0,0,0,0,8,0,8,0,0,0,1,0,1,0,0,0,2,0,2,0,0,0,0,0,0,0,0, +  0,0,0,0,0,0,0,0,8,0,0,8,0,0,1,0,1,0,0,2,0,0,2,0,0,0,0,0,0,0,0, +  0,0,0,0,0,7,0,0,0,8,0,8,0,0,1,0,1,0,0,2,0,2,0,0,0,3,0,0,0,0,0, +  0,0,0,0,7,0,7,0,0,8,0,0,8,0,1,0,1,0,2,0,0,2,0,0,3,0,3,0,0,0,0, +  0,0,0,0,0,7,0,7,0,0,8,0,8,0,1,0,1,0,2,0,2,0,0,3,0,3,0,0,0,0,0, +  0,0,0,0,0,0,7,0,7,0,8,0,0,0,0,0,0,0,0,0,2,0,3,0,3,0,0,0,0,0,0, +  0,0,6,6,0,0,0,7,0,7,0,0,0,0,0,0,0,0,0,0,0,3,0,3,0,0,0,4,4,0,0, +  0,0,0,0,6,6,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,4,4,0,0,0,0, +  0,6,6,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,4,4,0, +  0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0, +  0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0, +  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +  5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5, +  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +  5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5, +  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +  0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0, +  0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0, +  0,4,4,0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,6,6,0, +  0,0,0,0,4,4,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,6,6,0,0,0,0, +  0,0,4,4,0,0,0,3,0,3,0,0,0,0,0,0,0,0,0,0,0,7,0,7,0,0,0,6,6,0,0, +  0,0,0,0,0,0,3,0,3,0,2,0,0,0,0,0,0,0,0,0,8,0,7,0,7,0,0,0,0,0,0, +  0,0,0,0,0,3,0,3,0,0,2,0,2,0,1,0,1,0,8,0,8,0,0,7,0,7,0,0,0,0,0, +  0,0,0,0,3,0,3,0,0,2,0,0,2,0,1,0,1,0,8,0,0,8,0,0,7,0,7,0,0,0,0, +  0,0,0,0,0,3,0,0,0,2,0,2,0,0,1,0,1,0,0,8,0,8,0,0,0,7,0,0,0,0,0, +  0,0,0,0,0,0,0,0,2,0,0,2,0,0,1,0,1,0,0,8,0,0,8,0,0,0,0,0,0,0,0, +  0,0,0,0,0,0,0,0,2,0,2,0,0,0,1,0,1,0,0,0,8,0,8,0,0,0,0,0,0,0,0, +  0,0,0,0,0,0,0,0,0,0,2,0,0,0,1,0,1,0,0,0,8,0,0,0,0,0,0,0,0,0,0, +  0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +static const uint8_t s_text[TOP_TEXT_W*TOP_TEXT_H] = { +  0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,7,0,7,0,0,7,0,7,7,7,0,7,0,0,7,0,0,0,0,0, +  7,0,0,0,0,7,7,7,0,7,0,0,7,0,7,0,0,7,0,7,0,0,7,0,0,0,0,7,7,7,0,7,7,7,7,0,7,0, +  0,7,0,0,0,0,0,0,7,7,7,0,0,0,0,0,7,0,0,7,0,0,7,7,0,0,0,7,7,0,0,0,0,0,0,0,7,7, +  0,0,7,0,0,7,0,7,7,7,0,0,0,7,7,0,0,0,0,7,0,0,0,0,0,0,0,7,7,0,0,7,7,7,0,0,7,0, +  0,7,0,0,0,0,7,0,0,0,0,0,7,0,0,7,0,7,7,7,0,7,0,0,7,0,7,7,7,0,0,0,7,7,0,0,7,0, +  0,7,0,0,7,7,7,0,0,0,0,7,7,0,0,0,7,7,0,0,0,7,7,0,0,0,7,7,0,0,0,0,0,0,7,0,0,0, +  7,7,0,0,7,0,0,0,7,7,0,0,7,0,7,0,0,0,7,0,0,7,0,7,7,0,7,0,0,7,0,0,0,7,7,0,0,0, +  0,7,0,7,0,0,0,0,0,7,0,0,7,7,0,7,0,7,0,0,7,0,0,7,7,0,0,0,0,7,0,0,0,0,0,0,0,0, +  0,7,0,7,0,0,0,7,0,0,0,0,0,0,7,0,0,0,0,0,7,7,0,0,7,0,0,7,0,7,0,0,0,0,0,0,7,0, +  7,0,0,7,0,7,7,7,7,0,7,0,0,7,0,7,0,0,0,0,0,7,7,0,0,0,0,7,0,7,0,0,7,0,7,0,0,7, +  0,7,7,7,7,0,0,0,7,0,7,0,0,0,0,7,0,0,7,0,0,7,0,0,7,7,0,7,0,7,0,0,7,0,7,0,0,7, +  0,7,0,0,7,0,7,0,0,0,0,0,0,7,0,0,7,0,7,0,0,7,0,7,0,0,7,0,7,0,0,7,0,0,0,0,7,7, +  0,0,7,0,0,7,7,7,7,0,7,0,0,7,0,7,7,0,0,0,0,7,0,0,7,0,7,0,7,7,0,0,7,0,0,0,0,0, +  0,0,0,7,0,0,7,0,0,0,0,0,7,0,0,7,0,7,7,0,7,0,0,7,0,0,0,0,0,0,0,0,7,0,7,7,0,0, +  7,7,0,0,7,0,0,0,0,7,7,7,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,7,7,7,0,0,0, +  7,0,0,7,0,0,7,0,7,0,0,7,0,7,0,0,7,0,7,7,7,0,0,7,0,7,0,0,0,7,0,0,7,0,0,7,0,7, +  0,0,7,0,7,0,0,7,0,0,0,0,7,0,7,0,0,0,7,0,0,7,0,0,7,0,0,7,0,7,7,0,7,0,0,7,0,7, +  0,0,7,0,7,0,0,7,0,0,7,7,0,0,0,0,0,0,7,0,0,7,0,0,7,0,7,0,0,7,0,7,0,0,7,0,7,7, +  0,0,7,0,0,7,0,0,7,0,7,0,0,7,0,0,7,0,7,0,0,0,0,0,7,0,0,7,0,7,0,0,7,0,0,7,0,0, +  0,7,7,0,0,7,0,0,0,7,0,0,0,0,0,7,0,0,7,0,0,7,0,7,0,0,7,0,0,7,7,0,0,0,0,7,0,0, +  7,0,0,7,7,0,0,7,0,7,0,0,0,7,0,0,0,0,0,0,7,0,0,0,0,0,7,7,0,0,7,0,0,7,0,7,0,0, +  7,0,7,0,0,0,7,0,7,7,0,7,0,0,7,0,0,0,0,7,0,7,0,0,7,0,7,7,7,7,0,7,0,0,0,7,0,7, +  7,0,7,0,7,0,0,7,0,0,7,0,0,0,7,0,7,0,0,0,0,7,7,7,7,0,0,7,0,0,7,0,0,7,0,0,0,0, +  7,0,7,0,0,7,0,7,7,7,7,0,0,0,0,7,0,0,0,0,7,0,0,0,7,0,0,7,0,7,0,0,7,0,7,0,0,7, +  0,0,0,0,0,7,0,0,7,0,0,7,0,7,0,0,0,7,7,0,0,7,0,0,0,0,0,0,7,7,0,0,7,0,0,7,0,7, +  7,7,0,7,0,0,7,0,0,0,0,0,0,7,7,7,0,7,7,7,0,7,0,0,7,0,0,7,7,0,0,7,0,0,7,0,0,0, +  0,7,7,7,0,0,7,7,0,0,7,0,0,7,0,0,0,0,0,0,7,7,7,0,0,0,0,0,7,0,0,7,0,0,7,7,0,0, +  0,7,7,0,0,0,0,0,0,7,0,0,7,0,7,0,0,7,0,7,7,7,0,0,0,7,7,0,0,0,0,7,0,0,0,0,0,0, +  7,0,0,7,0,7,0,0,7,0,7,0,0,7,0,0,0,0,7,0,7,0,0,0,7,0,0,7,0,7,7,7,0,7,0,0,7,0, +  7,7,7,0,0,0,7,7,0,0,7,0,0,7,0,7,7,7,0,0,0,0,7,7,7,7,0,0,7,7,0,0,0,7,7,0,0,0, +  7,7,0,0,0,0,0,7,7,7,0,0,7,7,0 +}; + +static const uint8_t s_ver[VER_W*VER_H] = { +  2,0,0,2,0,0,0,0,0,0,0,0,0, +  2,0,0,2,0,0,2,2,0,0,2,0,2, +  2,0,0,2,0,2,2,2,2,0,2,2,0, +  0,2,2,0,0,2,0,0,0,0,2,0,0, +  0,2,2,0,0,0,2,2,2,0,2,0,0, +}; + +static const uint8_t s_curl_left[CURL_W*CURL_H] = { +  0,3,3,3,0,0,0,0,0,0,0, +  3,0,0,0,0,0,0,0,0,0,0, +  3,0,0,0,0,0,0,0,0,0,0, +  3,0,0,0,0,0,0,0,0,0,0, +  3,0,0,0,0,0,0,0,0,0,0, +  3,0,0,0,0,0,0,0,0,0,0, +  3,0,0,0,0,0,0,0,0,0,0, +  3,0,0,0,0,0,0,0,0,0,0, +  3,0,0,0,0,0,0,0,0,0,0, +  3,0,0,0,0,0,0,0,0,0,0, +  0,3,3,3,3,3,3,3,3,3,3, +}; + +static const uint8_t s_curl_right[CURL_W*CURL_H] = { +  0,0,0,0,0,0,0,3,3,3,0, +  0,0,0,0,0,0,0,0,0,0,3, +  0,0,0,0,0,0,0,0,0,0,3, +  0,0,0,0,0,0,0,0,0,0,3, +  0,0,0,0,0,0,0,0,0,0,3, +  0,0,0,0,0,0,0,0,0,0,3, +  0,0,0,0,0,0,0,0,0,0,3, +  0,0,0,0,0,0,0,0,0,0,3, +  0,0,0,0,0,0,0,0,0,0,3, +  0,0,0,0,0,0,0,0,0,0,3, +  3,3,3,3,3,3,3,3,3,3,0, +}; + +static const uint8_t s_play[PLAY_W*PLAY_H] = { +  1,0,0,0,0,0,0,1,1,1,1,0,0,1,0,0,0,0,0,0,1,1,1,0,0,1,0,0,0,1, +  1,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1, +  1,1,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0, +  1,1,1,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0, +  1,1,1,0,0,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,1,1,1,0,0,0,1,0,0, +  1,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0, +  1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,0,1,0,0,0,1,0,0,0,1,0,0, +}; + +static const uint8_t s_stop[STOP_W*STOP_H] = { +  0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,0, +  1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1, +  1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1, +  1,1,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1, +  1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,1,1,0, +  1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0, +  0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0, +}; + +static const uint8_t s_pause[PAUSE_W*PAUSE_H] = { +  0,0,0,0,0,0,0,0,3,3,3,3,0,0,0,3,3,3,0,0,3,0,0,0,3,0,0,3,3,3,3,0,0,3,3,3,3, +  3,3,0,3,3,0,0,0,3,0,0,0,3,0,3,0,0,0,3,0,3,0,0,0,3,0,3,0,0,0,0,0,3,0,0,0,0, +  3,3,0,3,3,0,0,0,3,0,0,0,3,0,3,0,0,0,3,0,3,0,0,0,3,0,3,0,0,0,0,0,3,0,0,0,0, +  3,3,0,3,3,0,0,0,3,0,0,0,3,0,3,0,0,0,3,0,3,0,0,0,3,0,0,3,3,3,0,0,3,3,3,3,0, +  3,3,0,3,3,0,0,0,3,3,3,3,0,0,3,3,3,3,3,0,3,0,0,0,3,0,0,0,0,0,3,0,3,0,0,0,0, +  3,3,0,3,3,0,0,0,3,0,0,0,0,0,3,0,0,0,3,0,3,0,0,0,3,0,0,0,0,0,3,0,3,0,0,0,0, +  0,0,0,0,0,0,0,0,3,0,0,0,0,0,3,0,0,0,3,0,0,3,3,3,0,0,3,3,3,3,0,0,0,3,3,3,3, +}; + +static const uint8_t s_fade[FADE_W*FADE_H] = { +  0,0,0,0,0,0,0,0,0,3,3,3,3,0,0,3,3,3,0,0,3,3,3,3,0,0,0,3,3,3,3, +  3,0,0,0,0,0,0,0,3,0,0,0,0,0,3,0,0,0,3,0,3,0,0,0,3,0,3,0,0,0,0, +  3,0,0,0,0,0,0,0,3,0,0,0,0,0,3,0,0,0,3,0,3,0,0,0,3,0,3,0,0,0,0, +  3,0,3,0,0,0,0,0,3,3,3,3,0,0,3,0,0,0,3,0,3,0,0,0,3,0,3,3,3,3,0, +  3,0,3,0,0,0,0,0,3,0,0,0,0,0,3,3,3,3,3,0,3,0,0,0,3,0,3,0,0,0,0, +  3,0,3,0,3,0,0,0,3,0,0,0,0,0,3,0,0,0,3,0,3,0,0,0,3,0,3,0,0,0,0, +  3,0,3,0,3,0,0,0,3,0,0,0,0,0,3,0,0,0,3,0,3,3,3,3,0,0,0,3,3,3,3, +}; + +static const uint8_t s_ff[FF_W*FF_H] = { +  3,0,0,3,0,0,0,0,0,0,3,3,3,3,0,0,3,3,3,3, +  3,3,0,3,3,0,0,0,0,3,0,0,0,0,0,3,0,0,0,0, +  3,3,0,3,3,3,0,0,0,3,0,0,0,0,0,3,0,0,0,0, +  3,3,0,3,3,3,3,0,0,3,3,3,3,0,0,3,3,3,3,0, +  3,3,0,3,3,3,0,0,0,3,0,0,0,0,0,3,0,0,0,0, +  3,3,0,3,3,0,0,0,0,3,0,0,0,0,0,3,0,0,0,0, +  3,0,0,3,0,0,0,0,0,3,0,0,0,0,0,3,0,0,0,0, +}; + +static const uint8_t s_rew[REW_W*REW_H] = { +  0,0,0,3,0,0,3,0,0,3,3,3,3,0,0,0,3,3,3,3,0,3,0,0,0,3, +  0,0,3,3,0,3,3,0,0,3,0,0,0,3,0,3,0,0,0,0,0,3,0,3,0,3, +  0,3,3,3,0,3,3,0,0,3,0,0,0,3,0,3,0,0,0,0,0,3,0,3,0,3, +  3,3,3,3,0,3,3,0,0,3,0,0,3,0,0,3,3,3,3,0,0,3,0,3,0,3, +  0,3,3,3,0,3,3,0,0,3,3,3,0,0,0,3,0,0,0,0,0,3,0,3,0,3, +  0,0,3,3,0,3,3,0,0,3,0,0,3,0,0,3,0,0,0,0,0,3,0,3,0,3, +  0,0,0,3,0,0,3,0,0,3,0,0,0,3,0,0,3,3,3,3,0,0,3,0,3,0, +}; + +static uint8_t s_floppy[FLOPPY_W*FLOPPY_H] = { +  3,3,3,3,3,3,3,0,0,0,3,3,3,3,0,0,3,3,3,0,0,3,0,0,0,0,0,0,3,3,3,3,0,3,3,3,3,0, +  0,0,3,3,3,0,0,3,0,0,0,3,0,0,0,3,0,0,0,0,3,3,3,0,0,0,3,3,3,0,0,0,0,0,3,0,3,3, +  3,3,3,3,0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,3,0,0,0,0,0,3,0,0,0,3,0,3, +  0,0,0,3,0,3,3,0,3,3,0,0,3,3,0,0,0,3,0,0,0,3,0,3,0,0,0,3,0,0,0,3,3,0,3,3,3,0, +  3,3,3,0,0,3,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,3,0,0,0,0,0,3,0,0,0,3,0,3,0,0, +  0,0,0,3,0,3,0,3,0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,3,0,0,3,0,3,0,3,3,0,0,0,3, +  3,0,0,3,3,3,3,0,0,0,0,3,0,0,0,3,0,0,0,0,0,3,3,3,3,0,0,3,0,0,0,3,0,3,0,0,0,0, +  0,3,0,0,0,3,0,0,0,3,0,0,0,0,0,0,3,0,0,0,0,3,3,0,0,3,0,0,3,0,3,3,3,0,3,3,3,0, +  0,3,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,3,0,0,0,0,0,3,3,3,3,0,0,3,0,0,0,0,0,3, +  0,0,0,3,0,0,0,3,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3, +  0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,3,0,0,0,0,0,3,0,0,0,0,0,3,0,0,0,3,0,3,0,0, +  0,3,0,0,0,3,0,0,0,0,3,0,0,0,0,3,0,0,0,3,0,0,0,0,3,0,3,3,3,3,3,3,3,0,0,3,0,0, +  0,0,0,0,3,3,3,0,0,0,3,3,3,3,0,0,3,3,3,3,0,3,0,0,0,0,0,0,3,3,3,0,0,3,0,0,0,3, +  0,0,3,3,3,0,0,3,3,3,3,3,0,0,3,3,3,0,0,0,0,0,3,0, +}; diff --git a/fmdsp/font_fmdsp_small_data.h b/fmdsp/font_fmdsp_small_data.h index d5f9105..60ee56a 100644 --- a/fmdsp/font_fmdsp_small_data.h +++ b/fmdsp/font_fmdsp_small_data.h @@ -1,5 +1,4 @@ -static const unsigned char fontdat[] = { -  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +static unsigned char fontdat[] = {    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -19,10 +18,11 @@ static const unsigned char fontdat[] = {    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x40, 0xa0, 0x50, 0xa0, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe0, 0x40, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, -  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x20, 0x40, 0x00,    0x00, 0x60, 0x90, 0x90, 0x90, 0x60, 0x00, 0x20, 0x60, 0x20, 0x20, 0x70,    0x00, 0x60, 0x90, 0x20, 0x40, 0xf0, 0x00, 0xe0, 0x10, 0x60, 0x10, 0xe0,    0x00, 0x20, 0x60, 0xa0, 0xf0, 0x20, 0x00, 0xf0, 0x80, 0xe0, 0x10, 0xe0, @@ -49,18 +49,18 @@ static const unsigned char fontdat[] = {    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x80, 0xb0, 0x80, 0xf0, -  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x10, 0x70, 0x90, 0x80, 0x70, 0x00, 0xf0, 0x80, 0xb0, 0x80, 0xf0,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xa0, 0xc0, 0xa0, 0x90, +  0x00, 0x80, 0x80, 0x80, 0x80, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x90, 0x90, 0x60,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0xf0, 0x00, 0x20, 0x40, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -128,4 +128,3 @@ static const unsigned char fontdat[] = {    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  }; - diff --git a/gtk/Makefile.am b/gtk/Makefile.am index fb06655..8777418 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -16,7 +16,8 @@ FMDRIVER_SRC=../fmdriver/fmdriver_fmp.c \  FMDSP_SRC=../fmdsp/fmdsp.c \            ../fmdsp/fmdsp-vramlookup-c.c \            ../fmdsp/font_rom.c \ -          ../fmdsp/font_fmdsp_small.c +          ../fmdsp/font_fmdsp_small.c \ +          ../fmdsp/fmdsp_platform_unix.c  #fmplayer_CFLAGS=$(CFLAGS)  #CFLAGS= @@ -48,6 +49,7 @@ fmplayer_SOURCES=main.c \                   ../common/fmplayer_file_gio.c \                   ../common/fmplayer_work_opna.c \                   ../common/fmplayer_drumrom_unix.c \ +                 ../fft/fft.c \                   $(LIBOPNA_SRC) \                   $(FMDRIVER_SRC) \                   $(FMDSP_SRC) diff --git a/gtk/fmplayer.xpm b/gtk/fmplayer.xpm index d52d9f4..87ae7a6 100644 --- a/gtk/fmplayer.xpm +++ b/gtk/fmplayer.xpm @@ -1,5 +1,5 @@  /* XPM */ -static char *fmplayer_xpm_16[] = { +static const char *fmplayer_xpm_16[] = {  /* columns rows colors chars-per-pixel */  "16 16 4 1 ",  "  c #40A040", diff --git a/gtk/fmplayer32.xpm b/gtk/fmplayer32.xpm index 062d12e..a97a327 100644 --- a/gtk/fmplayer32.xpm +++ b/gtk/fmplayer32.xpm @@ -1,5 +1,5 @@  /* XPM */ -static char *fmplayer_xpm_32[] = { +static const char *fmplayer_xpm_32[] = {  /* columns rows colors chars-per-pixel */  "32 32 8 1 ",  "  c gray25", @@ -19,6 +19,7 @@  #include "oscilloview.h"  #include "wavesave.h"  #include "common/fmplayer_common.h" +#include "fft/fft.h"  #include "fmplayer.xpm"  #include "fmplayer32.xpm" @@ -58,8 +59,12 @@ static struct {    const char *current_uri;    bool oscillo_should_update;    struct oscillodata oscillodata_audiothread[LIBOPNA_OSCILLO_TRACK_COUNT]; +  atomic_flag at_fftdata_flag; +  struct fmplayer_fft_data at_fftdata; +  struct fmplayer_fft_input_data fftdata;  } g = { -  .oscillo_should_update = true +  .oscillo_should_update = true, +  .at_fftdata_flag = ATOMIC_FLAG_INIT,  };  static void quit(void) { @@ -140,6 +145,11 @@ static int pastream_cb(const void *inptr, void *outptr, unsigned long frames,        atomic_flag_clear_explicit(&oscilloview_g.flag, memory_order_release);      }    } +  if (!atomic_flag_test_and_set_explicit( +    &g.at_fftdata_flag, memory_order_acquire)) { +    fft_write(&g.at_fftdata, buf, frames); +    atomic_flag_clear_explicit(&g.at_fftdata_flag, memory_order_release); +  }    return paContinue;  } @@ -228,6 +238,7 @@ static bool openfile(const char *uri) {    fmdsp_vram_init(&g.fmdsp, &g.work, g.vram);    Pa_StartStream(g.pastream);    g.pa_paused = false; +  g.work.paused = false;    {      const char *turi = strdup(uri);      free((void *)g.current_uri); @@ -282,7 +293,12 @@ static gboolean draw_cb(GtkWidget *w,                   gpointer p) {    (void)w;    (void)p; -  fmdsp_update(&g.fmdsp, &g.work, &g.opna, g.vram); +  if (!atomic_flag_test_and_set_explicit( +    &g.at_fftdata_flag, memory_order_acquire)) { +    memcpy(&g.fftdata.fdata, &g.at_fftdata, sizeof(g.fftdata)); +    atomic_flag_clear_explicit(&g.at_fftdata_flag, memory_order_release); +  } +  fmdsp_update(&g.fmdsp, &g.work, &g.opna, g.vram, &g.fftdata);    fmdsp_vrampalette(&g.fmdsp, g.vram, g.vram32, g.vram32_stride);    cairo_surface_t *s = cairo_image_surface_create_for_data(      g.vram32, CAIRO_FORMAT_RGB24, PC98_W, PC98_H, g.vram32_stride); @@ -391,9 +407,11 @@ static gboolean key_press_cb(GtkWidget *w,      if (g.pa_paused) {        Pa_StartStream(g.pastream);        g.pa_paused = false; +      g.work.paused = false;      } else {        Pa_StopStream(g.pastream);        g.pa_paused = true; +      g.work.paused = true;      }      break;    case GDK_KEY_F11: @@ -481,6 +499,7 @@ int main(int argc, char **argv) {    if (__builtin_cpu_supports("sse2")) opna_ssg_sinc_calc_func = opna_ssg_sinc_calc_sse2;    if (__builtin_cpu_supports("ssse3")) fmdsp_vramlookup_func = fmdsp_vramlookup_ssse3;  #endif +  fft_init_table();    load_fontrom();    gtk_init(&argc, &argv);    { diff --git a/libopna/opna.c b/libopna/opna.c index 567c913..9f87ff3 100644 --- a/libopna/opna.c +++ b/libopna/opna.c @@ -9,6 +9,7 @@ void opna_reset(struct opna *opna) {    opna_drum_reset(&opna->drum);    opna_adpcm_reset(&opna->adpcm);    opna->mask = 0; +  opna->generated_frames = 0;  }  void opna_writereg(struct opna *opna, unsigned reg, unsigned val) { @@ -42,6 +43,7 @@ void opna_mix_oscillo(struct opna *opna, int16_t *buf, unsigned samples, struct                       oscillo ? &oscillo[6] : 0, offset);    opna_drum_mix(&opna->drum, buf, samples);    opna_adpcm_mix(&opna->adpcm, buf, samples); +  opna->generated_frames += samples;  }  unsigned opna_get_mask(const struct opna *opna) { diff --git a/libopna/opna.h b/libopna/opna.h index 2ebca0d..a49a5f8 100644 --- a/libopna/opna.h +++ b/libopna/opna.h @@ -41,6 +41,7 @@ struct opna {    struct opna_adpcm adpcm;    struct opna_ssg_resampler resampler;    unsigned mask; +  uint64_t generated_frames;  };  void opna_reset(struct opna *opna); diff --git a/win32/amd64/Makefile b/win32/amd64/Makefile index 22ef073..97e46dc 100644 --- a/win32/amd64/Makefile +++ b/win32/amd64/Makefile @@ -4,6 +4,7 @@ vpath %.c ../../libopna  vpath %.c ../../fmdsp  vpath %.c ../../tonedata  vpath %.c ../../common +vpath %.c ../../fft  vpath %.rc ..  include ../fmplayer.mak diff --git a/win32/fmplayer.mak b/win32/fmplayer.mak index 9a514b2..d62861c 100644 --- a/win32/fmplayer.mak +++ b/win32/fmplayer.mak @@ -21,11 +21,13 @@ LIBOPNA_OBJS=opna \  FMDSP_OBJS=fmdsp \             fmdsp-vramlookup-c \             font_rom \ -           font_fmdsp_small +           font_fmdsp_small \ +           fmdsp_platform_win  TONEDATA_OBJS=tonedata  SSEOBJBASE=opnassg-sinc-sse2 \             fmdsp-vramlookup-ssse3  OBJBASE=main \ +        fft \          toneview \          oscilloview \          wavesave \ diff --git a/win32/main.c b/win32/main.c index 66a1bf0..c1df7a7 100644 --- a/win32/main.c +++ b/win32/main.c @@ -22,6 +22,7 @@  #include "about.h"  #include "common/fmplayer_common.h"  #include "wavesave.h" +#include "fft/fft.h"  enum {    ID_OPENFILE = 0x10, @@ -74,7 +75,12 @@ static struct {    HBITMAP bitmap_vram;    uint8_t *vram32;    bool drum_loaded; -} g; +  atomic_flag at_fftdata_flag; +  struct fmplayer_fft_data at_fftdata; +  struct fmplayer_fft_input_data fftdata; +} g = { +  .at_fftdata_flag = ATOMIC_FLAG_INIT, +};  HWND g_currentdlg; @@ -92,6 +98,11 @@ static void sound_cb(void *p, int16_t *buf, unsigned frames) {      memcpy(oscilloview_g.oscillodata, g.oscillodata_audiothread, sizeof(oscilloview_g.oscillodata));      atomic_flag_clear_explicit(&oscilloview_g.flag, memory_order_release);    } +  if (!atomic_flag_test_and_set_explicit( +    &g.at_fftdata_flag, memory_order_acquire)) { +    fft_write(&g.at_fftdata, buf, frames); +    atomic_flag_clear_explicit(&g.at_fftdata_flag, memory_order_release); +  }  }  static bool loadfontrom(void) { @@ -170,6 +181,7 @@ static void openfile(HWND hwnd, const wchar_t *path) {    if (!g.sound) goto err;    g.sound->pause(g.sound, 0);    g.paused = false; +  g.work.paused = false;    wchar_t *pathcpy = HeapAlloc(g.heap, 0, (lstrlen(path)+1)*sizeof(wchar_t));    if (pathcpy) {      lstrcpy(pathcpy, path); @@ -333,6 +345,7 @@ static bool proc_key(UINT vk, bool down, int repeat) {          case VK_F7:            if (g.sound) {              g.paused = !g.paused; +            g.work.paused = g.paused;              g.sound->pause(g.sound, g.paused);            }            return true; @@ -549,6 +562,7 @@ static void on_command(HWND hwnd, int id, HWND hwnd_c, UINT code) {    case ID_PAUSE:      if (g.sound) {        g.paused = !g.paused; +      g.work.paused = g.paused;        g.sound->pause(g.sound, g.paused);      }      break; @@ -611,7 +625,12 @@ static void on_destroy(HWND hwnd) {  }  static void on_paint(HWND hwnd) { -  fmdsp_update(&g.fmdsp, &g.work, &g.opna, g.vram); +  if (!atomic_flag_test_and_set_explicit( +    &g.at_fftdata_flag, memory_order_acquire)) { +    memcpy(&g.fftdata.fdata, &g.at_fftdata, sizeof(g.fftdata)); +    atomic_flag_clear_explicit(&g.at_fftdata_flag, memory_order_release); +  } +  fmdsp_update(&g.fmdsp, &g.work, &g.opna, g.vram, &g.fftdata);    fmdsp_vrampalette(&g.fmdsp, g.vram, g.vram32, PC98_W*4);    PAINTSTRUCT ps;    HDC dc = BeginPaint(hwnd, &ps); @@ -738,6 +757,8 @@ int CALLBACK wWinMain(HINSTANCE hinst, HINSTANCE hpinst,    if (__builtin_cpu_supports("sse2")) opna_ssg_sinc_calc_func = opna_ssg_sinc_calc_sse2;    if (__builtin_cpu_supports("ssse3")) fmdsp_vramlookup_func = fmdsp_vramlookup_ssse3; +  fft_init_table(); +    const wchar_t *argfile = 0;    {      wchar_t *cmdline = GetCommandLine(); diff --git a/win32/wavewrite.c b/win32/wavewrite.c index 7c2d6da..37f6145 100644 --- a/win32/wavewrite.c +++ b/win32/wavewrite.c @@ -3,6 +3,7 @@  #define WIN32_LEAN_AND_MEAN  #include <windows.h>  #include <stdlib.h> +#include <stdio.h>  struct wavefile {    HANDLE file; @@ -67,17 +68,16 @@ size_t wavewrite_write(struct wavefile *wavefile, const int16_t *buf, size_t fra  }  void wavewrite_close(struct wavefile *wavefile) { -  LONG fp;    uint32_t size;    DWORD written; -  if ((SetFilePointer(wavefile->file, 40, &fp, FILE_BEGIN) == INVALID_SET_FILE_POINTER) || (fp != 40)) { +  if (SetFilePointer(wavefile->file, 40, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {      goto cleanup;    }    size = wavefile->written_frames * 4;    if (!WriteFile(wavefile->file, &size, sizeof(size), &written, 0) || (written != sizeof(size))) {      goto cleanup;    } -  if ((SetFilePointer(wavefile->file, 4, &fp, FILE_BEGIN) == INVALID_SET_FILE_POINTER) || (fp != 4)) { +  if (SetFilePointer(wavefile->file, 4, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {      goto cleanup;    }    size += 4 + 8 + 16 + 8; diff --git a/win32/x86/Makefile b/win32/x86/Makefile index 6146d28..ea2e16e 100644 --- a/win32/x86/Makefile +++ b/win32/x86/Makefile @@ -4,6 +4,7 @@ vpath %.c ../../libopna  vpath %.c ../../fmdsp  vpath %.c ../../tonedata  vpath %.c ../../common +vpath %.c ../../fft  vpath %.rc ..  include ../fmplayer.mak | 
