From d78900cd1497441d7712805b08072e46ee361ff8 Mon Sep 17 00:00:00 2001 From: Takamichi Horikawa Date: Sun, 19 Feb 2017 17:25:56 +0900 Subject: add opna status display --- fmdriver/fmdriver.h | 35 ++++- fmdriver/fmdriver_fmp.c | 99 +++++++------- fmdriver/fmdriver_fmp.h | 30 ++--- fmdriver/ppz8.c | 2 + fmdsp/fmdsp.c | 334 +++++++++++++++++++++++++++++++++++++++++------- fmdsp/fmdsp.h | 16 ++- gtk/main.c | 111 +++++++++++++--- libopna/opna.c | 13 ++ libopna/opna.h | 24 +++- libopna/opnaadpcm.c | 22 ++-- libopna/opnaadpcm.h | 1 + libopna/opnadrum.c | 7 +- libopna/opnadrum.h | 1 + libopna/opnafm.c | 2 + libopna/opnafm.h | 4 + libopna/opnassg.c | 2 + libopna/opnassg.h | 1 + win32/main.c | 2 +- 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 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 +#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 +#include #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<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<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<