Skip to content

Commit

Permalink
implement pitch bend messages
Browse files Browse the repository at this point in the history
  • Loading branch information
webern committed Sep 8, 2023
1 parent f537434 commit 79a7e9b
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 5 deletions.
31 changes: 28 additions & 3 deletions src/core/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ use crate::core::{
};
use crate::error::{self, LibResult};
use crate::scribe::Scribe;
use log::trace;
use log::warn;
use log::{trace, warn};
use snafu::{OptionExt, ResultExt};
use std::convert::TryFrom;
use std::io::{Read, Write};
Expand Down Expand Up @@ -118,9 +117,19 @@ impl WriteBytes for PitchBendMessage {
write_status_byte(w, StatusType::PitchBend, self.channel)?;
let lsb = (self.pitch_bend.get() & 0x74) as u8;
let msb = ((self.pitch_bend.get() >> 7) & 0x74) as u8;
println!("WRITING LSB MSB: {} {}", lsb, msb);
write_u8!(w, lsb)?;
write_u8!(w, msb)?;
Ok(())
// write_status_byte(w, StatusType::PitchBend, self.channel)?;
// println!("pitch bend value: {}", self.pitch_bend.get());
// let msb = (self.pitch_bend.get() >> 8) as u8;
// let lsb = (self.pitch_bend.get() & 0b0000_0000_1111_1111) as u8;
// println!("pitch bend msb: {}", msb);
// println!("pitch bend lsb: {}", lsb);
// write_u8!(w, msb)?;
// write_u8!(w, lsb)?;
// Ok(())
}
}

Expand Down Expand Up @@ -334,7 +343,23 @@ impl Message {
noimpl!("channel pressure: https://github.com/webern/midi_file/issues/X")
}
StatusType::PitchBend => {
noimpl!("pitch bend: https://github.com/webern/midi_file/issues/10")
let lsb = iter.read_or_die().context(io!())?;
let msb = iter.read_or_die().context(io!())?;
println!("pitch bend read msb lsb {} {}", msb, lsb);
let high_bits = (msb as u16) << 7;
let low_bits = (lsb as u16) & 0b0000_0000_0111_111;
println!(
"pitch bend read high_bits low_bits {} {}",
high_bits, low_bits
);
let value = high_bits | low_bits;
println!("______________________PITCH BEND READ: {}", value);

// let value = println!("value {}", value);
Ok(Message::PitchBend(PitchBendMessage {
channel,
pitch_bend: PitchBendValue::new(value),
}))
}
StatusType::System => noimpl!("system: https://github.com/webern/midi_file/issues/10"),
}
Expand Down
3 changes: 3 additions & 0 deletions tests/data/pitch_bend.info
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Something I exported from Logic so that I know the exact pitch bend values. It has the following
pitch bend values on each beat 0, 20, 40, 127 , 125, 101, 40, 20.
Creative commons, Public domain, etc.
Binary file added tests/data/pitch_bend.mid
Binary file not shown.
3 changes: 3 additions & 0 deletions tests/data/pitch_bend_two_bytes.info
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Created with this amazing tool https://signal.vercel.app/edit
Pitch bend values are 8192, 8292, 8092, 16383, 16384, 0, 1, 8192.
Creative commons, Public domain, etc.
Binary file added tests/data/pitch_bend_two_bytes.mid
Binary file not shown.
86 changes: 86 additions & 0 deletions tests/integ.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
mod utils;

use crate::utils::{PITCH_BEND, PITCH_BEND_TWO_BYTES};
use midi_file::core::{Clocks, Control, DurationName, Message};
use midi_file::file::{Division, Event, Format, MetaEvent, QuarterNoteDivision};
use midi_file::MidiFile;
use std::fs::File;
use std::io::Read;
use tempfile::tempdir;
use utils::{enable_logging, test_file, AVE_MARIS_STELLA};

#[test]
Expand Down Expand Up @@ -176,3 +178,87 @@ fn ave_maris_stella_finale_export() {
assert_eq!(original, written);
}
}

#[test]
fn pitch_bend() {
enable_logging();
let midi_file = MidiFile::load(test_file(PITCH_BEND)).unwrap();
let track = midi_file.tracks().next().unwrap();

fn assert_pitch_bend(event: &Event, expected: u16) {
let message = match event {
Event::Midi(message) => message,
_ => panic!("wrong event type {:?}", event),
};
let pitch_bend_message = match message {
Message::PitchBend(p) => p,
_ => panic!("wrong message type {:?}", message),
};
assert_eq!(pitch_bend_message.pitch_bend().get(), expected);
}

// assert_pitch_bend(track.events().skip(8).next().unwrap().event(), 0);
// assert_pitch_bend(track.events().skip(9).next().unwrap().event(), 20);
// assert_pitch_bend(track.events().skip(10).next().unwrap().event(), 40);
// assert_pitch_bend(track.events().skip(11).next().unwrap().event(), 127);
// assert_pitch_bend(track.events().skip(12).next().unwrap().event(), 125);
// assert_pitch_bend(track.events().skip(13).next().unwrap().event(), 101);
// assert_pitch_bend(track.events().skip(14).next().unwrap().event(), 40);
// assert_pitch_bend(track.events().skip(15).next().unwrap().event(), 20);

let tempdir = tempdir().unwrap();
let path = tempdir.path().join("file.mid");
midi_file.save(&path).unwrap();
// let midi_file = MidiFile::load(&path).unwrap();
// let track = midi_file.tracks().next().unwrap();
// assert_pitch_bend(track.events().skip(8).next().unwrap().event(), 0);
// assert_pitch_bend(track.events().skip(9).next().unwrap().event(), 20);
// assert_pitch_bend(track.events().skip(10).next().unwrap().event(), 40);
// assert_pitch_bend(track.events().skip(11).next().unwrap().event(), 127);
// assert_pitch_bend(track.events().skip(12).next().unwrap().event(), 125);
// assert_pitch_bend(track.events().skip(13).next().unwrap().event(), 101);
// assert_pitch_bend(track.events().skip(14).next().unwrap().event(), 40);
// assert_pitch_bend(track.events().skip(15).next().unwrap().event(), 20);
}

#[test]
fn pitch_bend_two_byte() {
enable_logging();
let midi_file = MidiFile::load(test_file(PITCH_BEND_TWO_BYTES)).unwrap();
let track = midi_file.tracks().next().unwrap();

fn assert_pitch_bend(event: &Event, expected: u16) {
let message = match event {
Event::Midi(message) => message,
_ => panic!("wrong event type {:?}", event),
};
let pitch_bend_message = match message {
Message::PitchBend(p) => p,
_ => panic!("wrong message type {:?}", message),
};
assert_eq!(pitch_bend_message.pitch_bend().get(), expected);
}

// assert_pitch_bend(track.events().skip(8).next().unwrap().event(), 0);
// assert_pitch_bend(track.events().skip(9).next().unwrap().event(), 20);
// assert_pitch_bend(track.events().skip(10).next().unwrap().event(), 40);
// assert_pitch_bend(track.events().skip(11).next().unwrap().event(), 127);
// assert_pitch_bend(track.events().skip(12).next().unwrap().event(), 125);
// assert_pitch_bend(track.events().skip(13).next().unwrap().event(), 101);
// assert_pitch_bend(track.events().skip(14).next().unwrap().event(), 40);
// assert_pitch_bend(track.events().skip(15).next().unwrap().event(), 20);
//
// let tempdir = tempdir().unwrap();
// let path = tempdir.path().join("file.mid");
// midi_file.save(&path).unwrap();
// let midi_file = MidiFile::load(&path).unwrap();
// let track = midi_file.tracks().next().unwrap();
// assert_pitch_bend(track.events().skip(8).next().unwrap().event(), 0);
// assert_pitch_bend(track.events().skip(9).next().unwrap().event(), 20);
// assert_pitch_bend(track.events().skip(10).next().unwrap().event(), 40);
// assert_pitch_bend(track.events().skip(11).next().unwrap().event(), 127);
// assert_pitch_bend(track.events().skip(12).next().unwrap().event(), 125);
// assert_pitch_bend(track.events().skip(13).next().unwrap().event(), 101);
// assert_pitch_bend(track.events().skip(14).next().unwrap().event(), 40);
// assert_pitch_bend(track.events().skip(15).next().unwrap().event(), 20);
}
8 changes: 6 additions & 2 deletions tests/roundtrip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ use std::path::{Path, PathBuf};
use tempfile::TempDir;
use utils::{
enable_logging, test_file, ADESTE_FIDELES, ALS_DIE_ROEMER, AVE_MARIS_STELLA, BARITONE_SAX,
B_GUAJEO, LATER_FOLIA, LOGIC_PRO, PHOBOS_DORICO, TOBEFREE,
B_GUAJEO, LATER_FOLIA, LOGIC_PRO, PHOBOS_DORICO, PITCH_BEND, TOBEFREE,
};

type RtResult = std::result::Result<(), RtErr>;

enum RtErr {
Expand Down Expand Up @@ -241,6 +240,11 @@ fn phobos_dorico() {
round_trip_test(PHOBOS_DORICO).unwrap();
}

#[test]
fn pitch_bend() {
round_trip_test(PITCH_BEND).unwrap();
}

#[test]
fn tobeefree() {
round_trip_test(TOBEFREE).unwrap();
Expand Down
2 changes: 2 additions & 0 deletions tests/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ pub const B_GUAJEO: &str = "b_guajeo.mid";
pub const LATER_FOLIA: &str = "later_folia.mid";
pub const LOGIC_PRO: &str = "logic_pro.mid";
pub const PHOBOS_DORICO: &str = "phobos_dorico.mid";
pub const PITCH_BEND: &str = "pitch_bend.mid";
pub const PITCH_BEND_TWO_BYTES: &str = "pitch_bend_two_bytes.mid";
pub const TOBEFREE: &str = "tobefree.mid";

static LOGGER: Once = Once::new();
Expand Down

0 comments on commit 79a7e9b

Please sign in to comment.