R/howfree.R

Defines functions howfree

Documented in howfree

#' Count a scale's degrees of freedom
#'
#' Some scalar structures can vary their specific pitches much more flexibly
#' than others while retaining the same overall "color." For instance, the
#' meantone family of diatonic scales is generated by a line of fifths and
#' can only vary along one dimension: the size of the generating fifth.
#' This literally defines a line in the MCT geometry, and if the scale moves
#' off that line it ceases to have the same structure as the diatonic scale.
#' (Notably, it stops being non-degenerate well-formed.) By contrast, the
#' 5-limit just diatonic scale is defined by two distinct parameters: the 
#' size of its major third and the size of its perfect fifth. See "Modal 
#' Color Theory," pp. 26-27, for more discussion.
#'
#' The returned value is "essentialized," i.e. calculated by factoring out
#' degrees of freedom that are universal to the given hyperplane arrangement.
#' For instance, the set `(0, 4, 8)` has absolutely no room for variation in
#' the black arrangement, as none of its pitches can move at all. Unsurprisingly,
#' `howfree(c(0, 4, 8), ineqmat="black")` returns `0`. But if we use the 
#' modal color theory arrangement, i.e. `howfree(c(0, 4, 8), ineqmat="mct")`,
#' the result is still `0` even though for this arrangement we could transpose
#' the augmented triad to start on any pitch without altering its scalar structure.
#' For the MCT arrangement, chromatic transposition offers a degree of freedom
#' that is essentially invisible to the arrangement, so `howfree()` doesn't
#' report it in the value it returns for that arrangement. Similarly, the 
#' anaglyph arrangements (see [make_anaglyph_ineqmat()]) factor out transposition
#' of each set individually, so `howfree(..., inemqat="anaglyph")` ignores two
#' degrees of freedom.
#' 
#' @inheritParams signvector
#' 
#' @returns Single non-negative integer
#' 
#' @examples
#' c_natural_minor <- c(0, 2, 3, 5, 7, 8, 10)
#' c_melodic_minor <- c(0, 2, 3, 5, 7, 9, 11)
#' just_diatonic <- j(dia)
#' howfree(c_natural_minor)
#' howfree(c_melodic_minor)
#' howfree(just_diatonic)
#'
#' howfree(c(0, 4, 7))
#' howfree(c(0, 4, 7), ineqmat="white")
#'
#' howfree(c(0, 2, 6), ineqmat="mct")
#' howfree(c(0, 2, 6), ineqmat="roth")
#'
#' @export
howfree <- function(set, ineqmat=NULL, edo=12, rounder=10) {
  card <- length(set)
  if (card < 2) { 
    return(0) 
  }

  ineqmat <- choose_ineqmat(set, ineqmat)

  zeroesflat <- ineqmat[whichsvzeroes(set, ineqmat, edo, rounder), ]
  rank <- qr(zeroesflat)$rank

  scale_degree_matrix <- ineqmat[, 1:card]
  ineqmat_rank <- qr(scale_degree_matrix)$rank

  ineqmat_rank - rank
}

Try the musicMCT package in your browser

Any scripts or data that you put into this service are public.

musicMCT documentation built on June 21, 2026, 9:06 a.m.