Setup
We’ll load some libraries in R:
First, we just load our package midi file to have some scaffolding to put our notes in:
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'
We will compose our data by generating a dataframe as the one on the example midi file.
mfr$df_notes_wide %>% kable()
Click here to show the format of the dataframe we need to have.
| i_track|meta | note| channel| i_note| velocity_note_on| velocity_note_off| ticks_note_on| ticks_note_off| b_note_on| b_note_off|
|-------:|:-----|----:|-------:|------:|----------------:|-----------------:|-------------:|--------------:|----------:|----------:|
| 0|FALSE | 43| 9| 1| 72| 72| 0| 240| 0.0000000| 1.000000|
| 0|FALSE | 39| 9| 1| 64| 64| 0| 240| 0.0000000| 1.000000|
| 0|FALSE | 36| 9| 1| 101| 101| 0| 240| 0.0000000| 1.000000|
| 0|FALSE | 42| 9| 1| 101| 101| 480| 720| 2.0000000| 3.000000|
| 0|FALSE | 38| 9| 1| 101| 101| 480| 720| 2.0000000| 3.000000|
| 0|FALSE | 43| 9| 2| 64| 64| 720| 960| 3.0000000| 4.000000|
| 0|FALSE | 36| 9| 2| 101| 101| 960| 1200| 4.0000000| 5.000000|
| 0|FALSE | 43| 9| 3| 60| 60| 1440| 1680| 6.0000000| 7.000000|
| 0|FALSE | 42| 9| 2| 101| 101| 1440| 1680| 6.0000000| 7.000000|
| 0|FALSE | 43| 9| 4| 60| 60| 1920| 2160| 8.0000000| 9.000000|
| 0|FALSE | 39| 9| 2| 66| 66| 1920| 2160| 8.0000000| 9.000000|
| 0|FALSE | 36| 9| 3| 101| 101| 1920| 2160| 8.0000000| 9.000000|
| 0|FALSE | 42| 9| 3| 101| 101| 2400| 2640| 10.0000000| 11.000000|
| 0|FALSE | 38| 9| 2| 101| 101| 2400| 2640| 10.0000000| 11.000000|
| 0|FALSE | 43| 9| 5| 53| 53| 2640| 2880| 11.0000000| 12.000000|
| 0|FALSE | 36| 9| 4| 101| 101| 2880| 3120| 12.0000000| 13.000000|
| 0|FALSE | 43| 9| 6| 52| 52| 3360| 3600| 14.0000000| 15.000000|
| 0|FALSE | 42| 9| 4| 66| 66| 3360| 3600| 14.0000000| 15.000000|
| 0|FALSE | 43| 9| 7| 72| 72| 3840| 4080| 16.0000000| 17.000000|
| 0|FALSE | 39| 9| 3| 64| 64| 3840| 4080| 16.0000000| 17.000000|
| 0|FALSE | 36| 9| 5| 101| 101| 3840| 4080| 16.0000000| 17.000000|
| 0|FALSE | 42| 9| 5| 101| 101| 4320| 4560| 18.0000000| 19.000000|
| 0|FALSE | 38| 9| 3| 101| 101| 4320| 4560| 18.0000000| 19.000000|
| 0|FALSE | 43| 9| 8| 64| 64| 4560| 4800| 19.0000000| 20.000000|
| 0|FALSE | 36| 9| 6| 101| 101| 4800| 5040| 20.0000000| 21.000000|
| 0|FALSE | 43| 9| 9| 60| 60| 5280| 5520| 22.0000000| 23.000000|
| 0|FALSE | 42| 9| 6| 101| 101| 5280| 5520| 22.0000000| 23.000000|
| 0|FALSE | 43| 9| 10| 60| 60| 5760| 6000| 24.0000000| 25.000000|
| 0|FALSE | 39| 9| 4| 66| 66| 5760| 6000| 24.0000000| 25.000000|
| 0|FALSE | 36| 9| 7| 101| 101| 5760| 6000| 24.0000000| 25.000000|
| 0|FALSE | 42| 9| 7| 101| 101| 6240| 6480| 26.0000000| 27.000000|
| 0|FALSE | 38| 9| 4| 101| 101| 6240| 6480| 26.0000000| 27.000000|
| 0|FALSE | 43| 9| 11| 53| 53| 6480| 6720| 27.0000000| 28.000000|
| 0|FALSE | 36| 9| 8| 101| 101| 6720| 6960| 28.0000000| 29.000000|
| 0|FALSE | 43| 9| 12| 52| 52| 7200| 7440| 30.0000000| 31.000000|
| 0|FALSE | 42| 9| 8| 66| 66| 7200| 7440| 30.0000000| 31.000000|
| 0|FALSE | 43| 9| 13| 72| 72| 7680| 7920| 32.0000000| 33.000000|
| 0|FALSE | 39| 9| 5| 64| 64| 7680| 7920| 32.0000000| 33.000000|
| 0|FALSE | 36| 9| 9| 101| 101| 7680| 7920| 32.0000000| 33.000000|
| 0|FALSE | 42| 9| 9| 101| 101| 8160| 8400| 34.0000000| 35.000000|
| 0|FALSE | 38| 9| 5| 101| 101| 8160| 8400| 34.0000000| 35.000000|
| 0|FALSE | 43| 9| 14| 64| 64| 8400| 8640| 35.0000000| 36.000000|
| 0|FALSE | 36| 9| 10| 101| 101| 8640| 8880| 36.0000000| 37.000000|
| 0|FALSE | 43| 9| 15| 60| 60| 9120| 9360| 38.0000000| 39.000000|
| 0|FALSE | 42| 9| 10| 101| 101| 9120| 9360| 38.0000000| 39.000000|
| 0|FALSE | 43| 9| 16| 60| 60| 9600| 9840| 40.0000000| 41.000000|
| 0|FALSE | 39| 9| 6| 66| 66| 9600| 9840| 40.0000000| 41.000000|
| 0|FALSE | 36| 9| 11| 101| 101| 9600| 9840| 40.0000000| 41.000000|
| 0|FALSE | 42| 9| 11| 101| 101| 10080| 10320| 42.0000000| 43.000000|
| 0|FALSE | 38| 9| 6| 101| 101| 10080| 10320| 42.0000000| 43.000000|
| 0|FALSE | 43| 9| 17| 53| 53| 10320| 10560| 43.0000000| 44.000000|
| 0|FALSE | 36| 9| 12| 101| 101| 10560| 10800| 44.0000000| 45.000000|
| 0|FALSE | 43| 9| 18| 52| 52| 11040| 11280| 46.0000000| 47.000000|
| 0|FALSE | 42| 9| 12| 66| 66| 11040| 11280| 46.0000000| 47.000000|
| 0|FALSE | 43| 9| 19| 81| 81| 11520| 11760| 48.0000000| 49.000000|
| 0|FALSE | 36| 9| 13| 101| 101| 11520| 11760| 48.0000000| 49.000000|
| 0|FALSE | 42| 9| 13| 101| 101| 12000| 12240| 50.0000000| 51.000000|
| 0|FALSE | 39| 9| 7| 57| 57| 12000| 12240| 50.0000000| 51.000000|
| 0|FALSE | 38| 9| 7| 101| 101| 12000| 12240| 50.0000000| 51.000000|
| 0|FALSE | 43| 9| 20| 60| 60| 12240| 12480| 51.0000000| 52.000000|
| 0|FALSE | 36| 9| 14| 101| 101| 12480| 12720| 52.0000000| 53.000000|
| 0|FALSE | 43| 9| 21| 66| 66| 12960| 13200| 54.0000000| 55.000000|
| 0|FALSE | 42| 9| 14| 101| 101| 12960| 13200| 54.0000000| 55.000000|
| 0|FALSE | 43| 9| 22| 66| 66| 13440| 13680| 56.0000000| 57.000000|
| 0|FALSE | 36| 9| 15| 101| 101| 13440| 13680| 56.0000000| 57.000000|
| 0|FALSE | 46| 9| 1| 81| 81| 13920| 14160| 58.0000000| 59.000000|
| 0|FALSE | 45| 9| 1| 67| 67| 13920| 14160| 58.0000000| 59.000000|
| 0|FALSE | 39| 9| 8| 60| 60| 13920| 14160| 58.0000000| 59.000000|
| 0|FALSE | 38| 9| 8| 101| 101| 13920| 14160| 58.0000000| 59.000000|
| 0|FALSE | 39| 9| 9| 59| 59| 14400| 14640| 60.0000000| 61.000000|
| 0|FALSE | 36| 9| 16| 101| 101| 14400| 14640| 60.0000000| 61.000000|
| 0|FALSE | 39| 9| 10| 55| 55| 14640| 14880| 61.0000000| 62.000000|
| 0|FALSE | 45| 9| 2| 63| 63| 14880| 15120| 62.0000000| 63.000000|
| 0|FALSE | 43| 9| 23| 52| 52| 14880| 15120| 62.0000000| 63.000000|
| 0|FALSE | 42| 9| 15| 101| 101| 14880| 15120| 62.0000000| 63.000000|
| 0|FALSE | 39| 9| 11| 55| 55| 14880| 15120| 62.0000000| 63.000000|
| 0|FALSE | 42| 9| 16| 59| 59| 15120| 15360| 63.0000000| 64.000000|
| 0|FALSE | 39| 9| 12| 57| 57| 15120| 15360| 63.0000000| 64.000000|
| 1|FALSE | 50| 15| 1| 82| 82| 0| 240| 0.0000000| 1.000000|
| 1|FALSE | 45| 15| 1| 85| 85| 3240| 3840| 13.5000000| 16.000000|
| 1|FALSE | 50| 15| 2| 81| 81| 3840| 4080| 16.0000000| 17.000000|
| 1|FALSE | 45| 15| 2| 69| 69| 7200| 7680| 30.0000000| 32.000000|
| 1|FALSE | 50| 15| 3| 69| 69| 7680| 8040| 32.0000000| 33.500000|
| 1|FALSE | 45| 15| 3| 82| 82| 10440| 11400| 43.5000000| 47.500000|
| 1|FALSE | 50| 15| 4| 72| 72| 11520| 12600| 48.0000000| 52.500000|
| 1|FALSE | 57| 15| 1| 79| 79| 12960| 13440| 54.0000000| 56.000000|
| 1|FALSE | 55| 15| 1| 50| 50| 13440| 13920| 56.0000000| 58.000000|
| 1|FALSE | 53| 15| 1| 73| 73| 13920| 14400| 58.0000000| 60.000000|
| 1|FALSE | 52| 15| 1| 69| 69| 14400| 14880| 60.0000000| 62.000000|
| 1|FALSE | 48| 15| 1| 85| 85| 14880| 15360| 62.0000000| 64.000000|
| 2|FALSE | 62| 15| 1| 78| 78| 54| 369| 0.2250000| 1.537500|
| 2|FALSE | 57| 15| 1| 78| 78| 64| 424| 0.2666667| 1.766667|
| 2|FALSE | 65| 15| 1| 72| 72| 70| 353| 0.2916667| 1.470833|
| 2|FALSE | 62| 15| 2| 57| 57| 1473| 3150| 6.1375000| 13.125000|
| 2|FALSE | 57| 15| 2| 53| 53| 1482| 3197| 6.1750000| 13.320833|
| 2|FALSE | 65| 15| 2| 58| 58| 1490| 3142| 6.2083333| 13.091667|
| 2|FALSE | 62| 15| 3| 61| 61| 3339| 3544| 13.9125000| 14.766667|
| 2|FALSE | 57| 15| 3| 53| 53| 3348| 3576| 13.9500000| 14.900000|
| 2|FALSE | 65| 15| 3| 58| 58| 3356| 3552| 13.9833333| 14.800000|
| 2|FALSE | 62| 15| 4| 47| 47| 3851| 4471| 16.0458333| 18.629167|
| 2|FALSE | 57| 15| 4| 42| 42| 3859| 4590| 16.0791667| 19.125000|
| 2|FALSE | 65| 15| 4| 46| 46| 3868| 4205| 16.1166667| 17.520833|
| 2|FALSE | 62| 15| 5| 56| 56| 5247| 6939| 21.8625000| 28.912500|
| 2|FALSE | 57| 15| 5| 53| 53| 5256| 6963| 21.9000000| 29.012500|
| 2|FALSE | 65| 15| 5| 58| 58| 5264| 6915| 21.9333333| 28.812500|
| 2|FALSE | 62| 15| 6| 49| 49| 7136| 7443| 29.7333333| 31.012500|
| 2|FALSE | 57| 15| 6| 42| 42| 7145| 7467| 29.7708333| 31.112500|
| 2|FALSE | 65| 15| 6| 49| 49| 7153| 7419| 29.8041667| 30.912500|
| 2|FALSE | 62| 15| 7| 37| 37| 7679| 8018| 31.9958333| 33.408333|
| 2|FALSE | 57| 15| 7| 34| 34| 7688| 8097| 32.0333333| 33.737500|
| 2|FALSE | 65| 15| 7| 51| 51| 7696| 8010| 32.0666667| 33.375000|
| 2|FALSE | 57| 15| 8| 58| 58| 9115| 10956| 37.9791667| 45.650000|
| 2|FALSE | 62| 15| 8| 60| 60| 9123| 10885| 38.0125000| 45.354167|
| 2|FALSE | 65| 15| 8| 56| 56| 9131| 10877| 38.0458333| 45.320833|
| 2|FALSE | 62| 15| 9| 50| 50| 11403| 11850| 47.5125000| 49.375000|
| 2|FALSE | 57| 15| 9| 40| 40| 11411| 11929| 47.5458333| 49.704167|
| 2|FALSE | 65| 15| 9| 52| 52| 11419| 11859| 47.5791667| 49.412500|
| 2|FALSE | 62| 15| 10| 63| 63| 12846| 13114| 53.5250000| 54.641667|
| 2|FALSE | 59| 15| 1| 69| 69| 12854| 13145| 53.5583333| 54.770833|
| 2|FALSE | 67| 15| 1| 58| 58| 12862| 13122| 53.5916667| 54.675000|
| 2|FALSE | 59| 15| 2| 58| 58| 13413| 14088| 55.8875000| 58.700000|
| 2|FALSE | 62| 15| 11| 58| 58| 13421| 14016| 55.9208333| 58.400000|
| 2|FALSE | 67| 15| 2| 58| 58| 13429| 14025| 55.9541667| 58.437500|
| 2|FALSE | 59| 15| 3| 52| 52| 14175| 14522| 59.0625000| 60.508333|
| 2|FALSE | 67| 15| 3| 60| 60| 14183| 14474| 59.0958333| 60.308333|
| 2|FALSE | 62| 15| 12| 65| 65| 14191| 14442| 59.1291667| 60.175000|
| 2|FALSE | 59| 15| 4| 57| 57| 14859| 15080| 61.9125000| 62.833333|
| 2|FALSE | 62| 15| 13| 60| 60| 14868| 15049| 61.9500000| 62.704167|
| 2|FALSE | 67| 15| 4| 57| 57| 14876| 15089| 61.9833333| 62.870833|
| 2|FALSE | 62| 15| 14| 82| 82| 15355| 15360| 63.9791667| 64.000000|
We will measure our time in b_note_on
and
b_note_off
being the absolute times (in quarter notes) when
the notes are played.
In sf2 soundfonts midi channel 10 (which is channel 9 in pythonista world :) is usually used for drums. Let’s try this out. 36 is the bass drum and 38 the snare
n_beats <- 16
ticks_per_beat <- 960L
drum <- tibble(
i_track = 0,
meta = FALSE,
# This is just a repetition of a classical rock beat:
note = rep(c(36, 38), n_beats / 2),
channel = 9,
i_note = 1:n_beats,
velocity_note_on = 100,
velocity_note_off = 0,
b_note_on = 0:(n_beats-1),
b_note_off = b_note_on + 1 / 2,
)
drum %>% kable()
Show drum
dataframe
| i_track|meta | note| channel| i_note| velocity_note_on| velocity_note_off| b_note_on| b_note_off|
|-------:|:-----|----:|-------:|------:|----------------:|-----------------:|---------:|----------:|
| 0|FALSE | 36| 9| 1| 100| 0| 0| 0.5|
| 0|FALSE | 38| 9| 2| 100| 0| 1| 1.5|
| 0|FALSE | 36| 9| 3| 100| 0| 2| 2.5|
| 0|FALSE | 38| 9| 4| 100| 0| 3| 3.5|
| 0|FALSE | 36| 9| 5| 100| 0| 4| 4.5|
| 0|FALSE | 38| 9| 6| 100| 0| 5| 5.5|
| 0|FALSE | 36| 9| 7| 100| 0| 6| 6.5|
| 0|FALSE | 38| 9| 8| 100| 0| 7| 7.5|
| 0|FALSE | 36| 9| 9| 100| 0| 8| 8.5|
| 0|FALSE | 38| 9| 10| 100| 0| 9| 9.5|
| 0|FALSE | 36| 9| 11| 100| 0| 10| 10.5|
| 0|FALSE | 38| 9| 12| 100| 0| 11| 11.5|
| 0|FALSE | 36| 9| 13| 100| 0| 12| 12.5|
| 0|FALSE | 38| 9| 14| 100| 0| 13| 13.5|
| 0|FALSE | 36| 9| 15| 100| 0| 14| 14.5|
| 0|FALSE | 38| 9| 16| 100| 0| 15| 15.5|
We’ll just define a small helper function to calculate the absolute midi ticks passed from the time measured in beats, because when we generate the format to save the data to midi we need to calculate the relative time increments in ticks.
beats_to_ticks <- function(notes_wide) {
notes_wide %>%
mutate(
ticks_note_on = b_note_on * ticks_per_beat,
ticks_note_off = b_note_off * ticks_per_beat
)
}
Ok we are ready to pass these modified notes to our
MidiFramer
object
mfr$update_notes_wide(beats_to_ticks(drum))
and listen to the drums of our first composition:
mfr$play("drum.mp3")
Now we’ll add notes. Channel 1 should be grand piano. We will play major chords We define that all the 4 notes in the chord are played at the same time:
(b_note_on = (0:(n_beats-1) %/% 4) * 4)
#> [1] 0 0 0 0 4 4 4 4 8 8 8 8 12 12 12 12
These starting times will be used to define a notes
dataframe.
notes <- tibble(
i_track = 0,
meta = FALSE,
note = rep(c(60, 64, 67, 72), n_beats / 4),
channel = 0,
i_note = 1:n_beats,
velocity_note_on = 100,
velocity_note_off = 0,
b_note_on = b_note_on,
b_note_off = b_note_on + 1 * 2,
)
notes %>% kable()
click to show notes
frame
| i_track|meta | note| channel| i_note| velocity_note_on| velocity_note_off| b_note_on| b_note_off|
|-------:|:-----|----:|-------:|------:|----------------:|-----------------:|---------:|----------:|
| 0|FALSE | 60| 0| 1| 100| 0| 0| 2|
| 0|FALSE | 64| 0| 2| 100| 0| 0| 2|
| 0|FALSE | 67| 0| 3| 100| 0| 0| 2|
| 0|FALSE | 72| 0| 4| 100| 0| 0| 2|
| 0|FALSE | 60| 0| 5| 100| 0| 4| 6|
| 0|FALSE | 64| 0| 6| 100| 0| 4| 6|
| 0|FALSE | 67| 0| 7| 100| 0| 4| 6|
| 0|FALSE | 72| 0| 8| 100| 0| 4| 6|
| 0|FALSE | 60| 0| 9| 100| 0| 8| 10|
| 0|FALSE | 64| 0| 10| 100| 0| 8| 10|
| 0|FALSE | 67| 0| 11| 100| 0| 8| 10|
| 0|FALSE | 72| 0| 12| 100| 0| 8| 10|
| 0|FALSE | 60| 0| 13| 100| 0| 12| 14|
| 0|FALSE | 64| 0| 14| 100| 0| 12| 14|
| 0|FALSE | 67| 0| 15| 100| 0| 12| 14|
| 0|FALSE | 72| 0| 16| 100| 0| 12| 14|
With a small helper function, we can change the notes played depending on the measure we’re in:
# We play the tonic for 2 bars,
# and the subdominant (+5) and dominant (+7) for one each:
change_notes_on_measures <- function(notes) {
notes %>%
mutate(
note = case_when(
floor(b_note_on/4) %% 4 == 0 ~ note,
floor(b_note_on/4) %% 4 == 1 ~ note,
floor(b_note_on/4) %% 4 == 2 ~ note + 5,
floor(b_note_on/4) %% 4 == 3 ~ note + 7
)
)
}
notes <- notes %>%
change_notes_on_measures()
When we join the drum
and notes
dataframes
together:
We can apply the same as above:
mfr$update_notes_wide(midi_note_events_wide)
And play it:
mfr$play("combine.mp3")
Let’s rock! 🤟🥳
Write functions to compose midi frames
Instead of defining a whole dataframe as in the section before, we’ll now write a small helper function writing single notes to the needed dataframe format:
frame_notes <- function(
b,
dur,
note,
velocity = 100,
channel = 0,
i_track = 0,
meta = FALSE,
velocity_note_off = 0,
...
) {
tibble(
i_track = i_track,
meta = meta,
note = note,
channel = channel,
velocity_note_on = velocity,
velocity_note_off = velocity_note_off,
b_note_on = b,
b_note_off = b + dur,
)
}
It outputs one line of a dataframe for each midi in the
note
vector. We’ll design a repeating bass pattern of a C
major chord:
bass %>% kable()
Show output
| i_track|meta | note| channel| velocity_note_on| velocity_note_off| b_note_on| b_note_off|
|-------:|:-----|----:|-------:|----------------:|-----------------:|---------:|----------:|
| 0|FALSE | 36| 0| 100| 0| 0.5| 1.5|
| 0|FALSE | 43| 0| 100| 0| 1.5| 2.5|
| 0|FALSE | 41| 0| 100| 0| 2.5| 3.5|
| 0|FALSE | 48| 0| 100| 0| 3.5| 4.5|
| 0|FALSE | 36| 0| 100| 0| 4.5| 5.5|
| 0|FALSE | 43| 0| 100| 0| 5.5| 6.5|
| 0|FALSE | 41| 0| 100| 0| 6.5| 7.5|
| 0|FALSE | 48| 0| 100| 0| 7.5| 8.5|
| 0|FALSE | 36| 0| 100| 0| 8.5| 9.5|
| 0|FALSE | 43| 0| 100| 0| 9.5| 10.5|
| 0|FALSE | 41| 0| 100| 0| 10.5| 11.5|
| 0|FALSE | 48| 0| 100| 0| 11.5| 12.5|
| 0|FALSE | 36| 0| 100| 0| 12.5| 13.5|
| 0|FALSE | 43| 0| 100| 0| 13.5| 14.5|
| 0|FALSE | 41| 0| 100| 0| 14.5| 15.5|
| 0|FALSE | 48| 0| 100| 0| 15.5| 16.5|
In order to avoid repetitive typing we’ll also define a small helper function for chords:
Now we can pass a list of chord vectors to the function. We’ll repeat the same C major chord:
chords_list
Show list of chords passed
[[1]]
[1] 60 64 67 72
[[2]]
[1] 60 64 67 72
[[3]]
[1] 60 64 67 72
[[4]]
[1] 60 64 67 72
[[5]]
[1] 60 64 67 72
[[6]]
[1] 60 64 67 72
[[7]]
[1] 60 64 67 72
[[8]]
[1] 60 64 67 72
[[9]]
[1] 60 64 67 72
[[10]]
[1] 60 64 67 72
[[11]]
[1] 60 64 67 72
[[12]]
[1] 60 64 67 72
[[13]]
[1] 60 64 67 72
[[14]]
[1] 60 64 67 72
[[15]]
[1] 60 64 67 72
[[16]]
[1] 60 64 67 72
frame them:
chords <- frame_chords(
b = 1:n_beats - 1,
dur = 1,
velocity = 70,
note = chords_list
)
chords
Show framed chords
[38;5;246m# A tibble: 64 × 8
[39m
i_track meta note channel velocity_note_on velocity_note_off b_note_on
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<lgl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[38;5;250m 1
[39m 0 FALSE 60 0 70 0 0
[38;5;250m 2
[39m 0 FALSE 64 0 70 0 0
[38;5;250m 3
[39m 0 FALSE 67 0 70 0 0
[38;5;250m 4
[39m 0 FALSE 72 0 70 0 0
[38;5;250m 5
[39m 0 FALSE 60 0 70 0 1
[38;5;250m 6
[39m 0 FALSE 64 0 70 0 1
[38;5;250m 7
[39m 0 FALSE 67 0 70 0 1
[38;5;250m 8
[39m 0 FALSE 72 0 70 0 1
[38;5;250m 9
[39m 0 FALSE 60 0 70 0 2
[38;5;250m10
[39m 0 FALSE 64 0 70 0 2
[38;5;246m# ℹ 54 more rows
[39m
[38;5;246m# ℹ 1 more variable: b_note_off <dbl>
[39m
Now let’s write a simple rising arpeggiatator function:
arpeggiate <- function(
b,
chords_list,
dur = 1,
pattern = "rising",
n_beat = 4,
octave = 1,
...
) {
times <- tibble(b) %>%
rowwise() %>%
summarise(c(b + seq(0, 1, length.out = n_beat + 1)[-(n_beat + 1)])) %>%
pull()
notes <-
tibble(temp = chords_list) %>%
unnest(temp) %>%
pull() %>%
{. + octave * 12; .}
frame_notes(
dur = dur/n_beat,
b = times,
note = notes,
...
)
}
arp <- arpeggiate(
b = 1:n_beats - 1,
velocity = 90,
chords_list = chords_list
)
#> Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in
#> dplyr 1.1.0.
#> ℹ Please use `reframe()` instead.
#> ℹ When switching from `summarise()` to `reframe()`, remember that `reframe()`
#> always returns an ungrouped data frame and adjust accordingly.
#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
#> generated.
arp %>% kable()
Show arpeggio function output
| i_track|meta | note| channel| velocity_note_on| velocity_note_off| b_note_on| b_note_off|
|-------:|:-----|----:|-------:|----------------:|-----------------:|---------:|----------:|
| 0|FALSE | 60| 0| 90| 0| 0.00| 0.25|
| 0|FALSE | 64| 0| 90| 0| 0.25| 0.50|
| 0|FALSE | 67| 0| 90| 0| 0.50| 0.75|
| 0|FALSE | 72| 0| 90| 0| 0.75| 1.00|
| 0|FALSE | 60| 0| 90| 0| 1.00| 1.25|
| 0|FALSE | 64| 0| 90| 0| 1.25| 1.50|
| 0|FALSE | 67| 0| 90| 0| 1.50| 1.75|
| 0|FALSE | 72| 0| 90| 0| 1.75| 2.00|
| 0|FALSE | 60| 0| 90| 0| 2.00| 2.25|
| 0|FALSE | 64| 0| 90| 0| 2.25| 2.50|
| 0|FALSE | 67| 0| 90| 0| 2.50| 2.75|
| 0|FALSE | 72| 0| 90| 0| 2.75| 3.00|
| 0|FALSE | 60| 0| 90| 0| 3.00| 3.25|
| 0|FALSE | 64| 0| 90| 0| 3.25| 3.50|
| 0|FALSE | 67| 0| 90| 0| 3.50| 3.75|
| 0|FALSE | 72| 0| 90| 0| 3.75| 4.00|
| 0|FALSE | 60| 0| 90| 0| 4.00| 4.25|
| 0|FALSE | 64| 0| 90| 0| 4.25| 4.50|
| 0|FALSE | 67| 0| 90| 0| 4.50| 4.75|
| 0|FALSE | 72| 0| 90| 0| 4.75| 5.00|
| 0|FALSE | 60| 0| 90| 0| 5.00| 5.25|
| 0|FALSE | 64| 0| 90| 0| 5.25| 5.50|
| 0|FALSE | 67| 0| 90| 0| 5.50| 5.75|
| 0|FALSE | 72| 0| 90| 0| 5.75| 6.00|
| 0|FALSE | 60| 0| 90| 0| 6.00| 6.25|
| 0|FALSE | 64| 0| 90| 0| 6.25| 6.50|
| 0|FALSE | 67| 0| 90| 0| 6.50| 6.75|
| 0|FALSE | 72| 0| 90| 0| 6.75| 7.00|
| 0|FALSE | 60| 0| 90| 0| 7.00| 7.25|
| 0|FALSE | 64| 0| 90| 0| 7.25| 7.50|
| 0|FALSE | 67| 0| 90| 0| 7.50| 7.75|
| 0|FALSE | 72| 0| 90| 0| 7.75| 8.00|
| 0|FALSE | 60| 0| 90| 0| 8.00| 8.25|
| 0|FALSE | 64| 0| 90| 0| 8.25| 8.50|
| 0|FALSE | 67| 0| 90| 0| 8.50| 8.75|
| 0|FALSE | 72| 0| 90| 0| 8.75| 9.00|
| 0|FALSE | 60| 0| 90| 0| 9.00| 9.25|
| 0|FALSE | 64| 0| 90| 0| 9.25| 9.50|
| 0|FALSE | 67| 0| 90| 0| 9.50| 9.75|
| 0|FALSE | 72| 0| 90| 0| 9.75| 10.00|
| 0|FALSE | 60| 0| 90| 0| 10.00| 10.25|
| 0|FALSE | 64| 0| 90| 0| 10.25| 10.50|
| 0|FALSE | 67| 0| 90| 0| 10.50| 10.75|
| 0|FALSE | 72| 0| 90| 0| 10.75| 11.00|
| 0|FALSE | 60| 0| 90| 0| 11.00| 11.25|
| 0|FALSE | 64| 0| 90| 0| 11.25| 11.50|
| 0|FALSE | 67| 0| 90| 0| 11.50| 11.75|
| 0|FALSE | 72| 0| 90| 0| 11.75| 12.00|
| 0|FALSE | 60| 0| 90| 0| 12.00| 12.25|
| 0|FALSE | 64| 0| 90| 0| 12.25| 12.50|
| 0|FALSE | 67| 0| 90| 0| 12.50| 12.75|
| 0|FALSE | 72| 0| 90| 0| 12.75| 13.00|
| 0|FALSE | 60| 0| 90| 0| 13.00| 13.25|
| 0|FALSE | 64| 0| 90| 0| 13.25| 13.50|
| 0|FALSE | 67| 0| 90| 0| 13.50| 13.75|
| 0|FALSE | 72| 0| 90| 0| 13.75| 14.00|
| 0|FALSE | 60| 0| 90| 0| 14.00| 14.25|
| 0|FALSE | 64| 0| 90| 0| 14.25| 14.50|
| 0|FALSE | 67| 0| 90| 0| 14.50| 14.75|
| 0|FALSE | 72| 0| 90| 0| 14.75| 15.00|
| 0|FALSE | 60| 0| 90| 0| 15.00| 15.25|
| 0|FALSE | 64| 0| 90| 0| 15.25| 15.50|
| 0|FALSE | 67| 0| 90| 0| 15.50| 15.75|
| 0|FALSE | 72| 0| 90| 0| 15.75| 16.00|
We can concatenate these different parts into one dataframe by also
changing the chords played with our small function
change_notes_on_measures()
:
combination <- bind_rows(
# We'll add our note variation
# of a major chord to tonic, subdominant and dominant:
bass %>% change_notes_on_measures(),
chords %>% change_notes_on_measures(),
arp %>% change_notes_on_measures(),
# But not on the drum :)
drum
) %>%
beats_to_ticks()
combination %>% kable()
Show dataframe of whole combination
| i_track|meta | note| channel| velocity_note_on| velocity_note_off| b_note_on| b_note_off| i_note| ticks_note_on| ticks_note_off|
|-------:|:-----|----:|-------:|----------------:|-----------------:|---------:|----------:|------:|-------------:|--------------:|
| 0|FALSE | 36| 0| 100| 0| 0.50| 1.50| NA| 480| 1440|
| 0|FALSE | 43| 0| 100| 0| 1.50| 2.50| NA| 1440| 2400|
| 0|FALSE | 41| 0| 100| 0| 2.50| 3.50| NA| 2400| 3360|
| 0|FALSE | 48| 0| 100| 0| 3.50| 4.50| NA| 3360| 4320|
| 0|FALSE | 36| 0| 100| 0| 4.50| 5.50| NA| 4320| 5280|
| 0|FALSE | 43| 0| 100| 0| 5.50| 6.50| NA| 5280| 6240|
| 0|FALSE | 41| 0| 100| 0| 6.50| 7.50| NA| 6240| 7200|
| 0|FALSE | 48| 0| 100| 0| 7.50| 8.50| NA| 7200| 8160|
| 0|FALSE | 41| 0| 100| 0| 8.50| 9.50| NA| 8160| 9120|
| 0|FALSE | 48| 0| 100| 0| 9.50| 10.50| NA| 9120| 10080|
| 0|FALSE | 46| 0| 100| 0| 10.50| 11.50| NA| 10080| 11040|
| 0|FALSE | 53| 0| 100| 0| 11.50| 12.50| NA| 11040| 12000|
| 0|FALSE | 43| 0| 100| 0| 12.50| 13.50| NA| 12000| 12960|
| 0|FALSE | 50| 0| 100| 0| 13.50| 14.50| NA| 12960| 13920|
| 0|FALSE | 48| 0| 100| 0| 14.50| 15.50| NA| 13920| 14880|
| 0|FALSE | 55| 0| 100| 0| 15.50| 16.50| NA| 14880| 15840|
| 0|FALSE | 60| 0| 70| 0| 0.00| 1.00| NA| 0| 960|
| 0|FALSE | 64| 0| 70| 0| 0.00| 1.00| NA| 0| 960|
| 0|FALSE | 67| 0| 70| 0| 0.00| 1.00| NA| 0| 960|
| 0|FALSE | 72| 0| 70| 0| 0.00| 1.00| NA| 0| 960|
| 0|FALSE | 60| 0| 70| 0| 1.00| 2.00| NA| 960| 1920|
| 0|FALSE | 64| 0| 70| 0| 1.00| 2.00| NA| 960| 1920|
| 0|FALSE | 67| 0| 70| 0| 1.00| 2.00| NA| 960| 1920|
| 0|FALSE | 72| 0| 70| 0| 1.00| 2.00| NA| 960| 1920|
| 0|FALSE | 60| 0| 70| 0| 2.00| 3.00| NA| 1920| 2880|
| 0|FALSE | 64| 0| 70| 0| 2.00| 3.00| NA| 1920| 2880|
| 0|FALSE | 67| 0| 70| 0| 2.00| 3.00| NA| 1920| 2880|
| 0|FALSE | 72| 0| 70| 0| 2.00| 3.00| NA| 1920| 2880|
| 0|FALSE | 60| 0| 70| 0| 3.00| 4.00| NA| 2880| 3840|
| 0|FALSE | 64| 0| 70| 0| 3.00| 4.00| NA| 2880| 3840|
| 0|FALSE | 67| 0| 70| 0| 3.00| 4.00| NA| 2880| 3840|
| 0|FALSE | 72| 0| 70| 0| 3.00| 4.00| NA| 2880| 3840|
| 0|FALSE | 60| 0| 70| 0| 4.00| 5.00| NA| 3840| 4800|
| 0|FALSE | 64| 0| 70| 0| 4.00| 5.00| NA| 3840| 4800|
| 0|FALSE | 67| 0| 70| 0| 4.00| 5.00| NA| 3840| 4800|
| 0|FALSE | 72| 0| 70| 0| 4.00| 5.00| NA| 3840| 4800|
| 0|FALSE | 60| 0| 70| 0| 5.00| 6.00| NA| 4800| 5760|
| 0|FALSE | 64| 0| 70| 0| 5.00| 6.00| NA| 4800| 5760|
| 0|FALSE | 67| 0| 70| 0| 5.00| 6.00| NA| 4800| 5760|
| 0|FALSE | 72| 0| 70| 0| 5.00| 6.00| NA| 4800| 5760|
| 0|FALSE | 60| 0| 70| 0| 6.00| 7.00| NA| 5760| 6720|
| 0|FALSE | 64| 0| 70| 0| 6.00| 7.00| NA| 5760| 6720|
| 0|FALSE | 67| 0| 70| 0| 6.00| 7.00| NA| 5760| 6720|
| 0|FALSE | 72| 0| 70| 0| 6.00| 7.00| NA| 5760| 6720|
| 0|FALSE | 60| 0| 70| 0| 7.00| 8.00| NA| 6720| 7680|
| 0|FALSE | 64| 0| 70| 0| 7.00| 8.00| NA| 6720| 7680|
| 0|FALSE | 67| 0| 70| 0| 7.00| 8.00| NA| 6720| 7680|
| 0|FALSE | 72| 0| 70| 0| 7.00| 8.00| NA| 6720| 7680|
| 0|FALSE | 65| 0| 70| 0| 8.00| 9.00| NA| 7680| 8640|
| 0|FALSE | 69| 0| 70| 0| 8.00| 9.00| NA| 7680| 8640|
| 0|FALSE | 72| 0| 70| 0| 8.00| 9.00| NA| 7680| 8640|
| 0|FALSE | 77| 0| 70| 0| 8.00| 9.00| NA| 7680| 8640|
| 0|FALSE | 65| 0| 70| 0| 9.00| 10.00| NA| 8640| 9600|
| 0|FALSE | 69| 0| 70| 0| 9.00| 10.00| NA| 8640| 9600|
| 0|FALSE | 72| 0| 70| 0| 9.00| 10.00| NA| 8640| 9600|
| 0|FALSE | 77| 0| 70| 0| 9.00| 10.00| NA| 8640| 9600|
| 0|FALSE | 65| 0| 70| 0| 10.00| 11.00| NA| 9600| 10560|
| 0|FALSE | 69| 0| 70| 0| 10.00| 11.00| NA| 9600| 10560|
| 0|FALSE | 72| 0| 70| 0| 10.00| 11.00| NA| 9600| 10560|
| 0|FALSE | 77| 0| 70| 0| 10.00| 11.00| NA| 9600| 10560|
| 0|FALSE | 65| 0| 70| 0| 11.00| 12.00| NA| 10560| 11520|
| 0|FALSE | 69| 0| 70| 0| 11.00| 12.00| NA| 10560| 11520|
| 0|FALSE | 72| 0| 70| 0| 11.00| 12.00| NA| 10560| 11520|
| 0|FALSE | 77| 0| 70| 0| 11.00| 12.00| NA| 10560| 11520|
| 0|FALSE | 67| 0| 70| 0| 12.00| 13.00| NA| 11520| 12480|
| 0|FALSE | 71| 0| 70| 0| 12.00| 13.00| NA| 11520| 12480|
| 0|FALSE | 74| 0| 70| 0| 12.00| 13.00| NA| 11520| 12480|
| 0|FALSE | 79| 0| 70| 0| 12.00| 13.00| NA| 11520| 12480|
| 0|FALSE | 67| 0| 70| 0| 13.00| 14.00| NA| 12480| 13440|
| 0|FALSE | 71| 0| 70| 0| 13.00| 14.00| NA| 12480| 13440|
| 0|FALSE | 74| 0| 70| 0| 13.00| 14.00| NA| 12480| 13440|
| 0|FALSE | 79| 0| 70| 0| 13.00| 14.00| NA| 12480| 13440|
| 0|FALSE | 67| 0| 70| 0| 14.00| 15.00| NA| 13440| 14400|
| 0|FALSE | 71| 0| 70| 0| 14.00| 15.00| NA| 13440| 14400|
| 0|FALSE | 74| 0| 70| 0| 14.00| 15.00| NA| 13440| 14400|
| 0|FALSE | 79| 0| 70| 0| 14.00| 15.00| NA| 13440| 14400|
| 0|FALSE | 67| 0| 70| 0| 15.00| 16.00| NA| 14400| 15360|
| 0|FALSE | 71| 0| 70| 0| 15.00| 16.00| NA| 14400| 15360|
| 0|FALSE | 74| 0| 70| 0| 15.00| 16.00| NA| 14400| 15360|
| 0|FALSE | 79| 0| 70| 0| 15.00| 16.00| NA| 14400| 15360|
| 0|FALSE | 60| 0| 90| 0| 0.00| 0.25| NA| 0| 240|
| 0|FALSE | 64| 0| 90| 0| 0.25| 0.50| NA| 240| 480|
| 0|FALSE | 67| 0| 90| 0| 0.50| 0.75| NA| 480| 720|
| 0|FALSE | 72| 0| 90| 0| 0.75| 1.00| NA| 720| 960|
| 0|FALSE | 60| 0| 90| 0| 1.00| 1.25| NA| 960| 1200|
| 0|FALSE | 64| 0| 90| 0| 1.25| 1.50| NA| 1200| 1440|
| 0|FALSE | 67| 0| 90| 0| 1.50| 1.75| NA| 1440| 1680|
| 0|FALSE | 72| 0| 90| 0| 1.75| 2.00| NA| 1680| 1920|
| 0|FALSE | 60| 0| 90| 0| 2.00| 2.25| NA| 1920| 2160|
| 0|FALSE | 64| 0| 90| 0| 2.25| 2.50| NA| 2160| 2400|
| 0|FALSE | 67| 0| 90| 0| 2.50| 2.75| NA| 2400| 2640|
| 0|FALSE | 72| 0| 90| 0| 2.75| 3.00| NA| 2640| 2880|
| 0|FALSE | 60| 0| 90| 0| 3.00| 3.25| NA| 2880| 3120|
| 0|FALSE | 64| 0| 90| 0| 3.25| 3.50| NA| 3120| 3360|
| 0|FALSE | 67| 0| 90| 0| 3.50| 3.75| NA| 3360| 3600|
| 0|FALSE | 72| 0| 90| 0| 3.75| 4.00| NA| 3600| 3840|
| 0|FALSE | 60| 0| 90| 0| 4.00| 4.25| NA| 3840| 4080|
| 0|FALSE | 64| 0| 90| 0| 4.25| 4.50| NA| 4080| 4320|
| 0|FALSE | 67| 0| 90| 0| 4.50| 4.75| NA| 4320| 4560|
| 0|FALSE | 72| 0| 90| 0| 4.75| 5.00| NA| 4560| 4800|
| 0|FALSE | 60| 0| 90| 0| 5.00| 5.25| NA| 4800| 5040|
| 0|FALSE | 64| 0| 90| 0| 5.25| 5.50| NA| 5040| 5280|
| 0|FALSE | 67| 0| 90| 0| 5.50| 5.75| NA| 5280| 5520|
| 0|FALSE | 72| 0| 90| 0| 5.75| 6.00| NA| 5520| 5760|
| 0|FALSE | 60| 0| 90| 0| 6.00| 6.25| NA| 5760| 6000|
| 0|FALSE | 64| 0| 90| 0| 6.25| 6.50| NA| 6000| 6240|
| 0|FALSE | 67| 0| 90| 0| 6.50| 6.75| NA| 6240| 6480|
| 0|FALSE | 72| 0| 90| 0| 6.75| 7.00| NA| 6480| 6720|
| 0|FALSE | 60| 0| 90| 0| 7.00| 7.25| NA| 6720| 6960|
| 0|FALSE | 64| 0| 90| 0| 7.25| 7.50| NA| 6960| 7200|
| 0|FALSE | 67| 0| 90| 0| 7.50| 7.75| NA| 7200| 7440|
| 0|FALSE | 72| 0| 90| 0| 7.75| 8.00| NA| 7440| 7680|
| 0|FALSE | 65| 0| 90| 0| 8.00| 8.25| NA| 7680| 7920|
| 0|FALSE | 69| 0| 90| 0| 8.25| 8.50| NA| 7920| 8160|
| 0|FALSE | 72| 0| 90| 0| 8.50| 8.75| NA| 8160| 8400|
| 0|FALSE | 77| 0| 90| 0| 8.75| 9.00| NA| 8400| 8640|
| 0|FALSE | 65| 0| 90| 0| 9.00| 9.25| NA| 8640| 8880|
| 0|FALSE | 69| 0| 90| 0| 9.25| 9.50| NA| 8880| 9120|
| 0|FALSE | 72| 0| 90| 0| 9.50| 9.75| NA| 9120| 9360|
| 0|FALSE | 77| 0| 90| 0| 9.75| 10.00| NA| 9360| 9600|
| 0|FALSE | 65| 0| 90| 0| 10.00| 10.25| NA| 9600| 9840|
| 0|FALSE | 69| 0| 90| 0| 10.25| 10.50| NA| 9840| 10080|
| 0|FALSE | 72| 0| 90| 0| 10.50| 10.75| NA| 10080| 10320|
| 0|FALSE | 77| 0| 90| 0| 10.75| 11.00| NA| 10320| 10560|
| 0|FALSE | 65| 0| 90| 0| 11.00| 11.25| NA| 10560| 10800|
| 0|FALSE | 69| 0| 90| 0| 11.25| 11.50| NA| 10800| 11040|
| 0|FALSE | 72| 0| 90| 0| 11.50| 11.75| NA| 11040| 11280|
| 0|FALSE | 77| 0| 90| 0| 11.75| 12.00| NA| 11280| 11520|
| 0|FALSE | 67| 0| 90| 0| 12.00| 12.25| NA| 11520| 11760|
| 0|FALSE | 71| 0| 90| 0| 12.25| 12.50| NA| 11760| 12000|
| 0|FALSE | 74| 0| 90| 0| 12.50| 12.75| NA| 12000| 12240|
| 0|FALSE | 79| 0| 90| 0| 12.75| 13.00| NA| 12240| 12480|
| 0|FALSE | 67| 0| 90| 0| 13.00| 13.25| NA| 12480| 12720|
| 0|FALSE | 71| 0| 90| 0| 13.25| 13.50| NA| 12720| 12960|
| 0|FALSE | 74| 0| 90| 0| 13.50| 13.75| NA| 12960| 13200|
| 0|FALSE | 79| 0| 90| 0| 13.75| 14.00| NA| 13200| 13440|
| 0|FALSE | 67| 0| 90| 0| 14.00| 14.25| NA| 13440| 13680|
| 0|FALSE | 71| 0| 90| 0| 14.25| 14.50| NA| 13680| 13920|
| 0|FALSE | 74| 0| 90| 0| 14.50| 14.75| NA| 13920| 14160|
| 0|FALSE | 79| 0| 90| 0| 14.75| 15.00| NA| 14160| 14400|
| 0|FALSE | 67| 0| 90| 0| 15.00| 15.25| NA| 14400| 14640|
| 0|FALSE | 71| 0| 90| 0| 15.25| 15.50| NA| 14640| 14880|
| 0|FALSE | 74| 0| 90| 0| 15.50| 15.75| NA| 14880| 15120|
| 0|FALSE | 79| 0| 90| 0| 15.75| 16.00| NA| 15120| 15360|
| 0|FALSE | 36| 9| 100| 0| 0.00| 0.50| 1| 0| 480|
| 0|FALSE | 38| 9| 100| 0| 1.00| 1.50| 2| 960| 1440|
| 0|FALSE | 36| 9| 100| 0| 2.00| 2.50| 3| 1920| 2400|
| 0|FALSE | 38| 9| 100| 0| 3.00| 3.50| 4| 2880| 3360|
| 0|FALSE | 36| 9| 100| 0| 4.00| 4.50| 5| 3840| 4320|
| 0|FALSE | 38| 9| 100| 0| 5.00| 5.50| 6| 4800| 5280|
| 0|FALSE | 36| 9| 100| 0| 6.00| 6.50| 7| 5760| 6240|
| 0|FALSE | 38| 9| 100| 0| 7.00| 7.50| 8| 6720| 7200|
| 0|FALSE | 36| 9| 100| 0| 8.00| 8.50| 9| 7680| 8160|
| 0|FALSE | 38| 9| 100| 0| 9.00| 9.50| 10| 8640| 9120|
| 0|FALSE | 36| 9| 100| 0| 10.00| 10.50| 11| 9600| 10080|
| 0|FALSE | 38| 9| 100| 0| 11.00| 11.50| 12| 10560| 11040|
| 0|FALSE | 36| 9| 100| 0| 12.00| 12.50| 13| 11520| 12000|
| 0|FALSE | 38| 9| 100| 0| 13.00| 13.50| 14| 12480| 12960|
| 0|FALSE | 36| 9| 100| 0| 14.00| 14.50| 15| 13440| 13920|
| 0|FALSE | 38| 9| 100| 0| 15.00| 15.50| 16| 14400| 14880|
mfr$update_notes_wide(combination)
mfr$play("combination.mp3")
Combine parts
In vignette("pyramidi", package = "pyramidi")
there is
an example with accumulate()
how you can generate multiple
midifiles while successively adding modifications to the data. Now we
will also successively add parts together, but in the same midifile.
(part_names <- c("drum", "bass", "chords", "arp") %>% accumulate(paste, sep = " + "))
#> [1] "drum" "drum + bass"
#> [3] "drum + bass + chords" "drum + bass + chords + arp"
To do this, let’s first generate a list of midi frames, where at each step the accumulative former results are added to the new:
augmentation <- list(
drum,
chords %>% change_notes_on_measures(),
bass %>% change_notes_on_measures(),
arp %>% change_notes_on_measures()
) %>%
accumulate(full_join) %>%
set_names(part_names)
#> Joining with `by = join_by(i_track, meta, note, channel, velocity_note_on,
#> velocity_note_off, b_note_on, b_note_off)`
#> Joining with `by = join_by(i_track, meta, note, channel, velocity_note_on,
#> velocity_note_off, b_note_on, b_note_off)`
#> Joining with `by = join_by(i_track, meta, note, channel, velocity_note_on,
#> velocity_note_off, b_note_on, b_note_off)`
augmentation
Click here to see the list of parts.
$drum
[38;5;246m# A tibble: 16 × 9
[39m
i_track meta note channel i_note velocity_note_on velocity_note_off
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<lgl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<int>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[38;5;250m 1
[39m 0 FALSE 36 9 1 100 0
[38;5;250m 2
[39m 0 FALSE 38 9 2 100 0
[38;5;250m 3
[39m 0 FALSE 36 9 3 100 0
[38;5;250m 4
[39m 0 FALSE 38 9 4 100 0
[38;5;250m 5
[39m 0 FALSE 36 9 5 100 0
[38;5;250m 6
[39m 0 FALSE 38 9 6 100 0
[38;5;250m 7
[39m 0 FALSE 36 9 7 100 0
[38;5;250m 8
[39m 0 FALSE 38 9 8 100 0
[38;5;250m 9
[39m 0 FALSE 36 9 9 100 0
[38;5;250m10
[39m 0 FALSE 38 9 10 100 0
[38;5;250m11
[39m 0 FALSE 36 9 11 100 0
[38;5;250m12
[39m 0 FALSE 38 9 12 100 0
[38;5;250m13
[39m 0 FALSE 36 9 13 100 0
[38;5;250m14
[39m 0 FALSE 38 9 14 100 0
[38;5;250m15
[39m 0 FALSE 36 9 15 100 0
[38;5;250m16
[39m 0 FALSE 38 9 16 100 0
[38;5;246m# ℹ 2 more variables: b_note_on <int>, b_note_off <dbl>
[39m
$`drum + bass`
[38;5;246m# A tibble: 80 × 9
[39m
i_track meta note channel i_note velocity_note_on velocity_note_off
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<lgl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<int>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[38;5;250m 1
[39m 0 FALSE 36 9 1 100 0
[38;5;250m 2
[39m 0 FALSE 38 9 2 100 0
[38;5;250m 3
[39m 0 FALSE 36 9 3 100 0
[38;5;250m 4
[39m 0 FALSE 38 9 4 100 0
[38;5;250m 5
[39m 0 FALSE 36 9 5 100 0
[38;5;250m 6
[39m 0 FALSE 38 9 6 100 0
[38;5;250m 7
[39m 0 FALSE 36 9 7 100 0
[38;5;250m 8
[39m 0 FALSE 38 9 8 100 0
[38;5;250m 9
[39m 0 FALSE 36 9 9 100 0
[38;5;250m10
[39m 0 FALSE 38 9 10 100 0
[38;5;246m# ℹ 70 more rows
[39m
[38;5;246m# ℹ 2 more variables: b_note_on <dbl>, b_note_off <dbl>
[39m
$`drum + bass + chords`
[38;5;246m# A tibble: 96 × 9
[39m
i_track meta note channel i_note velocity_note_on velocity_note_off
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<lgl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<int>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[38;5;250m 1
[39m 0 FALSE 36 9 1 100 0
[38;5;250m 2
[39m 0 FALSE 38 9 2 100 0
[38;5;250m 3
[39m 0 FALSE 36 9 3 100 0
[38;5;250m 4
[39m 0 FALSE 38 9 4 100 0
[38;5;250m 5
[39m 0 FALSE 36 9 5 100 0
[38;5;250m 6
[39m 0 FALSE 38 9 6 100 0
[38;5;250m 7
[39m 0 FALSE 36 9 7 100 0
[38;5;250m 8
[39m 0 FALSE 38 9 8 100 0
[38;5;250m 9
[39m 0 FALSE 36 9 9 100 0
[38;5;250m10
[39m 0 FALSE 38 9 10 100 0
[38;5;246m# ℹ 86 more rows
[39m
[38;5;246m# ℹ 2 more variables: b_note_on <dbl>, b_note_off <dbl>
[39m
$`drum + bass + chords + arp`
[38;5;246m# A tibble: 160 × 9
[39m
i_track meta note channel i_note velocity_note_on velocity_note_off
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<lgl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<int>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[3m
[38;5;246m<dbl>
[39m
[23m
[38;5;250m 1
[39m 0 FALSE 36 9 1 100 0
[38;5;250m 2
[39m 0 FALSE 38 9 2 100 0
[38;5;250m 3
[39m 0 FALSE 36 9 3 100 0
[38;5;250m 4
[39m 0 FALSE 38 9 4 100 0
[38;5;250m 5
[39m 0 FALSE 36 9 5 100 0
[38;5;250m 6
[39m 0 FALSE 38 9 6 100 0
[38;5;250m 7
[39m 0 FALSE 36 9 7 100 0
[38;5;250m 8
[39m 0 FALSE 38 9 8 100 0
[38;5;250m 9
[39m 0 FALSE 36 9 9 100 0
[38;5;250m10
[39m 0 FALSE 38 9 10 100 0
[38;5;246m# ℹ 150 more rows
[39m
[38;5;246m# ℹ 2 more variables: b_note_on <dbl>, b_note_off <dbl>
[39m
All of these parts start at time 0. In order to make the parts start one after one another, we need to shift them in time. This is what the following code does.
# after augmenting, we'll add parts subtracting the instruments one after one
# another (the rev()erse):
composition <- c(augmentation, rev(set_names(augmentation, ~paste0(., "2")))) %>%
# put them in one dataframe and modify the starting time of the notes in the parts:
bind_rows(.id = "part") %>%
# (we need as_factor() to avoid alphabetical ordering of the parts)
group_by(part = as_factor(part)) %>%
mutate(i_part = cur_group_id()) %>%
ungroup() %>%
mutate_at(c("b_note_on", "b_note_off"), ~ . + (i_part - 1) * n_beats) %>%
# remove new columns to have the needed format for midi export:
select(-part, -i_part) %>%
beats_to_ticks()
Let’s have a listen to my first composition in R:
mfr$update_notes_wide(composition)
mfr$play("composition.mp3")