mirror of
https://github.com/exoticorn/microw8.git
synced 2026-01-20 11:16:42 +01:00
implement more of the sound-chip
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user