aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fmdriver/fmdriver.h35
-rw-r--r--fmdriver/fmdriver_fmp.c99
-rw-r--r--fmdriver/fmdriver_fmp.h30
-rw-r--r--fmdriver/ppz8.c2
-rw-r--r--fmdsp/fmdsp.c334
-rw-r--r--fmdsp/fmdsp.h16
-rw-r--r--gtk/main.c111
-rw-r--r--libopna/opna.c13
-rw-r--r--libopna/opna.h24
-rw-r--r--libopna/opnaadpcm.c22
-rw-r--r--libopna/opnaadpcm.h1
-rw-r--r--libopna/opnadrum.c7
-rw-r--r--libopna/opnadrum.h1
-rw-r--r--libopna/opnafm.c2
-rw-r--r--libopna/opnafm.h4
-rw-r--r--libopna/opnassg.c2
-rw-r--r--libopna/opnassg.h1
-rw-r--r--win32/main.c2
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
diff --git a/gtk/main.c b/gtk/main.c
index 9f660e6..9e2e989 100644
--- a/gtk/main.c
+++ b/gtk/main.c
@@ -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) {