MIDI_file Derived Type

type, public :: MIDI_file

The main class you need to create a MIDI file.


Components

Type Visibility Attributes Name Initial
character(len=:), private, allocatable :: filename
integer(kind=int32), private :: size_pos
integer, private :: status
integer, private :: unit

Type-Bound Procedures

procedure, public :: Control_Change

  • public subroutine Control_Change(self, channel, type, ctl_value)

    Many MIDI parameters can be set by Control Change. See the list.

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    integer, intent(in) :: channel
    integer, intent(in) :: type
    integer, intent(in) :: ctl_value

procedure, public :: Note_OFF

  • public subroutine Note_OFF(self, channel, note, velocity)

    Writes a Note OFF event. MIDI notes are in the range 0..127 The release velocity is in the range 0..127.

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    integer, intent(in) :: channel
    integer, intent(in) :: note
    integer, intent(in), optional :: velocity

procedure, public :: Note_ON

  • public subroutine Note_ON(self, channel, note, velocity)

    Writes a Note ON event. MIDI notes are in the range 0..127 The attack velocity is in the range 1..127 and will set the volume. A Note ON event with a zero velocity is equivalent to a Note OFF.

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    integer, intent(in) :: channel
    integer, intent(in) :: note
    integer, intent(in) :: velocity

procedure, public :: Pitch_Bend

  • public subroutine Pitch_Bend(self, channel, lsb, msb)

    Apply a pitch bend to all notes currently sounding on the channel. No bend is 00 40 (64 in decimal), maximum downward bend is 00 00, maximum upward bend is 7F 7F. The Least Significant Byte (lsb) is optional (default value is 0), as it is useful only for fine adjustment. You can not use it with play_note, play_chord or play_broken_chord: you must manage yourself the Note ON and Note OFF events, and put the bend between.

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    integer, intent(in) :: channel
    integer, intent(in), optional :: lsb
    integer, intent(in) :: msb

procedure, public :: Program_Change

  • public subroutine Program_Change(self, channel, instrument)

    Each channel (0..15) can use one General MIDI instrument (0..127) at a time.

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    integer, intent(in) :: channel
    integer, intent(in) :: instrument

procedure, public :: close

  • public subroutine close(self)

    Closes the MIDI file.

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self

procedure, public :: cue_point

  • public subroutine cue_point(self, text)

    Cue Point event: FF 07 len text

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    character(len=*), intent(in) :: text

procedure, public :: delta_time

  • public subroutine delta_time(self, ticks)

    Each MIDI event must be preceded by a delay called "delta time", expressed in MIDI ticks.

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    integer, intent(in) :: ticks

procedure, public :: end_of_track

  • public subroutine end_of_track(self)

    A track must end with 0xFF2F00.

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self

procedure, public :: get_name

  • public function get_name(self)

    Returns the name of the MIDI file:

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(in) :: self

    Return Value character(len=len(self%filename))

procedure, public :: instrument_name

  • public subroutine instrument_name(self, text)

    Instrument Name event: FF 04 len text

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    character(len=*), intent(in) :: text

procedure, public :: lyric

  • public subroutine lyric(self, text)

    Lyric event: FF 05 len text

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    character(len=*), intent(in) :: text

procedure, public :: marker

  • public subroutine marker(self, text)

    Marker event: FF 06 len text

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    character(len=*), intent(in) :: text

procedure, public :: new

  • public subroutine new(self, file_name, format, tracks, divisions, tempo, time_signature, copyright, text_event)

    Create a new MIDI file and its metadata track. Concerning the "divisions" argument, ForMIDI uses the "metrical timing" scheme, defining the number of ticks in a quarter note. The "timecode" scheme is not implemented. SMF format: 0: only one track in the file 1: several tracks played together (generally used) 2: several tracks played sequentially

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    character(len=*), intent(in) :: file_name
    integer, intent(in) :: format
    integer, intent(in) :: tracks
    integer, intent(in) :: divisions
    integer, intent(in) :: tempo
    integer, intent(in), optional :: time_signature(:)
    character(len=*), intent(in), optional :: copyright
    character(len=*), intent(in), optional :: text_event

procedure, public :: play_broken_chord

  • public subroutine play_broken_chord(self, channel, note, chord, velocity, value, values)

    Writes a broken chord using an array containing the intervals (see the music_common module). https://en.wikipedia.org/wiki/Arpeggio You must pass either a scalar value (whole duration) or a values array (containing the values for each note).

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    integer, intent(in) :: channel
    integer, intent(in) :: note
    integer, intent(in), dimension(:) :: chord
    integer, intent(in) :: velocity
    integer, intent(in), optional :: value
    integer, intent(in), optional, dimension(:) :: values

procedure, public :: play_chord

  • public subroutine play_chord(self, channel, note, chord, velocity, value)

    Writes a chord, waits for its duration, and writes the OFF events

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    integer, intent(in) :: channel
    integer, intent(in) :: note
    integer, intent(in), dimension(:) :: chord
    integer, intent(in) :: velocity
    integer, intent(in) :: value

procedure, public :: play_note

  • public subroutine play_note(self, channel, note, velocity, value)

    Write a Note ON event, waits for its duration, and writes a Note OFF.

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    integer, intent(in) :: channel
    integer, intent(in) :: note
    integer, intent(in) :: velocity
    integer, intent(in) :: value

procedure, public :: sequence_track_name

  • public subroutine sequence_track_name(self, text)

    Sequence or Track Name event: FF 03 len text

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    character(len=*), intent(in) :: text

procedure, public :: set_tempo

  • public subroutine set_tempo(self, duration)

    Specifies a tempo change by writing the duration of a quarter note expressed in µs. It is coded on 3 bytes: from 1 µs to 256**3 µs ~ 16.7 s. A duration of 500000 µs = 0.5 s is equivalent to a 120 bpm tempo. https://en.wikipedia.org/wiki/Tempo MIDI events must always be preceded by a "delta time", even if null:

    Read more…

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    integer, intent(in) :: duration

procedure, public :: set_time_signature

  • public subroutine set_time_signature(self, numerator, denominator, metronome, tsnotes)

    The time signature includes the numerator, the denominator, the number of MIDI clocks between metronome ticks, (there are 24 MIDI clocks per quarter note) and the number of 32nd notes in a quarter note. The number of "MIDI clocks" between metronome clicks.

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    integer, intent(in) :: numerator
    integer, intent(in) :: denominator
    integer, intent(in) :: metronome
    integer, intent(in), optional :: tsnotes

procedure, public :: text_event

  • public subroutine text_event(self, text)

    Text event: FF 01 len text

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    character(len=*), intent(in) :: text

procedure, public :: track_header

  • public subroutine track_header(self, track_name, text_event)

    Writes a track header and stores the position where the size of the track will be written when the track will be closed.

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    character(len=*), intent(in), optional :: track_name
    character(len=*), intent(in), optional :: text_event

procedure, private :: copyright_notice

  • public subroutine copyright_notice(self, text)

    Copyright Notice event: FF 02 len text

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    character(len=*), intent(in) :: text

procedure, private :: init_formidi

  • public subroutine init_formidi(self)

    Verifies the needed data types.

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(in) :: self

procedure, private :: write_string

  • public subroutine write_string(self, event, text)

    This subroutine is used my many events. The text must be coded in ASCII (7 bits).

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    integer, intent(in) :: event
    character(len=*), intent(in) :: text

procedure, private :: write_track_size

  • public subroutine write_track_size(self)

    Must be called when the track is finished. It writes its size at the memorized position in the track header.

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self

procedure, private :: write_variable_length_quantity

  • public subroutine write_variable_length_quantity(self, i)

    Writes the integer i in the MIDI file using the variable length quantity representation:

    Arguments

    Type IntentOptional Attributes Name
    class(MIDI_file), intent(inout) :: self
    integer(kind=int32), intent(in) :: i

Source Code

    type MIDI_file
        character(len=:), private, allocatable :: filename
        ! Output unit and file status:
        integer, private :: unit
        integer, private :: status
        ! To store where to write the size of a track in the file:
        integer(int32), private :: size_pos
    contains
        procedure, private :: init_formidi
        procedure, private :: write_variable_length_quantity
        procedure :: new
        procedure :: track_header
        procedure :: set_tempo
        procedure :: set_time_signature
        procedure :: end_of_track
        procedure :: get_name
        procedure, private :: write_track_size
        procedure :: Program_Change
        procedure :: play_note
        procedure :: play_chord
        procedure :: play_broken_chord
        procedure :: close
        procedure :: Control_Change
        procedure :: Pitch_Bend
        procedure :: Note_ON
        procedure :: Note_OFF
        procedure :: delta_time
        procedure, private :: write_string
        procedure :: text_event
        procedure, private :: copyright_notice
        procedure :: sequence_track_name
        procedure :: instrument_name
        procedure :: lyric
        procedure :: marker
        procedure :: cue_point
    end type MIDI_file