From a15e79648904bf9996597be942c0df2466ef2823 Mon Sep 17 00:00:00 2001 From: Dennis Ranke Date: Tue, 8 Mar 2022 22:20:54 +0100 Subject: [PATCH] first full version of time for ges --- examples/curlywas/tim_ges.cwa | 223 ++++++---------------------------- platform/bin/platform.uw8 | Bin 2716 -> 3316 bytes platform/src/ges.cwa | 154 +++++++++++++++++++++++ platform/src/platform.cwa | 31 +++++ src/run-web.html | 2 +- web/src/audiolet.js | 2 +- 6 files changed, 225 insertions(+), 187 deletions(-) create mode 100644 platform/src/ges.cwa 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 b2aca007866b61b6006208f28cee4a28d0406468..c77b12e2c49f26896b34f3ff9af8f90c37658169 100644 GIT binary patch literal 3316 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 literal 2716 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 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 @@ -uw8-run
\ No newline at end of file +uw8-run
\ No newline at end of file diff --git a/web/src/audiolet.js b/web/src/audiolet.js index ec5a949..662fc76 100644 --- a/web/src/audiolet.js +++ b/web/src/audiolet.js @@ -45,7 +45,7 @@ class APU extends AudioWorkletProcessor { this.memory = memory; - this.snd = instance.exports.snd; + this.snd = instance.exports.snd || platform_instance.exports.gesSnd; this.port.postMessage(2); }