mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 03:36:41 +01:00
131 lines
4.2 KiB
Rust
131 lines
4.2 KiB
Rust
use crate::*;
|
|
|
|
impl<T: Has<Vec<Track>> + Send + Sync> HasTracks for T {}
|
|
|
|
pub trait HasTracks: Has<Vec<Track>> + Send + Sync {
|
|
fn tracks (&self) -> &Vec<Track> {
|
|
Has::<Vec<Track>>::get(self)
|
|
}
|
|
fn tracks_mut (&mut self) -> &mut Vec<Track> {
|
|
Has::<Vec<Track>>::get_mut(self)
|
|
}
|
|
/// Run audio callbacks for every track and every device
|
|
fn process_tracks (&mut self, client: &Client, scope: &ProcessScope) -> Control {
|
|
for track in self.tracks_mut().iter_mut() {
|
|
if Control::Quit == Audio::process(&mut track.sequencer, client, scope) {
|
|
return Control::Quit
|
|
}
|
|
for device in track.devices.iter_mut() {
|
|
if Control::Quit == DeviceAudio(device).process(client, scope) {
|
|
return Control::Quit
|
|
}
|
|
}
|
|
}
|
|
Control::Continue
|
|
}
|
|
fn track_longest_name (&self) -> usize {
|
|
self.tracks().iter().map(|s|s.name.len()).fold(0, usize::max)
|
|
}
|
|
/// Stop all playing clips
|
|
fn tracks_stop_all (&mut self) {
|
|
for track in self.tracks_mut().iter_mut() {
|
|
track.sequencer.enqueue_next(None);
|
|
}
|
|
}
|
|
/// Stop all playing clips
|
|
fn tracks_launch (&mut self, clips: Option<Vec<Option<Arc<RwLock<MidiClip>>>>>) {
|
|
if let Some(clips) = clips {
|
|
for (clip, track) in clips.iter().zip(self.tracks_mut()) {
|
|
track.sequencer.enqueue_next(clip.as_ref());
|
|
}
|
|
} else {
|
|
for track in self.tracks_mut().iter_mut() {
|
|
track.sequencer.enqueue_next(None);
|
|
}
|
|
}
|
|
}
|
|
/// Iterate over tracks with their corresponding sizes.
|
|
fn tracks_with_sizes (
|
|
&self,
|
|
selection: &Selection,
|
|
editor_width: Option<usize>
|
|
) -> impl TracksSizes<'_> {
|
|
let mut x = 0;
|
|
let active_track = if let Some(width) = editor_width {
|
|
selection.track()
|
|
} else {
|
|
None
|
|
};
|
|
self.tracks().iter().enumerate().map(move |(index, track)|{
|
|
let width = active_track
|
|
.and_then(|_|editor_width)
|
|
.unwrap_or(track.width.max(8));
|
|
let data = (index, track, x, x + width);
|
|
x += width + Self::TRACK_SPACING;
|
|
data
|
|
})
|
|
}
|
|
/// Spacing between tracks.
|
|
const TRACK_SPACING: usize = 0;
|
|
}
|
|
|
|
impl Arrangement {
|
|
/// Add multiple tracks
|
|
pub fn tracks_add (
|
|
&mut self,
|
|
count: usize,
|
|
width: Option<usize>,
|
|
mins: &[PortConnect],
|
|
mouts: &[PortConnect],
|
|
) -> Usually<()> {
|
|
let jack = self.jack().clone();
|
|
let track_color_1 = ItemColor::random();
|
|
let track_color_2 = ItemColor::random();
|
|
for i in 0..count {
|
|
let color = track_color_1.mix(track_color_2, i as f32 / count as f32).into();
|
|
let mut track = self.track_add(None, Some(color), mins, mouts)?.1;
|
|
if let Some(width) = width {
|
|
track.width = width;
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Add a track
|
|
pub fn track_add (
|
|
&mut self,
|
|
name: Option<&str>,
|
|
color: Option<ItemTheme>,
|
|
mins: &[PortConnect],
|
|
mouts: &[PortConnect],
|
|
) -> Usually<(usize, &mut Track)> {
|
|
self.track_last += 1;
|
|
let name: Arc<str> = name.map_or_else(
|
|
||format!("Track{:02}", self.track_last).into(),
|
|
|x|x.to_string().into()
|
|
);
|
|
let mut track = Track {
|
|
width: (name.len() + 2).max(12),
|
|
color: color.unwrap_or_else(ItemTheme::random),
|
|
sequencer: Sequencer::new(
|
|
&format!("{name}"),
|
|
self.jack(),
|
|
Some(self.clock()),
|
|
None,
|
|
mins,
|
|
mouts
|
|
)?,
|
|
name,
|
|
..Default::default()
|
|
};
|
|
self.tracks_mut().push(track);
|
|
let len = self.tracks().len();
|
|
let index = len - 1;
|
|
for scene in self.scenes_mut().iter_mut() {
|
|
while scene.clips.len() < len {
|
|
scene.clips.push(None);
|
|
}
|
|
}
|
|
Ok((index, &mut self.tracks_mut()[index]))
|
|
}
|
|
}
|