mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
111 lines
3.4 KiB
Rust
111 lines
3.4 KiB
Rust
use crate::*;
|
|
impl Arranger {
|
|
pub fn track_next_name (&self) -> String {
|
|
format!("T{}", self.tracks.len() + 1)
|
|
}
|
|
pub fn track_add (&mut self, name: Option<&str>, color: Option<ItemPalette>)
|
|
-> Usually<&mut ArrangerTrack>
|
|
{
|
|
let name = name.map_or_else(||self.track_next_name(), |x|x.to_string());
|
|
let track = ArrangerTrack {
|
|
width: name.len() + 2,
|
|
name: Arc::new(name.into()),
|
|
color: color.unwrap_or_else(ItemPalette::random),
|
|
player: MidiPlayer::from(&self.clock),
|
|
};
|
|
self.tracks.push(track);
|
|
let index = self.tracks.len() - 1;
|
|
Ok(&mut self.tracks[index])
|
|
}
|
|
pub fn track_del (&mut self, index: usize) {
|
|
self.tracks.remove(index);
|
|
for scene in self.scenes.iter_mut() {
|
|
scene.clips.remove(index);
|
|
}
|
|
}
|
|
}
|
|
#[derive(Debug)] pub struct ArrangerTrack {
|
|
/// Name of track
|
|
pub name: Arc<RwLock<String>>,
|
|
/// Preferred width of track column
|
|
pub width: usize,
|
|
/// Identifying color of track
|
|
pub color: ItemPalette,
|
|
/// MIDI player state
|
|
pub player: MidiPlayer,
|
|
}
|
|
has_clock!(|self:ArrangerTrack|self.player.clock());
|
|
has_player!(|self:ArrangerTrack|self.player);
|
|
impl ArrangerTrack {
|
|
pub fn widths (tracks: &[Self]) -> Vec<(usize, usize)> {
|
|
let mut widths = vec![];
|
|
let mut total = 0;
|
|
for track in tracks.iter() {
|
|
let width = track.width;
|
|
widths.push((width, total));
|
|
total += width;
|
|
}
|
|
widths.push((0, total));
|
|
widths
|
|
}
|
|
pub fn with_widths (tracks: &[ArrangerTrack])
|
|
-> impl Iterator<Item = (usize, &ArrangerTrack, usize, usize)>
|
|
{
|
|
let mut x = 0;
|
|
tracks.iter().enumerate().map(move |(index, track)|{
|
|
let data = (index, track, x, x + track.width);
|
|
x += track.width;
|
|
data
|
|
})
|
|
}
|
|
/// Name of track
|
|
pub fn name (&self) -> &Arc<RwLock<String>> {
|
|
&self.name
|
|
}
|
|
/// Preferred width of track column
|
|
fn width (&self) -> usize {
|
|
self.width
|
|
}
|
|
/// Preferred width of track column
|
|
fn width_mut (&mut self) -> &mut usize {
|
|
&mut self.width
|
|
}
|
|
/// Identifying color of track
|
|
pub fn color (&self) -> ItemPalette {
|
|
self.color
|
|
}
|
|
fn longest_name (tracks: &[Self]) -> usize {
|
|
tracks.iter().map(|s|s.name().read().unwrap().len()).fold(0, usize::max)
|
|
}
|
|
pub const MIN_WIDTH: usize = 6;
|
|
fn width_inc (&mut self) {
|
|
*self.width_mut() += 1;
|
|
}
|
|
fn width_dec (&mut self) {
|
|
if self.width() > Self::MIN_WIDTH {
|
|
*self.width_mut() -= 1;
|
|
}
|
|
}
|
|
}
|
|
/// Hosts the JACK callback for a collection of tracks
|
|
pub struct TracksAudio<'a>(
|
|
// Track collection
|
|
pub &'a mut [ArrangerTrack],
|
|
/// Note buffer
|
|
pub &'a mut Vec<u8>,
|
|
/// Note chunk buffer
|
|
pub &'a mut Vec<Vec<Vec<u8>>>,
|
|
);
|
|
impl Audio for TracksAudio<'_> {
|
|
#[inline] fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
|
|
let model = &mut self.0;
|
|
let note_buffer = &mut self.1;
|
|
let output_buffer = &mut self.2;
|
|
for track in model.iter_mut() {
|
|
if PlayerAudio(track.player_mut(), note_buffer, output_buffer).process(client, scope) == Control::Quit {
|
|
return Control::Quit
|
|
}
|
|
}
|
|
Control::Continue
|
|
}
|
|
}
|