A drum machine written in Rust

Overview

rudiments

Crates.io Crates.io License License

rudiments is a step-sequencing drum machine that plays rhythm patterns using audio samples.

muppets animal, personal use license

Features

  • 16-step programmable measures.
  • Configurable per-track amplitude.
  • Adjustable tempo.
  • Playback once or on repeat.
  • Supports several audio file formats:
    • MP3
    • WAV
    • Vorbis
    • Flac

Playback and audio file decoding are handled by rodio.

Usage

rudiments 0.1.1
A step-sequencing drum machine

USAGE:
    rudiments [FLAGS] [OPTIONS] --pattern <FILE> --instrumentation <FILE> --samples <DIRECTORY>

FLAGS:
    -h, --help       Prints help information
    -r, --repeat     Repeat the pattern until stopped
    -V, --version    Prints version information

OPTIONS:
    -i, --instrumentation <FILE>    Path to instrumentation file
    -p, --pattern <FILE>            Path to pattern file
    -s, --samples <DIRECTORY>       Search path for sample files
    -t, --tempo <NUMBER>            Playback tempo [default: 120]

Inputs

rudiments loads a pattern file and binds the pattern's tracks to audio files in a samples directory per an instrumentation file.

Pattern file (--pattern)

Each line of a pattern file represents a track. There is no limit to the number of tracks in a pattern. A track contains an instrument name, a 16-step sequence, and an optional amplitude. The instrument name is an identifier and can only appear once per pattern. Each sequence represents a single measure in 4/4 time divided into 16th note steps (x for play and - for silent). A track may optionally include an amplitude in the range of [0,1] inclusive. By default, a track plays at full volume.

This is an example of a pattern file's contents for a standard 8th note groove with the hi-hat track played at half volume.

hi-hat |x-x-|x-x-|x-x-|x-x-| 0.5
snare  |----|x---|----|x---|
kick   |x---|----|x---|----|

Instrumentation file (--instrumentation)

An instrumentation file binds the instruments from a pattern file to audio sample files. Each line of an instrumentation file contains an instrument name and an audio file name. Each instrument may only appear once, but a single audio file may be bound to multiple instruments.

This is an example of an instrumentation file's contents that binds five instruments to four audio sample files.

Note that tom.wav is used for both tom-1 and tom-2.

hi-hat hh.wav
tom-1  tom.wav
tom-2  tom.wav
snare  snare.wav
kick   kick.wav

Samples directory (--samples)

rudiments will look in the samples directory for the audio files listed in the instrumentation file.

Tempo (--tempo)

This adjusts the playback tempo (aka beats per minute). The default playback tempo is 120.

Installation

rudiments can be installed with cargo.

$ cargo install rudiments

Upcoming features

  • Swing
  • Reverb
  • Record to output audio file
  • Pattern composition
  • Prevent clipping
  • Trigger inputs
  • Different time signatures
  • Terminal-based UI
    • Playback tracking
    • Live pattern editing

Missing a fun or useful feature? Feel free to submit feature requests and PRs!

Demos 🥁

The assets directory contains several example patterns as well as audio samples from the LinnDrum drum machine.

Standard 8th note groove

$ rudiments \
    --pattern ./assets/patterns/standard \
    --instrumentation ./assets/instrumentations/linndrum \
    --samples ./assets/samples/linndrum \
    --repeat

Burning Up (Madonna)

$ rudiments \
    --pattern ./assets/patterns/burning-up \
    --instrumentation ./assets/instrumentations/linndrum \
    --samples ./assets/samples/linndrum \
    --tempo 140 \
    --repeat

Thriller (Michael Jackson)

$ rudiments \
    --pattern ./assets/patterns/thriller \
    --instrumentation ./assets/instrumentations/linndrum \
    --samples ./assets/samples/linndrum \
    --tempo 118 \
    --repeat

Get a Little (Patrick Cowley)

$ rudiments \
    --pattern ./assets/patterns/get-a-little \
    --instrumentation ./assets/instrumentations/linndrum \
    --samples ./assets/samples/linndrum \
    --repeat

I Wanna Dance With Somebody (Whitney Houston)

$ rudiments \
    --pattern ./assets/patterns/i-wanna-dance-with-somebody \
    --instrumentation ./assets/instrumentations/linndrum \
    --samples ./assets/samples/linndrum \
    --tempo 118 \
    --repeat

Tom Sawyer (Rush)

$ rudiments \
    --pattern ./assets/patterns/tom-sawyer \
    --instrumentation ./assets/instrumentations/linndrum \
    --samples ./assets/samples/linndrum \
    --tempo 180

