diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml new file mode 100644 index 0000000..5a5378a --- /dev/null +++ b/.github/workflows/R-CMD-check.yaml @@ -0,0 +1,24 @@ +on: [push, pull_request] +name: R-CMD-check +jobs: + R-CMD-check: + if: "! contains(github.event.head_commit.message, '[ci skip]')" + + runs-on: ubuntu-latest + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + + steps: + - uses: actions/checkout@v4 + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::rcmdcheck + needs: check + - uses: r-lib/actions/check-r-package@v2 + with: + error-on: '"warning"' diff --git a/DESCRIPTION b/DESCRIPTION index cfc2955..a87ffc1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,4 +9,4 @@ Imports: graphics, utils, audio, crayon License: GPL (>=3) URL: https://github.com/egenn/music Encoding: UTF-8 -RoxygenNote: 7.2.1 +RoxygenNote: 7.3.2 diff --git a/R/build.R b/R/build.R index 0d81ffd..40a5a36 100644 --- a/R/build.R +++ b/R/build.R @@ -8,28 +8,30 @@ lapply(.octave, function(i) paste0(i, -2:8)) pos <- seq(.allnotes) names(pos) <- .allnotes -scaleSteps <- list(major = c(2, 2, 1, 2, 2, 2, 1), - minor = c(2, 1, 2, 2, 1, 2, 2), - dorian = c(2, 1, 2, 2, 2, 1, 2), - phrygian = c(1, 2, 2, 2, 1, 2, 2), - lydian = c(2, 2, 2, 1, 2, 2, 1), - lydianAugmented = c(2, 2, 2, 2, 1, 2, 1), - acoustic = c(2, 2, 2, 1, 2, 1, 2), - mixolydian = c(2, 2, 1, 2, 2, 1, 2), - locrian = c(1, 2, 2, 1, 2, 2, 2), - majorLocrian = c(2, 2, 1, 1, 2, 2, 2), - harmonicMajor = c(2, 2, 1, 2, 1, 3, 1), - harmonicMinor = c(2, 1, 2, 2, 1, 3, 1), - halfDiminished = c(2, 1, 2, 1, 2, 2, 2), - minorPentatonic = c(3, 2, 2, 3, 2), - majorPentatonic = c(2, 2, 3, 2, 3), - blues = c(3, 2, 1, 1, 3, 2), - altered = c(1, 2, 1, 2, 2, 2, 2), - hirajoshi = c(4, 2, 1, 4, 1), - insen = c(1, 4, 2, 4, 2), - algerian = c(2, 1, 3, 1, 1, 3, 1, 2, 1, 2), - hungarian = c(2, 1, 3, 1, 1, 3, 1), - `in` = c(1, 4, 2, 1, 4)) +scaleSteps <- list( + major = c(2, 2, 1, 2, 2, 2, 1), + minor = c(2, 1, 2, 2, 1, 2, 2), + dorian = c(2, 1, 2, 2, 2, 1, 2), + phrygian = c(1, 2, 2, 2, 1, 2, 2), + lydian = c(2, 2, 2, 1, 2, 2, 1), + lydianAugmented = c(2, 2, 2, 2, 1, 2, 1), + acoustic = c(2, 2, 2, 1, 2, 1, 2), + mixolydian = c(2, 2, 1, 2, 2, 1, 2), + locrian = c(1, 2, 2, 1, 2, 2, 2), + majorLocrian = c(2, 2, 1, 1, 2, 2, 2), + harmonicMajor = c(2, 2, 1, 2, 1, 3, 1), + harmonicMinor = c(2, 1, 2, 2, 1, 3, 1), + halfDiminished = c(2, 1, 2, 1, 2, 2, 2), + minorPentatonic = c(3, 2, 2, 3, 2), + majorPentatonic = c(2, 2, 3, 2, 3), + blues = c(3, 2, 1, 1, 3, 2), + altered = c(1, 2, 1, 2, 2, 2, 2), + hirajoshi = c(4, 2, 1, 4, 1), + insen = c(1, 4, 2, 4, 2), + algerian = c(2, 1, 3, 1, 1, 3, 1, 2, 1, 2), + hungarian = c(2, 1, 3, 1, 1, 3, 1), + `in` = c(1, 4, 2, 1, 4) +) #' Build Scale #' @@ -37,103 +39,117 @@ scaleSteps <- list(major = c(2, 2, 1, 2, 2, 2, 1), #' #' @param root String: Root note. e.g. "C4" #' @param scale String: Scale to build. Default = "minor" -#' @param descending Logical: If TRUE, return notes in descending order, +#' @param descending Logical: If TRUE, return notes in descending order, #' otherwise in ascending #' @param plot Logical: If TRUE, plot scale notes using \link{cplot_piano} #' @param play Logical: If TRUE, play scale using \link{playNote} -#' @param pairs Logical: If TRUE and \code{play = TRUE}, play the root note +#' @param pairs Logical: If TRUE and \code{play = TRUE}, play the root note #' along with each other note, in sequence -#' @param formatNotation Logical: If TRUE, format notes to include both flats -#' and sharps to avoid repeating the same letter. e.g. convert c("Gb4", "G4") +#' @param formatNotation Logical: If TRUE, format notes to include both flats +#' and sharps to avoid repeating the same letter. e.g. convert c("Gb4", "G4") #' to c("F#4", "G4") -#' @param ... Additional arguments to be passed to \link{playNote} if +#' @param ... Additional arguments to be passed to \link{playNote} if #' \code{play = TRUE} -#' +#' #' @author E.D. Gennatas #' @export #' @examples #' buildScale("C4", "minor") #' buildScale("B4", "minor", descending = TRUE, plot = TRUE) #' \dontrun{ -#' buildScale("B4", "minor", descending = TRUE, play = TRUE, plot TRUE) +#' buildScale("B4", "minor", descending = TRUE, play = TRUE, plot = TRUE) #' } -buildScale <- function(root, scale = "minor", - descending = FALSE, - plot = TRUE, - play = FALSE, - pairs = FALSE, - formatNotation = TRUE, ...) { - if (missing(root)) { - cat(crayon::silver$bold("Available scales:\n")) - cat(crayon::cyan$bold(paste(names(scaleSteps), collapse = ", ")), "\n") - return(invisible(9)) +buildScale <- function( + root, + scale = "minor", + descending = FALSE, + plot = TRUE, + play = FALSE, + pairs = FALSE, + formatNotation = TRUE, + ... +) { + if (missing(root)) { + cat(crayon::silver$bold("Available scales:\n")) + cat(crayon::cyan$bold(paste(names(scaleSteps), collapse = ", ")), "\n") + return(invisible(64)) + } else { + root <- formatNote(root) + } + scale <- match.arg(scale, names(scaleSteps)) + root.pos <- pos[root] + .scale.pos <- cumsum(c(root.pos, scaleSteps[[scale]])) + + .notes <- .allnotes[.scale.pos] + if (descending) { + .notes <- rev(.notes) + } + + if (play) { + if (!pairs) { + playNote(.notes, ...) } else { - root <- formatNote(root) - } - scale <- match.arg(scale, names(scaleSteps)) - root.pos <- pos[root] - .scale.pos <- cumsum(c(root.pos, scaleSteps[[scale]])) - - .notes <- .allnotes[.scale.pos] - if (descending) .notes <- rev(.notes) - - if (play) { - if (!pairs) { - playNote(.notes, ...) - } else { - .progression <- lapply( - seq(.notes)[-1], - function(i) strings(paste(root, .notes[i])) - ) - playProgression(.progression, ...) - } + .progression <- lapply( + seq(.notes)[-1], + function(i) strings(paste(root, .notes[i])) + ) + playProgression(.progression, ...) } + } - .notes1 <- if (formatNotation) formatNotation(.notes) else .notes - if (plot) { - cat(blue$bold(" ", root, scale, "scale\n")) - cplot_piano(.notes1) - return(invisible(.notes1)) - } + .notes1 <- if (formatNotation) { + formatNotation(.notes) + } else { + .notes + } + if (plot) { + cat(blue$bold(" ", root, scale, "scale\n")) + cplot_piano(.notes1) + return(invisible(.notes1)) + } - .notes1 + .notes1 } # music::buildScale -stepsByDegree <- list(`1` = 0, - `2` = 2, - b3 = 3, - `3` = 4, - `4` = 5, - b5 = 6, - `5` = 7, - `#5` = 8, - `6` = 9, - b7 = 10, - `7` = 11) - -chordSteps <- list(major = c(4, 3), - minor = c(3, 4), - sus2 = c(2, 5), - sus4 = c(5, 2), - `7th` = c(4, 3, 3), - major7th = c(4, 3, 4), - minor7th = c(3, 4, 3), - `6th` = c(4, 3, 2), - minor6th = c(3, 4, 2), - diminished = c(3, 3), - diminished7th = c(3, 3, 3), - halfDiminished7th = c(3, 3, 4), - augmented = c(4, 4), - `7th#5` = c(4, 4, 2), - `9th` = c(4, 3, 3, 4), - `7th#9` = c(4, 3, 3, 5), - major9th = c(4, 3, 4, 3), - added9th = c(4, 3, 7), - minor9th = c(3, 4, 3, 4), - minorAdd9th = c(3, 4, 7), - `5th` = 7, - flat5th = c(4, 2)) +stepsByDegree <- list( + `1` = 0, + `2` = 2, + b3 = 3, + `3` = 4, + `4` = 5, + b5 = 6, + `5` = 7, + `#5` = 8, + `6` = 9, + b7 = 10, + `7` = 11 +) + +chordSteps <- list( + major = c(4, 3), + minor = c(3, 4), + sus2 = c(2, 5), + sus4 = c(5, 2), + `7th` = c(4, 3, 3), + major7th = c(4, 3, 4), + minor7th = c(3, 4, 3), + `6th` = c(4, 3, 2), + minor6th = c(3, 4, 2), + diminished = c(3, 3), + diminished7th = c(3, 3, 3), + halfDiminished7th = c(3, 3, 4), + augmented = c(4, 4), + `7th#5` = c(4, 4, 2), + `9th` = c(4, 3, 3, 4), + `7th#9` = c(4, 3, 3, 5), + major9th = c(4, 3, 4, 3), + added9th = c(4, 3, 7), + minor9th = c(3, 4, 3, 4), + minorAdd9th = c(3, 4, 7), + `5th` = 7, + flat5th = c(4, 2) +) chords <- list() @@ -143,55 +159,71 @@ chords <- list() #' @param chord String: Chord to build. Default = "minor" #' @param plot Logical: If TRUE, plot chord notes using \link{cplot_piano} #' @param play Logical: If TRUE, play chord using \link{playChord} -#' @param formatNotation Logical: If TRUE, format notes to include both flats -#' and sharps to avoid repeating the same letter. e.g. convert c("Gb4", "G4") to +#' @param formatNotation Logical: If TRUE, format notes to include both flats +#' and sharps to avoid repeating the same letter. e.g. convert c("Gb4", "G4") to #' c("F#4", "G4") -#' @param ... Additional arguments to be passed to \link{playChord} if +#' @param ... Additional arguments to be passed to \link{playChord} if #' \code{play = TRUE} -#' +#' +#' @author E.D. Gennatas +#' @export #' @examples #' buildChord("C4", "minor") #' buildChord("A4", "sus2", plot = TRUE) #' \dontrun{ #' buildChord("B4", "sus2", play = TRUE) #' } -#' @export -#' @author E.D. Gennatas -buildChord <- function(root, chord = "minor", - plot = TRUE, - play = FALSE, - formatNotation = TRUE, ...) { - if (missing(root)) { - cat(crayon::silver$bold("Available chords:\n")) - cat(crayon::cyan$bold(paste(names(chordSteps), collapse = ", ")), "\n") - return(invisible(9)) - } else { - root <- formatNote(root) - } - chord <- match.arg(chord, names(chordSteps)) - root.pos <- pos[root] - .chord.pos <- cumsum(c(root.pos, chordSteps[[chord]])) - .chord <- .allnotes[.chord.pos] - if (play) playChord(.chord, ...) - .chord1 <- if (formatNotation) formatNotation(.chord) else .chord - if (plot) { - cat(blue$bold(" ", root, chord, "chord\n")) - cplot_piano(.chord1) - return(invisible(.chord1)) - } - .chord1 +buildChord <- function( + root, + chord = "minor", + plot = TRUE, + play = FALSE, + formatNotation = TRUE, + ... +) { + if (missing(root)) { + cat(crayon::silver$bold("Available chords:\n")) + cat(crayon::cyan$bold(paste(names(chordSteps), collapse = ", ")), "\n") + return(invisible(64)) + } else { + root <- formatNote(root) + } + chord <- match.arg(chord, names(chordSteps)) + root.pos <- pos[root] + .chord.pos <- cumsum(c(root.pos, chordSteps[[chord]])) + .chord <- .allnotes[.chord.pos] + if (play) { + playChord(.chord, ...) + } + .chord1 <- if (formatNotation) formatNotation(.chord) else .chord + if (plot) { + cat(blue$bold(" ", root, chord, "chord\n")) + cplot_piano(.chord1) + return(invisible(.chord1)) + } + .chord1 } # music::buildChord chordProgression <- list( - major = c( - "major", "minor", "minor", "major", - "major", "minor", "diminished" - ), - minor = c( - "minor", "diminished", "major", "minor", - "minor", "major", "major" - ) + major = c( + "major", + "minor", + "minor", + "major", + "major", + "minor", + "diminished" + ), + minor = c( + "minor", + "diminished", + "major", + "minor", + "minor", + "major", + "major" + ) ) #' Build Chord Progression @@ -202,50 +234,54 @@ chordProgression <- list( #' \link{cplot_piano} #' @param play Logical: If TRUE, play scale using \link{playProgression} #' @param formatNotation Logical: If TRUE, format notes to include both flats a -#' nd sharps to avoid repeating the same letter. e.g. convert c("Gb4", "G4") to +#' nd sharps to avoid repeating the same letter. e.g. convert c("Gb4", "G4") to #' c("F#4", "G4") -#' @param ... Additional arguments to be passed to \link{playProgression} if +#' @param ... Additional arguments to be passed to \link{playProgression} if #' \code{ play = TRUE} -#' +#' +#' @author E.D. Gennatas +#' @export #' @examples #' buildProgression("C4", "minor") #' buildProgression("Bb4", "major") #' \dontrun{ #' buildProgression("Bb4", "major", play = TRUE, plot = TRUE) #' } -#' @export -#' @author E.D. Gennatas - -buildProgression <- function(root = "A4", - scale = "minor", - plot = FALSE, - play = FALSE, - formatNotation = TRUE, ...) { +buildProgression <- function( + root = "A4", + scale = "minor", + plot = FALSE, + play = FALSE, + formatNotation = TRUE, + ... +) { root <- formatNote(root) .scale <- buildScale(root = root, scale = scale, plot = FALSE) .progression <- chordProgression[[scale]] .progression <- c(.progression, .progression[1]) .chords <- lapply( - seq(.scale), - function(i) { - buildChord( - root = .scale[i], - chord = .progression[i], - formatNotation = formatNotation, - plot = plot - ) - } + seq(.scale), + function(i) { + buildChord( + root = .scale[i], + chord = .progression[i], + formatNotation = formatNotation, + plot = plot + ) + } ) names(.chords) <- paste0(.scale, .progression) - if (play) playProgression(.chords) -# if (plot) { -# for (i in seq(.chords)) { -# cplot_piano(.chords[[i]]) -# cat("\n") -# } -# } - .chords + if (play) { + playProgression(.chords) + } + # if (plot) { + # for (i in seq(.chords)) { + # cplot_piano(.chords[[i]]) + # cat("\n") + # } + # } + .chords } # music::buildProgression diff --git a/R/play.R b/R/play.R index 4da3116..3dbc2f1 100644 --- a/R/play.R +++ b/R/play.R @@ -1,30 +1,40 @@ # play.R # ::music:: -# 2019 E.D. Gennatas lambdamd.org +# 2019- E.D. Gennatas lambdamd.org #' Minimal "Polyphonic" Wave Player #' #' Play one or more waveforms at the same time using \code{audio::play} #' -#' @param wave Matrix or vector of waveforms. If a matrix, each column should +#' @param wave Matrix or vector of waveforms. If a matrix, each column should #' be a waveform to be played simultaneously #' @param sample.rate Integer: Sample rate. Default = 44100 #' @param plot Logical: If TRUE: plot wave using \link{mplot}. + +#' @author E.D. Gennatas +#' @export #' @examples #' \dontrun{ #' playWave(freq2wave(440)) #' } -#' @export -#' @author E.D. Gennatas -playWave <- function(wave, - sample.rate = 44100, - plot = FALSE) { - if (is.null(dim(wave))) wave <- matrix(wave, ncol = 1) - n.notes <- NCOL(wave) - for (i in seq(n.notes)) audio::play(wave[, i], rate = sample.rate) +playWave <- function(wave, sample.rate = 44100, plot = FALSE) { + if (is.null(dim(wave))) { + wave <- matrix(wave, ncol = 1) + } + n.notes <- NCOL(wave) - if (plot) mplot(wave) + # Plot + if (plot) { + mplot(wave) + } + + # Combine waves + if (n.notes > 1) { + wave <- rowSums(wave) + } + + audio::play(wave, rate = sample.rate) } # music::playWave @@ -36,38 +46,42 @@ playWave <- function(wave, #' @param BPM Integer: Beats per minute. Default = 120 #' @param sample.rate Integer: Sample rate. Default = 44100 #' @param attack.time Integer: Attack time. Default = 50 (Helps prevent popping) -#' @param inner.release.time Integer: Release time, that ends on note OFF +#' @param inner.release.time Integer: Release time, that ends on note OFF #' (instead of beginning at note OFF). Default = 50 (Also helps prevent popping) #' @param plot Logical: If TRUE, plot waveform #' +#' @author E.D. Gennatas +#' @export #' @examples #' \dontrun{ #' playFreq(440) #' } -#' @export -#' @author E.D. Gennatas -playFreq <- function(frequency, - oscillator = "sine", - duration = rep(1, length(frequency)), - BPM = 120, - sample.rate = 44100, - attack.time = 50, - inner.release.time = 50, - plot = FALSE) { - wave <- unlist(c(mapply( - freq2wave, - frequency, - oscillator, - duration, - BPM, - sample.rate, - attack.time, - inner.release.time - ))) - - if (plot) mplot(wave) - playWave(wave) +playFreq <- function( + frequency, + oscillator = "sine", + duration = rep(1, length(frequency)), + BPM = 120, + sample.rate = 44100, + attack.time = 50, + inner.release.time = 50, + plot = FALSE +) { + wave <- unlist(c(mapply( + freq2wave, + frequency, + oscillator, + duration, + BPM, + sample.rate, + attack.time, + inner.release.time + ))) + + if (plot) { + mplot(wave) + } + playWave(wave) } # music::playFreq #' Play Note @@ -75,40 +89,45 @@ playFreq <- function(frequency, #' @inheritParams playFreq #' @inheritParams note2freq #' @param note String, Vector: Note(s) to be played, e.g. c("Ab4", "B4") -#' @param plot Logical: If TRUE, plot notes using \link{cplot_piano}. This -#' supports only two octaves; do not try plotting if your notes span more than +#' @param plot Logical: If TRUE, plot notes using \link{cplot_piano}. This +#' supports only two octaves; do not try plotting if your notes span more than #' two octaves. #' @param ... Additional arguments to pass to \link{note2freq} +#' +#' @author E.D. Gennatas +#' @export #' @examples #' \dontrun{ #' playNote("B4") #' } -#' @export -#' @author E.D. Gennatas -playNote <- function(note, - oscillator = "sine", - duration = rep(1, length(note)), - BPM = 120, - sample.rate = 44100, - attack.time = 50, - inner.release.time = 50, - A4 = 440, - plot = FALSE, ...) { - freqs <- note2freq(note, - A4 = A4, ... - ) - - if (plot) cplot_piano(note) - - playFreq(freqs, - oscillator = oscillator, - duration = duration, - BPM = BPM, - sample.rate = sample.rate, - attack.time = attack.time, - inner.release.time = inner.release.time - ) +playNote <- function( + note, + oscillator = "sine", + duration = rep(1, length(note)), + BPM = 120, + sample.rate = 44100, + attack.time = 50, + inner.release.time = 50, + A4 = 440, + plot = FALSE, + ... +) { + freqs <- note2freq(note, A4 = A4, ...) + + if (plot) { + cplot_piano(note) + } + + playFreq( + freqs, + oscillator = oscillator, + duration = duration, + BPM = BPM, + sample.rate = sample.rate, + attack.time = attack.time, + inner.release.time = inner.release.time + ) } # music::playNote @@ -117,95 +136,109 @@ playNote <- function(note, #' @inheritParams playNote #' @param chord String, vector: Notes making up chord. e.g. c("A4", "C5", "E5"). #' e.g. output of \link{buildChord} -#' @param type String: "harmonic", "ascending", "descending". +#' @param type String: "harmonic", "ascending", "descending". #' Default = "harmonic" #' @param plot Logical: If TRUE, plot chord using \link{cplot_piano} -#' @export +#' #' @return The constructed waveform (invisibly) +#' +#' @author E.D. Gennatas +#' @export #' @examples #' \dontrun{ #' playChord(buildChord("E4", "minor")) #' } -#' @author E.D. Gennatas - -playChord <- function(chord, - type = c("harmonic", "ascending", "descending"), - oscillator = "sine", - duration = 1, - sample.rate = 44100, - attack.time = 50, - inner.release.time = 50, - A4 = 440, - plot = FALSE, ...) { - type <- match.arg(type) - - wave <- lapply(chord, function(i) { - freq2wave(note2freq(i, A4 = A4, ...), - oscillator = oscillator, - duration = duration, - sample.rate = sample.rate, - attack.time = attack.time, - inner.release.time = inner.release.time - ) - }) - wave <- switch(type, - harmonic = do.call(cbind, wave), - ascending = do.call(c, wave), - descending = do.call(c, rev(wave)) +playChord <- function( + chord, + type = c("harmonic", "ascending", "descending"), + oscillator = "sine", + duration = 1, + sample.rate = 44100, + attack.time = 50, + inner.release.time = 50, + A4 = 440, + plot = FALSE, + ... +) { + type <- match.arg(type) + + wave <- lapply(chord, function(i) { + freq2wave( + note2freq(i, A4 = A4, ...), + oscillator = oscillator, + duration = duration, + sample.rate = sample.rate, + attack.time = attack.time, + inner.release.time = inner.release.time ) - - if (plot) cplot_piano(chord) - playWave(wave) - invisible(wave) + }) + + wave <- switch( + type, + harmonic = do.call(cbind, wave), + ascending = do.call(c, wave), + descending = do.call(c, rev(wave)) + ) + + if (plot) { + cplot_piano(chord) + } + playWave(wave) + invisible(wave) } # music::playChord #' Play Progression #' #' @inheritParams playNote -#' @param progression List of string vectors: Each element of the list is a +#' @param progression List of string vectors: Each element of the list is a #' chord. e.g. output of \link{buildProgression} -#' @param plot Logical. If TRUE, plot each chord in the progression using +#' @param plot Logical. If TRUE, plot each chord in the progression using #' \link{cplot_piano} +#' +#' @author E.D. Gennatas #' @export #' @examples #' \dontrun{ #' playProgression(buildProgression("G4", "minor")) #' } -#' @author E.D. Gennatas -playProgression <- function(progression, - oscillator = c("sine", "square", "saw", "triangle"), - duration = 1, - BPM = 120, - sample.rate = 44100, - attack.time = 50, - inner.release.time = 50, - A4 = 440, - plot = FALSE, ...) { - oscillator <- match.arg(oscillator) - wave <- lapply(progression, function(i) { - do.call( - cbind, - lapply(i, function(j) { - freq2wave(note2freq(j, A4 = A4, ...), - oscillator = oscillator, - duration = duration, - BPM = BPM, - sample.rate = sample.rate, - attack.time = attack.time, - inner.release.time = inner.release.time - ) - }) +playProgression <- function( + progression, + oscillator = c("sine", "square", "saw", "triangle"), + duration = 1, + BPM = 120, + sample.rate = 44100, + attack.time = 50, + inner.release.time = 50, + A4 = 440, + plot = FALSE, + ... +) { + oscillator <- match.arg(oscillator) + wave <- lapply(progression, function(i) { + do.call( + cbind, + lapply(i, function(j) { + freq2wave( + note2freq(j, A4 = A4, ...), + oscillator = oscillator, + duration = duration, + BPM = BPM, + sample.rate = sample.rate, + attack.time = attack.time, + inner.release.time = inner.release.time ) - }) - wave <- do.call(rbind, wave) - playWave(wave) - if (plot) { - for (i in seq(progression)) { - cplot_piano(progression[[i]]) - cat("\n") - } + }) + ) + }) + wave <- do.call(rbind, wave) + playWave(wave) + if (plot) { + for (i in seq(progression)) { + cplot_piano(progression[[i]]) + cat("\n") } + } } # playProgression diff --git a/R/zzz.R b/R/zzz.R index fdff817..f474964 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -12,19 +12,24 @@ #' on twelve-tone equal temperament tuning (12ET). Custom tuning can be defined #' by specifying frequency ratios and a root note. See \link{note2freq}. #' A4 defaults to 440Hz, and can be changed with the 'A4' argument. -#' @docType package +#' #' @name music-package #' @import graphics utils crayon +"_PACKAGE" NULL .onAttach <- function(libname, pkgname) { - music.ver <- read.dcf( - file = system.file("DESCRIPTION", package = pkgname), - fields = "Version" - ) - packageStartupMessage(paste0( - " .:", pkgname, " v", music.ver, - " \U1F3A7 Welcome, ", Sys.getenv("USER") - )) + music.ver <- read.dcf( + file = system.file("DESCRIPTION", package = pkgname), + fields = "Version" + ) + packageStartupMessage(paste0( + " .:", + pkgname, + " v", + music.ver, + " \U1F3A7 Welcome, ", + Sys.getenv("USER") + )) } diff --git a/Readme.md b/Readme.md index c880ae8..88b016f 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,5 @@ # **music** R package - -[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Build Status](https://travis-ci.com/egenn/music.svg?branch=master)](https://travis-ci.com/egenn/music) [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/egenn/music?branch=master&svg=true)](https://ci.appveyor.com/project/egenn/music) [![codecov](https://codecov.io/gh/egenn/music/branch/master/graph/badge.svg)](https://codecov.io/gh/egenn/music) +[![R-CMD-check](https://github.com/egenn/music/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/egenn/music/actions/workflows/R-CMD-check.yaml) [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/egenn/music?branch=master&svg=true)](https://ci.appveyor.com/project/egenn/music) [![codecov](https://codecov.io/gh/egenn/music/branch/master/graph/badge.svg)](https://codecov.io/gh/egenn/music) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![CRAN](https://www.r-pkg.org/badges/version/music)](https://cran.r-project.org/package=music) ![](http://cranlogs.r-pkg.org/badges/grand-total/music) diff --git a/man/freq2wave.Rd b/man/freq2wave.Rd index e3b5865..79853ab 100644 --- a/man/freq2wave.Rd +++ b/man/freq2wave.Rd @@ -28,7 +28,7 @@ freq2wave( \item{attack.time}{Integer: Attack time. Default = 50 (Helps prevent popping)} -\item{inner.release.time}{Integer: Release time, that ends on note OFF +\item{inner.release.time}{Integer: Release time, that ends on note OFF (instead of beginning at note OFF). Default = 50 (Also helps prevent popping)} \item{plot}{Logical: If TRUE, plot wave(s) using \link{mplot}} diff --git a/man/music-package.Rd b/man/music-package.Rd index 3a74c8e..e4c817c 100644 --- a/man/music-package.Rd +++ b/man/music-package.Rd @@ -2,15 +2,27 @@ % Please edit documentation in R/zzz.R \docType{package} \name{music-package} +\alias{music} \alias{music-package} \title{\pkg{music}: Learn and use music theory} \description{ -The music package allows you to build, play, and visualize scales, chords, +The music package allows you to build, play, and visualize scales, chords, and chord progression. -For playback, \pkg{music} builds waveforms as matrices and passes them to +For playback, \pkg{music} builds waveforms as matrices and passes them to the \pkg{audio} package which interfaces with the system's audio driver. -The default notation and frequencies used throughout the package are based -on twelve-tone equal temperament tuning (12ET). Custom tuning can be defined +The default notation and frequencies used throughout the package are based +on twelve-tone equal temperament tuning (12ET). Custom tuning can be defined by specifying frequency ratios and a root note. See \link{note2freq}. A4 defaults to 440Hz, and can be changed with the 'A4' argument. } +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/egenn/music} +} + +} +\author{ +\strong{Maintainer}: Efstathios D. Gennatas \email{gennatas@gmail.com} + +} diff --git a/man/playChord.Rd b/man/playChord.Rd index 029ba78..2c34a39 100644 --- a/man/playChord.Rd +++ b/man/playChord.Rd @@ -21,7 +21,7 @@ playChord( \item{chord}{String, vector: Notes making up chord. e.g. c("A4", "C5", "E5"). e.g. output of \link{buildChord}} -\item{type}{String: "harmonic", "ascending", "descending". +\item{type}{String: "harmonic", "ascending", "descending". Default = "harmonic"} \item{oscillator}{String: "sine", "square", "saw". Default = "sine"} @@ -32,7 +32,7 @@ Default = "harmonic"} \item{attack.time}{Integer: Attack time. Default = 50 (Helps prevent popping)} -\item{inner.release.time}{Integer: Release time, that ends on note OFF +\item{inner.release.time}{Integer: Release time, that ends on note OFF (instead of beginning at note OFF). Default = 50 (Also helps prevent popping)} \item{A4}{Float: Frequency for A4 in Hz. Default = 440} diff --git a/man/playFreq.Rd b/man/playFreq.Rd index 15eb04a..961358b 100644 --- a/man/playFreq.Rd +++ b/man/playFreq.Rd @@ -28,7 +28,7 @@ playFreq( \item{attack.time}{Integer: Attack time. Default = 50 (Helps prevent popping)} -\item{inner.release.time}{Integer: Release time, that ends on note OFF +\item{inner.release.time}{Integer: Release time, that ends on note OFF (instead of beginning at note OFF). Default = 50 (Also helps prevent popping)} \item{plot}{Logical: If TRUE, plot waveform} diff --git a/man/playNote.Rd b/man/playNote.Rd index 53f4c69..2656f9c 100644 --- a/man/playNote.Rd +++ b/man/playNote.Rd @@ -30,13 +30,13 @@ playNote( \item{attack.time}{Integer: Attack time. Default = 50 (Helps prevent popping)} -\item{inner.release.time}{Integer: Release time, that ends on note OFF +\item{inner.release.time}{Integer: Release time, that ends on note OFF (instead of beginning at note OFF). Default = 50 (Also helps prevent popping)} \item{A4}{Float: Frequency for A4 in Hz. Default = 440} -\item{plot}{Logical: If TRUE, plot notes using \link{cplot_piano}. This -supports only two octaves; do not try plotting if your notes span more than +\item{plot}{Logical: If TRUE, plot notes using \link{cplot_piano}. This +supports only two octaves; do not try plotting if your notes span more than two octaves.} \item{...}{Additional arguments to pass to \link{note2freq}} diff --git a/man/playProgression.Rd b/man/playProgression.Rd index d801bb8..6d827f7 100644 --- a/man/playProgression.Rd +++ b/man/playProgression.Rd @@ -18,7 +18,7 @@ playProgression( ) } \arguments{ -\item{progression}{List of string vectors: Each element of the list is a +\item{progression}{List of string vectors: Each element of the list is a chord. e.g. output of \link{buildProgression}} \item{oscillator}{String: "sine", "square", "saw". Default = "sine"} @@ -31,12 +31,12 @@ chord. e.g. output of \link{buildProgression}} \item{attack.time}{Integer: Attack time. Default = 50 (Helps prevent popping)} -\item{inner.release.time}{Integer: Release time, that ends on note OFF +\item{inner.release.time}{Integer: Release time, that ends on note OFF (instead of beginning at note OFF). Default = 50 (Also helps prevent popping)} \item{A4}{Float: Frequency for A4 in Hz. Default = 440} -\item{plot}{Logical. If TRUE, plot each chord in the progression using +\item{plot}{Logical. If TRUE, plot each chord in the progression using \link{cplot_piano}} \item{...}{Additional arguments to pass to \link{note2freq}} diff --git a/man/playWave.Rd b/man/playWave.Rd index 596d39a..de2b010 100644 --- a/man/playWave.Rd +++ b/man/playWave.Rd @@ -7,7 +7,7 @@ playWave(wave, sample.rate = 44100, plot = FALSE) } \arguments{ -\item{wave}{Matrix or vector of waveforms. If a matrix, each column should +\item{wave}{Matrix or vector of waveforms. If a matrix, each column should be a waveform to be played simultaneously} \item{sample.rate}{Integer: Sample rate. Default = 44100}