Skip to content

Commit

Permalink
Merge pull request #20 from pmcharrison/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
pmcharrison committed Apr 8, 2021
2 parents ae0af56 + a6798a4 commit 82e034a
Show file tree
Hide file tree
Showing 30 changed files with 744 additions and 51 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: hrep
Title: Harmony Representations
Version: 0.12.1
Version: 0.14.0
Authors@R: person("Peter", "Harrison", email = "pmc.harrison@gmail.com", role = c("aut", "cre"))
Description: This package provides utilities for representing and manipulating
chord sequences for perceptually informed harmony modelling.
Expand Down
18 changes: 18 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
S3method("[",coded_vec)
S3method("[",corpus)
S3method("[",vec)
S3method("[",wave)
S3method("[<-",coded_vec)
S3method("[<-",corpus)
S3method("[<-",vec)
Expand Down Expand Up @@ -32,6 +33,7 @@ S3method(as.character,pc_set)
S3method(as.character,pi_chord)
S3method(as.data.frame,smooth_spectrum)
S3method(as.data.frame,sparse_spectrum)
S3method(as.data.frame,wave)
S3method(as.integer,pc_chord)
S3method(as.list,corpus)
S3method(as.list,vec)
Expand All @@ -42,6 +44,8 @@ S3method(as.numeric,pi_chord)
S3method(c,chord)
S3method(c,corpus)
S3method(c,smooth_spectrum)
S3method(concatenate,list)
S3method(concatenate,wave)
S3method(edit_bass_pc,pc_chord)
S3method(encode,coded_vec)
S3method(encode,corpus)
Expand All @@ -53,6 +57,10 @@ S3method(encode,vec)
S3method(expand_harmonics,pi_chord)
S3method(expand_harmonics,sparse_fr_spectrum)
S3method(expand_harmonics,sparse_pi_spectrum)
S3method(filter_adsr,default)
S3method(filter_adsr,wave)
S3method(filter_spectrum,default)
S3method(filter_spectrum,sparse_fr_spectrum)
S3method(fr_chord,character)
S3method(fr_chord,chord)
S3method(fr_chord,fr_chord)
Expand Down Expand Up @@ -94,6 +102,7 @@ S3method(num_elements,coded_vec)
S3method(num_elements,corpus)
S3method(num_elements,vec)
S3method(num_sequences,corpus)
S3method(pad,wave)
S3method(pc,sparse_pc_spectrum)
S3method(pc_chord,character)
S3method(pc_chord,chord)
Expand Down Expand Up @@ -172,6 +181,7 @@ S3method(save_wav_sox,pi_chord)
S3method(save_wav_sox,sparse_fr_spectrum)
S3method(save_wav_sox,sparse_pi_spectrum)
S3method(save_wav_sox,vec)
S3method(set_labels,sparse_spectrum)
S3method(smooth_pc_spectrum,default)
S3method(smooth_pc_spectrum,sparse_pc_spectrum)
S3method(smooth_pi_spectrum,default)
Expand Down Expand Up @@ -236,6 +246,7 @@ export(amplitude_to_dB)
export(ascending_pc_dist)
export(coded_vec)
export(combine_sparse_spectra)
export(concatenate)
export(corpus)
export(cosine_similarity)
export(dB_to_amplitude)
Expand All @@ -250,6 +261,9 @@ export(encode_pc_chord)
export(encode_pc_chord_type)
export(encode_pc_set)
export(expand_harmonics)
export(filter_adsr)
export(filter_spectrum)
export(filter_spectrum_gaussian)
export(fr_chord)
export(freq)
export(freq_to_midi)
Expand Down Expand Up @@ -277,6 +291,7 @@ export(is.sparse_fr_spectrum)
export(is.sparse_pc_spectrum)
export(is.sparse_pi_spectrum)
export(is.vec)
export(is.wave)
export(label)
export(list_chords)
export(low_eq)
Expand All @@ -288,6 +303,7 @@ export(milne_pc_spec_dist)
export(milne_pc_spectrum)
export(num_elements)
export(num_sequences)
export(pad)
export(pc)
export(pc_chord)
export(pc_chord_type)
Expand All @@ -306,6 +322,8 @@ export(represent)
export(sample_rate)
export(save_wav)
export(save_wav_sox)
export(set_labels)
export(silence)
export(smooth_pc_spectrum)
export(smooth_pi_spectrum)
export(sparse_fr_spectrum)
Expand Down
17 changes: 17 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
# hrep 0.14.0

