mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
remove unused fields from arranger
This commit is contained in:
parent
e2492a1326
commit
326507f400
8 changed files with 172 additions and 46 deletions
|
|
@ -9,24 +9,32 @@ pub fn main () -> Usually<()> {
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
pub struct ArrangerCli {
|
pub struct ArrangerCli {
|
||||||
/// Name of JACK client
|
/// Name of JACK client
|
||||||
#[arg(short, long)] name: Option<String>,
|
#[arg(short, long)]
|
||||||
|
name: Option<String>,
|
||||||
|
|
||||||
/// Whether to include a transport toolbar (default: true)
|
/// Whether to include a transport toolbar (default: true)
|
||||||
#[arg(short, long, default_value_t = true)] transport: bool,
|
#[arg(short, long, default_value_t = true)]
|
||||||
|
transport: bool,
|
||||||
|
|
||||||
/// Number of tracks
|
/// Number of tracks
|
||||||
#[arg(short = 'x', long, default_value_t = 8)] tracks: usize,
|
#[arg(short = 'x', long, default_value_t = 8)]
|
||||||
|
tracks: usize,
|
||||||
|
|
||||||
/// Number of scenes
|
/// Number of scenes
|
||||||
#[arg(short, long, default_value_t = 8)] scenes: usize,
|
#[arg(short, long, default_value_t = 8)]
|
||||||
|
scenes: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArrangerCli {
|
impl ArrangerCli {
|
||||||
/// Run the arranger TUI from CLI arguments.
|
/// Run the arranger TUI from CLI arguments.
|
||||||
fn run (&self) -> Usually<()> {
|
fn run (&self) -> Usually<()> {
|
||||||
Tui::run(JackClient::new("tek_arranger")?.activate_with(|jack|{
|
let mut client_name = String::from("tek_arranger");
|
||||||
|
if let Some(name) = self.name.as_ref() {
|
||||||
|
client_name = name.clone();
|
||||||
|
}
|
||||||
|
Tui::run(JackClient::new(client_name.as_str())?.activate_with(|jack|{
|
||||||
let mut app = ArrangerTui::try_from(jack)?;
|
let mut app = ArrangerTui::try_from(jack)?;
|
||||||
app.color = ItemPalette::random();
|
app.color = ItemPalette::random();
|
||||||
if let Some(name) = self.name.as_ref() {
|
|
||||||
*app.name.write().unwrap() = name.clone();
|
|
||||||
}
|
|
||||||
let track_color_1 = ItemColor::random();
|
let track_color_1 = ItemColor::random();
|
||||||
let track_color_2 = ItemColor::random();
|
let track_color_2 = ItemColor::random();
|
||||||
for i in 0..self.tracks {
|
for i in 0..self.tracks {
|
||||||
|
|
|
||||||
|
|
@ -61,18 +61,18 @@ impl From<Color> for ItemPalette {
|
||||||
impl From<ItemColor> for ItemPalette {
|
impl From<ItemColor> for ItemPalette {
|
||||||
fn from (base: ItemColor) -> Self {
|
fn from (base: ItemColor) -> Self {
|
||||||
let mut light = base.okhsl.clone();
|
let mut light = base.okhsl.clone();
|
||||||
light.lightness = (light.lightness * 4. / 3.).min(Okhsl::<f32>::max_lightness());
|
light.lightness = (light.lightness * 1.3).min(Okhsl::<f32>::max_lightness());
|
||||||
let mut lighter = light.clone();
|
let mut lighter = light.clone();
|
||||||
lighter.lightness = (lighter.lightness * 5. / 3.).min(Okhsl::<f32>::max_lightness());
|
lighter.lightness = (lighter.lightness * 1.3).min(Okhsl::<f32>::max_lightness());
|
||||||
let mut lightest = lighter.clone();
|
let mut lightest = lighter.clone();
|
||||||
lightest.lightness = (lightest.lightness * 4. / 3.).min(Okhsl::<f32>::max_lightness());
|
lightest.lightness = (lightest.lightness * 1.3).min(Okhsl::<f32>::max_lightness());
|
||||||
|
|
||||||
let mut dark = base.okhsl.clone();
|
let mut dark = base.okhsl.clone();
|
||||||
dark.lightness = (dark.lightness * 0.75).max(Okhsl::<f32>::min_lightness());
|
dark.lightness = (dark.lightness * 0.75).max(Okhsl::<f32>::min_lightness());
|
||||||
dark.saturation = (dark.saturation * 0.75).max(Okhsl::<f32>::min_saturation());
|
dark.saturation = (dark.saturation * 0.75).max(Okhsl::<f32>::min_saturation());
|
||||||
let mut darker = dark.clone();
|
let mut darker = dark.clone();
|
||||||
darker.lightness = (darker.lightness * 0.66).max(Okhsl::<f32>::min_lightness());
|
darker.lightness = (darker.lightness * 0.66).max(Okhsl::<f32>::min_lightness());
|
||||||
darker.saturation = (darker.saturation * 0.66).max(Okhsl::<f32>::min_saturation());
|
darker.saturation = (darker.saturation * 0.66).max(Okhsl::<f32>::min_saturation());
|
||||||
let mut darkest = darker.clone();
|
let mut darkest = darker.clone();
|
||||||
darkest.lightness = (darkest.lightness * 0.50).max(Okhsl::<f32>::min_lightness());
|
darkest.lightness = (darkest.lightness * 0.50).max(Okhsl::<f32>::min_lightness());
|
||||||
darkest.saturation = (darkest.saturation * 0.50).max(Okhsl::<f32>::min_saturation());
|
darkest.saturation = (darkest.saturation * 0.50).max(Okhsl::<f32>::min_saturation());
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
use crate::*;
|
||||||
|
use std::thread::{spawn, JoinHandle};
|
||||||
|
use ::winit::{
|
||||||
|
application::ApplicationHandler,
|
||||||
|
event::WindowEvent,
|
||||||
|
event_loop::{ActiveEventLoop, ControlFlow, EventLoop},
|
||||||
|
window::{Window, WindowId},
|
||||||
|
platform::x11::EventLoopBuilderExtX11
|
||||||
|
};
|
||||||
|
|
||||||
|
//pub struct LV2PluginUI {
|
||||||
|
//write: (),
|
||||||
|
//controller: (),
|
||||||
|
//widget: (),
|
||||||
|
//features: (),
|
||||||
|
//transfer: (),
|
||||||
|
//}
|
||||||
|
|
||||||
|
pub fn run_lv2_ui (mut ui: LV2PluginUI) -> Usually<JoinHandle<()>> {
|
||||||
|
Ok(spawn(move||{
|
||||||
|
let event_loop = EventLoop::builder().with_x11().with_any_thread(true).build().unwrap();
|
||||||
|
event_loop.set_control_flow(ControlFlow::Wait);
|
||||||
|
event_loop.run_app(&mut ui).unwrap()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A LV2 plugin's X11 UI.
|
||||||
|
pub struct LV2PluginUI {
|
||||||
|
pub window: Option<Window>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LV2PluginUI {
|
||||||
|
pub fn new () -> Usually<Self> {
|
||||||
|
Ok(Self { window: None })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicationHandler for LV2PluginUI {
|
||||||
|
fn resumed (&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
self.window = Some(event_loop.create_window(Window::default_attributes()).unwrap());
|
||||||
|
}
|
||||||
|
fn window_event (&mut self, event_loop: &ActiveEventLoop, id: WindowId, event: WindowEvent) {
|
||||||
|
match event {
|
||||||
|
WindowEvent::CloseRequested => {
|
||||||
|
self.window.as_ref().unwrap().set_visible(false);
|
||||||
|
event_loop.exit();
|
||||||
|
},
|
||||||
|
WindowEvent::RedrawRequested => {
|
||||||
|
self.window.as_ref().unwrap().request_redraw();
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lv2_ui_instantiate (kind: &str) {
|
||||||
|
//let host = Suil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use ::livi::{
|
||||||
|
World,
|
||||||
|
Instance,
|
||||||
|
Plugin as LiviPlugin,
|
||||||
|
Features,
|
||||||
|
FeaturesBuilder,
|
||||||
|
Port,
|
||||||
|
event::LV2AtomSequence,
|
||||||
|
};
|
||||||
|
use std::thread::JoinHandle;
|
||||||
|
|
||||||
|
/// A LV2 plugin.
|
||||||
|
pub struct LV2Plugin {
|
||||||
|
pub world: World,
|
||||||
|
pub instance: Instance,
|
||||||
|
pub plugin: LiviPlugin,
|
||||||
|
pub features: Arc<Features>,
|
||||||
|
pub port_list: Vec<Port>,
|
||||||
|
pub input_buffer: Vec<LV2AtomSequence>,
|
||||||
|
pub ui_thread: Option<JoinHandle<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LV2Plugin {
|
||||||
|
const INPUT_BUFFER: usize = 1024;
|
||||||
|
pub fn new (uri: &str) -> Usually<Self> {
|
||||||
|
// Get 1st plugin at URI
|
||||||
|
let world = World::with_load_bundle(&uri);
|
||||||
|
let features = FeaturesBuilder { min_block_length: 1, max_block_length: 65536 };
|
||||||
|
let features = world.build_features(features);
|
||||||
|
let mut plugin = None;
|
||||||
|
if let Some(p) = world.iter_plugins().next() { plugin = Some(p); }
|
||||||
|
let plugin = plugin.expect("plugin not found");
|
||||||
|
let err = &format!("init {uri}");
|
||||||
|
let instance = unsafe { plugin.instantiate(features.clone(), 48000.0).expect(&err) };
|
||||||
|
let mut port_list = vec![];
|
||||||
|
for port in plugin.ports() {
|
||||||
|
port_list.push(port);
|
||||||
|
}
|
||||||
|
let input_buffer = Vec::with_capacity(Self::INPUT_BUFFER);
|
||||||
|
// Instantiate
|
||||||
|
Ok(Self {
|
||||||
|
world, instance, port_list, plugin, features, input_buffer, ui_thread: None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
impl<E: Engine> ::vst::host::Host for Plugin<E> {}
|
||||||
|
|
||||||
|
fn set_vst_plugin <E: Engine> (host: &Arc<Mutex<Plugin<E>>>, _path: &str) -> Usually<PluginKind> {
|
||||||
|
let mut loader = ::vst::host::PluginLoader::load(
|
||||||
|
&std::path::Path::new("/nix/store/ij3sz7nqg5l7v2dygdvzy3w6cj62bd6r-helm-0.9.0/lib/lxvst/helm.so"),
|
||||||
|
host.clone()
|
||||||
|
)?;
|
||||||
|
Ok(PluginKind::VST2 {
|
||||||
|
instance: loader.instance()?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
//! TODO
|
||||||
|
|
||||||
|
|
@ -1,48 +1,45 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use ClockCommand::{Play, Pause};
|
use ClockCommand::{Play, Pause};
|
||||||
use KeyCode::{Char, Down, Right, Delete};
|
use KeyCode::{Char, Delete};
|
||||||
/// Root view for standalone `tek_arranger`
|
/// Root view for standalone `tek_arranger`
|
||||||
pub struct ArrangerTui {
|
pub struct ArrangerTui {
|
||||||
pub jack: Arc<RwLock<JackClient>>,
|
jack: Arc<RwLock<JackClient>>,
|
||||||
pub clock: ClockModel,
|
pub clock: ClockModel,
|
||||||
pub phrases: PhraseListModel,
|
pub phrases: PhraseListModel,
|
||||||
pub tracks: Vec<ArrangerTrack>,
|
pub tracks: Vec<ArrangerTrack>,
|
||||||
pub scenes: Vec<ArrangerScene>,
|
pub scenes: Vec<ArrangerScene>,
|
||||||
pub name: Arc<RwLock<String>>,
|
|
||||||
pub splits: [u16;2],
|
pub splits: [u16;2],
|
||||||
pub selected: ArrangerSelection,
|
pub selected: ArrangerSelection,
|
||||||
pub mode: ArrangerMode,
|
pub mode: ArrangerMode,
|
||||||
pub color: ItemPalette,
|
pub color: ItemPalette,
|
||||||
pub size: Measure<Tui>,
|
pub size: Measure<Tui>,
|
||||||
pub cursor: (usize, usize),
|
|
||||||
pub menu_bar: Option<MenuBar<Tui, Self, ArrangerCommand>>,
|
|
||||||
pub status_bar: Option<ArrangerStatus>,
|
|
||||||
pub history: Vec<ArrangerCommand>,
|
|
||||||
pub note_buf: Vec<u8>,
|
pub note_buf: Vec<u8>,
|
||||||
pub midi_buf: Vec<Vec<Vec<u8>>>,
|
pub midi_buf: Vec<Vec<Vec<u8>>>,
|
||||||
pub editor: PhraseEditorModel,
|
pub editor: PhraseEditorModel,
|
||||||
pub perf: PerfModel,
|
pub perf: PerfModel,
|
||||||
}
|
}
|
||||||
from_jack!(|jack| ArrangerTui Self {
|
from_jack!(|jack| ArrangerTui {
|
||||||
jack: jack.clone(),
|
let clock = ClockModel::from(jack);
|
||||||
clock: ClockModel::from(jack),
|
let phrase = Arc::new(RwLock::new(Phrase::new(
|
||||||
phrases: PhraseListModel::default(),
|
"New", true, 4 * clock.timebase.ppq.get() as usize,
|
||||||
editor: PhraseEditorModel::default(),
|
None, Some(ItemColor::random().into())
|
||||||
selected: ArrangerSelection::Clip(0, 0),
|
)));
|
||||||
scenes: vec![],
|
Self {
|
||||||
tracks: vec![],
|
clock,
|
||||||
color: TuiTheme::bg().into(),
|
phrases: PhraseListModel::from(&phrase),
|
||||||
history: vec![],
|
editor: PhraseEditorModel::from(&phrase),
|
||||||
mode: ArrangerMode::V(1),
|
selected: ArrangerSelection::Clip(0, 0),
|
||||||
name: Arc::new(RwLock::new(String::new())),
|
scenes: vec![],
|
||||||
size: Measure::new(),
|
tracks: vec![],
|
||||||
cursor: (0, 0),
|
color: TuiTheme::bg().into(),
|
||||||
splits: [16, 20],
|
mode: ArrangerMode::V(1),
|
||||||
menu_bar: None,
|
size: Measure::new(),
|
||||||
status_bar: None,
|
splits: [16, 20],
|
||||||
midi_buf: vec![vec![];65536],
|
midi_buf: vec![vec![];65536],
|
||||||
note_buf: vec![],
|
note_buf: vec![],
|
||||||
perf: PerfModel::default(),
|
perf: PerfModel::default(),
|
||||||
|
jack: jack.clone(),
|
||||||
|
}
|
||||||
});
|
});
|
||||||
render!(<Tui>|self: ArrangerTui|{
|
render!(<Tui>|self: ArrangerTui|{
|
||||||
let arranger = ||lay!(|add|{
|
let arranger = ||lay!(|add|{
|
||||||
|
|
@ -67,11 +64,11 @@ render!(<Tui>|self: ArrangerTui|{
|
||||||
])),
|
])),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let with_pool = |x|Split::right(false, self.splits[1], PhraseListView(&self.phrases), x);
|
let with_pool = |x|Split::left(false, self.splits[1], PhraseListView(&self.phrases), x);
|
||||||
let play = Fixed::wh(5, 2, PlayPause(self.clock.is_rolling()));
|
let play = Fixed::wh(5, 2, PlayPause(self.clock.is_rolling()));
|
||||||
let transport = TransportView::from((self, None, true));
|
let transport = TransportView::from((self, None, true));
|
||||||
let with_transport = |x|col!([row!(![&play, &transport]), &x]);
|
let with_transport = |x|col!([row!(![&play, &transport]), &x]);
|
||||||
with_transport(col!([Fixed::h(self.splits[0], arranger()), with_pool(&self.editor),]))
|
with_transport(with_pool(col!([Fixed::h(self.splits[0], arranger()), &self.editor])))
|
||||||
});
|
});
|
||||||
audio!(|self: ArrangerTui, client, scope|{
|
audio!(|self: ArrangerTui, client, scope|{
|
||||||
// Start profiling cycle
|
// Start profiling cycle
|
||||||
|
|
|
||||||
|
|
@ -162,8 +162,7 @@ render!(<Tui>|self: ArrangerVHeader<'a>|row!(
|
||||||
// name and width of track
|
// name and width of track
|
||||||
let name = track.name().read().unwrap();
|
let name = track.name().read().unwrap();
|
||||||
let max_w = w.saturating_sub(1).min(name.len()).max(2);
|
let max_w = w.saturating_sub(1).min(name.len()).max(2);
|
||||||
let name = format!("▎{}", &name[0..max_w]);
|
let name = Tui::bold(true, Tui::fg(track.color.lightest.rgb, format!("▎{}", &name[0..max_w])));
|
||||||
let name = Tui::bold(true, Tui::fg(track.color.lightest.rgb, name));
|
|
||||||
// beats elapsed
|
// beats elapsed
|
||||||
let elapsed = if let Some((_, Some(phrase))) = track.player.play_phrase().as_ref() {
|
let elapsed = if let Some((_, Some(phrase))) = track.player.play_phrase().as_ref() {
|
||||||
let length = phrase.read().unwrap().length;
|
let length = phrase.read().unwrap().length;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue