-
Notifications
You must be signed in to change notification settings - Fork 101
/
Copy pathsfc_play.h
412 lines (332 loc) · 11.1 KB
/
sfc_play.h
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
#pragma once
// License: MIT http://opensource.org/licenses/MIT
// Author: dustpg mailto:[email protected]
#include <stdint.h>
//#define SFC_SMF_DEFINED
// 目前使用16.16定点小数, 可以换成6.10~8.8的16bit
typedef uint32_t sfc_fixed_t;
#define SFC_FIXED(x) (x << 16)
// 创建
static inline sfc_fixed_t sfc_fixed_make(uint32_t a, uint32_t b) {
// 防溢出操作
// 整数部分
const uint32_t part0 = a / b;
const uint32_t hi16 = part0 << 16;
// 小数部分
const uint32_t part1 = a % b;
const uint32_t lo16 = (part1 << 16) / b;
return hi16 | lo16;
}
// 增加
static inline uint32_t sfc_fixed_add(sfc_fixed_t* a, sfc_fixed_t b) {
*a += b; const uint32_t rv = *a >> 16; *a &= 0xffff; return rv;
}
// -------------------------------------------------------
// 2A03
// -------------------------------------------------------
/*
95.88
square_out = -----------------------
8128
----------------- + 100
square1 + square2
159.79
tnd_out = ------------------------------
1
------------------------ + 100
triangle noise dmc
-------- + ----- + -----
8227 12241 22638
*/
/// <summary>
/// StepFC: 混方波
/// </summary>
/// <param name="sq1">The SQ1.</param>
/// <param name="sq2">The SQ2.</param>
/// <returns></returns>
static inline float sfc_mix_square(float sq1, float sq2) {
return 95.88f / ((8128.f / (sq1 + sq2)) + 100.f);
}
/// <summary>
/// StepFC: 混TND
/// </summary>
/// <param name="triangle">The triangle.</param>
/// <param name="noise">The noise.</param>
/// <param name="dmc">The DMC.</param>
/// <returns></returns>
static inline float sfc_mix_tnd(float triangle, float noise, float dmc) {
return 159.79f / (1.f / (triangle / 8227.f + noise / 12241.f + dmc / 22638.f) + 100.f);
}
/// <summary>
/// 方波状态
/// </summary>
typedef struct {
// 方波 周期(+1s) 预乘2
uint16_t period_x2;
// 方波 音量
uint8_t volume;
// 方波 占空比 预乘8
uint8_t duty;
} sfc_square_ch_state_t;
typedef sfc_square_ch_state_t sfc_square_channel_state_t;
/// <summary>
/// 三角波状态
/// </summary>
typedef struct {
// 三角波 周期
uint16_t period;
// 三角波 递增掩码
uint8_t inc_mask;
// 三角波 播放掩码
uint8_t play_mask;
} sfc_triangle_ch_state_t;
/// <summary>
/// 噪声状态
/// </summary>
typedef struct {
// 噪声 周期
uint16_t period;
// 噪声 右移位数 6[短模式], 1[长模式]
uint8_t count;
// 三角波 音量
uint8_t volume;
} sfc_noise_ch_state_t;
// typedef
struct sfc_famicom;
typedef struct sfc_famicom sfc_famicom_t;
/// <summary>
/// StepFC: 2A03 用 样本模式整型上下文
/// </summary>
typedef struct {
// 方波#1 输出
float sq1_output;
// 方波#2 输出
float sq2_output;
// 三角波 输出
float tri_output;
// 噪音 输出
float noi_output;
// DMC 输出
float dmc_output;
// 方波#1 状态
sfc_square_ch_state_t sq1_state;
// 方波#2 状态
sfc_square_ch_state_t sq2_state;
// 三角波状态
sfc_triangle_ch_state_t tri_state;
// 噪音状态
sfc_noise_ch_state_t noi_state;
// 定点小数 方波#1
sfc_fixed_t sq1_clock;
// 定点小数 方波#2
sfc_fixed_t sq2_clock;
// 定点小数 三角波澜
sfc_fixed_t tri_clock;
// 定点小数 噪音
sfc_fixed_t noi_clock;
// 定点小数 DMC
sfc_fixed_t dmc_clock;
} sfc_2a03_smi_ctx_t;
// 2A03 整型采样模式 - 采样
void sfc_2a03_smi_sample(sfc_famicom_t*, sfc_2a03_smi_ctx_t*, const float[], sfc_fixed_t cps);
// 2A03 整型采样模式 - 更新方波#1
void sfc_2a03_smi_update_sq1(const sfc_famicom_t*, sfc_2a03_smi_ctx_t*);
// 2A03 整型采样模式 - 更新方波#2
void sfc_2a03_smi_update_sq2(const sfc_famicom_t*, sfc_2a03_smi_ctx_t*);
// 2A03 整型采样模式 - 更新三角波
void sfc_2a03_smi_update_tri(const sfc_famicom_t*, sfc_2a03_smi_ctx_t*);
// 2A03 整型采样模式 - 更新噪音
void sfc_2a03_smi_update_noi(const sfc_famicom_t*, sfc_2a03_smi_ctx_t*);
// -------------------------------------------------------
// VRC6
// -------------------------------------------------------
/// <summary>
/// StepFC: VRC7 用 样本模式整型上下文
/// </summary>
typedef struct {
// 方波#1 输出
float square1_output;
// 方波#2 输出
float square2_output;
// 锯齿波输出
float sawtooth_output;
// 方波#1 定点小数
sfc_fixed_t sq1_clock;
// 方波#2 定点小数
sfc_fixed_t sq2_clock;
// 锯齿波 定点小数
sfc_fixed_t saw_clock;
} sfc_vrc6_smi_ctx_t;
// VRC6 整型采样模式 - 采样
void sfc_vrc6_smi_sample(sfc_famicom_t*, sfc_vrc6_smi_ctx_t*, const float[], sfc_fixed_t cps);
// -------------------------------------------------------
// VRC7
// -------------------------------------------------------
/// <summary>
/// StepFC: VRC7 用 样本模式整型上下文
/// </summary>
typedef struct {
// 输出
float output[6];
// 合成
float mixed;
// 定点小数
sfc_fixed_t clock;
} sfc_vrc7_smi_ctx_t;
// VRC7 整型采样模式 - 采样
void sfc_vrc7_smi_sample(sfc_famicom_t*, sfc_vrc7_smi_ctx_t*, const float[], sfc_fixed_t cps);
// -------------------------------------------------------
// FDS1
// -------------------------------------------------------
/// <summary>
/// StepFC: FDS1 用 样本模式整型上下文
/// </summary>
typedef struct {
// 输出
float output;
// 定点小数 音量包络
sfc_fixed_t volenv_clock;
// 定点小数 调制包络
sfc_fixed_t modenv_clock;
// 定点小数 波输出
sfc_fixed_t wavout_clock;
// 定点小数 调制器
sfc_fixed_t mdunit_clock;
} sfc_fds1_smi_ctx_t;
// FDS1 整型采样模式 - 采样
void sfc_fds1_smi_sample(sfc_famicom_t*, sfc_fds1_smi_ctx_t*, const float[], sfc_fixed_t cps);
// 浮点版本
#ifdef SFC_SMF_DEFINED
// FDS 高级接口1
float sfc_fds1_get_output(sfc_famicom_t*);
void sfc_fds1_per_cpu_clock(sfc_famicom_t*);
// FDS 高级接口2
typedef struct {
float volenv_clock;
float volenv_tps;
float modenv_clock;
float modenv_tps;
float wavout_clock;
float mdunit_clock;
float mdunit_rate;
float cycle_remain;
} sfc_fds1_ctx_t;
float sfc_fds1_per_sample(sfc_famicom_t*, sfc_fds1_ctx_t*, float cps);
void sfc_fds1_samplemode_begin(sfc_famicom_t*, sfc_fds1_ctx_t*);
void sfc_fds1_samplemode_end(sfc_famicom_t*, sfc_fds1_ctx_t*);
#endif
// -------------------------------------------------------
// MMC5
// -------------------------------------------------------
/// <summary>
/// StepFC: MMC5 用 样本模式整型上下文
/// </summary>
typedef struct {
// 方波#1 输出
float sq1_output;
// 方波#2 输出
float sq2_output;
// PCM 输出
float pcm_output;
// 方波#1 状态
sfc_square_ch_state_t sq1_state;
// 方波#2 状态
sfc_square_ch_state_t sq2_state;
// 定点小数 方波#1
sfc_fixed_t sq1_clock;
// 定点小数 方波#2
sfc_fixed_t sq2_clock;
} sfc_mmc5_smi_ctx_t;
// MMC5 整型采样模式 - 采样
void sfc_mmc5_smi_sample(sfc_famicom_t*, sfc_mmc5_smi_ctx_t*, const float[], sfc_fixed_t cps);
// MMC5 整型采样模式 - 更新方波#1
void sfc_mmc5_smi_update_sq1(const sfc_famicom_t*, sfc_mmc5_smi_ctx_t*);
// MMC5 整型采样模式 - 更新方波#2
void sfc_mmc5_smi_update_sq2(const sfc_famicom_t*, sfc_mmc5_smi_ctx_t*);
// MMC5 整型采样模式 - 更新PCM
//void sfc_mmc5_smi_update_pcm(const sfc_famicom_t*, sfc_mmc5_smi_ctx_t*);
// 浮点版本
#ifdef SFC_SMF_DEFINED
typedef struct {
// 声道状态
sfc_square_ch_state_t state;
// 方波 时钟周期 - 浮点误差修正
float clock;
// 方波 浮点周期
float period;
// 方波 输出音量
float output;
}sfc_mmc5_square_ctx_t;
typedef struct {
sfc_mmc5_square_ctx_t squ1;
sfc_mmc5_square_ctx_t squ2;
} sfc_mmc5_ctx_t;
void sfc_mmc5_per_sample(sfc_famicom_t*, sfc_mmc5_ctx_t*, float cps);
void sfc_mmc5_samplemode_begin(sfc_famicom_t*, sfc_mmc5_ctx_t*);
void sfc_mmc5_samplemode_end(sfc_famicom_t*, sfc_mmc5_ctx_t*);
#endif
// -------------------------------------------------------
// N163
// -------------------------------------------------------
/// <summary>
/// StepFC: FME7用 样本模式整型上下文
/// </summary>
/// <remarks>
/// 各个声道直接访问 .apu.fme7 数据
/// </remarks>
typedef struct {
// 输出
float output;
// 副Mapper指定权重
float subweight;
// 定点小数 包络用时钟数
sfc_fixed_t clock;
} sfc_n163_smi_ctx_t;
// N163 整型采样模式 - 采样
void sfc_n163_smi_sample(sfc_famicom_t*, sfc_n163_smi_ctx_t*, const float[], sfc_fixed_t cps, uint8_t mode);
// N163 整型采样模式 - 更新副权重
void sfc_n163_smi_update_subweight(const sfc_famicom_t*, sfc_n163_smi_ctx_t* );
// 浮点版本
#ifdef SFC_SMF_DEFINED
typedef struct {
float clock;
float subweight;
} sfc_n163_ctx_t;
float sfc_n163_per_sample(sfc_famicom_t*, sfc_n163_ctx_t*, float cps, uint8_t mode);
void sfc_n163_samplemode_begin(sfc_famicom_t*, sfc_n163_ctx_t*);
void sfc_n163_samplemode_end(sfc_famicom_t*, sfc_n163_ctx_t*);
#endif
// -------------------------------------------------------
// FME-7(5B)
// -------------------------------------------------------
/// <summary>
/// StepFC: FME7用 样本模式整型上下文
/// </summary>
typedef struct {
// 输出
float output[3];
// 声道用时钟数 定点小数
sfc_fixed_t chn_clock[3];
// 噪音用时钟数 定点小数
sfc_fixed_t noi_clock;
// 包络用时钟数 定点小数
sfc_fixed_t env_clock;
} sfc_fme7_smi_ctx_t;
// FME7 整型采样模式 - 采样
void sfc_fme7_smi_sample(sfc_famicom_t*, sfc_fme7_smi_ctx_t*, const float[], sfc_fixed_t cps);
// 浮点版本
#ifdef SFC_SMF_DEFINED
typedef struct {
struct sfc_fme7_tone_s {
float period;
float clock;
} ch[3];
float noise_period;
float noise_clock;
float env_period;
float env_clock;
} sfc_fme7_ctx_t;
float sfc_fme7_per_sample(sfc_famicom_t*, sfc_fme7_ctx_t*, float cps);
void sfc_fme7_samplemode_begin(sfc_famicom_t*, sfc_fme7_ctx_t*);
void sfc_fme7_samplemode_end(sfc_famicom_t*, sfc_fme7_ctx_t*);
#endif