aboutsummaryrefslogtreecommitdiff
path: root/libopna
diff options
context:
space:
mode:
Diffstat (limited to 'libopna')
-rw-r--r--libopna/opnafm.c95
-rw-r--r--libopna/opnafm.h3
2 files changed, 82 insertions, 16 deletions
diff --git a/libopna/opnafm.c b/libopna/opnafm.c
index 437fcdc..3f5367f 100644
--- a/libopna/opnafm.c
+++ b/libopna/opnafm.c
@@ -2,6 +2,13 @@
#include "opnatables.h"
+#define LIBOPNA_ENABLE_HIRES_SIN
+#define LIBOPNA_ENABLE_HIRES_ENV
+
+enum {
+ ENV_MAX_HIRES = LIBOPNA_FM_ENV_MAX * 4
+};
+
enum {
CH3_MODE_NORMAL = 0,
CH3_MODE_CSM = 1,
@@ -10,7 +17,8 @@ enum {
static void opna_fm_slot_reset(struct opna_fm_slot *slot) {
slot->phase = 0;
- slot->env = 1023;
+ slot->env = LIBOPNA_FM_ENV_MAX;
+ slot->env_hires = ENV_MAX_HIRES;
slot->env_count = 0;
slot->env_state = ENV_RELEASE;
slot->rate_shifter = 0;
@@ -60,9 +68,18 @@ void opna_fm_reset(struct opna_fm *fm) {
}
fm->mask = 0;
}
-#define LIBOPNA_ENABLE_HIRES
// maximum output: 2042<<2 = 8168
static int16_t opna_fm_slotout(struct opna_fm_slot *slot, int16_t modulation) {
+#ifdef LIBOPNA_ENABLE_HIRES_SIN
+ unsigned pind_hires = (slot->phase >> 8);
+ pind_hires += modulation << 1;
+ bool minus = pind_hires & (1<<(LOGSINTABLEHIRESBIT+1));
+ bool reverse = pind_hires & (1<<LOGSINTABLEHIRESBIT);
+ if (reverse) pind_hires = ~pind_hires;
+ pind_hires &= (1<<LOGSINTABLEHIRESBIT)-1;
+
+ int logout = logsintable_hires[pind_hires];
+#else
unsigned pind = (slot->phase >> 10);
pind += modulation >> 1;
bool minus = pind & (1<<(LOGSINTABLEBIT+1));
@@ -70,18 +87,14 @@ static int16_t opna_fm_slotout(struct opna_fm_slot *slot, int16_t modulation) {
if (reverse) pind = ~pind;
pind &= (1<<LOGSINTABLEBIT)-1;
-#ifdef LIBOPNA_ENABLE_HIRES
- unsigned pind_hires = (slot->phase >> 8);
- pind_hires += modulation << 1;
- minus = pind_hires & (1<<(LOGSINTABLEHIRESBIT+1));
- reverse = pind_hires & (1<<LOGSINTABLEHIRESBIT);
- if (reverse) pind_hires = ~pind_hires;
- pind_hires &= (1<<LOGSINTABLEHIRESBIT)-1;
-
- int logout = logsintable_hires[pind_hires] + (slot->env << 2) + (slot->tl << 5);
+ int logout = logsintable[pind];
+#endif // LIBOPNA_ENABLE_HIRES_SIN
+#ifdef LIBOPNA_ENABLE_HIRES_ENV
+ logout += slot->env_hires;
#else
- int logout = logsintable[pind] + (slot->env << 2) + (slot->tl << 5);
-#endif // LIBOPNA_ENABLE_HIRES
+ logout += (slot->env << 2);
+#endif
+ logout += (slot->tl << 5);
int selector = logout & ((1<<EXPTABLEBIT)-1);
int shifter = logout >> EXPTABLEBIT;
@@ -226,6 +239,9 @@ static void opna_fm_slot_setrate(struct opna_fm_slot *slot, int status) {
int rate = 2*r + (slot->keycode >> (3 - slot->ks));
if (rate > 63) rate = 63;
+#ifdef LIBOPNA_ENABLE_HIRES_ENV
+ rate += 8;
+#endif
int rate_shifter = 11 - (rate >> 2);
if (rate_shifter < 0) {
slot->rate_selector = (rate & ((1<<2)-1)) + 4;
@@ -245,10 +261,56 @@ static void opna_fm_slot_env(struct opna_fm_slot *slot) {
int env_inc = rateinctable[slot->rate_selector][rate_index];
env_inc *= slot->rate_mul;
+#ifdef LIBOPNA_ENABLE_HIRES_ENV
switch (slot->env_state) {
int newenv;
int sl;
case ENV_ATTACK:
+ newenv = slot->env_hires + (((-slot->env_hires-1) * env_inc) >> 6);
+ if (newenv <= 0) {
+ slot->env_hires = 0;
+ slot->env_state = ENV_DECAY;
+ opna_fm_slot_setrate(slot, ENV_DECAY);
+ } else {
+ slot->env_hires = newenv;
+ }
+ break;
+ case ENV_DECAY:
+ slot->env_hires += env_inc;
+ sl = slot->sl;
+ if (sl == 0xf) sl = 0x1f;
+ if (slot->env_hires >= (sl << 7)) {
+ slot->env_state = ENV_SUSTAIN;
+ opna_fm_slot_setrate(slot, ENV_SUSTAIN);
+ }
+ break;
+ case ENV_SUSTAIN:
+ slot->env_hires += env_inc;
+ if (slot->env_hires >= ENV_MAX_HIRES) slot->env_hires = ENV_MAX_HIRES;
+ break;
+ case ENV_RELEASE:
+ slot->env_hires += env_inc;
+ if (slot->env_hires >= ENV_MAX_HIRES) {
+ slot->env_hires = ENV_MAX_HIRES;
+ slot->env_state = ENV_OFF;
+ }
+ break;
+ }
+ slot->env = slot->env_hires >> 2;
+#else // LIBOPNA_ENABLE_HIRES_ENV
+ switch (slot->env_state) {
+ int newenv;
+ int sl;
+ case ENV_ATTACK:
+ newenv = slot->env_hires + (((-slot->env-1) * env_inc) >> 6);
+ if (newenv <= 0) {
+ slot->env = 0;
+ slot->env_hires = 0;
+ slot->env_state = ENV_DECAY;
+ opna_fm_slot_setrate(slot, ENV_DECAY);
+ } else {
+ slot->env_hires = newenv;
+ }
newenv = slot->env + (((-slot->env-1) * env_inc) >> 4);
if (newenv <= 0) {
slot->env = 0;
@@ -269,16 +331,17 @@ static void opna_fm_slot_env(struct opna_fm_slot *slot) {
break;
case ENV_SUSTAIN:
slot->env += env_inc;
- if (slot->env >= 1023) slot->env = 1023;
+ if (slot->env >= LIBOPNA_FM_ENV_MAX) slot->env = LIBOPNA_FM_ENV_MAX;
break;
case ENV_RELEASE:
slot->env += env_inc;
- if (slot->env >= 1023) {
- slot->env = 1023;
+ if (slot->env >= LIBOPNA_FM_ENV_MAX) {
+ slot->env = LIBOPNA_FM_ENV_MAX;
slot->env_state = ENV_OFF;
}
break;
}
+#endif
}
}
diff --git a/libopna/opnafm.h b/libopna/opnafm.h
index cf4fff5..1a7f55a 100644
--- a/libopna/opnafm.h
+++ b/libopna/opnafm.h
@@ -8,6 +8,7 @@
extern "C" {
#endif
+#define LIBOPNA_FM_ENV_MAX 1023
enum {
ENV_ATTACK,
ENV_DECAY,
@@ -21,6 +22,8 @@ struct opna_fm_slot {
uint32_t phase;
// 10 bits
uint16_t env;
+ // 12 bits
+ uint16_t env_hires;
uint16_t env_count;
uint8_t env_state;
uint8_t rate_shifter;