@@ -69,6 +69,22 @@ ratio2cents <- function(ratio) {
6969 return (log2(ratio ) * 1200 )
7070}
7171
72+ # ' @title Cents to Fraction
73+ # ' @name cents2frac
74+ # ' @description Converts a vector of cents to a vector of the corresponding
75+ # ' ratios, expressed as a character vector of vulgar fractions
76+ # ' @importFrom fractional fractional
77+ # ' @export cents2frac
78+ # ' @param cents a numeric vector of cents values
79+ # ' @returns a vector of the corresponding vulgar fractions
80+ # ' @examples
81+ # ' print(cents2frac(seq(0, 1200, by = 100)))
82+ # '
83+
84+ cents2frac <- function (cents ) {
85+ return (as.character(fractional :: fractional(2 ^ (cents / 1200 ))))
86+ }
87+
7288# ' @title Ratio to Factors
7389# ' @name ratio2factors
7490# ' @description Converts a vector of ratios to a vector of the corresponding
@@ -80,17 +96,17 @@ ratio2cents <- function(ratio) {
8096# ' @returns a list of vectors, with each vector the integer factors that
8197# ' determined the corresponding ratio
8298# ' @examples
83- # ' (super <- sclfile_scale_table(system.file(
99+ # ' print (super <- sclfile_scale_table(system.file(
84100# ' "test_scl_files/carlos_super.scl",
85101# ' package = "consonaR"
86- # ' ))$scale_table$ratio )
87- # ' (super_factors <- ratio2factors(super))
102+ # ' ))$scale_table)
103+ # ' print (super_factors <- ratio2factors(cents2ratio( super$ratio_cents) ))
88104# '
89- # ' (harm <- sclfile_scale_table(system.file(
105+ # ' print (harm <- sclfile_scale_table(system.file(
90106# ' "test_scl_files/carlos_harm.scl",
91107# ' package = "consonaR"
92- # ' ))$scale_table$ratio )
93- # ' (harm_factors <- ratio2factors(harm))
108+ # ' ))$scale_table)
109+ # ' print (harm_factors <- ratio2factors(cents2ratio( harm$ratio_cents) ))
94110# '
95111# ' # we know the factors that yield the 1-3-5-7 Hexany
96112# ' # can we recover them?
@@ -195,33 +211,26 @@ sine_dissonance <- function(freq1, freq2, loud1, loud2) {
195211# ' @importFrom data.table data.table
196212# ' @importFrom data.table setkey
197213# ' @importFrom data.table ":="
198- # ' @importFrom data.table ".I"
199214# ' @importFrom data.table "shift"
200- # ' @importFrom fractional fractional
201215# ' @importFrom utils globalVariables
202216# ' @export et_scale_table
203217# ' @param period The period - default is 2, for an octave
204218# ' @param divisions Number of degrees in the scale - default is 12
205- # ' @param tonic_note_number MIDI note number of the tonic for the scale -
206- # ' - default is middle C = 60
207- # ' @returns a `data.table` with seven columns:
219+ # ' @param root_freq root frequency of the scale - default is middle C:
220+ # ' 440 / (2 ^ (9 / 12))
221+ # ' @returns a `data.table` with six columns:
208222# ' \itemize{
209- # ' \item `ratio `: the ratio that defines the note, as a number between 1 and
210- # ' `period`
223+ # ' \item `degree `: scale degree from zero to (number of notes) - 1
224+ # ' \item `ratio_cents`: the ratio in cents (hundredths of a semitone)
211225# ' \item `ratio_frac`: the ratio as a vulgar fraction (character). The ratios
212226# ' for this type of scale are usually irrational, so this is an approximation,
213227# ' computed by `fractional::fractional`.
214- # ' \item `ratio_cents`: the ratio in cents (hundredths of a semitone)
215- # ' \item `frequency`: frequency of the note given the `tonic_note_number`
228+ # ' \item `frequency`: frequency of the note given the `root_freq`
216229# ' parameter
217- # ' \item `bent_midi`: the MIDI note number as an integer plus a fraction. For
218- # ' example, middle C is MIDI note number 60 and middle C sharp is 61. The
219- # ' quarter-tone half-way between C and C sharp would have a `bent_midi` value
220- # ' of 60.5. The name `bent_midi` comes from the fact that a MIDI sequencer
221- # ' can convert the value to a regular integer MIDI note number message and
222- # ' a pitch bend message.
223230# ' \item `interval_cents`: interval between this note and the previous note
224- # ' \item `degree`: scale degree from zero to (number of notes) - 1
231+ # ' in cents
232+ # ' \item `interval_frac`: interval between this note and the previous note
233+ # ' as a vulgar fraction
225234# ' }
226235# ' @examples
227236# '
@@ -242,26 +251,24 @@ sine_dissonance <- function(freq1, freq2, loud1, loud2) {
242251et_scale_table <- function (
243252 period = 2.0 ,
244253 divisions = 12 ,
245- tonic_note_number = 60
254+ root_freq = 440 / ( 2 ^ ( 9 / 12 ))
246255 ) {
247256 degree <- seq(0 , divisions )
248257 ratio_cents <- degree * ratio2cents(period ) / divisions
249- ratio <- cents2ratio(ratio_cents )
250- ratio_frac <- as.character(fractional :: fractional(ratio ))
251- tonic_frequency <- 440 * 2 ^ ((tonic_note_number - 69 ) / 12 )
252- frequency <- ratio * tonic_frequency
253- bent_midi <- 0.01 * ratio_cents + tonic_note_number
258+ ratio_frac <- cents2frac(ratio_cents )
259+ frequency <- cents2ratio(ratio_cents ) * root_freq
254260 scale_table <- data.table :: data.table(
255- ratio ,
256- ratio_frac ,
261+ degree ,
257262 ratio_cents ,
258- frequency ,
259- bent_midi
263+ ratio_frac ,
264+ frequency
260265 )
261- data.table :: setkey(scale_table , ratio )
266+ data.table :: setkey(scale_table , ratio_cents )
262267 scale_table <- scale_table [, `:=`(
263- interval_cents = ratio_cents - data.table :: shift(ratio_cents ),
264- degree = .I - 1
268+ interval_cents = ratio_cents - data.table :: shift(ratio_cents )
269+ )]
270+ scale_table <- scale_table [, `:=`(
271+ interval_frac = cents2frac(interval_cents )
265272 )]
266273 scale_table $ degree [divisions + 1 ] <- 0
267274 return (scale_table )
@@ -273,55 +280,52 @@ et_scale_table <- function(
273280# ' @importFrom data.table data.table
274281# ' @importFrom data.table setkey
275282# ' @importFrom data.table ":="
276- # ' @importFrom data.table ".I"
277283# ' @importFrom data.table "shift"
278- # ' @importFrom fractional fractional
279284# ' @importFrom utils globalVariables
280285# ' @export sclfile_scale_table
281286# ' @param sclfile_path The path to a valid Scala `.scl` file
282- # ' @param tonic_note_number MIDI note number of the tonic for the scale -
283- # ' - default is middle C = 60
284- # ' @returns a `data.table` with seven columns :
287+ # ' @param root_freq root frequency of the scale - default is middle C:
288+ # ' 440 / (2 ^ (9 / 12))
289+ # ' @returns a list with two or three items :
285290# ' \itemize{
286- # ' \item `ratio`: the ratio that defines the note, as a number between 1 and
287- # ' `period`
288- # ' \item `ratio_frac`: the ratio as a vulgar fraction (character). The ratios
289- # ' for this type of scale are usually irrational, so this is an approximation,
290- # ' computed by `fractional::fractional`.
291- # ' \item `ratio_cents`: the ratio in cents (hundredths of a semitone)
292- # ' \item `frequency`: frequency of the note given the `tonic_note_number`
293- # ' parameter
294- # ' \item `bent_midi`: the MIDI note number as an integer plus a fraction. For
295- # ' example, middle C is MIDI note number 60 and middle C sharp is 61. The
296- # ' quarter-tone half-way between C and C sharp would have a `bent_midi` value
297- # ' of 60.5. The name `bent_midi` comes from the fact that a MIDI sequencer
298- # ' can convert the value to a regular integer MIDI note number message and
299- # ' a pitch bend message.
300- # ' \item `interval_cents`: interval between this note and the previous note
301- # ' \item `degree`: scale degree from zero to (number of notes) - 1
291+ # ' \item `status` (character): "Oll Korrect" if the results are valid,
292+ # ' otherwise an error message
293+ # ' \item `file_contents` (character vector): the contents read from the file
294+ # ' \item `scale_table` (data.table): if everything worked, the scale table
302295# ' }
303296# ' @examples
304297# '
305298# ' # a file with ratios specified in cents
306- # ' cents <- sclfile_scale_table(system.file(
299+ # ' alpha <- sclfile_scale_table(system.file(
307300# ' "test_scl_files/carlos_alpha.scl",
308301# ' package = "consonaR"
309302# ' ))
310- # ' if (cents $status == "Oll Korrect") {
311- # ' print(cents $scale_table)
303+ # ' if (alpha $status == "Oll Korrect") {
304+ # ' print(alpha $scale_table)
312305# ' } else {
313- # ' print(cents $status)
306+ # ' print(alpha $status)
314307# ' }
315308# '
316309# ' # a file with ratios specified as vulgar fractions
317- # ' ratios <- sclfile_scale_table(system.file(
310+ # ' harm <- sclfile_scale_table(system.file(
318311# ' "test_scl_files/carlos_harm.scl",
319312# ' package = "consonaR"
320313# ' ))
321- # ' if (ratios $status == "Oll Korrect") {
322- # ' print(ratios $scale_table)
314+ # ' if (harm $status == "Oll Korrect") {
315+ # ' print(harm $scale_table)
323316# ' } else {
324- # ' print(ratios$status)
317+ # ' print(harm$status)
318+ # ' }
319+ # '
320+ # ' # another file with ratios specified as vulgar fractions
321+ # ' super <- sclfile_scale_table(system.file(
322+ # ' "test_scl_files/carlos_super.scl",
323+ # ' package = "consonaR"
324+ # ' ))
325+ # ' if (super$status == "Oll Korrect") {
326+ # ' print(super$scale_table)
327+ # ' } else {
328+ # ' print(super$status)
325329# ' }
326330# '
327331# ' # a file that doesn't exist
@@ -336,7 +340,10 @@ et_scale_table <- function(
336340# ' }
337341# '
338342
339- sclfile_scale_table <- function (sclfile_path , tonic_note_number = 60 ) {
343+ sclfile_scale_table <- function (
344+ sclfile_path ,
345+ root_freq = 440 / (2 ^ (9 / 12 ))
346+ ) {
340347
341348 # bail if the file can't be opened for reading text
342349 previous_warn_option <- as.integer(options(warn = 2 ))
@@ -406,21 +413,20 @@ sclfile_scale_table <- function(sclfile_path, tonic_note_number = 60) {
406413 }
407414
408415 # finish up
409- ratio_frac <- as.character(fractional :: fractional(ratio ))
410- tonic_frequency <- 440 * 2 ^ ((tonic_note_number - 69 ) / 12 )
411- frequency <- ratio * tonic_frequency
412- bent_midi <- 0.01 * ratio_cents + tonic_note_number
416+ ratio_frac <- cents2frac(ratio_cents )
417+ frequency <- ratio * root_freq
413418 scale_table <- data.table :: data.table(
414- ratio ,
415- ratio_frac ,
419+ degree ,
416420 ratio_cents ,
417- frequency ,
418- bent_midi
421+ ratio_frac ,
422+ frequency
419423 )
420- data.table :: setkey(scale_table , ratio )
424+ data.table :: setkey(scale_table , ratio_cents )
421425 scale_table <- scale_table [, `:=`(
422- interval_cents = ratio_cents - data.table :: shift(ratio_cents ),
423- degree = .I - 1
426+ interval_cents = ratio_cents - data.table :: shift(ratio_cents )
427+ )]
428+ scale_table <- scale_table [, `:=`(
429+ interval_frac = cents2frac(interval_cents )
424430 )]
425431 scale_table $ degree [degrees + 1 ] <- 0
426432
@@ -510,3 +516,7 @@ prodset_scale_table <- function(
510516 scale_table $ degree [degrees + 1 ] <- 0
511517 return (scale_table )
512518}
519+
520+ utils :: globalVariables(c(
521+ " interval_cents"
522+ ))
0 commit comments