implement 80/A0/B0 events
This commit is contained in:
parent
e1c50c9de0
commit
cafc4a011b
|
@ -1,107 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
|
|
||||||
struct lxm_header_stream_desc_t {
|
|
||||||
uint32_t ptr; // offset to data stream
|
|
||||||
uint32_t size; // stream data size in bytes
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
LXM_HEADER_LOG_VOLUME = (1 << 0),
|
|
||||||
LXM_HEADER_PITCH_TABLE = (1 << 1),
|
|
||||||
|
|
||||||
LXM_HEADER_DESYNC_TEST = (1 << 31),
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lxm_header_t {
|
|
||||||
char magic[4]; // "LXM\x1A"
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
uint8_t minor;
|
|
||||||
uint8_t major;
|
|
||||||
};
|
|
||||||
uint16_t v;
|
|
||||||
} version;
|
|
||||||
uint16_t flags; // reserved
|
|
||||||
uint16_t frame_rate; // in Hz, 8.8fx
|
|
||||||
uint16_t num_samples;
|
|
||||||
uint8_t num_channels; // 0..32
|
|
||||||
uint8_t callstack_depth; // max nested backrefs
|
|
||||||
uint16_t amplification; // 8.8fx, for software mixer
|
|
||||||
uint32_t samples_ptr; // offset to sample descriptors
|
|
||||||
|
|
||||||
//lxm_header_stream_desc_t stream[num_channels + 1]; // first is control stream
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (flags & LXM_HEADER_PITCH_TABLE) {
|
|
||||||
uint16_t pitchtab_size; // 0..127
|
|
||||||
uint16_t pitchtab[pitchtab_size];
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
// sample descriptors, stored sequentially
|
|
||||||
enum {
|
|
||||||
LXM_SAMPLE_8BIT = (0 << 0),
|
|
||||||
LXM_SAMPLE_16BIT = (1 << 0),
|
|
||||||
LXM_SAMPLE_FORMAT_MASK = (7 << 0),
|
|
||||||
|
|
||||||
LXM_SAMPLE_ONESHOT = (0 << 3),
|
|
||||||
LXM_SAMPLE_LOOP_FORWARD = (1 << 3),
|
|
||||||
LXM_SAMPLE_LOOP_BIDIR = (2 << 3),
|
|
||||||
LXM_SAMPLE_LOOP_MASK = (3 << 3),
|
|
||||||
LXM_SAMPLE_LOOP_SHIFT = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lxm_sample_t {
|
|
||||||
uint16_t flags;
|
|
||||||
uint16_t compression; // currently 0
|
|
||||||
uint32_t sample_rate; // in hz, 24.8fx
|
|
||||||
int32_t length; // in samples, sustain loops not supported
|
|
||||||
int32_t loop_start; // in samples
|
|
||||||
uint32_t ofs_data; // offset in file
|
|
||||||
|
|
||||||
// optional, contains 0 if ignored
|
|
||||||
uint32_t max_sample_rate; // maximum sample rate occured in the file, used for target device sample rate optimization (emu8k :)
|
|
||||||
uint32_t opt_data; // sample optimization data (priority, etc)
|
|
||||||
uint32_t reserved;
|
|
||||||
};
|
|
||||||
|
|
||||||
// LXM v0 stream data:
|
|
||||||
enum {
|
|
||||||
LXM_STREAM_END_FRAME = 0xFF, // end of frame, set channel 0
|
|
||||||
LXM_STREAM_END = 0xFE, // end of stream, stop here or loop to LXM_STREAM_LOOP stream point
|
|
||||||
LXM_STREAM_NOP = 0xFD,
|
|
||||||
LXM_STREAM_NEW_ORDER = 0xFC, // nop, marks new order
|
|
||||||
LXM_STREAM_SET_FRAME_RATE = 0xFB, // word rate (as in lxm_header_t::frame_rate)
|
|
||||||
LXM_STREAM_LOOP = 0xFA, // set loop point here
|
|
||||||
|
|
||||||
// delay commands
|
|
||||||
LXM_STREAM_DELAY_INT32 = 0xF9, // dword delay
|
|
||||||
LXM_STREAM_DELAY_INT16 = 0xF8, // word delay
|
|
||||||
LXM_STREAM_DELAY_INT12 = 0xD0, // D0..DF - 0..4095 frames delay (hibyte in low 4 bits of command)
|
|
||||||
LXM_STERAM_DELAY_SHORT = 0xC0, // C0..CF - 1..16 frames delay
|
|
||||||
|
|
||||||
// back reference
|
|
||||||
LXM_STREAM_BACKREF = 0xE0, // E0..EF - word backrefpos (12 bit), byte frames
|
|
||||||
|
|
||||||
// setter commands
|
|
||||||
LXM_STREAM_VOLUME = 0x00, // 00..7F - volume is 7bit log compressed, end the frame
|
|
||||||
LXM_STREAM_SET = 0x80, // 80..9F - set all params
|
|
||||||
LXM_STREAM_RETRIG = 0xA0, // A0..AF - retrig note (ofs = 0), set all params
|
|
||||||
LXM_STREAM_SET_EXT = 0xB0, // B0..BF - reserved
|
|
||||||
|
|
||||||
// channel flags
|
|
||||||
LXM_STREAM_SET_SAMPLE = (1 << 0), // byte
|
|
||||||
LXM_STREAM_SET_PITCH = (1 << 1), // byte/word pitch/note compressed (see below)
|
|
||||||
LXM_STREAM_SET_PAN = (1 << 2), // byte left 00 .. 80 .. FF right
|
|
||||||
LXM_STREAM_SET_OFS = (1 << 3), // byte (sample_pos >> 8)
|
|
||||||
|
|
||||||
LXM_STREAM_RETRIG_END = (1 << 3), // end the frame
|
|
||||||
LXM_STREAM_SET_END = (1 << 4), // end the frame
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
|
@ -1,152 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "lxmfile.h"
|
|
||||||
|
|
||||||
// forward declarations
|
|
||||||
struct lxm_channel_context_t;
|
|
||||||
struct lxm_sample_context_t;
|
|
||||||
|
|
||||||
union lxm_frac_t {
|
|
||||||
struct {
|
|
||||||
uint32_t f;
|
|
||||||
int32_t i;
|
|
||||||
};
|
|
||||||
int64_t p;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lxm_stream_stack_t {
|
|
||||||
uint8_t* stream;
|
|
||||||
uint32_t samples_to_play;
|
|
||||||
uint32_t reload;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lxm_channel_context_t {
|
|
||||||
lxm_sample_context_t* sample; // current sample
|
|
||||||
|
|
||||||
uint32_t pitch; // current pitch
|
|
||||||
uint32_t volume; // current volume
|
|
||||||
uint32_t pan; // current panning
|
|
||||||
|
|
||||||
// mixer context
|
|
||||||
struct {
|
|
||||||
int32_t vol_l, vol_r; // 16.16fx
|
|
||||||
|
|
||||||
lxm_frac_t pos; // 32.32fx
|
|
||||||
lxm_frac_t delta; // 32.32fx
|
|
||||||
|
|
||||||
bool play_backwards;
|
|
||||||
|
|
||||||
int stopped;
|
|
||||||
} mixer;
|
|
||||||
|
|
||||||
// stream stack
|
|
||||||
lxm_stream_stack_t stack[16];
|
|
||||||
int stack_pos;
|
|
||||||
|
|
||||||
// stream data
|
|
||||||
struct {
|
|
||||||
uint32_t samples_to_play;
|
|
||||||
uint32_t delay;
|
|
||||||
uint32_t reload;
|
|
||||||
|
|
||||||
uint8_t* data;
|
|
||||||
uint8_t* ptr;
|
|
||||||
uint8_t* loop; // if active
|
|
||||||
} stream;
|
|
||||||
|
|
||||||
bool updated;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lxm_sample_context_t {
|
|
||||||
lxm_sample_t header;
|
|
||||||
|
|
||||||
// mixer.delta = (channel.pitch * sample.rate) / global.rate = channel.pitch * rate_factor;
|
|
||||||
uint32_t rate_factor; // 16.16fx
|
|
||||||
|
|
||||||
// data unions
|
|
||||||
union {
|
|
||||||
int8_t* data8;
|
|
||||||
int16_t* data16;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lxm_mixer_context_t {
|
|
||||||
// next row delay count/reload
|
|
||||||
int32_t spt_count; // 16.16fx
|
|
||||||
int32_t spt_reload; // 16.16fx
|
|
||||||
|
|
||||||
uint32_t out_channels; // 1 or 2
|
|
||||||
uint32_t sample_rate; // sample rate
|
|
||||||
|
|
||||||
// amplify
|
|
||||||
uint32_t chan_amplify; // 16.16fx
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lxm_context_t {
|
|
||||||
lxm_header_t header;
|
|
||||||
|
|
||||||
// sample contexts
|
|
||||||
lxm_sample_context_t* samples;
|
|
||||||
|
|
||||||
// channel context
|
|
||||||
lxm_channel_context_t channels[32];
|
|
||||||
|
|
||||||
// mixer context
|
|
||||||
lxm_mixer_context_t mixer;
|
|
||||||
|
|
||||||
// pitch table data
|
|
||||||
struct {
|
|
||||||
int size;
|
|
||||||
uint16_t* data;
|
|
||||||
} pitchtab;
|
|
||||||
|
|
||||||
// control stream data
|
|
||||||
struct {
|
|
||||||
uint32_t delay;
|
|
||||||
uint32_t reload;
|
|
||||||
|
|
||||||
uint8_t* data;
|
|
||||||
uint8_t* ptr;
|
|
||||||
} stream;
|
|
||||||
|
|
||||||
// position data
|
|
||||||
struct {
|
|
||||||
uint32_t order;
|
|
||||||
uint32_t frame;
|
|
||||||
uint64_t samples;
|
|
||||||
|
|
||||||
uint32_t looped;
|
|
||||||
} pos;
|
|
||||||
|
|
||||||
// loop data
|
|
||||||
struct {
|
|
||||||
uint8_t* data;
|
|
||||||
uint32_t frames;
|
|
||||||
uint64_t samples;
|
|
||||||
} loop;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// init context
|
|
||||||
int lxm_init(lxm_context_t* ctx, uint32_t out_channels, uint32_t sample_rate);
|
|
||||||
|
|
||||||
// free context
|
|
||||||
int lxm_free(lxm_context_t* ctx);
|
|
||||||
|
|
||||||
// load from file
|
|
||||||
int lxm_load(lxm_context_t* ctx, const char *filename);
|
|
||||||
|
|
||||||
// load from memory
|
|
||||||
int lxm_load_mem(lxm_context_t* ctx, const void *data, uint32_t size);
|
|
||||||
|
|
||||||
// reset to start
|
|
||||||
int lxm_rewind(lxm_context_t* ctx);
|
|
||||||
|
|
||||||
// play one tick
|
|
||||||
int lxm_tick(lxm_context_t* ctx);
|
|
||||||
|
|
||||||
// render int16_t stereo samples to buffer
|
|
||||||
// returns sample frames rendered or 0 if error
|
|
||||||
int lxm_render(lxm_context_t* ctx, int16_t* buf, int32_t count);
|
|
||||||
|
|
||||||
|
|
|
@ -153,8 +153,6 @@
|
||||||
<ClInclude Include="include\opl3.h" />
|
<ClInclude Include="include\opl3.h" />
|
||||||
<ClInclude Include="include\portaudio.h" />
|
<ClInclude Include="include\portaudio.h" />
|
||||||
<ClInclude Include="include\vgm.h" />
|
<ClInclude Include="include\vgm.h" />
|
||||||
<ClInclude Include="lxmfile.h" />
|
|
||||||
<ClInclude Include="lxmplay.h" />
|
|
||||||
<ClInclude Include="opmfile.h" />
|
<ClInclude Include="opmfile.h" />
|
||||||
<ClInclude Include="opmplay.h" />
|
<ClInclude Include="opmplay.h" />
|
||||||
<ClInclude Include="wavehead.h" />
|
<ClInclude Include="wavehead.h" />
|
||||||
|
|
|
@ -26,12 +26,6 @@
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="lxmfile.h">
|
|
||||||
<Filter>Файлы заголовков</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="lxmplay.h">
|
|
||||||
<Filter>Файлы заголовков</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="wavehead.h">
|
<ClInclude Include="wavehead.h">
|
||||||
<Filter>Файлы заголовков</Filter>
|
<Filter>Файлы заголовков</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
struct opm_header_stream_desc_t {
|
struct opm_header_stream_desc_t {
|
||||||
uint16_t ptr; // offset to data stream in paragraphs (bytes*16)
|
//uint16_t ptr; // offset to data stream in paragraphs (bytes*16)
|
||||||
uint16_t size; // stream data size in bytes
|
uint16_t size; // stream data size in bytes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,6 +52,9 @@ enum {
|
||||||
OPM_SET_ADSR = 0xA0, // A0..AF - set attack/sustain/decay/release for operator
|
OPM_SET_ADSR = 0xA0, // A0..AF - set attack/sustain/decay/release for operator
|
||||||
OPM_SET_FREQ_FB = 0xB0, // B0..BF - set frequency + feedback
|
OPM_SET_FREQ_FB = 0xB0, // B0..BF - set frequency + feedback
|
||||||
|
|
||||||
|
// control register set
|
||||||
|
OPM_CTRL_KEY_PERC = 0x00, // 00..7F - set key on/off for percussion, end of frame
|
||||||
|
OPM_CTRL_REG_SET = 0x80, // 80..BF - set control registers
|
||||||
|
|
||||||
// flags
|
// flags
|
||||||
OPM_KEY_OFF = (0 << 0),
|
OPM_KEY_OFF = (0 << 0),
|
||||||
|
@ -71,10 +74,16 @@ enum {
|
||||||
OPM_CMDA0_SELECT_OPERATOR = (1 << 2),
|
OPM_CMDA0_SELECT_OPERATOR = (1 << 2),
|
||||||
OPM_CMDA0_END_OF_FRAME = (1 << 3),
|
OPM_CMDA0_END_OF_FRAME = (1 << 3),
|
||||||
|
|
||||||
OPM_CMDB0_SET_FREQ_LOW = (1 << 0),
|
OPM_CMDB0_SET_FEEDBACK = (1 << 0),
|
||||||
OPM_CMDB0_SET_FREQ_HIGH = (1 << 1),
|
OPM_CMDB0_SET_FREQ_LOW = (1 << 1),
|
||||||
OPM_CMDB0_SET_FEEDBACK = (1 << 2),
|
OPM_CMDB0_SET_FREQ_HIGH = (1 << 2),
|
||||||
OPM_CMDB0_END_OF_FRAME = (1 << 3),
|
OPM_CMDB0_END_OF_FRAME = (1 << 3),
|
||||||
|
|
||||||
|
OPM_CTRL_SET_REG01 = (1 << 0),
|
||||||
|
OPM_CTRL_SET_REG08 = (1 << 1),
|
||||||
|
OPM_CTRL_SET_REG105 = (1 << 2),
|
||||||
|
OPM_CTRL_SET_REG104 = (1 << 3),
|
||||||
|
OPM_CTRL_SET_REGBD = (1 << 4),
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
|
@ -98,7 +98,6 @@ int opmplay_load_module(opmplay_context_t* ctx, opmplay_io_t* io) {
|
||||||
for (int ch = 0; ch < OPMPLAY_MAX_CHANNLES; ch++) {
|
for (int ch = 0; ch < OPMPLAY_MAX_CHANNLES; ch++) {
|
||||||
ctx->channels[ch].stream.data = (uint8_t*)opmplay_alloc(sizeof(uint8_t*) * (streamdesc[ch].size));
|
ctx->channels[ch].stream.data = (uint8_t*)opmplay_alloc(sizeof(uint8_t*) * (streamdesc[ch].size));
|
||||||
if (ctx->channels[ch].stream.data == NULL) return OPMPLAY_ERR_MEMALLOC;
|
if (ctx->channels[ch].stream.data == NULL) return OPMPLAY_ERR_MEMALLOC;
|
||||||
if (io->seek(io, streamdesc[ch].ptr << 4)) return OPMPLAY_ERR_IO;
|
|
||||||
if (io->read(io, ctx->channels[ch].stream.data, streamdesc[ch].size) != streamdesc[ch].size) return OPMPLAY_ERR_IO;
|
if (io->read(io, ctx->channels[ch].stream.data, streamdesc[ch].size) != streamdesc[ch].size) return OPMPLAY_ERR_IO;
|
||||||
ctx->channels[ch].stream.delay = 1;
|
ctx->channels[ch].stream.delay = 1;
|
||||||
}
|
}
|
||||||
|
@ -180,6 +179,17 @@ int opmplay_tick(opmplay_context_t* ctx, opl3_chip* opl3) {
|
||||||
bool isRun = true;
|
bool isRun = true;
|
||||||
if (--chctx->stream.delay == 0) {
|
if (--chctx->stream.delay == 0) {
|
||||||
while (isRun) {
|
while (isRun) {
|
||||||
|
if ((*(data) & 0xE0) == OPM_CTRL_REG_SET) {
|
||||||
|
int mask = *data;
|
||||||
|
data++;
|
||||||
|
if (mask & OPM_CTRL_SET_REG01) OPL3_WriteRegBuffered(opl3, 0x001, *data++);
|
||||||
|
if (mask & OPM_CTRL_SET_REG08) OPL3_WriteRegBuffered(opl3, 0x008, *data++);
|
||||||
|
if (mask & OPM_CTRL_SET_REG105) OPL3_WriteRegBuffered(opl3, 0x105, *data++);
|
||||||
|
if (mask & OPM_CTRL_SET_REG104) OPL3_WriteRegBuffered(opl3, 0x104, *data++);
|
||||||
|
if (mask & OPM_CTRL_SET_REGBD) OPL3_WriteRegBuffered(opl3, 0x0BD, *data++);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// check for common stuff
|
// check for common stuff
|
||||||
switch (*data) {
|
switch (*data) {
|
||||||
// end of stream - rewind everything
|
// end of stream - rewind everything
|
||||||
|
@ -209,18 +219,15 @@ int opmplay_tick(opmplay_context_t* ctx, opl3_chip* opl3) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
#if 0
|
|
||||||
// test for delay
|
// test for delay
|
||||||
newdelay = opmplay_set_delay(&data);
|
newdelay = opmplay_set_delay(&data);
|
||||||
if (newdelay > 0) {
|
if (newdelay > 0) {
|
||||||
chctx->stream.reload = newdelay;
|
chctx->stream.reload = newdelay;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
// register:data pair
|
printf("unknonw token %02x!\n", *data);
|
||||||
OPL3_WriteRegBuffered(opl3, *(data + 0), *(data + 1));
|
return OPMPLAY_ERR_BAD_FILE_STRUCTURE;
|
||||||
data += 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,6 +243,33 @@ int opmplay_tick(opmplay_context_t* ctx, opl3_chip* opl3) {
|
||||||
bool isRun = true;
|
bool isRun = true;
|
||||||
if (--chctx->stream.delay == 0) {
|
if (--chctx->stream.delay == 0) {
|
||||||
while (isRun) {
|
while (isRun) {
|
||||||
|
// get streams
|
||||||
|
if ((*(data) & 0xE0) == OPM_SET_MULT_WAVE_TL) {
|
||||||
|
int mask = *data;
|
||||||
|
int op = (mask & OPM_CMD80_SELECT_OPERATOR ? 3 : 0) + opmplay_opregs_channel_offset[ch];
|
||||||
|
data++;
|
||||||
|
if (mask & OPM_CMD80_SET_MULT) OPL3_WriteRegBuffered(opl3, 0x20+op, *data++);
|
||||||
|
if (mask & OPM_CMD80_SET_TL) OPL3_WriteRegBuffered(opl3, 0x40+op, *data++);
|
||||||
|
if (mask & OPM_CMD80_SET_WAVEFORM) OPL3_WriteRegBuffered(opl3, 0xE0+op, *data++);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((*(data) & 0xF0) == OPM_SET_ADSR) {
|
||||||
|
int mask = *data;
|
||||||
|
int op = (mask & OPM_CMDA0_SELECT_OPERATOR ? 3 : 0) + opmplay_opregs_channel_offset[ch];
|
||||||
|
data++;
|
||||||
|
if (mask & OPM_CMDA0_SET_AD) OPL3_WriteRegBuffered(opl3, 0x60 + op, *data++);
|
||||||
|
if (mask & OPM_CMDA0_SET_SR) OPL3_WriteRegBuffered(opl3, 0x80 + op, *data++);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((*(data) & 0xF0) == OPM_SET_FREQ_FB) {
|
||||||
|
int mask = *data;
|
||||||
|
data++;
|
||||||
|
if (mask & OPM_CMDB0_SET_FEEDBACK) OPL3_WriteRegBuffered(opl3, 0xC0 + ch, *data++);
|
||||||
|
if (mask & OPM_CMDB0_SET_FREQ_LOW) OPL3_WriteRegBuffered(opl3, 0xA0 + ch, *data++);
|
||||||
|
if (mask & OPM_CMDB0_SET_FREQ_HIGH) OPL3_WriteRegBuffered(opl3, 0xB0 + ch, *data++);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// check for common stuff
|
// check for common stuff
|
||||||
switch (*data) {
|
switch (*data) {
|
||||||
case OPM_STREAM_END:
|
case OPM_STREAM_END:
|
||||||
|
@ -258,41 +292,17 @@ int opmplay_tick(opmplay_context_t* ctx, opl3_chip* opl3) {
|
||||||
data++;
|
data++;
|
||||||
isRun = false;
|
isRun = false;
|
||||||
break;
|
break;
|
||||||
case OPM_STREAM_DELAY_INT16:
|
|
||||||
// delay (temporary)
|
|
||||||
chctx->stream.reload = *(data + 1) | (*(data + 2) << 8);
|
|
||||||
data += 3;
|
|
||||||
isRun = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
#if 0
|
|
||||||
// test for delay
|
// test for delay
|
||||||
newdelay = opmplay_set_delay(&data);
|
newdelay = opmplay_set_delay(&data);
|
||||||
if (newdelay > 0) {
|
if (newdelay > 0) {
|
||||||
chctx->stream.reload = newdelay;
|
chctx->stream.reload = newdelay;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
switch (*(data + 0) & 0xF0) {
|
printf("unknonw token %02x!\n", *data);
|
||||||
case 0x20:
|
return OPMPLAY_ERR_BAD_FILE_STRUCTURE;
|
||||||
case 0x40:
|
|
||||||
case 0x60:
|
|
||||||
case 0x80:
|
|
||||||
case 0xE0:
|
|
||||||
OPL3_WriteRegBuffered(opl3, *(data + 0) + opmplay_opregs_channel_offset[ch], *(data + 1));
|
|
||||||
break;
|
|
||||||
case 0xA0:
|
|
||||||
case 0xB0:
|
|
||||||
case 0xC0:
|
|
||||||
OPL3_WriteRegBuffered(opl3, *(data + 0) + ch, *(data + 1));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
OPL3_WriteRegBuffered(opl3, *(data + 0), *(data + 1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
data += 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
struct opm_header_stream_desc_t {
|
struct opm_header_stream_desc_t {
|
||||||
uint16_t ptr; // offset to data stream in paragraphs (bytes*16)
|
//uint16_t ptr; // offset to data stream in paragraphs (bytes*16)
|
||||||
uint16_t size; // stream data size in bytes
|
uint16_t size; // stream data size in bytes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,10 +74,16 @@ enum {
|
||||||
OPM_CMDA0_SELECT_OPERATOR = (1 << 2),
|
OPM_CMDA0_SELECT_OPERATOR = (1 << 2),
|
||||||
OPM_CMDA0_END_OF_FRAME = (1 << 3),
|
OPM_CMDA0_END_OF_FRAME = (1 << 3),
|
||||||
|
|
||||||
OPM_CMDB0_SET_FREQ_LOW = (1 << 0),
|
OPM_CMDB0_SET_FEEDBACK = (1 << 0),
|
||||||
OPM_CMDB0_SET_FREQ_HIGH = (1 << 1),
|
OPM_CMDB0_SET_FREQ_LOW = (1 << 1),
|
||||||
OPM_CMDB0_SET_FEEDBACK = (1 << 2),
|
OPM_CMDB0_SET_FREQ_HIGH = (1 << 2),
|
||||||
OPM_CMDB0_END_OF_FRAME = (1 << 3),
|
OPM_CMDB0_END_OF_FRAME = (1 << 3),
|
||||||
|
|
||||||
|
OPM_CTRL_SET_REG01 = (1 << 0),
|
||||||
|
OPM_CTRL_SET_REG08 = (1 << 1),
|
||||||
|
OPM_CTRL_SET_REG105 = (1 << 2),
|
||||||
|
OPM_CTRL_SET_RE104 = (1 << 3),
|
||||||
|
OPM_CTRL_SET_REGBD = (1 << 4),
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
|
@ -337,6 +337,7 @@ int opm_write_file(opm_convert_context_t* ctx) {
|
||||||
std::vector<opm_write_file_info_t> writeinfo(9 + 1);
|
std::vector<opm_write_file_info_t> writeinfo(9 + 1);
|
||||||
ctx->opmfile.streamdesc.resize(9 + 1);
|
ctx->opmfile.streamdesc.resize(9 + 1);
|
||||||
|
|
||||||
|
#if 0
|
||||||
// calculate offsets
|
// calculate offsets
|
||||||
auto fsize = round_to_para(sizeof(ctx->opmfile.header) + (9 + 1) * sizeof(opm_header_stream_desc_t));
|
auto fsize = round_to_para(sizeof(ctx->opmfile.header) + (9 + 1) * sizeof(opm_header_stream_desc_t));
|
||||||
for (int i = 0; i < 9 + 1; i++) {
|
for (int i = 0; i < 9 + 1; i++) {
|
||||||
|
@ -363,6 +364,23 @@ int opm_write_file(opm_convert_context_t* ctx) {
|
||||||
fwrite(ctx->oplchan_out[i].data(), sizeof(uint8_t), ctx->oplchan_out[i].size(), f);
|
fwrite(ctx->oplchan_out[i].data(), sizeof(uint8_t), ctx->oplchan_out[i].size(), f);
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
#else
|
||||||
|
for (int i = 0; i < 9 + 1; i++) {
|
||||||
|
ctx->opmfile.streamdesc[i].size = ctx->oplchan_out[i].size();
|
||||||
|
}
|
||||||
|
// dump to OPM file
|
||||||
|
FILE* f = fopen(ctx->opmfile.filename.c_str(), "wb");
|
||||||
|
if (!f) return 1;
|
||||||
|
|
||||||
|
// write header
|
||||||
|
fwrite(&ctx->opmfile.header, sizeof(opm_header_t), 1, f);
|
||||||
|
fwrite(ctx->opmfile.streamdesc.data(), sizeof(decltype(ctx->opmfile.streamdesc)::value_type), ctx->opmfile.streamdesc.size(), f);
|
||||||
|
// write channel streams
|
||||||
|
for (int i = 0; i < 1 + 9; i++) {
|
||||||
|
fwrite(ctx->oplchan_out[i].data(), sizeof(uint8_t), ctx->oplchan_out[i].size(), f);
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue