implement AY/SSG player part
This commit is contained in:
parent
4a3d35e7ec
commit
ad6deb23d2
|
@ -509,6 +509,24 @@ int main(int argc, char* argv[])
|
|||
yy++;
|
||||
|
||||
if ((ch % 3) == 2) {
|
||||
tprintf(0, yy, "AY%d: [%02X %02X] [%02X %02X] [%02X %02X] %02X %02X [%02X %02X %02X] [%02X %02X] <- %02X",
|
||||
cc,
|
||||
opn_reg_view[cc][0],
|
||||
opn_reg_view[cc][1],
|
||||
opn_reg_view[cc][2],
|
||||
opn_reg_view[cc][3],
|
||||
opn_reg_view[cc][4],
|
||||
opn_reg_view[cc][5],
|
||||
opn_reg_view[cc][6],
|
||||
opn_reg_view[cc][7],
|
||||
opn_reg_view[cc][8],
|
||||
opn_reg_view[cc][9],
|
||||
opn_reg_view[cc][10],
|
||||
opn_reg_view[cc][11],
|
||||
opn_reg_view[cc][12],
|
||||
opn_reg_view[cc][13]
|
||||
);
|
||||
yy++;
|
||||
tprintf(0, yy, "EC%d: [%02X %02X %02X %02X %02X %02X %02X %02X]",
|
||||
cc,
|
||||
opn_reg_view[cc][0xAD],
|
||||
|
@ -521,6 +539,7 @@ int main(int argc, char* argv[])
|
|||
opn_reg_view[cc][0xA2]
|
||||
);
|
||||
yy++;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -206,6 +206,81 @@ extern "C" {
|
|||
bool doNextOp;
|
||||
}
|
||||
|
||||
// AY channel stream
|
||||
const uint8_t* opmplay_parse_ay_channel_stream(opmplay_context_t* ctx, opmplay_channel_context_t* chctx, int ch, const uint8_t* data) {
|
||||
if ((*(data) & 0x80) == OPM_AYTONE_REGS) {
|
||||
// volume and period low
|
||||
int mask = *data;
|
||||
data++;
|
||||
opn_write_reg(chip_index, 8 + ch, (mask & OPM_AYTONE_CMD00_VOLUME_MASK));
|
||||
if (mask & OPM_AYTONE_CMD00_PERIOD_LOW) opn_write_reg(chip_index, 0 + (ch<<1), *data++);
|
||||
if (mask & OPM_AYTONE_CMD00_EOF) endOfFrame = true;
|
||||
doNextOp = true;
|
||||
goto done;
|
||||
}
|
||||
if ((*(data) & 0xC0) == OPM_AYTONE_PERIOD) {
|
||||
// period high/low
|
||||
int mask = *data;
|
||||
data++;
|
||||
opn_write_reg(chip_index, 1 + (ch<<1), (mask & OPM_AYTONE_CMD80_PERIOD_HIGH));
|
||||
if (mask & OPM_AYTONE_CMD80_PERIOD_LOW) opn_write_reg(chip_index, 0 + (ch << 1), *data++);
|
||||
if (mask & OPM_AYTONE_CMD80_EOF) endOfFrame = true;
|
||||
doNextOp = true;
|
||||
goto done;
|
||||
}
|
||||
if ((*(data) & 0xF8) == OPM_AYTONE_MASK) {
|
||||
const static uint8_t mask_lookup[4] = {(0<<3)|(0<<0), (0<<3)|(1<<0), (1<<3)|(0<<0), (1<<3)|(1<<0)};
|
||||
|
||||
// mask
|
||||
int mask = *data;
|
||||
data++;
|
||||
ctx->ssg_r7[chip_index] &= ~(((1 << 3) | (1 << 0)) << ch);
|
||||
ctx->ssg_r7[chip_index] |= (mask_lookup[mask & 3] << ch);
|
||||
if (mask & OPM_AYTONE_MASK_EOF) endOfFrame = true;
|
||||
doNextOp = true;
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
return data;
|
||||
}
|
||||
|
||||
// AY noise/envelope stream
|
||||
const uint8_t* opmplay_parse_ay_envnoise_stream(opmplay_context_t* ctx, opmplay_channel_context_t* chctx, int ch, const uint8_t* data) {
|
||||
if ((*(data) & 0x80) == OPM_AYENV_REGS) {
|
||||
// noise and period low
|
||||
int mask = *data;
|
||||
data++;
|
||||
opn_write_reg(chip_index, 6, (mask & OPM_AYENV_CMD00_NOISE_MASK));
|
||||
if (mask & OPM_AYENV_CMD00_PERIOD_LOW) opn_write_reg(chip_index, 11, *data++);
|
||||
if (mask & OPM_AYENV_CMD00_EOF) endOfFrame = true;
|
||||
doNextOp = true;
|
||||
goto done;
|
||||
}
|
||||
if ((*(data) & 0xC0) == OPM_AYENV_ENVTYPE) {
|
||||
// envelope type (and retrig)
|
||||
int mask = *data;
|
||||
data++;
|
||||
opn_write_reg(chip_index, 13, (mask & OPM_AYENV_CMD80_ENV_TYPE));
|
||||
if (mask & OPM_AYENV_CMD80_PERIOD_LOW) opn_write_reg(chip_index, 11, *data++);
|
||||
if (mask & OPM_AYENV_CMD80_EOF) endOfFrame = true;
|
||||
doNextOp = true;
|
||||
goto done;
|
||||
}
|
||||
if ((*(data) & 0xF8) == OPM_AYENV_PERIOD_FULL) {
|
||||
// mask
|
||||
int mask = *data;
|
||||
data++;
|
||||
if (mask & OPM_AYENV_CMDF0_PERIOD_LOW) opn_write_reg(chip_index, 11, *data++);
|
||||
if (mask & OPM_AYENV_CMDF0_PERIOD_HIGH) opn_write_reg(chip_index, 12, *data++);
|
||||
if (mask & OPM_AYENV_CMDF0_EOF) endOfFrame = true;
|
||||
doNextOp = true;
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
// FM control stream
|
||||
const uint8_t* opmplay_parse_fm_control_stream(opmplay_context_t* ctx, opmplay_channel_context_t* chctx, int ch, const uint8_t* data) {
|
||||
if ((*(data) & 0xE0) == OPM_CTRL_TIMER_CSM) {
|
||||
|
@ -225,34 +300,25 @@ const uint8_t* opmplay_parse_fm_control_stream(opmplay_context_t* ctx, opmplay_c
|
|||
// OP4 freq is handled by FM channel 3 stream
|
||||
int mask = *data;
|
||||
data++;
|
||||
if (mask & OPM_CTRL_EXTCH3_OP1_HIGH) opn_write_reg(chip_index, 0xAD, *data++);
|
||||
if (mask & OPM_CTRL_EXTCH3_OP1_LOW) opn_write_reg(chip_index, 0xA9, *data++);
|
||||
if (mask & OPM_CTRL_EXTCH3_OP2_HIGH) opn_write_reg(chip_index, 0xAC, *data++);
|
||||
if (mask & OPM_CTRL_EXTCH3_OP2_LOW) opn_write_reg(chip_index, 0xA8, *data++);
|
||||
if (mask & OPM_CTRL_EXTCH3_OP3_HIGH) opn_write_reg(chip_index, 0xAE, *data++);
|
||||
if (mask & OPM_CTRL_EXTCH3_OP3_LOW) opn_write_reg(chip_index, 0xAA, *data++);
|
||||
if (mask & OPM_CTRL_EXTCH3_OP1_HIGH) ctx->extch3_block[chip_index][0] = *data++;
|
||||
if (mask & OPM_CTRL_EXTCH3_OP1_LOW) {
|
||||
opn_write_reg(chip_index, 0xAD, ctx->extch3_block[chip_index][0]);
|
||||
opn_write_reg(chip_index, 0xA9, *data++);
|
||||
}
|
||||
if (mask & OPM_CTRL_EXTCH3_OP2_HIGH) ctx->extch3_block[chip_index][1] = *data++;
|
||||
if (mask & OPM_CTRL_EXTCH3_OP2_LOW) {
|
||||
opn_write_reg(chip_index, 0xAC, ctx->extch3_block[chip_index][1]);
|
||||
opn_write_reg(chip_index, 0xA8, *data++);
|
||||
}
|
||||
if (mask & OPM_CTRL_EXTCH3_OP3_HIGH) ctx->extch3_block[chip_index][2] = *data++;
|
||||
if (mask & OPM_CTRL_EXTCH3_OP3_LOW) {
|
||||
opn_write_reg(chip_index, 0xAE, ctx->extch3_block[chip_index][2]);
|
||||
opn_write_reg(chip_index, 0xAA, *data++);
|
||||
}
|
||||
if (mask & OPM_CTRL_EXTCH3_EOF) endOfFrame = true;
|
||||
doNextOp = true;
|
||||
goto done;
|
||||
}
|
||||
if ((*data & 0xF0) == OPM_STREAM_BACKREF) {
|
||||
// back reference, nested call :)
|
||||
int distance = ((*(data + 0) & 0x0F) << 8) | (*(data + 1));
|
||||
int frames_to_play = *(data + 2);
|
||||
chctx->stream.ptr = data + 3;
|
||||
opmplay_push_stack(chctx);
|
||||
data -= distance;
|
||||
chctx->stream.samples_to_play = frames_to_play; // hack?
|
||||
doNextOp = true;
|
||||
goto done;
|
||||
}
|
||||
if ((*data) == OPM_STREAM_END) {
|
||||
// rewind to start
|
||||
chctx->stream.reload = -1;
|
||||
endOfFrame = true;
|
||||
doNextOp = true;
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
return data;
|
||||
}
|
||||
|
@ -287,8 +353,11 @@ const uint8_t* opmplay_parse_fm_channel_stream(opmplay_context_t* ctx, opmplay_c
|
|||
// frequency/feedpack
|
||||
int mask = *data;
|
||||
data++;
|
||||
if (mask & OPM_FM_CMD80_REGA4) opn_write_reg(chip_index, 0xA4 + ch, *data++);
|
||||
if (mask & OPM_FM_CMD80_REGA0) opn_write_reg(chip_index, 0xA0 + ch, *data++);
|
||||
if (mask & OPM_FM_CMD80_REGA4) chctx->block = *data++;
|
||||
if (mask & OPM_FM_CMD80_REGA0) {
|
||||
opn_write_reg(chip_index, 0xA4 + ch, chctx->block);
|
||||
opn_write_reg(chip_index, 0xA0 + ch, *data++);
|
||||
}
|
||||
if (mask & OPM_FM_CMD80_REGB0) opn_write_reg(chip_index, 0xB0 + ch, *data++);
|
||||
if (mask & OPM_FM_CMD80_REGB4) opn_write_reg(chip_index, 0xB4 + ch, *data++);
|
||||
if (mask & OPM_FM_CMD80_EOF) endOfFrame = true;
|
||||
|
@ -303,25 +372,6 @@ const uint8_t* opmplay_parse_fm_channel_stream(opmplay_context_t* ctx, opmplay_c
|
|||
doNextOp = true;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((*data & 0xF0) == OPM_STREAM_BACKREF) {
|
||||
// back reference, nested call :)
|
||||
int distance = ((*(data + 0) & 0x0F) << 8) | (*(data + 1));
|
||||
int frames_to_play = *(data + 2);
|
||||
chctx->stream.ptr = data + 3;
|
||||
opmplay_push_stack(chctx);
|
||||
data -= distance;
|
||||
chctx->stream.samples_to_play = frames_to_play; // hack?
|
||||
doNextOp = true;
|
||||
goto done;
|
||||
}
|
||||
if ((*data) == OPM_STREAM_END) {
|
||||
// rewind to start
|
||||
chctx->stream.reload = -1;
|
||||
endOfFrame = true;
|
||||
doNextOp = true;
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
return data;
|
||||
}
|
||||
|
@ -343,6 +393,17 @@ const int opmplay_parse_stream(opmplay_context_t* ctx, opmplay_channel_context_t
|
|||
continue;
|
||||
}
|
||||
|
||||
if ((*data & 0xF0) == OPM_STREAM_BACKREF) {
|
||||
// back reference, nested call :)
|
||||
int distance = ((*(data + 0) & 0x0F) << 8) | (*(data + 1));
|
||||
int frames_to_play = *(data + 2);
|
||||
chctx->stream.ptr = data + 3;
|
||||
opmplay_push_stack(chctx);
|
||||
data -= distance;
|
||||
chctx->stream.samples_to_play = frames_to_play; // hack?
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for common stuff
|
||||
switch (*data) {
|
||||
// just an NOP, break
|
||||
|
@ -356,6 +417,11 @@ const int opmplay_parse_stream(opmplay_context_t* ctx, opmplay_channel_context_t
|
|||
chctx->stream.loop = data;
|
||||
data++;
|
||||
break;
|
||||
case OPM_STREAM_END:
|
||||
// rewind to start
|
||||
chctx->stream.reload = -1;
|
||||
endOfFrame = true;
|
||||
break;
|
||||
// set new frame rate
|
||||
case OPM_STREAM_SET_FRAME_RATE:
|
||||
ctx->header.frame_rate = *(uint16_t*)(data + 1); data += 3;
|
||||
|
@ -404,12 +470,25 @@ int opmplay_tick(opmplay_context_t* ctx) {
|
|||
opmplay_parse_stream(ctx, ctx->channels + 1, 0, opmplay_parse_fm_channel_stream);
|
||||
opmplay_parse_stream(ctx, ctx->channels + 2, 1, opmplay_parse_fm_channel_stream);
|
||||
opmplay_parse_stream(ctx, ctx->channels + 3, 2, opmplay_parse_fm_channel_stream);
|
||||
|
||||
opmplay_parse_stream(ctx, ctx->channels + 4, 0, opmplay_parse_ay_channel_stream);
|
||||
opmplay_parse_stream(ctx, ctx->channels + 5, 1, opmplay_parse_ay_channel_stream);
|
||||
opmplay_parse_stream(ctx, ctx->channels + 6, 2, opmplay_parse_ay_channel_stream);
|
||||
opmplay_parse_stream(ctx, ctx->channels + 7, 0, opmplay_parse_ay_envnoise_stream);
|
||||
opn_write_reg(chip_index, 7, ctx->ssg_r7[chip_index]);
|
||||
|
||||
chip_index = 1;
|
||||
opmplay_parse_stream(ctx, ctx->channels + 8, 0, opmplay_parse_fm_control_stream);
|
||||
opmplay_parse_stream(ctx, ctx->channels + 9, 0, opmplay_parse_fm_channel_stream);
|
||||
opmplay_parse_stream(ctx, ctx->channels + 10, 1, opmplay_parse_fm_channel_stream);
|
||||
opmplay_parse_stream(ctx, ctx->channels + 11, 2, opmplay_parse_fm_channel_stream);
|
||||
|
||||
opmplay_parse_stream(ctx, ctx->channels + 12, 0, opmplay_parse_ay_channel_stream);
|
||||
opmplay_parse_stream(ctx, ctx->channels + 13, 1, opmplay_parse_ay_channel_stream);
|
||||
opmplay_parse_stream(ctx, ctx->channels + 14, 2, opmplay_parse_ay_channel_stream);
|
||||
opmplay_parse_stream(ctx, ctx->channels + 15, 0, opmplay_parse_ay_envnoise_stream);
|
||||
opn_write_reg(chip_index, 7, ctx->ssg_r7[chip_index]);
|
||||
|
||||
// advance frame counter
|
||||
ctx->pos.frame++;
|
||||
|
||||
|
|
|
@ -88,6 +88,9 @@ struct opmplay_channel_context_t {
|
|||
const uint8_t* ptr;
|
||||
const uint8_t* loop; // if active
|
||||
} stream;
|
||||
|
||||
// private stuff
|
||||
uint8_t block; // cached block register
|
||||
};
|
||||
|
||||
struct opmplay_context_t {
|
||||
|
@ -103,6 +106,10 @@ struct opmplay_context_t {
|
|||
uint16_t frame_looped;
|
||||
uint32_t samples;
|
||||
} pos;
|
||||
|
||||
// private stuff
|
||||
uint8_t ssg_r7[2]; // cached SSG mask register
|
||||
uint8_t extch3_block[2][3]; // cached extch3 block
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ enum {
|
|||
OPM_AYTONE_CMD00_PERIOD_LOW = (1 << 5),
|
||||
OPM_AYTONE_CMD00_EOF = (1 << 6),
|
||||
|
||||
OPM_AYTONE_CMD80_PERIOD_HIGH = (0xF << 0),
|
||||
OPM_AYTONE_CMD80_PERIOD_HIGH_MASK = (0xF << 0),
|
||||
OPM_AYTONE_CMD80_PERIOD_LOW = (1 << 4),
|
||||
OPM_AYTONE_CMD80_EOF = (1 << 5),
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ int opm_requantize(opm_convert_context_t* ctx) {
|
|||
oplchans[channel].data.push_back((data >> ch) & ((1 << 0)|(1 << 3)));
|
||||
}
|
||||
break;
|
||||
case 5: case 11: case 12: case 13:
|
||||
case 6: case 11: case 12: case 13:
|
||||
// noise and envelope stuff
|
||||
channel = chip_chidx + ctx->ssg_chidx + 3;
|
||||
oplchans[channel].frame = currentFrame;
|
||||
|
@ -1055,7 +1055,7 @@ int opm_serialize_ssg_tone_stream(opm_channel_t* chctx) {
|
|||
OPM_AYTONE_PERIOD |
|
||||
((ef == 0) && (i == s.records.size() - 1) ? OPM_AYTONE_CMD80_EOF : 0) |
|
||||
(ef_cur & OPM_REC_AYTONE_PERIOD_LOW ? OPM_AYTONE_CMD80_PERIOD_LOW : 0) |
|
||||
(e.aytone.period_hi & OPM_AYTONE_CMD80_PERIOD_HIGH)
|
||||
(e.aytone.period_hi & OPM_AYTONE_CMD80_PERIOD_HIGH_MASK)
|
||||
);
|
||||
if (ef_cur & OPM_REC_AYTONE_PERIOD_LOW) s.rawdata.push_back(e.aytone.period_low);
|
||||
}
|
||||
|
@ -1076,11 +1076,11 @@ int opm_serialize_ssg_tone_stream(opm_channel_t* chctx) {
|
|||
|
||||
if (ef & OPM_REC_AYTONE_MASK) {
|
||||
// write mask at last
|
||||
ef & ~OPM_REC_AYTONE_MASK;
|
||||
ef &= ~OPM_REC_AYTONE_MASK;
|
||||
// write registers
|
||||
s.rawdata.push_back(
|
||||
OPM_AYTONE_REGS |
|
||||
((ef == 0) && (i == s.records.size() - 1) ? OPM_AYTONE_CMD00_EOF : 0) |
|
||||
OPM_AYTONE_MASK |
|
||||
((ef == 0) && (i == s.records.size() - 1) ? OPM_AYTONE_MASK_EOF : 0) |
|
||||
(e.aytone.mask & 1 ? OPM_AYTONE_MASK_TONE : 0) |
|
||||
(e.aytone.mask & 8 ? OPM_AYTONE_MASK_NOISE : 0)
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue