knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
This vignette shows how a midi file can also be read in by the tuneR package and then written to disc. However, for other midi files the code might need to be adapted a bit.
library(pyramidi) library(zeallot) library(dplyr) library(tidyr) library(ggplot2)
With pyramidi data can be loaded into a unnested dataframe like this:
mid_file_str <- system.file("extdata", "test_midi_file.mid", package = "pyramidi") mido_mid_file <- mido$MidiFile(mid_file_str) dfc <- miditapyr$frame_midi(mido_mid_file) ticks_per_beat = mido_mid_file$ticks_per_beat df <- dfc %>% miditapyr$unnest_midi() %>% as_tibble() df
With tuneR this can be done for this file in the following way:
df_tuner <- tuneR::readMidi(mid_file_str)
(for other midi files the cleaning code would have to be adapted)
# vector according to which we'll # rename the event types to the names given by mido, cf.: # https://mido.readthedocs.io/en/latest/message_types.html & # https://mido.readthedocs.io/en/latest/meta_message_types.html rename_type_vec <- c( "Set Tempo" = "set_tempo", "Time Signature" = "time_signature", "Note On" = "note_on", "Note Off" = "note_off", "Sequence/Track Name" = "track_name", "End of Track" = "end_of_track", "Key Signature" = "key", "Controller" = "control", "Program Change" = "program", "Pitch Bend" = "pitch" ) # transform the tuneR data.frame to the pyramidi format : df_tuner_mod <- df_tuner %>% mutate(event = as.character(event)) %>% as_tibble() %>% mutate(meta = !is.na(type)) %>% select(-type) %>% rename(type = event, note = parameter1, velocity = parameter2, i_track = track) %>% mutate(type = recode(type, !!!rename_type_vec)) %>% mutate(tempo = ifelse(type == "set_tempo", as.integer(parameterMetaSystem), NA)) %>% mutate(name = ifelse(type == "track_name", parameterMetaSystem, NA)) %>% mutate(temp = ifelse(type == "time_signature", parameterMetaSystem, NA)) %>% separate(temp, c("numerator", "denominator", "clocks_per_click", "temp1", "temp2", "notated_32nd_notes_per_beat"), convert = TRUE) %>% select(-temp1, -temp2) %>% arrange(i_track, time) %>% group_by(i_track) %>% # calculate time increments instead of total time: mutate(time = time - lag(time) %>% {.[1] = 0; .}) %>% ungroup() %>% mutate_if(is.numeric, ~ifelse(is.na(.), NaN, .)) %>% mutate(name = ifelse(is.na(name), list(NULL), name)) %>% # small correction of transforming "NA" strings into real NA values: mutate(name = ifelse(name == "NA", NA, name)) %>% select(-parameterMetaSystem)
dfm <- tab_measures(df_tuner_mod, ticks_per_beat) dfm %>% split_midi_frame() %->% c(df_meta, df_not_notes, df_notes_wide) df_meta <- df_meta
Now we have the data in 3 objects that MidiFramer
can understand. First let's create an empty MidiFramer
object:
mfr <- MidiFramer$new()
We'll set the ticks per beat (see here)
mfr$ticks_per_beat <- ticks_per_beat
First we'll pass the first two dataframes in the according fields of mfr
:
mfr$df_meta <- df_meta mfr$df_not_notes <- df_not_notes
We'll add the last one with the method MidiFramer$update_notes_wide()
,
in order to pass the information to other fields
(in particular mfr$mf$midi_frame_nested
,
which can be transformed back to a midi file;
see vignette("package_workflow")
):
mfr$update_notes_wide(df_notes_wide)
mfr$mf$write_file("round_tripped_midi_file.mid")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.