diff options
author | Takamichi Horikawa <takamichiho@gmail.com> | 2017-04-03 22:19:14 +0900 |
---|---|---|
committer | Takamichi Horikawa <takamichiho@gmail.com> | 2017-04-03 22:19:49 +0900 |
commit | fd698bc65313888c689877128d4b489c64f2e85f (patch) | |
tree | 0ad39ba217b1b43ffa1156f7ab81fcb6b186b9aa | |
parent | 4e4ba88b67cc9e891a69d65bbde460e1ba51a39e (diff) |
pmd: fix PPZ8 loop
-rw-r--r-- | fmdriver/fmdriver_common.c | 32 | ||||
-rw-r--r-- | fmdriver/fmdriver_common.h | 1 | ||||
-rw-r--r-- | fmdriver/fmdriver_pmd.c | 45 | ||||
-rw-r--r-- | fmdriver/fmdriver_pmd.h | 2 | ||||
-rw-r--r-- | fmdriver/ppz8.c | 13 | ||||
-rw-r--r-- | fmdriver/ppz8.h | 4 |
6 files changed, 91 insertions, 6 deletions
diff --git a/fmdriver/fmdriver_common.c b/fmdriver/fmdriver_common.c index 26e6def..b919c3a 100644 --- a/fmdriver/fmdriver_common.c +++ b/fmdriver/fmdriver_common.c @@ -69,3 +69,35 @@ uint8_t fmdriver_ssg_freq2key(uint16_t freq) { if (octave > 8) return 0x8b; return (octave << 4) | note; } + +uint8_t fmdriver_ppz8_freq2key(uint32_t freq) { + if (!freq) return 0x00; + int octave = 16+4; + while (!(freq & 0x80000000u)) { + freq <<= 1; + octave--; + } + if (octave < 0) return 0x00; + if (octave > 8) return 0x8b; + // round(0x8000*(2**((i+0.5)/12))) + static const uint16_t freqtab[0xc] = { + 0x83c0, + 0x8b96, + 0x93e3, + 0x9cae, + 0xa5ff, + 0xafde, + 0xba53, + 0xc567, + 0xd124, + 0xdd94, + 0xeac1, + 0xf8b6 + }; + uint16_t freqhigh = freq >> 16; + int note = 0; + for (; note < 12; note++) { + if (freqhigh < freqtab[note]) break; + } + return (octave << 4) | note; +} diff --git a/fmdriver/fmdriver_common.h b/fmdriver/fmdriver_common.h index 30cf12c..99679cb 100644 --- a/fmdriver/fmdriver_common.h +++ b/fmdriver/fmdriver_common.h @@ -35,6 +35,7 @@ static inline void fmdriver_fillpcmname(char *dest, const char *src) { uint8_t fmdriver_fm_freq2key(uint16_t freq); uint8_t fmdriver_ssg_freq2key(uint16_t freq); +uint8_t fmdriver_ppz8_freq2key(uint32_t freq); #if 0 #include <stdio.h> diff --git a/fmdriver/fmdriver_pmd.c b/fmdriver/fmdriver_pmd.c index 09630bf..7090fc8 100644 --- a/fmdriver/fmdriver_pmd.c +++ b/fmdriver/fmdriver_pmd.c @@ -45,6 +45,41 @@ enum { // 0790: PPZ8 +static uint8_t pmd_adpcm_freq2key(uint16_t freq) { + if (!freq) return 0x00; + static const uint16_t freqtab[12] = { + 0x8738, // e upper limit + 0x8f42, + 0x97c7, + 0xa0cd, + 0xaa5d, + 0xb47e, + 0xbf3a, + 0xca99, + 0xd6a5, + 0xe369, + 0xf0ee, + 0xff42, + }; + int octave = 5; + while (!(freq & 0x8000u)) { + freq <<= 1; + octave -= 1; + } + int key = 0; + for (; key < 12; key++) { + if (freq < freqtab[key]) break; + } + key += 5; + if (key >= 12) { + key -= 12; + octave++; + } + if (octave < 0) return 0x00; + if (octave > 8) return 0x8b; + return (octave << 4) | key; +} + // 33f7: write standard // 341f: write extended // 3447 @@ -1299,6 +1334,7 @@ static void pmd_note_freq_adpcm( static const uint16_t adpcm_tonetable[0x10] = { // 0788 // ??? + // different from round((16000*2*0x10000/(8000000/144))*(2**((i-7)/12))) 0x6264, 0x6840, 0x6e74, @@ -1306,7 +1342,7 @@ static void pmd_note_freq_adpcm( 0x7bfc, 0x835e, 0x8b2e, - 0x9376, + 0x9376,// g 0x9c3c, 0xa588, 0xaf62, @@ -1783,6 +1819,7 @@ static void pmd_adpcm_freq_out( if (newfreq > 0xffff) newfreq = 0xffff; if (newfreq < 0) newfreq = 0; freq = newfreq; + part->output_freq = freq; work->opna_writereg(work, 0x109, freq); work->opna_writereg(work, 0x10a, freq >> 8); } @@ -1809,6 +1846,7 @@ static void pmd_ppz8_freq_out( int64_t outfreq = freq + det; if (outfreq < 0) outfreq = 0; if (outfreq > INT32_MAX) outfreq = INT32_MAX; + part->output_freq = outfreq; if (work->ppz8) { work->ppz8_functbl->channel_freq(work->ppz8, pmd->proc_ch, outfreq); } @@ -5680,9 +5718,12 @@ static void pmd_work_status_update( } break; case PART_TYPE_ADPCM: - //track->playing = false; + track->actual_key = ((track->key & 0xf) == 0xf) ? + 0xff : pmd_adpcm_freq2key(part->output_freq); break; case PART_TYPE_PPZ8: + track->actual_key = ((track->key & 0xf) == 0xf) ? + 0xff : fmdriver_ppz8_freq2key(part->output_freq); break; } } diff --git a/fmdriver/fmdriver_pmd.h b/fmdriver/fmdriver_pmd.h index 708dd9e..25d42d7 100644 --- a/fmdriver/fmdriver_pmd.h +++ b/fmdriver/fmdriver_pmd.h @@ -238,7 +238,7 @@ struct pmd_part { bool proc_masked; // for display uint8_t len; - uint16_t output_freq; + uint32_t output_freq; }; struct pmd_ssgeff_data { diff --git a/fmdriver/ppz8.c b/fmdriver/ppz8.c index 7540ca0..4dea524 100644 --- a/fmdriver/ppz8.c +++ b/fmdriver/ppz8.c @@ -1,8 +1,14 @@ #include "ppz8.h" #include "fmdriver_common.h" -//#include <stdio.h> #include <string.h> +unsigned ppz8_get_mask(const struct ppz8 *ppz8) { + return ppz8->mask; +} +void ppz8_set_mask(struct ppz8 *ppz8, unsigned mask) { + ppz8->mask = mask & 0xffu; +} + void ppz8_init(struct ppz8 *ppz8, uint16_t srate, uint16_t mix_volume) { for (int i = 0; i < 2; i++) { struct ppz8_pcmbuf *buf = &ppz8->buf[i]; @@ -143,6 +149,7 @@ void ppz8_mix(struct ppz8 *ppz8, int16_t *buf, unsigned samples) { struct ppz8_channel *channel = &ppz8->channel[p]; if (!channel->playing) continue; int32_t out = ppz8_channel_calc(ppz8, channel); + if ((1u << p) & (ppz8->mask)) continue; out *= ppz8->mix_volume; out >>= 15; lo += (out * pan_vol[channel->pan][0]) >> 2; @@ -317,8 +324,8 @@ static void ppz8_channel_loop_voice(struct ppz8 *ppz8, uint8_t ch, uint8_t v) { 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; + channel->loopstartoff = voice->loopstart; + channel->loopendoff = voice->loopend; } static uint32_t ppz8_voice_length(struct ppz8 *ppz8, uint8_t v) { diff --git a/fmdriver/ppz8.h b/fmdriver/ppz8.h index cb9a158..f4ef4cb 100644 --- a/fmdriver/ppz8.h +++ b/fmdriver/ppz8.h @@ -43,6 +43,7 @@ struct ppz8 { uint16_t srate; uint8_t totalvol; uint16_t mix_volume; + unsigned mask; }; void ppz8_init(struct ppz8 *ppz8, uint16_t srate, uint16_t mix_volume); @@ -63,6 +64,9 @@ static inline uint32_t ppz8_pzi_decodebuf_samples(uint32_t pzidatalen) { return (pzidatalen - 0x920) * 2; } +unsigned ppz8_get_mask(const struct ppz8 *ppz8); +void ppz8_set_mask(struct ppz8 *ppz8, unsigned mask); + struct ppz8_functbl { void (*channel_play)(struct ppz8 *ppz8, uint8_t channel, uint8_t voice); void (*channel_stop)(struct ppz8 *ppz8, uint8_t channel); |