Reintroduce apps/arcade and the ten game crates that were ripped out of
the fork (assets, audio, blocks, coedit, gen, net, pkg, render, script,
session), from makepad-internal/dev. Reconcile against the fork's layout:
- makepad-game-sim/math come from the fork's existing libs/sim + sim/math;
the copied internal libs/game/{sim,math} are dropped and the kept game
crates plus arcade point at ../../sim and ../../sim/math.
- arcade AI is rewritten off the removed makepad-ai agent API onto the
makepad-ai-hub headless ChatProvider worker (example/cad pattern):
AiWorker{send,cancel,poll}, ai_worker_loop driving
ClaudeApiChatProvider(ClaudeCli), AiWorkerEvent availability/delta/
done/error mapped into the chat feed and authoring land_edit, with
main.rs send_message/cancel_request/event-drain rebuilt around it.
- the game-script sandbox is adapted to the fork's jailed splash storage:
every isolate gets mod.fs = splash_storage jail; splaes splash_storage
set_root_for_heap is now public so the ScriptHost (or Splash) can grant
a per-game jail root. ENT font: build.rs/dispatch.rs entities fill new
fork sim Entity/Part fields via ..Default::default(); world_raycast now
borrows mutably and returns the material id.
cargo check -p makepad-arcade and the game + arcade test suites pass.
51 lines
1.9 KiB
Rust
51 lines
1.9 KiB
Rust
//! Per-channel comparison: tells swapped channels apart from a broken
|
|
//! coupling (one channel right, the other wrong).
|
|
//! Usage: vorbis_ch <file.ogg> <ref.wav>
|
|
use makepad_game_audio as audio;
|
|
|
|
fn corr(a: &[f32], b: &[f32]) -> f64 {
|
|
let n = a.len().min(b.len());
|
|
let (mut num, mut da, mut db) = (0f64, 0f64, 0f64);
|
|
for i in 0..n {
|
|
let (x, y) = (a[i] as f64, b[i] as f64);
|
|
num += x * y;
|
|
da += x * x;
|
|
db += y * y;
|
|
}
|
|
if da <= 0.0 || db <= 0.0 {
|
|
return 0.0;
|
|
}
|
|
num / (da.sqrt() * db.sqrt())
|
|
}
|
|
|
|
fn chan(p: &audio::Pcm, c: usize) -> Vec<f32> {
|
|
p.samples.iter().skip(c).step_by(p.channels).cloned().collect()
|
|
}
|
|
|
|
fn main() {
|
|
let a: Vec<String> = std::env::args().collect();
|
|
let got = audio::decode(&std::fs::read(&a[1]).expect("ogg")).expect("decode");
|
|
let want = audio::wav::decode(&std::fs::read(&a[2]).expect("ref")).expect("ref");
|
|
println!("ch={} got={} ref={}", got.channels, got.frames(), want.frames());
|
|
if got.channels < 2 {
|
|
println!("mono: corr {:.4}", corr(&got.samples, &want.samples));
|
|
return;
|
|
}
|
|
let (gl, gr) = (chan(&got, 0), chan(&got, 1));
|
|
let (wl, wr) = (chan(&want, 0), chan(&want, 1));
|
|
println!(" L->L {:.4} L->R {:.4}", corr(&gl, &wl), corr(&gl, &wr));
|
|
println!(" R->R {:.4} R->L {:.4}", corr(&gr, &wr), corr(&gr, &wl));
|
|
// Mid/side view: coupling errors usually leave the mid intact and wreck
|
|
// the side, which is invisible in a plain per-channel correlation.
|
|
let mid = |l: &[f32], r: &[f32]| -> Vec<f32> {
|
|
l.iter().zip(r).map(|(a, b)| (a + b) * 0.5).collect()
|
|
};
|
|
let side = |l: &[f32], r: &[f32]| -> Vec<f32> {
|
|
l.iter().zip(r).map(|(a, b)| (a - b) * 0.5).collect()
|
|
};
|
|
println!(
|
|
" mid {:.4} side {:.4}",
|
|
corr(&mid(&gl, &gr), &mid(&wl, &wr)),
|
|
corr(&side(&gl, &gr), &side(&wl, &wr))
|
|
);
|
|
}
|