Never Gonna Give You Up (Rick Astley)

$ rudiments \
    --pattern ./assets/patterns/never-gonna-give-you-up \
    --instrumentation ./assets/instrumentations/linndrum \
    --samples ./assets/samples/linndrum
Comments
  • Installation error:  unresolved import `clap::Clap`

    Installation error: unresolved import `clap::Clap`

    Hey!

    When trying to install via cargo install rudiments, I am getting the following error:

       Compiling coreaudio-sys v0.2.8
       Compiling coreaudio-rs v0.9.1
       Compiling rodio v0.11.0
       Compiling rudiments v0.1.0
    error[E0432]: unresolved import `clap::Clap`
       --> /Users/bolandross/.cargo/registry/src/github.com-1ecc6299db9ec823/rudiments-0.1.0/src/main.rs:158:5
        |
    158 | use clap::Clap;
        |     ^^^^^^^^^^ no `Clap` in the root
    

    rustup --version gives me

    rustup 1.24.3 (ce5817a94 2021-05-31)
    info: This is the version for the rustup toolchain manager, not the rustc compiler.
    info: The currently active `rustc` version is `rustc 1.56.1 (59eed8a2a 2021-11-01)`
    
    opened by bolandross 1
  • File not found errors for instrumentation and pattern

    File not found errors for instrumentation and pattern

    When trying out the examples, I noticed that when the instrumentation or pattern file is misspelled, the error message was not very useful. In the parse methods, the file is attempted to be opened with File::open(p)?;, but that error doesn't print out the path that wasn't found.

    I'm new to rust, but my suggestion would be to add if !p.is_file() { return Err(FileDoesNotExistError(p.into())); } before the call to File::open(p)?, which let's us use the FileDoesNotExists error that's already defined in error.rs.

    cargo run -- --pattern ./assets/patterns/standard --instrumentation ./assets/instrumentations/lindrum --samples ./assets/samples/linndrum --tempo 140 --repeat

    Error: IOError(Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }) error: process didn't exit successfully: target\debug\rudiments.exe --pattern ./assets/patterns/standard --instrumentation ./assets/instrumentations/lindrum --samples ./assets/samples/linndrum --tempo 140 --repeat (exit code: 1)

    Using custom Error enum as suggested, output becomes:

    Error: FileDoesNotExistError("./assets/instrumentations/lindrum") error: process didn't exit successfully: target\debug\rudiments.exe --pattern ./assets/patterns/standard --instrumentation ./assets/instrumentations/lindrum --samples ./assets/samples/linndrum --tempo 140 --repeat (exit code: 1)

    opened by eliasreid 1
  • install fails on raspberrypi

    install fails on raspberrypi

    Just tried to install on raspberrypi and got the following error:

    $ cargo install rudiments
        Updating crates.io index
      Downloaded rudiments v0.1.1
      Downloaded 1 crate (855.8 KB) in 1.84s
      Installing rudiments v0.1.1
      Downloaded funty v1.1.0
      Downloaded byteorder v1.4.3
      Downloaded minimal-lexical v0.2.1
      Downloaded lewton v0.10.2
      Downloaded hound v3.5.0
      Downloaded wyz v0.2.0
      Downloaded nom v7.1.1
      Downloaded ogg v0.8.0
      Downloaded minimp3 v0.3.5
      Downloaded bitvec v0.18.5
      Downloaded claxon v0.4.3
      Downloaded slice-deque v0.3.0
      Downloaded radium v0.3.0
      Downloaded minimp3-sys v0.3.2
      Downloaded cpal v0.11.0
      Downloaded alsa-sys v0.1.2
      Downloaded rodio v0.11.0
      Downloaded 17 crates (8.0 MB) in 3.48s (largest was `rodio` at 7.1 MB)
       Compiling libc v0.2.135
       Compiling autocfg v1.1.0
       Compiling proc-macro2 v1.0.47
       Compiling unicode-ident v1.0.5
       Compiling quote v1.0.21
       Compiling syn v1.0.102
       Compiling pkg-config v0.3.25
       Compiling cc v1.0.73
       Compiling thiserror v1.0.37
       Compiling cpal v0.11.0
       Compiling tinyvec_macros v0.1.0
       Compiling memchr v2.5.0
       Compiling byteorder v1.4.3
       Compiling lazy_static v1.4.0
       Compiling hashbrown v0.12.3
       Compiling os_str_bytes v6.3.0
       Compiling hound v3.5.0
       Compiling bitflags v1.3.2
       Compiling claxon v0.4.3
       Compiling textwrap v0.15.1
       Compiling radium v0.3.0
       Compiling strsim v0.10.0
       Compiling wyz v0.2.0
       Compiling minimal-lexical v0.2.1
       Compiling termcolor v1.1.3
       Compiling funty v1.1.0
       Compiling num-traits v0.2.15
       Compiling indexmap v1.9.1
       Compiling tinyvec v1.6.0
       Compiling alsa-sys v0.1.2
       Compiling ogg v0.8.0
       Compiling clap_lex v0.2.4
       Compiling minimp3-sys v0.3.2
       Compiling bitvec v0.18.5
       Compiling lewton v0.10.2
       Compiling nom v7.1.1
       Compiling slice-deque v0.3.0
       Compiling atty v0.2.14
       Compiling clap v3.2.22
       Compiling minimp3 v0.3.5
       Compiling thiserror-impl v1.0.37
       Compiling rodio v0.11.0
       Compiling rudiments v0.1.1
    error: cannot find derive macro `Parser` in this scope
       --> /home/pi/.cargo/registry/src/github.com-1285ae84e5963aae/rudiments-0.1.1/src/main.rs:169:10
        |
    169 | #[derive(Parser, Debug)]
        |          ^^^^^^
        |
    note: `Parser` is imported here, but it is only a trait, without a derive macro
       --> /home/pi/.cargo/registry/src/github.com-1285ae84e5963aae/rudiments-0.1.1/src/main.rs:158:5
        |
    158 | use clap::Parser;
        |     ^^^^^^^^^^^^
    
    error: cannot find attribute `clap` in this scope
       --> /home/pi/.cargo/registry/src/github.com-1285ae84e5963aae/rudiments-0.1.1/src/main.rs:170:3
        |
    170 | #[clap(version = "0.1.1")]
        |   ^^^^
        |
        = note: `clap` is in scope, but it is a crate, not an attribute
    
    error: cannot find attribute `clap` in this scope
       --> /home/pi/.cargo/registry/src/github.com-1285ae84e5963aae/rudiments-0.1.1/src/main.rs:173:7
        |
    173 |     #[clap(short, long, value_name = "NUMBER", default_value = "120")]
        |       ^^^^
        |
        = note: `clap` is in scope, but it is a crate, not an attribute
    
    error: cannot find attribute `clap` in this scope
       --> /home/pi/.cargo/registry/src/github.com-1285ae84e5963aae/rudiments-0.1.1/src/main.rs:177:7
        |
    177 |     #[clap(short, long, value_name = "FILE")]
        |       ^^^^
        |
        = note: `clap` is in scope, but it is a crate, not an attribute
    
    error: cannot find attribute `clap` in this scope
       --> /home/pi/.cargo/registry/src/github.com-1285ae84e5963aae/rudiments-0.1.1/src/main.rs:181:7
        |
    181 |     #[clap(short, long, value_name = "FILE")]
        |       ^^^^
        |
        = note: `clap` is in scope, but it is a crate, not an attribute
    
    error: cannot find attribute `clap` in this scope
       --> /home/pi/.cargo/registry/src/github.com-1285ae84e5963aae/rudiments-0.1.1/src/main.rs:185:7
        |
    185 |     #[clap(short, long, value_name = "DIRECTORY")]
        |       ^^^^
        |
        = note: `clap` is in scope, but it is a crate, not an attribute
    
    error: cannot find attribute `clap` in this scope
       --> /home/pi/.cargo/registry/src/github.com-1285ae84e5963aae/rudiments-0.1.1/src/main.rs:189:7
        |
    189 |     #[clap(short, long)]
        |       ^^^^
        |
        = note: `clap` is in scope, but it is a crate, not an attribute
    
    error[E0599]: no function or associated item named `parse` found for struct `Opts` in the current scope
       --> /home/pi/.cargo/registry/src/github.com-1285ae84e5963aae/rudiments-0.1.1/src/main.rs:194:28
        |
    171 | struct Opts {
        | ----------- function or associated item `parse` not found for this struct
    ...
    194 |     let opts: Opts = Opts::parse();
        |                            ^^^^^ function or associated item not found in `Opts`
        |
        = help: items from traits can only be used if the trait is implemented and in scope
        = note: the following traits define an item `parse`, perhaps you need to implement one of them:
                candidate #1: `instrumentation::nom::Parser`
                candidate #2: `Tuple`
                candidate #3: `StructOpt`
                candidate #4: `TypedValueParser`
    
    For more information about this error, try `rustc --explain E0599`.
    error: could not compile `rudiments` due to 8 previous errors
    error: failed to compile `rudiments v0.1.1`, intermediate artifacts can be found at `/tmp/cargo-installVcoA5C`
    
    opened by shakfu 0
  • install fails on Apple Silicon

    install fails on Apple Silicon

    I tried installing via cargo install on my M1 Max chipset and it failed with the following error:

    error: cannot find derive macro Parser in this scope --> /Users/ken/.cargo/registry/src/github.com-1ecc6299db9ec823/rudiments-0.1.1/src/main.rs:169:10 | 169 | #[derive(Parser, Debug)] | ^^^^^^ | note: Parser is imported here, but it is only a trait, without a derive macro --> /Users/ken/.cargo/registry/src/github.com-1ecc6299db9ec823/rudiments-0.1.1/src/main.rs:158:5 | 158 | use clap::Parser; | ^^^^^^^^^^^^

    error: cannot find attribute clap in this scope --> /Users/ken/.cargo/registry/src/github.com-1ecc6299db9ec823/rudiments-0.1.1/src/main.rs:170:3 | 170 | #[clap(version = "0.1.1")] | ^^^^ | = note: clap is in scope, but it is a crate, not an attribute error: cannot find attribute clap in this scope --> /Users/ken/.cargo/registry/src/github.com-1ecc6299db9ec823/rudiments-0.1.1/src/main.rs:173:7 | 173 | #[clap(short, long, value_name = "NUMBER", default_value = "120")] | ^^^^ | = note: clap is in scope, but it is a crate, not an attribute error: cannot find attribute clap in this scope --> /Users/ken/.cargo/registry/src/github.com-1ecc6299db9ec823/rudiments-0.1.1/src/main.rs:177:7 | 177 | #[clap(short, long, value_name = "FILE")] | ^^^^ | = note: clap is in scope, but it is a crate, not an attribute

    error: cannot find attribute clap in this scope --> /Users/ken/.cargo/registry/src/github.com-1ecc6299db9ec823/rudiments-0.1.1/src/main.rs:181:7 | 181 | #[clap(short, long, value_name = "FILE")] | ^^^^ | = note: clap is in scope, but it is a crate, not an attribute error: cannot find attribute clap in this scope --> /Users/ken/.cargo/registry/src/github.com-1ecc6299db9ec823/rudiments-0.1.1/src/main.rs:185:7 | 185 | #[clap(short, long, value_name = "DIRECTORY")] | ^^^^ | = note: clap is in scope, but it is a crate, not an attribute error: cannot find attribute clap in this scope --> /Users/ken/.cargo/registry/src/github.com-1ecc6299db9ec823/rudiments-0.1.1/src/main.rs:189:7 | 189 | #[clap(short, long)] | ^^^^ | = note: clap is in scope, but it is a crate, not an attribute error[E0599]: no function or associated item named parse found for struct Opts in the current scope --> /Users/ken/.cargo/registry/src/github.com-1ecc6299db9ec823/rudiments-0.1.1/src/main.rs:194:28 | 171 | struct Opts { | ----------- function or associated item parse not found for this ... 194 | let opts: Opts = Opts::parse(); | ^^^^^ function or associated item not found in Opts | = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item parse, perhaps you need to implement one of them: candidate #1: instrumentation::nom::Parser candidate #2: Tuple candidate #3: StructOpt

    For more information about this error, try rustc --explain E0599. error: could not compile rudiments due to 8 previous errors error: failed to compile rudiments v0.1.1, intermediate artifacts can be found at /var/folders/l9/xdcp3xnn6s78_5l9w2_mnvtw0000gn/T/cargo-installmpUQJR

    opened by yankeeinlondon 5
  • Question: Curious why you chose to premix the sound files?

    Question: Curious why you chose to premix the sound files?

    Looking through the code, I can see that you wrote some code to premix the files into a single "track". This is cool and it never occurred to me that this approach can work well (which it does clearly!).

    I just have a general curiosity/architecture question for you?

    Why did you choose to premix in the first place versus playing the individual samples in real time? If they're managed individually you could potentially build a UI/Command-line component where you can view the sequencer and turn on or off each instrument per note?

    Really cool lib btw!

    -deckarep

    opened by deckarep 3
  • Playing on repeat may stop unexpectedly

    Playing on repeat may stop unexpectedly

    The thread::park function is used to block the main thread indefinitely for play on repeat. However, per the thread::park documentation, this function may not actually block indefinitely...

    A call to park does not guarantee that the thread will remain parked forever, and callers should be prepared for this possibility.

    opened by jonasrmichel 0
Owner
Jonas Michel
Jonas Michel
Spotify for the terminal written in Rust 🚀

Spotify TUI A Spotify client for the terminal written in Rust. The terminal in the demo above is using the Rigel theme. Spotify TUI Installation Homeb

Alexander Keliris 14.1k Jan 1, 2023
A music theory guide written in Rust.

Rust Music Theory A library and executable that provides programmatic implementation of the basis of the music theory. Table of Contents Overview Usag

Ozan Kaşıkçı 551 Dec 21, 2022
musify is a simple discord bot to play music within a voice channel, written in the rust programming language.

musify-rs musify is a simple discord bot to play music within a voice channel, written in the rust programming language. Features A simple song queue

NV6 5 Aug 14, 2022
A Spotify downloader written in rust, which does not require a premium account

DownOnSpot A Spotify downloader written in Rust Disclaimer DownOnSpot was not developed for piracy. It is meant to be used in compliance with DMCA, Se

oSumAtrIX 273 Jan 7, 2023
Terminal Music Player written in Rust

Terminal Music Player written in Rust Listen to music freely as both in freedom and free of charge! Freedom: As time goes by, online service providers

null 376 Jan 3, 2023
Loopers is graphical live looper, written in Rust, designed for ease of use and rock-solid stability

Loopers Loopers is a graphical live looper, written in Rust, designed for ease of use and rock-solid stability. It can be used as a practice tool, com

Micah Wylde 81 Dec 29, 2022
Synthesizer IO - a synthesizer written in Rust.

Synthesizer IO Hopefully, this will become a synthesizer written in Rust. At the moment, it's experimental bits of technology toward that end. Running

Raph Levien 278 Dec 13, 2022
VST2 frequency modulation synthesizer written in Rust

OctaSine VST2 frequency modulation synthesizer written in Rust. Official website with downloads OctaSine.com Audio examples SoundCloud Screenshots Lig

Joakim Frostegård 412 Dec 30, 2022
🎵 A super simple VST written in Rust

DigiDist This is a simple little VST plugin, developed in Rust using the vst2 crate. It doesn't sound particularly great, but it demonstrates just how

Joe Clay 34 May 29, 2022
A simple GUI audio player written in Rust with egui. Inspired by foobar2000.

Music Player A simple GUI music player inspired by foobar2000 written in Rust using egui. The goal of this project is to learn about making gui/ nativ

Ryan Blecher 5 Sep 16, 2022
Small music theory library with MIDI capabilities written in Rust

mumuse Small music theory library with MIDI capabilities written in Rust (wip). Examples Creating notes and transpositions // Declare Note from &str l

Alexis LOUIS 4 Jul 27, 2022
A terminal music player written in the Rust language.

A terminal music player written in the Rust language. (Windows) Requirements Configuration file path: C:\Users\xxx\.config\music_player\config.yml # P

xiao hui 162 Nov 12, 2022
Tool for solving music harmonics written in rust.

Harmonized Tool for solving harmonics tasks Installation steps Requirements Make shure you have installed rust cargo If not: Download and run rust ins

Dmitry Miasnenko 0 Jan 28, 2022
API-agnostic audio plugin framework written in Rust

Because everything is better when you do it yourself - Rust VST3 and CLAP framework and plugins

Robbert van der Helm 415 Dec 27, 2022
ncspot is a ncurses Spotify client written in Rust using librespot.

ncspot is a ncurses Spotify client written in Rust using librespot. It is heavily inspired by ncurses MPD clients, such as ncmpc. My motivation was to provide a simple and resource friendly alternative to the official client as well as to support platforms that currently don't have a Spotify client, such as the *BSDs.

Henrik Friedrichsen 3.4k Jan 8, 2023
🎹 [WIP] Full-fledged software sampler written in Rust.

sampler This project aims to be a full-fledged software sampler written in Rust. While I initially used Apple's AUSampler for sampled instruments in m

soaky audio 12 Dec 27, 2022
Small, compact music player written with Rust.

trill Small, compact music player based on rodio. Usage Run the program with --help to see the available options. To just play a sound file: trill -p

Will 3 Nov 25, 2022
Tools for working with MIDI files - written by All the Music LLC for musicians.

Tools for Generating and Working with MIDI Files NOTICE: This repo is under construction and is not ready for use. Once it is ready, and the other rep

null 9 Nov 17, 2022
A rust binding for the FMOD library

rust-fmod This is a rust binding for FMOD, the library developped by FIRELIGHT TECHNOLOGIES. FMOD website : www.fmod.org You can also find it on crate

Guillaume Gomez 55 Nov 2, 2022