refactor: into one big pile it goes

This commit is contained in:
stop screaming 2026-02-21 01:50:53 +02:00
parent 604a42a4bc
commit ec404b0305
24 changed files with 6559 additions and 6675 deletions

View file

@ -2,12 +2,64 @@ 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<RwLock<JackState<'j>>>
);
/// 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<str>),
Freewheel(bool),
SampleRate(Frames),
ClientRegistration(Arc<str>, bool),
PortRegistration(PortId, bool),
PortRename(PortId, Arc<str>, Arc<str>),
PortsConnected(PortId, PortId, bool),
GraphReorder,
XRun,
}
/// Generic notification handler that emits [JackEvent]
///
/// ```
/// let notify = tek::JackNotify(|_|{});
/// ```
pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T);
/// Total state
///
/// ```
/// use tek::tek_device::TracksView;
/// let app: tek::App = Default::default();
/// let _ = app.scene_add(None, None)?;
/// 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();
@ -53,7 +105,7 @@ use builder_pattern::Builder;
/// Configuration: mode, view, and bind definitions.
///
/// ```
/// let conf: tek::Config = Default::default();
/// let conf = tek::Config::default();
/// ```
#[derive(Default, Debug)] pub struct Config {
/// XDG base directories of running user.
@ -69,7 +121,7 @@ use builder_pattern::Builder;
/// Group of view and keys definitions.
///
/// ```
/// let mode: tek::Mode<std::sync::Arc<str>> = Default::default();
/// let mode = tek::Mode::<std::sync::Arc<str>>::default();
/// ```
#[derive(Default, Debug)] pub struct Mode<D: Language + Ord> {
pub path: PathBuf,
@ -83,7 +135,7 @@ use builder_pattern::Builder;
/// An input binding.
///
/// ```
/// let bind: tek::Bind<(), ()> = Default::default();
/// let bind = tek::Bind::<(), ()>::default();
/// ```
#[derive(Debug)] pub struct Bind<E, C>(
/// Map of each event (e.g. key combination) to
@ -142,9 +194,9 @@ use builder_pattern::Builder;
/// use clap::CommandFactory;
/// tek::Cli::command().debug_assert();
/// ```
#[derive(Debug, Parser, Default)]
#[derive(Parser)]
#[command(name = "tek", version, about = Some(HEADER), long_about = Some(HEADER))]
pub struct Cli {
#[derive(Debug, Default)] pub struct Cli {
/// Pre-defined configuration modes.
///
/// TODO: Replace these with scripted configurations.
@ -213,8 +265,7 @@ pub struct Cli {
/// ```
/// let axis = tek::ControlAxis::X;
/// ```
#[derive(Debug, Copy, Clone)]
pub enum ControlAxis {
#[derive(Debug, Copy, Clone)] pub enum ControlAxis {
X, Y, Z, I
}
@ -232,3 +283,794 @@ pub enum ControlAxis {
Browse(BrowseTarget, Arc<Browse>),
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: BeatsPerMinute,
/// MIDI ticks per beat
pub ppq: PulsesPerQuaver,
}
/// 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<AtomicUsize>,
/// Note coordinate of cursor
pub note_pos: Arc<AtomicUsize>,
/// Length of note that will be inserted, in pulses
pub note_len: Arc<AtomicUsize>,
}
///
/// ```
///
/// ```
#[derive(Debug, Clone, Default)] pub struct MidiSelection {
pub time_len: Arc<AtomicUsize>,
/// Length of visible time axis
pub time_axis: Arc<AtomicUsize>,
/// Earliest time displayed
pub time_start: Arc<AtomicUsize>,
/// Time step
pub time_zoom: Arc<AtomicUsize>,
/// Auto rezoom to fit in time axis
pub time_lock: Arc<AtomicBool>,
/// Length of visible note axis
pub note_axis: Arc<AtomicUsize>,
// Lowest note displayed
pub note_lo: Arc<AtomicUsize>,
}
/// A point in time in all time scales (microsecond, sample, MIDI pulse)
///
/// ```
///
/// ```
#[derive(Debug, Default, Clone)] pub struct Moment {
pub timebase: Arc<Timebase>,
/// 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 PulsesPerQuaver (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 BeatsPerMinute (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<Option<Transport>>,
/// Global temporal resolution (shared by [Moment] fields)
pub timebase: Arc<Timebase>,
/// Current global sample and usec (monotonic from JACK clock)
pub global: Arc<Moment>,
/// Global sample and usec at which playback started
pub started: Arc<RwLock<Option<Moment>>>,
/// Playback offset (when playing not from start)
pub offset: Arc<Moment>,
/// Current playhead position
pub playhead: Arc<Moment>,
/// Note quantization factor
pub quant: Arc<Quantize>,
/// Launch quantization factor
pub sync: Arc<LaunchSync>,
/// Size of buffer in samples
pub chunk: Arc<AtomicUsize>,
// Cache of formatted strings
pub view_cache: Arc<RwLock<ClockView>>,
/// For syncing the clock to an external source
#[cfg(feature = "port")] pub midi_in: Arc<RwLock<Option<MidiInput>>>,
/// For syncing other devices to this clock
#[cfg(feature = "port")] pub midi_out: Arc<RwLock<Option<MidiOutput>>>,
/// For emitting a metronome
#[cfg(feature = "port")] pub click_out: Arc<RwLock<Option<AudioOutput>>>,
}
/// Contains memoized renders of clock values.
///
/// Performance optimization.
#[derive(Debug)] pub struct ClockView {
pub sr: Memo<Option<(bool, f64)>, String>,
pub buf: Memo<Option<f64>, String>,
pub lat: Memo<Option<f64>, String>,
pub bpm: Memo<Option<f64>, String>,
pub beat: Memo<Option<f64>, String>,
pub time: Memo<Option<f64>, String>,
}
/// Arranger.
///
/// ```
/// let arranger = tek::Arrangement::default();
/// ```
#[derive(Default, Debug)] pub struct Arrangement {
/// Project name.
pub name: Arc<str>,
/// 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<RwLock<Buffer>>,
/// Display size
pub size: Measure<TuiOut>,
/// Display size of clips area
pub size_inner: Measure<TuiOut>,
/// Source of time
#[cfg(feature = "clock")] pub clock: Clock,
/// Allows one MIDI clip to be edited
#[cfg(feature = "editor")] pub editor: Option<MidiEditor>,
/// List of global midi inputs
#[cfg(feature = "port")] pub midi_ins: Vec<MidiInput>,
/// List of global midi outputs
#[cfg(feature = "port")] pub midi_outs: Vec<MidiOutput>,
/// List of global audio inputs
#[cfg(feature = "port")] pub audio_ins: Vec<AudioInput>,
/// List of global audio outputs
#[cfg(feature = "port")] pub audio_outs: Vec<AudioOutput>,
/// 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<Track>,
/// Scroll offset of tracks
#[cfg(feature = "track")] pub track_scroll: usize,
/// List of scenes
#[cfg(feature = "scene")] pub scenes: Vec<Scene>,
/// 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<TuiOut>,
}
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<RwLock<Option<Sample>>>),
ExportSample(Arc<RwLock<Option<Sample>>>),
ImportClip(Arc<RwLock<Option<MidiClip>>>),
ExportClip(Arc<RwLock<Option<MidiClip>>>),
}
/// 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<str>,
/// 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<TuiOut>,
/// 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<Arc<RwLock<MidiClip>>>,
/// Buffer where the whole clip is rerendered on change
pub buffer: Arc<RwLock<BigBuffer>>,
/// Size of actual notes area
pub size: Measure<TuiOut>,
/// 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<str>,
pub path: Option<Arc<str>>,
pub selected: usize,
pub mapping: bool,
pub midi_ins: Vec<Port<MidiIn>>,
pub midi_outs: Vec<Port<MidiOut>>,
pub audio_ins: Vec<Port<AudioIn>>,
pub audio_outs: Vec<Port<AudioOut>>,
pub lv2_world: livi::World,
pub lv2_instance: livi::Instance,
pub lv2_plugin: livi::Plugin,
pub lv2_features: Arc<livi::Features>,
pub lv2_port_list: Vec<livi::Port>,
pub lv2_input_buffer: Vec<livi::event::LV2AtomSequence>,
pub lv2_ui_thread: Option<JoinHandle<()>>,
}
/// A LV2 plugin's X11 UI.
#[cfg(feature = "lv2_gui")] pub struct LV2PluginUI {
pub window: Option<Window>
}
#[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<PoolMode>,
/// Embedded file browse
#[cfg(feature = "browse")] pub browse: Option<Browse>,
/// Collection of MIDI clips.
#[cfg(feature = "clip")] pub clips: Arc<RwLock<Vec<Arc<RwLock<MidiClip>>>>>,
/// Collection of sound samples.
#[cfg(feature = "sampler")] pub samples: Arc<RwLock<Vec<Arc<RwLock<Sample>>>>>,
}
/// 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<ClipLengthFocus>,
}
/// 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<str>,
/// Port handle.
pub port: Port<AudioIn>,
/// List of ports to connect to.
pub connections: Vec<Connect>,
}
/// 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<str>,
/// Port handle.
pub port: Port<AudioOut>,
/// List of ports to connect to.
pub connections: Vec<Connect>,
}
/// 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<str>,
/// Port handle.
pub port: Port<MidiIn>,
/// List of currently held notes.
pub held: Arc<RwLock<[bool;128]>>,
/// List of ports to connect to.
pub connections: Vec<Connect>,
}
/// 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<str>,
/// Port handle.
pub port: Port<MidiOut>,
/// List of ports to connect to.
pub connections: Vec<Connect>,
/// List of currently held notes.
pub held: Arc<RwLock<[bool;128]>>,
/// Buffer
pub note_buffer: Vec<u8>,
/// Buffer
pub output_buffer: Vec<Vec<Vec<u8>>>,
}
/// Port connection manager.
///
/// ```
/// let connect = tek::Connect::default();
/// ```
#[derive(Clone, Debug, Default)] pub struct Connect {
pub name: Option<ConnectName>,
pub scope: Option<ConnectScope>,
pub status: Arc<RwLock<Vec<(Port<Unowned>, Arc<str>, ConnectStatus)>>>,
pub info: Arc<str>,
}
/// Plays [Voice]s from [Sample]s.
///
/// ```
/// let sampler = tek::Sampler::default();
/// ```
#[derive(Debug, Default)] pub struct Sampler {
/// Name of sampler.
pub name: Arc<str>,
/// Device color.
pub color: ItemTheme,
/// Audio input ports. Samples get recorded here.
#[cfg(feature = "port")] pub audio_ins: Vec<AudioInput>,
/// Audio input meters.
#[cfg(feature = "meter")] pub input_meters: Vec<f32>,
/// Sample currently being recorded.
pub recording: Option<(usize, Option<Arc<RwLock<Sample>>>)>,
/// Recording buffer.
pub buffer: Vec<Vec<f32>>,
/// Samples mapped to MIDI notes.
pub samples: Samples<128>,
/// Samples that are not mapped to MIDI notes.
pub unmapped: Vec<Arc<RwLock<Sample>>>,
/// Sample currently being edited.
pub editing: Option<Arc<RwLock<Sample>>>,
/// MIDI input port. Triggers sample playback.
#[cfg(feature = "port")] pub midi_in: Option<MidiInput>,
/// Collection of currently playing instances of samples.
pub voices: Arc<RwLock<Vec<Voice>>>,
/// Audio output ports. Voices get played here.
#[cfg(feature = "port")] pub audio_outs: Vec<AudioOutput>,
/// Audio output meters.
#[cfg(feature = "meter")] pub output_meters: Vec<f32>,
/// 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<SamplerMode>,
/// Size of rendered sampler.
pub size: Measure<TuiOut>,
/// 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.
///
/// TODO: Map more than one sample per slot.
///
/// History: Separated to cleanly implement [Default].
///
/// ```
/// let samples = tek::Samples([None, None, None, None]);
/// ```
#[derive(Debug)] pub struct Samples<const N: usize>(
pub [Option<Arc<RwLock<Sample>>>;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<str>,
pub start: usize,
pub end: usize,
pub channels: Vec<Vec<f32>>,
pub rate: Option<usize>,
pub gain: f32,
pub color: ItemTheme,
}
/// A currently playing instance of a sample.
#[derive(Default, Debug, Clone)] pub struct Voice {
pub sample: Arc<RwLock<Sample>>,
pub after: usize,
pub position: usize,
pub velocity: f32,
}
pub struct AddSampleModal {
pub exited: bool,
pub dir: PathBuf,
pub subdirs: Vec<OsString>,
pub files: Vec<OsString>,
pub cursor: usize,
pub offset: usize,
pub sample: Arc<RwLock<Sample>>,
pub voices: Arc<RwLock<Vec<Voice>>>,
pub _search: Option<String>,
}
/// 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<str>,
/// Identifying color of scene
pub color: ItemTheme,
/// Clips in scene, one per track
pub clips: Vec<Option<Arc<RwLock<MidiClip>>>>,
}
/// 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<Arc<RwLock<MidiClip>>>)>,
/// Start time and next clip
#[cfg(feature = "clip")] pub next_clip: Option<(Moment, Option<Arc<RwLock<MidiClip>>>)>,
/// Record from MIDI ports to current sequence.
#[cfg(feature = "port")] pub midi_ins: Vec<MidiInput>,
/// Play from current sequence to MIDI ports
#[cfg(feature = "port")] pub midi_outs: Vec<MidiOutput>,
/// 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<RwLock<[bool; 128]>>,
/// Notes currently held at output
pub notes_out: Arc<RwLock<[bool; 128]>>,
/// MIDI output buffer
pub note_buf: Vec<u8>,
/// MIDI output buffer
pub midi_buf: Vec<Vec<Vec<u8>>>,
}
/// 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<str>,
/// 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<Device>,
}
// Commands supported by [Browse]
//#[derive(Debug, Clone, PartialEq)]
//pub enum BrowseCommand {
//Begin,
//Cancel,
//Confirm,
//Select(usize),
//Chdir(PathBuf),
//Filter(Arc<str>),
//}
/// Modes for clip pool
#[derive(Debug, Clone)] pub enum PoolMode {
/// Renaming a pattern
Rename(usize, Arc<str>),
/// 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<str>),
/** Match regular expression */
RegExp(Arc<str>),
}
#[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),
}