Skip to content

Commit

Permalink
begin reorganizing code (#4)
Browse files Browse the repository at this point in the history
Begin separating code out into separate files and modules.
  • Loading branch information
webern authored Jan 19, 2021
1 parent 13caa3c commit feef83f
Show file tree
Hide file tree
Showing 19 changed files with 888 additions and 815 deletions.
2 changes: 1 addition & 1 deletion .run/test.run.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="test" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="channel" value="DEFAULT" />
<option name="command" value="test --package midi" />
<option name="command" value="test --package midi_file" />
<option name="allFeatures" value="false" />
<option name="emulateTerminal" value="false" />
<option name="backtrace" value="SHORT" />
Expand Down
21 changes: 6 additions & 15 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [v0.0.0] 2021-01-18
## Added
- Everything [#0]

### Changed
- Nothing [#00]

[#0]: https://github.com/webern/template/pull/0
[#00]: https://github.com/webern/template/pull/00
- Everything: you can create simple MIDI files with this library.

<!-- version diff links -->
[Unreleased]: https://github.com/webern/template/compare/v0.0.5...HEAD
[v0.0.5]: https://github.com/webern/template/compare/v0.0.4...v0.0.5
[v0.0.4]: https://github.com/webern/template/compare/v0.0.3...v0.0.4
[v0.0.3]: https://github.com/webern/template/compare/v0.0.2...v0.0.3
[v0.0.2]: https://github.com/webern/template/compare/v0.0.1...v0.0.2
[v0.0.1]: https://github.com/webern/template/compare/v0.0.0...v0.0.1
[v0.0.0]: https://github.com/webern/template/releases/tag/v0.0.0
[Unreleased]: https://github.com/webern/midi_file/compare/v0.0.2...HEAD
[v0.0.2]: https://github.com/webern/midi_file/compare/v0.0.1...v0.0.2
[v0.0.1]: https://github.com/webern/midi_file/compare/v0.0.0...v0.0.1
[v0.0.0]: https://github.com/webern/midi_file/releases/tag/v0.0.0
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 11 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
[package]
name = "midi"
name = "midi_file"
version = "0.0.0"
authors = ["Matthew James Briggs <[email protected]>"]
edition = "2018"
exclude = ["tests/", ".gitignore"]
exclude = [
".gitignore",
".run",
"examples/",
"tests/",
]
license = "MIT OR Apache-2.0"
readme = "README.md"
description = "For reading and writing MIDI files."
repository = "https://github.com/webern/midi_file"
keywords = ["MIDI"]
categories = ["encoding"]

[dependencies]
log = "0.4"
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,11 @@ but any file you create with the library will be technically valid per the spec.
You *do not* need to know what bytes equal what or what the bounds of an allowable value are.
This is all constrained with types.

[example]: https://github.com/webern/midi/blob/main/examples/main.rs
[example]: https://github.com/webern/midi/blob/main/examples/main.rs

### Random Links

Things I've been looking at from time-to-time:

- https://www.music.mcgill.ca/~gary/306/week9/smf.html
- https://github.com/Shkyrockett/midi-unit-test-cases
9 changes: 5 additions & 4 deletions examples/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use midi::channel::Channel;
use midi::message::{NoteNumber, Velocity};
use midi::{Clocks, DurationName, Format, GeneralMidi, MidiFile, QuartersPerMinute, Track};
use midi_file::channel::Channel;
use midi_file::core::{Clocks, DurationName, GeneralMidi};
use midi_file::message::{NoteNumber, Velocity};
use midi_file::{Division, Format, MidiFile, QuartersPerMinute, Track};

// durations
const QUARTER: u32 = 1024;
Expand All @@ -19,7 +20,7 @@ const V: Velocity = Velocity::new(64);
const CH: Channel = Channel::new(0);

fn main() {
let mut mfile = MidiFile::new(Format::Multi);
let mut mfile = MidiFile::new(Format::Multi, Division::default());

// set up track metadata
let mut track = Track::default();
Expand Down
7 changes: 3 additions & 4 deletions src/byte_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ use std::io::{BufReader, Bytes, ErrorKind, Read};
use std::path::{Path, PathBuf};
use std::str::{from_utf8, Utf8Error};

/// The internals are weird, it's basically a debugging thing to be able to see the next few falues
/// at a breakpoint. Practically speaking, there is somewhere where I want to 're-read' the
/// 'current' value, so at least the 'current' cached value is useful, but the various 'peeks'
/// turned out to be unused.
// TODO - make this less weird
/// The internals are weird, it's basically a debugging thing to be able to see the next few values
/// at a breakpoint.
pub(crate) struct ByteIter<R: Read> {
iter: Bytes<R>,
position: Option<u64>,
Expand Down
63 changes: 63 additions & 0 deletions src/core/clocks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/// There are 24 MIDI Clocks in every quarter note. (12 MIDI Clocks in an eighth note, 6 MIDI Clocks in a 16th, etc).
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub enum Clocks {
DottedWhole,
Whole,
DottedHalf,
Half,
DottedQuarter,
Quarter,
DottedEighth,
Eighth,
DottedSixteenth,
Sixteenth,
Other(u8),
}

impl Default for Clocks {
fn default() -> Self {
Clocks::Quarter
}
}

impl Clocks {
pub(crate) fn from_u8(v: u8) -> Clocks {
match v {
142 => Clocks::DottedWhole,
96 => Clocks::Whole,
72 => Clocks::DottedHalf,
48 => Clocks::Half,
32 => Clocks::DottedQuarter,
24 => Clocks::Quarter,
18 => Clocks::DottedEighth,
12 => Clocks::Eighth,
9 => Clocks::DottedSixteenth,
6 => Clocks::Sixteenth,
_ => Clocks::Other(v),
}
}

pub(crate) fn to_u8(&self) -> u8 {
match self {
Clocks::DottedWhole => 142,
Clocks::Whole => 96,
Clocks::DottedHalf => 72,
Clocks::Half => 48,
Clocks::DottedQuarter => 32,
Clocks::Quarter => 24,
Clocks::DottedEighth => 18,
Clocks::Eighth => 12,
Clocks::DottedSixteenth => 9,
Clocks::Sixteenth => 6,
Clocks::Other(v) => *v,
}
}

pub fn new(clocks: u8) -> Self {
Self::from_u8(clocks)
}

pub fn resolve(&mut self) {
*self = Self::from_u8(self.to_u8())
}
}
73 changes: 73 additions & 0 deletions src/core/duration_name.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use crate::error::LibResult;
use crate::Error;
use std::convert::TryFrom;

#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub enum DurationName {
/// Whole Note / Semibreve
Whole = 0,

/// Half Note / Minim
Half = 1,

/// Quarter Note / Crotchet
Quarter = 2,

/// Eighth Note / Quaver
Eighth = 3,

/// Sixteenth note / Semiquaver
Sixteenth = 4,

/// Thirty-Second Note / Demisemiquaver
D32 = 5,

/// Sixty-Fourth Note / Hemidemisemiquaver
D64 = 6,

/// One-Twenty-Eighth Note / Semihemidemisemiquaver
D128 = 7,

/// Two-Fifty-Sixth Note / Demisemihemidemisemiquaver
D256 = 8,

/// Five-Twelfth Note
D512 = 9,

/// One Thousand, Twenty-Fourth Note
D1024 = 10,
}

impl Default for DurationName {
fn default() -> Self {
DurationName::Quarter
}
}

impl DurationName {
pub(crate) fn from_u8(v: u8) -> LibResult<Self> {
match v {
v if DurationName::Whole as u8 == v => Ok(DurationName::Whole),
v if DurationName::Half as u8 == v => Ok(DurationName::Half),
v if DurationName::Quarter as u8 == v => Ok(DurationName::Quarter),
v if DurationName::Eighth as u8 == v => Ok(DurationName::Eighth),
v if DurationName::Sixteenth as u8 == v => Ok(DurationName::Sixteenth),
v if DurationName::D32 as u8 == v => Ok(DurationName::D32),
v if DurationName::D64 as u8 == v => Ok(DurationName::D64),
v if DurationName::D128 as u8 == v => Ok(DurationName::D128),
v if DurationName::D256 as u8 == v => Ok(DurationName::D256),
v if DurationName::D512 as u8 == v => Ok(DurationName::D512),
v if DurationName::D1024 as u8 == v => Ok(DurationName::D1024),
_ => crate::error::Other { site: site!() }.fail(),
}
}
}

impl TryFrom<u8> for DurationName {
type Error = Error;

fn try_from(value: u8) -> crate::Result<Self> {
Ok(Self::from_u8(value)?)
}
}
138 changes: 138 additions & 0 deletions src/core/general_midi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum GeneralMidi {
AcousticGrandPiano = 1,
BrightAcousticPiano = 2,
ElectricGrandPiano = 3,
HonkyTonkPiano = 4,
ElectricPiano1 = 5,
ElectricPiano2 = 6,
Harpsichord = 7,
Clavi = 8,
Celesta = 9,
Glockenspiel = 10,
MusicBox = 11,
Vibraphone = 12,
Marimba = 13,
Xylophone = 14,
TubularBells = 15,
Dulcimer = 16,
DrawbarOrgan = 17,
PercussiveOrgan = 18,
RockOrgan = 19,
ChurchOrgan = 20,
ReedOrgan = 21,
Accordion = 22,
Harmonica = 23,
TangoAccordion = 24,
AcousticGuitarNylon = 25,
AcousticGuitarSteel = 26,
ElectricGuitarJazz = 27,
ElectricGuitarClean = 28,
ElectricGuitarMuted = 29,
OverdrivenGuitar = 30,
DistortionGuitar = 31,
GuitarHarmonics = 32,
AcousticBass = 33,
ElectricBassFinger = 34,
ElectricBassPick = 35,
FretlessBass = 36,
SlapBass1 = 37,
SlapBass2 = 38,
SynthBass1 = 39,
SynthBass2 = 40,
Violin = 41,
Viola = 42,
Cello = 43,
Contrabass = 44,
TremoloStrings = 45,
PizzicatoStrings = 46,
OrchestralHarp = 47,
Timpani = 48,
StringEnsemble1 = 49,
StringEnsemble2 = 50,
SynthStrings1 = 51,
SynthStrings2 = 52,
ChoirAahs = 53,
VoiceOohs = 54,
SynthVoice = 55,
OrchestraHit = 56,
Trumpet = 57,
Trombone = 58,
Tuba = 59,
MutedTrumpet = 60,
FrenchHorn = 61,
BrassSection = 62,
SynthBrass1 = 63,
SynthBrass2 = 64,
SopranoSax = 65,
AltoSax = 66,
TenorSax = 67,
BaritoneSax = 68,
Oboe = 69,
EnglishHorn = 70,
Bassoon = 71,
Clarinet = 72,
Piccolo = 73,
Flute = 74,
Recorder = 75,
PanFlute = 76,
BlownBottle = 77,
Shakuhachi = 78,
Whistle = 79,
Ocarina = 80,
Lead1Square = 81,
Lead2Sawtooth = 82,
Lead3Calliope = 83,
Lead4Chiff = 84,
Lead5Charang = 85,
Lead6Voice = 86,
Lead7Fifths = 87,
Lead8BassPlusLead = 88,
Pad1Newage = 89,
Pad2Warm = 90,
Pad3Polysynth = 91,
Pad4Choir = 92,
Pad5Bowed = 93,
Pad6Metallic = 94,
Pad7Halo = 95,
Pad8Sweep = 96,
Fx1Rain = 97,
Fx2Soundtrack = 98,
Fx3Crystal = 99,
Fx4Atmosphere = 100,
Fx5Brightness = 101,
Fx6Goblins = 102,
Fx7Echoes = 103,
Fx8SciFi = 104,
Sitar = 105,
Banjo = 106,
Shamisen = 107,
Koto = 108,
Kalimba = 109,
Bagpipe = 110,
Fiddle = 111,
Shanai = 112,
TinkleBell = 113,
Agogo = 114,
SteelDrums = 115,
Woodblock = 116,
TaikoDrum = 117,
MelodicTom = 118,
SynthDrum = 119,
ReverseCymbal = 120,
GuitarFretNoise = 121,
BreathNoise = 122,
Seashore = 123,
BirdTweet = 124,
TelephoneRing = 125,
Helicopter = 126,
Applause = 127,
Gunshot = 128,
}

impl Into<u8> for GeneralMidi {
fn into(self) -> u8 {
self as u8
}
}
Loading

0 comments on commit feef83f

Please sign in to comment.