Skip to content

Commit

Permalink
percussion: improve docs and examples
Browse files Browse the repository at this point in the history
  • Loading branch information
tsionyx committed Sep 26, 2024
1 parent ee896ff commit fd5cfd1
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 56 deletions.
71 changes: 62 additions & 9 deletions examples/hsom-exercises/ch6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use num_rational::Ratio;

use musik::{
attributes::TrillOptions,
dur, m,
midi::{Instrument, PercussionSound},
music::{rests, Primitive},
Dur, InstrumentName, Interval, Music, Octave, Pitch, Temporal as _, Volume,
Expand Down Expand Up @@ -372,24 +373,76 @@ pub fn sequence_all_percussions() -> Music {
.with_instrument(InstrumentName::Percussion)
}

// TODO: Exercise 6.8

/// Exercise 6.8
///
/// TODO: test more at <https://en.wikipedia.org/wiki/Drum_beat>
/// <https://www.songsterr.com/a/wsa/nirvana-in-bloom-drum-tab-s295>
pub fn drum_pattern() -> Music {
let m1 = PercussionSound::ClosedHiHat.note(Dur::QUARTER).times(4);
let m2 = Music::rest(Dur::HALF) + PercussionSound::AcousticSnare.note(Dur::HALF);
use musik::midi::PercussionSound::*;

// AcousticSnare = D2
// ClosedHiHat = F#2
let m1 = m!(F # 2 / 4) * 4;
let m2 = m!(_ / 2) + m!(D 2 / 2);

let m3 = (PercussionSound::ClosedHiHat.note(Dur::EIGHTH) + Music::rest(Dur::EIGHTH)).times(4);
let m4 = Music::rest(Dur::HALF) + PercussionSound::AcousticSnare.note(Dur::QUARTER);
let m3 = (ClosedHiHat.note(Dur::EIGHTH) + m!(_ / 8)) * 4;
let m4 = m!(_ / 2) + AcousticSnare.note(Dur::QUARTER);

((m1 | m2) + (m3 | m4))
.with_instrument(InstrumentName::Percussion)
.with_tempo(Ratio::new(4, 3))
}

// The following are some of the drum patterns from the wiki article
// <https://en.wikipedia.org/wiki/Drum_beat>

pub fn straight_blues_drum() -> Music {
use musik::midi::PercussionSound::*;

let sub = OpenHiHat.note(dur!(1 / 8)) * 4;
let pulse = AcousticBassDrum.note(dur!(1 / 4)) + AcousticSnare.note(dur!(1 / 4));

((sub | pulse) * 4).with_instrument(InstrumentName::Percussion)
}

pub fn compound_triple_drum() -> Music {
use musik::midi::PercussionSound::*;

let sub = OpenHiHat.note(dur!(1 / 8)) * 9;
let pulse = AcousticBassDrum.note(dur!(3 / 8)) + (AcousticSnare.note(dur!(3 / 8)) * 2);

((sub | pulse) * 2).with_instrument(InstrumentName::Percussion)
}

pub fn fill_groove_drum() -> Music {
use musik::midi::PercussionSound::*;

let sub1 = OpenHiHat.note(dur!(1 / 8)) * 7;
let pulse1 = AcousticBassDrum.note(dur!(1 / 4))
+ AcousticSnare.note(dur!(1 / 4))
+ AcousticBassDrum.note(dur!(1 / 4))
+ (AcousticSnare.note(dur!(1 / 8)) + (AcousticSnare.note(dur!(1 / 16)) * 2));

let sub2 = OpenHiHat.note(dur!(1 / 8)) * 8;
let pulse2 = AcousticBassDrum.note(dur!(1 / 4))
+ AcousticSnare.note(dur!(1 / 4))
+ (AcousticBassDrum.note(dur!(1 / 8)) * 2)
+ AcousticSnare.note(dur!(1 / 4));

(((sub1 | pulse1) + (sub2 | pulse2)) * 2).with_instrument(InstrumentName::Percussion)
}

pub fn heavy_metal_gallop_drum() -> Music {
use musik::midi::PercussionSound::*;

let hi_hat = OpenHiHat.note(dur!(1 / 4)) * 2;
let snare = m!(_ / 4) + AcousticSnare.note(dur!(1 / 4));
let pulse =
(AcousticBassDrum.note(dur!(1 / 8)) + (AcousticBassDrum.note(dur!(1 / 16)) * 2)) * 2;

((hi_hat | snare | pulse) * 4).with_instrument(InstrumentName::Percussion)
}

// TODO: <https://www.songsterr.com/a/wsa/nirvana-in-bloom-drum-tab-s295>
// <https://en.wikipedia.org/wiki/Percussion_notation>

#[test]
fn test_drum_pattern() {
use musik::Performable as _;
Expand Down
8 changes: 8 additions & 0 deletions examples/hsom-exercises/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Chapter6::FunkGroove => ch6::funk_groove().into(),
Chapter6::Percussion => ch6::sequence_all_percussions().into(),
Chapter6::Drum => ch6::drum_pattern().into(),
Chapter6::DrumStraightBlues => ch6::straight_blues_drum().into(),
Chapter6::DrumCompoundTriple => ch6::compound_triple_drum().into(),
Chapter6::DrumFillGroove => ch6::fill_groove_drum().into(),
Chapter6::DrumHeavyMetalGallop => ch6::heavy_metal_gallop_drum().into(),
Chapter6::Volumed => ch6::test_volume(Volume::loudest()).into(),
Chapter6::InsideOut => ch6::inside_out::example().into(),
Chapter6::Recursion1 => ch6::crazy_recursion::example1().into(),
Expand Down Expand Up @@ -201,6 +205,10 @@ enum Chapter6 {
FunkGroove,
Percussion,
Drum,
DrumStraightBlues,
DrumCompoundTriple,
DrumFillGroove,
DrumHeavyMetalGallop,
Volumed,
InsideOut,
Recursion1,
Expand Down
100 changes: 53 additions & 47 deletions src/output/midi/instruments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,57 +149,63 @@ pub enum Instrument {
#[derive(Debug, PartialEq, Eq, Copy, Clone, Enum, Sequence)]
#[allow(missing_docs)]
pub enum PercussionSound {
AcousticBassDrum,
BassDrum1,
SideStick,
AcousticSnare,
HandClap,
ElectricSnare,
LowFloorTom,
ClosedHiHat,
HighFloorTom,
PedalHiHat,
LowTom,
OpenHiHat,
LowMidTom,
HiMidTom,
CrashCymbal1,
HighTom,
RideCymbal1,
ChineseCymbal,
RideBell,
Tambourine,
SplashCymbal,
Cowbell,
CrashCymbal2,
Vibraslap,
RideCymbal2,
HiBongo,
LowBongo,
MuteHiConga,
OpenHiConga,
LowConga,
HighTimbale,
LowTimbale,
HighAgogo,
LowAgogo,
Cabasa,
Maracas,
ShortWhistle,
LongWhistle,
ShortGuiro,
LongGuiro,
Claves,
HiWoodBlock,
LowWoodBlock,
MuteCuica,
OpenCuica,
MuteTriangle,
OpenTriangle,
// the following comments specify the location of the instrument
// on the musical score sheet (as if it were a treble clef)
// <https://en.wikipedia.org/wiki/Percussion_notation#Key_or_legend_for_drum_kit>
AcousticBassDrum, // F4
BassDrum1, // E4
SideStick, // C5 with diagonal slash through note head
AcousticSnare, // C5
HandClap, // -
ElectricSnare, // C5
LowFloorTom, // G4
ClosedHiHat, // G5 with X head
HighFloorTom, // A4
PedalHiHat, // D4 with X head
LowTom, // B4
OpenHiHat, // G5 with diamond notehead
LowMidTom, // D5
HiMidTom, // E5
CrashCymbal1, // A5 with X head
HighTom, // F5
RideCymbal1, // F5 with X head
ChineseCymbal, // A5 with diamond notehead
RideBell, // F5 with X head?
Tambourine, // B4 with triangle head
SplashCymbal, // A5 with diamond notehead
Cowbell, // E5 with triangle head
CrashCymbal2, // -
Vibraslap, // -
RideCymbal2, // -
HiBongo, // -
LowBongo, // -
MuteHiConga, // -
OpenHiConga, // -
LowConga, // -
HighTimbale, // -
LowTimbale, // -
HighAgogo, // -
LowAgogo, // -
Cabasa, // -
Maracas, // -
ShortWhistle, // -
LongWhistle, // -
ShortGuiro, // -
LongGuiro, // -
Claves, // -
HiWoodBlock, // D5 with triangle head
LowWoodBlock, // C5 with triangle head
MuteCuica, // -
OpenCuica, // -
MuteTriangle, // -
OpenTriangle, // A5 with triangle head
}

impl PercussionSound {
/// Produce a MIDI note for the [`PercussionSound`].
///
/// The corresponding MIDI notes are spanned
/// the same interval as MIDI 35..=81, i.e. B1..=A5 pitches.
pub fn note(self, dur: Dur) -> Music {
let midi_key = u7::try_from(self.into_usize())
.expect("<=46 fits into u7")
Expand Down

0 comments on commit fd5cfd1

Please sign in to comment.