const GesChannelState.Trigger = 0; const GesChannelState.EnvState = 1; const GesChannelState.EnvVol = 2; const GesChannelState.Phase = 4; const GesChannelState.Size = 8; const GesState.Filter = GesChannelState.Size * 4; const GesState.Size = GesState.Filter + 8*4; const GesStateOffset = 32; const GesBufferOffset = 32 + GesState.Size; export fn gesSnd(t: i32) -> f32 { let baseAddr = 0!0x12c78; if !(t & 127) { let i: i32; loop clearLoop { (baseAddr + i)!GesBufferOffset = 0; branch_if (i := i + 4) < 128*4: clearLoop; } let ch: i32; loop channelLoop { let lazy channelState = baseAddr + GesStateOffset + ch * GesChannelState.Size; let lazy channelReg = baseAddr + ch * 6; let envState = channelState?GesChannelState.EnvState; let envVol = i32.load16_u(channelState, GesChannelState.EnvVol); let lazy oldTrigger = channelState?GesChannelState.Trigger; let lazy ctrl = channelReg?0; if (oldTrigger ^ ctrl) & (ctrl | 2) & 3 { envState = 1; envVol = 0; } channelState?GesChannelState.Trigger = ctrl; if envState { let lazy attack = channelReg?4 & 15; envVol = envVol + 12 * pow(1.675, (15 - attack) as f32) as i32; if envVol >= 65535 { envVol = 65535; envState = 0; } } else { let inline decay = (channelReg - (ctrl & 1))?5 >> 4; let inline dec = 8 * pow(1.5625, (15 - decay) as f32) as i32; envVol = envVol - ((dec * (envVol + 8192)) >> 16); let inline sustain = (channelReg?5 & 15) << 12; let lazy targetVol = (ctrl & 1) * sustain; if envVol < targetVol { envVol = targetVol; } } channelState?GesChannelState.EnvState = envState; i32.store16(envVol, channelState, GesChannelState.EnvVol); let inline note = i32.load16_u(channelReg, 2); let lazy freq = 440 as f32 * pow(2.0, (note - 69*256) as f32 / (12*256) as f32); let phaseInc = (freq * (65536.0 / 44100.0)) as i32; let phase = channelState!GesChannelState.Phase; let inline pulseWidth = channelReg?1; let phaseShift = (pulseWidth - 128) * 255; let invPhaseInc = 1 as f32 / phaseInc as f32; i = 0; let wave = ctrl >> 6; if wave < 2 { if wave { let pulsePhase1 = pulseWidth << 23; let pulsePhase2 = (511 - pulseWidth) << 23; loop sawLoop { let p = (phase ^ 32768) << 16; let saw = (p >> 16) - polyBlep(phase, invPhaseInc, -32767); let saw2 = select(p #>= pulsePhase1 & p #< pulsePhase2, -saw, saw); let saw2 = saw2 - polyBlep((p - pulsePhase1) >> 16, invPhaseInc, -saw) - polyBlep((p - pulsePhase2) >> 16, invPhaseInc, saw); (baseAddr + i)!(GesBufferOffset + 128*4) = saw2; phase = phase + phaseInc; branch_if (i := i + 4) < 64*4: sawLoop; } } else { let pulsePhase = 32768 + pulseWidth * 128; loop rectLoop { (baseAddr + i)!(GesBufferOffset + 128*4) = select((phase & 65535) < pulsePhase, -32768, 32767) - polyBlep(phase, invPhaseInc, -32767) - polyBlep(phase - pulsePhase, invPhaseInc, 32767); phase = phase + phaseInc; branch_if (i := i + 4) < 64*4: rectLoop; } } } else { if wave == 2 { let scale = pulseWidth + 256; loop triLoop { let s = phase << 16; s = (s ^ (s >> 31)); s = (s >> 8) * scale; s = (s ^ (s >> 31)); (baseAddr + i)!(GesBufferOffset + 128*4) = (s >> 15) - 32768; phase = phase + phaseInc; branch_if (i := i + 4) < 64*4: triLoop; } } else { loop noiseLoop { let s = phase >> 12; let inline pulse = ((phase >> 8) & 255) >= pulseWidth; s = s * 0x6746ba73; s = s ^ (s >> 15) * pulse; (baseAddr + i)!(GesBufferOffset + 128*4) = (s * 0x835776c7) >> 16; phase = phase + phaseInc; branch_if (i := i + 4) < 64*4: noiseLoop; } } } channelState!GesChannelState.Phase = phase; if ctrl & 32 { let lazy modSrc = (ch - 1) & 3; let inline channelState = baseAddr + GesStateOffset + modSrc * GesChannelState.Size; let inline channelReg = baseAddr + modSrc * 6; let inline note = i32.load16_u(channelReg, 2); let inline freq = 440 as f32 * pow(2.0, (note - 69*256) as f32 / (12*256) as f32); let phaseInc = (freq * (65536.0 / 44100.0)) as i32; let phase = channelState!GesChannelState.Phase; if modSrc > ch { phase = phase - (phaseInc << 6); } i = 0; loop ringLoop { let s = phase << 16; s = (s ^ (s >> 31)); (baseAddr + i)!(GesBufferOffset + 128*4) = ((baseAddr + i)!(GesBufferOffset + 128*4) * ((s >> 15) - 32768)) >> 15; phase = phase + phaseInc; branch_if (i := i + 4) < 64*4: ringLoop; } } let channelVol = ((baseAddr + (ch >> 1))?24 >> ((ch & 1) * 4)) & 15; envVol = envVol * channelVol / 15; let leftVol = (select(ctrl & 16, 0x3d5b, 0x6a79) >> (ch * 4)) & 15; let rightVol = 16 - leftVol; let lazy filter = (ctrl >> 2) & 3; i = 0; if filter < 2 { if filter { let f = (4096 as f32 - min(4096 as f32, 4096 as f32 * exp(freq * (-8.0 * 3.141 / 44100.0)))) as i32; let low = (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter); loop filterLoop { let in = ((baseAddr + i)!(GesBufferOffset + 128*4) * envVol) >> 18; low = low + (((in - low) * f) >> 12); (baseAddr + i * 2)!GesBufferOffset = (baseAddr + i * 2)!GesBufferOffset + ((low * leftVol) >> 4); (baseAddr + i * 2)!(GesBufferOffset + 4) = (baseAddr + i * 2)!(GesBufferOffset + 4) + ((low * rightVol) >> 4); branch_if (i := i + 4) < 64*4: filterLoop; (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter) = low; (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter + 4) = 0; } } else { loop mixLoop { let sample = ((baseAddr + i)!(GesBufferOffset + 128*4) * envVol) >> 18; (baseAddr + i * 2)!GesBufferOffset = (baseAddr + i * 2)!GesBufferOffset + ((sample * leftVol) >> 4); (baseAddr + i * 2)!(GesBufferOffset + 4) = (baseAddr + i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4); branch_if (i := i + 4) < 64*4: mixLoop; (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter) = sample; (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter + 4) = 0; } } } else { filter = filter - 2; let ctrl = (baseAddr + filter)?26; let note = i32.load16_u(baseAddr + filter * 2, 28); let inline freq = 440 as f32 * pow(2.0, (note - 69*256) as f32 / (12*256) as f32); let F = (8192 as f32 * sin(min(0.25, freq / 44100 as f32) * 3.1415)) as i32; let Q = 8192 - (ctrl >> 4) * (7000/15); let Qlimit = (8192*4096/F - F/2) * 3 / 4; if Q > Qlimit { Q = Qlimit; } let low_out = ctrl & 1; let high_out = (ctrl >> 1) & 1; let band_out = (ctrl >> 2) & 1; let low = (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter); let band = (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter + 4); loop filterLoop { let in = ((baseAddr + i)!(GesBufferOffset + 128*4) * envVol) >> 18; let high = in - low - ((band * Q) >> 12); band = band + ((F * high) >> 12); low = low + ((F * band) >> 12); let sample = low * low_out + high * high_out + band * band_out; (baseAddr + i * 2)!GesBufferOffset = (baseAddr + i * 2)!GesBufferOffset + ((sample * leftVol) >> 4); (baseAddr + i * 2)!(GesBufferOffset + 4) = (baseAddr + i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4); branch_if (i := i + 4) < 64*4: filterLoop; (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter) = low; (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter + 4) = band; } } branch_if (ch := ch + 1) < 4: channelLoop; } } ((baseAddr + (t & 127) * 4)!GesBufferOffset) as f32 / 32768 as f32 } fn polyBlep(transientPhase: i32, invPhaseInc: f32, magnitude: i32) -> i32 { let lazy t = ((transientPhase << 16) >> 16) as f32 * invPhaseInc; let lazy x = max(0 as f32, 1 as f32 - abs(t)); (f32.copysign(x * x, t) * magnitude as f32) as i32 }