-
-
Notifications
You must be signed in to change notification settings - Fork 7
/
fmtoy_ym3812.c
103 lines (88 loc) · 3.81 KB
/
fmtoy_ym3812.c
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
#include <stdlib.h>
#include "fmtoy.h"
#include "fmtoy_ym3812.h"
#include "libvgm/emu/SoundEmu.h"
#include "libvgm/emu/SoundDevs.h"
static void fmwrite(DEVFUNC_WRITE_A8D8 writefn, void *dataPtr, uint8_t reg, uint8_t data) {
writefn(dataPtr, 0, reg);
writefn(dataPtr, 1, data);
}
static int fmtoy_ym3812_init(struct fmtoy *fmtoy, int clock, int sample_rate, struct fmtoy_channel *channel) {
channel->chip->clock = clock;
DEV_GEN_CFG devCfg = {
.emuCore = 0,
.srMode = DEVRI_SRMODE_NATIVE,
.flags = 0x00,
.clock = clock,
.smplRate = sample_rate,
};
DEV_INFO *devinf = malloc(sizeof(DEV_INFO));
if(!devinf) return -1;
channel->chip->data = devinf;
if(SndEmu_Start(DEVID_YM3812, &devCfg, devinf))
return -2;
DEVFUNC_WRITE_A8D8 writefn;
SndEmu_GetDeviceFunc(devinf->devDef, RWF_REGISTER | RWF_WRITE, DEVRW_A8D8, 0, (void**)&writefn);
// Enable 6 channel mode
fmwrite(writefn, devinf->dataPtr, 0x01, 0x20);
return 0;
}
static int fmtoy_ym3812_destroy(struct fmtoy *fmtoy, struct fmtoy_channel *channel) {
SndEmu_Stop(channel->chip->data);
free(channel->chip->data);
return 0;
}
static void fmtoy_ym3812_program_change(struct fmtoy *fmtoy, uint8_t program, struct fmtoy_channel *channel) {
DEVFUNC_WRITE_A8D8 writefn;
DEV_INFO *devinf = channel->chip->data;
SndEmu_GetDeviceFunc(devinf->devDef, RWF_REGISTER | RWF_WRITE, DEVRW_A8D8, 0, (void**)&writefn);
struct opl_voice *v = &fmtoy->opl_voices[program];
int chan_offsets[] = {
0x00, 0x01, 0x02,
0x08, 0x09, 0x0a,
0x10, 0x11, 0x12,
};
for(int i = 0; i < 9; i++) {
fmwrite(writefn, devinf->dataPtr, 0xc0 + i, v->ch_fb_cnt[0]);
for(int j = 0; j < 2; j++) {
struct opl_voice_operator *op = &v->operators[j];
fmwrite(writefn, devinf->dataPtr, 0x20 + chan_offsets[i] + j * 3, op->am_vib_eg_ksr_mul);
fmwrite(writefn, devinf->dataPtr, 0x40 + chan_offsets[i] + j * 3, op->ksl_tl);
fmwrite(writefn, devinf->dataPtr, 0x60 + chan_offsets[i] + j * 3, op->ar_dr);
fmwrite(writefn, devinf->dataPtr, 0x80 + chan_offsets[i] + j * 3, op->sl_rr);
fmwrite(writefn, devinf->dataPtr, 0xe0 + chan_offsets[i] + j * 3, op->ws);
}
}
}
static void fmtoy_ym3812_set_pitch(struct fmtoy *fmtoy, int chip_channel, float pitch, struct fmtoy_channel *channel) {
DEVFUNC_WRITE_A8D8 writefn;
DEV_INFO *devinf = channel->chip->data;
SndEmu_GetDeviceFunc(devinf->devDef, RWF_REGISTER | RWF_WRITE, DEVRW_A8D8, 0, (void**)&writefn);
int block_fnum = opl_pitch_to_block_fnum(pitch, channel->chip->clock);
fmwrite(writefn, devinf->dataPtr, 0xa0 + chip_channel, block_fnum & 0xff);
fmwrite(writefn, devinf->dataPtr, 0xb0 + chip_channel, (channel->chip->channels[chip_channel].on ? 0x20 : 0x00) | block_fnum >> 8);
}
static void fmtoy_ym3812_pitch_bend(struct fmtoy *fmtoy, uint8_t chip_channel, float pitch, struct fmtoy_channel *channel) {
fmtoy_ym3812_set_pitch(fmtoy, chip_channel, pitch, channel);
}
static void fmtoy_ym3812_note_on(struct fmtoy *fmtoy, uint8_t chip_channel, float pitch, uint8_t velocity, struct fmtoy_channel *channel) {
fmtoy_ym3812_set_pitch(fmtoy, chip_channel, pitch, channel);
}
static void fmtoy_ym3812_note_off(struct fmtoy *fmtoy, uint8_t chip_channel, uint8_t velocity, struct fmtoy_channel *channel) {
fmtoy_ym3812_set_pitch(fmtoy, chip_channel, channel->chip->channels[chip_channel].pitch, channel);
}
static void fmtoy_ym3812_render(struct fmtoy *fmtoy, stream_sample_t **buffers, int num_samples, struct fmtoy_channel *channel) {
DEV_INFO *devinf = channel->chip->data;
devinf->devDef->Update(devinf->dataPtr, num_samples, buffers);
}
struct fmtoy_chip fmtoy_chip_ym3812 = {
.name = "YM3812",
.init = fmtoy_ym3812_init,
.destroy = fmtoy_ym3812_destroy,
.program_change = fmtoy_ym3812_program_change,
.pitch_bend = fmtoy_ym3812_pitch_bend,
.note_on = fmtoy_ym3812_note_on,
.note_off = fmtoy_ym3812_note_off,
.render = fmtoy_ym3812_render,
.max_poliphony = 9,
};