diff --git a/crates/forth/src/lib.rs b/crates/forth/src/lib.rs index 169af86..d05fc1b 100644 --- a/crates/forth/src/lib.rs +++ b/crates/forth/src/lib.rs @@ -9,4 +9,4 @@ pub use types::{ CcAccess, Dictionary, ExecutionTrace, Rng, SourceSpan, StepContext, Value, Variables, }; pub use vm::Forth; -pub use words::{Word, WordCompile, WORDS}; +pub use words::{lookup_word, Word, WordCompile, WORDS}; diff --git a/crates/forth/src/words.rs b/crates/forth/src/words.rs index 2e105fd..7e29158 100644 --- a/crates/forth/src/words.rs +++ b/crates/forth/src/words.rs @@ -2806,7 +2806,7 @@ static WORD_MAP: LazyLock> = LazyLock::new( map }); -fn lookup_word(name: &str) -> Option<&'static Word> { +pub fn lookup_word(name: &str) -> Option<&'static Word> { WORD_MAP.get(name).copied() } diff --git a/src/main.rs b/src/main.rs index d0310d4..0f6b9bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -329,14 +329,11 @@ fn main() -> io::Result<()> { app.flush_queued_changes(&sequencer.cmd_tx); app.flush_dirty_patterns(&sequencer.cmd_tx); - if app.ui.show_title { - app.ui.sparkles.tick(terminal.get_frame().area()); - } - terminal.draw(|frame| views::render(frame, &app, &link, &seq_snapshot))?; - - if event::poll(Duration::from_millis( + let had_event = event::poll(Duration::from_millis( app.audio.config.refresh_rate.millis(), - ))? { + ))?; + + if had_event { match event::read()? { Event::Key(key) => { let mut ctx = InputContext { @@ -362,6 +359,13 @@ fn main() -> io::Result<()> { _ => {} } } + + if app.playback.playing || had_event || app.ui.show_title { + if app.ui.show_title { + app.ui.sparkles.tick(terminal.get_frame().area()); + } + terminal.draw(|frame| views::render(frame, &app, &link, &seq_snapshot))?; + } } disable_raw_mode()?; diff --git a/src/model/mod.rs b/src/model/mod.rs index 086b7d5..4298009 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -1,6 +1,6 @@ mod script; -pub use cagire_forth::{Word, WordCompile, WORDS}; +pub use cagire_forth::{lookup_word, Word, WordCompile, WORDS}; pub use cagire_project::{ load, save, Bank, LaunchQuantization, Pattern, PatternSpeed, Project, SyncMode, MAX_BANKS, MAX_PATTERNS, diff --git a/src/state/audio.rs b/src/state/audio.rs index 6cf527d..fca19fb 100644 --- a/src/state/audio.rs +++ b/src/state/audio.rs @@ -22,21 +22,25 @@ pub enum RefreshRate { #[default] Fps60, Fps30, + Fps15, } impl RefreshRate { pub fn from_fps(fps: u32) -> Self { if fps >= 60 { RefreshRate::Fps60 - } else { + } else if fps >= 30 { RefreshRate::Fps30 + } else { + RefreshRate::Fps15 } } pub fn toggle(self) -> Self { match self { RefreshRate::Fps60 => RefreshRate::Fps30, - RefreshRate::Fps30 => RefreshRate::Fps60, + RefreshRate::Fps30 => RefreshRate::Fps15, + RefreshRate::Fps15 => RefreshRate::Fps60, } } @@ -44,6 +48,7 @@ impl RefreshRate { match self { RefreshRate::Fps60 => 16, RefreshRate::Fps30 => 33, + RefreshRate::Fps15 => 66, } } @@ -51,6 +56,7 @@ impl RefreshRate { match self { RefreshRate::Fps60 => "60", RefreshRate::Fps30 => "30", + RefreshRate::Fps15 => "15", } } @@ -58,6 +64,7 @@ impl RefreshRate { match self { RefreshRate::Fps60 => 60, RefreshRate::Fps30 => 30, + RefreshRate::Fps15 => 15, } } } diff --git a/src/views/highlight.rs b/src/views/highlight.rs index 477f90e..76d22eb 100644 --- a/src/views/highlight.rs +++ b/src/views/highlight.rs @@ -1,6 +1,6 @@ use ratatui::style::{Modifier, Style}; -use crate::model::{SourceSpan, WordCompile, WORDS}; +use crate::model::{lookup_word, SourceSpan, WordCompile}; use crate::theme; #[derive(Clone, Copy, PartialEq, Eq)] @@ -73,27 +73,23 @@ fn lookup_word_kind(word: &str) -> Option<(TokenKind, bool)> { return Some((TokenKind::Emit, true)); } - for w in WORDS { - if w.name == word || w.aliases.contains(&word) { - let kind = match &w.compile { - WordCompile::Param => TokenKind::Param, - WordCompile::Context(_) => TokenKind::Context, - _ => match w.category { - "Stack" => TokenKind::StackOp, - "Arithmetic" | "Comparison" | "Music" => TokenKind::Operator, - "Logic" if matches!(w.name, "and" | "or" | "not" | "xor" | "nand" | "nor") => { - TokenKind::Operator - } - "Sound" => TokenKind::Sound, - "Randomness" | "Probability" | "Selection" => TokenKind::Vary, - "Generator" => TokenKind::Generator, - _ => TokenKind::Keyword, - }, - }; - return Some((kind, w.varargs)); - } - } - None + let w = lookup_word(word)?; + let kind = match &w.compile { + WordCompile::Param => TokenKind::Param, + WordCompile::Context(_) => TokenKind::Context, + _ => match w.category { + "Stack" => TokenKind::StackOp, + "Arithmetic" | "Comparison" | "Music" => TokenKind::Operator, + "Logic" if matches!(w.name, "and" | "or" | "not" | "xor" | "nand" | "nor") => { + TokenKind::Operator + } + "Sound" => TokenKind::Sound, + "Randomness" | "Probability" | "Selection" => TokenKind::Vary, + "Generator" => TokenKind::Generator, + _ => TokenKind::Keyword, + }, + }; + Some((kind, w.varargs)) } fn is_note(word: &str) -> bool {