Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified assets/cali.ogg
Binary file not shown.
3 changes: 3 additions & 0 deletions phira/locales/en-US/cali.ftl
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@

label = CALIBRATION

now = Now:
avg = Avg:
3 changes: 3 additions & 0 deletions phira/locales/zh-CN/cali.ftl
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@

label = 延迟校准

now = 当前偏移:
avg = 平均偏移:
128 changes: 80 additions & 48 deletions phira/src/page/offset.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
prpr_l10n::tl_file!("cali");

use std::borrow::Cow;
use std::{borrow::Cow, collections::VecDeque};

use super::{Page, SharedState};
use crate::{get_data, get_data_mut, save_data};
use anyhow::{Context, Result};
use macroquad::prelude::*;
use prpr::{
core::{ParticleEmitter, ResourcePack, NOTE_WIDTH_RATIO_BASE},
ext::{create_audio_manger, semi_black, RectExt, SafeTexture, ScaleType},
core::ResourcePack,
ext::{create_audio_manger, screen_aspect, semi_black, RectExt},
time::TimeManager,
ui::{Slider, Ui},
ui::{Slider, Ui}
};
use sasa::{AudioClip, AudioManager, Music, MusicParams, PlaySfxParams, Sfx};

Expand All @@ -20,28 +20,27 @@ pub struct OffsetPage {
cali_hit: Sfx,

tm: TimeManager,
cali_last: bool,

click: SafeTexture,
_hit_fx: SafeTexture,
emitter: ParticleEmitter,
color: Color,

slider: Slider,

touched: bool,
touch: Option<(f32, f32)>,

latency_record: VecDeque<f32>,
}

impl OffsetPage {
const FADE_TIME: f32 = 0.8;

pub async fn new() -> Result<Self> {
let config = &get_data().config;
let mut audio = create_audio_manger(&get_data().config)?;
let cali = audio.create_music(
AudioClip::new(load_file("cali.ogg").await?)?,
MusicParams {
loop_mix_time: 0.,
amplifier: config.volume_music,
..Default::default()
},
)?;
Expand All @@ -50,31 +49,27 @@ impl OffsetPage {
let mut tm = TimeManager::new(1., true);
tm.force = 3e-2;

let respack = ResourcePack::from_path(get_data().config.res_pack_path.as_ref())
let respack = ResourcePack::from_path(config.res_pack_path.as_ref())
.await
.context("Failed to load resource pack")?;
let click = respack.note_style.click.clone();
let emitter = ParticleEmitter::new(&respack, get_data().config.note_scale, respack.info.hide_particles)?;

let latency_record: VecDeque<f32> = VecDeque::new();
Ok(Self {
_audio: audio,
cali,
cali_hit,

tm,
cali_last: false,

click,
_hit_fx: respack.hit_fx,
emitter,
color: respack.info.fx_perfect(),

slider: Slider::new(-500.0..500.0, 5.),
slider: Slider::new(-200.0..800.0, 1.),

touched: false,
touch: None,

latency_record,
})
}
}
}}

impl Page for OffsetPage {
fn can_play_bgm(&self) -> bool {
Expand Down Expand Up @@ -118,7 +113,12 @@ impl Page for OffsetPage {
config.offset = offset / 1000.;
return Ok(true);
}
if touch.phase == TouchPhase::Started && touch.position.x < 0. {
let x = touch.position.x;
let y = touch.position.y * screen_aspect();
if touch.phase == TouchPhase::Started
&& (-0.97..0.97).contains(&x)
&& (-0.60..0.00).contains(&y)
{
self.touched = true;
}
Ok(false)
Expand All @@ -137,54 +137,61 @@ impl Page for OffsetPage {
self.tm.update(pos);
}
}

let config = &mut get_data_mut().config;
if let Some(key) = get_last_key_pressed() {
if key == KeyCode::Left {
config.offset -= 0.005;
} else if key == KeyCode::Right {
config.offset += 0.005;
} else {
self.touched = true;
};
};
Ok(())
}

fn render(&mut self, ui: &mut Ui, s: &mut SharedState) -> Result<()> {
let t = s.t;
let aspect = 1. / screen_aspect();
let config = &get_data().config;
s.render_fader(ui, |ui| {
let lf = -0.92;
let lf = -0.97;
let mut r = ui.content_rect();
r.w += r.x - lf;
r.x = lf;
ui.fill_path(&r.rounded(0.02), semi_black(0.4));

let ct = (-0.4, r.bottom() - 0.12);
let hw = 0.4;
let hh = 0.005;
ui.fill_rect(Rect::new(ct.0 - hw, ct.1 - hh, hw * 2., hh * 2.), WHITE);
let ct = r.center();
let hw = 0.3 * aspect * 1.7777777;
let hh = 0.0075;
ui.fill_rect(Rect::new(0.0 - hh / 2., ct.y - aspect * 0.4 - hw / 2., hh, hw), WHITE);

let ot = t;

let config = &get_data().config;
let mut t = self.tm.now() as f32 - config.offset;

if t < 0. {
t += 2.;
}
if t >= 2. {
t -= 2.;
}
let ny = ct.1 + (t - 1.) * 0.6;
let latency = t - 1.;
if self.touched {
self.touch = Some((ot, ny));
self.touched = false;
}
if t <= 1. {
let w = NOTE_WIDTH_RATIO_BASE * config.note_scale * 2.;
let h = w * self.click.height() / self.click.width();
let r = Rect::new(ct.0 - w / 2., ny, w, h);
ui.fill_rect(r, (*self.click, r, ScaleType::Fit));
self.cali_last = true;
} else {
if self.cali_last {
let g = ui.to_global(ct);
self.emitter.emit_at(vec2(g.0, g.1), 0., self.color);
let _ = self.cali_hit.play(PlaySfxParams::default());
self.touch = Some((latency, ot));
if latency.abs() < 0.200 {
self.latency_record.push_back(latency);
if self.latency_record.len() > 10 {
self.latency_record.pop_front();
}
}
self.cali_last = false;
self.touched = false;
self.cali_hit.play(PlaySfxParams {
amplifier: config.volume_sfx,
}).unwrap();
}

if let Some((time, pos)) = &self.touch {
if let Some((latency, time)) = self.touch {
let p = (ot - time) / Self::FADE_TIME;
if p > 1. {
self.touch = None;
Expand All @@ -194,16 +201,41 @@ impl Page for OffsetPage {
a: (if p <= 0.5 { 1. } else { (1. - p) * 2. }) * self.color.a,
..self.color
};
ui.fill_rect(Rect::new(ct.0 - hw, pos - hh, hw * 2., hh * 2.), c);
if latency.abs() <= 0.700 {
ui.fill_rect(Rect::new(calculate_pos(latency) - hh / 2., ct.y - aspect * 0.4 - hw / 2., hh, hw), c);
}

ui.text(format!("{} {:.0}ms", tl!("now"), latency * 1000.))
.pos(0.0, ct.y + aspect * 0.3)
.anchor(0.5, 1.)
.size(0.5)
.color(Color::new(1., 1., 1., 0.8 * c.a))
.draw();
}
}

let avg_latency = if self.latency_record.is_empty() {
0.0
} else {
self.latency_record.iter().sum::<f32>() / self.latency_record.len() as f32
};
ui.text(format!("{} {:.0}ms", tl!("avg"), avg_latency * 1000.))
.pos(0.0, ct.y + aspect * 0.4)
.anchor(0.5, 1.)
.size(0.5)
.color(Color::new(1., 1., 1., 0.8))
.draw();

let offset = config.offset * 1000.;
self.slider
.render(ui, Rect::new(0.46, -0.1, 0.45, 0.2), ot, offset, format!("{offset:.0}ms"));
.render(ui, Rect::new(-0.08, ct.y + aspect * 0.1 - 0.2 / 2., 0.45, 0.2), ot, offset, format!("{offset:.0}ms"));
});

self.emitter.draw(get_frame_time());
fn calculate_pos(x: f32) -> f32 {
let base = (x.abs() * 9.0) + 1.0;
let value = base.log(10.0);
value * x.signum()
}

Ok(())
}
Expand Down