- Add `[.wave` method.
- Add `silence` function.
- Add `concatenate` method for waves.
- Add `pad` method for waves.
- Improve sparse spectrum plotting.
- Implement spectral filters.
- Implement ADSR filter.
- Implement `as.data.frame.wave`.
- `wave` now supports the argument `phase`.
- Bugfix in propagating spectrum labels.

# hrep 0.13.0

- Support plotting harmonic numbers.

# hrep 0.12.1

- Exported `play_wav`.
Expand Down
27 changes: 19 additions & 8 deletions R/expand-harmonics.R
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@
#' @param digits
#' Number of digits to which each partial's MIDI pitch should be rounded.
#'
#' @param label_harmonics
#' If TRUE, then the harmonics in the resulting spectrum are labelled with their harmonic numbers.
#'
#' @rdname expand_harmonics
#' @export
expand_harmonics <- function(x,
num_harmonics = 11L,
roll_off = 1,
digits = 6) {
digits = 6,
label_harmonics = FALSE) {
UseMethod("expand_harmonics")
}

Expand All @@ -33,11 +37,13 @@ expand_harmonics <- function(x,
expand_harmonics.sparse_fr_spectrum <- function(x,
num_harmonics = 11L,
roll_off = 1,
digits = 6) {
digits = 6,
label_harmonics = FALSE) {
expand_harmonics(sparse_pi_spectrum(x),
num_harmonics = num_harmonics,
roll_off = roll_off,
digits = digits) %>%
digits = digits,
label_harmonics = label_harmonics) %>%
sparse_fr_spectrum()
}

Expand All @@ -46,30 +52,35 @@ expand_harmonics.sparse_fr_spectrum <- function(x,
expand_harmonics.sparse_pi_spectrum <- function(x,
num_harmonics = 11L,
roll_off = 1,
digits = 6) {
digits = 6,
label_harmonics = FALSE) {
template <- pi_harmonic_template(num_harmonics, roll_off)

purrr::map2(pitch(x), amp(x),
function(pitch, amp) {
data.frame(
df <- data.frame(
x = pitch + template$interval,
y = amp * template$amplitude
)
if (label_harmonics) df$labels <- seq_along(template$interval)
df
}) %>%
collapse_summing_amplitudes(digits = digits) %>%
{.sparse_pi_spectrum(pitch = .$x, amplitude = .$y)}
{.sparse_pi_spectrum(pitch = .$x, amplitude = .$y, labels = .$labels)}
}

#' @rdname expand_harmonics
#' @export
expand_harmonics.pi_chord <- function(x,
num_harmonics = 11L,
roll_off = 1,
digits = 6) {
digits = 6,
label_harmonics = FALSE) {
sparse_pi_spectrum(x,
num_harmonics = num_harmonics,
roll_off = roll_off,
digits = digits)
digits = digits,
label_harmonics = label_harmonics)
}

pi_harmonic_template <- function(num_harmonics, roll_off, digits = 6) {
Expand Down
102 changes: 102 additions & 0 deletions R/filter-adsr.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#' ADSR
#'
#' Filters an object through the Attack-Decay-Sustain-Release (ADSR) envelope model,
#' implemented with linear interpolation.
#'
#' @param x
#' Object to filter; will be coerced to a wave object via \code{\link{wave}}.
#'
#' @param attack
#' (Positive numeric scalar)
#' Duration of the attack portion, in seconds.
#' At the end of the attack portion, the envelope amplitude reaches 1.
#'
#' @param decay
#' (Positive numeric scalar)
#' Duration of the decay portion, in seconds.
#'
#' @param sustain
#' (Numeric scalar between 0 and 1)
#' Envelope amplitude during the sustain portion.
#'
#'
#' @param hold
#' (Positive numeric scalar)
#' Duration of the sustain portion, in seconds.
#'
#' @param release
#' (Positive numeric scalar)
#' Duration of the release portion, in seconds.
#'
#' @inheritDotParams wave
#'
#' @rdname filter_adsr
#' @export
filter_adsr <- function(
x,
attack,
decay,
sustain,
hold,
release,
...
) {
checkmate::qassert(attack, "N1[0,)")
checkmate::qassert(decay, "N1[0,)")
checkmate::qassert(sustain, "N1[0,1]")
checkmate::qassert(hold, "N1[0,)")
checkmate::qassert(release, "N1[0,)")
UseMethod("filter_adsr")
}

#' @export
filter_adsr.default <- function(
x,
attack,
decay,
sustain,
hold,
release,
...
) {
filter_adsr.wave(
wave(x, ...),
attack = attack,
decay = decay,
sustain = sustain,
hold = hold,
release = release
)
}

#' @rdname filter_adsr
#' @export
filter_adsr.wave <- function(
x,
attack,
decay,
sustain,
hold,
release,
...
) {
if (attack == 0) attack <- 1e-10
if (decay == 0) decay <- 1e-10
if (hold == 0) hold <- 1e-10
if (release == 0) release <- 1e-10

anchors <- tibble::tribble(
~ time, ~ amplitude,
0, 0,
attack, 1,
attack + decay, sustain,
attack + decay + hold, sustain,
attack + decay + hold + release, 0
)
anchors$sample <- 1 + anchors$time * sample_rate(x)
envelope <- stats::approx(x = anchors$sample,
y = anchors$amplitude,
xout = seq_along(x),
rule = 2)$y
x * envelope
}
8 changes: 5 additions & 3 deletions R/sparse-fr-spectrum.R
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#' @keywords internal
.sparse_fr_spectrum <- function(frequency, amplitude) {
.sparse_fr_spectrum <- function(frequency, amplitude, labels = NULL) {
checkmate::qassert(frequency, "N")
checkmate::qassert(amplitude, "N")
stopifnot(length(frequency) == length(amplitude))
Expand All @@ -10,7 +10,8 @@
y_unit = "amplitude",
label = "sparse frequency spectrum",
x_lab = "Frequency (Hz)",
y_lab = "Amplitude")
y_lab = "Amplitude",
labels = labels)
class(res) <- c("sparse_fr_spectrum", "chord", class(res))
res
}
Expand Down Expand Up @@ -72,7 +73,8 @@ sparse_fr_spectrum.sparse_fr_spectrum <- function(x, ...) {
sparse_fr_spectrum.sparse_pi_spectrum <- function(x, ...) {
.sparse_fr_spectrum(
frequency = midi_to_freq(pitch(x)),
amplitude = amp(x)
amplitude = amp(x),
labels = x$labels
)
}

Expand Down
14 changes: 9 additions & 5 deletions R/sparse-pc-spectrum.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.sparse_pc_spectrum <- function(pc, amplitude) {
.sparse_pc_spectrum <- function(pc, amplitude, labels = NULL) {
checkmate::qassert(pc, "N[0,12)")
checkmate::qassert(amplitude, "N")
stopifnot(length(pc) == length(amplitude))
Expand All @@ -9,7 +9,8 @@
y_unit = "amplitude",
label = "sparse pitch-class spectrum",
x_lab = "Pitch class",
y_lab = "Amplitude")
y_lab = "Amplitude",
labels = labels)
class(res) <- c("sparse_pc_spectrum", "chord", class(res))
res
}
Expand Down Expand Up @@ -71,13 +72,16 @@ sparse_pc_spectrum.sparse_pc_spectrum <- function(x, ...) {
}

sparse_pc_spectrum.sparse_pi_spectrum <- function(x, digits = 6) {
data.frame(x = pitch(x),
y = amp(x)) %>%
df <- data.frame(x = pitch(x),
y = amp(x))
if (!is.null(x$labels)) df$labels <- x$labels
df %>%
list() %>%
collapse_summing_amplitudes(digits = digits, modulo = 12) %>%
{
.sparse_pc_spectrum(pc = .[[1]],
amplitude = .[[2]])
amplitude = .[[2]],
labels = .$labels)
}
}

Expand Down
8 changes: 5 additions & 3 deletions R/sparse-pi-spectrum.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.sparse_pi_spectrum <- function(pitch, amplitude) {
.sparse_pi_spectrum <- function(pitch, amplitude, labels = NULL) {
checkmate::qassert(pitch, "N")
checkmate::qassert(amplitude, "N")
stopifnot(length(pitch) == length(amplitude))
Expand All @@ -9,7 +9,8 @@
y_unit = "amplitude",
label = "sparse pitch spectrum",
x_lab = "Pitch (MIDI)",
y_lab = "Amplitude")
y_lab = "Amplitude",
labels = labels)
class(res) <- c("sparse_pi_spectrum", "chord", class(res))
res
}
Expand Down Expand Up @@ -76,7 +77,8 @@ sparse_pi_spectrum.sparse_pi_spectrum <- function(x, ...) {
sparse_pi_spectrum.sparse_fr_spectrum <- function(x, ...) {
.sparse_pi_spectrum(
pitch = freq_to_midi(freq(x)),
amplitude = amp(x)
amplitude = amp(x),
labels = x$labels
)
}

Expand Down
Loading

0 comments on commit 82e034a

Please sign in to comment.