From 96f9c849d2b055d97d6893bdf5a5a19313c4d1f6 Mon Sep 17 00:00:00 2001 From: ncondits3 Date: Wed, 27 Dec 2023 07:31:56 -0500 Subject: [PATCH] Created harte() function. --- DESCRIPTION | 2 +- NAMESPACE | 1 + R/Chords.R | 147 +++++++++++++++++++--- R/Keys.R | 7 +- R/Regex.R | 43 ++++++- _pkgdown.yml | 1 - docs/404.html | 2 +- docs/LICENSE-text.html | 2 +- docs/articles/ComplexSyntax.html | 4 +- docs/articles/Context.html | 2 +- docs/articles/index.html | 2 +- docs/authors.html | 2 +- docs/index.html | 2 +- docs/pkgdown.yml | 2 +- docs/reference/LO5th.html | 2 +- docs/reference/REparser.html | 2 +- docs/reference/RegexFind.html | 2 +- docs/reference/accidental.html | 2 +- docs/reference/bhatk.html | 4 +- docs/reference/bpm2sec.html | 2 +- docs/reference/census.html | 8 +- docs/reference/cents.html | 2 +- docs/reference/chord.html | 31 ++++- docs/reference/chordDeparsing.html | 2 +- docs/reference/chordFunctions.html | 14 ++- docs/reference/chordParsing.html | 2 +- docs/reference/cleave.html | 4 +- docs/reference/cleaveGraceNotes.html | 2 +- docs/reference/collapseHumdrum.html | 2 +- docs/reference/combineFields.html | 2 +- docs/reference/context.html | 4 +- docs/reference/count.html | 4 +- docs/reference/crossEntropy.html | 2 +- docs/reference/degree.html | 4 +- docs/reference/delta.html | 2 +- docs/reference/diatonicSetS4.html | 2 +- docs/reference/ditto.html | 2 +- docs/reference/draw.html | 2 +- docs/reference/duple.html | 2 +- docs/reference/duration.html | 2 +- docs/reference/entropy.html | 2 +- docs/reference/enum.html | 2 +- docs/reference/evaluatingExpressions.html | 2 +- docs/reference/expand.html | 2 +- docs/reference/expandPaths.html | 2 +- docs/reference/figuredBass.html | 8 +- docs/reference/freq.html | 4 +- docs/reference/gamut.html | 2 +- docs/reference/grid.html | 2 +- docs/reference/groupHumdrum.html | 4 +- docs/reference/groupingFactors.html | 2 +- docs/reference/harm.html | 6 +- docs/reference/helmholtz.html | 4 +- docs/reference/hop.html | 2 +- docs/reference/humCoercion.html | 2 +- docs/reference/humMerge.html | 2 +- docs/reference/humMeter.html | 2 +- docs/reference/humSize.html | 2 +- docs/reference/humSummary.html | 4 +- docs/reference/humTable.html | 54 ++++---- docs/reference/humdrumDispatch.html | 4 +- docs/reference/humdrumPitch.html | 2 +- docs/reference/humdrumR.html | 2 +- docs/reference/humdrumRclass.html | 6 +- docs/reference/index.html | 6 +- docs/reference/indexHumdrum.html | 4 +- docs/reference/int.html | 4 +- docs/reference/interpretations.html | 4 +- docs/reference/interval.html | 4 +- docs/reference/invert.html | 2 +- docs/reference/ioi.html | 2 +- docs/reference/is.major.html | 2 +- docs/reference/is.simple.html | 2 +- docs/reference/kern.html | 4 +- docs/reference/key.html | 2 +- docs/reference/keyDeparsing.html | 2 +- docs/reference/keyFunctions.html | 2 +- docs/reference/keyParsing.html | 2 +- docs/reference/lag.html | 6 +- docs/reference/lilypond.html | 4 +- docs/reference/meter.html | 2 +- docs/reference/metlev.html | 4 +- docs/reference/mutualInfo.html | 2 +- docs/reference/nbeats.html | 2 +- docs/reference/notehead.html | 2 +- docs/reference/octave.html | 2 +- docs/reference/p.html | 2 +- docs/reference/partialMatching.html | 2 +- docs/reference/pc.html | 4 +- docs/reference/pitch.html | 4 +- docs/reference/pitchDeparsing.html | 2 +- docs/reference/pitchFunctions.html | 2 +- docs/reference/pitchParsing.html | 2 +- docs/reference/pullHumdrum.html | 4 +- docs/reference/quality.html | 2 +- docs/reference/rational.html | 2 +- docs/reference/readHumdrum.html | 4 +- docs/reference/recip.html | 2 +- docs/reference/recordDuration.html | 2 +- docs/reference/recycling.html | 2 +- docs/reference/reference.html | 8 +- docs/reference/regexConstruction.html | 2 +- docs/reference/rend.html | 4 +- docs/reference/rhythmDeparsing.html | 2 +- docs/reference/rhythmFunctions.html | 2 +- docs/reference/rhythmParsing.html | 2 +- docs/reference/romanKey.html | 2 +- docs/reference/romanNumerals.html | 2 +- docs/reference/segments.html | 2 +- docs/reference/selectedFields.html | 68 ++++------ docs/reference/semits.html | 6 +- docs/reference/sigma.html | 2 +- docs/reference/signature.html | 2 +- docs/reference/silbeFormat.html | 2 +- docs/reference/solfa.html | 4 +- docs/reference/solfg.html | 4 +- docs/reference/sonority.html | 2 +- docs/reference/spines.html | 8 +- docs/reference/step.html | 2 +- docs/reference/struct.html | 4 +- docs/reference/subset.humdrumR.html | 4 +- docs/reference/syncopation.html | 2 +- docs/reference/tactus.html | 2 +- docs/reference/tally.html | 5 +- docs/reference/tandem.html | 2 +- docs/reference/tatum.html | 2 +- docs/reference/tertian.html | 6 +- docs/reference/tertianSetS4.html | 2 +- docs/reference/time.html | 2 +- docs/reference/timebase.html | 2 +- docs/reference/timeline.html | 2 +- docs/reference/token.html | 2 +- docs/reference/tonalIntervalS4.html | 2 +- docs/reference/tonh.html | 4 +- docs/reference/transpose.html | 2 +- docs/reference/unfoldStops.html | 2 +- docs/reference/validateHumdrum.html | 24 ++-- docs/reference/vectorization.html | 2 +- docs/reference/withinHumdrum.html | 6 +- docs/reference/wort.html | 2 +- docs/reference/writeHumdrum.html | 2 +- man/chord.Rd | 19 ++- man/chordFunctions.Rd | 12 +- tests/testthat/test-Chords.R | 4 +- tests/testthat/test-Pitch.R | 8 +- tests/testthat/test-Subset.R | 13 +- tests/testthat/test-Within.R | 4 +- 147 files changed, 512 insertions(+), 311 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 10635648..95eac536 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: humdrumR Title: humdrumR -Version: 0.7.0.1 +Version: 0.7.0.2 Authors@R: c(person("Nathaniel", "Condit-Schultz", email = "natcs@gatech.edu", role = c("aut", "cre")), person("Claire", "Arthur", email = "claire.arthur@gatech.edu", role = "aut")) Description: This package is a toolkit for the visualization, manipulation, and analysis of data encoded in the Humdrum syntax ( 0) + extensions <- array(.paste(qualities, extensions), dim = dim(qualities)) + + fig <- apply(extensions, 1, .paste, collapse = ',') + + fig <- paste0('(', fig, ')') + + shorthand <- c('3,5' = 'maj', 'b3,5' = 'min', 'b3,b5' = 'dim', '3,#5' = 'aug', + '3,5,7' = 'maj7', 'b3,5,b7' = 'min7', '3,5,b7' = '7', 'b3,b5,b7' = 'hdim7', 'b3,b5,bb7' = 'dim7', 'b3,5,7' = 'minmaj7', + '3,5,6' = 'maj6', 'b3,5,6' = 'min6', + '3,5,7,9' = 'maj9', 'b3,5,b7,9' = 'min9', '3,5,b7,9' = '9', + '5,11' = 'sus4', '5,9' = 'sus2') + names(shorthand) <- paste0('(1,', names(shorthand), ')') + fig[fig %in% names(shorthand)] <- shorthand[fig[fig %in% names(shorthand)]] + + + + root <- tint2simplepitch(root, flat = flat, ...) + + # bass + bass <- local({ + inverted <- x@Inversion > 0L + bass <- character(length(x)) + bass[inverted] <- paste0('/', extensions[cbind(which(inverted), x@Inversion[inverted] + 1L)]) + bass + + }) + paste0(root, ':', fig, bass) + +} + @@ -1018,7 +1064,6 @@ sciQualities2tset <- function(str, inversion = 0L, ...) { dset <- qualities2dset(chord, steporder = 4L, allow_partial = TRUE, ...) - extension <- sapply(stringr::str_locate_all(str, '[^.]'), \(x) sum(as.integer(2L^(x[, 'start'] - 1L)))) tset(dset@Root, dset@Signature, dset@Alteration, extension = extension, inversion = inversion) @@ -1059,7 +1104,7 @@ figuredBass2tset <- function(x, ...) { figurations <- parseFiguration(figurations) - tsets <- .unlist(figurations[, + tset <- .unlist(figurations[, { tints <- interval2tint(paste0(Accidentals[[1]], Degrees[[1]]), qualities = FALSE) tints <- tints - tints[1] @@ -1067,11 +1112,11 @@ figuredBass2tset <- function(x, ...) { sciDegrees <- paste(tint2specifier(tints, qualities=T, explicitNaturals = TRUE), collapse = '') list(list(sciQualities2tset(sciDegrees, minor = 'm', diminish = 'd', augment = 'A', major = 'M', - inversion = inversion) - tints[inversion + 1L])) + inversion = inversion) - tints[inversion + 1L])) }, by = 1:nrow(figurations)]$V1) - tsets + bass + tset + bass } @@ -1121,7 +1166,6 @@ chord2tset <- function(x, ..., major = 'maj', minor = 'min', augment = 'aug', di if (any(bass != '')) { hasbass <- bass != '' - bassint <- integer(sum(hasbass)) bassint <- getFifth(kern2tint(stringr::str_sub(bass[hasbass], start = 2L))) - getFifth(kern2tint(tonalChroma[hasbass])) tset@Inversion[hasbass] <- c(0L, 2L, 4L, 6L, 1L, 3L, 5L)[bassint %% 7L + 1L] @@ -1130,9 +1174,69 @@ chord2tset <- function(x, ..., major = 'maj', minor = 'min', augment = 'aug', di tset +} + +harte2tset <- function(x, ..., major = 'maj', minor = 'min', augment = 'aug', diminish = 'dim', flat = '-') { + REparse(x, + makeRE.harte(..., major = major, minor = minor, augment = augment, diminish = diminish, + flat = flat, collapse = FALSE), # makes tonalChroma, figqual, bass + toEnv = TRUE) -> parsed + + # shorthand translation + shorthands <- local({ + shorthands <- c(maj = '3,5', min = 'b3,5', aug = '3,#5', dim = 'b3,b5', + '7' = '3,5,b7', maj7 = '3,5,7', min7 = 'b3,5,b7', dim7 = 'b3,b5,bb7', hdim7 = 'b3,b5,b7', minmaj7 = 'b3,5,7', + maj6 = '3,5,6', min6 = 'b3,5,6', + '9' = '3,5,b7,9', maj9 = '3,5,7,9', min9 = 'b3,5,b7,9', + sus2 = '2,5', sus4 = '4,5') + shorthands <- setNames(paste0('(1,', shorthands, ')'), names(shorthands)) + + names(shorthands) <- gsub('maj', major, names(shorthands)) + names(shorthands) <- gsub('min', minor, names(shorthands)) + names(shorthands) <- gsub('aug', augment, names(shorthands)) + names(shorthands) <- gsub('dim', diminish, names(shorthands)) + + shorthands + + + }) + + + fig <- figqual + fig[!grepl('^\\(', figqual)] <- shorthands[figqual[!grepl('^\\(', figqual)]] + + # translate fig to tertian + fig <- gsub('^\\(1,', '', gsub('\\)$', '', fig)) + fig <- strsplit(fig, split = ',') + tertian <- c('P', rep('.', 6)) + ind <- c('3' = 2L, '5' = 3L, '7' = 4L, + '2' = 5L, '9' = 5L, + '4' = 6L, '11' = 6L, + '6' = 7L, '13' = 7L) + tertian <- sapply(unique(fig), + \(fig) { + qualities <- tint2specifier(interval2tint(fig, qualities = FALSE, flat = 'b'), qualities = TRUE, explicitNaturals = TRUE) + + fig <- gsub('[b#]+', '', fig) + tertian[ind[fig]] <- qualities + paste(tertian, collapse = '') + + }) + tset <- sciQualities2tset(tertian, augment = 'A', diminish = 'd')[match(fig, unique(fig))] + + if (any(bass != '')) { + hasbass <- bass != '' + + tset@Inversion[hasbass] <- ind[gsub('\\/b?', '', bass[hasbass])] - 1L + + } + + tset + kern2tint(tonalChroma, flat = flat) + } + ##... Numbers integer2tset <- function(x) tset(x, x) @@ -1208,6 +1312,7 @@ tertianSet.integer <- integer2tset tertianSet.character <- makeHumdrumDispatcher(list('harm', makeRE.harm, harm2tset), list('roman', makeRE.roman, roman2tset), list('figuredBass', makeRE.figuredBass, figuredBass2tset), + list('harte', makeRE.harte, harte2tset), list('any', makeRE.tertian, tertian2tset), list('any', makeRE.chord, chord2tset), funcName = 'tertianSet.character', @@ -1268,11 +1373,15 @@ setAs('tertianSet', 'diatonicSet', function(from) tset(from@Root, from@Signature #' These functions can be used to extract and "translate," or otherwise modify, data representing tertian harmony information. #' The functions are: #' -#' + [chord()] -#' + [figuredBass()] -#' + [harm()] -#' + [roman()] -#' + [tertian()] +#' + Jazz/Pop +#' + [chord()] +#' + [harte()] +#' + Classical +#' + [figuredBass()] +#' + [tertian()] +#' + *Roman Numerals* +#' + [harm()] +#' + [roman()] #' #' @seealso To better understand how these functions work, read about how tertian harmonies are #' [parsed][chordParsing] and [deparsed][chordDeparsing]. @@ -1403,7 +1512,13 @@ NULL #' "Pop/Jazz" chord symbols #' -#' This function outputs a generic "jazz" chord symbol representation of a tonal harmony. +#' These functions outputs jazz/pop-style chord symbols. +#' There is no universal standard for how to notate such chord symbols, in particular in plain text. +#' The `chord()` function outputs a chord symbol representation roughly consistent with "standard practices." +#' +#' For more rigorous, consistent work, we recommend the [Harte](https://github.com/Computational-Cognitive-Musicology-Lab/Star-Wars-Thematic-Corpus) notation, +#' which is the standard used by MIREX, etc. +#' The `harte()` function will output standard Harte symbols. #' #' @examples #' romanNumerals <- c('2I', '2IV7', '1V', '2vi', '2-VI', '2iio7', '2Vb9') @@ -1420,6 +1535,10 @@ NULL #' @export chord <- makeChordTransformer(tset2chord, 'chord') +#' @rdname chord +#' @export +harte <- makeChordTransformer(tset2harte, 'harte') + #' Figured bass representation of harmony #' #' This function outputs a [figured bass](https://en.wikipedia.org/wiki/Figured_bass) diff --git a/R/Keys.R b/R/Keys.R index 8f1268a3..cb947dc4 100644 --- a/R/Keys.R +++ b/R/Keys.R @@ -658,7 +658,7 @@ qualities2dset <- function(x, steporder = 2L, allow_partial = FALSE, modes <- list(c(perfect, perfect, major, major, major, major, augment), c(perfect, perfect, major, major, major, major, perfect), c(perfect, perfect, major, major, major, minor, perfect), - c(perfect, perfect, major, minor, major, minor, perfect), + c(perfect, perfect, major, major, minor, minor, perfect), c(perfect, perfect, major, minor, minor, minor, perfect), c(perfect, perfect, minor, minor, minor, minor, perfect), c(perfect, diminish, minor, minor, minor, minor, perfect)) @@ -709,10 +709,13 @@ qualities2dset <- function(x, steporder = 2L, allow_partial = FALSE, change <- ifelse(which(altered) %in% c(1L, 2L, 7L), # Perfects match(actual, quality.labels[-c(2, 4)]) - match(supposedtobe, quality.labels[-c(2, 4)]), # no M or m match(actual, quality.labels[-3]) - match(supposedtobe, quality.labels[-3])) # no P + if (any(abs(change) > 1L)) change <- sign(change) altermat <- matrix(0L, nrow = 1, ncol = 7) - altermat[((which(altered) - mode) %% 7L) + 1L] <- change + # altermat[ , ((which(altered) - mode - 1L) %% 7L) + 1L] <- change + altered <- which(altered) + altermat[ , (altered %% 7L) + 1L] <- change alterint <- baltern2int(altermat) c(mode = mode, altered = alterint) diff --git a/R/Regex.R b/R/Regex.R index 2224b37f..6e979f2e 100644 --- a/R/Regex.R +++ b/R/Regex.R @@ -543,7 +543,7 @@ makeRE.pc <- function(ten = 'A', eleven = 'B', ...) { #### REs for diatonic sets #### -makeRE.alterations <- function(..., qualities = FALSE) { +makeRE.alterations <- function(..., qualities = FALSE, sep = '') { # names(alteration.labels) <- gsub('augment', 'sharp', names(alteration.labels)) # names(alteration.labels) <- gsub('diminish', 'flat', names(alteration.labels)) @@ -552,8 +552,8 @@ makeRE.alterations <- function(..., qualities = FALSE) { parts = c("species", "step"), step.signed = FALSE, flat = 'b', step.labels = c(1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13), regexname = 'alterations') - - paste0('(', makeRE(..., qualities = qualities, quality.required = FALSE), ')*') + if (sep != '') sep <- paste0(sep, '?') + paste0('(', makeRE(..., qualities = qualities, quality.required = FALSE), sep, ')*') } makeRE.key <- function(..., parts = c("step", "species", "mode", "alterations"), @@ -683,6 +683,43 @@ makeRE.chord <- function(..., major = '[Mm]aj', minor = 'min', augment = 'aug', } +makeRE.harte <- function(..., major = 'maj', minor = 'min', augment = 'aug', diminish = 'dim', + bass.sep = '/', flat = '-', + collapse = TRUE) { + REs <- makeRE.tonalChroma(parts = c("step", "species"), flat = flat, + step.labels = '[A-G]', qualities = FALSE, + step.sign = FALSE, ...) + + REs$colon <- ':' + + + triads <- c(major, minor, augment, diminish) + sevenths <- paste0(c(major, minor, diminish, paste0('h', diminish), paste0(minor, major), ''), + '7') + sixths <- paste0(c(major, minor), '6') + ninths <- paste0(c(major, minor, ''), 9) + sus <- c('sus2', 'sus4') + + quality <-captureRE(c(triads, sevenths,sixths, ninths, sus)) + + figurations <- paste0('\\(', makeRE.alterations(..., step.labels = 1:13, flat = 'b', sep = ','), '\\)') + + REs$figqual <- paste0('(', quality, '|', figurations, ')') + + REs$bass <- paste0('(', bass.sep, + makeRE.tonalChroma(parts = c("species", "step"), flat = 'b', + step.labels = 1:13, qualities = FALSE, + step.sign = FALSE, ...), + ')?') + + REs <- REs[c("tonalChroma", "colon", "figqual", "bass")] + + + + if (collapse) setNames(cREs(REs), 'harte') else REs + +} + makeRE.figuredBass <- function(..., bass.sep = ' ', collapse = TRUE) { REs <- c(bass = unname(makeRE.kern(..., collapse = TRUE)), bass.sep = paste0(bass.sep, '?'), diff --git a/_pkgdown.yml b/_pkgdown.yml index ac2fd70c..ea540eec 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -145,7 +145,6 @@ reference: - key - signature - romanKey - - roman - harm - chord - tertian diff --git a/docs/404.html b/docs/404.html index d1e190d5..52104016 100644 --- a/docs/404.html +++ b/docs/404.html @@ -25,7 +25,7 @@ Georgia Tech CCMLab humdrumR - 0.7.0.1 + 0.7.0.2