NAME

Music::BachChoralHarmony - Parse the UCI Bach choral harmony data set

VERSION

version 0.0410

SYNOPSIS

  use Music::BachChoralHarmony;

  my $bach = Music::BachChoralHarmony->new;
  my $songs = $bach->parse;

  # show all the song ids:
  print Dumper [ sort keys %$songs ];
  print Dumper [ sort keys %{ $bach->data } ]; # Same

  # show all the song titles:
  print Dumper [ map { $songs->{$_}{title} } sort keys %$songs ];

  $songs = $bach->search( id => '000106b_' );
  $songs = $bach->search( id => '000106b_ 000206b_' );
  $songs = $bach->search( key => 'C_M' );         # In C major
  $songs = $bach->search( key => 'C_M C_m' );     # In C major or C minor
  $songs = $bach->search( bass => 'C' );          # With a C note in the bass
  $songs = $bach->search( bass => 'C D' );        # With C or D in the bass
  $songs = $bach->search( bass => 'C & D' );      # With C and D in the bass
  $songs = $bach->search( chord => 'C_M' );       # With a C major chord
  $songs = $bach->search( chord => 'C_M D_m' );   # With a C major or a D minor chord
  $songs = $bach->search( chord => 'C_M & D_m' ); # With C major and D minor chords
  $songs = $bach->search( notes => 'C E G' );     # With the notes C or E or G
  $songs = $bach->search( notes => 'C & E & G' ); # With C and E and G
  # Args can be combined too:
  $songs = $bach->search( key => 'C_M C_m', chord => 'X_m & F_M' );

  # Possibly handy:
  my $notes = $bach->bits2notes('100000000000');     # [ C ]
  $notes = $bach->bits2notes('010000000000');        # [ Db ]
  $notes = $bach->bits2notes('000000000010');        # [ Bb ]
  $notes = $bach->bits2notes( '000000000010', '#' ); # [ A# ]
  $notes = $bach->bits2notes('110000000010');        # [ C Db Bb ]

DESCRIPTION

Music::BachChoralHarmony parses the UCI Bach choral harmony data set of 60 chorales and does a few things:

* It turns the UCI CSV data into a perl data structure.

* It combines the Bach BWV number, song title and key with the data.

* It converts the UCI YES/NO note specification into a bit string and named note list.

* It allows searching by ids, keys, notes, and chords.

The BWV and titles were collected from an Internet Archive and filled-in from https://bach-chorales.com/. The keys were computed with a music21 program, and if missing filled-in again from https://bach-chorales.com/. Check out the links in the "SEE ALSO" section for more information.

The main purpose of this module is to produce the results of the eg/* programs. So check 'em out!

ATTRIBUTES

data_file

  $file = $bach->data_file;

The local file where the Bach choral harmony data set resides.

Default: dist_dir()/jsbach_chorals_harmony.data

key_title

  $file = $bach->key_title;

The local file where the key signatures and titles for each song are listed by BWV number.

Default: dist_dir()/jsbach_BWV_keys_titles.txt

data

  $songs = $bach->data;

The data resulting from the "parse" method.

METHODS

new

  $bach = Music::BachChoralHarmony->new;

Create a new Music::BachChoralHarmony object.

parse

  $songs = $bach->parse;

Parse the data_file and key_title files into the data hash reference of each song keyed by the song id. Each song includes a BWV identifier, title, key and list of events. The event list is made of hash references with a notes bit-string, bass note, the accent value and the resonating chord.

  $songs = $bach->search( $k => $v ); # As in the SYNOPSIS above

Search the parsed result data by song ids, keys, bass notes, chords, or individual notes and return a hash reference of the format:

  { $song_id => $song_data, ... }

The id, and key can be searched by single or multiple values returning all songs that match. Note names must be separated with a space character.

The bass, chord, and notes can be searched either as or (separating note names with a space character), or as inclusive and (separating note names with an & character).

bits2notes

  $notes = $bach->bits2notes($string);
  $notes = $bach->bits2notes( $string, $accidental );

Convert a bit-string of 12 binary positions to a note list array reference.

The accidental can be given as # sharp or b flat in the case of enharmonic notes. Default: b

The dataset notes bit-string is defined by position as follows:

  0  => C
  1  => C# or Db
  2  => D
  3  => D# or Eb
  4  => E
  5  => F
  6  => F# or Gb
  7  => G
  8  => G# or Ab
  9  => A
  10 => A# or Bb
  11 => B

SEE ALSO

The eg/* and t/01-methods.t files in this distribution.

File::ShareDir

List::Util

Moo

Text::CSV

https://archive.ics.uci.edu/ml/datasets/Bach+Choral+Harmony is the dataset itself.

https://web.archive.org/web/20140515065053/http://www.jsbchorales.net/bwv.shtml was the original site.

http://www.bach-chorales.com/BachChorales.htm is a more modern site.

https://github.com/ology/Bach-Chorales/ is a web app that displays chord transitions with this module.

https://github.com/ology/Bach-Chorales/blob/master/bin/key.py is a program written to extract the key signature.

https://github.com/ology/Bach-Chorales/blob/master/chorales.zip are the collected MIDI files and PDF transcriptions.

https://en.wikipedia.org/wiki/Chorale_cantata_(Bach) describes the context.

THANK YOU

Dan Book (DBOOK) for the ShareDir clues.

AUTHOR

Gene Boggs <gene@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2020 by Gene Boggs.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.