mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
IT BOPS
This commit is contained in:
parent
0ba14bf2da
commit
3ba5e253b0
5 changed files with 120 additions and 59 deletions
|
|
@ -171,13 +171,24 @@ pub fn render (state: &Plugin, buf: &mut Buffer, area: Rect)
|
||||||
let Rect { x, y, height, .. } = area;
|
let Rect { x, y, height, .. } = area;
|
||||||
let mut width = 40u16;
|
let mut width = 40u16;
|
||||||
match &state.plugin {
|
match &state.plugin {
|
||||||
Some(PluginKind::LV2 { portList, .. }) => {
|
Some(PluginKind::LV2 { portList, instance, .. }) => {
|
||||||
|
let start = state.selected.saturating_sub((height as usize / 2).saturating_sub(1));
|
||||||
|
let end = start + height as usize - 2;
|
||||||
//draw_box(buf, Rect { x, y, width, height });
|
//draw_box(buf, Rect { x, y, width, height });
|
||||||
for i in 0..height-3 {
|
for i in start..end {
|
||||||
if let Some(port) = portList.get(i as usize) {
|
if let Some(port) = portList.get(i) {
|
||||||
let label = &format!("C·· M·· {:25} = {:03}", port.name, port.default_value);
|
let value = if let Some(value) = instance.control_input(port.index) {
|
||||||
|
value
|
||||||
|
} else {
|
||||||
|
port.default_value
|
||||||
|
};
|
||||||
|
let label = &format!("C·· M·· {:25} = {value:.03}", port.name);
|
||||||
width = width.max(label.len() as u16);
|
width = width.max(label.len() as u16);
|
||||||
label.blit(buf, x + 2, y + 2 + i as u16, None);
|
label.blit(buf, x + 2, y + 1 + i as u16 - start as u16, if i == state.selected {
|
||||||
|
Some(Style::default().green())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -200,26 +211,67 @@ fn draw_header (state: &Plugin, buf: &mut Buffer, x: u16, y: u16, w: u16) -> Usu
|
||||||
|
|
||||||
pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually<bool> {
|
pub fn handle (s: &mut Plugin, event: &AppEvent) -> Usually<bool> {
|
||||||
handle_keymap(s, event, keymap!(Plugin {
|
handle_keymap(s, event, keymap!(Plugin {
|
||||||
|
|
||||||
[Up, NONE, "cursor_up", "move cursor up",
|
[Up, NONE, "cursor_up", "move cursor up",
|
||||||
|s: &mut Plugin|{
|
|s: &mut Plugin|{
|
||||||
s.selected = s.selected.saturating_sub(1);
|
if s.selected > 0 {
|
||||||
if s.selected < s.offset {
|
s.selected = s.selected - 1
|
||||||
s.offset = s.selected;
|
} else {
|
||||||
|
s.selected = match &s.plugin {
|
||||||
|
Some(PluginKind::LV2 { portList, .. }) => portList.len() - 1,
|
||||||
|
_ => 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}],
|
}],
|
||||||
|
|
||||||
[Down, NONE, "cursor_down", "move cursor down",
|
[Down, NONE, "cursor_down", "move cursor down",
|
||||||
|s: &mut Plugin|{
|
|s: &mut Plugin|{
|
||||||
s.selected = s.selected + 1;
|
s.selected = s.selected + 1;
|
||||||
if s.selected >= s.offset + 19 {
|
match &s.plugin {
|
||||||
s.offset = s.offset + 1;
|
Some(PluginKind::LV2 { portList, .. }) => {
|
||||||
|
if s.selected >= portList.len() {
|
||||||
|
s.selected = 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}],
|
}],
|
||||||
|
|
||||||
|
[Char(','), NONE, "decrement", "decrement value",
|
||||||
|
|s: &mut Plugin|{
|
||||||
|
match s.plugin.as_mut() {
|
||||||
|
Some(PluginKind::LV2 { portList, ref mut instance, .. }) => {
|
||||||
|
let index = portList[s.selected].index;
|
||||||
|
if let Some(value) = instance.control_input(index) {
|
||||||
|
instance.set_control_input(index, value - 0.01);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}],
|
||||||
|
|
||||||
|
[Char('.'), NONE, "increment", "increment value",
|
||||||
|
|s: &mut Plugin|{
|
||||||
|
match s.plugin.as_mut() {
|
||||||
|
Some(PluginKind::LV2 { portList, ref mut instance, .. }) => {
|
||||||
|
let index = portList[s.selected].index;
|
||||||
|
if let Some(value) = instance.control_input(index) {
|
||||||
|
instance.set_control_input(index, value + 0.01);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}],
|
||||||
|
|
||||||
[Char('m'), NONE, "toggle_midi_map", "toggle midi map mode",
|
[Char('m'), NONE, "toggle_midi_map", "toggle midi map mode",
|
||||||
|s: &mut Plugin|{
|
|s: &mut Plugin|{
|
||||||
s.mapping = !s.mapping;
|
s.mapping = !s.mapping;
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}]
|
}]
|
||||||
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,18 +115,18 @@ fn toggle_help (state: &mut Launcher) -> Usually<bool> {
|
||||||
}
|
}
|
||||||
fn focus_next (state: &mut Launcher) -> Usually<bool> {
|
fn focus_next (state: &mut Launcher) -> Usually<bool> {
|
||||||
match state.view {
|
match state.view {
|
||||||
LauncherView::Tracks => { state.view = LauncherView::Chains; },
|
LauncherView::Tracks => { state.view = LauncherView::Sequencer; },
|
||||||
LauncherView::Chains => { state.view = LauncherView::Sequencer; },
|
LauncherView::Sequencer => { state.view = LauncherView::Chains; },
|
||||||
LauncherView::Sequencer => { state.view = LauncherView::Tracks; },
|
LauncherView::Chains => { state.view = LauncherView::Tracks; },
|
||||||
_ => {},
|
_ => {},
|
||||||
};
|
};
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
fn focus_prev (state: &mut Launcher) -> Usually<bool> {
|
fn focus_prev (state: &mut Launcher) -> Usually<bool> {
|
||||||
match state.view {
|
match state.view {
|
||||||
LauncherView::Tracks => { state.view = LauncherView::Sequencer; },
|
LauncherView::Tracks => { state.view = LauncherView::Chains; },
|
||||||
LauncherView::Sequencer => { state.view = LauncherView::Chains; },
|
LauncherView::Chains => { state.view = LauncherView::Sequencer; },
|
||||||
LauncherView::Chains => { state.view = LauncherView::Tracks; },
|
LauncherView::Sequencer => { state.view = LauncherView::Tracks; },
|
||||||
_ => {},
|
_ => {},
|
||||||
};
|
};
|
||||||
Ok(true)
|
Ok(true)
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ impl Launcher {
|
||||||
monitoring: true,
|
monitoring: true,
|
||||||
recording: false,
|
recording: false,
|
||||||
overdub: true,
|
overdub: true,
|
||||||
cursor: (1, 1),
|
cursor: (2, 2),
|
||||||
position: 0,
|
position: 0,
|
||||||
scenes: scenes.unwrap_or_else(||vec![Scene::new(&"Scene 1", &[None])]),
|
scenes: scenes.unwrap_or_else(||vec![Scene::new(&"Scene 1", &[None])]),
|
||||||
tracks: if let Some(tracks) = tracks { tracks } else { vec![
|
tracks: if let Some(tracks) = tracks { tracks } else { vec![
|
||||||
|
|
@ -184,7 +184,7 @@ pub fn render (state: &Launcher, buf: &mut Buffer, mut area: Rect) -> Usually<Re
|
||||||
let mut y = y + 1;
|
let mut y = y + 1;
|
||||||
y = y + LauncherGridView::new(
|
y = y + LauncherGridView::new(
|
||||||
state, buf, Rect { x, y, width, height: 8 }, state.view.is_tracks()
|
state, buf, Rect { x, y, width, height: 8 }, state.view.is_tracks()
|
||||||
).draw()?.height - 1;
|
).draw()?.height;
|
||||||
y = y + draw_section_sequencer(state, buf, Rect { x, y, width, height: 8 })?.height;
|
y = y + draw_section_sequencer(state, buf, Rect { x, y, width, height: 8 })?.height;
|
||||||
y = y + draw_section_chains(state, buf, Rect { x, y, width, height: 8 })?.height;
|
y = y + draw_section_chains(state, buf, Rect { x, y, width, height: 8 })?.height;
|
||||||
area.height = y;
|
area.height = y;
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ pub fn process (state: &mut Sequencer, _: &Client, scope: &ProcessScope) -> Cont
|
||||||
type MIDIChunk = [Option<Vec<Vec<u8>>>];
|
type MIDIChunk = [Option<Vec<Vec<u8>>>];
|
||||||
|
|
||||||
/// Add "all notes off" to the start of a buffer.
|
/// Add "all notes off" to the start of a buffer.
|
||||||
fn all_notes_off (output: &mut MIDIChunk) {
|
pub fn all_notes_off (output: &mut MIDIChunk) {
|
||||||
output[0] = Some(vec![]);
|
output[0] = Some(vec![]);
|
||||||
if let Some(Some(frame)) = output.get_mut(0) {
|
if let Some(Some(frame)) = output.get_mut(0) {
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
|
|
@ -83,7 +83,7 @@ fn all_notes_off (output: &mut MIDIChunk) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn play_from_sequence (
|
pub fn play_from_sequence (
|
||||||
output: &mut MIDIChunk,
|
output: &mut MIDIChunk,
|
||||||
sequence: &PhraseData,
|
sequence: &PhraseData,
|
||||||
timebase: &Arc<Timebase>,
|
timebase: &Arc<Timebase>,
|
||||||
|
|
@ -113,7 +113,7 @@ fn play_from_sequence (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn monitor_and_record (
|
pub fn monitor_and_record (
|
||||||
scope: &ProcessScope,
|
scope: &ProcessScope,
|
||||||
output: &mut MIDIChunk,
|
output: &mut MIDIChunk,
|
||||||
sequence: &mut PhraseData,
|
sequence: &mut PhraseData,
|
||||||
|
|
|
||||||
85
src/main.rs
85
src/main.rs
|
|
@ -44,7 +44,7 @@ fn main () -> Result<(), Box<dyn Error>> {
|
||||||
let (client, _) = Client::new("init", ClientOptions::NO_START_SERVER)?;
|
let (client, _) = Client::new("init", ClientOptions::NO_START_SERVER)?;
|
||||||
let timebase = Arc::new(Timebase {
|
let timebase = Arc::new(Timebase {
|
||||||
rate: AtomicUsize::new(client.sample_rate()),
|
rate: AtomicUsize::new(client.sample_rate()),
|
||||||
tempo: AtomicUsize::new(113000),
|
tempo: AtomicUsize::new(150000),
|
||||||
ppq: AtomicUsize::new(96),
|
ppq: AtomicUsize::new(96),
|
||||||
});
|
});
|
||||||
let ppq = timebase.ppq() as u32;
|
let ppq = timebase.ppq() as u32;
|
||||||
|
|
@ -64,34 +64,6 @@ fn main () -> Result<(), Box<dyn Error>> {
|
||||||
sample!(44, "Hihat", "/home/user/Lab/Music/pak/chh.wav"),
|
sample!(44, "Hihat", "/home/user/Lab/Music/pak/chh.wav"),
|
||||||
])))?.boxed(),
|
])))?.boxed(),
|
||||||
]), Some(vec![
|
]), Some(vec![
|
||||||
Phrase::new("4K", ppq * 4, Some(BTreeMap::from([
|
|
||||||
play!(0 => [
|
|
||||||
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
|
||||||
] ),
|
|
||||||
play!(4 => [
|
|
||||||
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
|
||||||
]),
|
|
||||||
play!(8 => [
|
|
||||||
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
|
||||||
]),
|
|
||||||
play!(12 => [
|
|
||||||
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
|
||||||
]),
|
|
||||||
]))),
|
|
||||||
Phrase::new("KS", ppq * 4, Some(BTreeMap::from([
|
|
||||||
play!(0 => [
|
|
||||||
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
|
||||||
] ),
|
|
||||||
play!(4 => [
|
|
||||||
MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
|
|
||||||
]),
|
|
||||||
play!(10 => [
|
|
||||||
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
|
||||||
]),
|
|
||||||
play!(12 => [
|
|
||||||
MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
|
|
||||||
]),
|
|
||||||
]))),
|
|
||||||
Phrase::new("KSH", ppq * 4, Some(BTreeMap::from([
|
Phrase::new("KSH", ppq * 4, Some(BTreeMap::from([
|
||||||
play!(0 => [
|
play!(0 => [
|
||||||
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
|
|
@ -123,20 +95,57 @@ fn main () -> Result<(), Box<dyn Error>> {
|
||||||
MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
|
MidiMessage::NoteOn { key: 44.into(), vel: 100.into() },
|
||||||
]),
|
]),
|
||||||
]))),
|
]))),
|
||||||
|
Phrase::new("4K", ppq * 4, Some(BTreeMap::from([
|
||||||
|
play!(0 => [
|
||||||
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
|
] ),
|
||||||
|
play!(4 => [
|
||||||
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(8 => [
|
||||||
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(12 => [
|
||||||
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
]))),
|
||||||
|
Phrase::new("KS", ppq * 4, Some(BTreeMap::from([
|
||||||
|
play!(0 => [
|
||||||
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
|
] ),
|
||||||
|
play!(4 => [
|
||||||
|
MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(10 => [
|
||||||
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(12 => [
|
||||||
|
MidiMessage::NoteOn { key: 40.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
]))),
|
||||||
]))?,
|
]))?,
|
||||||
|
|
||||||
Track::new("Helm", &timebase, Some(vec![
|
Track::new("Helm", &timebase, Some(vec![
|
||||||
Plugin::lv2("Helm", "file:///home/user/.lv2/Helm.lv2", &[1, 0, 0, 2])?.boxed(),
|
//Plugin::lv2("Helm", "file:///home/user/.lv2/Helm.lv2", &[1, 0, 0, 2])?.boxed(),
|
||||||
|
Plugin::lv2("Odin2", "file:///home/user/.lv2/Odin2.lv2", &[1, 0, 0, 2])?.boxed(),
|
||||||
]), Some(vec![
|
]), Some(vec![
|
||||||
Phrase::new("E G A Bb", ppq * 4, Some(BTreeMap::from([
|
Phrase::new("E G A Bb", ppq * 4, Some(BTreeMap::from([
|
||||||
( ppq / 2 + ppq * 0, vec![MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }] ),
|
play!(2 => [
|
||||||
( ppq / 2 + ppq * 1 / 2, vec![MidiMessage::NoteOff { key: 36.into(), vel: 100.into() }] ),
|
MidiMessage::NoteOff { key: 42.into(), vel: 100.into() },
|
||||||
( ppq / 2 + ppq * 1, vec![MidiMessage::NoteOn { key: 39.into(), vel: 100.into() }] ),
|
MidiMessage::NoteOn { key: 36.into(), vel: 100.into() },
|
||||||
( ppq / 2 + ppq * 3 / 2, vec![MidiMessage::NoteOff { key: 39.into(), vel: 100.into() }] ),
|
]),
|
||||||
( ppq / 2 + ppq * 2, vec![MidiMessage::NoteOn { key: 41.into(), vel: 100.into() }] ),
|
play!(6 => [
|
||||||
( ppq / 2 + ppq * 5 / 2, vec![MidiMessage::NoteOff { key: 41.into(), vel: 100.into() }] ),
|
MidiMessage::NoteOff { key: 36.into(), vel: 100.into() },
|
||||||
( ppq / 2 + ppq * 3, vec![MidiMessage::NoteOn { key: 42.into(), vel: 100.into() }] ),
|
MidiMessage::NoteOn { key: 39.into(), vel: 100.into() },
|
||||||
( ppq / 2 + ppq * 7 / 2 - 1, vec![MidiMessage::NoteOff { key: 42.into(), vel: 100.into() }] ),
|
]),
|
||||||
|
play!(10 => [
|
||||||
|
MidiMessage::NoteOff { key: 39.into(), vel: 100.into() },
|
||||||
|
MidiMessage::NoteOn { key: 41.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
|
play!(14 => [
|
||||||
|
MidiMessage::NoteOff { key: 41.into(), vel: 100.into() },
|
||||||
|
MidiMessage::NoteOn { key: 42.into(), vel: 100.into() },
|
||||||
|
]),
|
||||||
])))
|
])))
|
||||||
]))?,
|
]))?,
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue