From 0f82e6e711bf070ae8c148c8c6fc9409510d2333 Mon Sep 17 00:00:00 2001 From: Dennis Ranke Date: Sat, 19 Mar 2022 14:53:21 +0100 Subject: [PATCH] removed aliasing in rect and saw oscilators --- examples/curlywas/tim_ges.cwa | 10 ++++++---- platform/bin/platform.uw8 | Bin 3426 -> 3529 bytes platform/src/ges.cwa | 29 ++++++++++++++++++++++------- src/run-web.html | 2 +- test/ges_test.cwa | 30 ++++++++++++++++++++++++++++++ 5 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 test/ges_test.cwa diff --git a/examples/curlywas/tim_ges.cwa b/examples/curlywas/tim_ges.cwa index 7619079..5d276c6 100644 --- a/examples/curlywas/tim_ges.cwa +++ b/examples/curlywas/tim_ges.cwa @@ -1,3 +1,5 @@ +import "env.memory" memory(4); + fn melody(ch: i32, t: i32, T: i32) { let lazy riff_pos = abs(((T&31) - 16) as f32) as i32; let lazy shift = ((1-((T>>5)&3))%2-1) * 2; @@ -7,7 +9,7 @@ fn melody(ch: i32, t: i32, T: i32) { let inline riff_note = 5514 >> (riff_pos % note_count * 4) & 15; let inline melody_note = shift + octave - riff_note; - ch?1 = riff_pos * 10 + 4; + ch?1 = riff_pos * 10 + 63; ch?3 = melody_note + 64; let inline arp_note = shift + ((0x85>>((t/2)%3*4)) & 15) - 1; @@ -36,12 +38,12 @@ export fn upd() { data 80 { i8( - 0, 64, 0, 128, 0, 0x90, - 0, 64, 0, 128, 0, 0x4c, + 0, 80, 0, 128, 0, 0x90, + 0, 80, 0, 128, 0, 0x4c, 5, 128, 0, 128, 0, 0x4c, 5, 128, 0, 128, 0, 0x4c, 0xf8, 0x85, - 0x81, 0x81, 0, 105, 0, 80 + 0x81, 0x81, 0, 110, 0, 80 ) } diff --git a/platform/bin/platform.uw8 b/platform/bin/platform.uw8 index 22136eea47013af4c63eae049021c269f96890cb..21ac62c27fae79273fa9c0a586c587a26428ba39 100644 GIT binary patch literal 3529 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 f32 { channelState?GesChannelState.Trigger = ctrl; if envState { - envVol = envVol + 8 * pow(1.5625, (15 - channelReg?4 & 15) as f32) as i32; - if envVol >= 65535 { + let lazy attack = channelReg?4 & 15; + envVol = envVol + 12 * pow(1.5625, (15 - attack) as f32) as i32; + if envVol >= 65535 | !attack { envVol = 65535; envState = 0; } @@ -61,25 +62,33 @@ export fn gesSnd(t: i32) -> f32 { 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; - p = ((p ^ (p >> 31)) >> 15) + phaseShift; - p = (p < 0 | p > 65535) * 65535; - i!(GesBufferOffset + 128*4) = (phase ^ p & 65535) - 32768; + 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); + i!(GesBufferOffset + 128*4) = saw2; phase = phase + phaseInc; branch_if (i := i + 4) < 64*4: sawLoop; } } else { + let pulsePhase = 32768 + pulseWidth * 128; loop rectLoop { - let p = (phase & 65535) + phaseShift; - i!(GesBufferOffset + 128*4) = select(p >= 32768, -32768, 32767); + 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; } @@ -163,3 +172,9 @@ export fn gesSnd(t: i32) -> f32 { } (((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 +} \ No newline at end of file diff --git a/src/run-web.html b/src/run-web.html index 8d674ce..11d4b7d 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/test/ges_test.cwa b/test/ges_test.cwa new file mode 100644 index 0000000..34cde63 --- /dev/null +++ b/test/ges_test.cwa @@ -0,0 +1,30 @@ +import "env.memory" memory(4); +import "env.pow" fn pow(f32, f32) -> f32; +import "env.sin" fn sin(f32) -> f32; +import "env.cls" fn cls(i32); +import "env.rectangle" fn rectangle(f32, f32, f32, f32, i32); + +include "../platform/src/ges.cwa" + +export fn snd(t: i32) -> f32 { + gesSnd(t) +} + +export fn upd() { + 80?0 = 32!32 / 200 & 2 | 0x41; + 80?3 = (32!32 / 400)%7*12/7 + 40; + let pulse = (32!32 * 256 / 2000) & 511; + if pulse >= 256 { + pulse = 511 - pulse; + } + 80?1 = pulse; + + cls(0); + rectangle(0.0, 100.0, (pulse * 320 / 256) as f32, 16.0, 15); +} + +data 80 { + i8( + 0x41, 0, 0, 80, 0x70, 0 + ) +} \ No newline at end of file