canon.f90 Source File


This file depends on

sourcefile~~canon.f90~~EfferentGraph sourcefile~canon.f90 canon.f90 sourcefile~gm_instruments.f90 GM_instruments.f90 sourcefile~canon.f90->sourcefile~gm_instruments.f90 sourcefile~midi_control_changes.f90 MIDI_control_changes.f90 sourcefile~canon.f90->sourcefile~midi_control_changes.f90 sourcefile~midi_file_class.f90 MIDI_file_class.f90 sourcefile~canon.f90->sourcefile~midi_file_class.f90 sourcefile~music.f90 music.f90 sourcefile~canon.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

!> An example based on the first measures of Pachelbel's Canon
!> https://en.wikipedia.org/wiki/Pachelbel%27s_Canon
program canon
    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
    ! Notes of the bass and theme:
    character(3), parameter :: bass(1:8) =  ["D3 ","A2 ","B2 ","F#2","G2 ", &
                                            &"D2 ","G2 ","A2 " ]
    character(3), parameter :: theme(1:16) = [ "F#5","E5 ","D5 ","C#5", &
                                             & "B4 ","A4 ","B4 ","C#5", &
                                             & "D5 ","C#5","B4 ","A4 ", &
                                             & "G4 ","F#4","G4 ","E4 " ]
    ! List of General MIDI instruments to use sequentially:
    integer, parameter :: instrument(1:17) = [ 40, 41, 42, 44, 45, 48,&
                                 & 49, 51, 52, 89, 90, 91, 92, 94, 95, 99, 100 ]
    ! Pan value for each track:
    integer, parameter :: panning(2:5) = [ 54, 34, 74, 94 ]
    integer :: track
    character(13) :: track_name
    integer :: i, j

    ! Create a file with 5 tracks (including the metadata track):
    ! A quarter note will last 1000000 µs = 1 s => tempo = 60 bpm
    call midi%new("canon.mid", format=1, tracks=5, divisions=quarter_note, tempo=1000000, copyright="Public domain")

    ! (1) A first music track: ground bass
    call midi%track_header(track_name="ground bass")
    call midi%Control_Change(channel=0, type=Effects_1_Depth, ctl_value=64)  ! Reverb
    ! Instrument on channel 0:
    call midi%Program_Change(channel=0, instrument=String_Ensemble_1)
    ! Panning:
    call midi%Control_Change(channel=0, type=Pan, ctl_value=panning(2))

    do j = 1, 30
        do i = 1, 8
            call midi%play_note(channel=0, note=MIDI_Note(bass(i)), velocity=mf_level, value=quarter_note)
        end do
    end do
    call midi%end_of_track()

    ! Three other music tracks: a three voices canon with various instruments
    do track = 3, 5
        write(track_name, '("Canon voice ",I0)') track-2
        call midi%track_header(track_name)

        ! Reverb and pan:
        call midi%Control_Change(channel=track, type=Effects_1_Depth, ctl_value=64)
        call midi%Control_Change(channel=track, type=Pan, ctl_value=panning(track))

        ! A pause to shift the start of each voice of the canon:
        call midi%play_note(channel=track, note=0, velocity=0, value=8*quarter_note*(track - 2))

        do j = 1, 15
            ! Let's change regularly the instruments to add some variations:
            call midi%Program_Change(channel=track, instrument=instrument((track - 3) + j))
            ! Let's play the theme:
            do i = 1, 16
                call midi%play_note(channel=track, note=MIDI_Note(theme(i)), velocity=mf_level, value=quarter_note)
            end do
        end do

        call midi%end_of_track()
    end do

    call midi%close()

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