Giter Club home page Giter Club logo

guitar-tab-generator's Introduction

Guitar Tab Generator

Build + Test Coverage

Guitar Tab Generator logo

Generate fingerstyle guitar tabs based on the difficulty of different finger positions. Built with Rust. Designed for compilation to WebAssembly for use in web applications.

Web Assembly Rust


Table of Contents

Demo

Example web application ๐Ÿš€

Guitar Tab Generator Demo

Features

  • Input pitch parsing
  • Alternate tunings
  • Capo consideration
  • Any number of strings (not just 6 string guitars!)
  • Configurable number of frets
  • Tab width and padding formatting
  • Playback indicator for playback applications
  • Pathfinding algorithm leverage Dijkstra's algorithm to calculate the arrangement with the least difficulty.

Previous versions

This project has been attempted numerous times with varying levels of success. This attempt utilizes Rust and WASM to overcome the previously-encountered roadblocks regarding performance, distribution, and developer ergonomics.

Pathfinding Algorithm Visualization

The pathfinding calculation is initiated by the Arrangement::create_arrangements() function.

Let's look at an example with a standard guitar where we want to find the optimal arrangement to play a G3, then a rest, then a B3, then a D4 and G4 simultaneously. The pitch input for this example could look like this:

G3

B3
D4G4

Pitch Fingerings

The different fingerings are then calculated for each pitch. For example, a G3 can be played on string 3 at fret 0, or string 4 at fret 5, and so on:

Beat 1 pitch fingerings

Representation String Fret
G3 : 3 โ‡’ 0 3 0
G3 : 4 โ‡’ 5 4 5
G3 : 5 โ‡’ 10 5 10
G3 : 6 โ‡’ 15 6 15

Beat 2 is a rest and therefore has no fingerings.

Beat 3 pitch fingerings

Representation String Fret
B3 : 2 โ‡’ 0 2 0
B3 : 3 โ‡’ 4 3 4
B3 : 4 โ‡’ 9 4 9
B3 : 5 โ‡’ 14 5 14

Beat 4 pitch fingerings

Representation String Fret Representation String Fret
D4 : 2 โ‡’ 3 2 3 G4 : 1 โ‡’ 3 1 3
D4 : 3 โ‡’ 7 3 7 G4 : 2 โ‡’ 8 2 8
D4 : 4 โ‡’ 12 4 12 G4 : 3 โ‡’ 12 3 12
D4 : 5 โ‡’ 17 5 17 G4 : 4 โ‡’ 17 4 17

Fingering combinations for each beat

For beat 1 and beat 3, the fingering combinations are identical to the pitch fingerings since those beats only play one pitch each. For beat 4, we calculate the cartesian product of the pitch fingerings to consider all of the fingerings combinations.

Beat 4 fingering combinations

D4 Fingering G4 Fingering
D4 : 2 โ‡’ 3 G4 : 1 โ‡’ 3
D4 : 2 โ‡’ 3 G4 : 2 โ‡’ 8
D4 : 2 โ‡’ 3 G4 : 3 โ‡’ 12
D4 : 2 โ‡’ 3 G4 : 4 โ‡’ 17
D4 : 3 โ‡’ 7 G4 : 1 โ‡’ 3
D4 : 3 โ‡’ 7 G4 : 2 โ‡’ 8
D4 : 3 โ‡’ 7 G4 : 3 โ‡’ 12
D4 : 3 โ‡’ 7 G4 : 4 โ‡’ 17
D4 : 4 โ‡’ 12 G4 : 1 โ‡’ 3
D4 : 4 โ‡’ 12 G4 : 2 โ‡’ 8
D4 : 4 โ‡’ 12 G4 : 3 โ‡’ 12
D4 : 4 โ‡’ 12 G4 : 4 โ‡’ 17
D4 : 5 โ‡’ 17 G4 : 1 โ‡’ 3
D4 : 5 โ‡’ 17 G4 : 2 โ‡’ 8
D4 : 5 โ‡’ 17 G4 : 3 โ‡’ 12
D4 : 5 โ‡’ 17 G4 : 4 โ‡’ 17

Note: D4 : 2 โ‡’ 3 with G4 : 1 โ‡’ 3 is valid; while D4 : 2 โ‡’ 3 with G4 : 2 โ‡’ 8 is invalid since multiple frets cannot be played on the same string.

Pathfinding nodes

To calculate the optimal set of fingering combinations of each beat, we construct a node for each fingering combination. The node contains underlying data that informs the calculation of the difficulty of progressing from one fingering combination to another including

  • the average non-zero fret value
  • the non-zero fret span

Additionally, each node must be unique so the beat index is included in the underlying data of the node.

