diff options
| -rw-r--r-- | fmdriver/fmdriver.h | 35 | ||||
| -rw-r--r-- | fmdriver/fmdriver_fmp.c | 99 | ||||
| -rw-r--r-- | fmdriver/fmdriver_fmp.h | 30 | ||||
| -rw-r--r-- | fmdriver/ppz8.c | 2 | ||||
| -rw-r--r-- | fmdsp/fmdsp.c | 334 | ||||
| -rw-r--r-- | fmdsp/fmdsp.h | 16 | ||||
| -rw-r--r-- | gtk/main.c | 111 | ||||
| -rw-r--r-- | libopna/opna.c | 13 | ||||
| -rw-r--r-- | libopna/opna.h | 24 | ||||
| -rw-r--r-- | libopna/opnaadpcm.c | 22 | ||||
| -rw-r--r-- | libopna/opnaadpcm.h | 1 | ||||
| -rw-r--r-- | libopna/opnadrum.c | 7 | ||||
| -rw-r--r-- | libopna/opnadrum.h | 1 | ||||
| -rw-r--r-- | libopna/opnafm.c | 2 | ||||
| -rw-r--r-- | libopna/opnafm.h | 4 | ||||
| -rw-r--r-- | libopna/opnassg.c | 2 | ||||
| -rw-r--r-- | libopna/opnassg.h | 1 | ||||
| -rw-r--r-- | win32/main.c | 2 | 
18 files changed, 553 insertions, 153 deletions
| diff --git a/fmdriver/fmdriver.h b/fmdriver/fmdriver.h index e858567..a35f9b8 100644 --- a/fmdriver/fmdriver.h +++ b/fmdriver/fmdriver.h @@ -6,29 +6,46 @@  #include "ppz8.h"  enum { -  FMDRIVER_TRACK_NUM = 10, +  FMDRIVER_TRACK_FM_1, +  FMDRIVER_TRACK_FM_2, +  FMDRIVER_TRACK_FM_3, +  FMDRIVER_TRACK_FM_3_EX_1, +  FMDRIVER_TRACK_FM_3_EX_2, +  FMDRIVER_TRACK_FM_3_EX_3, +  FMDRIVER_TRACK_FM_4, +  FMDRIVER_TRACK_FM_5, +  FMDRIVER_TRACK_FM_6, +  FMDRIVER_TRACK_SSG_1, +  FMDRIVER_TRACK_SSG_2, +  FMDRIVER_TRACK_SSG_3, +  FMDRIVER_TRACK_ADPCM, +  FMDRIVER_TRACK_NUM +}; +enum {    // 1 line = 80 characters, may contain half-width doublebyte characters    FMDRIVER_TITLE_BUFLEN = 80*2+1,  };  enum fmdriver_track_type { -  FMDRIVER_TRACK_FM, -  FMDRIVER_TRACK_SSG, -  FMDRIVER_TRACK_ADPCM, +  FMDRIVER_TRACKTYPE_FM, +  FMDRIVER_TRACKTYPE_SSG, +  FMDRIVER_TRACKTYPE_ADPCM, +  FMDRIVER_TRACKTYPE_CNT,  };  enum fmdriver_track_info {    FMDRIVER_TRACK_INFO_NORMAL,    FMDRIVER_TRACK_INFO_SSG_NOISE_ONLY,    FMDRIVER_TRACK_INFO_SSG_NOISE_MIX, -  FMDRIVER_TRACK_INFO_PPZ8 +  FMDRIVER_TRACK_INFO_FM3EX, +  FMDRIVER_TRACK_INFO_PPZ8, +  FMDRIVER_TRACK_INFO_PDZF,  };  struct fmdriver_track_status {    bool playing; -  enum fmdriver_track_type type; +  bool masked;    enum fmdriver_track_info info; -  uint8_t num;    uint8_t ticks;    uint8_t ticks_left;    uint8_t key; @@ -39,6 +56,10 @@ struct fmdriver_track_status {    uint8_t gate;    int8_t detune;    char status[9]; +  bool fmslotmask[4]; +  // for FMP, ppz8 channel+1 or 0 +  // use for track mask or display +  uint8_t ppz8_ch;  };  struct fmdriver_work { diff --git a/fmdriver/fmdriver_fmp.c b/fmdriver/fmdriver_fmp.c index 8f3c948..efdcbb9 100644 --- a/fmdriver/fmdriver_fmp.c +++ b/fmdriver/fmdriver_fmp.c @@ -1594,7 +1594,7 @@ static void fmp_part_lfo_calc(struct driver_fmp *fmp,  static void fmp_part_keyon_fm(struct fmdriver_work *work,
                                struct driver_fmp *fmp,
                                struct fmp_part *part) {
 -  if (part->lfo_f.portamento) return;
 +  if (part->lfo_f.mask) return;
    // 27df
    uint8_t out = part->opna_keyon_out;
    if (part->type.fm_3) {
 @@ -1734,7 +1734,7 @@ static void fmp_part_keyon(struct fmdriver_work *work,        part->lfo_f.lfo = false;
      }
      // 281e
 -    if (part->lfo_f.portamento) {
 +    if (part->lfo_f.mask) {
        part->u.ssg.env_f.attack = false;
        part->u.ssg.env_f.portamento = true;
        return;
 @@ -2163,7 +2163,7 @@ static void fmp_part_ssg_env_reset(struct fmp_part *part) {  static void fmp_adpcm_addr_set(struct fmdriver_work *work,
                                 struct driver_fmp *fmp,
                                 struct fmp_part *part) {
 -  if (part->lfo_f.portamento) return;
 +  if (part->lfo_f.mask) return;
    work->opna_writereg(work, 0x100, 0x00);
    work->opna_writereg(work, 0x100, 0x01);
    //work->opna_writereg(work, 0x110, 0x08);
 @@ -2212,7 +2212,7 @@ static void fmp_part_keyon_pre(struct driver_fmp *fmp, struct fmp_part *part) {    part->status.keyon = true;
    if (part->type.ssg && !part->status.tie_cont && !part->u.ssg.env_f.ppz) {
      part->u.ssg.env_f.portamento = false;
 -    if (!part->lfo_f.portamento) {
 +    if (!part->lfo_f.mask) {
        fmp_part_ssg_env_reset(part);
      }
    }
 @@ -2727,68 +2727,52 @@ static uint8_t fmp_note2key(uint8_t note) {    return key;
  }
 +static const uint8_t fmp_track_map[FMDRIVER_TRACK_NUM] = {
 +  FMP_PART_FM_1,
 +  FMP_PART_FM_2,
 +  FMP_PART_FM_3,
 +  FMP_PART_FM_EX1,
 +  FMP_PART_FM_EX2,
 +  FMP_PART_FM_EX3,
 +  FMP_PART_FM_4,
 +  FMP_PART_FM_5,
 +  FMP_PART_FM_6,
 +  FMP_PART_SSG_1,
 +  FMP_PART_SSG_2,
 +  FMP_PART_SSG_3,
 +  FMP_PART_ADPCM,
 +};
 +
  static void fmp_work_status_init(struct fmdriver_work *work,
                                   const struct driver_fmp *fmp) {
 -
 -  static const uint8_t fmp_track_map[FMDRIVER_TRACK_NUM] = {
 -    FMP_PART_FM_1,
 -    FMP_PART_FM_2,
 -    FMP_PART_FM_3,
 -    FMP_PART_FM_4,
 -    FMP_PART_FM_5,
 -    FMP_PART_FM_6,
 -    FMP_PART_SSG_1,
 -    FMP_PART_SSG_2,
 -    FMP_PART_SSG_3,
 -    FMP_PART_ADPCM,
 -  };
 -
    for (int t = 0; t < FMDRIVER_TRACK_NUM; 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->num = (part->pdzf.mode ? part->pdzf.ppz8_channel : part->opna_keyon_out)+1;
      track->info = FMDRIVER_TRACK_INFO_NORMAL;
 -    if (part->type.adpcm) {
 -      track->type = FMDRIVER_TRACK_ADPCM;
 -    } else if (part->type.ssg) {
 -      track->type = FMDRIVER_TRACK_SSG;
 -    } else {
 -      track->type = FMDRIVER_TRACK_FM;
 -    }
 -    if (part->type.fm && part->opna_keyon_out > 3) {
 -      track->num--;
 -    }
 +  }
 +  for (int i = 0; i < 3; i++) {
 +    work->track_status[FMDRIVER_TRACK_SSG_1+i].ppz8_ch = 1+i;
 +    work->track_status[FMDRIVER_TRACK_FM_3_EX_1+i].ppz8_ch = 4+i;
    }
  }
  static void fmp_work_status_update(struct fmdriver_work *work,
                                     const struct driver_fmp *fmp) {
    work->ssg_noise_freq = fmp->ssg_noise_freq;
 -  static const uint8_t fmp_track_map[FMDRIVER_TRACK_NUM] = {
 -    FMP_PART_FM_1,
 -    FMP_PART_FM_2,
 -    FMP_PART_FM_3,
 -    FMP_PART_FM_4,
 -    FMP_PART_FM_5,
 -    FMP_PART_FM_6,
 -    FMP_PART_SSG_1,
 -    FMP_PART_SSG_2,
 -    FMP_PART_SSG_3,
 -    FMP_PART_ADPCM,
 -  };
 -
    for (int t = 0; t < FMDRIVER_TRACK_NUM; 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->num = (part->pdzf.mode ? part->pdzf.ppz8_channel : part->opna_keyon_out)+1;
      track->info = FMDRIVER_TRACK_INFO_NORMAL;
      if (part->type.adpcm) {
        track->actual_key = 0xff;
        track->volume = part->actual_vol;
      } else if (part->type.ssg) {
 -      if (part->u.ssg.env_f.ppz || part->pdzf.mode) {
 +      if (part->pdzf.mode) {
 +        track->info = FMDRIVER_TRACK_INFO_PDZF;
 +        track->actual_key = 0xff;
 +      } else if (part->u.ssg.env_f.ppz) {
          track->info = FMDRIVER_TRACK_INFO_PPZ8;
          track->actual_key = 0xff;
        } else {
 @@ -2803,16 +2787,19 @@ static void fmp_work_status_update(struct fmdriver_work *work,        track->volume = part->current_vol - 1;
      } else {
        if (part->pdzf.mode) {
 -        track->info = FMDRIVER_TRACK_INFO_PPZ8;
 +        track->info = FMDRIVER_TRACK_INFO_PDZF;
          track->actual_key = 0xff;
        } else {
 +        if (part->u.fm.slot_mask & 0xf0) {
 +          track->info = FMDRIVER_TRACK_INFO_FM3EX;
 +          for (int s = 0; s < 4; s++) {
 +            track->fmslotmask[s] = part->u.fm.slot_mask & (1<<(4+s));
 +          }
 +        }
          track->actual_key = part->status.rest ? 0xff : fmp_fm_freq2key(part->prev_freq);
        }
        track->volume = 0x7f - part->actual_vol;
      }
 -    if (part->type.fm && part->opna_keyon_out > 3) {
 -      track->num--;
 -    }
      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);
 @@ -3456,6 +3443,22 @@ bool fmp_load(struct driver_fmp *fmp,    return true;
  }
 +static const uint8_t fmp_fmdriver_track_map[FMDRIVER_TRACK_NUM] = {
 +  FMP_PART_FM_1,
 +  FMP_PART_FM_2,
 +  FMP_PART_FM_3,
 +  FMP_PART_FM_EX1,
 +  FMP_PART_FM_EX2,
 +  FMP_PART_FM_EX3,
 +  FMP_PART_FM_4,
 +  FMP_PART_FM_5,
 +  FMP_PART_FM_6,
 +  FMP_PART_SSG_1,
 +  FMP_PART_SSG_2,
 +  FMP_PART_SSG_3,
 +  FMP_PART_ADPCM
 +};
 +
  void fmp_init(struct fmdriver_work *work, struct driver_fmp *fmp) {
    fmp_title(work, fmp, read16le(fmp->data)+4);
    fmp_struct_init(work, fmp);
 diff --git a/fmdriver/fmdriver_fmp.h b/fmdriver/fmdriver_fmp.h index d70013c..5211a80 100644 --- a/fmdriver/fmdriver_fmp.h +++ b/fmdriver/fmdriver_fmp.h @@ -116,7 +116,7 @@ struct fmp_part {    // 0000    struct {      // 0x01 -    bool portamento: 1; +    bool mask: 1;      // 0x02      bool lfo: 1; // ?      // 0x04 @@ -226,20 +226,20 @@ struct fmp_part {      // SSG backup??    } type;    // 0b00xx x0xx xxxx xxxx -  // || | || |||| |||| -  // || | || |||| |||`- FM#1 -  // || | || |||| ||`-- FM#2 -  // || | || |||| |`--- FM#3 -  // || | || |||| `---- FM#4 -  // || | || |||`------ FM#5 -  // || | || ||`------- FM#6 -  // || | || |`-------- SSG#1 -  // || | || `--------- SSG#2 -  // || | |`----------- SSG#3 -  // || | `------------ rhythm -  // || `-------------- FMEX#1 -  // |`---------------- FMEX#2 -  // `----------------- FMEX#3 +  //     || | || |||| |||| +  //     || | || |||| |||`- FM#1 +  //     || | || |||| ||`-- FM#2 +  //     || | || |||| |`--- FM#3 +  //     || | || |||| `---- FM#4 +  //     || | || |||`------ FM#5 +  //     || | || ||`------- FM#6 +  //     || | || |`-------- SSG#1 +  //     || | || `--------- SSG#2 +  //     || | |`----------- SSG#3 +  //     || | `------------ rhythm +  //     || `-------------- FMEX#1 +  //     |`---------------- FMEX#2 +  //     `----------------- FMEX#3    // 004c    uint16_t part_bit;    // 004e diff --git a/fmdriver/ppz8.c b/fmdriver/ppz8.c index 39caf0d..8838367 100644 --- a/fmdriver/ppz8.c +++ b/fmdriver/ppz8.c @@ -1,5 +1,6 @@  #include "ppz8.h"  #include "fmdriver_common.h" +#include <stdio.h>  void ppz8_init(struct ppz8 *ppz8, uint16_t srate, uint16_t mix_volume) {    for (int i = 0; i < 2; i++) { @@ -269,6 +270,7 @@ static void ppz8_channel_loopoffset(struct ppz8 *ppz8, uint8_t ch,    struct ppz8_channel *channel = &ppz8->channel[ch];    channel->loopstartoff = startoff;    channel->loopendoff = endoff; +  fprintf(stderr, "channel: %d, start: %08x, end: %08x\n", ch, startoff, endoff);  }  static void ppz8_channel_pan(struct ppz8 *ppz8, uint8_t ch, uint8_t pan) { diff --git a/fmdsp/fmdsp.c b/fmdsp/fmdsp.c index 35ea7fd..43be966 100644 --- a/fmdsp/fmdsp.c +++ b/fmdsp/fmdsp.c @@ -3,6 +3,7 @@  #include "font.h"  #include "fmdriver/fmdriver.h"  #include <stdio.h> +#include "libopna/opna.h"  static void vramblit(uint8_t *vram, int x, int y,                       const uint8_t *data, int w, int h) { @@ -52,6 +53,8 @@ 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_updated = true;  } @@ -123,48 +126,112 @@ static void fmdsp_putline(const char *strptr, uint8_t *vram,    }  } -void fmdsp_vram_init(struct fmdsp *fmdsp, -                     struct fmdriver_work *work, -                     uint8_t *vram) { -  for (int y = 0; y < PC98_H; y++) { +static const char *track_type_string_table[FMDRIVER_TRACKTYPE_CNT] = { +  "FM   ", "SSG  ", "ADPCM" +}; + +static struct { +  uint8_t type; +  uint8_t num; +} track_type_table[FMDRIVER_TRACK_NUM] = { +  {FMDRIVER_TRACKTYPE_FM, 1}, +  {FMDRIVER_TRACKTYPE_FM, 2}, +  {FMDRIVER_TRACKTYPE_FM, 3}, +  {FMDRIVER_TRACKTYPE_FM, 3}, +  {FMDRIVER_TRACKTYPE_FM, 3}, +  {FMDRIVER_TRACKTYPE_FM, 3}, +  {FMDRIVER_TRACKTYPE_FM, 4}, +  {FMDRIVER_TRACKTYPE_FM, 5}, +  {FMDRIVER_TRACKTYPE_FM, 6}, +  {FMDRIVER_TRACKTYPE_SSG, 1}, +  {FMDRIVER_TRACKTYPE_SSG, 2}, +  {FMDRIVER_TRACKTYPE_SSG, 3}, +  {FMDRIVER_TRACKTYPE_ADPCM, 1}, +}; + +enum { +  FMDSP_TRACK_DISP_CNT_DEFAULT = 10 +}; + +static uint8_t track_disp_table_default[FMDSP_TRACK_DISP_CNT_DEFAULT] = { +  FMDRIVER_TRACK_FM_1, +  FMDRIVER_TRACK_FM_2, +  FMDRIVER_TRACK_FM_3, +  FMDRIVER_TRACK_FM_4, +  FMDRIVER_TRACK_FM_5, +  FMDRIVER_TRACK_FM_6, +  FMDRIVER_TRACK_SSG_1, +  FMDRIVER_TRACK_SSG_2, +  FMDRIVER_TRACK_SSG_3, +  FMDRIVER_TRACK_ADPCM, +}; +static uint8_t track_disp_table_opn[FMDSP_TRACK_DISP_CNT_DEFAULT] = { +  FMDRIVER_TRACK_FM_1, +  FMDRIVER_TRACK_FM_2, +  FMDRIVER_TRACK_FM_3, +  FMDRIVER_TRACK_FM_3_EX_1, +  FMDRIVER_TRACK_FM_3_EX_2, +  FMDRIVER_TRACK_FM_3_EX_3, +  FMDRIVER_TRACK_SSG_1, +  FMDRIVER_TRACK_SSG_2, +  FMDRIVER_TRACK_SSG_3, +  FMDRIVER_TRACK_ADPCM, +}; + +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++) {      for (int x = 0; x < PC98_W; x++) {        vram[y*PC98_W+x] = 0;      }    } -  for (int t = 0; t < 10; t++) { -    struct fmdriver_track_status *track = &work->track_status[t]; +  for (int i = 0; i < FMDSP_TRACK_DISP_CNT_DEFAULT; i++) { +    int t = (fmdsp->style == FMDSP_DISPSTYLE_DEFAULT) ? +            track_disp_table_default[i] : +            track_disp_table_opn[i];      const char *track_type; -    switch (track->type) { -    case FMDRIVER_TRACK_FM: +    switch (track_type_table[t].type) { +    case FMDRIVER_TRACKTYPE_FM:        track_type = "FM   ";        break; -    case FMDRIVER_TRACK_SSG: +    case FMDRIVER_TRACKTYPE_SSG:        track_type = "SSG  ";        break; -    case FMDRIVER_TRACK_ADPCM: +    case FMDRIVER_TRACKTYPE_ADPCM:        track_type = "ADPCM";        break;      } -    fmdsp_putline(track_type, vram, &font_fmdsp_small, 1, TRACK_H*t, 2, true); -    vramblit(vram, NUM_X+NUM_W*0, TRACK_H*t+1, s_num[(track->num/10)%10], NUM_W, NUM_H); -    vramblit(vram, NUM_X+NUM_W*1, TRACK_H*t+1, s_num[track->num%10], NUM_W, NUM_H); +    fmdsp_putline(track_type, vram, &font_fmdsp_small, 1, TRACK_H*i, 2, true); +    int tracknum = track_type_table[t].num; +    vramblit(vram, NUM_X+NUM_W*0, TRACK_H*i+1, s_num[(tracknum/10)%10], NUM_W, NUM_H); +    vramblit(vram, NUM_X+NUM_W*1, TRACK_H*i+1, s_num[tracknum%10], NUM_W, NUM_H); -    //vramblit(vram, 1, TRACK_H*t+7, s_track, TNAME_W, TNAME_H); -    fmdsp_putline("TRACK.", vram, &font_fmdsp_small, 1, TRACK_H*t+6, 1, true); -    vramblit(vram, KEY_LEFT_X, TRACK_H*t+KEY_Y, s_key_left, KEY_LEFT_W, KEY_H); -    for (int i = 0; i < KEY_OCTAVES; i++) { -      vramblit(vram, KEY_X+KEY_W*i, TRACK_H*t+KEY_Y, +    fmdsp_putline("TRACK.", vram, &font_fmdsp_small, 1, TRACK_H*i+6, 1, true); +    vramblit(vram, KEY_LEFT_X, TRACK_H*i+KEY_Y, s_key_left, KEY_LEFT_W, KEY_H); +    for (int j = 0; j < KEY_OCTAVES; j++) { +      vramblit(vram, KEY_X+KEY_W*j, TRACK_H*i+KEY_Y,                  s_key_bg, KEY_W, KEY_H);      } -    vramblit(vram, KEY_X+KEY_W*KEY_OCTAVES, TRACK_H*t+KEY_Y, +    vramblit(vram, KEY_X+KEY_W*KEY_OCTAVES, TRACK_H*i+KEY_Y,               s_key_right, KEY_RIGHT_W, KEY_H); -    vramblit_color(vram, BAR_L_X, TRACK_H*t+BAR_Y, +    vramblit_color(vram, BAR_L_X, TRACK_H*i+BAR_Y,                     s_bar_l, BAR_L_W, BAR_H, 3); -    for (int i = 0; i < BAR_CNT; i++) { -      vramblit_color(vram, BAR_X+BAR_W*i, TRACK_H*t+BAR_Y, +    for (int j = 0; j < BAR_CNT; j++) { +      vramblit_color(vram, BAR_X+BAR_W*j, TRACK_H*i+BAR_Y,                  s_bar, BAR_W, BAR_H, 3);      }    } +} + +void fmdsp_vram_init(struct fmdsp *fmdsp, +                     struct fmdriver_work *work, +                     uint8_t *vram) { +  fmdsp->style_updated = true; +  for (int y = 0; y < PC98_H; y++) { +    for (int x = 0; x < PC98_W; x++) { +      vram[y*PC98_W+x] = 0; +    } +  }    vramblit(vram, PLAYING_X, PLAYING_Y,             s_playing, PLAYING_W, PLAYING_H);    for (int x = 74; x < PC98_W; x++) { @@ -219,25 +286,187 @@ static void fmdsp_palette_fade(struct fmdsp *fmdsp) {    }  } +static void fmdsp_track_info_fm(const struct opna *opna, +                                int chi, const bool *slotmask, +                                int x, int y, +                                uint8_t *vram +) { +  const struct opna_fm_channel *ch = &opna->fm.channel[chi]; +  for (int si = 0; si < 4; si++) { +    if (slotmask && slotmask[si]) continue; +    const struct opna_fm_slot *s = &ch->slot[si]; +    int level = s->tl << 5;                // (0 - 4064) +    int envlevel = level + (s->env<<2); +    int leveld = (4096 - level) / 64;      // (0 - 63) +    if (leveld < 0) leveld = 0; +    int envleveld = (4096 - envlevel) / 64; +    if (envleveld < 0) envleveld = 0; +    for (int px = 0; px < 64; px++) { +      int color = 3; +      if (px < envleveld) color = 2; +      if (px == leveld) color = 7; +      for (int py = 0; py < 4; py++) { +        vram[(y+2+py+si*6)*PC98_W+(x+px*2)] = color; +      } +    } +    const char *envstr = ""; +    switch (s->env_state) { +    case ENV_ATTACK: +      envstr = "ATT"; +      break; +    case ENV_DECAY: +      envstr = "DEC"; +      break; +    case ENV_SUSTAIN: +      envstr = "SUS"; +      break; +    case ENV_RELEASE: +      envstr = "REL"; +      break; +    } +    fmdsp_putline(envstr, vram, &font_fmdsp_small, x+130, y+si*6, 1, false); +    char strbuf[4]; +    snprintf(strbuf, sizeof(strbuf), "%03X", s->env); +    fmdsp_putline(strbuf, vram, &font_fmdsp_small, x+150, y+si*6, 1, false); +  } +  char strbuf[5]; +  snprintf(strbuf, sizeof(strbuf), "%04X", ch->fnum); +  fmdsp_putline(strbuf, vram, &font_fmdsp_small, x+170, y, 1, false); +} + +static void fmdsp_track_info_ssg(const struct opna *opna, +                                 int chi, +                                 int x, int y, +                                 uint8_t *vram +) { +  int envleveld = opna_ssg_channel_level(&opna->ssg, chi); +  for (int px = 0; px < 64; px++) { +    int color = 3; +    if (px < (envleveld+31)) color = 2; +    if (px < 32) color = 7; +    for (int py = 0; py < 4; py++) { +      vram[(y+2+py)*PC98_W+(x+px*2)] = color; +    } +  } +} + +static void fmdsp_track_info_adpcm(const struct opna *opna, +                                   int x, int y, +                                   uint8_t *vram) { +  fmdsp_putline("VOL DELTA  START    PTR    END", +                vram, &font_fmdsp_small, x, y, 1, false); +  char buf[7]; +  snprintf(buf, sizeof(buf), "%3d", opna->adpcm.vol); +  fmdsp_putline(buf, vram, &font_fmdsp_small, x, y+6, 1, false); +  snprintf(buf, sizeof(buf), "%04X", opna->adpcm.delta); +  fmdsp_putline(buf, vram, &font_fmdsp_small, x+25, y+6, 1, false); +  snprintf(buf, sizeof(buf), "%06X", (opna->adpcm.start)<<5); +  fmdsp_putline(buf, vram, &font_fmdsp_small, x+50, y+6, 1, false); +  snprintf(buf, sizeof(buf), "%06X", (opna->adpcm.ramptr)<<5); +  fmdsp_putline(buf, vram, &font_fmdsp_small, x+85, y+6, 1, false); +  snprintf(buf, sizeof(buf), "%06X", ((opna->adpcm.end+1)<<5)-1); +  fmdsp_putline(buf, vram, &font_fmdsp_small, x+120, y+6, 1, false); +} + +static void fmdsp_track_info_ppz8(const struct ppz8 *ppz8, +                                  int chi, +                                  int x, int y, +                                  uint8_t *vram) { +  const struct ppz8_channel *ch = &ppz8->channel[chi]; +  fmdsp_putline("PAN VOL     FREQ      PTR      END    LOOPS    LOOPE", +                vram, &font_fmdsp_small, x, y, 1, false); +  char buf[9]; +  if (ch->pan) { +    int pan = ch->pan-5; +    snprintf(buf, sizeof(buf), "%+d", pan); +    char c = ' '; +    if (pan < 0) c = 'L'; +    if (pan > 0) c = 'R'; +    buf[0] = c; +  } else { +    snprintf(buf, sizeof(buf), "--"); +  } +  fmdsp_putline(buf, vram, &font_fmdsp_small, x+5, y+6, 1, false); +  snprintf(buf, sizeof(buf), "%03d", ch->vol); +  fmdsp_putline(buf, vram, &font_fmdsp_small, x+20, y+6, 1, false); +  snprintf(buf, sizeof(buf), "%08X", ch->freq); +  fmdsp_putline(buf, vram, &font_fmdsp_small, x+40, y+6, 1, false); +  snprintf(buf, sizeof(buf), "%08X", (unsigned)(ch->ptr>>16)); +  fmdsp_putline(buf, vram, &font_fmdsp_small, x+85, y+6, 1, false); +  snprintf(buf, sizeof(buf), "%08X", (unsigned)(ch->endptr>>16)); +  fmdsp_putline(buf, vram, &font_fmdsp_small, x+130, y+6, 1, false); +  snprintf(buf, sizeof(buf), "%08X", (unsigned)(ch->loopstartptr>>16)); +  fmdsp_putline(buf, vram, &font_fmdsp_small, x+175, y+6, 1, false); +  snprintf(buf, sizeof(buf), "%08X", (unsigned)(ch->loopendptr>>16)); +  fmdsp_putline(buf, vram, &font_fmdsp_small, x+220, y+6, 1, false); +} +  void fmdsp_update(struct fmdsp *fmdsp, -                  const struct fmdriver_work *work, uint8_t *vram) { -  for (int t = 0; t < 10; t++) { +                  const struct fmdriver_work *work, +                  const struct opna *opna, +                  uint8_t *vram) { +  if (fmdsp->style_updated) fmdsp_track_init_10(fmdsp, vram); +  fmdsp->style_updated = false; +  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 = (fmdsp->style == FMDSP_DISPSTYLE_DEFAULT) ? +            track_disp_table_default[it] : +            track_disp_table_opn[it];      const struct fmdriver_track_status *track = &work->track_status[t]; -    char track_info[5] = "    "; + +    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); +      } +    } + +    const char *track_info1 = "    "; +    char track_info2[5] = "    ";      if (track->playing) {        switch (track->info) {        case FMDRIVER_TRACK_INFO_PPZ8: -        snprintf(track_info, sizeof(track_info), "PPZ8"); +        snprintf(track_info2, sizeof(track_info2), "PPZ8"); +        break; +      case FMDRIVER_TRACK_INFO_PDZF: +        snprintf(track_info2, sizeof(track_info2), "PDZF");          break;        case FMDRIVER_TRACK_INFO_SSG_NOISE_ONLY: -        snprintf(track_info, sizeof(track_info), "N%02X ", work->ssg_noise_freq); +        snprintf(track_info2, sizeof(track_info2), "N%02X ", work->ssg_noise_freq);          break;        case FMDRIVER_TRACK_INFO_SSG_NOISE_MIX: -        snprintf(track_info, sizeof(track_info), "M%02X ", work->ssg_noise_freq); +        snprintf(track_info2, sizeof(track_info2), "M%02X ", work->ssg_noise_freq); +        break; +      case FMDRIVER_TRACK_INFO_FM3EX: +        track_info1 = "EX  "; +        for (int c = 0; c < 4; c++) { +          track_info2[c] = track->fmslotmask[c] ? ' ' : ('1'+c); +        }          break;        }      } -    fmdsp_putline(track_info, vram, &font_fmdsp_small, TINFO_X, TRACK_H*t+6, 2, true); +    fmdsp_putline(track_info1, vram, &font_fmdsp_small, TINFO_X, TRACK_H*it+0, 2, true); +    fmdsp_putline(track_info2, vram, &font_fmdsp_small, TINFO_X, TRACK_H*it+6, 2, true);      char notestr[5] = " S  ";      if (track->playing) {        if ((track->key&0xf) == 0xf) { @@ -252,52 +481,52 @@ void fmdsp_update(struct fmdsp *fmdsp,        }      }      char numbuf[5]; -    fmdsp_putline("KN:", vram, &font_fmdsp_small, TDETAIL_X, TRACK_H*t+6, 1, true); -    fmdsp_putline(notestr, vram, &font_fmdsp_small, TDETAIL_KN_V_X, TRACK_H*t+6, 1, true); -    fmdsp_putline("TN:", vram, &font_fmdsp_small, TDETAIL_TN_X, TRACK_H*t+6, 1, true); +    fmdsp_putline("KN:", vram, &font_fmdsp_small, TDETAIL_X, TRACK_H*it+6, 1, true); +    fmdsp_putline(notestr, vram, &font_fmdsp_small, TDETAIL_KN_V_X, TRACK_H*it+6, 1, true); +    fmdsp_putline("TN:", vram, &font_fmdsp_small, TDETAIL_TN_X, TRACK_H*it+6, 1, true);      snprintf(numbuf, sizeof(numbuf), "%03d", track->tonenum); -    fmdsp_putline(numbuf, vram, &font_fmdsp_small, TDETAIL_TN_V_X, TRACK_H*t+6, 1, true); -    fmdsp_putline("VL:", vram, &font_fmdsp_small, TDETAIL_VL_X, TRACK_H*t+6, 1, true); +    fmdsp_putline(numbuf, vram, &font_fmdsp_small, TDETAIL_TN_V_X, TRACK_H*it+6, 1, true); +    fmdsp_putline("VL:", vram, &font_fmdsp_small, TDETAIL_VL_X, TRACK_H*it+6, 1, true);      snprintf(numbuf, sizeof(numbuf), "%03d", track->volume); -    fmdsp_putline(numbuf, vram, &font_fmdsp_small, TDETAIL_VL_V_X, TRACK_H*t+6, 1, true); -    fmdsp_putline("GT:", vram, &font_fmdsp_small, TDETAIL_GT_X, TRACK_H*t+6, 1, true); +    fmdsp_putline(numbuf, vram, &font_fmdsp_small, TDETAIL_VL_V_X, TRACK_H*it+6, 1, true); +    fmdsp_putline("GT:", vram, &font_fmdsp_small, TDETAIL_GT_X, TRACK_H*it+6, 1, true);      //snprintf(numbuf, sizeof(numbuf), "%03d", track->tonenum); -    //fmdsp_putline(numbuf, vram, &font_fmdsp_small, TDETAIL_GT_V_X, TRACK_H*t+6, 1, true); -    fmdsp_putline("DT:", vram, &font_fmdsp_small, TDETAIL_DT_X, TRACK_H*t+6, 1, true); +    //fmdsp_putline(numbuf, vram, &font_fmdsp_small, TDETAIL_GT_V_X, TRACK_H*it+6, 1, true); +    fmdsp_putline("DT:", vram, &font_fmdsp_small, TDETAIL_DT_X, TRACK_H*it+6, 1, true);      if (track->detune) {        snprintf(numbuf, sizeof(numbuf), "%+04d", track->detune);      } else {        snprintf(numbuf, sizeof(numbuf), " 000");      } -    fmdsp_putline(numbuf, vram, &font_fmdsp_small, TDETAIL_DT_V_X, TRACK_H*t+6, 1, true); -    fmdsp_putline("M:", vram, &font_fmdsp_small, TDETAIL_M_X, TRACK_H*t+6, 1, true); -    fmdsp_putline(track->status, vram, &font_fmdsp_small, TDETAIL_M_V_X, TRACK_H*t+6, 1, true); +    fmdsp_putline(numbuf, vram, &font_fmdsp_small, TDETAIL_DT_V_X, TRACK_H*it+6, 1, true); +    fmdsp_putline("M:", vram, &font_fmdsp_small, TDETAIL_M_X, TRACK_H*it+6, 1, true); +    fmdsp_putline(track->status, vram, &font_fmdsp_small, TDETAIL_M_V_X, TRACK_H*it+6, 1, true);      for (int i = 0; i < KEY_OCTAVES; i++) { -      vramblit(vram, KEY_X+KEY_W*i, TRACK_H*t+KEY_Y, +      vramblit(vram, KEY_X+KEY_W*i, TRACK_H*it+KEY_Y,                  s_key_bg, KEY_W, KEY_H);        if (track->playing) {          if (track->actual_key >> 4 == i) { -          vramblit_key(vram, KEY_X+KEY_W*i, TRACK_H*t+KEY_Y, +          vramblit_key(vram, KEY_X+KEY_W*i, TRACK_H*it+KEY_Y,                        s_key_mask, KEY_W, KEY_H,                        track->actual_key & 0xf, 8);          }          if (track->key >> 4 == i) { -          vramblit_key(vram, KEY_X+KEY_W*i, TRACK_H*t+KEY_Y, +          vramblit_key(vram, KEY_X+KEY_W*i, TRACK_H*it+KEY_Y,                        s_key_mask, KEY_W, KEY_H, -                      track->key & 0xf, 6); +                      track->key & 0xf, track->masked ? 8 : 6);          }        }      } -    uint8_t color_on = track->key == 0xff ? 7 : 2; +    uint8_t color_on = ((track->key == 0xff) || track->masked) ? 7 : 2;      if (!track->playing) color_on = 3; -    vramblit_color(vram, BAR_L_X, TRACK_H*t+BAR_Y, +    vramblit_color(vram, BAR_L_X, TRACK_H*it+BAR_Y,                     s_bar_l, BAR_L_W, BAR_H, color_on);      for (int i = 0; i < BAR_CNT; i++) {        int c = (i < (track->ticks_left>>2)) ? color_on : 3; -      vramblit_color(vram, BAR_X+BAR_W*i, TRACK_H*t+BAR_Y, +      vramblit_color(vram, BAR_X+BAR_W*i, TRACK_H*it+BAR_Y,                  s_bar, BAR_W, BAR_H, c);      } -    vramblit_color(vram, BAR_X+BAR_W*(track->ticks>>2), TRACK_H*t+BAR_Y, +    vramblit_color(vram, BAR_X+BAR_W*(track->ticks>>2), TRACK_H*it+BAR_Y,                     s_bar, BAR_W, BAR_H, 7);    }    fmdsp_palette_fade(fmdsp); @@ -331,3 +560,10 @@ static void fontrom_copy_rows(uint8_t *font, const uint8_t *fontrom,      }    }  } + +void fmdsp_dispstyle_set(struct fmdsp *fmdsp, enum FMDSP_DISPSTYLE style) { +  if (style < 0) return; +  if (style >= FMDSP_DISPSTYLE_CNT) return; +  fmdsp->style = style; +  fmdsp->style_updated = true; +} diff --git a/fmdsp/fmdsp.h b/fmdsp/fmdsp.h index f123138..9a67bc7 100644 --- a/fmdsp/fmdsp.h +++ b/fmdsp/fmdsp.h @@ -2,12 +2,15 @@  #define MYON_FMDSP_H_INCLUDED  #include <stdint.h> +#include <stdbool.h>  #include "font.h"  #ifdef __cplusplus  extern "C" {  #endif +struct opna; +  enum {    PC98_W = 640,    PC98_H = 400 @@ -17,11 +20,18 @@ enum {    FMDSP_PALETTE_COLORS = 9  }; +enum FMDSP_DISPSTYLE { +  FMDSP_DISPSTYLE_DEFAULT, +  FMDSP_DISPSTYLE_OPN, +  FMDSP_DISPSTYLE_CNT +}; +  struct fmdsp {    uint8_t palette[FMDSP_PALETTE_COLORS*3];    uint8_t target_palette[FMDSP_PALETTE_COLORS*3];    const struct fmdsp_font *font98; - +  enum FMDSP_DISPSTYLE style; +  bool style_updated;  };  struct fmdriver_work; @@ -29,10 +39,12 @@ 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, uint8_t *vram); +void fmdsp_update(struct fmdsp *fmdsp, const struct fmdriver_work *work, +                  const struct opna *opna, uint8_t *vram);  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); +void fmdsp_dispstyle_set(struct fmdsp *fmdsp, enum FMDSP_DISPSTYLE style);  #ifdef __cplusplus  }  #endif @@ -407,7 +407,7 @@ static GtkWidget *create_menubar() {  static gboolean draw_cb(GtkWidget *w,                   cairo_t *cr,                   gpointer p) { -  fmdsp_update(&g.fmdsp, &g.work, g.vram); +  fmdsp_update(&g.fmdsp, &g.work, &g.opna, g.vram);    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); @@ -433,6 +433,32 @@ static void destroynothing(gpointer p) {    (void)p;  } +static void mask_update(void) { +  unsigned mask = opna_get_mask(&g.opna); +  g.work.track_status[FMDRIVER_TRACK_FM_1].masked = mask & LIBOPNA_CHAN_FM_1; +  g.work.track_status[FMDRIVER_TRACK_FM_2].masked = mask & LIBOPNA_CHAN_FM_2; +  g.work.track_status[FMDRIVER_TRACK_FM_3].masked = mask & LIBOPNA_CHAN_FM_3; +  g.work.track_status[FMDRIVER_TRACK_FM_3_EX_1].masked = mask & LIBOPNA_CHAN_FM_3; +  g.work.track_status[FMDRIVER_TRACK_FM_3_EX_2].masked = mask & LIBOPNA_CHAN_FM_3; +  g.work.track_status[FMDRIVER_TRACK_FM_3_EX_3].masked = mask & LIBOPNA_CHAN_FM_3; +  g.work.track_status[FMDRIVER_TRACK_FM_4].masked = mask & LIBOPNA_CHAN_FM_4; +  g.work.track_status[FMDRIVER_TRACK_FM_5].masked = mask & LIBOPNA_CHAN_FM_5; +  g.work.track_status[FMDRIVER_TRACK_FM_6].masked = mask & LIBOPNA_CHAN_FM_6; +  g.work.track_status[FMDRIVER_TRACK_SSG_1].masked = mask & LIBOPNA_CHAN_SSG_1; +  g.work.track_status[FMDRIVER_TRACK_SSG_2].masked = mask & LIBOPNA_CHAN_SSG_2; +  g.work.track_status[FMDRIVER_TRACK_SSG_3].masked = mask & LIBOPNA_CHAN_SSG_3; +  g.work.track_status[FMDRIVER_TRACK_ADPCM].masked = mask & LIBOPNA_CHAN_ADPCM; +} + +static void mask_set(unsigned mask, bool shift) { +  if (shift) { +    opna_set_mask(&g.opna, mask); +  } else { +    opna_set_mask(&g.opna, opna_get_mask(&g.opna) ^ mask); +  } +  mask_update(); +} +  static gboolean key_press_cb(GtkWidget *w,                               GdkEvent *e,                               gpointer ptr) { @@ -442,26 +468,75 @@ static gboolean key_press_cb(GtkWidget *w,      if (e->key.state & GDK_CONTROL_MASK) {        fmdsp_palette_set(&g.fmdsp, e->key.keyval - GDK_KEY_F1);        return TRUE; +    } +  } +  bool shift = e->key.state & GDK_SHIFT_MASK; +  switch (e->key.keyval) { +  case GDK_KEY_F6: +    if (g.current_uri) { +      openfile(g.current_uri); +    } +    break; +  case GDK_KEY_F7: +    if (g.pa_paused) { +      Pa_StartStream(g.pastream); +      g.pa_paused = false;      } else { -      switch (e->key.keyval) { -      case GDK_KEY_F6: -        if (g.current_uri) { -          openfile(g.current_uri); -        } -        break; -      case GDK_KEY_F7: -        if (g.pa_paused) { -          Pa_StartStream(g.pastream); -          g.pa_paused = false; -        } else { -          Pa_StopStream(g.pastream); -          g.pa_paused = true; -        } -        break; -      } +      Pa_StopStream(g.pastream); +      g.pa_paused = true;      } +    break; +  case GDK_KEY_F11: +    fmdsp_dispstyle_set(&g.fmdsp, (g.fmdsp.style+1) % FMDSP_DISPSTYLE_CNT); +    break; +  case GDK_KEY_1: +    mask_set(LIBOPNA_CHAN_FM_1, shift); +    break; +  case GDK_KEY_2: +    mask_set(LIBOPNA_CHAN_FM_2, shift); +    break; +  case GDK_KEY_3: +    mask_set(LIBOPNA_CHAN_FM_3, shift); +    break; +  case GDK_KEY_4: +    mask_set(LIBOPNA_CHAN_FM_4, shift); +    break; +  case GDK_KEY_5: +    mask_set(LIBOPNA_CHAN_FM_5, shift); +    break; +  case GDK_KEY_6: +    mask_set(LIBOPNA_CHAN_FM_6, shift); +    break; +  case GDK_KEY_7: +    mask_set(LIBOPNA_CHAN_SSG_1, shift); +    break; +  case GDK_KEY_8: +    mask_set(LIBOPNA_CHAN_SSG_2, shift); +    break; +  case GDK_KEY_9: +    mask_set(LIBOPNA_CHAN_SSG_3, shift); +    break; +  case GDK_KEY_0: +    mask_set(LIBOPNA_CHAN_DRUM_ALL, shift); +    break; +  case GDK_KEY_minus: +    mask_set(LIBOPNA_CHAN_ADPCM, shift); +    break; +  // jp106 / pc98 +  case GDK_KEY_asciicircum: +  // us +  case GDK_KEY_equal: +    opna_set_mask(&g.opna, ~opna_get_mask(&g.opna)); +    mask_update(); +    break; +  case GDK_KEY_backslash: +    opna_set_mask(&g.opna, 0); +    mask_update(); +    break; +  default: +    return FALSE;    } -  return FALSE; +  return TRUE;  }  static void drag_data_recv_cb( diff --git a/libopna/opna.c b/libopna/opna.c index 4e198a0..fb9e24a 100644 --- a/libopna/opna.c +++ b/libopna/opna.c @@ -6,6 +6,7 @@ void opna_reset(struct opna *opna) {    opna_ssg_resampler_reset(&opna->resampler);    opna_drum_reset(&opna->drum);    opna_adpcm_reset(&opna->adpcm); +  opna->mask = 0;  }  void opna_writereg(struct opna *opna, unsigned reg, unsigned val) { @@ -22,3 +23,15 @@ void opna_mix(struct opna *opna, int16_t *buf, unsigned samples) {    opna_drum_mix(&opna->drum, buf, samples);    opna_adpcm_mix(&opna->adpcm, buf, samples);  } + +unsigned opna_get_mask(const struct opna *opna) { +  return opna->mask; +} + +void opna_set_mask(struct opna *opna, unsigned mask) { +  opna->mask = mask & 0xffffu; +  opna->fm.mask = mask & ((1<<(6+1))-1); +  opna->ssg.mask = (mask >> 6) & ((1<<(3+1))-1); +  opna->adpcm.masked = mask & LIBOPNA_CHAN_ADPCM; +  opna->drum.mask = (mask >> 9) & ((1<<(6+1))-1); +} diff --git a/libopna/opna.h b/libopna/opna.h index a056156..b5e9d87 100644 --- a/libopna/opna.h +++ b/libopna/opna.h @@ -10,18 +10,40 @@  extern "C" {  #endif +enum { +  LIBOPNA_CHAN_FM_1 = 0x0001, +  LIBOPNA_CHAN_FM_2 = 0x0002, +  LIBOPNA_CHAN_FM_3 = 0x0004, +  LIBOPNA_CHAN_FM_4 = 0x0008, +  LIBOPNA_CHAN_FM_5 = 0x0010, +  LIBOPNA_CHAN_FM_6 = 0x0020, +  LIBOPNA_CHAN_SSG_1 = 0x0040, +  LIBOPNA_CHAN_SSG_2 = 0x0080, +  LIBOPNA_CHAN_SSG_3 = 0x0100, +  LIBOPNA_CHAN_DRUM_BD = 0x0200, +  LIBOPNA_CHAN_DRUM_SD = 0x0400, +  LIBOPNA_CHAN_DRUM_TOP = 0x0800, +  LIBOPNA_CHAN_DRUM_HH = 0x1000, +  LIBOPNA_CHAN_DRUM_TOM = 0x2000, +  LIBOPNA_CHAN_DRUM_RIM = 0x4000, +  LIBOPNA_CHAN_DRUM_ALL = 0x7e00, +  LIBOPNA_CHAN_ADPCM = 0x8000, +}; +  struct opna {    struct opna_fm fm;    struct opna_ssg ssg;    struct opna_drum drum;    struct opna_adpcm adpcm;    struct opna_ssg_resampler resampler; - +  unsigned mask;  };  void opna_reset(struct opna *opna);  void opna_writereg(struct opna *opna, unsigned reg, unsigned val);  void opna_mix(struct opna *opna, int16_t *buf, unsigned samples); +unsigned opna_get_mask(const struct opna *opna); +void opna_set_mask(struct opna *opna, unsigned mask);  #ifdef __cplusplus  } diff --git a/libopna/opnaadpcm.c b/libopna/opnaadpcm.c index 1157b56..68dbae5 100644 --- a/libopna/opnaadpcm.c +++ b/libopna/opnaadpcm.c @@ -185,16 +185,18 @@ void opna_adpcm_mix(struct opna_adpcm *adpcm, int16_t *buf, unsigned samples) {    if (!(adpcm->control1 & C1_START)) return;    for (unsigned i = 0; i < samples; i++) {      adpcm_calc(adpcm); -    int32_t lo = buf[i*2+0]; -    int32_t ro = buf[i*2+1]; -    if (adpcm->control2 & C2_L) lo += (adpcm->out>>1); -    if (adpcm->control2 & C2_R) ro += (adpcm->out>>1); -    if (lo < INT16_MIN) lo = INT16_MIN; -    if (lo > INT16_MAX) lo = INT16_MAX; -    if (ro < INT16_MIN) ro = INT16_MIN; -    if (ro > INT16_MAX) ro = INT16_MAX; -    buf[i*2+0] = lo; -    buf[i*2+1] = ro; +    if (!adpcm->masked) { +      int32_t lo = buf[i*2+0]; +      int32_t ro = buf[i*2+1]; +      if (adpcm->control2 & C2_L) lo += (adpcm->out>>1); +      if (adpcm->control2 & C2_R) ro += (adpcm->out>>1); +      if (lo < INT16_MIN) lo = INT16_MIN; +      if (lo > INT16_MAX) lo = INT16_MAX; +      if (ro < INT16_MIN) ro = INT16_MIN; +      if (ro > INT16_MAX) ro = INT16_MAX; +      buf[i*2+0] = lo; +      buf[i*2+1] = ro; +    }      if (!(adpcm->control1 & C1_START)) return;    }  } diff --git a/libopna/opnaadpcm.h b/libopna/opnaadpcm.h index 27a1349..42033ad 100644 --- a/libopna/opnaadpcm.h +++ b/libopna/opnaadpcm.h @@ -23,6 +23,7 @@ struct opna_adpcm {    int16_t prev_acc;    uint16_t adpcmd;    int16_t out; +  bool masked;  };  void opna_adpcm_reset(struct opna_adpcm *adpcm); diff --git a/libopna/opnadrum.c b/libopna/opnadrum.c index 2527c1a..1a298af 100644 --- a/libopna/opnadrum.c +++ b/libopna/opnadrum.c @@ -25,6 +25,7 @@ void opna_drum_reset(struct opna_drum *drum) {      drum->drums[d].right = false;    }    drum->total_level = 0; +  drum->mask = 0;  }  void opna_drum_set_rom(struct opna_drum *drum, void *romptr) { @@ -90,8 +91,10 @@ 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); -        if (drum->drums[d].left) lo += co; -        if (drum->drums[d].right) ro += co; +        if (!(drum->mask & (1u << d))) { +          if (drum->drums[d].left) lo += co; +          if (drum->drums[d].right) ro += co; +        }          drum->drums[d].index++;          if (drum->drums[d].index == drum->drums[d].len) {            drum->drums[d].index = 0; diff --git a/libopna/opnadrum.h b/libopna/opnadrum.h index 7c13098..79f95a2 100644 --- a/libopna/opnadrum.h +++ b/libopna/opnadrum.h @@ -40,6 +40,7 @@ struct opna_drum {    int16_t rom_hh[OPNA_ROM_HH_SIZE];    int16_t rom_tom[OPNA_ROM_TOM_SIZE];    int16_t rom_rim[OPNA_ROM_RIM_SIZE]; +  unsigned mask;  };  void opna_drum_reset(struct opna_drum *drum); diff --git a/libopna/opnafm.c b/libopna/opnafm.c index c7512a8..437fcdc 100644 --- a/libopna/opnafm.c +++ b/libopna/opnafm.c @@ -58,6 +58,7 @@ void opna_fm_reset(struct opna_fm *fm) {      fm->ch3.fnum[i] = 0;      fm->ch3.blk[i] = 0;    } +  fm->mask = 0;  }  #define LIBOPNA_ENABLE_HIRES  // maximum output: 2042<<2 = 8168 @@ -497,6 +498,7 @@ void opna_fm_mix(struct opna_fm *fm, int16_t *buf, unsigned samples) {          opna_fm_chan_phase(&fm->channel[c]);        }        o >>= 1; +      if (fm->mask & (1<<c)) continue;        if (fm->lselect[c]) lo += o;        if (fm->rselect[c]) ro += o;      } diff --git a/libopna/opnafm.h b/libopna/opnafm.h index acd673f..cf4fff5 100644 --- a/libopna/opnafm.h +++ b/libopna/opnafm.h @@ -78,6 +78,10 @@ struct opna_fm {    // pan    bool lselect[6];    bool rselect[6]; + +  // mask +  // when (1<<channel), the channel is masked +  unsigned mask;  };  void opna_fm_reset(struct opna_fm *fm); diff --git a/libopna/opnassg.c b/libopna/opnassg.c index cc797b0..1345502 100644 --- a/libopna/opnassg.c +++ b/libopna/opnassg.c @@ -73,6 +73,7 @@ void opna_ssg_reset(struct opna_ssg *ssg) {    ssg->env_alt = false;    ssg->env_hld = false;    ssg->env_holding = false; +  ssg->mask = 0;  }  void opna_ssg_resampler_reset(struct opna_ssg_resampler *resampler) { @@ -171,6 +172,7 @@ void opna_ssg_generate_raw(struct opna_ssg *ssg, int16_t *buf, int samples) {          ssg->ch[ch].tone_counter = 0;          ssg->ch[ch].out = !ssg->ch[ch].out;        } +      if (ssg->mask & (1<<ch)) continue;  #if 0        if (opna_ssg_tone_out(ssg, ch)) {          int level = opna_ssg_chan_env(ssg, ch) diff --git a/libopna/opnassg.h b/libopna/opnassg.h index 5928c49..adcd231 100644 --- a/libopna/opnassg.h +++ b/libopna/opnassg.h @@ -24,6 +24,7 @@ struct opna_ssg {    bool env_alt;    bool env_hld;    bool env_holding; +  unsigned mask;  };  struct opna_ssg_resampler { diff --git a/win32/main.c b/win32/main.c index c926f5b..1e637b7 100644 --- a/win32/main.c +++ b/win32/main.c @@ -466,7 +466,7 @@ static void on_destroy(HWND hwnd) {  }  static void on_paint(HWND hwnd) { -  fmdsp_update(&g.fmdsp, &g.work, g.vram); +  fmdsp_update(&g.fmdsp, &g.work, &g.opna, g.vram);    PAINTSTRUCT ps;    static BITMAPINFO *bi = 0;    if (!bi) { | 
