239 lines
6 KiB
C++
239 lines
6 KiB
C++
#pragma once
|
|
#include <stdint.h>
|
|
#include "opmfile.h"
|
|
#include "vgm.h"
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#include <map>
|
|
|
|
struct opm_control_track_t {
|
|
uint32_t frame;
|
|
int type, data;
|
|
};
|
|
|
|
/*
|
|
oof
|
|
â îáùåì, äëÿ êàæäîãî ôðåéìà ïîíàäîáèòñÿ õðàíèòü öåïî÷êó ñîáûòèé, ðàçäåëÿåìûõ
|
|
çàïèñüþ â key on (åñëè òàêîâàÿ åñòü), ïîñêîëüêó äëÿ ðåòðèãà íîòû íàäî ñíà÷àëà
|
|
ñáîðñèòü key on â 0, çàòåì ïîñòàâèòü â 1
|
|
*/
|
|
|
|
enum : uint64_t {
|
|
// control stream
|
|
OPM_REC_REG24 = (1 << 0),
|
|
OPM_REC_REG25 = (1 << 1),
|
|
OPM_REC_REG27 = (1 << 2),
|
|
OPM_REC_REG22 = (1 << 3),
|
|
OPM_REC_EXTCH3_OP1_LOW = (1 << 4),
|
|
OPM_REC_EXTCH3_OP1_HIGH = (1 << 5),
|
|
OPM_REC_EXTCH3_OP2_LOW = (1 << 6),
|
|
OPM_REC_EXTCH3_OP2_HIGH = (1 << 7),
|
|
OPM_REC_EXTCH3_OP3_LOW = (1 << 8),
|
|
OPM_REC_EXTCH3_OP3_HIGH = (1 << 9),
|
|
|
|
// FM stream
|
|
OPM_REC_REG30 = (1 << 0),
|
|
OPM_REC_REG40 = (1 << 1),
|
|
OPM_REC_REG50 = (1 << 2),
|
|
OPM_REC_REG60 = (1 << 3),
|
|
OPM_REC_REG70 = (1 << 4),
|
|
OPM_REC_REG80 = (1 << 5),
|
|
OPM_REC_REG90 = (1 << 6),
|
|
|
|
OPM_REC_REG30_IDX = 0,
|
|
OPM_REC_REG40_IDX = 1,
|
|
OPM_REC_REG50_IDX = 2,
|
|
OPM_REC_REG60_IDX = 3,
|
|
OPM_REC_REG70_IDX = 4,
|
|
OPM_REC_REG80_IDX = 5,
|
|
OPM_REC_REG90_IDX = 6,
|
|
|
|
OPM_REC_OP_SHIFTMUL = 7,
|
|
|
|
OPM_REC_CHREG_SHIFT = OPM_REC_OP_SHIFTMUL*4,
|
|
OPM_REC_REGA0 = (1ULL << (OPM_REC_CHREG_SHIFT + 0)),
|
|
OPM_REC_REGA4 = (1ULL << (OPM_REC_CHREG_SHIFT + 1)),
|
|
OPM_REC_REGB0 = (1ULL << (OPM_REC_CHREG_SHIFT + 2)),
|
|
OPM_REC_REGB4 = (1ULL << (OPM_REC_CHREG_SHIFT + 3)),
|
|
OPM_REC_KEY = (1ULL << (OPM_REC_CHREG_SHIFT + 4)),
|
|
|
|
// SSG tone stream
|
|
OPM_REC_AYTONE_VOLUME = (1 << 0),
|
|
OPM_REC_AYTONE_PERIOD_LOW = (1 << 1),
|
|
OPM_REC_AYTONE_PERIOD_HIGH = (1 << 2),
|
|
OPM_REC_AYTONE_MASK = (1 << 3),
|
|
|
|
// SSG env/noise stream
|
|
OPM_REC_AYENV_NOISE = (1 << 0),
|
|
OPM_REC_AYENV_PERIOD_LOW = (1 << 1),
|
|
OPM_REC_AYENV_PERIOD_HIGH = (1 << 2),
|
|
OPM_REC_AYENV_ENVTYPE = (1 << 3),
|
|
|
|
// rhythm stream
|
|
OPM_RHYTHM_REG10_KEYON = (1 << 16),
|
|
};
|
|
|
|
struct opm_frame_record {
|
|
uint64_t flags; // yeah!
|
|
|
|
union {
|
|
struct {
|
|
// control channel
|
|
int reg24, reg25, reg27, reg22;
|
|
struct {
|
|
int freq[2][4];
|
|
} extch3;
|
|
};
|
|
struct {
|
|
// fm channel
|
|
int opdata[4][9-3+1]; // regs 30..90
|
|
int fnum, block, fb, pan, key;
|
|
};
|
|
struct {
|
|
// SSG tone channel
|
|
int volume, mask, period_low, period_hi;
|
|
} aytone;
|
|
struct {
|
|
// SSG envelope/noise channel
|
|
int noise, envtype, period_low, period_hi;
|
|
} ayenv;
|
|
struct {
|
|
// rhythm channels
|
|
int regs[16];
|
|
int key_on;
|
|
} rhythm;
|
|
};
|
|
};
|
|
|
|
enum {
|
|
OPM_CHAN_NEWPATTERN = (1 << 0),
|
|
OPM_CHAN_LOOP_POINT = (1 << 1),
|
|
OPM_FRAME0 = (1 << 2),
|
|
|
|
OPM_CHAN_BACKREF = (1 << 8),
|
|
};
|
|
|
|
struct opm_channel_record_t {
|
|
// current frame index
|
|
uint32_t frame;
|
|
// distance between next and this frame
|
|
uint32_t frame_dist;
|
|
// flags
|
|
int flags;
|
|
// raw data
|
|
std::vector<uint8_t> rawdata;
|
|
// records
|
|
std::vector<opm_frame_record> records;
|
|
// compression data
|
|
int distance_frames, distance_bytes, frames_to_play, frames_to_play_total;
|
|
// byte stamp
|
|
uint32_t byte_stamp;
|
|
};
|
|
|
|
|
|
struct opm_framerate_estimate_t {
|
|
float max_delay_freq; // maximum possible frequency, delays faster are concatenated together
|
|
float max_delay_base; // maximum base delay allowed
|
|
float min_delay_threshold; // percentile of delays used to find the minimum delay
|
|
float trim_threshold; // delays with occurence lower than threshld will be trimmed
|
|
float rescale_min_ratio; // used to rescale delays to one base
|
|
};
|
|
|
|
struct vgm_context_t {
|
|
std::vector<uint8_t> vgmfile;
|
|
VGMHeader* header;
|
|
uint32_t loop_pos;
|
|
uint32_t start, end; // offsets
|
|
};
|
|
|
|
struct opm_channel_rawdata_t {
|
|
// current frame index
|
|
uint32_t frame;
|
|
// loop flag
|
|
bool loop;
|
|
// raw OPL data
|
|
std::vector<uint8_t> data;
|
|
};
|
|
|
|
struct opm_channel_t {
|
|
// non-empty (i.e key on present)
|
|
bool used;
|
|
|
|
// OPL register stream (parsed from VGM)
|
|
std::vector<opm_channel_rawdata_t> opl;
|
|
|
|
// records
|
|
std::vector<opm_channel_record_t> records;
|
|
|
|
// packed records
|
|
std::vector<opm_channel_record_t> packed;
|
|
|
|
// raw stream bytes
|
|
std::vector<uint8_t> rawstream;
|
|
|
|
// stream descriptor
|
|
opm_header_stream_desc_t streamdesc;
|
|
};
|
|
|
|
struct opm_convert_context_t {
|
|
// VGM context
|
|
vgm_context_t vgm;
|
|
|
|
// chip type
|
|
uint32_t chip_type; // OPM_FLAG_CHIP_*
|
|
uint32_t max_channels;
|
|
uint32_t ctrl_chidx;
|
|
uint32_t fm_chidx;
|
|
uint32_t ssg_chidx;
|
|
uint32_t rhy_chidx;
|
|
uint32_t dual_chidx;
|
|
bool percussion_mode;
|
|
|
|
// conversion flags
|
|
struct {
|
|
int compress_level;
|
|
int max_stack_depth;
|
|
int verbosity;
|
|
bool optimize_vgm;
|
|
} flags;
|
|
|
|
// frame rate stuff
|
|
double delay;
|
|
opm_framerate_estimate_t estimate;
|
|
|
|
// total frames
|
|
uint32_t total_frames;
|
|
|
|
// -----------------------------------
|
|
// channel struct
|
|
std::vector<opm_channel_t> ch;
|
|
|
|
// raw per-channel OPL data
|
|
std::vector<std::vector<opm_channel_rawdata_t>> oplchan;
|
|
std::vector<std::vector<uint8_t>> oplchan_out;
|
|
|
|
// -----------------------------------
|
|
|
|
// channel records
|
|
std::vector<std::vector<opm_channel_record_t>> opmrecords;
|
|
|
|
// compressed streams
|
|
std::vector<std::vector<opm_channel_record_t>> opmpacked;
|
|
|
|
// final OPM stream
|
|
std::vector<std::vector<uint8_t>> opmstream;
|
|
|
|
// -----------------------------------
|
|
struct {
|
|
std::string name_prefix;
|
|
std::string filename;
|
|
std::string foldername;
|
|
opm_header_t header;
|
|
std::vector<opm_header_stream_desc_t> streamdesc;
|
|
} opmfile;
|
|
|
|
std::string logname;
|
|
};
|
|
|