flowchart TB
    subgraph Beat1
    direction TB
        1.1("G3 : 3 โ‡’ 0")
        1.2("G3 : 4 โ‡’ 5")
        1.3("G3 : 5 โ‡’ 10")
        1.4("G3 : 6 โ‡’ 15")
    end

    subgraph Beat2
    direction TB
        2.1("Rest")
    end

    subgraph Beat3
    direction TB
        3.1("B3 : 2 โ‡’ 0")
        3.2("B3 : 3 โ‡’ 4")
        3.3("B3 : 4 โ‡’ 9")
        3.4("B3 : 5 โ‡’ 14")
    end

    subgraph Beat4
    direction TB
        4.1("D4 : 2 โ‡’ 3 \nG4 : 1 โ‡’ 3")
        4.2("D4 : 2 โ‡’ 3 \nG4 : 3 โ‡’ 12")
        4.3("D4 : 2 โ‡’ 3 \nG4 : 4 โ‡’ 17")
        4.4("D4 : 3 โ‡’ 7 \nG4 : 1 โ‡’ 3")
        4.5("D4 : 3 โ‡’ 7 \nG4 : 2 โ‡’ 8")
        4.6("D4 : 3 โ‡’ 7 \nG4 : 4 โ‡’ 17")
        4.7("D4 : 4 โ‡’ 12\nG4 : 1 โ‡’ 3")
        4.8("D4 : 4 โ‡’ 12\nG4 : 2 โ‡’ 8")
        4.9("D4 : 4 โ‡’ 12\nG4 : 3 โ‡’ 12")
        4.10("D4 : 5 โ‡’ 17\nG4 : 1 โ‡’ 3")
        4.11("D4 : 5 โ‡’ 17\nG4 : 2 โ‡’ 8")
        4.12("D4 : 5 โ‡’ 17\nG4 : 3 โ‡’ 12")
        4.13("D4 : 5 โ‡’ 17\nG4 : 4 โ‡’ 17")
    end

    Beat1 ~~~ Beat2 ~~~ Beat3 ~~~ Beat4
Loading

With the node edges, we can see the directed graph take shape:

%%{ init: { 'flowchart': { 'curve': 'basis' } } }%%
flowchart TB
    subgraph Beat1
    direction TB
        1.1("G3 : 3 โ‡’ 0")
        1.2("G3 : 4 โ‡’ 5")
        1.3("G3 : 5 โ‡’ 10")
        1.4("G3 : 6 โ‡’ 15")
    end

    1.1 & 1.2 & 1.3 & 1.4 --> 2.1

    subgraph Beat2
    direction TB
        2.1("Rest")
    end

    2.1 --> 3.1 & 3.2 & 3.3 & 3.4

    subgraph Beat3
    direction TB
        3.1("B3 : 2 โ‡’ 0")
        3.2("B3 : 3 โ‡’ 4")
        3.3("B3 : 4 โ‡’ 9")
        3.4("B3 : 5 โ‡’ 14")
    end

    3.1 & 3.2 & 3.3 & 3.4 --> 4.1 & 4.2 & 4.3 & 4.4 & 4.5 & 4.6 & 4.7 & 4.8 & 4.9 & 4.10 & 4.11 & 4.12 & 4.13

    subgraph Beat4
    direction TB
        4.1("D4 : 2 โ‡’ 3 \nG4 : 1 โ‡’ 3")
        4.2("D4 : 2 โ‡’ 3 \nG4 : 3 โ‡’ 12")
        4.3("D4 : 2 โ‡’ 3 \nG4 : 4 โ‡’ 17")
        4.4("D4 : 3 โ‡’ 7 \nG4 : 1 โ‡’ 3")
        4.5("D4 : 3 โ‡’ 7 \nG4 : 2 โ‡’ 8")
        4.6("D4 : 3 โ‡’ 7 \nG4 : 4 โ‡’ 17")
        4.7("D4 : 4 โ‡’ 12\nG4 : 1 โ‡’ 3")
        4.8("D4 : 4 โ‡’ 12\nG4 : 2 โ‡’ 8")
        4.9("D4 : 4 โ‡’ 12\nG4 : 3 โ‡’ 12")
        4.10("D4 : 5 โ‡’ 17\nG4 : 1 โ‡’ 3")
        4.11("D4 : 5 โ‡’ 17\nG4 : 2 โ‡’ 8")
        4.12("D4 : 5 โ‡’ 17\nG4 : 3 โ‡’ 12")
        4.13("D4 : 5 โ‡’ 17\nG4 : 4 โ‡’ 17")
    end

    Beat1 ~~~ Beat2 ~~~ Beat3 ~~~ Beat4
Loading

Algorithm choice

The number of fingering combinations grows exponentially with more beats and pitches so the choice of shortest path algorithm is critical. The Dijkstra pathfinding algorithm was chosen for this application of the "shortest path exercise" for the following reasons:

  • The sequential nature of the musical arrangement problem results in a directed graph where only nodes representing consecutive beat fingering combinations have edges from one to the next.
  • The edges between nodes are weighted with the difficulty of moving from one fingering combination to another so the graph above is already constructed with the only possible next nodes connected.

Contributing and Installation

Build from source

Requires:

git clone https://github.com/noahbaculi/guitar-tab-generator.git
cd guitar-tab-generator

Run examples

cargo run --example basic
cargo run --example advanced

Background code runner

bacon

Calculate code coverage

cargo tarpaulin --out Html --output-dir dev/tarpaulin-coverage

Screen for potentially unused feature flags

unused-features analyze --report-dir 'dev/unused-features-report'
unused-features build-report --input 'dev/unused-features-report/report.json'

Build WASM binary

wasm-pack build --target web --out-dir pkg/wasm_guitar_tab_generator

# check binary size
ls -l pkg/wasm_guitar_tab_generator/guitar_tab_generator_bg.wasm

Future Improvements

  • Borrowed types vs box vs RC
  • Parallelism with Rayon
  • Add filter for max_fret_span in arrangements
  • Audit namespace of functions (object functions vs standalone) (public vs private)
  • Property testing with Proptest

guitar-tab-generator's People

Contributors

noahbaculi avatar

Stargazers

n3r0_ avatar nawin avatar Huy avatar ranyaaaa !!! avatar Shrey  avatar

Watchers

 avatar

guitar-tab-generator's Issues

webserver

what would be the procces for adding a webserver to display the generated tabs as shown in the readme?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.