-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtfi_file.c
More file actions
152 lines (139 loc) · 4.04 KB
/
tfi_file.c
File metadata and controls
152 lines (139 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <stdio.h>
#include <string.h>
#include "tfi_file.h"
/*
$00 algo
$01 feedback
per-operator:
{
$03... mul
$04... detune+3
$05... tl
$06... rs
$07... ar
$08... dr
$09... sr
$0A... rr
$0B... sl
$0C... ssg
}
*/
// get signed DT from unsigned DT
static int convert_dt_u2s(int dt_unsigned) {
int dt_signed = dt_unsigned & 3;
if (dt_unsigned & 4) return -dt_signed;
else return dt_signed;
}
// get unsigned DT from signed DT
static int convert_dt_s2u(int dt_signed) {
if (dt_signed < 0) return ((-dt_signed) & 3) | 4;
else return dt_signed & 3;
}
void tfi_file_init(struct tfi_file *f) {
memset(f, 0, sizeof(*f));
}
int tfi_file_load(struct tfi_file *tfi, uint8_t *data, size_t data_len) {
if(data_len != 42) return -1;
uint8_t *p = data;
tfi->alg = *p++;
tfi->fb = *p++;
for(int i = 0; i < 4; i++) {
tfi->operators[i].mul = *p++;
tfi->operators[i].dt = convert_dt_s2u((*p++ & 7) - 3);
tfi->operators[i].tl = *p++;
tfi->operators[i].rs = *p++;
tfi->operators[i].ar = *p++;
tfi->operators[i].dr = *p++;
tfi->operators[i].sr = *p++;
tfi->operators[i].rr = *p++;
tfi->operators[i].sl = *p++;
tfi->operators[i].ssg_eg = *p++;
}
return 0;
}
int tfi_file_save(struct tfi_file *f, int (*write_fn)(void *, size_t, void *), void *data_ptr) {
uint8_t buf[42] = { 0 };
uint8_t *p = buf;
*p++ = f->alg;
*p++ = f->fb;
for(int i = 0; i < 4; i++) {
*p++ = f->operators[i].mul;
*p++ = 3 + convert_dt_u2s(f->operators[i].dt);
*p++ = f->operators[i].tl;
*p++ = f->operators[i].rs;
*p++ = f->operators[i].ar;
*p++ = f->operators[i].dr;
*p++ = f->operators[i].sr;
*p++ = f->operators[i].rr;
*p++ = f->operators[i].sl;
*p++ = f->operators[i].ssg_eg;
}
return write_fn(buf, 42, data_ptr);
}
#ifdef HAVE_STDIO
void tfi_file_dump(struct tfi_file *f) {
printf("alg=%d fb=%d\n", f->alg, f->fb);
printf("OP MUL DT TL RS AR DR SR RR SL SSG-EG\n");
for(int i = 0; i < 4; i++) {
struct tfi_file_operator *op = f->operators + i;
printf("%d %d %d %d %d %d %d %d %d %d %d\n", i, op->mul, op->dt, op->tl, op->rs, op->ar, op->dr, op->sr, op->rr, op->sl, op->ssg_eg);
}
}
#endif
#ifdef ENABLE_LOADERS
#include "loader.h"
static int load(void *data, int data_len, struct fm_voice_bank *bank) {
struct tfi_file f;
int r = tfi_file_load(&f, data, data_len);
if(r) return r;
struct opn_voice *voice = fm_voice_bank_reserve_opn_voices(bank, 1);
if(!voice) return -1;
voice->lfo = 0;
voice->slot = 0x0f;
voice->fb_con = (f.fb & 0x07) << 3 | (f.alg & 0x07);
for(int i = 0; i < 4; i++) {
struct opn_voice_operator *op = &voice->operators[i];
struct tfi_file_operator *fop = &f.operators[i];
op->dt_mul = (fop->dt & 0x07) << 3 | (fop->mul & 0x07);
op->tl = fop->tl & 0x7f;
op->ks_ar = fop->rs << 6 | (fop->ar & 0x1f);
op->am_dr = fop->dr & 0x1f;
op->sr = fop->sr;
op->sl_rr = fop->sl << 4 | (fop->rr & 0x0f);
op->ssg_eg = fop->ssg_eg;
}
return 0;
}
static int save(struct fm_voice_bank *bank, struct fm_voice_bank_position *pos, int (*write_fn)(void *, size_t, void *), void *data_ptr) {
if(bank->num_opn_voices <= pos->opn) return -1;
struct tfi_file f;
tfi_file_init(&f);
struct opn_voice* voice = &bank->opn_voices[pos->opn];
if (!voice) return - 1;
f.fb = opn_voice_get_fb(voice);
f.alg = opn_voice_get_con(voice);
for(int i = 0; i < 4; i++) {
f.operators[i].dt = opn_voice_get_operator_dt(voice, i);
f.operators[i].mul = opn_voice_get_operator_mul(voice, i);
f.operators[i].tl = opn_voice_get_operator_tl(voice, i);
f.operators[i].rs = opn_voice_get_operator_ks(voice, i);
f.operators[i].ar = opn_voice_get_operator_ar(voice, i);
f.operators[i].dr = opn_voice_get_operator_dr(voice, i);
f.operators[i].sr = opn_voice_get_operator_sr(voice, i);
f.operators[i].sl = opn_voice_get_operator_sl(voice, i);
f.operators[i].rr = opn_voice_get_operator_rr(voice, i);
}
pos->opn++;
return tfi_file_save(&f, write_fn, data_ptr);
}
struct loader tfi_file_loader = {
.load = load,
.save = save,
.name = "TFI",
.description = "TFI",
.file_ext = "tfi",
.max_opl_voices = 0,
.max_opm_voices = 0,
.max_opn_voices = 1,
};
#endif