Created
June 8, 2013 00:16
-
-
Save gtrak/5733287 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns com.gtrak.emu.chips.ym2612) | |
(defmacro defs | |
[& def-specs] | |
(let [def-specs (partition 2 def-specs) | |
forms (for [[var val] def-specs] | |
`(def ~var ~val))] | |
`(do ~@forms))) | |
;; envelope generator | |
(defs | |
ENV_BITS 10 | |
ENV_LEN (bit-shift-left 1 ENV_BITS) | |
ENV_STEP (/ 128.0 ENV_LEN) | |
MAX_ATT_INDEX (dec ENV_LEN) ;; 1023 | |
MIN_ATT_INDEX 0 ;; 0 | |
EG_ATT 4 | |
EG_DEC 3 | |
EG_SUS 2 | |
EG_REL 1 | |
EG_OFF 0 | |
;; phase generator (detune mask) | |
DT_BITS 17 | |
DT_LEN (bit-shift-left 1 DT_BITS) | |
DT_MASK (dec DT_LEN) | |
;; operator unit | |
SIN_BITS 10 | |
SIN_LEN (bit-shift-left 1 SIN_BITS) | |
SIN_MASK (dec SIN_LEN) | |
TL_RES_LEN 256 ;; 8 bits addressing (real chip) | |
TL_BITS 14 ;; channel output | |
;; TL_TAB_LEN is calculated as: | |
;; 13 - sinus amplitude bits (Y axis) | |
;; 2 - sinus sign bit (Y axis) | |
;; TL_RES_LEN - sinus resolution (X axis) | |
TL_TAB_LEN (* 13 2 TL_RES_LEN) | |
tl_tab [] ;;static signed int tl_tab[TL_TAB_LEN]; | |
ENV_QUIET (bit-shift-right TL_TAB_LEN 3) | |
;; sin waveform table in 'decibel' scale | |
;; static unsigned int sin_tab[SIN_LEN]; | |
sin_tab []) | |
;; sustain level table (3dB per step) | |
;; bit0 bit1 bit2 bit3 bit4 bit5 bit6 | |
;; 1 2 4 8 16 32 64 (value) | |
;; 0.75 1.5 3 6 12 24 48 (dB) | |
;; 0 - 15: 0 3 6 9 12 15 18 21 24 27 30 33 36 39 42 93 (dB) | |
;; attenuation value (10 bits) = (SL << 2) << 3 | |
;;static const UINT32 sl_table[16]= | |
;; {{ | |
;; SC( 0) SC( 1) SC( 2) SC(3 ) SC(4 ) SC(5 ) SC(6 ) SC( 7) | |
;; SC( 8) SC( 9) SC(10) SC(11) SC(12) SC(13) SC(14) SC(31) | |
;; } ; | |
(let [SC (fn [db] (* db (/ 4.0 ENV_STEP)))] | |
(def sl_table (mapv SC (concat (range 15) [31])))) | |
(def RATE_STEPS 8) | |
(def eg_inc | |
;; dimension: 19*RATE_STEPS | |
;; cycle:0 1 2 3 4 5 6 7 | |
[0 1 0 1 0 1 0 1 ;; rates 00..11 0 (increment by 0 or 1) | |
0 1 0 1 1 1 0 1 ;; rates 00..11 1 | |
0 1 1 1 0 1 1 1 ;; rates 00..11 2 | |
0 1 1 1 1 1 1 1 ;; rates 00..11 3 | |
1 1 1 1 1 1 1 1 ;; rate 12 0 (increment by 1) | |
1 1 1 2 1 1 1 2 ;; rate 12 1 | |
1 2 1 2 1 2 1 2 ;; rate 12 2 | |
1 2 2 2 1 2 2 2 ;; rate 12 3 | |
2 2 2 2 2 2 2 2 ;; rate 13 0 (increment by 2) | |
2 2 2 4 2 2 2 4 ;; rate 13 1 | |
2 4 2 4 2 4 2 4 ;; rate 13 2 | |
2 4 4 4 2 4 4 4 ;; rate 13 3 | |
4 4 4 4 4 4 4 4 ;; rate 14 0 (increment by 4) | |
4 4 4 8 4 4 4 8 ;; rate 14 1 | |
4 8 4 8 4 8 4 8 ;; rate 14 2 | |
4 8 8 8 4 8 8 8 ;; rate 14 3 | |
8 8 8 8 8 8 8 8 ;; rates 15 0 15 1 15 2 15 3 (increment by 8) | |
16 16 16 16 16 16 16 16 ;; rates 15 2 15 3 for attack | |
0 0 0 0 0 0 0 0 ] ;; infinity rates for attack and decay(s) | |
) | |
(let [O (fn [a] (* a RATE_STEPS))] | |
;;note that there is no 17) in this table - it's directly in the code | |
(def eg_rate_select | |
;; dimension: [32+64+32] Envelope Generator rates (32 + 64 rates + 32 RKS) | |
(mapv | |
O | |
[;; 32 infinite time rates (same as Rate 0) | |
18 18 18 18 18 18 18 18 | |
18 18 18 18 18 18 18 18 | |
18 18 18 18 18 18 18 18 | |
18 18 18 18 18 18 18 18 | |
18 18 0 0 | |
0 0 2 2 ;; Nemesis's tests | |
0 1 2 3 | |
0 1 2 3 | |
0 1 2 3 | |
0 1 2 3 | |
0 1 2 3 | |
0 1 2 3 | |
0 1 2 3 | |
0 1 2 3 | |
0 1 2 3 | |
0 1 2 3 | |
;; rate 12 | |
4 5 6 7 | |
;; rate 13 | |
8 9 10 11 | |
;; rate 14 | |
12 13 14 15 | |
;; rate 15 | |
16 16 16 16 | |
;; 32 dummy rates (same as 15 3) | |
16 16 16 16 16 16 16 16 | |
16 16 16 16 16 16 16 16 | |
16 16 16 16 16 16 16 16 | |
16 16 16 16 16 16 16 16]))) | |
;;rate 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
;;shift 11 10 9 8 7 6 5 4 3 2 1 0 0 0 0 0 | |
;;mask 2047 1023 511 255 127 63 31 15 7 3 1 0 0 0 0 0 | |
;; dimension [32+64+32] | |
(def eg_rate_shift | |
[;; Envelope Generator counter shifts (32 + 64 rates + 32 RKS) | |
;; fixed (should be the same as rate 0 even if it makes no difference since increment value is 0 for these rates) | |
11 11 11 11 11 11 11 11 | |
11 11 11 11 11 11 11 11 | |
11 11 11 11 11 11 11 11 | |
11 11 11 11 11 11 11 11 | |
;; rates 00-11 | |
11 11 11 11 | |
10 10 10 10 | |
9 9 9 9 | |
8 8 8 8 | |
7 7 7 7 | |
6 6 6 6 | |
5 5 5 5 | |
4 4 4 4 | |
3 3 3 3 | |
2 2 2 2 | |
1 1 1 1 | |
0 0 0 0 | |
;; rate 12 | |
0 0 0 0 | |
;; rate 13 | |
0 0 0 0 | |
;; rate 14 | |
0 0 0 0 | |
;; rate 15 | |
0 0 0 0 | |
;; 32 dummy rates (same as 15 3) | |
0 0 0 0 0 0 0 0 | |
0 0 0 0 0 0 0 0 | |
0 0 0 0 0 0 0 0 | |
0 0 0 0 0 0 0 0]) | |
;; dimension: [4 * 32]= | |
(def dt_tab | |
[;; this is YM2151 and YM2612 phase increment data (in 10.10 fixed point format) | |
;; FD=0 | |
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | |
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | |
;; FD=1 | |
0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2 | |
2 3 3 3 4 4 4 5 5 6 6 7 8 8 8 8 | |
;; FD=2 | |
1 1 1 1 2 2 2 2 2 3 3 3 4 4 4 5 | |
5 6 6 7 8 8 9 10 11 12 13 14 16 16 16 16 | |
;; FD=3 | |
2 2 2 2 2 3 3 3 4 4 4 5 5 6 6 7 | |
8 8 9 10 11 12 13 14 16 17 19 20 22 22 22 22 | |
]) | |
;; OPN key frequency number -> key code follow table | |
;; fnum higher 4bit -> keycode lower 2bit | |
(def opn_fktable [0 0 0 0 0 0 0 1 2 3 3 3 3 3 3 3]) | |
;; 8 LFO speed parameters | |
;; each value represents number of samples that one LFO level will last for | |
(def lfo_samples_per_step [108 77 71 67 62 44 8 5]) | |
(def lfo_ams_depth_shift = [8 3 1 0]) | |
;; register number to channel number , slot offset | |
(defn OPN_CHAN [N] (bit-and N 3)) | |
(defn OPN_SLOT [N] (bit-and (bit-shift-right N 2) 3)) | |
;; slot number | |
(defs | |
SLOT1 0 | |
SLOT2 2 | |
SLOT3 1 | |
SLOT4 3) | |
;; struct describing a single operator (SLOT) | |
(defrecord FM_SLOT | |
[DT; ;; detune :dt_tab[DT] | |
KSR; ;; key scale rate :3-KSR | |
ar; ;; attack rate | |
d1r; ;; decay rate | |
d2r; ;; sustain rate | |
rr; ;; release rate | |
ksr; ;; key scale rate :kcode>>(3-KSR) | |
mul; ;; multiple :ML_TABLE[ML] | |
;; Phase Generator | |
phase; ;; phase counter | |
Incr; ;; phase step | |
;; Envelope Generator | |
state; ;; phase type | |
tl; ;; total level: TL << 3 | |
volume; ;; envelope counter | |
sl; ;; sustain level:sl_table[SL] | |
vol_out; ;; current output from EG circuit (without AM from LFO) | |
eg_sh_ar; ;; (attack state) | |
eg_sel_ar; ;; (attack state) | |
eg_sh_d1r; ;; (decay state) | |
eg_sel_d1r; ;; (decay state) | |
eg_sh_d2r; ;; (sustain state) | |
eg_sel_d2r; ;; (sustain state) | |
eg_sh_rr; ;; (release state) | |
eg_sel_rr; ;; (release state) | |
ssg; ;; SSG-EG waveform | |
ssgn; ;; SSG-EG negated output | |
key; ;; 0=last key was KEY OFF, 1=KEY ON | |
;; LFO | |
AMmask; ;; AM enable flag | |
]) | |
(defrecord FM_CH | |
[^FM_SLOT SLOT; ;; four SLOTs (operators) | |
ALGO; ;; algorithm | |
FB; ;; feedback shift | |
op1_out; ;; length 2, op1 output for feedback | |
connect1; ;; SLOT1 output pointer | |
connect3; ;; SLOT3 output pointer | |
connect2; ;; SLOT2 output pointer | |
connect4; ;; SLOT4 output pointer | |
mem_connect; ;; where to put the delayed sample (MEM) | |
mem_value; ;; delayed sample (MEM) value | |
pms; ;; channel PMS | |
ams; ;; channel AMS | |
fc; ;; fnum,blk | |
kcode; ;; key code | |
block_fnum; ;; blk/fnum value (for LFO PM calculations) | |
]) | |
(defrecord FM_ST | |
[address; ;; address register | |
status; ;; status flag | |
mode; ;; mode CSM / 3SLOT | |
fn_h; ;; freq latch | |
TA; ;; timer a value | |
TAL; ;; timer a base | |
TAC; ;; timer a counter | |
TB; ;; timer b value | |
TBL; ;; timer b base | |
TBC; ;; timer b counter | |
dt_tab; [8][32]; ;; DeTune table | |
]) | |
;;********************************************************* | |
;; OPN unit | |
;;********************************************************* | |
;; OPN 3slot struct | |
(defrecord FM_3SLOT | |
[fc;[3]; ;; fnum3,blk3: calculated | |
fn_h; ;; freq3 latch | |
kcode; [3]; ;; key code | |
block_fnum; [3]; ;; current fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) | |
key_csm; ;; CSM mode Key-ON flag | |
]) | |
;; OPN/A/B common state | |
(defrecord FM_OPN | |
[^FM_ST ST; ;; general state | |
^FM_3SLOT SL3; ;; 3 slot mode state | |
pan; [6*2]; ;; fm channels output masks (0xffffffff = enable) | |
;; EG | |
eg_cnt; ;; global envelope generator counter | |
eg_timer; ;; global envelope generator counter works at frequency = chipclock/144/3 | |
;; LFO | |
lfo_cnt; ;; current LFO phase (out of 128) | |
lfo_timer; ;; current LFO phase runs at LFO frequency | |
lfo_timer_overflow; ;; LFO timer overflows every N samples (depends on LFO frequency) | |
LFO_AM; ;; current LFO AM step | |
LFO_PM; ;; current LFO PM step | |
]) | |
;;********************************************************* | |
;; YM2612 chip | |
;;********************************************************* | |
(defrecord YM2612 | |
[^FM_CH CH; [6]; ;; channel state | |
dacen; ;; DAC mode | |
dacout; ;; DAC output | |
^FM_OPN OPN; ;; OPN state | |
]) | |
(defrecord State | |
[tl_tab sin_tab lfo_pm_table ^YM2612 ym2612 | |
m2 c1 c2 ;; Phase Modulation input for operators 2,3,4 | |
mem ;; one sample delay memory | |
out_fm ;; [8] ;; outputs of working channels | |
]) | |
(defn update-volumes | |
[slot] | |
(let [{:keys [ar ksr volume s1]} slot | |
sus-or-dec (if (= s1 MIN_ATT_INDEX) EG_SUS EG_DEC)] | |
(if (< (+ ar ksr) 94) | |
(assoc slot :state (if (< volume MIN_ATT_INDEX) | |
sus-or-dec | |
EG_ATT)) | |
(-> (assoc slot :volume MIN_ATT_INDEX) | |
(assoc :state sus-or-dec))))) | |
(defn update-eg | |
[slot] | |
(let [{:keys [ssg ssgn volume t1]} slot] | |
(assoc slot :vol_out (+ t1 (if (and (bit-and ssg 0x08) (bit-or ssgn (bit-and ssg 0x04))) | |
(bit-and (- 0x200 volume) MAX_ATT_INDEX) | |
volume))))) | |
(defn FM_KEYON | |
[state ^FM_CH ch s] | |
(let [slot (ch :SLOT s)] | |
(if (and (not (:key slot)) (not (-> state :ym2612 :OPN :SL3 :key_csm))) | |
(let [slot (-> slot | |
(assoc :phase 0) | |
(assoc :ssgn 0) | |
update-volumes | |
update-eg | |
(assoc :key y1))] | |
(assoc-in ch [:SLOT s] slot))))) | |
(defn FM_KEYOFF | |
[state ^FM_CH ch s] | |
(let [slot (ch :SLOT s)] | |
(if (and (:key slot) (not (-> state :ym2612 :OPN :SL3 :key_csm))) | |
(if (> (:state slot) EG_REL) | |
(assoc slot :state EG_REL)) | |
(let [slot (-> slot | |
(assoc :phase 0) | |
(assoc :ssgn 0) | |
update-volumes | |
update-eg | |
(assoc :key y1))] | |
(assoc-in ch [:SLOT s] slot))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment