use crate::*; use clap::{self, Parser, Subcommand}; use builder_pattern::Builder; /// Wraps [JackState], and through it [jack::Client] when connected. /// /// ``` /// let jack = tek::Jack::default(); /// ``` #[derive(Clone, Debug, Default)] pub struct Jack<'j> ( pub(crate) Arc>> ); /// This is a connection which may be [Inactive], [Activating], or [Active]. /// In the [Active] and [Inactive] states, [JackState::client] returns a /// [jack::Client], which you can use to talk to the JACK API. /// /// ``` /// let state = tek::JackState::default(); /// ``` #[derive(Debug, Default)] pub enum JackState<'j> { /// Unused #[default] Inert, /// Before activation. Inactive(Client), /// During activation. Activating, /// After activation. Must not be dropped for JACK thread to persist. Active(DynamicAsyncClient<'j>), } /// Event enum for JACK events. /// /// ``` /// let event = tek::JackEvent::XRun; /// ``` #[derive(Debug, Clone, PartialEq)] pub enum JackEvent { ThreadInit, Shutdown(ClientStatus, Arc), Freewheel(bool), SampleRate(Frames), ClientRegistration(Arc, bool), PortRegistration(PortId, bool), PortRename(PortId, Arc, Arc), PortsConnected(PortId, PortId, bool), GraphReorder, XRun, } /// Generic notification handler that emits [JackEvent] /// /// ``` /// let notify = tek::JackNotify(|_|{}); /// ``` pub struct JackNotify(pub T); /// Total state /// /// ``` /// use tek::{TracksView, ScenesView, AddScene}; /// let mut app = tek::App::default(); /// let _ = app.scene_add(None, None).unwrap(); /// let _ = app.update_clock(); /// app.project.editor = Some(Default::default()); /// //let _: Vec<_> = app.project.inputs_with_sizes().collect(); /// //let _: Vec<_> = app.project.outputs_with_sizes().collect(); /// let _: Vec<_> = app.project.tracks_with_sizes().collect(); /// //let _: Vec<_> = app.project.scenes_with_sizes(true, 10, 10).collect(); /// //let _: Vec<_> = app.scenes_with_colors(true, 10).collect(); /// //let _: Vec<_> = app.scenes_with_track_colors(true, 10, 10).collect(); /// let _ = app.project.w(); /// //let _ = app.project.w_sidebar(); /// //let _ = app.project.w_tracks_area(); /// let _ = app.project.h(); /// //let _ = app.project.h_tracks_area(); /// //let _ = app.project.h_inputs(); /// //let _ = app.project.h_outputs(); /// let _ = app.project.h_scenes(); /// ``` #[derive(Default, Debug)] pub struct App { /// Base color. pub color: ItemTheme, /// Must not be dropped for the duration of the process pub jack: Jack<'static>, /// Display size pub size: Measure, /// Performance counter pub perf: PerfModel, /// Available view modes and input bindings pub config: Config, /// Currently selected mode pub mode: Arc>>, /// Undo history pub history: Vec<(AppCommand, Option)>, /// Dialog overlay pub dialog: Dialog, /// Contains all recently created clips. pub pool: Pool, /// Contains the currently edited musical arrangement pub project: Arrangement, /// Error, if any pub error: Arc>>> } /// Configuration: mode, view, and bind definitions. /// /// ``` /// let config = tek::Config::default(); /// ``` /// /// ``` /// // Some dizzle. /// // What indentation to use here lol? /// let source = stringify!((mode :menu (name Menu) /// (info Mode selector.) (keys :axis/y :confirm) /// (view (bg (g 0) (bsp/s :ports/out /// (bsp/n :ports/in /// (bg (g 30) (bsp/s (fixed/y 7 :logo) /// (fill :dialog/menu))))))))); /// // Add this definition to the config and try to load it. /// // A "mode" is basically a state machine /// // with associated input and output definitions. /// tek::Config::default().add(&source).unwrap().get_mode(":menu").unwrap(); /// ``` #[derive(Default, Debug)] pub struct Config { /// XDG base directories of running user. pub dirs: BaseDirectories, /// Active collection of interaction modes. pub modes: Modes, /// Active collection of event bindings. pub binds: Binds, /// Active collection of view definitions. pub views: Views, } /// Group of view and keys definitions. /// /// ``` /// let mode = tek::Mode::>::default(); /// ``` #[derive(Default, Debug)] pub struct Mode { pub path: PathBuf, pub name: Vec, pub info: Vec, pub view: Vec, pub keys: Vec, pub modes: Modes, } /// An input binding. /// /// ``` /// let bind = tek::Bind::<(), ()>::default(); /// ``` #[derive(Debug)] pub struct Bind( /// Map of each event (e.g. key combination) to /// all command expressions bound to it by /// all loaded input layers. pub BTreeMap>> ); /// An input binding. /// /// ``` /// let binding: tek::Binding<()> = Default::default(); /// ``` #[derive(Debug, Clone)] pub struct Binding { pub commands: Arc<[C]>, pub condition: Option, pub description: Option>, pub source: Option>, } /// Condition that must evaluate to true in order to enable an input layer. /// /// ``` /// let condition = tek::Condition(std::sync::Arc::new(Box::new(||{true}))); /// ``` #[derive(Clone)] pub struct Condition( pub Arcbool + Send + Sync>> ); /// List of menu items. /// /// ``` /// let items: tek::MenuItems = Default::default(); /// ``` #[derive(Debug, Clone, Default, PartialEq)] pub struct MenuItems( pub Arc<[MenuItem]> ); /// An item of a menu. /// /// ``` /// let item: tek::MenuItem = Default::default(); /// ``` #[derive(Clone)] pub struct MenuItem( /// Label pub Arc, /// Callback pub ArcUsually<()> + Send + Sync>> ); /// The command-line interface descriptor. /// /// ``` /// let cli: tek::Cli = Default::default(); /// /// use clap::CommandFactory; /// tek::Cli::command().debug_assert(); /// ``` #[derive(Parser)] #[command(name = "tek", version, about = Some(HEADER), long_about = Some(HEADER))] #[derive(Debug, Default)] pub struct Cli { /// Pre-defined configuration modes. /// /// TODO: Replace these with scripted configurations. #[command(subcommand)] pub action: Action, } /// Application modes that can be passed to the mommand line interface. /// /// ``` /// let action: tek::Action = Default::default(); /// ``` #[derive(Debug, Clone, Subcommand, Default)] pub enum Action { /// Continue where you left off #[default] Resume, /// Run headlessly in current session. Headless, /// Show status of current session. Status, /// List known sessions. List, /// Continue work in a copy of the current session. Fork, /// Create a new empty session. New { /// Name of JACK client #[arg(short='n', long)] name: Option, /// Whether to attempt to become transport master #[arg(short='Y', long, default_value_t = false)] sync_lead: bool, /// Whether to sync to external transport master #[arg(short='y', long, default_value_t = true)] sync_follow: bool, /// Initial tempo in beats per minute #[arg(short='b', long, default_value = None)] bpm: Option, /// Whether to include a transport toolbar (default: true) #[arg(short='c', long, default_value_t = true)] show_clock: bool, /// MIDI outs to connect to (multiple instances accepted) #[arg(short='I', long)] midi_from: Vec, /// MIDI outs to connect to (multiple instances accepted) #[arg(short='i', long)] midi_from_re: Vec, /// MIDI ins to connect to (multiple instances accepted) #[arg(short='O', long)] midi_to: Vec, /// MIDI ins to connect to (multiple instances accepted) #[arg(short='o', long)] midi_to_re: Vec, /// Audio outs to connect to left input #[arg(short='l', long)] left_from: Vec, /// Audio outs to connect to right input #[arg(short='r', long)] right_from: Vec, /// Audio ins to connect from left output #[arg(short='L', long)] left_to: Vec, /// Audio ins to connect from right output #[arg(short='R', long)] right_to: Vec, /// Tracks to create #[arg(short='t', long)] tracks: Option, /// Scenes to create #[arg(short='s', long)] scenes: Option, }, /// Import media as new session. Import, /// Show configuration. Config, /// Show version. Version, } /// A control axis. /// /// ``` /// let axis = tek::ControlAxis::X; /// ``` #[derive(Debug, Copy, Clone)] pub enum ControlAxis { X, Y, Z, I } /// Various possible dialog modes. /// /// ``` /// let dialog: tek::Dialog = Default::default(); /// ``` #[derive(Debug, Clone, Default, PartialEq)] pub enum Dialog { #[default] None, Help(usize), Menu(usize, MenuItems), Device(usize), Message(Arc), Browse(BrowseTarget, Arc), Options, } /// Temporal resolutions: sample rate, tempo, MIDI pulses per quaver (beat) /// /// ``` /// /// ``` #[derive(Debug, Clone)] pub struct Timebase { /// Audio samples per second pub sr: SampleRate, /// MIDI beats per minute pub bpm: Bpm, /// MIDI ticks per beat pub ppq: Ppq, } /// Iterator that emits subsequent ticks within a range. /// /// ``` /// let iter = tek::TicksIterator::default(); /// ``` #[derive(Debug, Default)] pub struct TicksIterator { pub spp: f64, pub sample: usize, pub start: usize, pub end: usize, } /// /// ``` /// use tek::{TimeRange, NoteRange}; /// let model = tek::MidiSelection::from((1, false)); /// /// let _ = model.get_time_len(); /// let _ = model.get_time_zoom(); /// let _ = model.get_time_lock(); /// let _ = model.get_time_start(); /// let _ = model.get_time_axis(); /// let _ = model.get_time_end(); /// /// let _ = model.get_note_lo(); /// let _ = model.get_note_axis(); /// let _ = model.get_note_hi(); /// ``` #[derive(Debug, Clone)] pub struct MidiCursor { /// Time coordinate of cursor pub time_pos: Arc, /// Note coordinate of cursor pub note_pos: Arc, /// Length of note that will be inserted, in pulses pub note_len: Arc, } /// /// ``` /// /// ``` #[derive(Debug, Clone, Default)] pub struct MidiSelection { pub time_len: Arc, /// Length of visible time axis pub time_axis: Arc, /// Earliest time displayed pub time_start: Arc, /// Time step pub time_zoom: Arc, /// Auto rezoom to fit in time axis pub time_lock: Arc, /// Length of visible note axis pub note_axis: Arc, // Lowest note displayed pub note_lo: Arc, } /// A point in time in all time scales (microsecond, sample, MIDI pulse) /// /// ``` /// /// ``` #[derive(Debug, Default, Clone)] pub struct Moment { pub timebase: Arc, /// Current time in microseconds pub usec: Microsecond, /// Current time in audio samples pub sample: SampleCount, /// Current time in MIDI pulses pub pulse: Pulse, } /// /// ``` /// /// ``` #[derive(Debug, Clone, Default)] pub enum Moment2 { #[default] None, Zero, Usec(Microsecond), Sample(SampleCount), Pulse(Pulse), } /// MIDI resolution in PPQ (pulses per quarter note) /// /// ``` /// /// ``` #[derive(Debug, Default)] pub struct Ppq (pub(crate) AtomicF64); /// Timestamp in MIDI pulses /// /// ``` /// /// ``` #[derive(Debug, Default)] pub struct Pulse (pub(crate) AtomicF64); /// Tempo in beats per minute /// /// ``` /// /// ``` #[derive(Debug, Default)] pub struct Bpm (pub(crate) AtomicF64); /// Quantization setting for launching clips /// /// ``` /// /// ``` #[derive(Debug, Default)] pub struct LaunchSync (pub(crate) AtomicF64); /// Quantization setting for notes /// /// ``` /// /// ``` #[derive(Debug, Default)] pub struct Quantize (pub(crate) AtomicF64); /// Timestamp in audio samples /// /// ``` /// /// ``` #[derive(Debug, Default)] pub struct SampleCount (pub(crate) AtomicF64); /// Audio sample rate in Hz (samples per second) /// /// ``` /// /// ``` #[derive(Debug, Default)] pub struct SampleRate (pub(crate) AtomicF64); /// Timestamp in microseconds /// /// ``` /// /// ``` #[derive(Debug, Default)] pub struct Microsecond (pub(crate) AtomicF64); /// The source of time. /// /// ``` /// let clock = tek::Clock::default(); /// ``` #[derive(Clone, Default)] pub struct Clock { /// JACK transport handle. pub transport: Arc>, /// Global temporal resolution (shared by [Moment] fields) pub timebase: Arc, /// Current global sample and usec (monotonic from JACK clock) pub global: Arc, /// Global sample and usec at which playback started pub started: Arc>>, /// Playback offset (when playing not from start) pub offset: Arc, /// Current playhead position pub playhead: Arc, /// Note quantization factor pub quant: Arc, /// Launch quantization factor pub sync: Arc, /// Size of buffer in samples pub chunk: Arc, // Cache of formatted strings pub view_cache: Arc>, /// For syncing the clock to an external source #[cfg(feature = "port")] pub midi_in: Arc>>, /// For syncing other devices to this clock #[cfg(feature = "port")] pub midi_out: Arc>>, /// For emitting a metronome #[cfg(feature = "port")] pub click_out: Arc>>, } /// Contains memoized renders of clock values. /// /// Performance optimization. #[derive(Debug)] pub struct ClockView { pub sr: Memo, String>, pub buf: Memo, String>, pub lat: Memo, String>, pub bpm: Memo, String>, pub beat: Memo, String>, pub time: Memo, String>, } /// Arranger. /// /// ``` /// let arranger = tek::Arrangement::default(); /// ``` #[derive(Default, Debug)] pub struct Arrangement { /// Project name. pub name: Arc, /// Base color. pub color: ItemTheme, /// JACK client handle. pub jack: Jack<'static>, /// FIXME a render of the project arrangement, redrawn on update. /// TODO rename to "render_cache" or smth pub arranger: Arc>, /// Display size pub size: Measure, /// Display size of clips area pub size_inner: Measure, /// Source of time #[cfg(feature = "clock")] pub clock: Clock, /// Allows one MIDI clip to be edited #[cfg(feature = "editor")] pub editor: Option, /// List of global midi inputs #[cfg(feature = "port")] pub midi_ins: Vec, /// List of global midi outputs #[cfg(feature = "port")] pub midi_outs: Vec, /// List of global audio inputs #[cfg(feature = "port")] pub audio_ins: Vec, /// List of global audio outputs #[cfg(feature = "port")] pub audio_outs: Vec, /// Selected UI element #[cfg(feature = "select")] pub selection: Selection, /// Last track number (to avoid duplicate port names) #[cfg(feature = "track")] pub track_last: usize, /// List of tracks #[cfg(feature = "track")] pub tracks: Vec, /// Scroll offset of tracks #[cfg(feature = "track")] pub track_scroll: usize, /// List of scenes #[cfg(feature = "scene")] pub scenes: Vec, /// Scroll offset of scenes #[cfg(feature = "scene")] pub scene_scroll: usize, } /// Browses for files to load/save. /// /// ``` /// let browse = tek::Browse::default(); /// ``` #[derive(Debug, Clone, Default, PartialEq)] pub struct Browse { pub cwd: PathBuf, pub dirs: Vec<(OsString, String)>, pub files: Vec<(OsString, String)>, pub filter: String, pub index: usize, pub scroll: usize, pub size: Measure, } pub(crate) struct EntriesIterator<'a> { pub browser: &'a Browse, pub offset: usize, pub length: usize, pub index: usize, } #[derive(Clone, Debug)] pub enum BrowseTarget { SaveProject, LoadProject, ImportSample(Arc>>), ExportSample(Arc>>), ImportClip(Arc>>), ExportClip(Arc>>), } /// A MIDI sequence. /// /// ``` /// let clip = tek::MidiClip::default(); /// ``` #[derive(Debug, Clone, Default)] pub struct MidiClip { pub uuid: uuid::Uuid, /// Name of clip pub name: Arc, /// Temporal resolution in pulses per quarter note pub ppq: usize, /// Length of clip in pulses pub length: usize, /// Notes in clip pub notes: MidiData, /// Whether to loop the clip or play it once pub looped: bool, /// Start of loop pub loop_start: usize, /// Length of loop pub loop_length: usize, /// All notes are displayed with minimum length pub percussive: bool, /// Identifying color of clip pub color: ItemTheme, } /// A device that can be plugged into the chain. /// /// ``` /// let device = tek::Device::default(); /// ``` #[derive(Debug, Default)] pub enum Device { #[default] Bypass, Mute, #[cfg(feature = "sampler")] Sampler(Sampler), #[cfg(feature = "lv2")] // TODO Lv2(Lv2), #[cfg(feature = "vst2")] // TODO Vst2, #[cfg(feature = "vst3")] // TODO Vst3, #[cfg(feature = "clap")] // TODO Clap, #[cfg(feature = "sf2")] // TODO Sf2, } /// Some sort of wrapper? pub struct DeviceAudio<'a>(pub &'a mut Device); /// Contains state for viewing and editing a clip. /// /// ``` /// use std::sync::{Arc, RwLock}; /// let clip = tek::MidiClip::stop_all(); /// let mut editor = tek::MidiEditor { /// mode: tek::PianoHorizontal::new(Some(&Arc::new(RwLock::new(clip)))), /// size: Default::default(), /// //keys: Default::default(), /// }; /// let _ = editor.put_note(true); /// let _ = editor.put_note(false); /// let _ = editor.clip_status(); /// let _ = editor.edit_status(); /// ``` pub struct MidiEditor { /// Size of editor on screen pub size: Measure, /// View mode and state of editor pub mode: PianoHorizontal, } /// A clip, rendered as a horizontal piano roll. /// /// ``` /// let piano = tek::PianoHorizontal::default(); /// ``` #[derive(Clone, Default)] pub struct PianoHorizontal { pub clip: Option>>, /// Buffer where the whole clip is rerendered on change pub buffer: Arc>, /// Size of actual notes area pub size: Measure, /// The display window pub range: MidiSelection, /// The note cursor pub point: MidiCursor, /// The highlight color palette pub color: ItemTheme, /// Width of the keyboard pub keys_width: u16, } /// 12 piano keys, some highlighted. /// /// ``` /// let keys = tek::OctaveVertical::default(); /// ``` #[derive(Copy, Clone)] pub struct OctaveVertical { pub on: [bool; 12], pub colors: [Color; 3] } /// A LV2 plugin. #[derive(Debug)] #[cfg(feature = "lv2")] pub struct Lv2 { /// JACK client handle (needs to not be dropped for standalone mode to work). pub jack: Jack<'static>, pub name: Arc, pub path: Option>, pub selected: usize, pub mapping: bool, pub midi_ins: Vec>, pub midi_outs: Vec>, pub audio_ins: Vec>, pub audio_outs: Vec>, pub lv2_world: livi::World, pub lv2_instance: livi::Instance, pub lv2_plugin: livi::Plugin, pub lv2_features: Arc, pub lv2_port_list: Vec, pub lv2_input_buffer: Vec, pub lv2_ui_thread: Option>, } /// A LV2 plugin's X11 UI. #[cfg(feature = "lv2_gui")] pub struct LV2PluginUI { pub window: Option } #[derive(Debug, Default)] pub enum MeteringMode { #[default] Rms, Log10, } #[derive(Debug, Default, Clone)] pub struct Log10Meter(pub f32); #[derive(Debug, Default, Clone)] pub struct RmsMeter(pub f32); #[derive(Debug, Default)] pub enum MixingMode { #[default] Summing, Average, } /// A clip pool. /// /// ``` /// let pool = tek::Pool::default(); /// ``` #[derive(Debug)] pub struct Pool { pub visible: bool, /// Selected clip pub clip: AtomicUsize, /// Mode switch pub mode: Option, /// Embedded file browse #[cfg(feature = "browse")] pub browse: Option, /// Collection of MIDI clips. #[cfg(feature = "clip")] pub clips: Arc>>>>, /// Collection of sound samples. #[cfg(feature = "sampler")] pub samples: Arc>>>>, } /// Displays and edits clip length. #[derive(Clone, Debug, Default)] pub struct ClipLength { /// Pulses per beat (quaver) pub ppq: usize, /// Beats per bar pub bpb: usize, /// Length of clip in pulses pub pulses: usize, /// Selected subdivision pub focus: Option, } /// Some sort of wrapper again? pub struct PoolView<'a>(pub &'a Pool); /// Audio input port. #[derive(Debug)] pub struct AudioInput { /// Handle to JACK client, for receiving reconnect events. pub jack: Jack<'static>, /// Port name pub name: Arc, /// Port handle. pub port: Port, /// List of ports to connect to. pub connections: Vec, } /// Audio output port. #[derive(Debug)] pub struct AudioOutput { /// Handle to JACK client, for receiving reconnect events. pub jack: Jack<'static>, /// Port name pub name: Arc, /// Port handle. pub port: Port, /// List of ports to connect to. pub connections: Vec, } /// MIDI input port. #[derive(Debug)] pub struct MidiInput { /// Handle to JACK client, for receiving reconnect events. pub jack: Jack<'static>, /// Port name pub name: Arc, /// Port handle. pub port: Port, /// List of currently held notes. pub held: Arc>, /// List of ports to connect to. pub connections: Vec, } /// MIDI output port. #[derive(Debug)] pub struct MidiOutput { /// Handle to JACK client, for receiving reconnect events. pub jack: Jack<'static>, /// Port name pub name: Arc, /// Port handle. pub port: Port, /// List of ports to connect to. pub connections: Vec, /// List of currently held notes. pub held: Arc>, /// Buffer pub note_buffer: Vec, /// Buffer pub output_buffer: Vec>>, } /// Port connection manager. /// /// ``` /// let connect = tek::Connect::default(); /// ``` #[derive(Clone, Debug, Default)] pub struct Connect { pub name: Option, pub scope: Option, pub status: Arc, Arc, ConnectStatus)>>>, pub info: Arc, } /// Plays [Voice]s from [Sample]s. /// /// ``` /// let sampler = tek::Sampler::default(); /// ``` #[derive(Debug, Default)] pub struct Sampler { /// Name of sampler. pub name: Arc, /// Device color. pub color: ItemTheme, /// Audio input ports. Samples get recorded here. #[cfg(feature = "port")] pub audio_ins: Vec, /// Audio input meters. #[cfg(feature = "meter")] pub input_meters: Vec, /// Sample currently being recorded. pub recording: Option<(usize, Option>>)>, /// Recording buffer. pub buffer: Vec>, /// Samples mapped to MIDI notes. pub samples: SampleKit<128>, /// Samples that are not mapped to MIDI notes. pub unmapped: Vec>>, /// Sample currently being edited. pub editing: Option>>, /// MIDI input port. Triggers sample playback. #[cfg(feature = "port")] pub midi_in: Option, /// Collection of currently playing instances of samples. pub voices: Arc>>, /// Audio output ports. Voices get played here. #[cfg(feature = "port")] pub audio_outs: Vec, /// Audio output meters. #[cfg(feature = "meter")] pub output_meters: Vec, /// How to mix the voices. pub mixing_mode: MixingMode, /// How to meter the inputs and outputs. pub metering_mode: MeteringMode, /// Fixed gain applied to all output. pub output_gain: f32, /// Currently active modal, if any. pub mode: Option, /// Size of rendered sampler. pub size: Measure, /// Lowest note displayed. pub note_lo: AtomicUsize, /// Currently selected note. pub note_pt: AtomicUsize, /// Selected note as row/col. pub cursor: (AtomicUsize, AtomicUsize), } /// Collection of samples, one per slot, fixed number of slots. /// /// History: Separated to cleanly implement [Default]. /// /// ``` /// let samples = tek::SampleKit([None, None, None, None]); /// ``` #[derive(Debug)] pub struct SampleKit( pub [Option>>;N] ); /// A sound cut. /// /// ``` /// let sample = tek::Sample::default(); /// let sample = tek::Sample::new("test", 0, 0, vec![]); /// ``` #[derive(Default, Debug)] pub struct Sample { pub name: Arc, pub start: usize, pub end: usize, pub channels: Vec>, pub rate: Option, pub gain: f32, pub color: ItemTheme, } /// A currently playing instance of a sample. #[derive(Default, Debug, Clone)] pub struct Voice { pub sample: Arc>, pub after: usize, pub position: usize, pub velocity: f32, } pub struct AddSampleModal { pub exited: bool, pub dir: PathBuf, pub subdirs: Vec, pub files: Vec, pub cursor: usize, pub offset: usize, pub sample: Arc>, pub voices: Arc>>, pub _search: Option, } /// A scene consists of a set of clips to play together. /// /// ``` /// let scene: tek::Scene = Default::default(); /// let _ = scene.pulses(); /// let _ = scene.is_playing(&[]); /// ``` #[derive(Debug, Default)] pub struct Scene { /// Name of scene pub name: Arc, /// Identifying color of scene pub color: ItemTheme, /// Clips in scene, one per track pub clips: Vec>>>, } /// Represents the current user selection in the arranger #[derive(PartialEq, Clone, Copy, Debug, Default)] pub enum Selection { #[default] /// Nothing is selected Nothing, /// The whole mix is selected Mix, /// A MIDI input is selected. Input(usize), /// A MIDI output is selected. Output(usize), /// A scene is selected. #[cfg(feature = "scene")] Scene(usize), /// A track is selected. #[cfg(feature = "track")] Track(usize), /// A clip (track × scene) is selected. #[cfg(feature = "track")] TrackClip { track: usize, scene: usize }, /// A track's MIDI input connection is selected. #[cfg(feature = "track")] TrackInput { track: usize, port: usize }, /// A track's MIDI output connection is selected. #[cfg(feature = "track")] TrackOutput { track: usize, port: usize }, /// A track device slot is selected. #[cfg(feature = "track")] TrackDevice { track: usize, device: usize }, } /// Contains state for playing a clip /// /// ``` /// let clip = tek::MidiClip::default(); /// println!("Empty clip: {clip:?}"); /// /// let clip = tek::MidiClip::stop_all(); /// println!("Panic clip: {clip:?}"); /// /// let mut clip = tek::MidiClip::new("clip", true, 1, None, None); /// clip.set_length(96); /// clip.toggle_loop(); /// clip.record_event(12, midly::MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }); /// assert!(clip.contains_note_on(36.into(), 6, 18)); /// assert_eq!(&clip.notes, &clip.duplicate().notes); /// /// let clip = std::sync::Arc::new(clip); /// assert_eq!(clip.clone(), clip); /// /// let sequencer = tek::Sequencer::default(); /// println!("{sequencer:?}"); /// ``` pub struct Sequencer { /// State of clock and playhead #[cfg(feature = "clock")] pub clock: Clock, /// Start time and clip being played #[cfg(feature = "clip")] pub play_clip: Option<(Moment, Option>>)>, /// Start time and next clip #[cfg(feature = "clip")] pub next_clip: Option<(Moment, Option>>)>, /// Record from MIDI ports to current sequence. #[cfg(feature = "port")] pub midi_ins: Vec, /// Play from current sequence to MIDI ports #[cfg(feature = "port")] pub midi_outs: Vec, /// Play input through output. pub monitoring: bool, /// Write input to sequence. pub recording: bool, /// Overdub input to sequence. pub overdub: bool, /// Send all notes off pub reset: bool, // TODO?: after Some(nframes) /// Notes currently held at input pub notes_in: Arc>, /// Notes currently held at output pub notes_out: Arc>, /// MIDI output buffer pub note_buf: Vec, /// MIDI output buffer pub midi_buf: Vec>>, } /// A track consists of a sequencer and zero or more devices chained after it. /// /// ``` /// let track: tek::Track = Default::default(); /// ``` #[derive(Debug, Default)] pub struct Track { /// Name of track pub name: Arc, /// Identifying color of track pub color: ItemTheme, /// Preferred width of track column pub width: usize, /// MIDI sequencer state pub sequencer: Sequencer, /// Device chain pub devices: Vec, } // Commands supported by [Browse] //#[derive(Debug, Clone, PartialEq)] //pub enum BrowseCommand { //Begin, //Cancel, //Confirm, //Select(usize), //Chdir(PathBuf), //Filter(Arc), //} /// Modes for clip pool #[derive(Debug, Clone)] pub enum PoolMode { /// Renaming a pattern Rename(usize, Arc), /// Editing the length of a pattern Length(usize, usize, ClipLengthFocus), /// Load clip from disk Import(usize, Browse), /// Save clip to disk Export(usize, Browse), } /// Focused field of `ClipLength` #[derive(Copy, Clone, Debug)] pub enum ClipLengthFocus { /// Editing the number of bars Bar, /// Editing the number of beats Beat, /// Editing the number of ticks Tick, } #[derive(Clone, Debug, PartialEq)] pub enum ConnectName { /** Exact match */ Exact(Arc), /** Match regular expression */ RegExp(Arc), } #[derive(Clone, Copy, Debug, PartialEq)] pub enum ConnectScope { One, All } #[derive(Clone, Copy, Debug, PartialEq)] pub enum ConnectStatus { Missing, Disconnected, Connected, Mismatch, } #[derive(Debug)] pub enum SamplerMode { // Load sample from path Import(usize, Browse), }