implement more of the sound-chip

This commit is contained in:
2022-03-07 23:58:54 +01:00
parent 780caf965a
commit 81adcf0198
2 changed files with 129 additions and 18 deletions

View File

@@ -1,7 +1,7 @@
include "../include/microw8-api.cwa" include "../include/microw8-api.cwa"
export fn upd() { export fn upd() {
let T = 32!32 / 120; let T = 32!32 / 116;
let inline riff_pos = abs(((T&31) - 16) as f32) as i32; let inline riff_pos = abs(((T&31) - 16) as f32) as i32;
let lazy shift = ((1-((T>>5)&3))%2-1) * 2; let lazy shift = ((1-((T>>5)&3))%2-1) * 2;
@@ -11,35 +11,112 @@ export fn upd() {
let inline riff_note = 5514 >> (riff_pos % note_count * 4) & 15; let inline riff_note = 5514 >> (riff_pos % note_count * 4) & 15;
let inline melody_note = shift + octave - riff_note; let inline melody_note = shift + octave - riff_note;
80?1 = melody_note + 64; 80?0 = ((T&1) << 1); // note trigger
80?4 = 0xa; // attack, decay
80?5 = 0xa; // sustain, release
80?3 = melody_note + 76;
} }
export fn snd(t: i32) -> f32 { export fn snd(t: i32) -> f32 {
gesSample(t) gesSample(t)
} }
const gesStateOffset = 112; const GesChannelState.Trigger = 0;
const gesBufferOffset = 120; const GesChannelState.EnvState = 1;
const GesChannelState.EnvVol = 2;
const GesChannelState.Phase = 4;
const GesChannelState.Size = 6;
const GesState.Size = GesChannelState.Size * 4;
const GesStateOffset = 112;
const GesBufferOffset = 112 + GesState.Size;
fn gesSample(t: i32) -> f32 { fn gesSample(t: i32) -> f32 {
if !(t & 127) { if !(t & 127) {
let i: i32; let i: i32;
loop clearLoop { loop clearLoop {
i!gesBufferOffset = 0; i!GesBufferOffset = 0;
branch_if (i := i + 4) < 128*4: clearLoop; branch_if (i := i + 4) < 128*8: clearLoop;
} }
let phase = 0!gesStateOffset; let ch: i32;
let inline note = 80?1; 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) >> 1) & 1) | (ctrl & !(oldTrigger & 1)) {
envState = 0;
envVol = 0;
}
if envState == 0 {
envVol = envVol + (16384 / ((channelReg?4 >> 4) + 1));
if envVol >= 65535 {
envVol = 65535;
envState = 1;
}
} else {
if envState == 1 & 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 = channelReg?3;
let inline freq = 440 as f32 * pow(2.0, (note - 69) as f32 / 12 as f32); let inline freq = 440 as f32 * pow(2.0, (note - 69) as f32 / 12 as f32);
let phaseInc = (freq * (65536.0 / 88200.0)) as i32; let phaseInc = (freq * (65536.0 / 88200.0)) as i32;
let phase = i32.load16_u(channelState, GesChannelState.Phase);
i = 0; i = 0;
loop osciLoop { let wave = ctrl >> 6;
i!gesBufferOffset = (phase & 65535) - 32768; if wave < 2 {
if wave == 0 {
loop rectLoop {
i!(GesBufferOffset + 128*4) = select(phase & 32768, -32768, 32767);
phase = phase + phaseInc; phase = phase + phaseInc;
branch_if (i := i + 4) < 128*4: osciLoop; branch_if (i := i + 4) < 64*4: rectLoop;
} }
0!gesStateOffset = phase;
} }
(((t & 127) * 4)!gesBufferOffset) as f32 / 32768 as f32 else
{
loop sawLoop {
i!(GesBufferOffset + 128*4) = (phase & 65535) - 32768;
phase = phase + phaseInc;
branch_if (i := i + 4) < 64*4: sawLoop;
}
}
}
i32.store16(phase, channelState, GesChannelState.Phase);
i = 0;
loop mixLoop {
let sample = (i!(GesBufferOffset + 128*4) * envVol) >> 18;
(i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + sample;
(i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + sample;
branch_if (i := i + 4) < 64*4: mixLoop;
}
branch_if (ch := ch + 1) < 4: channelLoop;
}
}
(((t & 127) * 4)!GesBufferOffset) as f32 / (32768 * 10) as f32
} }

View File

@@ -18,7 +18,9 @@ The memory has to be imported as `env` `memory` and has a maximum size of 256kb
00000-00040: user memory 00000-00040: user memory
00040-00044: time since module start in ms 00040-00044: time since module start in ms
00044-0004c: gamepad state 00044-0004c: gamepad state
0004c-00078: reserved 0004c-00050: reserved
00050-00070: sound registers
00070-00078: reserved
00078-12c78: frame buffer 00078-12c78: frame buffer
12c78-13000: reserved 12c78-13000: reserved
13000-13400: palette 13000-13400: palette
@@ -269,6 +271,38 @@ Sets the background color.
Sets the cursor position. In normal mode `x` and `y` are multiplied by 8 to get the pixel position, in graphics mode they are used as is. Sets the cursor position. In normal mode `x` and `y` are multiplied by 8 to get the pixel position, in graphics mode they are used as is.
## Sound
```
Per channel:
00 : CTRL - wave form, ring, sync, filter send, trigger
bit 0: note on flag
bit 1: note trigger
bit 2,3: filter 0,1 send
bit 6,7: wave form (rect, saw, tri, noise)
01 : PULS - pulse width
02 : FINE - fine tuning
03 : NOTE - note
04 : ENVA - attack, decay
05 : ENVR - sustain, release
50-56: channel 0
56-5b: channel 1
5c-61: channel 2
62-67: channel 3
68: VO01 - volumes channel 0&1
69: VO23 - volumes channel 2&3
6a : FCTR 0 - type, resonance
6b : FCTR 1 - type, resonance
6c : FFIN 0 - cutoff fine tuning
6d : FNOT 0 - cutoff note
6e : FFIN 1 - cutoff fine tuning
6f : FNOT 1 - cutoff note
```
# The `uw8` tool # The `uw8` tool
The `uw8` tool included in the MicroW8 download includes a number of useful tools for developing MicroW8 carts. For small productions written in The `uw8` tool included in the MicroW8 download includes a number of useful tools for developing MicroW8 carts. For small productions written in