mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
and it once again compiles
This commit is contained in:
parent
6dd4caeb42
commit
430c51e305
31 changed files with 466 additions and 694 deletions
|
|
@ -2,6 +2,160 @@
|
|||
|
||||
use crate::*;
|
||||
|
||||
/// Represents the tracks and scenes of the composition.
|
||||
pub struct Arranger {
|
||||
/// Display mode of arranger
|
||||
pub mode: ArrangerViewMode,
|
||||
/// Currently selected element.
|
||||
pub selected: ArrangerFocus,
|
||||
/// Collection of tracks.
|
||||
pub tracks: Vec<SequencerTrack>,
|
||||
/// Collection of scenes.
|
||||
pub scenes: Vec<Scene>,
|
||||
pub focused: bool,
|
||||
pub entered: bool,
|
||||
pub fixed_height: bool,
|
||||
pub sequencer: Sequencer,
|
||||
}
|
||||
|
||||
/// Display mode of arranger
|
||||
pub enum ArrangerViewMode {
|
||||
Vertical,
|
||||
VerticalCompact,
|
||||
Horizontal,
|
||||
}
|
||||
|
||||
impl ArrangerViewMode {
|
||||
fn to_next (&mut self) {
|
||||
*self = match self {
|
||||
Self::Vertical => Self::VerticalCompact,
|
||||
Self::VerticalCompact => Self::Horizontal,
|
||||
Self::Horizontal => Self::Vertical,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Arranger {
|
||||
pub fn new () -> Self {
|
||||
Self {
|
||||
mode: ArrangerViewMode::Vertical,
|
||||
selected: ArrangerFocus::Clip(0, 0),
|
||||
scenes: vec![],
|
||||
tracks: vec![],
|
||||
entered: true,
|
||||
focused: true,
|
||||
fixed_height: false,
|
||||
sequencer: Sequencer::new(),
|
||||
}
|
||||
}
|
||||
pub fn activate (&mut self) {
|
||||
match self.selected {
|
||||
ArrangerFocus::Scene(s) => {
|
||||
for (track_index, track) in self.tracks.iter_mut().enumerate() {
|
||||
track.sequence = self.scenes[s].clips[track_index];
|
||||
track.reset = true;
|
||||
}
|
||||
},
|
||||
ArrangerFocus::Clip(t, s) => {
|
||||
self.tracks[t].sequence = self.scenes[s].clips[t];
|
||||
self.tracks[t].reset = true;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
fn show_phrase (&mut self) -> Usually<()> {
|
||||
unimplemented!()
|
||||
//let phrase = self.phrase();
|
||||
//self.sequencer.show(phrase)
|
||||
}
|
||||
pub fn phrase (&self) -> Option<&Arc<RwLock<Phrase>>> {
|
||||
let track_id = self.selected.track()?;
|
||||
self.tracks.get(track_id)?.phrases.get((*self.scene()?.clips.get(track_id)?)?)
|
||||
}
|
||||
pub fn phrase_next (&mut self) {
|
||||
let track_index = self.selected.track();
|
||||
let scene_index = self.selected.scene();
|
||||
track_index
|
||||
.and_then(|index|self.tracks.get_mut(index).map(|track|(index, track)))
|
||||
.and_then(|(track_index, track)|{
|
||||
let phrases = track.phrases.len();
|
||||
scene_index
|
||||
.and_then(|index|self.scenes.get_mut(index))
|
||||
.and_then(|scene|{
|
||||
if let Some(phrase_index) = scene.clips[track_index] {
|
||||
if phrase_index >= phrases - 1 {
|
||||
scene.clips[track_index] = None;
|
||||
} else {
|
||||
scene.clips[track_index] = Some(phrase_index + 1);
|
||||
}
|
||||
} else if phrases > 0 {
|
||||
scene.clips[track_index] = Some(0);
|
||||
}
|
||||
Some(())
|
||||
})
|
||||
});
|
||||
}
|
||||
pub fn phrase_prev (&mut self) {
|
||||
let track_index = self.selected.track();
|
||||
let scene_index = self.selected.scene();
|
||||
track_index
|
||||
.and_then(|index|self.tracks.get_mut(index).map(|track|(index, track)))
|
||||
.and_then(|(track_index, track)|{
|
||||
let phrases = track.phrases.len();
|
||||
scene_index
|
||||
.and_then(|index|self.scenes.get_mut(index))
|
||||
.and_then(|scene|{
|
||||
if let Some(phrase_index) = scene.clips[track_index] {
|
||||
scene.clips[track_index] = if phrase_index == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(phrase_index - 1)
|
||||
};
|
||||
} else if phrases > 0 {
|
||||
scene.clips[track_index] = Some(phrases - 1);
|
||||
}
|
||||
Some(())
|
||||
})
|
||||
});
|
||||
}
|
||||
pub fn scene (&self) -> Option<&Scene> {
|
||||
self.selected.scene().map(|s|self.scenes.get(s)).flatten()
|
||||
}
|
||||
pub fn scene_mut (&mut self) -> Option<&mut Scene> {
|
||||
self.selected.scene().map(|s|self.scenes.get_mut(s)).flatten()
|
||||
}
|
||||
pub fn scene_next (&mut self) {
|
||||
self.selected.scene_next(self.scenes.len() - 1)
|
||||
}
|
||||
pub fn scene_prev (&mut self) {
|
||||
self.selected.scene_prev()
|
||||
}
|
||||
pub fn scene_add (&mut self, name: Option<&str>) -> Usually<&mut Scene> {
|
||||
let clips = vec![None;self.tracks.len()];
|
||||
self.scenes.push(match name {
|
||||
Some(name) => Scene::new(name, clips),
|
||||
None => Scene::new(&self.scene_default_name(), clips),
|
||||
});
|
||||
let index = self.scenes.len() - 1;
|
||||
Ok(&mut self.scenes[index])
|
||||
}
|
||||
pub fn scene_del (&mut self) {
|
||||
unimplemented!("Arranger::scene_del");
|
||||
}
|
||||
pub fn scene_default_name (&self) -> String {
|
||||
format!("Scene {}", self.scenes.len() + 1)
|
||||
}
|
||||
}
|
||||
|
||||
render!(Arranger |self, buf, area| match self.mode {
|
||||
ArrangerViewMode::Horizontal =>
|
||||
super::arranger_view_h::draw(self, buf, area),
|
||||
ArrangerViewMode::Vertical =>
|
||||
super::arranger_view_v::draw_expanded(self, buf, area),
|
||||
ArrangerViewMode::VerticalCompact =>
|
||||
super::arranger_view_v::draw_compact(self, buf, area),
|
||||
});
|
||||
|
||||
/// Key bindings for arranger section.
|
||||
pub const KEYMAP_ARRANGER: &'static [KeyBinding<Arranger>] = keymap!(Arranger {
|
||||
[Char('`'), NONE, "arranger_mode_switch", "switch the display mode", |app: &mut Arranger| {
|
||||
|
|
@ -55,86 +209,3 @@ pub const KEYMAP_ARRANGER: &'static [KeyBinding<Arranger>] = keymap!(Arranger {
|
|||
Ok(true)
|
||||
}],
|
||||
});
|
||||
|
||||
/// Represents the tracks and scenes of the composition.
|
||||
pub struct Arranger {
|
||||
/// Display mode of arranger
|
||||
pub mode: ArrangerViewMode,
|
||||
/// Currently selected element.
|
||||
pub selected: ArrangerFocus,
|
||||
/// Collection of tracks.
|
||||
pub tracks: Vec<SequencerTrack>,
|
||||
/// Collection of scenes.
|
||||
pub scenes: Vec<Scene>,
|
||||
|
||||
pub focused: bool,
|
||||
pub entered: bool,
|
||||
pub fixed_height: bool,
|
||||
|
||||
pub sequencer: Sequencer,
|
||||
}
|
||||
|
||||
/// Display mode of arranger
|
||||
pub enum ArrangerViewMode {
|
||||
Vertical,
|
||||
VerticalCompact,
|
||||
Horizontal,
|
||||
}
|
||||
|
||||
impl ArrangerViewMode {
|
||||
fn to_next (&mut self) {
|
||||
*self = match self {
|
||||
Self::Vertical => Self::VerticalCompact,
|
||||
Self::VerticalCompact => Self::Horizontal,
|
||||
Self::Horizontal => Self::Vertical,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Arranger {
|
||||
|
||||
pub fn new () -> Self {
|
||||
Self {
|
||||
mode: ArrangerViewMode::Vertical,
|
||||
selected: ArrangerFocus::Clip(0, 0),
|
||||
scenes: vec![],
|
||||
tracks: vec![],
|
||||
entered: true,
|
||||
focused: true,
|
||||
fixed_height: false,
|
||||
sequencer: Sequencer::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn activate (&mut self) {
|
||||
match self.selected {
|
||||
ArrangerFocus::Scene(s) => {
|
||||
for (track_index, track) in self.tracks.iter_mut().enumerate() {
|
||||
track.sequence = self.scenes[s].clips[track_index];
|
||||
track.reset = true;
|
||||
}
|
||||
},
|
||||
ArrangerFocus::Clip(t, s) => {
|
||||
self.tracks[t].sequence = self.scenes[s].clips[t];
|
||||
self.tracks[t].reset = true;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn show_phrase (&mut self) -> Usually<()> {
|
||||
unimplemented!()
|
||||
//let phrase = self.phrase();
|
||||
//self.sequencer.show(phrase)
|
||||
}
|
||||
}
|
||||
|
||||
render!(Arranger |self, buf, area| match self.mode {
|
||||
ArrangerViewMode::Horizontal =>
|
||||
super::arranger_view_h::draw(self, buf, area),
|
||||
ArrangerViewMode::Vertical =>
|
||||
super::arranger_view_v::draw_expanded(self, buf, area),
|
||||
ArrangerViewMode::VerticalCompact =>
|
||||
super::arranger_view_v::draw_compact(self, buf, area),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,57 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
use super::Arranger;
|
||||
|
||||
/// Phrase management methods
|
||||
impl Arranger {
|
||||
pub fn phrase (&self) -> Option<&Arc<RwLock<Phrase>>> {
|
||||
let track_id = self.selected.track()?;
|
||||
self.tracks.get(track_id)?.phrases.get((*self.scene()?.clips.get(track_id)?)?)
|
||||
}
|
||||
pub fn phrase_next (&mut self) {
|
||||
let track_index = self.selected.track();
|
||||
let scene_index = self.selected.scene();
|
||||
track_index
|
||||
.and_then(|index|self.tracks.get_mut(index).map(|track|(index, track)))
|
||||
.and_then(|(track_index, track)|{
|
||||
let phrases = track.phrases.len();
|
||||
scene_index
|
||||
.and_then(|index|self.scenes.get_mut(index))
|
||||
.and_then(|scene|{
|
||||
if let Some(phrase_index) = scene.clips[track_index] {
|
||||
if phrase_index >= phrases - 1 {
|
||||
scene.clips[track_index] = None;
|
||||
} else {
|
||||
scene.clips[track_index] = Some(phrase_index + 1);
|
||||
}
|
||||
} else if phrases > 0 {
|
||||
scene.clips[track_index] = Some(0);
|
||||
}
|
||||
Some(())
|
||||
})
|
||||
});
|
||||
}
|
||||
pub fn phrase_prev (&mut self) {
|
||||
let track_index = self.selected.track();
|
||||
let scene_index = self.selected.scene();
|
||||
track_index
|
||||
.and_then(|index|self.tracks.get_mut(index).map(|track|(index, track)))
|
||||
.and_then(|(track_index, track)|{
|
||||
let phrases = track.phrases.len();
|
||||
scene_index
|
||||
.and_then(|index|self.scenes.get_mut(index))
|
||||
.and_then(|scene|{
|
||||
if let Some(phrase_index) = scene.clips[track_index] {
|
||||
scene.clips[track_index] = if phrase_index == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(phrase_index - 1)
|
||||
};
|
||||
} else if phrases > 0 {
|
||||
scene.clips[track_index] = Some(phrases - 1);
|
||||
}
|
||||
Some(())
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -17,9 +17,8 @@ submod! {
|
|||
sequencer_track
|
||||
arranger
|
||||
arranger_focus
|
||||
arranger_phrase
|
||||
arranger_scene
|
||||
arranger_track
|
||||
scene
|
||||
}
|
||||
|
||||
pubmod! {
|
||||
|
|
|
|||
|
|
@ -79,6 +79,60 @@ impl Phrase {
|
|||
}
|
||||
}
|
||||
}
|
||||
fn from_edn <'e> (ppq: usize, args: &[Edn<'e>]) -> Usually<Self> {
|
||||
let mut phrase = Self::default();
|
||||
let mut name = String::new();
|
||||
let mut beats = 0usize;
|
||||
let mut steps = 0usize;
|
||||
edn!(edn in args {
|
||||
Edn::Map(map) => {
|
||||
if let Some(Edn::Str(n)) = map.get(&Edn::Key(":name")) {
|
||||
name = String::from(*n);
|
||||
}
|
||||
if let Some(Edn::Int(b)) = map.get(&Edn::Key(":beats")) {
|
||||
beats = *b as usize;
|
||||
phrase.length = ppq * beats;
|
||||
for _ in phrase.notes.len()..phrase.length {
|
||||
phrase.notes.push(Vec::with_capacity(16))
|
||||
}
|
||||
}
|
||||
if let Some(Edn::Int(s)) = map.get(&Edn::Key(":steps")) {
|
||||
steps = *s as usize;
|
||||
}
|
||||
},
|
||||
Edn::List(args) => {
|
||||
let time = (match args.get(0) {
|
||||
Some(Edn::Key(text)) => text[1..].parse::<f64>()?,
|
||||
Some(Edn::Int(i)) => *i as f64,
|
||||
Some(Edn::Double(f)) => f64::from(*f),
|
||||
_ => panic!("unexpected in phrase '{name}': {:?}", args.get(0)),
|
||||
} * beats as f64 * ppq as f64 / steps as f64) as usize;
|
||||
for edn in args[1..].iter() {
|
||||
match edn {
|
||||
Edn::List(args) => if let (
|
||||
Some(Edn::Int(key)),
|
||||
Some(Edn::Int(vel)),
|
||||
) = (
|
||||
args.get(0),
|
||||
args.get(1),
|
||||
) {
|
||||
let (key, vel) = (
|
||||
u7::from((*key as u8).min(127)),
|
||||
u7::from((*vel as u8).min(127)),
|
||||
);
|
||||
phrase.notes[time].push(MidiMessage::NoteOn { key, vel })
|
||||
} else {
|
||||
panic!("unexpected list in phrase '{name}'")
|
||||
},
|
||||
_ => panic!("unexpected in phrase '{name}': {edn:?}")
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => panic!("unexpected in phrase '{name}': {edn:?}"),
|
||||
});
|
||||
phrase.name = name;
|
||||
Ok(phrase)
|
||||
}
|
||||
}
|
||||
|
||||
/// Define a MIDI phrase.
|
||||
|
|
|
|||
|
|
@ -1,115 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
impl Phrase {
|
||||
fn load_edn <'e> (ppq: usize, args: &[Edn<'e>]) -> Usually<Self> {
|
||||
let mut phrase = Self::default();
|
||||
let mut name = String::new();
|
||||
let mut beats = 0usize;
|
||||
let mut steps = 0usize;
|
||||
edn!(edn in args {
|
||||
Edn::Map(map) => {
|
||||
if let Some(Edn::Str(n)) = map.get(&Edn::Key(":name")) {
|
||||
name = String::from(*n);
|
||||
}
|
||||
if let Some(Edn::Int(b)) = map.get(&Edn::Key(":beats")) {
|
||||
beats = *b as usize;
|
||||
phrase.length = ppq * beats;
|
||||
for _ in phrase.notes.len()..phrase.length {
|
||||
phrase.notes.push(Vec::with_capacity(16))
|
||||
}
|
||||
}
|
||||
if let Some(Edn::Int(s)) = map.get(&Edn::Key(":steps")) {
|
||||
steps = *s as usize;
|
||||
}
|
||||
},
|
||||
Edn::List(args) => {
|
||||
let time = (match args.get(0) {
|
||||
Some(Edn::Key(text)) => text[1..].parse::<f64>()?,
|
||||
Some(Edn::Int(i)) => *i as f64,
|
||||
Some(Edn::Double(f)) => f64::from(*f),
|
||||
_ => panic!("unexpected in phrase '{name}': {:?}", args.get(0)),
|
||||
} * beats as f64 * ppq as f64 / steps as f64) as usize;
|
||||
for edn in args[1..].iter() {
|
||||
match edn {
|
||||
Edn::List(args) => if let (
|
||||
Some(Edn::Int(key)),
|
||||
Some(Edn::Int(vel)),
|
||||
) = (
|
||||
args.get(0),
|
||||
args.get(1),
|
||||
) {
|
||||
let (key, vel) = (
|
||||
u7::from((*key as u8).min(127)),
|
||||
u7::from((*vel as u8).min(127)),
|
||||
);
|
||||
phrase.notes[time].push(MidiMessage::NoteOn { key, vel })
|
||||
} else {
|
||||
panic!("unexpected list in phrase '{name}'")
|
||||
},
|
||||
_ => panic!("unexpected in phrase '{name}': {edn:?}")
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => panic!("unexpected in phrase '{name}': {edn:?}"),
|
||||
});
|
||||
phrase.name = name;
|
||||
Ok(phrase)
|
||||
}
|
||||
}
|
||||
|
||||
//impl Phrase {
|
||||
//fn from_edn <'e> (ppq: usize, args: &[Edn<'e>]) -> Usually<Self> {
|
||||
//let mut phrase = Self::default();
|
||||
//let mut name = String::new();
|
||||
//let mut beats = 0usize;
|
||||
//let mut steps = 0usize;
|
||||
//edn!(edn in args {
|
||||
//Edn::Map(map) => {
|
||||
//if let Some(Edn::Str(n)) = map.get(&Edn::Key(":name")) {
|
||||
//name = String::from(*n);
|
||||
//}
|
||||
//if let Some(Edn::Int(b)) = map.get(&Edn::Key(":beats")) {
|
||||
//beats = *b as usize;
|
||||
//phrase.length = ppq * beats;
|
||||
//for _ in phrase.notes.len()..phrase.length {
|
||||
//phrase.notes.push(Vec::with_capacity(16))
|
||||
//}
|
||||
//}
|
||||
//if let Some(Edn::Int(s)) = map.get(&Edn::Key(":steps")) {
|
||||
//steps = *s as usize;
|
||||
//}
|
||||
//},
|
||||
//Edn::List(args) => {
|
||||
//let time = (match args.get(0) {
|
||||
//Some(Edn::Key(text)) => text[1..].parse::<f64>()?,
|
||||
//Some(Edn::Int(i)) => *i as f64,
|
||||
//Some(Edn::Double(f)) => f64::from(*f),
|
||||
//_ => panic!("unexpected in phrase '{name}': {:?}", args.get(0)),
|
||||
//} * beats as f64 * ppq as f64 / steps as f64) as usize;
|
||||
//for edn in args[1..].iter() {
|
||||
//match edn {
|
||||
//Edn::List(args) => if let (
|
||||
//Some(Edn::Int(key)),
|
||||
//Some(Edn::Int(vel)),
|
||||
//) = (
|
||||
//args.get(0),
|
||||
//args.get(1),
|
||||
//) {
|
||||
//let (key, vel) = (
|
||||
//u7::from((*key as u8).min(127)),
|
||||
//u7::from((*vel as u8).min(127)),
|
||||
//);
|
||||
//phrase.notes[time].push(MidiMessage::NoteOn { key, vel })
|
||||
//} else {
|
||||
//panic!("unexpected list in phrase '{name}'")
|
||||
//},
|
||||
//_ => panic!("unexpected in phrase '{name}': {edn:?}")
|
||||
//}
|
||||
//}
|
||||
//},
|
||||
//_ => panic!("unexpected in phrase '{name}': {edn:?}"),
|
||||
//});
|
||||
//phrase.name = name;
|
||||
//Ok(phrase)
|
||||
//}
|
||||
//}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
use crate::*;
|
||||
|
||||
use super::Arranger;
|
||||
|
||||
/// A collection of phrases to play on each track.
|
||||
pub struct Scene {
|
||||
pub name: String,
|
||||
|
|
@ -48,33 +46,28 @@ pub fn scene_ppqs (tracks: &[SequencerTrack], scenes: &[Scene]) -> Vec<(usize, u
|
|||
scenes
|
||||
}
|
||||
|
||||
/// Scene management methods
|
||||
impl Arranger {
|
||||
pub fn scene (&self) -> Option<&Scene> {
|
||||
self.selected.scene().map(|s|self.scenes.get(s)).flatten()
|
||||
}
|
||||
pub fn scene_mut (&mut self) -> Option<&mut Scene> {
|
||||
self.selected.scene().map(|s|self.scenes.get_mut(s)).flatten()
|
||||
}
|
||||
pub fn scene_next (&mut self) {
|
||||
self.selected.scene_next(self.scenes.len() - 1)
|
||||
}
|
||||
pub fn scene_prev (&mut self) {
|
||||
self.selected.scene_prev()
|
||||
}
|
||||
pub fn scene_add (&mut self, name: Option<&str>) -> Usually<&mut Scene> {
|
||||
let clips = vec![None;self.tracks.len()];
|
||||
self.scenes.push(match name {
|
||||
Some(name) => Scene::new(name, clips),
|
||||
None => Scene::new(&self.scene_default_name(), clips),
|
||||
impl Scene {
|
||||
pub fn from_edn <'a, 'e> (args: &[Edn<'e>]) -> Usually<Self> {
|
||||
let mut name = None;
|
||||
let mut clips = vec![];
|
||||
edn!(edn in args {
|
||||
Edn::Map(map) => {
|
||||
let key = map.get(&Edn::Key(":name"));
|
||||
if let Some(Edn::Str(n)) = key {
|
||||
name = Some(*n);
|
||||
} else {
|
||||
panic!("unexpected key in scene '{name:?}': {key:?}")
|
||||
}
|
||||
},
|
||||
Edn::Symbol("_") => {
|
||||
clips.push(None);
|
||||
},
|
||||
Edn::Int(i) => {
|
||||
clips.push(Some(*i as usize));
|
||||
},
|
||||
_ => panic!("unexpected in scene '{name:?}': {edn:?}")
|
||||
});
|
||||
let index = self.scenes.len() - 1;
|
||||
Ok(&mut self.scenes[index])
|
||||
}
|
||||
pub fn scene_del (&mut self) {
|
||||
unimplemented!("Arranger::scene_del");
|
||||
}
|
||||
pub fn scene_default_name (&self) -> String {
|
||||
format!("Scene {}", self.scenes.len() + 1)
|
||||
let scene = Self::new(name.unwrap_or(""), clips);
|
||||
Ok(scene)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
impl Scene {
|
||||
pub fn load_edn <'a, 'e> (app: &'a mut App, args: &[Edn<'e>]) -> Usually<&'a mut Self> {
|
||||
let mut name = None;
|
||||
let mut clips = vec![];
|
||||
edn!(edn in args {
|
||||
Edn::Map(map) => {
|
||||
let key = map.get(&Edn::Key(":name"));
|
||||
if let Some(Edn::Str(n)) = key {
|
||||
name = Some(*n);
|
||||
} else {
|
||||
panic!("unexpected key in scene '{name:?}': {key:?}")
|
||||
}
|
||||
},
|
||||
Edn::Symbol("_") => {
|
||||
clips.push(None);
|
||||
},
|
||||
Edn::Int(i) => {
|
||||
clips.push(Some(*i as usize));
|
||||
},
|
||||
_ => panic!("unexpected in scene '{name:?}': {edn:?}")
|
||||
});
|
||||
let scene = app.arranger.scene_add(name)?;
|
||||
scene.clips = clips;
|
||||
Ok(scene)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue