Skip to content

Commit

Permalink
Add inversions to CLI, and fix inversions/slashes.
Browse files Browse the repository at this point in the history
  • Loading branch information
twitchax committed Dec 22, 2022
1 parent d796def commit 89fb3e7
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 9 deletions.
17 changes: 13 additions & 4 deletions src/bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,21 @@ enum Command {
#[arg(short, long, default_value_t = 4i8)]
octave: i8,

/// Sets the inversion of the chord
#[arg(short, long, default_value_t = 0u8)]
inversion: u8,

/// Sets the delay between notes (in seconds)
#[arg(short, long, default_value_t = 0.2f32)]
delay: f32,

/// Sets the duration of play (in seconds)
#[arg(short, long, default_value_t = 3.0f32)]
length: f32,

/// Fade in duration (in seconds)
#[arg(short, long, default_value_t = 0.1f32)]
fade_in: f32,
},
}

Expand All @@ -58,10 +66,10 @@ fn start(args: Args) -> Void {

describe(&chord);
}
Some(Command::Play { symbol, octave, delay, length }) => {
let chord = Chord::parse(&symbol)?.with_octave(Octave::Zero + octave);
Some(Command::Play { symbol, octave, inversion, delay, length, fade_in }) => {
let chord = Chord::parse(&symbol)?.with_octave(Octave::Zero + octave).with_inversion(inversion);

play(&chord, delay, length);
play(&chord, delay, length, fade_in);
}
None => {
println!("No command given.");
Expand All @@ -74,7 +82,7 @@ fn describe(chord: &Chord) {
println!("{}", chord);
}

fn play(chord: &Chord, delay: f32, length: f32) {
fn play(chord: &Chord, delay: f32, length: f32, fade_in: f32) {
describe(chord);

let (_stream, stream_handle) = OutputStream::try_default().unwrap();
Expand All @@ -87,6 +95,7 @@ fn play(chord: &Chord, delay: f32, length: f32) {
let source = SineWave::new(n.frequency())
.take_duration(Duration::from_secs_f32(length - k as f32 * delay))
.delay(Duration::from_secs_f32(k as f32 * delay))
.fade_in(Duration::from_secs_f32(fade_in))
.amplify(0.20);

sink.append(source);
Expand Down
17 changes: 14 additions & 3 deletions src/chord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{collections::HashSet, fmt::Display};

use pest::Parser;

use crate::{note::{Note, CZero}, modifier::{Modifier, Extension, Degree, HasIsDominant}, known_chord::{KnownChord, HasRelativeChord, HasRelativeScale}, interval::Interval, base::{HasDescription, HasName, HasStaticName, Res}, parser::{ChordParser, Rule, note_str_to_note}, octave::{Octave}, named_pitch::HasNamedPitch};
use crate::{note::{Note, CZero, NoteRecreator}, modifier::{Modifier, Extension, Degree, HasIsDominant}, known_chord::{KnownChord, HasRelativeChord, HasRelativeScale}, interval::Interval, base::{HasDescription, HasName, HasStaticName, Res}, parser::{ChordParser, Rule, note_str_to_note}, octave::{Octave, HasOctave}, named_pitch::HasNamedPitch};

// Traits.

Expand Down Expand Up @@ -767,7 +767,16 @@ impl HasChord for Chord {
}

// Add slash note.
if let Some(slash) = self.slash {
if let Some(mut slash) = self.slash {
// Fix slash note (it should be less than, or equal to, one octave away from the bottom tone).
let bottom = *result.first().unwrap_or(&CZero);
let floor = Note::new(bottom.named_pitch(), bottom.octave() - 1);

slash = slash.with_octave(Octave::Zero);
while slash < floor {
slash += Interval::PerfectOctave;
}

result.insert(0, slash);
}

Expand Down Expand Up @@ -1050,12 +1059,14 @@ mod tests {

// Slashes.

assert_eq!(Chord::new(C).with_slash(D).chord(), vec![D, C, E, G]);
assert_eq!(Chord::new(C).with_slash(D).chord(), vec![DThree, C, E, G]);
assert_eq!(Chord::new(CFive).with_slash(D).chord(), vec![DFour, CFive, EFive, GFive]);

// Inversions.

assert_eq!(C.into_chord().with_inversion(1).chord(), vec![E, G, CFive]);
assert_eq!(C.into_chord().with_inversion(2).chord(), vec![G, CFive, EFive]);
assert_eq!(C.into_chord().maj7().with_inversion(3).chord(), vec![B, CFive, EFive, GFive]);

}

Expand Down
28 changes: 26 additions & 2 deletions src/note.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![allow(dead_code)]
#![allow(non_upper_case_globals)]

use std::ops::{Add, AddAssign};
use std::{ops::{Add, AddAssign}, cmp::Ordering};

use paste::paste;
use crate::{named_pitch::{NamedPitch, HasNamedPitch}, interval::{Interval, HasEnharmonicDistance}, base::HasStaticName, chord::Chord, pitch::{HasFrequency, HasBaseFrequency, Pitch, HasPitch}, octave::{Octave, HasOctave}};
Expand Down Expand Up @@ -89,13 +89,21 @@ pub trait IntoChord {
fn into_chord(self) -> Chord;
}

/// A trait which allows for a [`Note`] to be recreated with different properties.
pub trait NoteRecreator {
/// Recreates this [`Note`] with the given [`NamedPitch`].
fn with_named_pitch(self, named_pitch: NamedPitch) -> Self;
/// Recreates this [`Note`] with the given [`Octave`].
fn with_octave(self, octave: Octave) -> Self;
}

// Struct.

/// A note type.
///
/// This is a named pitch with an octave. This type allows for correctly attributing octave changes
/// across an interval from one [`Note`] to another.
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug, PartialOrd, Ord)]
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
pub struct Note {
/// The octave of the note.
octave: Octave,
Expand Down Expand Up @@ -161,6 +169,16 @@ impl IntoChord for Note {
}
}

impl NoteRecreator for Note {
fn with_named_pitch(self, named_pitch: NamedPitch) -> Self {
Self::new(named_pitch, self.octave)
}

fn with_octave(self, octave: Octave) -> Self {
Self::new(self.named_pitch, octave)
}
}

impl Add<Interval> for Note {
type Output = Self;

Expand Down Expand Up @@ -199,6 +217,12 @@ impl AddAssign<Interval> for Note {
}
}

impl PartialOrd for Note {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.octave.cmp(&other.octave).then(self.pitch().cmp(&other.pitch())))
}
}

// Define octaves.

define_octave!(Zero, Octave::Zero);
Expand Down

0 comments on commit 89fb3e7

Please sign in to comment.