Title: | Learn and Experiment with Music Theory |
---|---|
Description: | An aid for learning and using music theory. You can build chords, scales, and chord progressions using 12-note equal temperament tuning (12-ET) or user-defined tuning. Includes functions to visualize notes on a piano using ASCII plots in the console and to plot waveforms using base graphics. It allows simple playback of notes and chords using the 'audio' package. |
Authors: | Efstathios D. Gennatas [aut, cre] |
Maintainer: | Efstathios D. Gennatas <[email protected]> |
License: | GPL (>=3) |
Version: | 0.1.3 |
Built: | 2024-11-02 04:27:05 UTC |
Source: | https://github.com/egenn/music |
The music package allows you to build, play, and visualize scales, chords, and chord progression. For playback, music builds waveforms as matrices and passes them to the 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 by specifying frequency ratios and a root note. See note2freq. A4 defaults to 440Hz, and can be changed with the 'A4' argument.
Build Chord
buildChord( root, chord = "minor", plot = TRUE, play = FALSE, formatNotation = TRUE, ... )
buildChord( root, chord = "minor", plot = TRUE, play = FALSE, formatNotation = TRUE, ... )
root |
String: Root note |
chord |
String: Chord to build. Default = "minor" |
plot |
Logical: If TRUE, plot chord notes using cplot_piano |
play |
Logical: If TRUE, play chord using playChord |
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") |
... |
Additional arguments to be passed to playChord if
|
E.D. Gennatas
buildChord("C4", "minor") buildChord("A4", "sus2", plot = TRUE) ## Not run: buildChord("B4", "sus2", play = TRUE) ## End(Not run)
buildChord("C4", "minor") buildChord("A4", "sus2", plot = TRUE) ## Not run: buildChord("B4", "sus2", play = TRUE) ## End(Not run)
Build Chord Progression
buildProgression( root = "A4", scale = "minor", plot = FALSE, play = FALSE, formatNotation = TRUE, ... )
buildProgression( root = "A4", scale = "minor", plot = FALSE, play = FALSE, formatNotation = TRUE, ... )
root |
String: Root note. Default = "A4" |
scale |
String: "major" or "minor". Default = "minor" |
plot |
Logical: If TRUE, plot each chord in the progression using cplot_piano |
play |
Logical: If TRUE, play scale using playProgression |
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 c("F#4", "G4") |
... |
Additional arguments to be passed to playProgression if
|
E.D. Gennatas
buildProgression("C4", "minor") buildProgression("Bb4", "major") ## Not run: buildProgression("Bb4", "major", play = TRUE, plot = TRUE) ## End(Not run)
buildProgression("C4", "minor") buildProgression("Bb4", "major") ## Not run: buildProgression("Bb4", "major", play = TRUE, plot = TRUE) ## End(Not run)
Build Scale / Mode
buildScale( root, scale = "minor", descending = FALSE, plot = TRUE, play = FALSE, pairs = FALSE, formatNotation = TRUE, ... )
buildScale( root, scale = "minor", descending = FALSE, plot = TRUE, play = FALSE, pairs = FALSE, formatNotation = TRUE, ... )
root |
String: Root note. e.g. "C4" |
scale |
String: Scale to build. Default = "minor" |
descending |
Logical: If TRUE, return notes in descending order, otherwise in ascending |
plot |
Logical: If TRUE, plot scale notes using cplot_piano |
play |
Logical: If TRUE, play scale using playNote |
pairs |
Logical: If TRUE and |
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") |
... |
Additional arguments to be passed to playNote if
|
E.D. Gennatas
buildScale("C4", "minor") buildScale("B4", "minor", descending = TRUE, plot = TRUE) ## Not run: buildScale("B4", "minor", descending = TRUE, play = TRUE, plot TRUE) ## End(Not run)
buildScale("C4", "minor") buildScale("B4", "minor", descending = TRUE, plot = TRUE) ## Not run: buildScale("B4", "minor", descending = TRUE, play = TRUE, plot TRUE) ## End(Not run)
Build an ASCII plot of notes on a piano
cplot_piano(notes = buildScale("C4", "minor"), blackKey.col = "white")
cplot_piano(notes = buildScale("C4", "minor"), blackKey.col = "white")
notes |
String, vector: Notes to highlight.
Default = |
blackKey.col |
Color to use for black keys. Default = "white" for use on a dark terminal. Set to "black" for use on a light terminal. |
E.D. Gennatas
cplot_piano(buildScale("B4", "minor"))
cplot_piano(buildScale("B4", "minor"))
Calculates delay and reverb time in milliseconds given tempo in beats per minute (BPM) and delay/reverb time in note duration
delay_time( bpm = 120, note = c("2", "1", "1/2", "1/2T", "1/4D", "1/4", "1/4T", "1/8D", "1/8", "1/8T", "1/16D", "1/16", "1/16T", "1/32D", "1/32", "1/32T"), verbose = TRUE )
delay_time( bpm = 120, note = c("2", "1", "1/2", "1/2T", "1/4D", "1/4", "1/4T", "1/8D", "1/8", "1/8T", "1/16D", "1/16", "1/16T", "1/32D", "1/32", "1/32T"), verbose = TRUE )
bpm |
Integer: Beats per minute. Default = 120 |
note |
Character: Delay/Reverb time in note duration: "2", "1", "1/2", "1/2T", "1/4D", "1/4", "1/4T", "1/8D", "1/8", "1/8T", "1/16D", "1/16", "1/16T", "1/32D", "1/32", "1/32T". "2" means a double note, "1" a whole, and so on. "T" denotes a triple note, "D" denotes a dotted note. Case insensitive. Default = "1/4" (quarter note) |
verbose |
Logical: If TRUE print message to console |
This function originally appeared in the rtemis
package
Delay time, invisibly
E.D. Gennatas
delay_time(120, "1/8")
delay_time(120, "1/8")
Converts the internal note representation which uses flats, to the
notation commonly used to write scales and chords, where a mix of sharps and
flats is used to avoid repeating the same letter note.
(e.g. "G#5" "A5"
, instead of "Ab5" "A5"
)
e.g. convert the C4 Lydian from:
"C4" "D4" "E4" "Gb4" "G4" "A4" "B4" "C5"
to:
"C4" "D4" "E4" "F#4" "G4" "A4" "B4" "C5"
or convert the A4 major from:
"A4" "B4" "Db5" "D5" "E5" "Gb5" "Ab5" "A5"
to:
"A4" "B4" "C#5" "D5" "E5" "F#5" "G#5" "A5"
formatNotation(notes)
formatNotation(notes)
notes |
String, vector: Notes to format |
E.D. Gennatas
formatNotation(c("Db4", "D4", "E4", "Gb4", "G4", "A4", "B4", "C5"))
formatNotation(c("Db4", "D4", "E4", "Gb4", "G4", "A4", "B4", "C5"))
Format notes for use in other music functions
formatNote(notes, default.octave = 4)
formatNote(notes, default.octave = 4)
notes |
Vector, String: Input notes in the form
|
default.octave |
Integer: Octave to use if missing in |
Converts sharps to flats, adds octave number if missing (Default = 4), and converts (rare) "bb" notes to regular notes
E.D. Gennatas
formatNote(c("D#4", "Ebb"))
formatNote(c("D#4", "Ebb"))
Frequency to waveform
freq2wave( frequency, oscillator = c("sine", "square", "saw", "triangle"), duration = 1, BPM = 120, sample.rate = 44100, attack.time = 50, inner.release.time = 50, plot = FALSE )
freq2wave( frequency, oscillator = c("sine", "square", "saw", "triangle"), duration = 1, BPM = 120, sample.rate = 44100, attack.time = 50, inner.release.time = 50, plot = FALSE )
frequency |
Float, vector: Frequency/ies to convert to waveform |
oscillator |
String: "sine", "square", "saw". Default = "sine" |
duration |
Float: Note duration in beats. Default = 1 |
BPM |
Integer: Beats per minute. Default = 120 |
sample.rate |
Integer: Sample rate. Default = 44100 |
attack.time |
Integer: Attack time. Default = 50 (Helps prevent popping) |
inner.release.time |
Integer: Release time, that ends on note OFF (instead of beginning at note OFF). Default = 50 (Also helps prevent popping) |
plot |
Logical: If TRUE, plot wave(s) using mplot |
E.D. Gennatas
wave <- freq2wave(note2freq(buildChord("A4", "sus2")))
wave <- freq2wave(note2freq(buildChord("A4", "sus2")))
Plot waveform
mplot( x, type = "l", main = NULL, legend = TRUE, lwd = 1, pty = "m", bg = "black", fg = "gray50", col = "cyan", col.axis = "gray50", col.lab = "gray50", col.main = "gray80", col.legend = "white", tcl = 0.3, xaxt = "s", yaxt = "s", new = FALSE, mgp = c(2, 0, 0), mar = NULL, oma = NULL, ... )
mplot( x, type = "l", main = NULL, legend = TRUE, lwd = 1, pty = "m", bg = "black", fg = "gray50", col = "cyan", col.axis = "gray50", col.lab = "gray50", col.main = "gray80", col.legend = "white", tcl = 0.3, xaxt = "s", yaxt = "s", new = FALSE, mgp = c(2, 0, 0), mar = NULL, oma = NULL, ... )
x |
Input |
type |
String: "l" for lines, "p" for points. Default = "l" |
main |
String: Plot title |
legend |
Logical: If TRUE, show legends on plot, if |
lwd |
Float: Line width. Default = 1 |
pty |
String: "m" to fill available device space, "s" for square plot. Default = "m" |
bg |
Color: background color |
fg |
Color: foreground color |
col |
Color: Point/line color |
col.axis |
Color: Axes' color |
col.lab |
Color: Label color |
col.main |
Color: Title color |
col.legend |
Color: Legend color |
tcl |
The 'tcl' param of par |
xaxt |
The 'xaxt' param of par |
yaxt |
The 'yaxt' param of par |
new |
The 'new' param of par |
mgp |
The 'mgp' param of par |
mar |
Vector, length 4: Margins for |
oma |
Vector, length 4: The 'oma' param of par |
... |
Additional parameters to pass to |
E.D. Gennatas
Convert notes to frequencies
note2freq( note, tuning = c("12ET", "custom"), custom.ratios = c(1, 16/15, 9/8, 6/5, 5/4, 4/3, 45/32, 3/2, 8/5, 5/3, 9/5, 15/8, 2), A4 = 440, custom.root = "C", default.octave = 4 )
note2freq( note, tuning = c("12ET", "custom"), custom.ratios = c(1, 16/15, 9/8, 6/5, 5/4, 4/3, 45/32, 3/2, 8/5, 5/3, 9/5, 15/8, 2), A4 = 440, custom.root = "C", default.octave = 4 )
note |
String: Note(s) to convert to frequencies |
tuning |
String: "12ET": 12-note equal temperament, "custom":
Intonation defined by |
custom.ratios |
Numeric, vector, length 13: Custom ratios for a 12-note
scale, starting with 1 (root) and ending in 2 (octave) to use when
|
A4 |
Float: Frequency for A4 in Hz. Default = 440 |
custom.root |
String: Root note for just intonation
( |
default.octave |
Integer: If |
E.D. Gennatas
note2freq(buildScale("B4", "minor"))
note2freq(buildScale("B4", "minor"))
Calculates note distance in semitones
noteDistance(notes)
noteDistance(notes)
notes |
String, vector: Notes in form |
Vector of length length(notes)
with semitone distances
between successive notes
E.D. Gennatas
noteDistance(strings("C4 Eb4 Gb4 Bb4"))
noteDistance(strings("C4 Eb4 Gb4 Bb4"))
Play Chord
playChord( chord, type = c("harmonic", "ascending", "descending"), oscillator = "sine", duration = 1, sample.rate = 44100, attack.time = 50, inner.release.time = 50, A4 = 440, plot = FALSE, ... )
playChord( chord, type = c("harmonic", "ascending", "descending"), oscillator = "sine", duration = 1, sample.rate = 44100, attack.time = 50, inner.release.time = 50, A4 = 440, plot = FALSE, ... )
chord |
String, vector: Notes making up chord. e.g. c("A4", "C5", "E5"). e.g. output of buildChord |
type |
String: "harmonic", "ascending", "descending". Default = "harmonic" |
oscillator |
String: "sine", "square", "saw". Default = "sine" |
duration |
Float: Note duration in beats. Default = 1 |
sample.rate |
Integer: Sample rate. Default = 44100 |
attack.time |
Integer: Attack time. Default = 50 (Helps prevent popping) |
inner.release.time |
Integer: Release time, that ends on note OFF (instead of beginning at note OFF). Default = 50 (Also helps prevent popping) |
A4 |
Float: Frequency for A4 in Hz. Default = 440 |
plot |
Logical: If TRUE, plot chord using cplot_piano |
... |
Additional arguments to pass to note2freq |
The constructed waveform (invisibly)
E.D. Gennatas
## Not run: playChord(buildChord("E4", "minor")) ## End(Not run)
## Not run: playChord(buildChord("E4", "minor")) ## End(Not run)
Play frequency
playFreq( frequency, oscillator = "sine", duration = rep(1, length(frequency)), BPM = 120, sample.rate = 44100, attack.time = 50, inner.release.time = 50, plot = FALSE )
playFreq( frequency, oscillator = "sine", duration = rep(1, length(frequency)), BPM = 120, sample.rate = 44100, attack.time = 50, inner.release.time = 50, plot = FALSE )
frequency |
Numeric, Vector: Frequency / frequencies to play |
oscillator |
String: "sine", "square", "saw". Default = "sine" |
duration |
Float: Note duration in beats. Default = 1 |
BPM |
Integer: Beats per minute. Default = 120 |
sample.rate |
Integer: Sample rate. Default = 44100 |
attack.time |
Integer: Attack time. Default = 50 (Helps prevent popping) |
inner.release.time |
Integer: Release time, that ends on note OFF (instead of beginning at note OFF). Default = 50 (Also helps prevent popping) |
plot |
Logical: If TRUE, plot waveform |
E.D. Gennatas
## Not run: playFreq(440) ## End(Not run)
## Not run: playFreq(440) ## End(Not run)
Play Note
playNote( note, oscillator = "sine", duration = rep(1, length(note)), BPM = 120, sample.rate = 44100, attack.time = 50, inner.release.time = 50, A4 = 440, plot = FALSE, ... )
playNote( note, oscillator = "sine", duration = rep(1, length(note)), BPM = 120, sample.rate = 44100, attack.time = 50, inner.release.time = 50, A4 = 440, plot = FALSE, ... )
note |
String, Vector: Note(s) to be played, e.g. c("Ab4", "B4") |
oscillator |
String: "sine", "square", "saw". Default = "sine" |
duration |
Float: Note duration in beats. Default = 1 |
BPM |
Integer: Beats per minute. Default = 120 |
sample.rate |
Integer: Sample rate. Default = 44100 |
attack.time |
Integer: Attack time. Default = 50 (Helps prevent popping) |
inner.release.time |
Integer: Release time, that ends on note OFF (instead of beginning at note OFF). Default = 50 (Also helps prevent popping) |
A4 |
Float: Frequency for A4 in Hz. Default = 440 |
plot |
Logical: If TRUE, plot notes using cplot_piano. This supports only two octaves; do not try plotting if your notes span more than two octaves. |
... |
Additional arguments to pass to note2freq |
E.D. Gennatas
## Not run: playNote("B4") ## End(Not run)
## Not run: playNote("B4") ## End(Not run)
Play Progression
playProgression( 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, ... )
playProgression( 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, ... )
progression |
List of string vectors: Each element of the list is a chord. e.g. output of buildProgression |
oscillator |
String: "sine", "square", "saw". Default = "sine" |
duration |
Float: Note duration in beats. Default = 1 |
BPM |
Integer: Beats per minute. Default = 120 |
sample.rate |
Integer: Sample rate. Default = 44100 |
attack.time |
Integer: Attack time. Default = 50 (Helps prevent popping) |
inner.release.time |
Integer: Release time, that ends on note OFF (instead of beginning at note OFF). Default = 50 (Also helps prevent popping) |
A4 |
Float: Frequency for A4 in Hz. Default = 440 |
plot |
Logical. If TRUE, plot each chord in the progression using cplot_piano |
... |
Additional arguments to pass to note2freq |
E.D. Gennatas
## Not run: playProgression(buildProgression("G4", "minor")) ## End(Not run)
## Not run: playProgression(buildProgression("G4", "minor")) ## End(Not run)
Play one or more waveforms at the same time using audio::play
playWave(wave, sample.rate = 44100, plot = FALSE)
playWave(wave, sample.rate = 44100, plot = FALSE)
wave |
Matrix or vector of waveforms. If a matrix, each column should be a waveform to be played simultaneously |
sample.rate |
Integer: Sample rate. Default = 44100 |
plot |
Logical: If TRUE: plot wave using mplot. |
E.D. Gennatas
## Not run: playWave(freq2wave(440)) ## End(Not run)
## Not run: playWave(freq2wave(440)) ## End(Not run)
Convenience function to separate notes into vector of strings
strings(x, sep = " ")
strings(x, sep = " ")
x |
String: A single character object which consists of multiple notes
separated by |
sep |
String: the character that separates notes in |
Makes it easy to copy-paste notes into other functions
e.g. playChord(strings("C4 Eb4 G4 D5"))
E.D. Gennatas
strings("C4 Eb4 Gb4 Bb4")
strings("C4 Eb4 Gb4 Bb4")