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
|
#ifdef DSP_CPP
inline void DSP::voice_output(voice_t& v, bool channel) {
//apply left/right volume
int amp = (state.t_output * (int8)VREG(voll + channel)) >> 7;
//add to output total
state.t_main_out[channel] += amp;
state.t_main_out[channel] = sclamp<16>(state.t_main_out[channel]);
//optionally add to echo total
if(state.t_eon & v.vbit) {
state.t_echo_out[channel] += amp;
state.t_echo_out[channel] = sclamp<16>(state.t_echo_out[channel]);
}
}
void DSP::voice_1(voice_t& v) {
state.t_dir_addr = (state.t_dir << 8) + (state.t_srcn << 2);
state.t_srcn = VREG(srcn);
}
void DSP::voice_2(voice_t& v) {
//read sample pointer (ignored if not needed)
uint16 addr = state.t_dir_addr;
if(!v.kon_delay) addr += 2;
uint8 lo = smp.apuram[(uint16)(addr + 0)];
uint8 hi = smp.apuram[(uint16)(addr + 1)];
state.t_brr_next_addr = ((hi << 8) + lo);
state.t_adsr0 = VREG(adsr0);
//read pitch, spread over two clocks
state.t_pitch = VREG(pitchl);
}
void DSP::voice_3(voice_t& v) {
voice_3a(v);
voice_3b(v);
voice_3c(v);
}
void DSP::voice_3a(voice_t& v) {
state.t_pitch += (VREG(pitchh) & 0x3f) << 8;
}
void DSP::voice_3b(voice_t& v) {
state.t_brr_byte = smp.apuram[(uint16)(v.brr_addr + v.brr_offset)];
state.t_brr_header = smp.apuram[(uint16)(v.brr_addr)];
}
void DSP::voice_3c(voice_t& v) {
//pitch modulation using previous voice's output
if(state.t_pmon & v.vbit) {
state.t_pitch += ((state.t_output >> 5) * state.t_pitch) >> 10;
}
if(v.kon_delay) {
//get ready to start BRR decoding on next sample
if(v.kon_delay == 5) {
v.brr_addr = state.t_brr_next_addr;
v.brr_offset = 1;
v.buf_pos = 0;
state.t_brr_header = 0; //header is ignored on this sample
}
//envelope is never run during KON
v.env = 0;
v.hidden_env = 0;
//disable BRR decoding until last three samples
v.interp_pos = 0;
v.kon_delay--;
if(v.kon_delay & 3) v.interp_pos = 0x4000;
//pitch is never added during KON
state.t_pitch = 0;
}
//gaussian interpolation
int output = gaussian_interpolate(v);
//noise
if(state.t_non & v.vbit) {
output = (int16)(state.noise << 1);
}
//apply envelope
state.t_output = ((output * v.env) >> 11) & ~1;
v.t_envx_out = v.env >> 4;
//immediate silence due to end of sample or soft reset
if(REG(flg) & 0x80 || (state.t_brr_header & 3) == 1) {
v.env_mode = env_release;
v.env = 0;
}
if(state.every_other_sample) {
//KOFF
if(state.t_koff & v.vbit) {
v.env_mode = env_release;
}
//KON
if(state.kon & v.vbit) {
v.kon_delay = 5;
v.env_mode = env_attack;
}
}
//run envelope for next sample
if(!v.kon_delay) envelope_run(v);
}
void DSP::voice_4(voice_t& v) {
//decode BRR
state.t_looped = 0;
if(v.interp_pos >= 0x4000) {
brr_decode(v);
v.brr_offset += 2;
if(v.brr_offset >= 9) {
//start decoding next BRR block
v.brr_addr = (uint16)(v.brr_addr + 9);
if(state.t_brr_header & 1) {
v.brr_addr = state.t_brr_next_addr;
state.t_looped = v.vbit;
}
v.brr_offset = 1;
}
}
//apply pitch
v.interp_pos = (v.interp_pos & 0x3fff) + state.t_pitch;
//keep from getting too far ahead (when using pitch modulation)
if(v.interp_pos > 0x7fff) v.interp_pos = 0x7fff;
//output left
voice_output(v, 0);
}
void DSP::voice_5(voice_t& v) {
//output right
voice_output(v, 1);
//ENDX, OUTX and ENVX won't update if you wrote to them 1-2 clocks earlier
state.endx_buf = REG(endx) | state.t_looped;
//clear bit in ENDX if KON just began
if(v.kon_delay == 5) state.endx_buf &= ~v.vbit;
}
void DSP::voice_6(voice_t& v) {
state.outx_buf = state.t_output >> 8;
}
void DSP::voice_7(voice_t& v) {
//update ENDX
REG(endx) = (uint8)state.endx_buf;
state.envx_buf = v.t_envx_out;
}
void DSP::voice_8(voice_t& v) {
//update OUTX
VREG(outx) = (uint8)state.outx_buf;
}
void DSP::voice_9(voice_t& v) {
//update ENVX
VREG(envx) = (uint8)state.envx_buf;
}
#endif
|