Code for loading and saving various FM voice formats meant for the Yamaha YM series of chips (OPL, OPM, OPN etc.), format autodetection code, and conversion between the various formats.
This library is meant to be used in fmtoy and vgm2x.
Format | Type | Op | Max voices |
---|---|---|---|
INS | OPN | 4 | 1 |
DMP | OPN | 4 | 1 |
OPM | OPM | 4 | unlimited |
TFI | OPN | 4 | 1 |
Y12 | OPN | 4 | 1 |
SBI | OPL | 2 | 1 |
INS | OPL | 2 | 1 |
BNK | OPL | 2 | 65536 |
IBK | OPL | 2 | 128 |
CMF | OPL | 2 | 128/256/65536 |
OPL
Field | Bit | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ||
ch_fb_cnt[0] |
D | C | B | A | FB | CNT | Channel mask, feedback, connection | ||
dam_dvb_ryt_bd_sd_tom_tc_hh |
AM | VIB | RYT | BD | SD | TOM | TC | HH | |
am_vib_eg_ksr_mul |
AM | VIB | EGT | KSR | MUL | ||||
ksl_tl |
KSL | TL | |||||||
ar_dr |
AR | DR | |||||||
sl_rr |
SL | RR | |||||||
ws |
WS | Waveform select |
Conversion between OPL, OPM and OPN voices is only possible in some cases, in other cases it involves approximation, and in others it is not possible.
Reading:
uint8_t *data; // Have your data in this buffer
size_t data_len; // with this length
struct opm_file opm;
int r = opm_file_load(&opm, data, data_len);
if(r != OPM_FILE_SUCCESS) {
fprintf(stderr, "Could not load file: %s (%d)\n", opm_file_error_string(r), r);
exit(1);
}
Writing:
size_t write_fn(void *buf, size_t bufsize, void *data_ptr) {
FILE *f = (FILE *)data_ptr;
return fwrite(buf, 1, bufsize, f);
}
struct opm_file opm;
opm_file_init(&opm);
FILE *f = fopen("out.opm", "w");
int opm_file_save(&opm, write_fn, f);
fclose(f);
emmake make libfmvoice.a