la_folia Program

Uses

  • program~~la_folia~~UsesGraph program~la_folia la_folia module~gm_instruments GM_instruments program~la_folia->module~gm_instruments module~midi_control_changes MIDI_control_changes program~la_folia->module~midi_control_changes module~midi_file_class MIDI_file_class program~la_folia->module~midi_file_class module~music music program~la_folia->module~music iso_fortran_env iso_fortran_env module~midi_file_class->iso_fortran_env module~utilities utilities module~midi_file_class->module~utilities module~music->iso_fortran_env module~music_common music_common module~music->module~music_common module~music->module~utilities module~utilities->iso_fortran_env

An example on the classical Portuguese/Spanish theme of La Folia https://en.wikipedia.org/wiki/Folia


Calls

program~~la_folia~~CallsGraph program~la_folia la_folia proc~analyze analyze program~la_folia->proc~analyze proc~control_change MIDI_file%Control_Change program~la_folia->proc~control_change proc~dotted dotted program~la_folia->proc~dotted proc~end_of_track MIDI_file%end_of_track program~la_folia->proc~end_of_track proc~get_name MIDI_file%get_name program~la_folia->proc~get_name proc~midi_note MIDI_Note program~la_folia->proc~midi_note proc~new MIDI_file%new program~la_folia->proc~new proc~play_broken_chord MIDI_file%play_broken_chord program~la_folia->proc~play_broken_chord proc~play_chord MIDI_file%play_chord program~la_folia->proc~play_chord proc~program_change MIDI_file%Program_Change program~la_folia->proc~program_change proc~track_header MIDI_file%track_header program~la_folia->proc~track_header proc~checked_int8 checked_int8 proc~control_change->proc~checked_int8 proc~delta_time MIDI_file%delta_time proc~control_change->proc~delta_time proc~end_of_track->proc~delta_time proc~write_track_size MIDI_file%write_track_size proc~end_of_track->proc~write_track_size proc~new->proc~end_of_track proc~new->proc~track_header proc~checked_int16 checked_int16 proc~new->proc~checked_int16 proc~checked_int32 checked_int32 proc~new->proc~checked_int32 proc~new->proc~checked_int8 proc~copyright_notice MIDI_file%copyright_notice proc~new->proc~copyright_notice proc~init_formidi MIDI_file%init_formidi proc~new->proc~init_formidi proc~set_tempo MIDI_file%set_tempo proc~new->proc~set_tempo proc~set_time_signature MIDI_file%set_time_signature proc~new->proc~set_time_signature proc~text_event MIDI_file%text_event proc~new->proc~text_event proc~play_broken_chord->proc~checked_int32 proc~play_broken_chord->proc~delta_time proc~note_off MIDI_file%Note_OFF proc~play_broken_chord->proc~note_off proc~note_on MIDI_file%Note_ON proc~play_broken_chord->proc~note_on proc~play_chord->proc~checked_int32 proc~play_chord->proc~delta_time proc~play_chord->proc~note_off proc~play_chord->proc~note_on proc~program_change->proc~checked_int8 proc~program_change->proc~delta_time proc~sequence_track_name MIDI_file%sequence_track_name proc~track_header->proc~sequence_track_name proc~track_header->proc~text_event proc~write_string MIDI_file%write_string proc~copyright_notice->proc~write_string proc~delta_time->proc~checked_int32 proc~write_variable_length_quantity MIDI_file%write_variable_length_quantity proc~delta_time->proc~write_variable_length_quantity proc~note_off->proc~checked_int8 proc~note_on->proc~checked_int8 proc~sequence_track_name->proc~write_string proc~set_tempo->proc~checked_int32 proc~set_tempo->proc~delta_time proc~set_time_signature->proc~checked_int8 proc~set_time_signature->proc~delta_time proc~text_event->proc~write_string proc~write_string->proc~checked_int8 proc~write_string->proc~delta_time proc~write_string->proc~write_variable_length_quantity proc~variable_length_quantity variable_length_quantity proc~write_variable_length_quantity->proc~variable_length_quantity

Variables

Type Attributes Name Initial
integer, dimension(3) :: arpeggio1
integer, dimension(3) :: arpeggio2
character(len=3) :: chord_type
character(len=7), parameter :: chords(1:17) = ["D3 m h.", "A2 7 h.", "D3 m h.", "C3 M h.", "F3 M h.", "C3 M h.", "D3 m h.", "A2 7 h.", "D3 m h.", "A2 7 h.", "D3 m h.", "C3 M h.", "F3 M h.", "C3 M h.", "D3 m h.", "A2 7 h.", "D3 m h."]
integer :: d
integer :: i
integer :: j
type(MIDI_file) :: midi
integer :: n
character(len=3) :: note
character(len=3) :: note_value

Subroutines

subroutine analyze(string, note, chord_type, note_value)

Receives a string with an encoded chord, and returns its fundamental, the type of chord and its encoded value

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: string
character(len=3), intent(out) :: note
character(len=3), intent(out) :: chord_type
character(len=3), intent(out) :: note_value

Source Code

program la_folia
    use MIDI_file_class
    use music
    use MIDI_control_changes, only: Effects_1_Depth, Pan
    ! Contains the list of General MIDI 128 instruments and 47 percussions:
    use GM_instruments

    implicit none
    type(MIDI_file) :: midi
    integer :: n, d
    character(3) :: note, chord_type, note_value
    integer, dimension(3) :: arpeggio1, arpeggio2
    ! Chords of the Folia theme in D minor.
    ! This is a first attempt to encode a chord into a string with its fundamental,
    ! its type (M, m, 7th...) and its value (w, q, h, etc.).
    ! That system may evolve in the future.
    ! https://en.wikipedia.org/wiki/Note_value
    character(7), parameter :: chords(1:17) = [ "D3 m h.","A2 7 h.","D3 m h.","C3 M h.", &
                                              & "F3 M h.","C3 M h.","D3 m h.","A2 7 h.", &
                                              & "D3 m h.","A2 7 h.","D3 m h.","C3 M h.", &
                                              & "F3 M h.","C3 M h.","D3 m h.","A2 7 h.","D3 m h." ]
    integer :: i, j

    ! Create a file with 3 tracks (including the metadata track):
    ! A quarter note will last 600000 µs = 0.6 s => tempo = 100 bpm
    ! The time signature is 3/4 (this argument is optional with 4/4 for default value).
    call midi%new("la_folia.mid", format=1, tracks=3, divisions=quarter_note, tempo=600000, &
                & time_signature=[3, 4], copyright="Public domain")

    ! (1) A track with chords played by strings on MIDI channel 0
    call midi%track_header(track_name="chords")
    ! Reverb:
    call midi%Control_Change(channel=0, type=Effects_1_Depth, ctl_value=64)
    ! Panning, slightly on the left (center is 64):
    call midi%Control_Change(channel=0, type=Pan, ctl_value=44)
    ! Choosing the instrument:
    call midi%Program_Change(channel=0, instrument=String_Ensemble_1)

    ! We repeat the theme three times identically:
    do j = 1, 3
        do i = 1, 17
            call analyze(chords(i), note, chord_type, note_value)
            if (note_value(1:1) == "q") d = quarter_note      ! quarter note
            if (note_value(1:1) == "h") d = half_note         ! half note
            if (note_value(2:2) == ".") d = dotted(d)         ! Dotted note

            n = MIDI_Note(trim(note))

            select case(trim(chord_type))
            case("m")
                call midi%play_chord(channel=0, note=n, chord=MINOR_CHORD, velocity=f_level, value=d)
            case("M")
                call midi%play_chord(channel=0, note=n, chord=MAJOR_CHORD, velocity=f_level, value=d)
            case("7")
                call midi%play_chord(channel=0, note=n, chord=DOMINANT_7TH_CHORD, velocity=f_level, value=d)
            end select
        end do
    end do
    ! Outro:
    call midi%play_chord(channel=0, note=n, chord=MINOR_CHORD, velocity=f_level, value=d)

    call midi%end_of_track()

    ! (2) A track with arpeggios by plucked strings on MIDI channel 1
    call midi%track_header(track_name="la Folia")
    ! Reverb:
    call midi%Control_Change(channel=1, type=Effects_1_Depth, ctl_value=64)
    ! Panning, slightly on the right (center is 64):
    call midi%Control_Change(channel=1, type=Pan, ctl_value=84)
    ! Choosing the instrument:
    call midi%Program_Change(channel=1, instrument=Electric_Guitar_clean)

    ! We repeat the theme three times but with various arpeggios:
    do j = 1, 3
        do i = 1, 17
            call analyze(chords(i), note, chord_type, note_value)
            if (note_value(1:1) == "q") d = eighth_note
            if (note_value(1:1) == "h") d = quarter_note
            if (note_value(2:2) == ".") d = dotted(d)

            n = MIDI_Note(trim(note))

            select case (trim(chord_type))
            case("m")
                arpeggio1 = MINOR_CHORD
            case("M")
                arpeggio1 = MAJOR_CHORD
            case("7")
                ! We don't play the fifth (7), because we want only three notes, not four:
                arpeggio1 = [ 0, 4, 10 ]
            end select

            ! Each chord is played two times, in various ways:
            select case(j)
            case(1)
                ! Swept the same way:
                arpeggio2 = arpeggio1
            case(2)
                ! The second time, swept in reverse order:
                arpeggio2 = arpeggio1(3:1:-1)
            case(3)
                ! Both reversed:
                arpeggio2 = arpeggio1(3:1:-1)
                arpeggio1 = arpeggio2
            end select

            call midi%play_broken_chord(channel=1, note=n, chord=arpeggio1, velocity=mf_level, value=d)
            call midi%play_broken_chord(channel=1, note=n, chord=arpeggio2, velocity=mf_level, value=d)
        end do
    end do

    call midi%end_of_track()

    call midi%close()

    print *,"You can now play the file ", midi%get_name()

contains

    !> Receives a string with an encoded chord, and returns its fundamental,
    !> the type of chord and its encoded value
    subroutine analyze(string, note, chord_type, note_value)
        character(*), intent(in) :: string
        character(3), intent(out) :: note, chord_type, note_value
        integer :: i1, i2

        i1=index(trim(string), " ", back=.false.)
        i2=index(trim(string), " ", back=.true.)
        note       = string(1:i1-1)
        chord_type = string(i1+1:i2-1)
        note_value = string(i2+1:)
    end subroutine

end program la_folia