Skip to contents

The class MidiFramer can be used to read midi files to dataframes in order to facilitate to manipulate the data from R. You can also create midi data from R without reading it from a file. The data is transformed to various formats. One of the MidiFramer fields is a MidiFrames object of the python miditapyr package. Its method write_file() can be used to write the data back to a midi file.

Details

Public fields

midi_file_string

Path to the midi file.

mf

miditapyr$MidiFrames object.

dfm

result of tab_measures().

df_notes_long

Result of pivot_long_notes().

df_meta, df_not_notes, df_notes_wide

Results of split_midi_frame().

midi_frame_mod

Result of merge_midi_frames().

params

Parameters used in internal functions; Named list; params$columns_to_add is passed to tab_measures(columns_to_add).

Active bindings

df_meta, df_not_notes, df_notes_wide

Results of split_midi_frame().

ticks_per_beat

Set ticks per beat of MidiFrames()$mf$midi_file. The value of ticks_per_beat passed should be integer. When a value is passed, the field mf$midi_file$ticks_per_beat is modified.

Methods


Method new()

Initialize a MidiFramer object

Usage

MidiFramer$new(midi_file_string = NULL)

Arguments

midi_file_string

Path to the midi file; if NULL (the default), an empty MidiFramer object is created.


Method update_notes_wide()

Update a MidiFramer object with modified notes

Usage

MidiFramer$update_notes_wide(mod)

Arguments

mod

Dataframe or function returning a dataframe of the format of df_notes_wide.

Examples

\dontrun{
midi_file_string <- system.file("extdata", "test_midi_file.mid", package = "pyramidi")
mfr <- MidiFramer$new(midi_file_string)
# Function to replace every note with a random midi note between 60 & 71:
mod <- function(dfn) {
  n_notes <- sum(!is.na(dfn$note))
  dfn %>% dplyr::mutate(note = ifelse(
    !is.na(note),
    sample(60:71, n_notes, TRUE),
    note
  ))
}
set.seed(123)
mfr$update_notes_wide(mod)
mfr$play()
# You can pass functions to the $update_notes_wide() method (as above), but
# you can also modify the dataframe directly and pass it. Therefore, the
# following results in the same:
set.seed(123)
df_mod <- mod(mfr$df_notes_wide)
mfr$update_notes_wide(df_mod)
mfr$play()
}


Method populate_r_fields()

Populate the fields of a MidiFramer object

This can also be used to recalculate all the object's attributes, when a value in params is changed (see examples).

Usage

MidiFramer$populate_r_fields()

Examples

\dontrun{
midi_file_string <- system.file("extdata", "test_midi_file.mid", package = "pyramidi")
mfr <- MidiFramer$new(midi_file_string)
mfr$params$columns_to_add <- c("m", "b", "t", "time")
mfr$populate_r_fields()
}


Method play()

Play midi from MidiFramer object. Writes a midi file and either playing it in the R console (live = TRUE), or otherwise (live = FALSE) writes an audio file and adding an html audio player in an Rmarkdown (/quarto?) document. Calls player() helper function.

WARNING: Setting overwrite = TRUE (the default!!) will DELETE the specified audio files!!! (see more details below)

Usage

MidiFramer$play(
  audiofile = tempfile("mf_out_", fileext = ".mp3"),
  soundfont = fluidsynth::soundfont_path(),
  midifile = gsub("\\....$", ".mid", audiofile),
  live = interactive(),
  verbose = FALSE,
  overwrite = TRUE,
  ...
)

Arguments

audiofile

Path to the audiofile to be synthesized. If audiofile of type mp3, it will first be synthesized to wav, and then converted to mp3 with ffmpeg; (character string).

soundfont

path to sf2 sound font (character string); if not specified, the default soundfont of the fluidsynth package (fluidsynth::soundfont_path()) will be (downloaded if not present and) used.

midifile

Path to the midi file to synthesize on; (character string).

live

