HeadMusic

CI Security Gem Version Documentation

The head_music Ruby gem provides a toolkit for working with Western music theory. Model and manipulate the fundamental elements of music including pitches, scales, key signatures, intervals, and chords.

Features

  • Western Music Theory Fundamentals: Work with pitches, scales, intervals, chords, and key signatures
  • Musical Analysis: Analyze harmonic progressions, voice leading, and counterpoint
  • Style Analysis: Rules for species counterpoint and voice leading
  • Internationalization: Support for multiple languages (English, French, German, Italian, Russian, Spanish)
  • Instrument Modeling: Extensive database of musical instruments with ranges and properties

Installation

Add this line to your application’s Gemfile:

ruby gem 'head_music'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install head_music

Quick Start

```ruby require ‘head_music’

Work with pitches and intervals

pitch = HeadMusic::Rudiment::Pitch.get(‘C4’) higher_pitch = HeadMusic::Rudiment::Pitch.get(‘E4’) interval = HeadMusic::Analysis::DiatonicInterval.new(pitch, higher_pitch) puts interval.name # => “major third”

Create scales

scale = HeadMusic::Rudiment::Scale.get(‘C’, :major) puts scale.pitches.map(&:to_s) # => [“C4”, “D4”, “E4”, “F4”, “G4”, “A4”, “B4”]

Analyze chords

pitches = %w[C4 E4 G4].map { |p| HeadMusic::Rudiment::Pitch.get(p) } chord = HeadMusic::Analysis::PitchSet.new(pitches) puts chord.major_triad? # => true ```

Style Analysis

Look up a style guide by key and analyze a voice against it. Style::Guide.get returns nil for an unknown key, so a stored key can be validated before use.

```ruby guide = HeadMusic::Style::Guide.get(‘first_species_harmony’) guide.category # => :harmony guide.display_name # => “First Species Harmony”

assessment = guide.assess(voice) assessment.fitness # => 0.0 to 1.0 assessment.messages # => [“Prefer contrary motion. Move voices in different melodic directions.”] ```

A guide declares its guidelines in three tiers, and the tier decides how much each one counts:

ruby guide.gate_items # preconditions -- can this voice be assessed at all? guide.primary_items # what the guide is about guide.secondary_items # background craft it inherits rather than teaches guide.guide_items # all three, in that order

A gate asks whether the voice can be assessed at all. Failing one stops the assessment — the rubric is not computed, and the grade is the gates alone:

ruby assessment.assessable? # => false for a voice too short to judge, or with no companion voice assessment.fitness # => the gates' product; the rubric was never reached

Among the rules that are assessed, primaries share φ⁻¹ of the rubric and secondaries share φ⁻², which is why a species guide weighs its own rules as heavily as all the craft it inherits put together. The budgets are fixed rather than divided by item count, so what a guide teaches does not thin out as it inherits more. A rubric that declares only one tier is renormalized to the full range.

Within a tier, a second axis: strength. A prohibition (:strong, the default) weighs twice a preference (:weak), normalized by that tier’s own total. Strength never crosses a tier boundary, and it is inert on gates, which multiply the whole rubric:

ruby HeadMusic::Style::Guidelines::NoParallelPerfectOnDownbeats.strength # => :strong HeadMusic::Style::Guidelines::PreferContraryMotion.strength # => :weak

Unlike tier, strength is a property of the guideline rather than of the list it was declared in — a preference is a preference in every guide that names it. An item may override it for the tradition-dependent case, with Guideline.with(strength: :weak).

Each entry is a Style::GuideItem — a guideline plus the configuration this guide gives it — and assessing one yields a frozen Style::GuideItemAssessment:

```ruby item = guide.primary_items.first item.guideline # => HeadMusic::Style::Guidelines::NoUnisonsInMiddle item.config # => {} item.strength # => :strong

assessment.guide_item_assessments.first.tier # => :gate assessment.guide_item_assessments.first.strength # => :strong assessment.guide_item_assessments.first.fitness # => 0.0 to 1.0 ```

Guides whose tiers vary by configuration are built with .with. The six contour melodies are registered under their own keys, and each key is exactly one such configuration:

ruby HeadMusic::Style::Guide.get('arch_contour_melody') # the same guide, spelled out HeadMusic::Style::Guides::ContourMelody.with(contour: :arch, minimum_melodic_intervals: 2)

Configure it differently and you get a different guide — one the registry does not hold, whose key is nil and whose display_name falls back to the class. Prefer the key when you mean a registered guide, and .with when you deliberately want a configuration of your own.

Documentation

Requirements

  • Ruby 3.3.0 or higher
  • ActiveSupport 7.0+

Development

After checking out the repo, run bin/setup to install dependencies.

Running Tests

```bash # Run all tests bundle exec rspec

Run tests with coverage

bundle exec rake

Run quality checks (tests + linting + security)

bundle exec rake quality ```

Code Quality

```bash # Run linting bundle exec rubocop

Run security audit

bundle exec rake bundle:audit:check

Generate documentation

bundle exec rake doc ```

Available Rake Tasks

  • rake spec - Run tests
  • rake quality - Run tests, linting, and security audit
  • rake doc - Generate YARD documentation
  • rake doc_stats - Show documentation coverage statistics
  • rake coverage - Open coverage report in browser

Releasing a New Version

  1. Update the version number in lib/head_music/version.rb
  2. Commit the version change: git commit -am "Bump version to X.Y.Z"
  3. Push to main: git push origin main
  4. Release the gem:

bash bundle exec rake release

This will: - Build the gem - Create and push a git tag (e.g., vX.Y.Z) - Push the gem to RubyGems

The git tag push also triggers a GitHub Actions workflow that creates a GitHub Release with auto-generated release notes.

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Project Structure

lib/head_music/ ├── analysis/ # Musical analysis tools (intervals, chords, etc.) ├── content/ # Musical content (compositions, voices, notes) ├── instruments/ # Instrument definitions and properties ├── rudiment/ # Basic music theory elements (pitches, scales, etc.) └── style/ # Style analysis and composition rules

Code of Conduct

This project is intended to be a safe, welcoming space for collaboration. Contributors are expected to adhere to our Code of Conduct.

License

The gem is available as open source under the terms of the MIT License.

Support