diff options
| -rw-r--r-- | fmdriver/fmdriver_fmp.c | 59 | ||||
| -rw-r--r-- | fmdriver/fmdriver_fmp.h | 1 | ||||
| -rw-r--r-- | fmdriver/ppz8.c | 11 | ||||
| -rw-r--r-- | fmdriver/ppz8.h | 3 | ||||
| -rw-r--r-- | fmdsp/fmdsp.c | 176 | ||||
| -rw-r--r-- | fmdsp/fmdsp.h | 11 | ||||
| -rw-r--r-- | fmdsp/fmdsp_sprites.h | 119 | ||||
| -rw-r--r-- | libopna/opnaadpcm.c | 8 | ||||
| -rw-r--r-- | libopna/opnaadpcm.h | 3 | ||||
| -rw-r--r-- | libopna/opnadrum.c | 7 | ||||
| -rw-r--r-- | libopna/opnadrum.h | 2 | ||||
| -rw-r--r-- | libopna/opnafm.c | 13 | ||||
| -rw-r--r-- | libopna/opnafm.h | 3 | ||||
| -rw-r--r-- | libopna/opnassg.c | 13 | ||||
| -rw-r--r-- | libopna/opnassg.h | 2 | 
15 files changed, 398 insertions, 33 deletions
| diff --git a/fmdriver/fmdriver_fmp.c b/fmdriver/fmdriver_fmp.c index 5e01089..74c119c 100644 --- a/fmdriver/fmdriver_fmp.c +++ b/fmdriver/fmdriver_fmp.c @@ -2698,6 +2698,7 @@ static void fmp_part_cmd_rhythm(struct fmdriver_work *work,              uint8_t voice = fmp->pdzf.rhythm[p&1].voice[((rhythm->volumes[p] & 0x10) >> 4)];
              uint8_t pan = fmp->pdzf.rhythm[p&1].pan + 5;
              uint32_t freq = fmp_ppz8_note_freq(fmp->pdzf.rhythm[p&1].note);
 +            fmp->pdzf.rhythm_current_note = fmp->pdzf.rhythm[p&1].note;
              uint8_t channel = 6;
              work->ppz8_functbl->channel_play(
                work->ppz8,
 @@ -2777,15 +2778,40 @@ static void fmp_work_status_init(struct fmdriver_work *work,  static void fmp_work_status_update(struct fmdriver_work *work,
                                     const struct driver_fmp *fmp) {
    work->ssg_noise_freq = fmp->ssg_noise_freq;
 -  for (int t = 0; t < FMDRIVER_TRACK_NUM; t++) {
 +  for (int t = 0; t < FMDRIVER_TRACK_PPZ8_1; t++) {
      struct fmdriver_track_status *track = &work->track_status[t];
      const struct fmp_part *part = &fmp->parts[fmp_track_map[t]];
      track->playing = !part->status.off;
      track->info = FMDRIVER_TRACK_INFO_NORMAL;
 +    track->ticks = part->status.off ? 0 : part->tonelen-1;
 +    track->ticks_left = part->tonelen_cnt;
 +    track->key = part->status.rest ? 0xff : fmp_note2key(part->prev_note);
 +    track->tonenum = part->tone;
 +    track->detune = part->detune - ((part->detune & 0x8000) ? 0x10000 : 0);
 +    track->status[0] = part->lfo_f.p ? 'P' : '-';
 +    track->status[1] = part->lfo_f.q ? 'Q' : '-';
 +    track->status[2] = part->lfo_f.r ? 'R' : '-';
 +    track->status[3] = part->lfo_f.a ? 'A' : '-';
 +    track->status[4] = '-';
 +    track->status[5] = part->lfo_f.e ? 'e' : '-';
 +    track->status[6] = (part->type.fm && part->u.fm.hlfo_apms) ? 'H' : '-';
 +    track->status[7] = part->status.pitchbend ? 'P' : '-';
      if (part->type.adpcm) {
        track->actual_key = 0xff;
        track->volume = part->actual_vol;
      } else if (part->type.ssg) {
 +      struct fmdriver_track_status *ppztrack =
 +          &work->track_status[FMDRIVER_TRACK_PPZ8_1-1+track->ppz8_ch];
 +      ppztrack->actual_key = 0xff;
 +      if (part->pdzf.mode || part->u.ssg.env_f.ppz) {
 +        ppztrack->playing = !part->status.off;
 +        ppztrack->key = track->key;
 +        ppztrack->tonenum = track->tonenum;
 +        ppztrack->info = FMDRIVER_TRACK_INFO_NORMAL;
 +      } else {
 +        ppztrack->playing = false;
 +        ppztrack->key = 0xff;
 +      }
        if (part->pdzf.mode) {
          track->info = FMDRIVER_TRACK_INFO_PDZF;
          track->actual_key = 0xff;
 @@ -2801,8 +2827,15 @@ static void fmp_work_status_update(struct fmdriver_work *work,        track->volume = part->current_vol - 1;
      } else {
        if (part->pdzf.mode) {
 +        struct fmdriver_track_status *ppztrack =
 +            &work->track_status[FMDRIVER_TRACK_PPZ8_1-1+track->ppz8_ch];
          track->info = FMDRIVER_TRACK_INFO_PDZF;
          track->actual_key = 0xff;
 +        ppztrack->actual_key = 0xff;
 +        ppztrack->playing = !part->status.off;
 +        ppztrack->key = track->key;
 +        ppztrack->tonenum = work->ppz8 ? work->ppz8->channel[track->ppz8_ch-1].voice : 0;
 +        ppztrack->info = FMDRIVER_TRACK_INFO_NORMAL;
        } else {
          if (part->u.fm.slot_mask & 0xf0) {
            track->info = FMDRIVER_TRACK_INFO_FM3EX;
 @@ -2814,20 +2847,13 @@ static void fmp_work_status_update(struct fmdriver_work *work,        }
        track->volume = 0x7f - part->actual_vol;
      }
 -    track->ticks = part->status.off ? 0 : part->tonelen-1;
 -    track->ticks_left = part->tonelen_cnt;
 -    track->key = part->status.rest ? 0xff : fmp_note2key(part->prev_note);
 -    track->tonenum = part->tone;
 -    track->detune = part->detune - ((part->detune & 0x8000) ? 0x10000 : 0);
 -    track->status[0] = part->lfo_f.p ? 'P' : '-';
 -    track->status[1] = part->lfo_f.q ? 'Q' : '-';
 -    track->status[2] = part->lfo_f.r ? 'R' : '-';
 -    track->status[3] = part->lfo_f.a ? 'A' : '-';
 -    track->status[4] = '-';
 -    track->status[5] = part->lfo_f.e ? 'e' : '-';
 -    track->status[6] = (part->type.fm && part->u.fm.hlfo_apms) ? 'H' : '-';
 -    track->status[7] = part->status.pitchbend ? 'P' : '-';
    }
 +  work->track_status[FMDRIVER_TRACK_PPZ8_7].playing = fmp->pdzf.rhythm[0].enabled || fmp->pdzf.rhythm[1].enabled;
 +  work->track_status[FMDRIVER_TRACK_PPZ8_7].tonenum = work->ppz8 ? work->ppz8->channel[6].voice : 0;
 +  uint8_t key = 0xff;
 +  if (work->ppz8 && work->ppz8->channel[6].playing) key = fmp->pdzf.rhythm_current_note;
 +  work->track_status[FMDRIVER_TRACK_PPZ8_7].key = key;
 +  work->track_status[FMDRIVER_TRACK_PPZ8_7].actual_key = key;
  }
  static void fmp_part_pdzf_freq_update(
 @@ -3147,6 +3173,11 @@ static void fmp_struct_init(struct fmdriver_work *work,    fmp->parts[FMP_PART_FM_EX3].pdzf.ppz8_channel = 5;
    fmp->parts[FMP_PART_FM_EX3].pdzf.loopstart32 = -1;
    fmp->parts[FMP_PART_FM_EX3].pdzf.loopend32 = -1;
 +  
 +  // ppz8 unused parts
 +  for (int i = 0; i < 8; i++) {
 +    fmp->parts[FMP_PART_PPZ8_1+i].status.off = true;
 +  }
  }
  // 1774
 diff --git a/fmdriver/fmdriver_fmp.h b/fmdriver/fmdriver_fmp.h index 4fd107a..ead8074 100644 --- a/fmdriver/fmdriver_fmp.h +++ b/fmdriver/fmdriver_fmp.h @@ -534,6 +534,7 @@ struct driver_fmp {        uint8_t note;        bool enabled;      } rhythm[2]; +    uint8_t rhythm_current_note;    } pdzf;  }; diff --git a/fmdriver/ppz8.c b/fmdriver/ppz8.c index 4dea524..d1afd72 100644 --- a/fmdriver/ppz8.c +++ b/fmdriver/ppz8.c @@ -37,6 +37,7 @@ void ppz8_init(struct ppz8 *ppz8, uint16_t srate, uint16_t mix_volume) {      channel->vol = 8;      channel->pan = 5;      channel->voice = 0; +    leveldata_init(&channel->leveldata);    }    ppz8->srate = srate;    ppz8->totalvol = 12; @@ -128,6 +129,7 @@ static int32_t ppz8_channel_calc(struct ppz8 *ppz8, struct ppz8_channel *channel  }  void ppz8_mix(struct ppz8 *ppz8, int16_t *buf, unsigned samples) { +  unsigned level[8] = {0};    static const uint8_t pan_vol[10][2] = {      {0, 0},      {4, 0}, @@ -144,11 +146,13 @@ void ppz8_mix(struct ppz8 *ppz8, int16_t *buf, unsigned samples) {      int32_t lo = buf[i*2+0];      int32_t ro = buf[i*2+1];      for (int p = 0; p < 8; p++) { -      //if (p < 3) continue; -      //if (p >= 6) continue;        struct ppz8_channel *channel = &ppz8->channel[p];        if (!channel->playing) continue;        int32_t out = ppz8_channel_calc(ppz8, channel); +      { +        unsigned uout = out > 0 ? out : -out; +        if (uout > level[p]) level[p] = uout; +      }        if ((1u << p) & (ppz8->mask)) continue;        out *= ppz8->mix_volume;        out >>= 15; @@ -162,6 +166,9 @@ void ppz8_mix(struct ppz8 *ppz8, int16_t *buf, unsigned samples) {      buf[i*2+0] = lo;      buf[i*2+1] = ro;    } +  for (int p = 0; p < 8; p++) { +    leveldata_update(&ppz8->channel[p].leveldata, level[p]); +  }  }  static int16_t calc_acc(int16_t acc, uint16_t adpcmd, uint8_t data) { diff --git a/fmdriver/ppz8.h b/fmdriver/ppz8.h index f4ef4cb..35c67dc 100644 --- a/fmdriver/ppz8.h +++ b/fmdriver/ppz8.h @@ -3,6 +3,8 @@  #include <stdint.h>  #include <stdbool.h> +#include <stdatomic.h> +#include "leveldata/leveldata.h"  #ifdef __cplusplus  extern "C" { @@ -35,6 +37,7 @@ struct ppz8_channel {    uint8_t pan;    uint8_t voice;    bool playing; +  struct leveldata leveldata;  };  struct ppz8 { diff --git a/fmdsp/fmdsp.c b/fmdsp/fmdsp.c index 7331dc2..16fe141 100644 --- a/fmdsp/fmdsp.c +++ b/fmdsp/fmdsp.c @@ -6,6 +6,8 @@  #include "libopna/opna.h"  #include "fmdsp_platform_info.h"  #include "version.h" +#include <math.h> +#include <string.h>  fmdsp_vramlookup_type fmdsp_vramlookup_func = fmdsp_vramlookup_c; @@ -87,7 +89,7 @@ static void fmdsp_putline(const char *strptr, uint8_t *vram,            xo -= (xo % (fw*8));            cp932str++;          } else { -          if ((x+xo+8) > PC98_W) return; +          if ((x+xo+fw) > PC98_W) return;            const void *fp = font->get(font, *cp932str++, FMDSP_FONT_ANK);            if (fp) {              vram_putchar(vram, fp, x+xo, y, fw, fh, color, bg); @@ -102,7 +104,7 @@ static void fmdsp_putline(const char *strptr, uint8_t *vram,        uint8_t sjis_2nd = *cp932str++;        uint16_t jis = sjis2jis(sjis_1st, sjis_2nd);        bool half = jis_is_halfwidth(jis); -      if ((x+xo+(half ? 8 : 16)) > PC98_W) return; +      if ((x+xo+fw*(half ? 1 : 2)) > PC98_W) return;        const void *fp = font->get(font, jis, FMDSP_FONT_JIS_LEFT);        if (fp) {          vram_putchar(vram, fp, x+xo, y, fw, fh, color, bg); @@ -395,10 +397,35 @@ static void fmdsp_track_init_10(struct fmdsp *fmdsp,      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); +    fmdsp_putline("ON", vram, &font_fmdsp_small, +                  LEVEL_TEXT_X+5, LEVEL_TEXT_Y, 1, true); +    fmdsp_putline("PAN", vram, &font_fmdsp_small, +                  LEVEL_TEXT_X, LEVEL_TEXT_Y+8, 1, true); +    fmdsp_putline("PROG", vram, &font_fmdsp_small, +                  LEVEL_TEXT_X-5, LEVEL_TEXT_Y+16, 1, true); +    fmdsp_putline("KEY", vram, &font_fmdsp_small, +                  LEVEL_TEXT_X, LEVEL_TEXT_Y+23, 1, true); +    fmdsp_putline("FM1", vram, &font_fmdsp_small, +                  LEVEL_X+LEVEL_W*0, LEVEL_TRACK_Y, 7, true); +    fmdsp_putline("FM4", vram, &font_fmdsp_small, +                  LEVEL_X+LEVEL_W*3, LEVEL_TRACK_Y, 7, true); +    fmdsp_putline("SSG", vram, &font_fmdsp_small, +                  LEVEL_X+LEVEL_W*6, LEVEL_TRACK_Y, 7, true); +    fmdsp_putline("RHY", vram, &font_fmdsp_small, +                  LEVEL_X+LEVEL_W*9, LEVEL_TRACK_Y, 7, true); +    fmdsp_putline("ADP", vram, &font_fmdsp_small, +                  LEVEL_X+LEVEL_W*10, LEVEL_TRACK_Y, 7, true); +    fmdsp_putline("PPZ", vram, &font_fmdsp_small, +                  LEVEL_X+LEVEL_W*11, LEVEL_TRACK_Y, 7, true); +    for (int y = 0; y < 63; y++) { +      vram[(LEVEL_Y+y)*PC98_W+LEVEL_X-2] = 2; +      if ((y % 2) == 0) vram[(LEVEL_Y+y)*PC98_W+LEVEL_X-3] = 2; +      if ((y % 8) == 6) vram[(LEVEL_Y+y)*PC98_W+LEVEL_X-4] = 2; +    } +    fmdsp_putline("0", vram, &font_fmdsp_small, +                  LEVEL_X-9, LEVEL_Y-1, 7, true); +    fmdsp_putline("-48", vram, &font_fmdsp_small, +                  LEVEL_X-19, LEVEL_Y+56, 7, true);    }  } @@ -713,8 +740,8 @@ static void fmdsp_track_without_key(  }  static void fmdsp_update_10(struct fmdsp *fmdsp, -                  const struct fmdriver_work *work, -                  const struct opna *opna, +                  struct fmdriver_work *work, +                  struct opna *opna,                    uint8_t *vram,                    struct fmplayer_fft_input_data *idata) {    if (fmdsp->style != FMDSP_DISPSTYLE_ORIGINAL) { @@ -939,6 +966,134 @@ static void fmdsp_update_10(struct fmdsp *fmdsp,        vram[py*PC98_W+px+1] = 7;        vram[py*PC98_W+px+2] = 7;      } +    // level +    struct { +      unsigned level; +      int t; +      bool masked; +      uint8_t pan; +      uint8_t prog; +      uint8_t key; +      bool playing; +    } levels[FMDSP_LEVEL_COUNT] = {0}; +    for (int c = 0; c < 6; c++) { +      levels[c].level = leveldata_read(&opna->fm.channel[c].leveldata); +      static const int table[4] = {5, 4, 0, 2}; +      levels[c].pan = table[opna->fm.lselect[c]*2 + opna->fm.rselect[c]]; +    } +    levels[0].t = FMDRIVER_TRACK_FM_1; +    levels[1].t = FMDRIVER_TRACK_FM_2; +    levels[2].t = FMDRIVER_TRACK_FM_3; +    levels[3].t = FMDRIVER_TRACK_FM_4; +    levels[4].t = FMDRIVER_TRACK_FM_5; +    levels[5].t = FMDRIVER_TRACK_FM_6; +     +    for (int c = 0; c < 3; c++) { +      levels[6+c].level = leveldata_read(&opna->resampler.leveldata[c]); +      levels[6+c].t = FMDRIVER_TRACK_SSG_1+c; +      levels[6+c].pan = 2; +    } +    { +      unsigned dl = 0; +      for (int d = 0; d < 6; d++) { +        unsigned l = leveldata_read(&opna->drum.drums[d].leveldata); +        if (l > dl) dl = l; +      } +      levels[9].level = dl; +      levels[9].pan = 2; +    } +    levels[10].level = leveldata_read(&opna->adpcm.leveldata); +    levels[10].t = FMDRIVER_TRACK_ADPCM; +    { +      static const int table[4] = {5, 4, 0, 2}; +      int ind = 0; +      if (opna->adpcm.control2 & 0x80) ind |= 2; +      if (opna->adpcm.control2 & 0x40) ind |= 1; +      levels[10].pan = table[ind]; +    } +    for (int p = 0; p < 8; p++) { +      levels[11+p].pan = 5; +      levels[11+p].t = FMDRIVER_TRACK_PPZ8_1+p; +    } +    if (work->ppz8) { +      for (int p = 0; p < 8; p++) { +        levels[11+p].level = leveldata_read(&work->ppz8->channel[p].leveldata); +        static const int table[10] = {5, 0, 1, 1, 1, 2, 3, 3, 3, 4}; +        levels[11+p].pan = table[work->ppz8->channel[p].pan]; +      } +    } +    for (int c = 0; c < FMDSP_LEVEL_COUNT; c++) { +      levels[c].masked = c == 9 ? fmdsp->masked_rhythm : fmdsp->masked[levels[c].t]; +      levels[c].prog = work->track_status[levels[c].t].tonenum; +      levels[c].key = work->track_status[levels[c].t].key; +      levels[c].playing = work->track_status[levels[c].t].playing; +      if (work->track_status[levels[c].t].info == FMDRIVER_TRACK_INFO_PDZF || +          work->track_status[levels[c].t].info == FMDRIVER_TRACK_INFO_PPZ8) { +        levels[c].playing = false; +      } +      if (!levels[c].playing) levels[c].pan = 5; +    } +     +    for (int c = 0; c < FMDSP_LEVEL_COUNT; c++) { +      unsigned level = levels[c].level; +      unsigned llevel = 0; +      if (level) { +        float db = 20.0f * log10f((float)level / (1<<15)); +        float fllevel = (db / 48.0f + 1.0f) * 32.0f; +        if (fllevel > 0.0f) llevel = fllevel; +      } +       +      if (fmdsp->leveldata[c] <= llevel) { +        fmdsp->leveldata[c] = llevel; +        fmdsp->levelcnt[c] = 30; +      } else { +        if (fmdsp->levelcnt[c]) { +          fmdsp->levelcnt[c]--; +        } else { +          if (fmdsp->leveldata[c]) { +            if (fmdsp->leveldropdiv[c]) { +              fmdsp->leveldropdiv[c]--; +            } else { +              static const uint8_t divtab[16] = { +                32, 16, 8, 8, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, +              }; +              fmdsp->leveldropdiv[c] = divtab[fmdsp->leveldata[c] / 2]; +              fmdsp->leveldata[c]--; +            } +          } +        } +      } +      for (unsigned y = 0; y < 64; y += 2) { +        unsigned plevel = (63 - y) / 2; +        for (int x = 0; x < LEVEL_DISP_W; x++) { +          uint8_t color = llevel > plevel ? 2 : 3; +          if (plevel == fmdsp->leveldata[c]) color = 7; +          vram[(y+LEVEL_Y)*PC98_W+LEVEL_X+LEVEL_W*c+x] = color; +        } +      } +      vramblit_color(vram, +                     LEVEL_X+LEVEL_W*c-1, PANPOT_Y, +                     s_panpot[levels[c].pan], PANPOT_W, PANPOT_H, +                     levels[c].masked ? 5 : 1); +      char buf[4]; +      if (c != 9) { +        snprintf(buf, sizeof(buf), "%03d", levels[c].prog); +        fmdsp_putline(buf, vram, &font_fmdsp_small, +                      LEVEL_X+LEVEL_W*c, LEVEL_PROG_Y, +                      1, true); +      } +      strcpy(buf, "---"); +      if (c != 9 && levels[c].playing) { +        uint8_t oct = levels[c].key >> 4; +        uint8_t n = levels[c].key & 0xf; +        if (n < 12) { +          snprintf(buf, sizeof(buf), "%03d", oct*12+n); +        } +      } +      fmdsp_putline(buf, vram, &font_fmdsp_small, +                    LEVEL_X+LEVEL_W*c, LEVEL_KEY_Y, +                    1, true); +    }    }  }  static void fmdsp_update_13(struct fmdsp *fmdsp, @@ -997,8 +1152,8 @@ static void fmdsp_update_13(struct fmdsp *fmdsp,  }  void fmdsp_update(struct fmdsp *fmdsp, -                  const struct fmdriver_work *work, -                  const struct opna *opna, +                  struct fmdriver_work *work, +                  struct opna *opna,                    uint8_t *vram,                    struct fmplayer_fft_input_data *idata) {    if (fmdsp->style_updated) { @@ -1022,6 +1177,7 @@ void fmdsp_update(struct fmdsp *fmdsp,    fmdsp->masked[FMDRIVER_TRACK_SSG_2] = mask & LIBOPNA_CHAN_SSG_2;    fmdsp->masked[FMDRIVER_TRACK_SSG_3] = mask & LIBOPNA_CHAN_SSG_3;    fmdsp->masked[FMDRIVER_TRACK_ADPCM] = mask & LIBOPNA_CHAN_ADPCM; +  fmdsp->masked_rhythm = (mask & LIBOPNA_CHAN_DRUM_ALL) == LIBOPNA_CHAN_DRUM_ALL;    unsigned ppz8mask = 0;    if (work->ppz8) {      ppz8mask = ppz8_get_mask(work->ppz8); diff --git a/fmdsp/fmdsp.h b/fmdsp/fmdsp.h index 6a98707..e458d39 100644 --- a/fmdsp/fmdsp.h +++ b/fmdsp/fmdsp.h @@ -19,7 +19,8 @@ enum {  };  enum { -  FMDSP_PALETTE_COLORS = 10 +  FMDSP_PALETTE_COLORS = 10, +  FMDSP_LEVEL_COUNT = 19,  };  enum FMDSP_DISPSTYLE { @@ -38,12 +39,16 @@ struct fmdsp {    enum FMDSP_DISPSTYLE style;    bool style_updated;    bool masked[FMDRIVER_TRACK_NUM]; +  bool masked_rhythm;    uint8_t fftdata[FFTDISPLEN];    uint8_t fftcnt[FFTDISPLEN];    uint8_t fftdropdiv[FFTDISPLEN];    uint64_t framecnt;    int cpuusage;    int fps; +  uint8_t leveldata[FMDSP_LEVEL_COUNT]; +  uint8_t levelcnt[FMDSP_LEVEL_COUNT]; +  uint8_t leveldropdiv[FMDSP_LEVEL_COUNT];  };  struct fmdriver_work; @@ -51,8 +56,8 @@ void fmdsp_init(struct fmdsp *fmdsp, const struct fmdsp_font *font);  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, +void fmdsp_update(struct fmdsp *fmdsp, struct fmdriver_work *work, +                  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); diff --git a/fmdsp/fmdsp_sprites.h b/fmdsp/fmdsp_sprites.h index d9d71ac..c942e24 100644 --- a/fmdsp/fmdsp_sprites.h +++ b/fmdsp/fmdsp_sprites.h @@ -14,8 +14,8 @@ enum {    TDETAIL_GT_X = TDETAIL_VL_V_X+19,    TDETAIL_GT_V_X = TDETAIL_GT_X+13,    TDETAIL_DT_X = TDETAIL_GT_V_X+23, -  TDETAIL_DT_S_X = TDETAIL_DT_X+12, -  TDETAIL_DT_V_X = TDETAIL_DT_S_X+5, +  TDETAIL_DT_S_X = TDETAIL_DT_X+13, +  TDETAIL_DT_V_X = TDETAIL_DT_S_X+4,    TDETAIL_M_X = 249,    TDETAIL_M_V_X = TDETAIL_M_X+8,    NUM_X = 31, @@ -166,6 +166,16 @@ enum {    FLOPPY_Y = 87,    LEVEL_TEXT_X = 318,    LEVEL_TEXT_Y = 290, +  LEVEL_X = 353-16, +  LEVEL_Y = 227, +  LEVEL_DISP_W = 14, +  LEVEL_W = 16, +  PANPOT_W = 15, +  PANPOT_H = 15, +  PANPOT_Y = LEVEL_Y+64, +  LEVEL_TRACK_Y = LEVEL_Y-9, +  LEVEL_PROG_Y = PANPOT_Y+15, +  LEVEL_KEY_Y = LEVEL_PROG_Y+7,  };  enum { @@ -867,3 +877,108 @@ static uint8_t s_floppy[FLOPPY_W*FLOPPY_H] = {    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,  }; + +static uint8_t s_panpot[6][PANPOT_W*PANPOT_H] = { +  { +    0,0,0,0,0,1,1,1,1,1,0,0,0,0,0, +    0,0,0,1,1,0,0,0,0,0,1,1,0,0,0, +    0,0,1,0,0,0,0,0,0,0,0,0,1,0,0, +    0,1,0,1,1,1,0,0,0,0,0,0,0,1,0, +    0,1,0,1,1,0,0,0,0,0,0,0,0,1,0, +    1,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,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,1,0, +    0,1,0,0,0,0,0,0,0,0,0,0,0,1,0, +    0,0,1,0,0,0,0,0,0,0,0,0,1,0,0, +    0,0,0,1,1,0,0,0,0,0,1,1,0,0,0, +    0,0,0,0,0,1,1,1,1,1,0,0,0,0,0, +  }, +  { +    0,0,0,0,0,1,1,1,1,1,0,0,0,0,0, +    0,0,0,1,1,0,0,0,0,0,1,1,0,0,0, +    0,0,1,0,0,1,1,0,0,0,0,0,1,0,0, +    0,1,0,0,0,1,1,1,1,0,0,0,0,1,0, +    0,1,0,0,1,1,1,0,0,0,0,0,0,1,0, +    1,0,0,0,1,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,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,1,0, +    0,1,0,0,0,0,0,0,0,0,0,0,0,1,0, +    0,0,1,0,0,0,0,0,0,0,0,0,1,0,0, +    0,0,0,1,1,0,0,0,0,0,1,1,0,0,0, +    0,0,0,0,0,1,1,1,1,1,0,0,0,0,0, +  }, +  { +    0,0,0,0,0,1,1,1,1,1,0,0,0,0,0, +    0,0,0,1,1,0,0,0,0,0,1,1,0,0,0, +    0,0,1,0,0,0,1,1,1,0,0,0,1,0,0, +    0,1,0,0,0,1,1,1,1,1,0,0,0,1,0, +    0,1,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,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,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,1,0, +    0,1,0,0,0,0,0,0,0,0,0,0,0,1,0, +    0,0,1,0,0,0,0,0,0,0,0,0,1,0,0, +    0,0,0,1,1,0,0,0,0,0,1,1,0,0,0, +    0,0,0,0,0,1,1,1,1,1,0,0,0,0,0, +  }, +  { +    0,0,0,0,0,1,1,1,1,1,0,0,0,0,0, +    0,0,0,1,1,0,0,0,0,0,1,1,0,0,0, +    0,0,1,0,0,0,0,0,1,1,0,0,1,0,0, +    0,1,0,0,0,0,1,1,1,1,0,0,0,1,0, +    0,1,0,0,0,0,0,0,1,1,1,0,0,1,0, +    1,0,0,0,0,0,0,0,0,0,1,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,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,1,0, +    0,1,0,0,0,0,0,0,0,0,0,0,0,1,0, +    0,0,1,0,0,0,0,0,0,0,0,0,1,0,0, +    0,0,0,1,1,0,0,0,0,0,1,1,0,0,0, +    0,0,0,0,0,1,1,1,1,1,0,0,0,0,0, +  }, +  { +    0,0,0,0,0,1,1,1,1,1,0,0,0,0,0, +    0,0,0,1,1,0,0,0,0,0,1,1,0,0,0, +    0,0,1,0,0,0,0,0,0,0,0,0,1,0,0, +    0,1,0,0,0,0,0,0,0,1,1,1,0,1,0, +    0,1,0,0,0,0,0,0,0,0,1,1,0,1,0, +    1,0,0,0,0,0,0,0,0,0,0,1,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,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,1,0, +    0,1,0,0,0,0,0,0,0,0,0,0,0,1,0, +    0,0,1,0,0,0,0,0,0,0,0,0,1,0,0, +    0,0,0,1,1,0,0,0,0,0,1,1,0,0,0, +    0,0,0,0,0,1,1,1,1,1,0,0,0,0,0, +  }, +  { +    0,0,0,0,0,1,1,1,1,1,0,0,0,0,0, +    0,0,0,1,1,0,0,0,0,0,1,1,0,0,0, +    0,0,1,0,0,0,0,0,0,0,0,0,1,0,0, +    0,1,0,0,0,0,0,0,0,0,0,0,0,1,0, +    0,1,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,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +    1,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,1,0, +    0,1,0,0,0,0,0,0,0,0,0,0,0,1,0, +    0,0,1,0,0,0,0,0,0,0,0,0,1,0,0, +    0,0,0,1,1,0,0,0,0,0,1,1,0,0,0, +    0,0,0,0,0,1,1,1,1,1,0,0,0,0,0, +  }, +}; diff --git a/libopna/opnaadpcm.c b/libopna/opnaadpcm.c index 68dbae5..361064a 100644 --- a/libopna/opnaadpcm.c +++ b/libopna/opnaadpcm.c @@ -35,6 +35,7 @@ void opna_adpcm_reset(struct opna_adpcm *adpcm) {    adpcm->prev_acc = 0;    adpcm->adpcmd = 127;    adpcm->out = 0; +  leveldata_init(&adpcm->leveldata);  }  static uint32_t addr_conv(const struct opna_adpcm *adpcm, uint16_t a) { @@ -183,8 +184,14 @@ void opna_adpcm_writereg(struct opna_adpcm *adpcm, unsigned reg, unsigned val) {  void opna_adpcm_mix(struct opna_adpcm *adpcm, int16_t *buf, unsigned samples) {    if (!adpcm->ram) return;    if (!(adpcm->control1 & C1_START)) return; +  unsigned level = 0;    for (unsigned i = 0; i < samples; i++) {      adpcm_calc(adpcm); +    { +      int clevel = adpcm->out>>1; +      if (clevel < 0) clevel = -clevel; +      if (((unsigned)clevel) > level) level = clevel; +    }      if (!adpcm->masked) {        int32_t lo = buf[i*2+0];        int32_t ro = buf[i*2+1]; @@ -199,6 +206,7 @@ void opna_adpcm_mix(struct opna_adpcm *adpcm, int16_t *buf, unsigned samples) {      }      if (!(adpcm->control1 & C1_START)) return;    } +  leveldata_update(&adpcm->leveldata, level);  }  void opna_adpcm_set_ram_256k(struct opna_adpcm *adpcm, void *ram) { diff --git a/libopna/opnaadpcm.h b/libopna/opnaadpcm.h index 42033ad..27a0be3 100644 --- a/libopna/opnaadpcm.h +++ b/libopna/opnaadpcm.h @@ -3,6 +3,7 @@  #include <stdint.h>  #include <stdbool.h> +#include "leveldata/leveldata.h"  #ifdef __cplusplus  extern "C" { @@ -24,6 +25,8 @@ struct opna_adpcm {    uint16_t adpcmd;    int16_t out;    bool masked; +  atomic_uint levelvu; +  struct leveldata leveldata;  };  void opna_adpcm_reset(struct opna_adpcm *adpcm); diff --git a/libopna/opnadrum.c b/libopna/opnadrum.c index 1a298af..c3e8d38 100644 --- a/libopna/opnadrum.c +++ b/libopna/opnadrum.c @@ -23,6 +23,7 @@ void opna_drum_reset(struct opna_drum *drum) {      drum->drums[d].level = 0;      drum->drums[d].left = false;      drum->drums[d].right = false; +    leveldata_init(&drum->drums[d].leveldata);    }    drum->total_level = 0;    drum->mask = 0; @@ -81,6 +82,7 @@ void opna_drum_set_rom(struct opna_drum *drum, void *romptr) {  }  void opna_drum_mix(struct opna_drum *drum, int16_t *buf, int samples) { +  unsigned levels[6] = {0};    for (int i = 0; i < samples; i++) {      int32_t lo = buf[i*2+0];      int32_t ro = buf[i*2+1]; @@ -91,6 +93,8 @@ void opna_drum_mix(struct opna_drum *drum, int16_t *buf, int samples) {          unsigned level = (drum->drums[d].level^0x1f) + (drum->total_level^0x3f);          co *= 15 - (level&7);          co >>= 1+(level>>3); +        unsigned outlevel = co > 0 ? co : -co; +        if (outlevel > levels[d]) levels[d] = outlevel;          if (!(drum->mask & (1u << d))) {            if (drum->drums[d].left) lo += co;            if (drum->drums[d].right) ro += co; @@ -109,6 +113,9 @@ void opna_drum_mix(struct opna_drum *drum, int16_t *buf, int samples) {      buf[i*2+0] = lo;      buf[i*2+1] = ro;    } +  for (int d = 0; d < 6; d++) { +    leveldata_update(&drum->drums[d].leveldata, levels[d]); +  }  }  void opna_drum_writereg(struct opna_drum *drum, unsigned reg, unsigned val) { diff --git a/libopna/opnadrum.h b/libopna/opnadrum.h index 79f95a2..7260995 100644 --- a/libopna/opnadrum.h +++ b/libopna/opnadrum.h @@ -3,6 +3,7 @@  #include <stdint.h>  #include <stdbool.h> +#include "leveldata/leveldata.h"  #ifdef __cplusplus  extern "C" { @@ -32,6 +33,7 @@ struct opna_drum {      unsigned level;      bool left;      bool right; +    struct leveldata leveldata;    } drums[6];    unsigned total_level;    int16_t rom_bd[OPNA_ROM_BD_SIZE]; diff --git a/libopna/opnafm.c b/libopna/opnafm.c index 4e86b80..0d57a98 100644 --- a/libopna/opnafm.c +++ b/libopna/opnafm.c @@ -3,6 +3,7 @@  #include "opnatables.h" +  //#include <stdio.h>  #define printf(...) @@ -27,6 +28,7 @@ static void opna_fm_slot_reset(struct opna_fm_slot *slot) {  void opna_fm_chan_reset(struct opna_fm_channel *chan) { +  leveldata_init(&chan->leveldata);    for (int i = 0; i < 4; i++) {      opna_fm_slot_reset(&chan->slot[i]);    } @@ -595,8 +597,6 @@ static int gcd(int a, int b) {    return b;  } - -  void opna_fm_mix(struct opna_fm *fm, int16_t *buf, unsigned samples,                   struct oscillodata *oscillo, unsigned offset) {    if (oscillo) { @@ -620,6 +620,7 @@ void opna_fm_mix(struct opna_fm *fm, int16_t *buf, unsigned samples,        }      }    } +  unsigned level[6] = {0};    for (unsigned i = 0; i < samples; i++) {      if (!fm->env_div3) {        for (int c = 0; c < 6; c++) { @@ -639,6 +640,11 @@ void opna_fm_mix(struct opna_fm *fm, int16_t *buf, unsigned samples,      for (int c = 0; c < 6; c++) {        struct opna_fm_frame o = opna_fm_chanout(&fm->channel[c]); +      unsigned nlevel[2]; +      nlevel[0] = o.data[0] > 0 ? o.data[0] : -o.data[0]; +      nlevel[1] = o.data[1] > 0 ? o.data[1] : -o.data[1]; +      if (nlevel[1] > nlevel[0]) nlevel[0] = nlevel[1]; +      if (nlevel[0] > level[c]) level[c] = nlevel[0];        if (oscillo) oscillo[c].buf[offset+i] = o.data[0] + o.data[1];        // TODO: CSM        if (c == 2 && fm->ch3.mode != CH3_MODE_NORMAL) { @@ -677,4 +683,7 @@ void opna_fm_mix(struct opna_fm *fm, int16_t *buf, unsigned samples,      }      fm->env_div3--;    } +  for (int c = 0; c < 6; c++) { +    leveldata_update(&fm->channel[c].leveldata, level[c]); +  }  } diff --git a/libopna/opnafm.h b/libopna/opnafm.h index 9da143f..359517b 100644 --- a/libopna/opnafm.h +++ b/libopna/opnafm.h @@ -3,6 +3,7 @@  #include <stdint.h>  #include <stdbool.h> +#include "leveldata/leveldata.h"  #ifdef __cplusplus  extern "C" { @@ -64,6 +65,8 @@ struct opna_fm_channel {    uint8_t fb;    uint16_t fnum;    uint8_t blk; +   +  struct leveldata leveldata;  };  struct opna_fm { diff --git a/libopna/opnassg.c b/libopna/opnassg.c index 86d9c9a..d92a8b8 100644 --- a/libopna/opnassg.c +++ b/libopna/opnassg.c @@ -134,6 +134,9 @@ void opna_ssg_resampler_reset(struct opna_ssg_resampler *resampler) {      resampler->buf[i] = 0;    }    resampler->index = 0; +  for (int c = 0; c < 3; c++) { +    leveldata_init(&resampler->leveldata[c]); +  }  }  void opna_ssg_writereg(struct opna_ssg *ssg, unsigned reg, unsigned val) { @@ -286,6 +289,7 @@ void opna_ssg_mix_55466(        }      }    } +  unsigned level[3] = {0};    for (int i = 0; i < samples; i++) {      {        int ssg_samples = ((resampler->index + 9)>>1) - ((resampler->index)>>1); @@ -305,6 +309,12 @@ void opna_ssg_mix_55466(      opna_ssg_sinc_calc_func(resampler->index, resampler->buf, outbuf);      for (int ch = 0; ch < 3; ch++) {        if (oscillo) oscillo[ch].buf[offset+i] = outbuf[ch] >> 15; +      int32_t nlevel = outbuf[ch]; +      nlevel >>= 16; +      nlevel *= 13000; +      nlevel >>= 14; +      if (nlevel < 0) nlevel = -nlevel; +      if (((unsigned)nlevel) > level[ch]) level[ch] = nlevel;        if (!(ssg->mask & (1<<ch))) sample += outbuf[ch] >> 2;      }      sample >>= 16; @@ -322,5 +332,8 @@ void opna_ssg_mix_55466(      buf[i*2+0] = lo;      buf[i*2+1] = ro;    } +  for (int c = 0; c < 3; c++) { +    leveldata_update(&resampler->leveldata[c], level[c]); +  }  }  #undef BUFINDEX diff --git a/libopna/opnassg.h b/libopna/opnassg.h index 8af8429..3077d08 100644 --- a/libopna/opnassg.h +++ b/libopna/opnassg.h @@ -3,6 +3,7 @@  #include <stdint.h>  #include <stdbool.h> +#include "leveldata/leveldata.h"  #ifdef __cplusplus  extern "C" { @@ -35,6 +36,7 @@ struct opna_ssg {  struct opna_ssg_resampler {    int16_t buf[OPNA_SSG_SINCTABLELEN*4 * 2];    unsigned index; +  struct leveldata leveldata[3];  };  void opna_ssg_reset(struct opna_ssg *ssg); | 
