Skip to content

malcolmsailor/dumb_composer

Repository files navigation

A project to generate synthetic Classical music annotated with chord changes.

The approach is purely rule-based. My goal here was to create augmented data for training Roman-numeral analysis models like the one in my 2024 ISMIR paper.

The general intuition behind the project is that the composition of music is a little bit like a one-way function. In other words, it is relatively easy to write rules to go from a chord progression to a musical surface, but harder to write rules to go from the musical surface to the chord progression.

While it was a fun project and the generated music can be amusing to listen to, I didn't find that it improved the test performance of my trained models, presumably because the synthetic data lies too far out of distribution. It's possible that refining the code to produce better music would render it useful, but for now I do not plan to pursue this research direction further.

There is further discussion of this project in my upcoming dissertation.

Contents

Scripts

There are four main scripts. For usage, see Usage below.

scripts/run_incremental_contrapuntist.py
scripts/run_incremental_contrapuntist_with_accomps.py
scripts/run_incremental_contrapuntist_with_prefabs.py
scripts/run_incremental_contrapuntist_with_prefabs_and_accomps.py

Each of these generate music in batch, taking a chord progression or progressions as inputs. They each follow a slightly different procedure:

Example of the output of run_incremental_contrapuntist.py

Example of the output of run_incremental_contrapuntist_with_accomps.py

Example of the output of run_incremental_contrapuntist_with_prefabs

  • run_incremental_contrapuntist_with_prefabs_and_accomps.py: add both accompanimental patterns and melodic/rhythmic ornamentation to an underlying four-part realization. Listen to an example (score excerpt below)

Example of the output of run_incremental_contrapuntist_with_prefabs_and_accomps

The examples above show the start of each MIDI file when opened in MuseScore. To any of my fellow punctilious music theorists, I apologize for the infelicitous enharmonic notations.

Usage

The only required arguments for each script are

  • one or more RomanText files containing chord progressions to realize as positional arguments. (In docs/examples, I have placed two example RomanText files from the When In Rome corpus.)
  • --output-folder, specifying where to save the output.

For example:

python scripts/run_incremental_contrapuntist_with_prefabs_and_accomps.py \
    docs/examples/Bach_Chorale_1.txt \
    docs/examples/Beethoven_Sonata_2_ii.txt \
    --output-folder ~/tmp/dumb_composer_output

The remaining arguments are undocumented for the time being, but their usage can be inferred from user_scripts/synthetic_data.sh which shows how I used these scripts to build a synthetic dataset.

Note that the script may fail on a given input file if it is long or complex.

Discussion

The procedure for generating synthetic data is sketched in the following flow chart. Many details are omitted (for example, the application of suspensions to the voice-leading skeleton). The first step ("Make chord progression") was carried out by a separate Python script, not included in this repository.

Flow chart outlining the synthetic data generation procedure.

About

A Rule-Based Classical Music Generator

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors