motifs.f90 Source File


This file depends on

sourcefile~~motifs.f90~~EfferentGraph sourcefile~motifs.f90 motifs.f90 sourcefile~gm_instruments.f90 GM_instruments.f90 sourcefile~motifs.f90->sourcefile~gm_instruments.f90 sourcefile~midi_control_changes.f90 MIDI_control_changes.f90 sourcefile~motifs.f90->sourcefile~midi_control_changes.f90 sourcefile~midi_file_class.f90 MIDI_file_class.f90 sourcefile~motifs.f90->sourcefile~midi_file_class.f90 sourcefile~music.f90 music.f90 sourcefile~motifs.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, 2024-07-01
! Last modifications: 2024-07-04

!> An example mixing Dmitri Shostakovich's [DSCH motif](https://en.wikipedia.org/wiki/DSCH_motif)
!> and [BACH motif](https://en.wikipedia.org/wiki/BACH_motif), with four
!> musical tracks.
program motifs
    use MIDI_file_class
    use music
    use MIDI_control_changes, only: Effects_1_Depth, Effects_3_Depth, Pan
    ! Contains the list of General MIDI 128 instruments and 47 percussions:
    use GM_instruments

    implicit none
    type(MIDI_file) :: midi
    integer, parameter :: arpeggio(1:6) = [ 0, 7, 12, 7, 12, 7 ]
    integer, parameter :: octave=12
    integer :: values(1:6)
    integer :: i, j, k, n, v
    integer :: BACH(4)
    integer :: DSCH(4)
    integer :: scale(6)

    ! BACH and DSCH are in German notation:
    BACH(1) = MIDI_Note("Bb2")  ! B
    BACH(2) = MIDI_Note("A2")   ! A
    BACH(3) = MIDI_Note("C3")   ! C
    BACH(4) = MIDI_Note("B2")   ! H

    DSCH(1) = MIDI_Note("D3")   ! D
    DSCH(2) = MIDI_Note("Eb3")  ! Es
    DSCH(3) = MIDI_Note("C3")   ! C
    DSCH(4) = MIDI_Note("B2")   ! H

    ! The total value of the arpeggio is a whole note (four quarter notes):
    values(1) = dotted(eighth_note)
    values(2) = eighth_note
    values(3) = dotted(eighth_note)
    values(4) = eighth_note
    values(5) = dotted(eighth_note)
    values(6) = dotted(eighth_note)

    ! A scale composed of all notes in the two motifs:
    scale = [ MIDI_Note("A2"), MIDI_Note("Bb2"), MIDI_Note("B2"), MIDI_Note("C3"), MIDI_Note("D3"), MIDI_Note("Eb3")]

    ! Create a file with 5 tracks (including the metadata track):
    ! A quarter note will last 375000 µs = 0.375 s => tempo = 160 bpm
    ! The time signature is 4/4 (default value).
    call midi%new("motifs.mid", format=1, tracks=5, divisions=quarter_note, tempo=375000)

    ! (1) A bass track on MIDI channel 0
    call midi%track_header(track_name="bass")
    ! Chorus:
    call midi%Control_Change(channel=0, type=Effects_3_Depth, ctl_value=32)
    ! 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=Electric_Bass_finger)

    ! The four musical tracks will use the same loops, to follow the structure
    ! of the song and stay synchronized, using silence when necessary.

    ! Intro
    ! Silence (velocity=0):
    call midi%play_note(channel=0, note=0, velocity=0, value=whole_note)
    ! Playing the scale:
    do i = 1, size(scale)
        call midi%play_note(channel=0, note=scale(i), velocity=f_level, value=half_note)
    end do

    do k = 1, 2
        ! Chorus
        do j = 1, 4
            do i = 1, size(DSCH)
                ! Duration = whole note
                call midi%play_broken_chord(channel=0, note=DSCH(i), chord=arpeggio, velocity=ff_level, values=values)
            end do
        end do

        ! Verse
        do j = 1, 4
            do i = 1, size(BACH)
                ! Duration = whole note
                call midi%play_broken_chord(channel=0, note=BACH(i), chord=arpeggio, velocity=ff_level, values=values)
            end do
        end do
    end do

    ! Outro
    ! Reverb:
    call midi%Control_Change(channel=0, type=Effects_1_Depth, ctl_value=127)
    do i = 1, size(scale)
        ! With decreasing level and increasing duration:
        call midi%play_chord(channel=0, note=scale(i), chord=MAJOR_CHORD, &
                           & velocity=int(ff_level/(1.2**i)), value=int(half_note*1.2**i))
    end do

    call midi%end_of_track()

    !---------------------------------------------------------------------------
    ! (2) A synth track on MIDI channel 1
    call midi%track_header(track_name="synth")
    ! 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=80)
    ! Choosing the instrument:
    call midi%Program_Change(channel=1, instrument=Pad_2_warm)

    ! Intro
    ! Silence:
    call midi%play_note(channel=1, note=0, velocity=0, value=whole_note)
    ! Playing the scale:
    do i = 1, size(scale)
        call midi%play_chord(channel=1, note=scale(i), chord=MAJOR_CHORD, velocity=f_level, value=half_note)
    end do

    do k = 1, 2
        ! Chorus
        do j = 1, 4
            do i = 1, size(DSCH)
                call midi%play_chord(channel=1, note=DSCH(i), chord=MAJOR_CHORD, velocity=ff_level, value=whole_note)
            end do
        end do

        ! Verse
        do j = 1, 4
            do i = 1, size(BACH)
                call midi%play_chord(channel=1, note=BACH(i), chord=MAJOR_CHORD, velocity=ff_level, value=whole_note)
            end do
        end do
    end do

    call midi%end_of_track()

    !---------------------------------------------------------------------------
    ! (3) A drums track
    call midi%track_header(track_name="drums")
    ! Reverb:
    call midi%Control_Change(channel=drums, type=Effects_1_Depth, ctl_value=127)
    ! Panning (center is 64):
    call midi%Control_Change(channel=drums, type=Pan, ctl_value=64)

    ! Intro
    do i = 1, size(scale)+2
        call midi%play_note(channel=drums, note=Side_Stick, velocity=ff_level, value=half_note)
    end do

    do k = 1, 2
        ! Chorus
        do j = 1, 4
            ! The total value of the broken chord is a whole note (four quarter notes):
            do i = 1, size(DSCH)
                call midi%play_note(channel=drums, note=Bass_Drum_1,    velocity=ffff_level, &
                                  & value=quarter_note)
                call midi%play_note(channel=drums, note=Closed_Hi_Hat,  velocity=ffff_level, &
                                  & value=quarter_note)
                call midi%play_note(channel=drums, note=Bass_Drum_1,    velocity=ffff_level, &
                                  & value=quarter_note)
                call midi%play_note(channel=drums, note=Acoustic_Snare, velocity=ffff_level, &
                                  & value=quarter_note)
            end do
        end do

        ! Verse
        do j = 1, 4
            do i = 1, size(BACH)
                call midi%play_note(channel=drums, note=Bass_Drum_1,   velocity=ffff_level, value=quarter_note)
                call midi%play_note(channel=drums, note=Closed_Hi_Hat, velocity=ffff_level, value=quarter_note)
                call midi%play_note(channel=drums, note=Bass_Drum_1,   velocity=ffff_level, value=quarter_note)
                call midi%play_note(channel=drums, note=Closed_Hi_Hat, velocity=ffff_level, value=quarter_note)
            end do
        end do
    end do

    call midi%end_of_track()

    !---------------------------------------------------------------------------
    ! (4) A guitar track on MIDI channel 2
    call midi%track_header(track_name="guitar")
    ! Reverb:
    call midi%Control_Change(channel=2, type=Effects_1_Depth, ctl_value=127)
    ! Panning, slightly on the left (center is 64):
    call midi%Control_Change(channel=2, type=Pan, ctl_value=32)
    ! Choosing the instrument:
    call midi%Program_Change(channel=2, instrument=Acoustic_Guitar_nylon)

    ! Intro
    ! Silence:
    call midi%play_note(channel=2, note=0, velocity=0, value=whole_note)
    ! Silence:
    do i = 1, size(scale)
        call midi%play_note(channel=2, note=0, velocity=0, value=half_note)
    end do

    ! Base note:
    n = DSCH(1)+octave
    ! fifth=+7, fourth=+5, 7th=+10, octave=+12
    do k = 1, 2
        do j = 1, 4*4
            if ((k == 1).and.(j<=8)) then
                v = 0   ! silence at the beginning of the song
            else
                v = f_level-4
            end if
            call midi%play_note(channel=2, note=n+7, velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+5, velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+7, velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+5, velocity=v, value=quarter_note)
        end do

        do j = 1, 4
            call midi%play_note(channel=2, note=n+7,  velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+10, velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+7,  velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+10, velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+12, velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+10, velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+7,  velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+12, velocity=v, value=quarter_note)
        end do

        do j = 1, 4
            call midi%play_note(channel=2, note=n+7,  velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+10, velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+7,  velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+10, velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+12, velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+10, velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+7,  velocity=v, value=quarter_note)
            call midi%play_note(channel=2, note=n+5,  velocity=v, value=quarter_note)
        end do
    end do

    call midi%end_of_track()

    !---------------------------------------------------------------------------
    call midi%close()

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

end program motifs