diff --git a/examples/curlywas/tim_ges.cwa b/examples/curlywas/tim_ges.cwa index 1e01df7..77eb363 100644 --- a/examples/curlywas/tim_ges.cwa +++ b/examples/curlywas/tim_ges.cwa @@ -1,6 +1,4 @@ -include "../include/microw8-api.cwa" - -fn melody(ch: i32, T: i32) { +fn melody(ch: i32, t: i32, T: i32) { let inline riff_pos = abs(((T&31) - 16) as f32) as i32; let lazy shift = ((1-((T>>5)&3))%2-1) * 2; @@ -10,197 +8,52 @@ fn melody(ch: i32, T: i32) { let inline melody_note = shift + octave - riff_note; ch?0 = ((T&1) << 1) | 0x4; // note trigger - ch?4 = 0xa; // attack, decay - ch?5 = 0xa; // sustain, release ch?3 = melody_note + 64; + + let inline arp_note = shift + ((0x85>>((t/2)%3*4)) & 15) - 1; + 80?3 = arp_note + 64; } export fn upd() { - let T = 32!32 / 116; - melody(92, T); - melody(98, T - 3); - 0x69?0 = 0xaf; -} + let lazy t = 32!32 / (1000/60); + let lazy T = t / 8; + melody(98, t, T - 3); + melody(92, t, T); -export fn snd(t: i32) -> f32 { - gesSample(t) -} + 80?0 = ((T >= 256) & (T/12+(T-3)/12)) * 2 | 0x4; // arp trigger -const GesChannelState.Trigger = 0; -const GesChannelState.EnvState = 1; -const GesChannelState.EnvVol = 2; -const GesChannelState.Phase = 4; -const GesChannelState.Size = 6; - -const GesState.Filter = GesChannelState.Size * 4; -const GesState.Size = GesState.Filter + 8*4; - -const GesStateOffset = 112; -const GesBufferOffset = 112 + GesState.Size; - -fn gesSample(t: i32) -> f32 { - if !(t & 127) { - let i: i32; - loop clearLoop { - i!GesBufferOffset = 0; - branch_if (i := i + 4) < 128*8: clearLoop; - } - - let ch: i32; - loop channelLoop { - let channelState = GesStateOffset + ch * GesChannelState.Size; - let channelReg = 80 + ch * 6; - let envState = channelState?GesChannelState.EnvState; - let envVol = i32.load16_u(channelState, GesChannelState.EnvVol); - - let oldTrigger = channelState?GesChannelState.Trigger; - let ctrl = channelReg?0; - channelState?GesChannelState.Trigger = ctrl; - if (oldTrigger ^ ctrl) & (ctrl | 2) & 3 { - envState = 1; - envVol = 0; - } - - if envState { - envVol = envVol + (16384 / ((channelReg?4 >> 4) + 1)); - if envVol >= 65535 { - envVol = 65535; - envState = 0; - } - } else { - if !envState & ctrl { - envVol = envVol - (16 - (channelReg?4 & 15)) * 48; - let sustain = (channelReg?5 >> 4) * 4096; - if envVol < sustain { - envVol = sustain; - } - } else { - envVol = envVol - (16 - (channelReg?5 & 15)) * 48; - if envVol < 0 { - envVol = 0; - } - } - } - channelState?GesChannelState.EnvState = envState; - - i32.store16(envVol, channelState, GesChannelState.EnvVol); - - 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 = i32.load16_u(channelState, GesChannelState.Phase) << 8; - - i = 0; - let wave = ctrl >> 6; - if wave < 2 { - if wave { - loop sawLoop { - i!(GesBufferOffset + 128*4) = (phase & 65535) - 32768; - phase = phase + phaseInc; - branch_if (i := i + 4) < 64*4: sawLoop; - } - } - else - { - loop rectLoop { - i!(GesBufferOffset + 128*4) = select(phase & 32768, -32768, 32767); - phase = phase + phaseInc; - branch_if (i := i + 4) < 64*4: rectLoop; - } - } - } else { - if wave == 2 { - loop triLoop { - let s = phase << 16; - s = s ^ (s >> 31); - 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) & 4095; - s = s * 0x6746ba73; - s = s ^ (s >> 15); - i!(GesBufferOffset + 128*4) = (s * 0x83567a92) >> 16; - phase = phase + phaseInc; - branch_if (i := i + 4) < 64*4: noiseLoop; - } - } - } - - i32.store16(phase >> 8, channelState, GesChannelState.Phase); - - let channelVol = ((ch >> 1)?0x68 >> ((ch & 1) * 4)) & 15; - envVol = envVol * channelVol / 15; - - let leftVol = (0x4c6a >> (ch * 4)) & 15; - let rightVol = 16 - leftVol; - - let filter = ((ctrl >> 2) & 3) - 1; - - i = 0; - if filter #> 1 { - loop mixLoop { - let sample = (i!(GesBufferOffset + 128*4) * envVol) >> 18; - (i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + ((sample * leftVol) >> 4); - (i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4); - branch_if (i := i + 4) < 64*4: mixLoop; - } - } else { - let ctrl = filter?0x6a; - let note = i32.load16_u(filter * 2, 0x6c); - let inline freq = 440 as f32 * pow(2.0, (note - 69*256) as f32 / (12*256) as f32); - let F = min(4096 as f32, 8192 as f32 * sin(freq * (3.1415 / 44100.0))) as i32; - let Q = 7000 - ctrl * (6000/255); - let low_out = ctrl & 1; - let high_out = (ctrl >> 1) & 1; - let band_out = (ctrl >> 2) & 1; - let low = (ch * 8)!(GesStateOffset + GesState.Filter); - let band = (ch * 8)!(GesStateOffset + GesState.Filter + 4); - loop filterLoop { - let in = (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; - (i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + ((sample * leftVol) >> 4); - (i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4); - branch_if (i := i + 4) < 64*4: filterLoop; - } - (ch * 8)!(GesStateOffset + GesState.Filter) = low; - (ch * 8)!(GesStateOffset + GesState.Filter + 4) = band; - } - - branch_if (ch := ch + 1) < 4: channelLoop; - } + if T >= 128 { + let inline bass_step = T % 8; + 86?3 = if bass_step / 2 == 2 { + 86?0 = 0xc2; + 90 + } else { + 86?0 = ((197 >> bass_step) & 1) | 0x48; + ((T & 4) * ((T & 7) - 1)) / 2 + 28 + }; } - (((t & 127) * 4)!GesBufferOffset) as f32 / 32768 as f32 -} - -fn memclr(base: i32, size: i32) { - loop bytes { - (base + (size := size - 1))?0 = 0; - branch_if size: bytes; - } -} - -start fn start() { - memclr(0, 64); - memclr(112, 8); - memclr(0x14000, 0x2c000); } data 80 { i8( - 0, 128, 0, 69, 0x8, 0xc8, - 0, 128, 0, 69, 0x8, 0xc8, - 0, 128, 0, 69, 0x8, 0xc8, - 0, 128, 0, 69, 0x8, 0xc8, - 0xff, 0xff, - 0xc1, 0, 0, 105, 0, 0 + 0, 128, 0, 128, 0x40, 0xe, + 0, 128, 0, 128, 0x8, 0xc8, + 0, 128, 0, 128, 0xa, 0xa, + 0, 128, 0, 128, 0xa, 0xa, + 0xf8, 0x85, + 0xc1, 0xf1, 0, 110, 0, 90 ) -} \ No newline at end of file +} + +/* + +include "../../platform/src/ges.cwa" + +import "env.pow" fn pow(f32, f32) -> f32; +import "env.sin" fn sin(f32) -> f32; + +export fn snd(t: i32) -> f32 { + gesSnd(t) +} + +*/ \ No newline at end of file diff --git a/platform/bin/platform.uw8 b/platform/bin/platform.uw8 index b2aca00..c77b12e 100644 Binary files a/platform/bin/platform.uw8 and b/platform/bin/platform.uw8 differ diff --git a/platform/src/ges.cwa b/platform/src/ges.cwa new file mode 100644 index 0000000..ad75ae8 --- /dev/null +++ b/platform/src/ges.cwa @@ -0,0 +1,154 @@ +const GesChannelState.Trigger = 0; +const GesChannelState.EnvState = 1; +const GesChannelState.EnvVol = 2; +const GesChannelState.Phase = 4; +const GesChannelState.Size = 6; + +const GesState.Filter = GesChannelState.Size * 4; +const GesState.Size = GesState.Filter + 8*4; + +const GesStateOffset = 112; +const GesBufferOffset = 112 + GesState.Size; + +export fn gesSnd(t: i32) -> f32 { + if !(t & 127) { + let i: i32; + loop clearLoop { + i!GesBufferOffset = 0; + branch_if (i := i + 4) < 128*8: clearLoop; + } + + let ch: i32; + loop channelLoop { + let lazy channelState = GesStateOffset + ch * GesChannelState.Size; + let lazy channelReg = 80 + 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 { + envVol = envVol + (16384 / ((channelReg?4 >> 4) + 1)); + if envVol >= 65535 { + envVol = 65535; + envState = 0; + } + } else { + if !envState & ctrl { + envVol = envVol - (16 - (channelReg?4 & 15)) * 48; + let sustain = (channelReg?5 >> 4) * 4096; + if envVol < sustain { + envVol = sustain; + } + } else { + envVol = envVol - (16 - (channelReg?5 & 15)) * 48; + if envVol < 0 { + envVol = 0; + } + } + } + channelState?GesChannelState.EnvState = envState; + + i32.store16(envVol, channelState, GesChannelState.EnvVol); + + 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 = i32.load16_u(channelState, GesChannelState.Phase) << 8; + + i = 0; + let wave = ctrl >> 6; + if wave < 2 { + if wave { + loop sawLoop { + i!(GesBufferOffset + 128*4) = (phase & 65535) - 32768; + phase = phase + phaseInc; + branch_if (i := i + 4) < 64*4: sawLoop; + } + } + else + { + loop rectLoop { + i!(GesBufferOffset + 128*4) = select(phase & 32768, -32768, 32767); + phase = phase + phaseInc; + branch_if (i := i + 4) < 64*4: rectLoop; + } + } + } else { + if wave == 2 { + loop triLoop { + let s = phase << 16; + s = s ^ (s >> 31); + 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) & 4095; + s = s * 0x6746ba73; + s = s ^ (s >> 15); + i!(GesBufferOffset + 128*4) = (s * 0x83567a92) >> 16; + phase = phase + phaseInc; + branch_if (i := i + 4) < 64*4: noiseLoop; + } + } + } + + i32.store16(phase >> 8, channelState, GesChannelState.Phase); + + let channelVol = ((ch >> 1)?0x68 >> ((ch & 1) * 4)) & 15; + envVol = envVol * channelVol / 15; + + let leftVol = (0x4c6a >> (ch * 4)) & 15; + let rightVol = 16 - leftVol; + + let lazy filter = ((ctrl >> 2) & 3) - 1; + + i = 0; + if filter #> 1 { + loop mixLoop { + let sample = (i!(GesBufferOffset + 128*4) * envVol) >> 18; + (i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + ((sample * leftVol) >> 4); + (i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4); + branch_if (i := i + 4) < 64*4: mixLoop; + } + } else { + let ctrl = filter?0x6a; + let note = i32.load16_u(filter * 2, 0x6c); + let inline freq = 440 as f32 * pow(2.0, (note - 69*256) as f32 / (12*256) as f32); + let F = min(4096 as f32, 8192 as f32 * sin(freq * (3.1415 / 44100.0))) as i32; + let Q = 7000 - ctrl * (6000/255); + let low_out = ctrl & 1; + let high_out = (ctrl >> 1) & 1; + let band_out = (ctrl >> 2) & 1; + let low = (ch * 8)!(GesStateOffset + GesState.Filter); + let band = (ch * 8)!(GesStateOffset + GesState.Filter + 4); + loop filterLoop { + let in = (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; + (i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + ((sample * leftVol) >> 4); + (i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4); + branch_if (i := i + 4) < 64*4: filterLoop; + } + (ch * 8)!(GesStateOffset + GesState.Filter) = low; + (ch * 8)!(GesStateOffset + GesState.Filter + 4) = band; + } + + branch_if (ch := ch + 1) < 4: channelLoop; + } + } + (((t & 127) * 4)!GesBufferOffset) as f32 / 32768 as f32 +} diff --git a/platform/src/platform.cwa b/platform/src/platform.cwa index 8cc97bc..2fa37f0 100644 --- a/platform/src/platform.cwa +++ b/platform/src/platform.cwa @@ -1,6 +1,8 @@ import "env.memory" memory(4); +import "env.sin" fn sin(f32) -> f32; import "env.cos" fn cos(f32) -> f32; +import "env.pow" fn pow(f32, f32) -> f32; export fn time() -> f32 { (0!64) as f32 / 1000 as f32 @@ -500,6 +502,12 @@ export fn setCursorPosition(x: i32, y: i32) { textCursorY = y * scale; } +/////////// +// SOUND // +/////////// + +include "ges.cwa" + /////////// // SETUP // /////////// @@ -508,6 +516,13 @@ export fn endFrame() { 68!4 = 68!0; } +fn memclr(base: i32, size: i32) { + loop bytes { + (base + (size := size - 1))?0 = 0; + branch_if size: bytes; + } +} + start fn setup() { let i: i32 = 12*16*3-1; let avg: f32; @@ -540,10 +555,26 @@ start fn setup() { branch_if (i := i - 1) >= 0: expand_sweetie; } + memclr(0, 64); + memclr(112, 8); + memclr(0x14000, 0x2c000); + + cls(0); randomSeed(random()); } +data 80 { + i8( + 0, 128, 0, 69, 0x8, 0xc8, + 0, 128, 0, 69, 0x8, 0xc8, + 0, 128, 0, 69, 0x8, 0xc8, + 0, 128, 0, 69, 0x8, 0xc8, + 0xff, 0xff, + 1, 1, 0, 100, 0, 100 + ) +} + data 0x13000+192*4 { i32( 0x2c1c1a, diff --git a/src/run-web.html b/src/run-web.html index 83088b8..c690081 100644 --- a/src/run-web.html +++ b/src/run-web.html @@ -1 +1 @@ -