logical; if TRUE the synthesized midi is directly played in the console. If FALSE an audio html tag is written. This will generate a small audio player when knitting an Rmd document (and probably also Quarto qmd files; I didn't check).

verbose

logical whether to print command line output; defaults to FALSE

overwrite

logical; defaults to TRUE; if file exists and overwrite = FALSE, the existing files will not be overwritten and the function errors out.

...

Arguments passed to the fluidsynth functions (fluidsynth::midi_play or fluidsynth::midi_convert depending on the value of live).

@seealso

player

Examples

midi_file_string <- system.file("extdata", "test_midi_file.mid", package = "pyramidi")
mfr <- MidiFramer$new(midi_file_string)
mfr$play()
# The play method does basically this:
\dontrun{
midi_out <- "my_output.mid"
mp3file <- "test.mp3"
mfr$mf$write_file(midi_out)
fluidsynth::midi_convert(midi_out, output = mp3file)
# `overwrite` = TRUE overwrites midi_out & mp3file
}


Method clone()

The objects of this class are cloneable with this method.

Usage

MidiFramer$clone(deep = FALSE)

Arguments

deep

Whether to make a deep clone.

Examples

if (FALSE) {
## Create a MidiFramer object from a midi file:
midi_file_string <- system.file("extdata", "test_midi_file.mid", package = "pyramidi")
MidiFramer$new(midi_file_string)

## ------------------------------------------------
## Create empty MidiFramer object to illustrate
## the use of the `ticks_per_beat` active binding:
## ------------------------------------------------

mfr <- MidiFramer$new()
# Print default value of empty MidiFile object:
mfr$mf$midi_file$ticks_per_beat
# Modify it with the active binding ticks_per_beat:
mfr$ticks_per_beat <- 960L
# Print it again:
mfr$mf$midi_file$ticks_per_beat
}

## ------------------------------------------------
## Method `MidiFramer$update_notes_wide`
## ------------------------------------------------

if (FALSE) {
midi_file_string <- system.file("extdata", "test_midi_file.mid", package = "pyramidi")
mfr <- MidiFramer$new(midi_file_string)
# Function to replace every note with a random midi note between 60 & 71:
mod <- function(dfn) {
  n_notes <- sum(!is.na(dfn$note))
  dfn %>% dplyr::mutate(note = ifelse(
    !is.na(note),
    sample(60:71, n_notes, TRUE),
    note
  ))
}
set.seed(123)
mfr$update_notes_wide(mod)
mfr$play()
# You can pass functions to the $update_notes_wide() method (as above), but
# you can also modify the dataframe directly and pass it. Therefore, the
# following results in the same:
set.seed(123)
df_mod <- mod(mfr$df_notes_wide)
mfr$update_notes_wide(df_mod)
mfr$play()
}

## ------------------------------------------------
## Method `MidiFramer$populate_r_fields`
## ------------------------------------------------

if (FALSE) {
midi_file_string <- system.file("extdata", "test_midi_file.mid", package = "pyramidi")
mfr <- MidiFramer$new(midi_file_string)
mfr$params$columns_to_add <- c("m", "b", "t", "time")
mfr$populate_r_fields()
}

## ------------------------------------------------
## Method `MidiFramer$play`
## ------------------------------------------------

midi_file_string <- system.file("extdata", "test_midi_file.mid", package = "pyramidi")
mfr <- MidiFramer$new(midi_file_string)
#> Error in python_config_impl(python) : 
#>   Error running '/home/runner/.virtualenvs/r-reticulate/python': No such file.
#> The Python installation used to create the virtualenv has been moved or removed:
#>   '/opt/hostedtoolcache/Python/3.11.8/x64/bin'
mfr$play()
#> <audio controls="">
#>   <source src="/tmp/RtmpcdQMVt/mf_out_1e2a725f17d7.mp3" type="audio/mp3"/>
#> </audio>
# The play method does basically this:
if (FALSE) {
midi_out <- "my_output.mid"
mp3file <- "test.mp3"
mfr$mf$write_file(midi_out)
fluidsynth::midi_convert(midi_out, output = mp3file)
# `overwrite` = TRUE overwrites midi_out & mp3file
}