aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakamichi Horikawa <takamichiho@gmail.com>2017-04-03 22:19:14 +0900
committerTakamichi Horikawa <takamichiho@gmail.com>2017-04-03 22:19:49 +0900
commitfd698bc65313888c689877128d4b489c64f2e85f (patch)
tree0ad39ba217b1b43ffa1156f7ab81fcb6b186b9aa
parent4e4ba88b67cc9e891a69d65bbde460e1ba51a39e (diff)
pmd: fix PPZ8 loop
-rw-r--r--fmdriver/fmdriver_common.c32
-rw-r--r--fmdriver/fmdriver_common.h1
-rw-r--r--fmdriver/fmdriver_pmd.c45
-rw-r--r--fmdriver/fmdriver_pmd.h2
-rw-r--r--fmdriver/ppz8.c13
-rw-r--r--fmdriver/ppz8.h4
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);