Fifths
This plugin demonstrates simple MIDI event reading and writing.
For every note-on and note-off event it reads, it writes the original note and it’s fifth. Therefore, you can play a power-chords by pressing only one key!
fifths/eg-fifths-rs.lv2/manifest.ttl
You should be familiar with these Turtle files by know!
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
<https://github.com/RustAudio/rust-lv2/tree/master/docs/fifths>
a lv2:Plugin ;
lv2:binary <libfifths.so> ;
rdfs:seeAlso <fifths.ttl> .
fifths/eg-fifths-rs.lv2/fifths.ttl
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
<https://github.com/RustAudio/rust-lv2/tree/master/docs/fifths>
a lv2:Plugin ;
doap:name "Example Fifths (Rust Edition)" ;
doap:license <http://opensource.org/licenses/isc> ;
lv2:project <https://github.com/RustAudio/rust-lv2> ;
lv2:requiredFeature urid:map , lv2:inPlaceBroken ;
lv2:optionalFeature lv2:hardRTCapable ;
lv2:port [
a lv2:InputPort ,
atom:AtomPort ;
atom:bufferType atom:Sequence ;
atom:supports midi:MidiEvent ;
lv2:index 0 ;
lv2:symbol "in" ;
lv2:name "In"
] , [
a lv2:OutputPort ,
atom:AtomPort ;
atom:bufferType atom:Sequence ;
atom:supports midi:MidiEvent ;
lv2:index 1 ;
lv2:symbol "out" ;
lv2:name "Out"
] .
fifths/Cargo.toml
[package]
name = "fifths"
version = "0.1.0"
authors = ["Jan-Oliver 'Janonard' Opdenhövel <jan.opdenhoevel@protonmail.com>"]
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
wmidi = "3.1.0"
lv2 = "0.6.0"
fifths/src/lib.rs
The same as before…
use lv2::prelude::*;
use wmidi::*;
#[derive(PortCollection)]
pub struct Ports {
input: InputPort<AtomPort>,
output: OutputPort<AtomPort>,
}
#[derive(FeatureCollection)]
pub struct Features<'a> {
map: LV2Map<'a>,
}
#[derive(URIDCollection)]
pub struct URIDs {
atom: AtomURIDCollection,
midi: MidiURIDCollection,
unit: UnitURIDCollection,
}
#[uri("https://github.com/RustAudio/rust-lv2/tree/master/docs/fifths")]
pub struct Fifths {
urids: URIDs,
}
impl Plugin for Fifths {
type Ports = Ports;
type InitFeatures = Features<'static>;
type AudioFeatures = ();
fn new(_plugin_info: &PluginInfo, features: &mut Features<'static>) -> Option<Self> {
Some(Self {
urids: features.map.populate_collection()?,
})
}
This plugin works similar to the previous one: It iterates over the events in the input port. However, it only needs to write one or two messages instead of blocks of audio.
fn run(&mut self, ports: &mut Ports, _: &mut (), _: u32) {
Get the reading handle of the input sequence.
let input_sequence = ports
.input
.read(self.urids.atom.sequence, self.urids.unit.beat)
.unwrap();
Initialise the output sequence and get the writing handle.
let mut output_sequence = ports
.output
.init(
self.urids.atom.sequence,
TimeStampURID::Frames(self.urids.unit.frame),
)
.unwrap();
for (timestamp, atom) in input_sequence {
Every message is forwarded, regardless of it’s content.
output_sequence.forward(timestamp, atom);
Retrieve the message.
let message = if let Some(message) = atom.read(self.urids.midi.wmidi, ()) {
message
} else {
continue;
};
match message {
MidiMessage::NoteOn(channel, note, velocity) => {
Create a note 5th (7 semitones) higher than the input.
if let Ok(note) = note.step(7) {
Write the fifth. Writing is done after initialization.
output_sequence
.init(
timestamp,
self.urids.midi.wmidi,
MidiMessage::NoteOn(channel, note, velocity),
)
.unwrap();
}
}
MidiMessage::NoteOff(channel, note, velocity) => {
Do the same thing for NoteOff
.
if let Ok(note) = note.step(7) {
output_sequence
.init(
timestamp,
self.urids.midi.wmidi,
MidiMessage::NoteOff(channel, note, velocity),
)
.unwrap();
}
}
_ => (),
}
}
}
}
lv2_descriptors!(Fifths);