mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
bye sequencer
This commit is contained in:
parent
2165e5d45d
commit
316fe45b2a
12 changed files with 510 additions and 759 deletions
|
|
@ -1,141 +0,0 @@
|
|||
use crate::core::*;
|
||||
use crate::model::*;
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SequencerMode { Tiny, Compact, Horizontal, Vertical, }
|
||||
pub struct Sequencer {
|
||||
pub name: String,
|
||||
/// JACK transport handle.
|
||||
pub transport: ::jack::Transport,
|
||||
/// JACK MIDI input port that will be created.
|
||||
pub midi_in: Port<MidiIn>,
|
||||
/// JACK MIDI output port that will be created.
|
||||
pub midi_out: Port<MidiOut>,
|
||||
/// Holds info about tempo
|
||||
pub timebase: Arc<Timebase>,
|
||||
/// Phrase selector
|
||||
pub sequence: Option<usize>,
|
||||
/// Map: tick -> MIDI events at tick
|
||||
pub phrases: Vec<Phrase>,
|
||||
/// Red keys on piano roll.
|
||||
pub notes_on: Vec<bool>,
|
||||
/// Play sequence to output.
|
||||
pub playing: TransportState,
|
||||
/// Play input through output.
|
||||
pub monitoring: bool,
|
||||
/// Write input to sequence.
|
||||
pub recording: bool,
|
||||
/// Don't delete when recording.
|
||||
pub overdub: bool,
|
||||
/// Display mode
|
||||
pub view: SequencerMode,
|
||||
/// Range of notes to display
|
||||
pub note_start: usize,
|
||||
/// Position of cursor within note range
|
||||
pub note_cursor: usize,
|
||||
/// PPM per display unit
|
||||
pub time_zoom: usize,
|
||||
/// Range of time steps to display
|
||||
pub time_start: usize,
|
||||
/// Position of cursor within time range
|
||||
pub time_cursor: usize,
|
||||
}
|
||||
render!(Sequencer = crate::view::sequencer::render);
|
||||
handle!(Sequencer = crate::control::sequencer::handle);
|
||||
process!(Sequencer |self, _client, scope| {
|
||||
if self.sequence.is_none() { return Control::Continue }
|
||||
let phrase = self.phrases.get_mut(self.sequence.unwrap());
|
||||
if phrase.is_none() { return Control::Continue }
|
||||
let phrase = phrase.unwrap();
|
||||
let frame = scope.last_frame_time() as usize;
|
||||
let frames = scope.n_frames() as usize;
|
||||
let mut output: Vec<Option<Vec<Vec<u8>>>> = vec![None;frames];
|
||||
let transport = self.transport.query().unwrap();
|
||||
if transport.state != self.playing {
|
||||
all_notes_off(&mut output);
|
||||
}
|
||||
self.playing = transport.state;
|
||||
// Play from phrase into output buffer
|
||||
if self.playing == TransportState::Rolling {
|
||||
phrase.process_out(
|
||||
&mut output,
|
||||
&mut self.notes_on,
|
||||
&self.timebase,
|
||||
frame,
|
||||
frames
|
||||
);
|
||||
}
|
||||
// Play from input to monitor, and record into phrase.
|
||||
phrase.process_in(
|
||||
self.midi_in.iter(scope),
|
||||
&mut self.notes_on,
|
||||
if self.monitoring { Some(&mut output) } else { None },
|
||||
self.recording && self.playing == TransportState::Rolling,
|
||||
&self.timebase,
|
||||
frame,
|
||||
);
|
||||
write_output(&mut self.midi_out.writer(scope), &mut output, frames);
|
||||
Control::Continue
|
||||
});
|
||||
impl Sequencer {
|
||||
pub fn new (
|
||||
name: &str,
|
||||
timebase: &Arc<Timebase>,
|
||||
phrases: Option<Vec<Phrase>>,
|
||||
) -> Usually<Self> {
|
||||
let (client, _status) = Client::new(name, ClientOptions::NO_START_SERVER)?;
|
||||
let transport = client.transport();
|
||||
Ok(Self {
|
||||
name: name.into(),
|
||||
timebase: timebase.clone(),
|
||||
phrases: phrases.unwrap_or_else(||vec![Phrase::default()]),
|
||||
sequence: Some(0),
|
||||
|
||||
transport,
|
||||
midi_in: client.register_port("in", MidiIn::default())?,
|
||||
monitoring: true,
|
||||
recording: true,
|
||||
midi_out: client.register_port("out", MidiOut::default())?,
|
||||
playing: TransportState::Starting,
|
||||
overdub: true,
|
||||
|
||||
view: SequencerMode::Horizontal,
|
||||
notes_on: vec![false;128],
|
||||
note_start: 12,
|
||||
note_cursor: 0,
|
||||
time_zoom: 24,
|
||||
time_start: 0,
|
||||
time_cursor: 0,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn phrase <'a> (&'a self) -> Option<&'a Phrase> {
|
||||
self.phrases.get(self.sequence?)
|
||||
}
|
||||
}
|
||||
impl PortList for Sequencer {
|
||||
fn midi_ins (&self) -> Usually<Vec<String>> { Ok(vec![self.midi_in.name()?]) }
|
||||
fn midi_outs (&self) -> Usually<Vec<String>> { Ok(vec![self.midi_out.name()?]) }
|
||||
}
|
||||
/// Add "all notes off" to the start of a buffer.
|
||||
pub fn all_notes_off (output: &mut MIDIChunk) {
|
||||
output[0] = Some(vec![]);
|
||||
if let Some(Some(frame)) = output.get_mut(0) {
|
||||
let mut buf = vec![];
|
||||
let msg = MidiMessage::Controller { controller: 123.into(), value: 0.into() };
|
||||
let evt = LiveEvent::Midi { channel: 0.into(), message: msg };
|
||||
evt.write(&mut buf).unwrap();
|
||||
frame.push(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/// Write to JACK port from output buffer (containing notes from sequence and/or monitor)
|
||||
fn write_output (writer: &mut ::jack::MidiWriter, output: &mut MIDIChunk, frames: usize) {
|
||||
for time in 0..frames {
|
||||
if let Some(Some(frame)) = output.get_mut(time ) {
|
||||
for event in frame.iter() {
|
||||
writer.write(&::jack::RawMidi { time: time as u32, bytes: &event })
|
||||
.expect(&format!("{event:?}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,50 +2,48 @@ use crate::core::*;
|
|||
use crate::model::*;
|
||||
|
||||
pub struct Track {
|
||||
pub name: String,
|
||||
pub sequencer: Sequencer,
|
||||
pub chain: Chain,
|
||||
pub midi_out: Port<MidiOut>,
|
||||
pub name: String,
|
||||
/// Play input through output.
|
||||
pub monitoring: bool,
|
||||
/// Write input to sequence.
|
||||
pub recording: bool,
|
||||
/// Overdub input to sequence.
|
||||
pub overdub: bool,
|
||||
/// Map: tick -> MIDI events at tick
|
||||
pub phrases: Vec<Phrase>,
|
||||
/// Phrase selector
|
||||
pub sequence: Option<usize>,
|
||||
/// Output from current sequence.
|
||||
pub midi_out: Port<MidiOut>,
|
||||
/// Red keys on piano roll.
|
||||
pub notes_on: Vec<bool>,
|
||||
/// Device chain
|
||||
pub chain: Chain,
|
||||
}
|
||||
|
||||
impl Track {
|
||||
pub fn new (
|
||||
name: &str,
|
||||
jack: &Client,
|
||||
timebase: &Arc<Timebase>,
|
||||
devices: Option<Vec<Box<dyn Device>>>,
|
||||
phrases: Option<Vec<Phrase>>,
|
||||
name: &str,
|
||||
jack: &Client,
|
||||
devices: Option<Vec<Box<dyn Device>>>,
|
||||
phrases: Option<Vec<Phrase>>,
|
||||
) -> Usually<Self> {
|
||||
let sequencer = Sequencer::new(&name, timebase, phrases)?;
|
||||
let chain = Chain::new(&name, devices)?;
|
||||
let midi_out = jack.register_port(name, MidiOut)?;
|
||||
//let (client, _status) = Client::new("init", ClientOptions::NO_START_SERVER)?;
|
||||
//{
|
||||
//if let (Some(output), Some(input)) = (
|
||||
//sequencer.midi_outs()?.get(0).clone(),
|
||||
//if let Some(item) = chain.items.get(0) {
|
||||
//if let Some(port) = item.midi_ins()?.get(0) {
|
||||
//Some(port.clone())
|
||||
//} else {
|
||||
//None
|
||||
//}
|
||||
//} else {
|
||||
//None
|
||||
//}
|
||||
//) {
|
||||
//client.connect_ports_by_name(&output, &input)?;
|
||||
//}
|
||||
//}
|
||||
Ok(Self { name: name.to_string(), sequencer, chain, midi_out })
|
||||
Ok(Self {
|
||||
name: name.to_string(),
|
||||
chain: Chain::new(&name, devices)?,
|
||||
midi_out: jack.register_port(name, MidiOut)?,
|
||||
notes_on: vec![],
|
||||
monitoring: false,
|
||||
recording: false,
|
||||
overdub: true,
|
||||
sequence: None,
|
||||
phrases: phrases.unwrap_or_else(||vec![])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PortList for Track {
|
||||
fn midi_ins (&self) -> Usually<Vec<String>> {
|
||||
self.sequencer.midi_ins()
|
||||
}
|
||||
fn audio_outs (&self) -> Usually<Vec<String>> {
|
||||
self.chain.audio_outs()
|
||||
}
|
||||
fn midi_ins (&self) -> Usually<Vec<String>> { Ok(vec![]) }
|
||||
fn midi_outs (&self) -> Usually<Vec<String>> { Ok(vec![self.midi_out.name()?]) }
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue