mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-09 05:06:43 +01:00
wip: refactor pt.4, reduce number of files
This commit is contained in:
parent
adf5b3f0f8
commit
8c37c95cc6
60 changed files with 2185 additions and 2187 deletions
|
|
@ -1,292 +1,23 @@
|
|||
pub(crate) use tek_core::*;
|
||||
pub(crate) use tek_core::jack::{TransportState, Port, MidiIn, MidiOut};
|
||||
pub(crate) use tek_core::midly::{MidiMessage, num::u7};
|
||||
pub(crate) use tek_core::jack::*;
|
||||
pub(crate) use tek_core::midly::{*, live::LiveEvent, num::u7};
|
||||
pub(crate) use std::thread::JoinHandle;
|
||||
pub(crate) use std::fmt::{Debug, Formatter, Error};
|
||||
|
||||
submod! {
|
||||
clock
|
||||
mixer
|
||||
phrase
|
||||
plugin
|
||||
pool
|
||||
sampler
|
||||
sample
|
||||
scene
|
||||
sequencer
|
||||
track
|
||||
transport
|
||||
voice
|
||||
|
||||
api_cmd
|
||||
api_edn
|
||||
}
|
||||
|
||||
/// A timer with starting point, current time, and quantization
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Clock {
|
||||
/// Playback state
|
||||
pub playing: RwLock<Option<TransportState>>,
|
||||
/// Global sample and usec at which playback started
|
||||
pub started: RwLock<Option<(usize, usize)>>,
|
||||
/// Current moment in time
|
||||
pub current: Instant,
|
||||
/// Note quantization factor
|
||||
pub quant: Quantize,
|
||||
/// Launch quantization factor
|
||||
pub sync: LaunchSync,
|
||||
}
|
||||
|
||||
impl Clock {
|
||||
#[inline] pub fn timebase (&self) -> &Arc<Timebase> {
|
||||
&self.current.timebase
|
||||
}
|
||||
#[inline] pub fn pulse (&self) -> f64 {
|
||||
self.current.pulse.get()
|
||||
}
|
||||
#[inline] pub fn quant (&self) -> f64 {
|
||||
self.quant.get()
|
||||
}
|
||||
#[inline] pub fn sync (&self) -> f64 {
|
||||
self.sync.get()
|
||||
}
|
||||
#[inline] pub fn next_launch_pulse (&self) -> usize {
|
||||
let sync = self.sync.get() as usize;
|
||||
let pulse = self.current.pulse.get() as usize;
|
||||
if pulse % sync == 0 { pulse } else { (pulse / sync + 1) * sync }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TransportToolbar {
|
||||
pub jack: Arc<RwLock<JackClient>>,
|
||||
/// JACK transport handle.
|
||||
pub transport: jack::Transport,
|
||||
/// Current sample rate, tempo, and PPQ.
|
||||
pub clock: Arc<Clock>,
|
||||
/// Enable metronome?
|
||||
pub metronome: bool,
|
||||
}
|
||||
|
||||
pub struct Arrangement {
|
||||
/// JACK client handle (needs to not be dropped for standalone mode to work).
|
||||
pub jack: Arc<RwLock<JackClient>>,
|
||||
/// Global timebase
|
||||
pub clock: Arc<Clock>,
|
||||
/// Name of arranger
|
||||
pub name: Arc<RwLock<String>>,
|
||||
/// Collection of phrases.
|
||||
pub phrases: Arc<RwLock<Vec<Phrase>>>,
|
||||
/// Collection of tracks.
|
||||
pub tracks: Vec<Sequencer>,
|
||||
/// Collection of scenes.
|
||||
pub scenes: Vec<Scene>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Sequencer {
|
||||
/// Name of track
|
||||
pub name: Arc<RwLock<String>>,
|
||||
/// Preferred width of track column
|
||||
pub width: usize,
|
||||
/// Identifying color of track
|
||||
pub color: ItemColor,
|
||||
/// MIDI player/recorder
|
||||
pub player: PhrasePlayer,
|
||||
}
|
||||
|
||||
/// Phrase player.
|
||||
#[derive(Debug)]
|
||||
pub struct PhrasePlayer {
|
||||
/// Global timebase
|
||||
pub clock: Arc<Clock>,
|
||||
/// Start time and phrase being played
|
||||
pub phrase: Option<(Instant, Option<Arc<RwLock<Phrase>>>)>,
|
||||
/// Start time and next phrase
|
||||
pub next_phrase: Option<(Instant, Option<Arc<RwLock<Phrase>>>)>,
|
||||
/// 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)
|
||||
/// Record from MIDI ports to current sequence.
|
||||
pub midi_inputs: Vec<Port<MidiIn>>,
|
||||
/// Play from current sequence to MIDI ports
|
||||
pub midi_outputs: Vec<Port<MidiOut>>,
|
||||
/// MIDI output buffer
|
||||
pub midi_note: Vec<u8>,
|
||||
/// MIDI output buffer
|
||||
pub midi_chunk: Vec<Vec<Vec<u8>>>,
|
||||
/// Notes currently held at input
|
||||
pub notes_in: Arc<RwLock<[bool; 128]>>,
|
||||
/// Notes currently held at output
|
||||
pub notes_out: Arc<RwLock<[bool; 128]>>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct Scene {
|
||||
/// Name of scene
|
||||
pub name: Arc<RwLock<String>>,
|
||||
/// Clips in scene, one per track
|
||||
pub clips: Vec<Option<Arc<RwLock<Phrase>>>>,
|
||||
/// Identifying color of scene
|
||||
pub color: ItemColor,
|
||||
}
|
||||
|
||||
/// A MIDI sequence.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Phrase {
|
||||
pub uuid: uuid::Uuid,
|
||||
/// Name of phrase
|
||||
pub name: String,
|
||||
/// Temporal resolution in pulses per quarter note
|
||||
pub ppq: usize,
|
||||
/// Length of phrase in pulses
|
||||
pub length: usize,
|
||||
/// Notes in phrase
|
||||
pub notes: PhraseData,
|
||||
/// Whether to loop the phrase or play it once
|
||||
pub loop_on: 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 phrase
|
||||
pub color: ItemColorTriplet,
|
||||
}
|
||||
|
||||
/// MIDI message structural
|
||||
pub type PhraseData = Vec<Vec<MidiMessage>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Mixer {
|
||||
/// JACK client handle (needs to not be dropped for standalone mode to work).
|
||||
pub jack: Arc<RwLock<JackClient>>,
|
||||
pub name: String,
|
||||
pub tracks: Vec<MixerTrack>,
|
||||
pub selected_track: usize,
|
||||
pub selected_column: usize,
|
||||
}
|
||||
|
||||
/// A mixer track.
|
||||
#[derive(Debug)]
|
||||
pub struct MixerTrack {
|
||||
pub name: String,
|
||||
/// Inputs and outputs of 1st and last device
|
||||
pub ports: JackPorts,
|
||||
/// Device chain
|
||||
pub devices: Vec<JackClient>,
|
||||
}
|
||||
|
||||
/// The sampler plugin plays sounds.
|
||||
#[derive(Debug)]
|
||||
pub struct Sampler {
|
||||
pub jack: Arc<RwLock<JackClient>>,
|
||||
pub name: String,
|
||||
pub mapped: BTreeMap<u7, Arc<RwLock<Sample>>>,
|
||||
pub unmapped: Vec<Arc<RwLock<Sample>>>,
|
||||
pub voices: Arc<RwLock<Vec<Voice>>>,
|
||||
pub ports: JackPorts,
|
||||
pub buffer: Vec<Vec<f32>>,
|
||||
pub output_gain: f32
|
||||
}
|
||||
|
||||
/// A sound sample.
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Sample {
|
||||
pub name: String,
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
pub channels: Vec<Vec<f32>>,
|
||||
pub rate: Option<usize>,
|
||||
}
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
||||
/// A plugin device.
|
||||
#[derive(Debug)]
|
||||
pub struct Plugin {
|
||||
/// JACK client handle (needs to not be dropped for standalone mode to work).
|
||||
pub jack: Arc<RwLock<JackClient>>,
|
||||
pub name: String,
|
||||
pub path: Option<String>,
|
||||
pub plugin: Option<PluginKind>,
|
||||
pub selected: usize,
|
||||
pub mapping: bool,
|
||||
pub ports: JackPorts,
|
||||
}
|
||||
impl Plugin {
|
||||
pub fn new_lv2 (
|
||||
jack: &Arc<RwLock<JackClient>>,
|
||||
name: &str,
|
||||
path: &str,
|
||||
) -> Usually<JackDevice> {
|
||||
let plugin = LV2Plugin::new(path)?;
|
||||
jack_from_lv2(name, &plugin.plugin)?.run(|ports|Box::new(Self {
|
||||
jack: jack.clone(),
|
||||
name: name.into(),
|
||||
path: Some(String::from(path)),
|
||||
plugin: Some(PluginKind::LV2(plugin)),
|
||||
selected: 0,
|
||||
mapping: false,
|
||||
ports
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// Supported plugin formats.
|
||||
#[derive(Default)]
|
||||
pub enum PluginKind {
|
||||
#[default] None,
|
||||
LV2(LV2Plugin),
|
||||
VST2 { instance: ::vst::host::PluginInstance },
|
||||
VST3,
|
||||
}
|
||||
impl std::fmt::Debug for PluginKind {
|
||||
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(f, "{}", match self {
|
||||
Self::None => "(none)",
|
||||
Self::LV2(_) => "LV2",
|
||||
Self::VST2{..} => "VST2",
|
||||
Self::VST3 => "VST3",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A LV2 plugin.
|
||||
#[derive(Debug)]
|
||||
pub struct LV2Plugin {
|
||||
pub world: livi::World,
|
||||
pub instance: livi::Instance,
|
||||
pub plugin: livi::Plugin,
|
||||
pub features: Arc<livi::Features>,
|
||||
pub port_list: Vec<livi::Port>,
|
||||
pub input_buffer: Vec<livi::event::LV2AtomSequence>,
|
||||
pub ui_thread: Option<JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl LV2Plugin {
|
||||
const INPUT_BUFFER: usize = 1024;
|
||||
pub fn new (uri: &str) -> Usually<Self> {
|
||||
let world = livi::World::with_load_bundle(&uri);
|
||||
let features = world
|
||||
.build_features(livi::FeaturesBuilder {
|
||||
min_block_length: 1,
|
||||
max_block_length: 65536,
|
||||
});
|
||||
let plugin = world
|
||||
.iter_plugins()
|
||||
.nth(0)
|
||||
.expect(&format!("plugin not found: {uri}"));
|
||||
Ok(Self {
|
||||
instance: unsafe {
|
||||
plugin
|
||||
.instantiate(features.clone(), 48000.0)
|
||||
.expect(&format!("instantiate failed: {uri}"))
|
||||
},
|
||||
port_list: plugin.ports().collect::<Vec<_>>(),
|
||||
input_buffer: Vec::with_capacity(Self::INPUT_BUFFER),
|
||||
ui_thread: None,
|
||||
world,
|
||||
features,
|
||||
plugin,
|
||||
})
|
||||
}
|
||||
api_jack
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue