circle_of_fifths.f90 Source File


This file depends on

sourcefile~~circle_of_fifths.f90~~EfferentGraph sourcefile~circle_of_fifths.f90 circle_of_fifths.f90 sourcefile~gm_instruments.f90 GM_instruments.f90 sourcefile~circle_of_fifths.f90->sourcefile~gm_instruments.f90 sourcefile~midi_control_changes.f90 MIDI_control_changes.f90 sourcefile~circle_of_fifths.f90->sourcefile~midi_control_changes.f90 sourcefile~midi_file_class.f90 MIDI_file_class.f90 sourcefile~circle_of_fifths.f90->sourcefile~midi_file_class.f90 sourcefile~music.f90 music.f90 sourcefile~circle_of_fifths.f90->sourcefile~music.f90 sourcefile~utilities.f90 utilities.f90 sourcefile~midi_file_class.f90->sourcefile~utilities.f90 sourcefile~music_common.f90 music_common.f90 sourcefile~music.f90->sourcefile~music_common.f90 sourcefile~music.f90->sourcefile~utilities.f90

Source Code

! ForMIDI: a small Fortran MIDI sequencer for composing music and exploring 
!          algorithmic music
! License GPL-3.0-or-later
! Vincent Magnin
! Last modifications: 2024-06-22

!--------------------------------------
!> A random walk on the circle of fifths
!--------------------------------------
program circle_of_fifths
    use, intrinsic :: iso_fortran_env, only: dp=>real64
    use MIDI_file_class
    use music
    use MIDI_control_changes, only: Effects_1_Depth
    ! Contains the list of General MIDI 128 instruments and 47 percussions:
    use GM_instruments

    implicit none
    type(MIDI_file) :: midi
    integer :: channel, instrument, velocity, note
    character(3) :: name
    logical  :: major
    integer, parameter :: length = 200
    integer  :: i
    real(dp) :: p

    ! Create a file with 2 tracks (including the metadata track):
    ! The first track is always a metadata track. We define the 
    ! tempo: a quarter note will last 500000 µs = 0.5 s => tempo = 120 bpm
    call midi%new("circle_of_fifths.mid", format=1, tracks=2, divisions=quarter_note, tempo=500000)

    ! (1) The single music track:
    call midi%track_header()

    ! Sounds also good with instruments String_Ensemble_2 and Pad_8_sweep:
    instrument = Choir_Aahs
    ! We will use altenatively MIDI channels 0 and 1 to avoid cutting
    ! the tail of each chord:
    call midi%Program_Change(channel=0, instrument=instrument)
    call midi%Program_Change(channel=1, instrument=instrument)
    ! Heavy (127) reverb effect:
    call midi%Control_Change(channel=0, type=Effects_1_Depth, ctl_value=127)  ! Reverb
    call midi%Control_Change(channel=1, type=Effects_1_Depth, ctl_value=127)  ! Reverb

    ! We start with C Major (note at the top of the Major circle):
    note = 1
    major = .true.
    name = trim(CIRCLE_OF_FIFTHS_MAJOR(note)) // "4"
    call midi%play_chord(channel=0, note=MIDI_Note(name), chord=MAJOR_CHORD, velocity=f_level+10, value=whole_note)

    ! A random walk with three events: we can go one note clockwise,
    ! one note counterclockwise or switch Major<->minor.
    do i = 1, length
        ! A random number 0 <= p < 3
        call random_number(p)
        p = 3 * p
        ! The three possible events:
        if (p >= 2.0_dp) then
            note = note + 1
            if (note > 12) note = 1
        else if (p >= 1.0_dp) then
            note = note - 1
            if (note < 1) note = 12
        else
            major = .not. major
        end if

        ! Alternate between channels 0 and 1:
        channel = mod(i, 2)

        ! The volume will evolve, to obtain some dynamics:
        velocity = f_level + 10 + int(20*sin(real(i)))

        ! Write a major or minor chord on the track:
        if (major) then
            name = trim(CIRCLE_OF_FIFTHS_MAJOR(note)) // "4"
            call midi%play_chord(channel, MIDI_Note(name), MAJOR_CHORD, velocity, whole_note)
        else
            name = trim(CIRCLE_OF_FIFTHS_MINOR(note)) // "4"
            call midi%play_chord(channel, MIDI_Note(name), MINOR_CHORD, velocity, whole_note)
        end if
    end do

    call midi%end_of_track()

    call midi%close()

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