mirror of
https://github.com/exoticorn/microw8.git
synced 2026-01-21 03:36:41 +01:00
Compare commits
10 Commits
a5edeb21d8
...
sound
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c82f4ad02 | |||
| 4dd8c3b029 | |||
| 2bf8938183 | |||
| 491bf88ade | |||
| e05701300c | |||
| df0c169d54 | |||
| 61941bceeb | |||
| 8fa64519e4 | |||
| 7a52ce4e4c | |||
| 6f20d303c8 |
38
examples/curlywas/simple_music.cwa
Normal file
38
examples/curlywas/simple_music.cwa
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
include "../include/microw8-api.cwa"
|
||||||
|
|
||||||
|
global mut frame = 0;
|
||||||
|
|
||||||
|
export fn upd() {
|
||||||
|
if frame % 16 == 0 {
|
||||||
|
let ch: i32;
|
||||||
|
loop channels {
|
||||||
|
playNote(ch, (ch * 32 + (frame / 16) % 32)?0x20000);
|
||||||
|
branch_if ch := (ch + 1) % 4: channels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frame = frame + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
data 0x20000 {
|
||||||
|
i8(
|
||||||
|
0x4e, 0x0, 0x0, 0x4c, 0x49, 0x0, 0x45, 0x47,
|
||||||
|
0x49, 0x47, 0x45, 0x44, 0x42, 0x0, 0x3d, 0x41,
|
||||||
|
0x44, 0x0, 0x0, 0x47, 0x49, 0x47, 0x45, 0x41,
|
||||||
|
0x44, 0x0, 0x0, 0x0, 0x42, 0x0, 0x0, 0x0,
|
||||||
|
|
||||||
|
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0x38,
|
||||||
|
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0x38,
|
||||||
|
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0x38,
|
||||||
|
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0x38,
|
||||||
|
|
||||||
|
0x2a, 0x0, 0x0, 0x0, 0x2d, 0x0, 0x0, 0x0,
|
||||||
|
0x2c, 0x0, 0x28, 0x0, 0x2a, 0x0, 0x0, 0x0,
|
||||||
|
0x25, 0x0, 0x0, 0x0, 0x29, 0x0, 0x0, 0x0,
|
||||||
|
0x2c, 0x0, 0x2d, 0x0, 0x2a, 0x0, 0x25, 0x0,
|
||||||
|
|
||||||
|
0x0, 0x0, 0x31, 0x0, 0x34, 0x0, 0x0, 0x36,
|
||||||
|
0x38, 0x39, 0x38, 0x34, 0x36, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x3d, 0x3b, 0x39, 0x38, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x39, 0x38, 0x39, 0x38, 0x0, 0x36, 0x0
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
|
// Steady On Tim, It's Only A Budget Game
|
||||||
|
// original bytebeat by Gasman / Hooy-Program
|
||||||
|
// ported to MicroW8/GES by exoticorn/icebird
|
||||||
|
|
||||||
import "env.memory" memory(4);
|
import "env.memory" memory(4);
|
||||||
|
|
||||||
fn melody(ch: i32, t: i32, T: i32) {
|
fn melody(ch: i32, t: i32, T: i32) {
|
||||||
@@ -9,7 +13,7 @@ fn melody(ch: i32, t: i32, T: i32) {
|
|||||||
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;
|
||||||
|
|
||||||
ch?1 = 248 - riff_pos * 15;
|
ch?1 = 230 - riff_pos * 14;
|
||||||
ch?3 = melody_note + 64;
|
ch?3 = melody_note + 64;
|
||||||
|
|
||||||
let inline arp_note = shift + ((0x85>>((t/2)%3*4)) & 15) - 1;
|
let inline arp_note = shift + ((0x85>>((t/2)%3*4)) & 15) - 1;
|
||||||
@@ -22,13 +26,13 @@ export fn upd() {
|
|||||||
melody(98, t, T - 3);
|
melody(98, t, T - 3);
|
||||||
melody(92, t, T);
|
melody(92, t, T);
|
||||||
|
|
||||||
80?0 = ((T >= 256) & (T/12+(T-3)/12)) * 2 | 0x44; // arp trigger
|
80?0 = ((T >= 256) & (T/12+(T-3)/12)) * 2 | 0x48; // arp trigger
|
||||||
|
|
||||||
if T >= 128 {
|
if T >= 128 {
|
||||||
let inline bass_step = T % 8;
|
let inline bass_step = T % 8;
|
||||||
86?3 = if bass_step / 2 == 2 {
|
86?3 = if bass_step / 2 == 2 {
|
||||||
86?0 = 0xc2;
|
86?0 = 0xd6;
|
||||||
80
|
81
|
||||||
} else {
|
} else {
|
||||||
86?0 = ((197 >> bass_step) & 1) | 0x48;
|
86?0 = ((197 >> bass_step) & 1) | 0x48;
|
||||||
((T & 4) * ((T & 7) - 1)) / 2 + 28
|
((T & 4) * ((T & 7) - 1)) / 2 + 28
|
||||||
@@ -38,12 +42,12 @@ export fn upd() {
|
|||||||
|
|
||||||
data 80 {
|
data 80 {
|
||||||
i8(
|
i8(
|
||||||
0, 0x81, 0, 0, 0, 0x90,
|
0, 0x90, 0, 0, 0, 0x90,
|
||||||
0, 0x4c, 0, 0, 0, 0x5c,
|
0, 0x4c, 0, 0, 0, 0x4c,
|
||||||
5, 0, 0, 0, 0, 0x4c,
|
0x19, 0, 0, 0, 0, 0x4c,
|
||||||
5, 0, 0, 0, 0, 0x4c,
|
0x19, 0, 0, 0, 0, 0x4c,
|
||||||
0xfa, 0x85,
|
0xfa, 0x84,
|
||||||
0x81, 0x81, 0, 110, 0, 90
|
0xc1, 0xc1, 0, 107, 0, 0x4c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,6 +55,7 @@ data 80 {
|
|||||||
include "../../platform/src/ges.cwa"
|
include "../../platform/src/ges.cwa"
|
||||||
|
|
||||||
import "env.pow" fn pow(f32, f32) -> f32;
|
import "env.pow" fn pow(f32, f32) -> f32;
|
||||||
|
import "env.exp" fn exp(f32) -> f32;
|
||||||
import "env.sin" fn sin(f32) -> f32;
|
import "env.sin" fn sin(f32) -> f32;
|
||||||
|
|
||||||
export fn snd(t: i32) -> f32 {
|
export fn snd(t: i32) -> f32 {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import "env.setCursorPosition" fn setCursorPosition(i32, i32);
|
|||||||
import "env.rectangle_outline" fn rectangle_outline(f32, f32, f32, f32, i32);
|
import "env.rectangle_outline" fn rectangle_outline(f32, f32, f32, f32, i32);
|
||||||
import "env.circle_outline" fn circle_outline(f32, f32, f32, i32);
|
import "env.circle_outline" fn circle_outline(f32, f32, f32, i32);
|
||||||
import "env.exp" fn exp(f32) -> f32;
|
import "env.exp" fn exp(f32) -> f32;
|
||||||
|
import "env.playNote" fn playNote(i32, i32);
|
||||||
|
|
||||||
const TIME_MS = 0x40;
|
const TIME_MS = 0x40;
|
||||||
const GAMEPAD = 0x44;
|
const GAMEPAD = 0x44;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
(import "env" "rectangle_outline" (func $rectangle_outline (param f32) (param f32) (param f32) (param f32) (param i32)))
|
(import "env" "rectangle_outline" (func $rectangle_outline (param f32) (param f32) (param f32) (param f32) (param i32)))
|
||||||
(import "env" "circle_outline" (func $circle_outline (param f32) (param f32) (param f32) (param i32)))
|
(import "env" "circle_outline" (func $circle_outline (param f32) (param f32) (param f32) (param i32)))
|
||||||
(import "env" "exp" (func $exp (param f32) (result f32)))
|
(import "env" "exp" (func $exp (param f32) (result f32)))
|
||||||
|
(import "env" "playNote" (func $playNote (param i32) (param i32)))
|
||||||
|
|
||||||
;; to use defines, include this file with a preprocessor
|
;; to use defines, include this file with a preprocessor
|
||||||
;; like gpp (https://logological.org/gpp).
|
;; like gpp (https://logological.org/gpp).
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -7,21 +7,22 @@ const GesChannelState.Size = 8;
|
|||||||
const GesState.Filter = GesChannelState.Size * 4;
|
const GesState.Filter = GesChannelState.Size * 4;
|
||||||
const GesState.Size = GesState.Filter + 8*4;
|
const GesState.Size = GesState.Filter + 8*4;
|
||||||
|
|
||||||
const GesStateOffset = 112;
|
const GesStateOffset = 32;
|
||||||
const GesBufferOffset = 112 + GesState.Size;
|
const GesBufferOffset = 32 + GesState.Size;
|
||||||
|
|
||||||
export fn gesSnd(t: i32) -> f32 {
|
export fn gesSnd(t: i32) -> f32 {
|
||||||
|
let baseAddr = 0!0x12c78;
|
||||||
if !(t & 127) {
|
if !(t & 127) {
|
||||||
let i: i32;
|
let i: i32;
|
||||||
loop clearLoop {
|
loop clearLoop {
|
||||||
i!GesBufferOffset = 0;
|
(baseAddr + i)!GesBufferOffset = 0;
|
||||||
branch_if (i := i + 4) < 128*8: clearLoop;
|
branch_if (i := i + 4) < 128*4: clearLoop;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ch: i32;
|
let ch: i32;
|
||||||
loop channelLoop {
|
loop channelLoop {
|
||||||
let lazy channelState = GesStateOffset + ch * GesChannelState.Size;
|
let lazy channelState = baseAddr + GesStateOffset + ch * GesChannelState.Size;
|
||||||
let lazy channelReg = 80 + ch * 6;
|
let lazy channelReg = baseAddr + ch * 6;
|
||||||
let envState = channelState?GesChannelState.EnvState;
|
let envState = channelState?GesChannelState.EnvState;
|
||||||
let envVol = i32.load16_u(channelState, GesChannelState.EnvVol);
|
let envVol = i32.load16_u(channelState, GesChannelState.EnvVol);
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ export fn gesSnd(t: i32) -> f32 {
|
|||||||
let saw2 = saw2 -
|
let saw2 = saw2 -
|
||||||
polyBlep((p - pulsePhase1) >> 16, invPhaseInc, -saw) -
|
polyBlep((p - pulsePhase1) >> 16, invPhaseInc, -saw) -
|
||||||
polyBlep((p - pulsePhase2) >> 16, invPhaseInc, saw);
|
polyBlep((p - pulsePhase2) >> 16, invPhaseInc, saw);
|
||||||
i!(GesBufferOffset + 128*4) = saw2;
|
(baseAddr + i)!(GesBufferOffset + 128*4) = saw2;
|
||||||
phase = phase + phaseInc;
|
phase = phase + phaseInc;
|
||||||
branch_if (i := i + 4) < 64*4: sawLoop;
|
branch_if (i := i + 4) < 64*4: sawLoop;
|
||||||
}
|
}
|
||||||
@@ -86,7 +87,7 @@ export fn gesSnd(t: i32) -> f32 {
|
|||||||
{
|
{
|
||||||
let pulsePhase = 32768 + pulseWidth * 128;
|
let pulsePhase = 32768 + pulseWidth * 128;
|
||||||
loop rectLoop {
|
loop rectLoop {
|
||||||
i!(GesBufferOffset + 128*4) = select((phase & 65535) < pulsePhase, -32768, 32767) -
|
(baseAddr + i)!(GesBufferOffset + 128*4) = select((phase & 65535) < pulsePhase, -32768, 32767) -
|
||||||
polyBlep(phase, invPhaseInc, -32767) -
|
polyBlep(phase, invPhaseInc, -32767) -
|
||||||
polyBlep(phase - pulsePhase, invPhaseInc, 32767);
|
polyBlep(phase - pulsePhase, invPhaseInc, 32767);
|
||||||
phase = phase + phaseInc;
|
phase = phase + phaseInc;
|
||||||
@@ -101,7 +102,7 @@ export fn gesSnd(t: i32) -> f32 {
|
|||||||
s = (s ^ (s >> 31));
|
s = (s ^ (s >> 31));
|
||||||
s = (s >> 8) * scale;
|
s = (s >> 8) * scale;
|
||||||
s = (s ^ (s >> 31));
|
s = (s ^ (s >> 31));
|
||||||
i!(GesBufferOffset + 128*4) = (s >> 15) - 32768;
|
(baseAddr + i)!(GesBufferOffset + 128*4) = (s >> 15) - 32768;
|
||||||
phase = phase + phaseInc;
|
phase = phase + phaseInc;
|
||||||
branch_if (i := i + 4) < 64*4: triLoop;
|
branch_if (i := i + 4) < 64*4: triLoop;
|
||||||
}
|
}
|
||||||
@@ -111,7 +112,7 @@ export fn gesSnd(t: i32) -> f32 {
|
|||||||
let inline pulse = ((phase >> 8) & 255) >= pulseWidth;
|
let inline pulse = ((phase >> 8) & 255) >= pulseWidth;
|
||||||
s = s * 0x6746ba73;
|
s = s * 0x6746ba73;
|
||||||
s = s ^ (s >> 15) * pulse;
|
s = s ^ (s >> 15) * pulse;
|
||||||
i!(GesBufferOffset + 128*4) = (s * 0x835776c7) >> 16;
|
(baseAddr + i)!(GesBufferOffset + 128*4) = (s * 0x835776c7) >> 16;
|
||||||
phase = phase + phaseInc;
|
phase = phase + phaseInc;
|
||||||
branch_if (i := i + 4) < 64*4: noiseLoop;
|
branch_if (i := i + 4) < 64*4: noiseLoop;
|
||||||
}
|
}
|
||||||
@@ -122,8 +123,8 @@ export fn gesSnd(t: i32) -> f32 {
|
|||||||
|
|
||||||
if ctrl & 32 {
|
if ctrl & 32 {
|
||||||
let lazy modSrc = (ch - 1) & 3;
|
let lazy modSrc = (ch - 1) & 3;
|
||||||
let inline channelState = GesStateOffset + modSrc * GesChannelState.Size;
|
let inline channelState = baseAddr + GesStateOffset + modSrc * GesChannelState.Size;
|
||||||
let inline channelReg = 80 + modSrc * 6;
|
let inline channelReg = baseAddr + modSrc * 6;
|
||||||
|
|
||||||
let inline note = i32.load16_u(channelReg, 2);
|
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 inline freq = 440 as f32 * pow(2.0, (note - 69*256) as f32 / (12*256) as f32);
|
||||||
@@ -138,13 +139,13 @@ export fn gesSnd(t: i32) -> f32 {
|
|||||||
loop ringLoop {
|
loop ringLoop {
|
||||||
let s = phase << 16;
|
let s = phase << 16;
|
||||||
s = (s ^ (s >> 31));
|
s = (s ^ (s >> 31));
|
||||||
i!(GesBufferOffset + 128*4) = (i!(GesBufferOffset + 128*4) * ((s >> 15) - 32768)) >> 15;
|
(baseAddr + i)!(GesBufferOffset + 128*4) = ((baseAddr + i)!(GesBufferOffset + 128*4) * ((s >> 15) - 32768)) >> 15;
|
||||||
phase = phase + phaseInc;
|
phase = phase + phaseInc;
|
||||||
branch_if (i := i + 4) < 64*4: ringLoop;
|
branch_if (i := i + 4) < 64*4: ringLoop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let channelVol = ((ch >> 1)?0x68 >> ((ch & 1) * 4)) & 15;
|
let channelVol = ((baseAddr + (ch >> 1))?24 >> ((ch & 1) * 4)) & 15;
|
||||||
envVol = envVol * channelVol / 15;
|
envVol = envVol * channelVol / 15;
|
||||||
|
|
||||||
let leftVol = (select(ctrl & 16, 0x3d5b, 0x6a79) >> (ch * 4)) & 15;
|
let leftVol = (select(ctrl & 16, 0x3d5b, 0x6a79) >> (ch * 4)) & 15;
|
||||||
@@ -156,30 +157,30 @@ export fn gesSnd(t: i32) -> f32 {
|
|||||||
if filter < 2 {
|
if filter < 2 {
|
||||||
if filter {
|
if filter {
|
||||||
let f = (4096 as f32 - min(4096 as f32, 4096 as f32 * exp(freq * (-8.0 * 3.141 / 44100.0)))) as i32;
|
let f = (4096 as f32 - min(4096 as f32, 4096 as f32 * exp(freq * (-8.0 * 3.141 / 44100.0)))) as i32;
|
||||||
let low = (ch * 8)!(GesStateOffset + GesState.Filter);
|
let low = (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter);
|
||||||
loop filterLoop {
|
loop filterLoop {
|
||||||
let in = (i!(GesBufferOffset + 128*4) * envVol) >> 18;
|
let in = ((baseAddr + i)!(GesBufferOffset + 128*4) * envVol) >> 18;
|
||||||
low = low + (((in - low) * f) >> 12);
|
low = low + (((in - low) * f) >> 12);
|
||||||
(i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + ((low * leftVol) >> 4);
|
(baseAddr + i * 2)!GesBufferOffset = (baseAddr + i * 2)!GesBufferOffset + ((low * leftVol) >> 4);
|
||||||
(i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + ((low * rightVol) >> 4);
|
(baseAddr + i * 2)!(GesBufferOffset + 4) = (baseAddr + i * 2)!(GesBufferOffset + 4) + ((low * rightVol) >> 4);
|
||||||
branch_if (i := i + 4) < 64*4: filterLoop;
|
branch_if (i := i + 4) < 64*4: filterLoop;
|
||||||
(ch * 8)!(GesStateOffset + GesState.Filter) = low;
|
(baseAddr + ch * 8)!(GesStateOffset + GesState.Filter) = low;
|
||||||
(ch * 8)!(GesStateOffset + GesState.Filter + 4) = 0;
|
(baseAddr + ch * 8)!(GesStateOffset + GesState.Filter + 4) = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
loop mixLoop {
|
loop mixLoop {
|
||||||
let sample = (i!(GesBufferOffset + 128*4) * envVol) >> 18;
|
let sample = ((baseAddr + i)!(GesBufferOffset + 128*4) * envVol) >> 18;
|
||||||
(i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + ((sample * leftVol) >> 4);
|
(baseAddr + i * 2)!GesBufferOffset = (baseAddr + i * 2)!GesBufferOffset + ((sample * leftVol) >> 4);
|
||||||
(i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4);
|
(baseAddr + i * 2)!(GesBufferOffset + 4) = (baseAddr + i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4);
|
||||||
branch_if (i := i + 4) < 64*4: mixLoop;
|
branch_if (i := i + 4) < 64*4: mixLoop;
|
||||||
(ch * 8)!(GesStateOffset + GesState.Filter) = sample;
|
(baseAddr + ch * 8)!(GesStateOffset + GesState.Filter) = sample;
|
||||||
(ch * 8)!(GesStateOffset + GesState.Filter + 4) = 0;
|
(baseAddr + ch * 8)!(GesStateOffset + GesState.Filter + 4) = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
filter = filter - 2;
|
filter = filter - 2;
|
||||||
let ctrl = filter?0x6a;
|
let ctrl = (baseAddr + filter)?26;
|
||||||
let note = i32.load16_u(filter * 2, 0x6c);
|
let note = i32.load16_u(baseAddr + filter * 2, 28);
|
||||||
let inline freq = 440 as f32 * pow(2.0, (note - 69*256) as f32 / (12*256) as f32);
|
let inline freq = 440 as f32 * pow(2.0, (note - 69*256) as f32 / (12*256) as f32);
|
||||||
let F = (8192 as f32 * sin(min(0.25, freq / 44100 as f32) * 3.1415)) as i32;
|
let F = (8192 as f32 * sin(min(0.25, freq / 44100 as f32) * 3.1415)) as i32;
|
||||||
let Q = 8192 - (ctrl >> 4) * (7000/15);
|
let Q = 8192 - (ctrl >> 4) * (7000/15);
|
||||||
@@ -190,28 +191,28 @@ export fn gesSnd(t: i32) -> f32 {
|
|||||||
let low_out = ctrl & 1;
|
let low_out = ctrl & 1;
|
||||||
let high_out = (ctrl >> 1) & 1;
|
let high_out = (ctrl >> 1) & 1;
|
||||||
let band_out = (ctrl >> 2) & 1;
|
let band_out = (ctrl >> 2) & 1;
|
||||||
let low = (ch * 8)!(GesStateOffset + GesState.Filter);
|
let low = (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter);
|
||||||
let band = (ch * 8)!(GesStateOffset + GesState.Filter + 4);
|
let band = (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter + 4);
|
||||||
loop filterLoop {
|
loop filterLoop {
|
||||||
let in = (i!(GesBufferOffset + 128*4) * envVol) >> 18;
|
let in = ((baseAddr + i)!(GesBufferOffset + 128*4) * envVol) >> 18;
|
||||||
|
|
||||||
let high = in - low - ((band * Q) >> 12);
|
let high = in - low - ((band * Q) >> 12);
|
||||||
band = band + ((F * high) >> 12);
|
band = band + ((F * high) >> 12);
|
||||||
low = low + ((F * band) >> 12);
|
low = low + ((F * band) >> 12);
|
||||||
|
|
||||||
let sample = low * low_out + high * high_out + band * band_out;
|
let sample = low * low_out + high * high_out + band * band_out;
|
||||||
(i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + ((sample * leftVol) >> 4);
|
(baseAddr + i * 2)!GesBufferOffset = (baseAddr + i * 2)!GesBufferOffset + ((sample * leftVol) >> 4);
|
||||||
(i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4);
|
(baseAddr + i * 2)!(GesBufferOffset + 4) = (baseAddr + i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4);
|
||||||
branch_if (i := i + 4) < 64*4: filterLoop;
|
branch_if (i := i + 4) < 64*4: filterLoop;
|
||||||
(ch * 8)!(GesStateOffset + GesState.Filter) = low;
|
(baseAddr + ch * 8)!(GesStateOffset + GesState.Filter) = low;
|
||||||
(ch * 8)!(GesStateOffset + GesState.Filter + 4) = band;
|
(baseAddr + ch * 8)!(GesStateOffset + GesState.Filter + 4) = band;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
branch_if (ch := ch + 1) < 4: channelLoop;
|
branch_if (ch := ch + 1) < 4: channelLoop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(((t & 127) * 4)!GesBufferOffset) as f32 / 32768 as f32
|
((baseAddr + (t & 127) * 4)!GesBufferOffset) as f32 / 32768 as f32
|
||||||
}
|
}
|
||||||
|
|
||||||
fn polyBlep(transientPhase: i32, invPhaseInc: f32, magnitude: i32) -> i32 {
|
fn polyBlep(transientPhase: i32, invPhaseInc: f32, magnitude: i32) -> i32 {
|
||||||
|
|||||||
@@ -339,6 +339,11 @@ fn printSingleChar(char: i32) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if char == 7 {
|
||||||
|
80?0 = 80?0 ^ 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if char == 8 {
|
if char == 8 {
|
||||||
textCursorX = textCursorX - 8;
|
textCursorX = textCursorX - 8;
|
||||||
if !graphicsText & textCursorX < 0 {
|
if !graphicsText & textCursorX < 0 {
|
||||||
@@ -509,6 +514,26 @@ export fn setCursorPosition(x: i32, y: i32) {
|
|||||||
|
|
||||||
include "ges.cwa"
|
include "ges.cwa"
|
||||||
|
|
||||||
|
export fn playNote(channel: i32, note: i32) {
|
||||||
|
(channel * 6)?80 = (channel * 6)?80 & 0xfe ^ if note {
|
||||||
|
(channel * 6)?83 = note & 127;
|
||||||
|
2 | !(note >> 7)
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
data 80 {
|
||||||
|
i8(
|
||||||
|
0x80, 0xc0, 0, 81, 0xa0, 0x50,
|
||||||
|
0xc4, 0, 0, 69, 0x60, 0x40,
|
||||||
|
0x44, 0xb0, 0, 69, 0x90, 0x43,
|
||||||
|
0x4, 0xf0, 0, 69, 0xa4, 0x44,
|
||||||
|
0xff, 0xff,
|
||||||
|
1, 1, 0, 100, 0, 100
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
///////////
|
///////////
|
||||||
// SETUP //
|
// SETUP //
|
||||||
///////////
|
///////////
|
||||||
@@ -565,15 +590,8 @@ start fn setup() {
|
|||||||
randomSeed(random());
|
randomSeed(random());
|
||||||
}
|
}
|
||||||
|
|
||||||
data 80 {
|
data 0x12c78 {
|
||||||
i8(
|
i32(80)
|
||||||
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 {
|
data 0x13000+192*4 {
|
||||||
|
|||||||
@@ -43,27 +43,6 @@ Changes:
|
|||||||
* CurlyWas: implement support for constants
|
* CurlyWas: implement support for constants
|
||||||
* fix crash when trying to draw zero sized line
|
* fix crash when trying to draw zero sized line
|
||||||
|
|
||||||
### v0.1.1
|
### Older versions
|
||||||
|
|
||||||
* [Web runtime](v0.1.1)
|
[Find older versions here.](versions)
|
||||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-linux.tgz)
|
|
||||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-macos.tgz)
|
|
||||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-windows.zip)
|
|
||||||
|
|
||||||
Changes:
|
|
||||||
|
|
||||||
* implement more robust file watcher
|
|
||||||
* add basic video recording on F10 in web runtime
|
|
||||||
* add screenshot on F9
|
|
||||||
* add watchdog to interrupt hanging update in native runtime
|
|
||||||
* add devkit mode to web runtime
|
|
||||||
* add unpack and compile commands to uw8
|
|
||||||
* add support for table/element section in pack command
|
|
||||||
* disable wayland support (caused missing window decorations in gnome)
|
|
||||||
|
|
||||||
### v0.1.0
|
|
||||||
|
|
||||||
* [Web runtime](v0.1.0)
|
|
||||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-linux.tgz)
|
|
||||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-macos.tgz)
|
|
||||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-windows.zip)
|
|
||||||
@@ -19,10 +19,11 @@ The memory has to be imported as `env` `memory` and has a maximum size of 256kb
|
|||||||
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-00050: reserved
|
0004c-00050: reserved
|
||||||
00050-00070: sound registers
|
00050-00070: sound data (synced to sound thread)
|
||||||
00070-00078: reserved
|
00070-00078: reserved
|
||||||
00078-12c78: frame buffer
|
00078-12c78: frame buffer
|
||||||
12c78-13000: reserved
|
12c78-12c7c: sound registers/work area base address (for sndGes function)
|
||||||
|
12c7c-13000: reserved
|
||||||
13000-13400: palette
|
13000-13400: palette
|
||||||
13400-13c00: font
|
13400-13c00: font
|
||||||
13c00-14000: reserved
|
13c00-14000: reserved
|
||||||
@@ -231,7 +232,8 @@ Avoid the reserved control chars, they are currently NOPs but their behavior can
|
|||||||
| 2-3 | - | Reserved |
|
| 2-3 | - | Reserved |
|
||||||
| 4 | - | Switch to normal mode |
|
| 4 | - | Switch to normal mode |
|
||||||
| 5 | - | Switch to graphics mode |
|
| 5 | - | Switch to graphics mode |
|
||||||
| 6-7 | - | Reserved |
|
| 6 | - | Reserved |
|
||||||
|
| 7 | - | Bell / trigger sound channel 0 |
|
||||||
| 8 | - | Move cursor left |
|
| 8 | - | Move cursor left |
|
||||||
| 9 | - | Move cursor right |
|
| 9 | - | Move cursor right |
|
||||||
| 10 | - | Move cursor down |
|
| 10 | - | Move cursor down |
|
||||||
@@ -273,34 +275,120 @@ Sets the cursor position. In normal mode `x` and `y` are multiplied by 8 to get
|
|||||||
|
|
||||||
## Sound
|
## Sound
|
||||||
|
|
||||||
|
### Low level operation
|
||||||
|
|
||||||
|
MicroW8 actually runs two instances of your module. On the first instance, it calls `upd` and displays the framebuffer found in its memory. On the
|
||||||
|
second instance, it calls `snd` instead with an incrementing sample index and expects that function to return sound samples for the left and right
|
||||||
|
channel at 44100 Hz. If your module does not export a `snd` function, it calls the api function `sndGes` instead.
|
||||||
|
|
||||||
|
As the only means of communication, 32 bytes starting at address 0x00050 are copied from main to sound memory after `upd` returns.
|
||||||
|
|
||||||
|
By default, the `sndGes` function generates sound based on the 32 bytes at 0x00050. This means that in the default configuration those 32 bytes act
|
||||||
|
as sound registers. See the `sndGes` function for the meaning of those registers.
|
||||||
|
|
||||||
|
### fn playNote(channel: i32, note: i32)
|
||||||
|
|
||||||
|
Triggers a note (1-127) on the given channel (0-3). Notes are semitones with 69 being A4 (same as MIDI). A note value of 0 stops the
|
||||||
|
sound playing on that channel. A note value 128-255 will trigger note-128 and immediately stop it (playing attack+release parts of envelope).
|
||||||
|
|
||||||
|
This function assumes the default setup, with the `sndGes` registers located at 0x00050.
|
||||||
|
|
||||||
|
### fn sndGes(sampleIndex: i32) -> f32
|
||||||
|
|
||||||
|
This implements a sound chip, generating sound based on 32 bytes of sound registers.
|
||||||
|
|
||||||
|
The spec of this sound chip are:
|
||||||
|
|
||||||
|
- 4 channels with individual volume control (0-15)
|
||||||
|
- rect, saw, tri, noise wave forms selectable per channel
|
||||||
|
- each wave form supports some kind of pulse width modulation
|
||||||
|
- each channel has an optional automatic low pass filter, or can be sent to one of two manually controllable filters
|
||||||
|
- each channel can select between a narrow and a wide stereo positioning. The two stereo positions of each channel are fixed.
|
||||||
|
- optional ring modulation
|
||||||
|
|
||||||
|
This function requires 1024 bytes of working memory, the first 32 bytes of which are interpreted as the sound registers.
|
||||||
|
The base address of its working memory can be configured by writing the address to 0x12c78. It defaults to 0x00050.
|
||||||
|
|
||||||
|
Here is a short description of the 32 sound registers.
|
||||||
|
|
||||||
```
|
```
|
||||||
Per channel:
|
00 - CTRL0
|
||||||
|
06 - CTRL1
|
||||||
|
0c - CTRL2
|
||||||
|
12 - CTRL3
|
||||||
|
| 7 6 | 5 | 4 | 3 2 | 1 | 0 |
|
||||||
|
| wave | ring | wide | filter | trigger | note on |
|
||||||
|
|
||||||
00 : CTRL - wave form, ring, sync, filter send, trigger
|
note on: stay in decay/sustain part of envelope
|
||||||
bit 0: note on flag
|
trigger: the attack part of the envlope is triggered when either this changes
|
||||||
bit 1: note trigger
|
or note on is changed from 0 to 1.
|
||||||
bit 2,3: filter 0,1 send
|
filter : 0 - no filter
|
||||||
bit 6,7: wave form (rect, saw, tri, noise)
|
1 - fixed 6db 1-pole filter with cutoff two octaves above note
|
||||||
01 : PULS - pulse width
|
2 - programmable filter 0
|
||||||
02 : FINE - fine tuning
|
3 - programmable filter 1
|
||||||
03 : NOTE - note
|
wide : use wide stereo panning
|
||||||
04 : ENVA - attack, decay
|
ring : ring modulate with triangle wave at frequency of previous channel
|
||||||
05 : ENVR - sustain, release
|
wave : 0 - rectangle
|
||||||
|
1 - saw
|
||||||
|
2 - triangle
|
||||||
|
3 - noise
|
||||||
|
|
||||||
50-56: channel 0
|
01 - PULS0
|
||||||
56-5b: channel 1
|
07 - PULS1
|
||||||
5c-61: channel 2
|
0d - PULS2
|
||||||
62-67: channel 3
|
13 - PULS3
|
||||||
|
Pulse width 0-255, with 0 being the plain version of each wave form.
|
||||||
|
rectangle - 50%-100% pulse width
|
||||||
|
saw - inverts 0%-100% of the saw wave form around the center
|
||||||
|
triangle - morphs into an octave up triangle wave
|
||||||
|
noise - blends into a decimated saw wave (just try it out)
|
||||||
|
|
||||||
68: VO01 - volumes channel 0&1
|
02 - FINE0
|
||||||
69: VO23 - volumes channel 2&3
|
08 - FINE1
|
||||||
|
0e - FINE2
|
||||||
|
14 - FINE3
|
||||||
|
Fractional note
|
||||||
|
|
||||||
6a : FCTR 0 - type, resonance
|
03 - NOTE0
|
||||||
6b : FCTR 1 - type, resonance
|
09 - NOTE1
|
||||||
6c : FFIN 0 - cutoff fine tuning
|
0f - NOTE2
|
||||||
6d : FNOT 0 - cutoff note
|
15 - NOTE3
|
||||||
6e : FFIN 1 - cutoff fine tuning
|
Note, 69 = A4
|
||||||
6f : FNOT 1 - cutoff note
|
|
||||||
|
04 - ENVA0
|
||||||
|
0a - ENVA1
|
||||||
|
10 - ENVA2
|
||||||
|
16 - ENVA3
|
||||||
|
| 7 6 5 4 | 3 2 1 0 |
|
||||||
|
| decay | attack |
|
||||||
|
|
||||||
|
05 - ENVB0
|
||||||
|
0b - ENVB1
|
||||||
|
11 - ENVB2
|
||||||
|
17 - ENVB3
|
||||||
|
| 7 6 5 4 | 3 2 1 0 |
|
||||||
|
| release | sustain |
|
||||||
|
|
||||||
|
18 - VO01
|
||||||
|
| 7 6 5 4 | 3 2 1 0 |
|
||||||
|
| volume 1 | volume 0 |
|
||||||
|
|
||||||
|
19 - VO23
|
||||||
|
| 7 6 5 4 | 3 2 1 0 |
|
||||||
|
| volume 3 | volume 2 |
|
||||||
|
|
||||||
|
1a - FCTR0
|
||||||
|
1b - FCTR1
|
||||||
|
| 7 6 5 4 | 3 | 2 | 1 | 0 |
|
||||||
|
| resonance | 0 | band | high | low |
|
||||||
|
|
||||||
|
1c - FFIN0
|
||||||
|
1e - FFIN1
|
||||||
|
cutoff frequency - fractional note
|
||||||
|
|
||||||
|
1d - FNOT0
|
||||||
|
1f - FNOT1
|
||||||
|
cutoff frequency - note
|
||||||
```
|
```
|
||||||
|
|
||||||
# The `uw8` tool
|
# The `uw8` tool
|
||||||
|
|||||||
42
site/content/versions.md
Normal file
42
site/content/versions.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
+++
|
||||||
|
description = "Versions"
|
||||||
|
+++
|
||||||
|
|
||||||
|
### v0.1.2
|
||||||
|
|
||||||
|
* [Web runtime](v0.1.2)
|
||||||
|
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-linux.tgz)
|
||||||
|
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-macos.tgz)
|
||||||
|
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-windows.zip)
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
* add option to `uw8 run` to run the cart in the browser using the web runtime
|
||||||
|
* CurlyWas: implement `include` support
|
||||||
|
* CurlyWas: implement support for constants
|
||||||
|
* fix crash when trying to draw zero sized line
|
||||||
|
|
||||||
|
### v0.1.1
|
||||||
|
|
||||||
|
* [Web runtime](v0.1.1)
|
||||||
|
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-linux.tgz)
|
||||||
|
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-macos.tgz)
|
||||||
|
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-windows.zip)
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
* implement more robust file watcher
|
||||||
|
* add basic video recording on F10 in web runtime
|
||||||
|
* add screenshot on F9
|
||||||
|
* add watchdog to interrupt hanging update in native runtime
|
||||||
|
* add devkit mode to web runtime
|
||||||
|
* add unpack and compile commands to uw8
|
||||||
|
* add support for table/element section in pack command
|
||||||
|
* disable wayland support (caused missing window decorations in gnome)
|
||||||
|
|
||||||
|
### v0.1.0
|
||||||
|
|
||||||
|
* [Web runtime](v0.1.0)
|
||||||
|
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-linux.tgz)
|
||||||
|
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-macos.tgz)
|
||||||
|
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-windows.zip)
|
||||||
1
site/static/v0.2.0rc1/index.html
Normal file
1
site/static/v0.2.0rc1/index.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -261,6 +261,8 @@ impl super::Runtime for MicroW8 {
|
|||||||
|
|
||||||
let (tx, rx) = mpsc::sync_channel::<[u8; 32]>(1);
|
let (tx, rx) = mpsc::sync_channel::<[u8; 32]>(1);
|
||||||
|
|
||||||
|
let start_time = Instant::now();
|
||||||
|
|
||||||
let mut sample_index = 0;
|
let mut sample_index = 0;
|
||||||
let stream = {
|
let stream = {
|
||||||
device.build_output_stream(
|
device.build_output_stream(
|
||||||
@@ -269,6 +271,13 @@ impl super::Runtime for MicroW8 {
|
|||||||
if let Ok(regs) = rx.try_recv() {
|
if let Ok(regs) = rx.try_recv() {
|
||||||
memory.write(&mut store, 80, ®s).unwrap();
|
memory.write(&mut store, 80, ®s).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let time = start_time.elapsed().as_millis() as i32;
|
||||||
|
let mem = memory.data_mut(&mut store);
|
||||||
|
mem[64..68].copy_from_slice(&time.to_le_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
for v in buffer {
|
for v in buffer {
|
||||||
*v = snd.call(&mut store, (sample_index,)).unwrap_or(0.0);
|
*v = snd.call(&mut store, (sample_index,)).unwrap_or(0.0);
|
||||||
sample_index = sample_index.wrapping_add(1);
|
sample_index = sample_index.wrapping_add(1);
|
||||||
|
|||||||
@@ -166,6 +166,8 @@ impl BaseModule {
|
|||||||
|
|
||||||
add_function(&mut functions, &type_map, "exp", &[F32], Some(F32));
|
add_function(&mut functions, &type_map, "exp", &[F32], Some(F32));
|
||||||
|
|
||||||
|
add_function(&mut functions, &type_map, "playNote", &[I32, I32], None);
|
||||||
|
|
||||||
for i in functions.len()..64 {
|
for i in functions.len()..64 {
|
||||||
add_function(
|
add_function(
|
||||||
&mut functions,
|
&mut functions,
|
||||||
@@ -291,7 +293,10 @@ impl BaseModule {
|
|||||||
|
|
||||||
pub fn write_as_cwa<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
pub fn write_as_cwa<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
||||||
fn inner(mut file: File, base: &BaseModule) -> Result<()> {
|
fn inner(mut file: File, base: &BaseModule) -> Result<()> {
|
||||||
writeln!(file, "// MicroW8 APIs, to be `include`d in CurlyWas sources")?;
|
writeln!(
|
||||||
|
file,
|
||||||
|
"// MicroW8 APIs, to be `include`d in CurlyWas sources"
|
||||||
|
)?;
|
||||||
writeln!(file, "import \"env.memory\" memory({});", base.memory)?;
|
writeln!(file, "import \"env.memory\" memory({});", base.memory)?;
|
||||||
writeln!(file)?;
|
writeln!(file)?;
|
||||||
for &(module, ref name, type_id) in &base.function_imports {
|
for &(module, ref name, type_id) in &base.function_imports {
|
||||||
@@ -402,5 +407,5 @@ const CONSTANTS: &[(&str, u32)] = &[
|
|||||||
("BUTTON_A", 4),
|
("BUTTON_A", 4),
|
||||||
("BUTTON_B", 5),
|
("BUTTON_B", 5),
|
||||||
("BUTTON_X", 6),
|
("BUTTON_X", 6),
|
||||||
("BUTTON_Y", 7)
|
("BUTTON_Y", 7),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -5,7 +5,11 @@ class APU extends AudioWorkletProcessor {
|
|||||||
this.sampleIndex = 0;
|
this.sampleIndex = 0;
|
||||||
this.port.onmessage = (ev) => {
|
this.port.onmessage = (ev) => {
|
||||||
if(this.memory) {
|
if(this.memory) {
|
||||||
|
if(isNaN(ev.data)) {
|
||||||
U8(this.memory.buffer, 80, 32).set(U8(ev.data));
|
U8(this.memory.buffer, 80, 32).set(U8(ev.data));
|
||||||
|
} else {
|
||||||
|
this.startTime = ev.data;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.load(ev.data[0], ev.data[1]);
|
this.load(ev.data[0], ev.data[1]);
|
||||||
}
|
}
|
||||||
@@ -51,7 +55,9 @@ class APU extends AudioWorkletProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
process(inputs, outputs, parameters) {
|
process(inputs, outputs, parameters) {
|
||||||
if(this.snd) {
|
if(this.snd && this.startTime) {
|
||||||
|
let u32Mem = new Uint32Array(this.memory.buffer);
|
||||||
|
u32Mem[16] = Date.now() - this.startTime;
|
||||||
let channels = outputs[0];
|
let channels = outputs[0];
|
||||||
let index = this.sampleIndex;
|
let index = this.sampleIndex;
|
||||||
let numSamples = channels[0].length;
|
let numSamples = channels[0].length;
|
||||||
|
|||||||
@@ -91,13 +91,16 @@ export default function MicroW8(screen, config = {}) {
|
|||||||
keyboardElement.onkeyup = keyHandler;
|
keyboardElement.onkeyup = keyHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let audioContext;
|
||||||
|
let audioNode;
|
||||||
|
|
||||||
async function runModule(data, keepUrl) {
|
async function runModule(data, keepUrl) {
|
||||||
if (cancelFunction) {
|
if (cancelFunction) {
|
||||||
cancelFunction();
|
cancelFunction();
|
||||||
cancelFunction = null;
|
cancelFunction = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let audioContext = new AudioContext({sampleRate: 44100});
|
audioContext = new AudioContext({sampleRate: 44100});
|
||||||
let keepRunning = true;
|
let keepRunning = true;
|
||||||
let abortController = new AbortController();
|
let abortController = new AbortController();
|
||||||
cancelFunction = () => {
|
cancelFunction = () => {
|
||||||
@@ -114,7 +117,7 @@ export default function MicroW8(screen, config = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await audioContext.audioWorklet.addModule(audioWorkletUrl);
|
await audioContext.audioWorklet.addModule(audioWorkletUrl);
|
||||||
let audioNode = new AudioNode(audioContext);
|
audioNode = new AudioNode(audioContext);
|
||||||
|
|
||||||
let audioReadyFlags = 0;
|
let audioReadyFlags = 0;
|
||||||
let audioReadyResolve;
|
let audioReadyResolve;
|
||||||
@@ -126,7 +129,6 @@ export default function MicroW8(screen, config = {}) {
|
|||||||
audioReadyResolve = null;
|
audioReadyResolve = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
audioNode.port.onmessage = (e) => updateAudioReady(e.data);
|
|
||||||
let audioStateChange = () => {
|
let audioStateChange = () => {
|
||||||
if(audioContext.state == 'suspended') {
|
if(audioContext.state == 'suspended') {
|
||||||
if(config.startButton) {
|
if(config.startButton) {
|
||||||
@@ -211,6 +213,8 @@ export default function MicroW8(screen, config = {}) {
|
|||||||
data = loadModuleData(data);
|
data = loadModuleData(data);
|
||||||
|
|
||||||
let platform_data = await loadModuleURL(platformUrl);
|
let platform_data = await loadModuleURL(platformUrl);
|
||||||
|
|
||||||
|
audioNode.port.onmessage = (e) => updateAudioReady(e.data);
|
||||||
audioNode.port.postMessage([platform_data, data]);
|
audioNode.port.postMessage([platform_data, data]);
|
||||||
|
|
||||||
let platform_instance = await instantiate(platform_data);
|
let platform_instance = await instantiate(platform_data);
|
||||||
@@ -240,10 +244,12 @@ export default function MicroW8(screen, config = {}) {
|
|||||||
isPaused = false;
|
isPaused = false;
|
||||||
audioContext.resume();
|
audioContext.resume();
|
||||||
startTime += now - pauseTime;
|
startTime += now - pauseTime;
|
||||||
|
audioNode.port.postMessage(startTime);
|
||||||
} else {
|
} else {
|
||||||
isPaused = true;
|
isPaused = true;
|
||||||
audioContext.suspend();
|
audioContext.suspend();
|
||||||
pauseTime = now;
|
pauseTime = now;
|
||||||
|
audioNode.port.postMessage(0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
window.addEventListener('focus', () => updateVisibility(true), { signal: abortController.signal });
|
window.addEventListener('focus', () => updateVisibility(true), { signal: abortController.signal });
|
||||||
@@ -331,14 +337,25 @@ export default function MicroW8(screen, config = {}) {
|
|||||||
|
|
||||||
let videoRecorder;
|
let videoRecorder;
|
||||||
let videoStartTime;
|
let videoStartTime;
|
||||||
|
let videoAudioSourceNode;
|
||||||
|
let videoAudioStreamNode;
|
||||||
function recordVideo() {
|
function recordVideo() {
|
||||||
if(videoRecorder) {
|
if(videoRecorder) {
|
||||||
videoRecorder.stop();
|
videoRecorder.stop();
|
||||||
videoRecorder = null;
|
videoRecorder = null;
|
||||||
|
videoAudioSourceNode.disconnect(videoAudioStreamNode);
|
||||||
|
videoAudioSourceNode = null;
|
||||||
|
videoAudioStreamNode = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
videoRecorder = new MediaRecorder(screen.captureStream(), {
|
let stream = screen.captureStream();
|
||||||
|
videoAudioStreamNode = audioContext.createMediaStreamDestination();
|
||||||
|
videoAudioSourceNode = audioNode;
|
||||||
|
audioNode.connect(videoAudioStreamNode);
|
||||||
|
stream.addTrack(videoAudioStreamNode.stream.getAudioTracks()[0]);
|
||||||
|
|
||||||
|
videoRecorder = new MediaRecorder(stream, {
|
||||||
mimeType: 'video/webm',
|
mimeType: 'video/webm',
|
||||||
videoBitsPerSecond: 25000000
|
videoBitsPerSecond: 25000000
|
||||||
});
|
});
|
||||||
|
|||||||
4559
web/yarn.lock
4559
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user