diff options
Diffstat (limited to 'fmdriver')
| -rw-r--r-- | fmdriver/fmdriver.h | 12 | ||||
| -rw-r--r-- | fmdriver/fmdriver_common.h | 18 | ||||
| -rw-r--r-- | fmdriver/fmdriver_fmp.c | 27 | ||||
| -rw-r--r-- | fmdriver/fmdriver_pmd.c | 535 | ||||
| -rw-r--r-- | fmdriver/fmdriver_pmd.h | 6 | ||||
| -rw-r--r-- | fmdriver/ppz8.c | 50 | ||||
| -rw-r--r-- | fmdriver/ppz8.h | 9 | 
7 files changed, 614 insertions, 43 deletions
| diff --git a/fmdriver/fmdriver.h b/fmdriver/fmdriver.h index 84234ee..9f3afee 100644 --- a/fmdriver/fmdriver.h +++ b/fmdriver/fmdriver.h @@ -19,6 +19,14 @@ enum {    FMDRIVER_TRACK_SSG_2,    FMDRIVER_TRACK_SSG_3,    FMDRIVER_TRACK_ADPCM, +  FMDRIVER_TRACK_PPZ8_1, +  FMDRIVER_TRACK_PPZ8_2, +  FMDRIVER_TRACK_PPZ8_3, +  FMDRIVER_TRACK_PPZ8_4, +  FMDRIVER_TRACK_PPZ8_5, +  FMDRIVER_TRACK_PPZ8_6, +  FMDRIVER_TRACK_PPZ8_7, +  FMDRIVER_TRACK_PPZ8_8,    FMDRIVER_TRACK_NUM  };  enum { @@ -30,6 +38,7 @@ enum fmdriver_track_type {    FMDRIVER_TRACKTYPE_FM,    FMDRIVER_TRACKTYPE_SSG,    FMDRIVER_TRACKTYPE_ADPCM, +  FMDRIVER_TRACKTYPE_PPZ8,    FMDRIVER_TRACKTYPE_CNT,  }; @@ -85,7 +94,10 @@ struct fmdriver_work {    char comment[3][FMDRIVER_TITLE_BUFLEN];    // only single-byte uppercase cp932    char filename[FMDRIVER_TITLE_BUFLEN]; +  // always 8 characters and pad with ' ' +  char pcmname[2][9];    // driver status (for display) +  bool pcmerror[2];    uint8_t ssg_noise_freq;    struct fmdriver_track_status track_status[FMDRIVER_TRACK_NUM];    // fm3ex part map diff --git a/fmdriver/fmdriver_common.h b/fmdriver/fmdriver_common.h index 2700336..30cf12c 100644 --- a/fmdriver/fmdriver_common.h +++ b/fmdriver/fmdriver_common.h @@ -7,6 +7,10 @@ static inline uint16_t read16le(const uint8_t *ptr) {    return (unsigned)ptr[0] | (((unsigned)ptr[1])<<8);  } +static inline uint32_t read32le(const uint8_t *ptr) { +  return (uint32_t)ptr[0] | (((uint32_t)ptr[1])<<8) | (((uint32_t)ptr[2])<<16) | (((uint32_t)ptr[3])<<24); +} +  static inline int8_t u8s8(uint8_t v) {    return (v & 0x80) ? ((int16_t)v)-0x100 : v;  } @@ -15,6 +19,20 @@ static inline int16_t u16s16(uint16_t v) {    return (v & 0x8000u) ? ((int32_t)v)-0x10000l : v;  } +static inline void fmdriver_fillpcmname(char *dest, const char *src) { +  int i; +  for (i = 0; i < 8; i++) { +    dest[i] = src[i]; +    if (!src[i]) break; +  } +  if (src[i]) i = 0; + +  for (; i < 8; i++) { +    dest[i] = ' '; +  } +  dest[i] = 0; +} +  uint8_t fmdriver_fm_freq2key(uint16_t freq);  uint8_t fmdriver_ssg_freq2key(uint16_t freq); diff --git a/fmdriver/fmdriver_fmp.c b/fmdriver/fmdriver_fmp.c index 90a157c..cc6f1a6 100644 --- a/fmdriver/fmdriver_fmp.c +++ b/fmdriver/fmdriver_fmp.c @@ -2746,6 +2746,14 @@ static const uint8_t fmp_track_map[FMDRIVER_TRACK_NUM] = {    FMP_PART_SSG_2,
    FMP_PART_SSG_3,
    FMP_PART_ADPCM,
 +  FMP_PART_PPZ8_1,
 +  FMP_PART_PPZ8_2,
 +  FMP_PART_PPZ8_3,
 +  FMP_PART_PPZ8_4,
 +  FMP_PART_PPZ8_5,
 +  FMP_PART_PPZ8_6,
 +  FMP_PART_PPZ8_7,
 +  FMP_PART_PPZ8_8,
  };
  static void fmp_work_status_init(struct fmdriver_work *work,
 @@ -3468,27 +3476,12 @@ 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);
    fmp_init_parts(work, fmp);
    uint16_t fmtoneptr = fmp->datainfo.fmtoneptr;
 +  (void)fmtoneptr;
    FMDRIVER_DEBUG(" 000 %03d %03d\n",
                   fmp->data[fmtoneptr+0x18]&0x7,
                   (fmp->data[fmtoneptr+0x18]>>3)&0x7
 @@ -3497,6 +3490,8 @@ void fmp_init(struct fmdriver_work *work, struct driver_fmp *fmp) {    work->driver = fmp;
    work->driver_opna_interrupt = fmp_opna_interrupt;
    fmp_work_status_init(work, fmp);
 +  fmdriver_fillpcmname(work->pcmname[0], fmp->pvi_name);
 +  fmdriver_fillpcmname(work->pcmname[1], fmp->ppz_name);
  }
  // 4235
 diff --git a/fmdriver/fmdriver_pmd.c b/fmdriver/fmdriver_pmd.c index 2a093c2..09630bf 100644 --- a/fmdriver/fmdriver_pmd.c +++ b/fmdriver/fmdriver_pmd.c @@ -70,6 +70,7 @@ static uint8_t pmd_opna_read_ssgout(struct fmdriver_work *work) {    return work->opna_readreg(work, 0x07);  } +/*  // 331f  static void pmd_stop_sound(struct fmdriver_work *work,                       struct driver_pmd *pmd) { @@ -126,7 +127,9 @@ static void pmd_stop_sound(struct fmdriver_work *work,      }    }  } +*/ +/*  // 11df  static void pmd_mstop(struct fmdriver_work *work,                        struct driver_pmd *pmd) { @@ -137,6 +140,7 @@ static void pmd_mstop(struct fmdriver_work *work,    pmd->fadeout_vol = 0xff;    pmd_stop_sound(work, pmd);  } +*/  // 1058  static void pmd_reset_state(struct driver_pmd *pmd) { @@ -1310,8 +1314,6 @@ static void pmd_note_freq_adpcm(      0, 0, 0, 0    };    uint8_t octave = note >> 4; -  int cl = 5 - octave; -  if (cl < 0) cl = 0;    uint16_t tonefreq = adpcm_tonetable[note & 0x0f];    if (octave <= 5) {      tonefreq >>= (5 - octave); @@ -1327,6 +1329,50 @@ static void pmd_note_freq_adpcm(    part->actual_freq = tonefreq;  } +// 0c97 +static void pmd_note_freq_ppz8( +  struct pmd_part *part, +  uint8_t note +) { +  if ((note & 0xf) == 0xf) { +    // 0cd8 +    part->actual_note = 0xff; +    if (!part->lfof.freq && !part->lfof_b.freq) { +      part->actual_freq = 0; +      part->actual_freq_upper = 0; +    } +    return; +  } +  part->actual_note = note; +  static const uint16_t ppz8_tonetable[0x10] = { +    // 0cf1 +    // documented in ppz8.doc +    // different from round(0x8000*(2**(i/12))) +    0x8000, +    0x87a6, +    0x8fb3, +    0x9838, +    0xa146, +    0xaade, +    0xb4ff, +    0xbfcc, +    0xcb34, +    0xd747, +    0xe418, +    0xf1a5, +    0, 0, 0, 0 +  }; +  int octave = (note >> 4) - 4; +  uint32_t freq = ppz8_tonetable[note & 0x0f]; +  if (octave < 0) { +    freq >>= -octave; +  } else { +    freq <<= octave; +  } +  part->actual_freq = freq; +  part->actual_freq_upper = freq >> 16; +} +  // 14a0  static void pmd_part_calc_gate(    struct driver_pmd *pmd, @@ -1594,6 +1640,72 @@ static void pmd_adpcm_vol_out(    work->opna_writereg(work, 0x10b, vol);  } +// 0b33 +static void pmd_ppz8_vol_out( +  struct fmdriver_work *work, +  struct driver_pmd *pmd, +  struct pmd_part *part +) { +  uint8_t vol = part->volume_save; +  if (!vol) vol = part->vol; +   +  // 0b3f +  if (pmd->ppz8_voldown) { +    uint8_t voldown = -pmd->ppz8_voldown; +    vol = vol * voldown >> 8; +  } +  // 0b4c +  if (pmd->fadeout_vol) { +    uint8_t fadeout = -pmd->fadeout_vol; +    vol = vol * fadeout >> 8; +  } +  // 0b59 +  if (vol) { +    if (part->ssg_env_state_old == SSG_ENV_STATE_OLD_NEW) { +      uint8_t envvol = part->ssg_env_vol; +      if (!envvol) { +        vol = 0; +        // -> 0bd4 +      } else { +        vol = (vol * (envvol+1)) >> 3; +        if (vol & 1) { +          vol >>= 1; +          vol++; +        } else { +          vol >>= 1; +        } +      } +    } else { +      // 0b7d +      int newvol = vol + (part->ssg_env_vol << 4); +      if (newvol > 0xff) newvol = 0xff; +      if (newvol < 0) newvol = 0; +      vol = newvol; +    } +    // 0ba4 +    if (part->lfof.vol || part->lfof_b.vol) { +      int32_t lfovol = 0; +      if (part->lfof.vol) vol += part->lfo_diff; +      if (part->lfof_b.vol) vol += part->lfo_diff_b; +      lfovol += vol; +      vol = lfovol; +      if (lfovol < 0) { +        vol = 0; +      } else if (lfovol > 0xff) { +        vol = 0xff; +      } +    } +  } +  // 0bd4 +  if (work->ppz8) { +    if (vol) { +      work->ppz8_functbl->channel_volume(work->ppz8, pmd->proc_ch, vol >> 4); +    } else { +      work->ppz8_functbl->channel_stop(work->ppz8, pmd->proc_ch); +    } +  } +} +  // 2985  static void pmd_ssg_freq_out(    struct fmdriver_work *work, @@ -1675,6 +1787,33 @@ static void pmd_adpcm_freq_out(    work->opna_writereg(work, 0x10a, freq >> 8);  } +// 0c27 +static void pmd_ppz8_freq_out( +  struct fmdriver_work *work, +  struct driver_pmd *pmd, +  struct pmd_part *part +) { +  uint32_t freq = part->actual_freq | (((uint32_t)part->actual_freq_upper) << 16); +  if (!freq) return; +  if (part->portamento_diff) { +    freq += part->portamento_diff * 4; +  } +  int32_t det = 0; +  if (part->lfof.freq || part->lfof_b.freq) { +    if (part->lfof.freq) det += part->lfo_diff; +    if (part->lfof_b.freq) det += part->lfo_diff_b; +  } +  // 0c6a +  det += part->detune; +  det *= freq >> 8; +  int64_t outfreq = freq + det; +  if (outfreq < 0) outfreq = 0; +  if (outfreq > INT32_MAX) outfreq = INT32_MAX; +  if (work->ppz8) { +    work->ppz8_functbl->channel_freq(work->ppz8, pmd->proc_ch, outfreq); +  } +} +  // 2c9f  static uint16_t pmd_part_ssg_readout(    struct fmdriver_work *work, @@ -1756,6 +1895,18 @@ static void pmd_part_adpcm_keyon(    }  } +// 0bf6 +static void pmd_part_ppz8_keyon( +  struct fmdriver_work *work, +  struct driver_pmd *pmd, +  struct pmd_part *part +) { +  if (part->actual_note == 0xff) return; +  if (work->ppz8) { +    work->ppz8_functbl->channel_play(work->ppz8, pmd->proc_ch, part->tonenum); +  } +} +  // 2942  static uint32_t pmd_blkfnum_normalize(    uint16_t blk, @@ -1932,6 +2083,37 @@ static void pmd_part_adpcm_out(    pmd_part_loop_check(pmd, part);  } +// 0803 +static void pmd_part_ppz8_out( +  struct fmdriver_work *work, +  struct driver_pmd *pmd, +  struct pmd_part *part +) { +  if (part->volume_save && part->actual_note != 0xff) { +    if (!pmd->volume_saved) { +      part->volume_save = 0; +    } +    pmd->volume_saved = false; +  } +  pmd_ppz8_vol_out(work, pmd, part); +  pmd_ppz8_freq_out(work, pmd, part); +  if (part->keystatus.off) { +    pmd_part_ppz8_keyon(work, pmd, part); +  } +  // 082d +  part->note_proc++; +  pmd->no_keyoff = false; +  pmd->volume_saved = false; +  part->keystatus.off = false; +  part->keystatus.off_mask = false; +  if (pmd->datalen > (part->ptr + 1)) { +    if (pmd->data[part->ptr] == 0xfb) { +      part->keystatus.off_mask = true; +    } +  } +  pmd_part_loop_check(pmd, part); +} +  // none  static bool pmd_part_masked(    const struct pmd_part *part @@ -2052,11 +2234,6 @@ static void pmd_cmdff_tonenum_adpcm(    pmd->adpcm_release = 0x8000;  } -// 0a3c -static void pmd() { -  // 0790 -} -  // 0afd  static void pmd_cmdff_tonenum_ppz8(    struct fmdriver_work *work, @@ -2065,6 +2242,10 @@ static void pmd_cmdff_tonenum_ppz8(  ){    part->tonenum = pmd_part_cmdload(pmd, part);    // 0a3c +  if (work->ppz8) { +    work->ppz8_functbl->channel_loop_voice(work->ppz8, pmd->proc_ch, part->tonenum); +  } +  // set origfreq  }  // 22b3 @@ -2340,7 +2521,7 @@ static void pmd_cmdf1_ppsdrv(    struct driver_pmd *pmd,    struct pmd_part *part  ){ -  uint8_t data = pmd_part_cmdload(pmd, part); +  /* uint8_t data = */pmd_part_cmdload(pmd, part);    // TODO: PPSDRV  } @@ -2447,6 +2628,22 @@ static void pmd_cmdec_pan_adpcm(    part->pan = pmd_part_cmdload(pmd, part) << 6;  } +// 0aca +static void pmd_cmdec_pan_ppz8( +  struct fmdriver_work *work, +  struct driver_pmd *pmd, +  struct pmd_part *part +) { +  uint8_t pan = pmd_part_cmdload(pmd, part); +  // 0ced +  static const uint8_t pantable[4] = {0, 9, 1, 5}; +  part->pan = 0; +  if (pan < 4) part->pan = pantable[pan]; +  if (work->ppz8) { +    work->ppz8_functbl->channel_pan(work->ppz8, pmd->proc_ch, part->pan); +  } +} +  // 265d  static void pmd_opnarhythm_inc(uint8_t *incdata, uint8_t val) {    for (int i = 0; i < 6; i++) { @@ -2838,7 +3035,7 @@ static void pmd_cmdda_portamento_adpcm(    uint8_t n1 = part->actual_note;    note = pmd_part_cmdload(pmd, part);    note = pmd_part_note_transpose(part, note); -  pmd_note_freq_fm(part, note); +  pmd_note_freq_adpcm(part, note);    uint16_t f2 = part->actual_freq;    part->actual_freq = f1;    part->actual_note = n1; @@ -2858,6 +3055,42 @@ static void pmd_cmdda_portamento_adpcm(    pmd_part_adpcm_out(work, pmd, part);  } +// 0a62 +static void pmd_cmdda_portamento_ppz8( +  struct fmdriver_work *work, +  struct driver_pmd *pmd, +  struct pmd_part *part +){ +  uint8_t note = pmd_part_cmdload(pmd, part); +  if (pmd_part_masked(part)) return; +  pmd_part_lfo_init_ssg(work, pmd, part, note); +  note = pmd_part_note_transpose(part, note); +  pmd_note_freq_ppz8(part, note); +  uint32_t f1 = (((uint32_t)part->actual_freq_upper) << 16) | part->actual_freq; +  uint8_t n1 = part->actual_note; +  note = pmd_part_cmdload(pmd, part); +  note = pmd_part_note_transpose(part, note); +  pmd_note_freq_ppz8(part, note); +  uint32_t f2 = (((uint32_t)part->actual_freq_upper) << 16) | part->actual_freq; +  part->actual_freq = f1; +  part->actual_freq_upper = f1 >> 16; +  part->actual_note = n1; +  int16_t freqdiff = u16s16((f2 - f1)>>4); +  uint8_t clocks = pmd_part_cmdload(pmd, part); +  part->len = part->len_cnt = clocks; +  pmd_part_calc_gate(pmd, part); +  int16_t p_add = 0; +  int16_t p_rem = 0; +  if (clocks) { +    p_add = freqdiff / clocks; +    p_rem = freqdiff % clocks; +  } +  part->portamento_add = p_add; +  part->portamento_rem = p_rem; +  part->lfof.portamento = true; +  pmd_part_ppz8_out(work, pmd, part); +} +  // 20bf  static void pmd_cmdd6_md(    struct fmdriver_work *work, @@ -2990,10 +3223,10 @@ static void pmd_cmdce_adpcm_loop(    struct fmdriver_work *work,    struct driver_pmd *pmd,    struct pmd_part *part -){ +) {    uint16_t diff = pmd_part_cmdload(pmd, part);    diff |= (uint16_t)pmd_part_cmdload(pmd, part) << 8; -  if (!(diff & 0x80)) diff += pmd->adpcm_start; +  if (!(diff & 0x8000)) diff += pmd->adpcm_start;    else diff += pmd->adpcm_stop;    pmd->adpcm_start_loop = diff;    diff = pmd_part_cmdload(pmd, part); @@ -3010,6 +3243,26 @@ static void pmd_cmdce_adpcm_loop(    pmd->adpcm_release = diff;  } +// 0a04 +static void pmd_cmdce_ppz8_loop( +  struct fmdriver_work *work, +  struct driver_pmd *pmd, +  struct pmd_part *part +) { +  uint32_t startoff = pmd_part_cmdload(pmd, part); +  startoff |= (uint16_t)pmd_part_cmdload(pmd, part) << 8; +  uint32_t endoff = pmd_part_cmdload(pmd, part); +  endoff |= (uint16_t)pmd_part_cmdload(pmd, part) << 8; +  if (work->ppz8) { +    uint32_t len = work->ppz8_functbl->voice_length(work->ppz8, part->tonenum); +    if (startoff & 0x8000) startoff = len + u16s16(startoff); +    if (endoff & 0x8000) endoff = len + u16s16(endoff); +    work->ppz8_functbl->channel_loopoffset(work->ppz8, pmd->proc_ch, startoff, endoff); +  } +  pmd_part_cmdload(pmd, part); +  pmd_part_cmdload(pmd, part); +} +  // 1e1b  static void pmd_cmdcd_env_new(    struct fmdriver_work *work, @@ -3215,6 +3468,27 @@ static void pmd_cmdc3_pan_ex_adpcm(    part->pan = pan;  } +// 0ae5 +static void pmd_cmdc3_pan_ex_ppz8( +  struct fmdriver_work *work, +  struct driver_pmd *pmd, +  struct pmd_part *part +){ +  uint8_t data = pmd_part_cmdload(pmd, part); +  pmd_part_cmdload(pmd, part); +  if (!(data & 0x80)) { +    if (data > 4) data = 4; +  } else { +    if (data < 0xfc) data = 0xfc; +  } +  data += 5; +  uint8_t pan = data; +  part->pan = pan; +  if (work->ppz8) { +    work->ppz8_functbl->channel_pan(work->ppz8, pmd->proc_ch, part->pan); +  } +} +  // 2509  static void pmd_cmdc2_lfo_delay(    struct fmdriver_work *work, @@ -3510,7 +3784,7 @@ static void pmd_cmdc0_mml_mask_adpcm(    struct fmdriver_work *work,    struct driver_pmd *pmd,    struct pmd_part *part -){ +) {    uint8_t data = pmd_part_cmdload(pmd, part);    if (data >= 2) {      pmd_cmdc0_extended(work, pmd, part, data); @@ -3532,6 +3806,36 @@ static void pmd_cmdc0_mml_mask_adpcm(    }  } +// 09d8 +static void pmd_cmdc0_mml_mask_ppz8( +  struct fmdriver_work *work, +  struct driver_pmd *pmd, +  struct pmd_part *part +) { +  uint8_t data = pmd_part_cmdload(pmd, part); +  if (data >= 2) { +    pmd_cmdc0_extended(work, pmd, part, data); +    return; +  } else if (data == 1) { +    // 09e4 +    part->mask.mml = false; +    bool masked = pmd_part_masked(part); +    part->mask.mml = true; +    if (!masked) { +      if (work->ppz8) { +        work->ppz8_functbl->channel_stop(work->ppz8, pmd->proc_ch); +      } +    } +    part->proc_masked = true; +    // -> 08ca +  } else { +    // 09fa +    part->mask.mml = false; +    part->proc_masked = pmd_part_masked(part); +    // -> 07cd +  } +} +  // 1caa  static void pmd_cmdc0_mml_mask_rhythm(    struct fmdriver_work *work, @@ -4099,8 +4403,8 @@ static const pmd_cmd_func pmd_cmd_table_adpcm[PMD_CMD_CNT] = {    pmd_cmd_null_1,    pmd_cmde3_vol_add_adpcm,    pmd_cmde2_vol_sub, -  pmd_cmde1_ams_pms, -  pmd_cmde0_hlfo, +  pmd_cmd_null_1, +  pmd_cmd_null_1,    pmd_cmddf_meas_len,    pmd_cmdde_echo_init_add_adpcm,    pmd_cmddd_echo_init_sub, @@ -4151,7 +4455,85 @@ static const pmd_cmd_func pmd_cmd_table_adpcm[PMD_CMD_CNT] = {  };  static const pmd_cmd_func pmd_cmd_table_ppz8[PMD_CMD_CNT] = { -   +  pmd_cmdff_tonenum_ppz8, +  pmd_cmdfe_gate_abs, +  pmd_cmdfd_vol, +  pmd_cmdfc_tempo, +  pmd_cmdfb_tie, +  pmd_cmdfa_d5_det, +  pmd_cmdf9_repeat_reset, +  pmd_cmdf8_repeat, +  pmd_cmdf7_repeat_exit, +  pmd_cmdf6_set_loop, +  pmd_cmdf5_transpose, +  pmd_cmdf4_volinc_adpcm, +  pmd_cmdf3_voldec_adpcm, +  pmd_cmdf2_lfo, +  pmd_cmdf1_lfo_switch, +  pmd_cmdf0_env_old, +  pmd_cmdef_poke, +  pmd_cmd_null_1, +  pmd_cmd_null_1, +  pmd_cmdec_pan_ppz8, +  pmd_cmdeb_opnarhythm, +  pmd_cmdea_opnarhythm_il, +  pmd_cmde9_opnarhythm_pan, +  pmd_cmde8_opnarhythm_tl, +  pmd_cmde7_transpose_rel, +  pmd_cmde6_opnarhythm_tl_rel, +  pmd_cmde5_opnarhythm_il_rel, +  pmd_cmd_null_1, +  pmd_cmde3_vol_add_adpcm, +  pmd_cmde2_vol_sub, +  pmd_cmd_null_1, +  pmd_cmd_null_1, +  pmd_cmddf_meas_len, +  pmd_cmdde_echo_init_add_adpcm, +  pmd_cmddd_echo_init_sub, +  pmd_cmddc_status1, +  pmd_cmddb_status1_add, +  pmd_cmdda_portamento_ppz8, +  pmd_cmd_null_1, +  pmd_cmd_null_1, +  pmd_cmd_null_1, +  pmd_cmdd6_md, +  pmd_cmdfa_d5_det, +  pmd_cmdd4_ssgeff, +  pmd_cmdd3_fmeff, +  pmd_cmdd2_fadeout, +  pmd_cmd_null_1, +  pmd_cmd_null_1, +  pmd_cmd_null_1, +  pmd_cmdce_ppz8_loop, +  pmd_cmdcd_env_new, +  pmd_cmd_null_1, +  pmd_cmdcb_lfo_waveform, +  pmd_cmdca_lfo_ext, +  pmd_cmdc9_env_ext, +  pmd_cmd_null_3, +  pmd_cmd_null_3, +  pmd_cmd_null_6, +  pmd_cmd_null_1, +  pmd_cmdc4_gate_rel, +  pmd_cmdc3_pan_ex_ppz8, +  pmd_cmdc2_lfo_delay, +  pmd_cmd_null_0, +  pmd_cmdc0_mml_mask_ppz8, +  pmd_cmdbf_lfo2, +  pmd_cmdbe_lfo2_switch, +  pmd_cmdbd_lfo2_md, +  pmd_cmdbc_lfo2_waveform, +  pmd_cmdbb_lfo2_ext, +  pmd_cmdba_lfo2_slotmask, // slotmask on PPZ8?? +  pmd_cmdb9_lfo2_delay, +  pmd_cmd_null_2, +  pmd_cmdb7_lfo_md_cnt, +  pmd_cmd_null_1, +  pmd_cmd_null_2, +  pmd_cmd_null_16, +  pmd_cmdb3_gate_min, +  pmd_cmdb2_transpose_master, +  pmd_cmdb1_gate_rand_range  };  // 1857 @@ -4210,6 +4592,20 @@ static void pmd_part_cmd_adpcm(    pmd_cmd_table_adpcm[cmd^0xff](work, pmd, part);  } +// 02c6 +static void pmd_part_cmd_ppz8( +  struct fmdriver_work *work, +  struct driver_pmd *pmd, +  struct pmd_part *part, +  uint8_t cmd +) { +  if (cmd < 0xb1) { +    part->ptr = 0; +    return; +  } +  pmd_cmd_table_ppz8[cmd^0xff](work, pmd, part); +} +  // 20e8  static void pmd_portamento_tick(    struct pmd_part *part @@ -4375,6 +4771,49 @@ static void pmd_part_proc_adpcm_lfoenv(    pmd_part_loop_check(pmd, part);  } +// 084c +static void pmd_part_proc_ppz8_lfoenv( +  struct fmdriver_work *work, +  struct driver_pmd *pmd, +  struct pmd_part *part +) { +  static const struct pmd_part_lfo_flags lfof_z; +  pmd->lfoprocf = lfof_z; +  pmd->lfoprocf_b = lfof_z; +  pmd->lfoprocf.portamento = part->lfof.portamento; +   +  if (part->lfof.freq || part->lfof.vol || part->lfof.sync || part->lfof.portamento || +      part->lfof_b.freq || part->lfof_b.vol || part->lfof_b.sync || part->lfof_b.portamento) { +    // 085a +    if (part->lfof.freq || part->lfof.vol) { +      if (pmd_lfo_tick(pmd, part)) { +        pmd->lfoprocf.freq = part->lfof.freq; +        pmd->lfoprocf.vol = part->lfof.vol; +      } +    } +    if (part->lfof_b.freq || part->lfof_b.vol) { +      pmd_part_lfo_flip(part); +      if (pmd_lfo_tick(pmd, part)) { +        pmd->lfoprocf_b.freq = part->lfof_b.freq; +        pmd->lfoprocf_b.vol = part->lfof_b.vol; +      } +      pmd_part_lfo_flip(part); +    } +    // 088e +    if (pmd->lfoprocf.freq || pmd->lfoprocf.portamento || pmd->lfoprocf_b.freq) { +      if (pmd->lfoprocf.portamento) { +        pmd_portamento_tick(part); +      } +      pmd_ppz8_freq_out(work, pmd, part); +    } +  } +  // 08a2 +  if (pmd_ssg_env_proc(pmd, part) || pmd->lfoprocf.vol || pmd->lfoprocf_b.vol || pmd->fadeout_speed) { +    pmd_ppz8_vol_out(work, pmd, part); +  } +  pmd_part_loop_check(pmd, part); +} +  // 16d9  static bool pmd_part_ssg_next_masked(    struct fmdriver_work *work, @@ -4938,36 +5377,70 @@ static void pmd_part_proc_ppz8(    struct driver_pmd *pmd,    struct pmd_part *part  ) { -  /*    if (!part->ptr) return;    part->proc_masked = pmd_part_masked(part);    part->len_cnt--; -  if (!part->keystatus.off && !part->keystatus.off_mask) { +  if (part->proc_masked) { +    part->keystatus.off = true; +    part->keystatus.off_mask = true; +  } else if (!part->keystatus.off && !part->keystatus.off_mask) {      // 07b6      if (part->len_cnt <= part->gate) {        part->keystatus.off = true;        part->keystatus.off_mask = true; -      pmd_part_off_ppz8(work, pmd, part); +      pmd_part_off_ppz8(part);      }    }    // 07c2    if (part->len_cnt) { -    // 084c +    if (part->proc_masked) { +      pmd_part_loop_check(pmd, part); +    } else { +      pmd_part_proc_ppz8_lfoenv(work, pmd, part); +    } +    return;    }    part->lfof.portamento = false;    for (;;) { -    // 07cd +    // 07cd / 08ca      uint8_t cmd = pmd_part_cmdload(pmd, part);      if (cmd & 0x80) {        if (cmd != 0x80) { -        pmd_part_cmd_adpcm(work, pmd, part, cmd); +        pmd_part_cmd_ppz8(work, pmd, part, cmd);          if (cmd == 0xda && !pmd_part_masked(part)) return;        } else { -        // 0187 +        // 07d9 / 08d6 +        part->ptr = 0; +        part->loop.looped = true; +        part->loop.ended = true; +        part->actual_note = 0xff; +        if (!part->loop_ptr) { +          if (part->proc_masked) { +            pmd_part_loop_check_masked(pmd, part); +          } else { +            pmd_part_proc_ppz8_lfoenv(work, pmd, part); +          } +          return; +        } +        part->ptr = part->loop_ptr; +        part->loop.ended = false; +      } +    } else { +      // 07f3 / 08f3 +      if (part->proc_masked) { +        part->actual_freq_upper = 0; +        pmd_part_proc_note_masked(work, pmd, part); +      } else { +        pmd_part_lfo_init_ssg(work, pmd, part, cmd); +        cmd = pmd_part_note_transpose(part, cmd); +        pmd_note_freq_ppz8(part, cmd); +        part->len = part->len_cnt = pmd_part_cmdload(pmd, part); +        pmd_part_calc_gate(pmd, part); +        pmd_part_ppz8_out(work, pmd, part);        } +      return;      }    } -  */  }  // 11fd @@ -5119,6 +5592,7 @@ enum pmd_part_type {    PART_TYPE_FM,    PART_TYPE_SSG,    PART_TYPE_ADPCM, +  PART_TYPE_PPZ8  };  static const struct { @@ -5139,6 +5613,14 @@ static const struct {    {PMD_PART_SSG_2, PART_TYPE_SSG,   false},    {PMD_PART_SSG_3, PART_TYPE_SSG,   false},    {PMD_PART_ADPCM, PART_TYPE_ADPCM, false}, +  {PMD_PART_PPZ_1, PART_TYPE_PPZ8,   false}, +  {PMD_PART_PPZ_2, PART_TYPE_PPZ8,   false}, +  {PMD_PART_PPZ_3, PART_TYPE_PPZ8,   false}, +  {PMD_PART_PPZ_4, PART_TYPE_PPZ8,   false}, +  {PMD_PART_PPZ_5, PART_TYPE_PPZ8,   false}, +  {PMD_PART_PPZ_6, PART_TYPE_PPZ8,   false}, +  {PMD_PART_PPZ_7, PART_TYPE_PPZ8,   false}, +  {PMD_PART_PPZ_8, PART_TYPE_PPZ8,   false},  };  static void pmd_work_status_update( @@ -5200,6 +5682,8 @@ static void pmd_work_status_update(      case PART_TYPE_ADPCM:        //track->playing = false;        break; +    case PART_TYPE_PPZ8: +      break;      }    }    work->ssg_noise_freq = pmd->ssg_noise_freq_wrote; @@ -5221,6 +5705,7 @@ static void pmd_opna_interrupt(struct fmdriver_work *work) {    pmd_work_status_update(work, pmd);  } +/*  // 0f4d  static void pmd_mstart(    struct fmdriver_work *work, @@ -5242,6 +5727,7 @@ static void pmd_mstart(    // TODO    // 4375??  } +*/  bool pmd_load(struct driver_pmd *pmd,                uint8_t *data, uint16_t datalen) { @@ -5353,6 +5839,8 @@ void pmd_init(struct fmdriver_work *work,    if (pcmfile) {      pmd_filenamecopy(pmd->ppcfile, pcmfile);    } +  fmdriver_fillpcmname(work->pcmname[0], pmd->ppcfile); +  fmdriver_fillpcmname(work->pcmname[1], pmd->ppzfile);  }  enum { @@ -5396,4 +5884,5 @@ bool pmd_ppc_load(    work->opna_writereg(work, 0x110, 0x0c);    work->opna_writereg(work, 0x100, 0x01); +  return true;  } diff --git a/fmdriver/fmdriver_pmd.h b/fmdriver/fmdriver_pmd.h index ba03cda..708dd9e 100644 --- a/fmdriver/fmdriver_pmd.h +++ b/fmdriver/fmdriver_pmd.h @@ -6,6 +6,7 @@ extern "C" {  #endif  #include "fmdriver.h" +#include <stddef.h>  enum {    PMD_FILENAMELEN = 8+1+3  }; @@ -222,6 +223,9 @@ struct pmd_part {    uint8_t note_proc;    // 005b    uint8_t gate_min; +  // 005c +  // for ppz8 +  uint16_t actual_freq_upper;    // 005e    uint8_t curr_note;    // 005f @@ -460,7 +464,7 @@ struct driver_pmd {  bool pmd_load(struct driver_pmd *pmd, uint8_t *data, uint16_t datalen);  void pmd_init(struct fmdriver_work *work, struct driver_pmd *pmd); - +bool pmd_ppc_load(struct fmdriver_work *work, uint8_t *data, size_t datalen);  #ifdef __cplusplus  }  #endif diff --git a/fmdriver/ppz8.c b/fmdriver/ppz8.c index a373d84..7540ca0 100644 --- a/fmdriver/ppz8.c +++ b/fmdriver/ppz8.c @@ -1,6 +1,7 @@  #include "ppz8.h"  #include "fmdriver_common.h"  //#include <stdio.h> +#include <string.h>  void ppz8_init(struct ppz8 *ppz8, uint16_t srate, uint16_t mix_volume) {    for (int i = 0; i < 2; i++) { @@ -69,7 +70,6 @@ static int32_t ppz8_channel_calc(struct ppz8 *ppz8, struct ppz8_channel *channel      out += (int32_t)channel->prevout[0] * (0x10000u - coeff);      out += (int32_t)channel->prevout[1] * coeff;      out >>= 16; -      // volume: out * 2**((volume-15)/2)      out >>= (7 - ((channel->vol&0xf)>>1));      if (!(channel->vol&1)) { @@ -83,7 +83,7 @@ static int32_t ppz8_channel_calc(struct ppz8 *ppz8, struct ppz8_channel *channel    channel->ptr += ptrdiff;    uint32_t bufdiff = (channel->ptr>>16) - (oldptr>>16);    if (bufdiff) { -    if (/*bufdiff == 1*/0) { +    if (bufdiff == 1) {        channel->prevout[0] = channel->prevout[1];        channel->prevout[1] = 0;        channel->ptr = ppz8_loop(channel, channel->ptr); @@ -219,6 +219,33 @@ bool ppz8_pvi_load(struct ppz8 *ppz8, uint8_t bnum,    return true;  } +bool ppz8_pzi_load(struct ppz8 *ppz8, uint8_t bnum, +                   const uint8_t *pzidata, uint32_t pzidatalen, +                   int16_t *decodebuf) { +  if (bnum >= 2) return false; +  if (pzidatalen < (0x20+(18*128))) return false; +  if (memcmp(pzidata, "PZI0", 4) && memcmp(pzidata, "PZI1", 4)) return false; +  struct ppz8_pcmbuf *buf = &ppz8->buf[bnum]; +  for (int i = 0; i < 0x80; i++) { +    struct ppz8_pcmvoice *voice = &buf->voice[i]; +    voice->start = read32le(&pzidata[0x20+18*i+0]) * 2; +    voice->len = read32le(&pzidata[0x20+18*i+4]) * 2; +    voice->loopstart = read32le(&pzidata[0x20+18*i+8]); +    voice->loopend = read32le(&pzidata[0x20+18*i+12]); +    voice->origfreq = read16le(&pzidata[0x20+18*i+16]);/* +    if (voice->origfreq) { +      voice->origfreq = 0x100000000 / voice->origfreq; +    }*/ +    //voice->origfreq = 15974; +  } +  buf->data = decodebuf; +  buf->buflen = pzidatalen - (0x20+(18*128)); +  for (uint32_t i = 0; i < buf->buflen; i++) { +    buf->data[i] = (pzidata[0x20+18*128+i] - 0x80) << 8; +  } +  return true; +} +  static void ppz8_channel_play(struct ppz8 *ppz8, uint8_t ch, uint8_t v) {    if (ch >= 8) return;    struct ppz8_channel *channel = &ppz8->channel[ch]; @@ -285,6 +312,21 @@ static void ppz8_total_volume(struct ppz8 *ppz8, uint8_t vol) {    ppz8->totalvol = vol;  } +static void ppz8_channel_loop_voice(struct ppz8 *ppz8, uint8_t ch, uint8_t v) { +  if (ch >= 8) return; +  struct ppz8_channel *channel = &ppz8->channel[ch]; +  struct ppz8_pcmbuf *buf = &ppz8->buf[v>>7]; +  struct ppz8_pcmvoice *voice = &buf->voice[v & 0x7f]; +  channel->loopstartptr = ((uint64_t)(voice->loopstart)>>1)<<16; +  channel->loopendptr = ((uint64_t)(voice->loopend)>>1)<<16; +} + +static uint32_t ppz8_voice_length(struct ppz8 *ppz8, uint8_t v) { +  struct ppz8_pcmbuf *buf = &ppz8->buf[v>>7]; +  struct ppz8_pcmvoice *voice = &buf->voice[v & 0x7f]; +  return voice->len; +} +  const struct ppz8_functbl ppz8_functbl = {    ppz8_channel_play,    ppz8_channel_stop, @@ -292,5 +334,7 @@ const struct ppz8_functbl ppz8_functbl = {    ppz8_channel_freq,    ppz8_channel_loopoffset,    ppz8_channel_pan, -  ppz8_total_volume +  ppz8_total_volume, +  ppz8_channel_loop_voice, +  ppz8_voice_length  }; diff --git a/fmdriver/ppz8.h b/fmdriver/ppz8.h index 6ced669..cb9a158 100644 --- a/fmdriver/ppz8.h +++ b/fmdriver/ppz8.h @@ -50,11 +50,18 @@ void ppz8_mix(struct ppz8 *ppz8, int16_t *buf, unsigned samples);  bool ppz8_pvi_load(struct ppz8 *ppz8, uint8_t buf,                     const uint8_t *pvidata, uint32_t pvidatalen,                     int16_t *decodebuf); +bool ppz8_pzi_load(struct ppz8 *ppz8, uint8_t bnum, +                   const uint8_t *pzidata, uint32_t pzidatalen, +                   int16_t *decodebuf);  static inline uint32_t ppz8_pvi_decodebuf_samples(uint32_t pvidatalen) {    if (pvidatalen < 0x210) return 0;    return (pvidatalen - 0x210) * 2;  } +static inline uint32_t ppz8_pzi_decodebuf_samples(uint32_t pzidatalen) { +  if (pzidatalen < 0x920) return 0; +  return (pzidatalen - 0x920) * 2; +}  struct ppz8_functbl {    void (*channel_play)(struct ppz8 *ppz8, uint8_t channel, uint8_t voice); @@ -65,6 +72,8 @@ struct ppz8_functbl {                               uint32_t startoff, uint32_t endoff);    void (*channel_pan)(struct ppz8 *ppz8, uint8_t channel, uint8_t pan);    void (*total_volume)(struct ppz8 *ppz8, uint8_t vol); +  void (*channel_loop_voice)(struct ppz8 *ppz8, uint8_t channel, uint8_t voice); +  uint32_t (*voice_length)(struct ppz8 *ppz8, uint8_t voice);  };  extern const struct ppz8_functbl ppz8_functbl; | 
