blues.f90 Source File


This file depends on

sourcefile~~blues.f90~~EfferentGraph sourcefile~blues.f90 blues.f90 sourcefile~gm_instruments.f90 GM_instruments.f90 sourcefile~blues.f90->sourcefile~gm_instruments.f90 sourcefile~midi_control_changes.f90 MIDI_control_changes.f90 sourcefile~blues.f90->sourcefile~midi_control_changes.f90 sourcefile~midi_file_class.f90 MIDI_file_class.f90 sourcefile~blues.f90->sourcefile~midi_file_class.f90 sourcefile~music.f90 music.f90 sourcefile~blues.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 stochastic blues
program blues
    use, intrinsic :: iso_fortran_env, only: dp=>real64
    use MIDI_file_class
    use music
    use MIDI_control_changes, only: Effects_1_Depth, Modulation_Wheel_or_Lever, Pan
    ! Contains the list of General MIDI 128 instruments and 47 percussions:
    use GM_instruments

    implicit none
    type(MIDI_file) :: midi
    real(dp) :: p, delta
    integer :: i, j, jmax
    integer, parameter :: nb_notes = 6
    integer, parameter :: length = 200
    integer :: b_scale(0:127)     ! Blues scale
    integer :: octave, note, value
    logical :: again
    ! The tonic is the C note:
    integer :: tonic

    tonic = MIDI_Note("C1")

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

    ! (1) A first music track with guitar:
    call midi%track_header()
    ! Reverb:
    call midi%Control_Change(channel=0, type=Effects_1_Depth, ctl_value=64)
    ! Modulation:
    call midi%Control_Change(channel=0, type=Modulation_Wheel_or_Lever, ctl_value=40)
    ! Panning, slightly on the left (center is 64):
    call midi%Control_Change(channel=0, type=Pan, ctl_value=44)
    ! Instrument:
    call midi%Program_Change(channel=0, instrument=Distortion_Guitar)

    ! A blues scale C, Eb, F, Gb, G, Bb, repeated at each octave.
    ! The MIDI note 0 is a C-1, but can not be heard (f=8.18 Hz).
    ! https://en.wikipedia.org/wiki/Hexatonic_scale#Blues_scale
    ! We copy the blues scale at the beginning of the array:
    do j = 0, 5
        b_scale(j) = MIDI_Note(trim(HEXATONIC_BLUES_SCALE(j+1))//"0") - 12
    end do

    ! And we copy it as many times as possible:
    jmax = nb_notes - 1
    octave = 1
    again = .true.
    do
        do j = 0, nb_notes-1
            if (b_scale(j) + octave*12 <= 127) then
                jmax = octave*nb_notes + j
                b_scale(jmax) = b_scale(j) + octave*12
            else
                again = .false.
            end if
        end do
        octave = octave + 1
        if (.not. again) exit
    end do

    ! Let's make a random walk on that scale:
    value = quarter_note
    note = tonic
    do i = 1, length
        call midi%play_chord(channel=0, note=b_scale(note), chord=POWER_CHORD, velocity=p_level-2, value=value)

        ! Random walk:
        call random_number(p)
        ! We need a kind of restoring force to avoid going too far:
        delta = ((b_scale(note) - b_scale(tonic)) / 12.0_dp) * 0.45_dp
        if (p >= 0.55_dp + delta) then
            if (note < jmax) note = note + 1
        else if (p >= 0.1_dp) then
            if (note > 0) note = note - 1
        end if

        ! Duration:
        call random_number(p)
        if (p >= 0.75_dp) then
            value = quarter_note
        else
            value = sixteenth_note
        end if
    end do

    call midi%end_of_track()

    ! (2) Drums track (channel 9 by default):
    call midi%track_header()
    ! Reverb:
    call midi%Control_Change(channel=drums, type=Effects_1_Depth, ctl_value=64)
    ! Panning, slightly on the right (center is 64):
    call midi%Control_Change(channel=drums, type=Pan, ctl_value=84)

    do i = 1, length*2
        call midi%delta_time(0)
        ! On the drum channel, each note corresponds to a percussion:
        call midi%Note_ON(channel=drums, note=Closed_Hi_Hat, velocity=80)

        ! We use modulo to create a rhythm:
        if (mod(i, 6) == 4) then
            call midi%delta_time(0)
            call midi%Note_ON(channel=drums, note=Acoustic_Snare, velocity=92)
        else if ((mod(i, 6) == 1) .or. (mod(i, 12) == 6)) then
            call midi%delta_time(0)
            call midi%Note_ON(channel=drums, note=Acoustic_Bass_Drum, velocity=127)
        end if

        call midi%delta_time(quarter_note / 3)
        call midi%Note_OFF(channel=drums, note=Closed_Hi_Hat, velocity=64)

        if (mod(i, 6) == 4) then
            call midi%delta_time(0)
            call midi%Note_OFF(channel=drums, note=Acoustic_Snare, velocity=92)
        else if ((mod(i, 6) == 1) .or. (mod(i, 12) == 6)) then
            call midi%delta_time(0)
            call midi%Note_OFF(channel=drums, note=Acoustic_Bass_Drum, velocity=127)
        end if
    end do

    call midi%end_of_track()

    call midi%close()

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