Greboca  

Suport technique et veille technologique

Aujourd’hui, les grandes entreprises et administrations publiques hésitent entre continuer à utiliser des logiciels propriétaires ou basculer vers les Logiciels Libres. Pourtant, la plupart des logiciels libres sont capables de bien traiter les données issues des logiciels propriétaire, et parfois avec une meilleur compatibilité.

C’est alors la barrière de la prise en main qui fait peur, et pourtant...

Les logiciels libres

L’aspect « Logiciel Libre » permet une évolution rapide et une plus grande participation des utilisateurs. Les aides et tutoriels foisonnent sur Internet ou sont directement inclus dans le logiciel lui-même.

Enfin, les concepteurs sont plus proches des utilisateurs, ce qui rend les logiciels libres plus agréable à utiliser et conviviaux.

Grâce à la disponibilité des logiciels libres, vous trouverez facilement des services de support techniques et la licence n’est plus un frein à l’utilisation de ces logiciels par votre personnel.

Notre support technique concerne essentiellement les logiciels libres, que ce soit sous forme de services ponctuels ou de tutoriels.

LinuxFr.org : les journaux  -  TapTempo Fortran

 -  Novembre 2021 - 

Sommaire

TapTempo Fortran

Difficile d'échapper à l'engouement planétaire pour TapTempo… Voici donc enfin une version en Fortran moderne (ce qui pour moi désigne le langage à partir de la norme Fortran 90).

Pourquoi Fortran ?

  1. Le calcul éminemment scientifique du tempo me semble mériter de recourir au King du calcul, le mathematical FORmula TRANslating system de John Backus, prix Turing 1977.
  2. Fortran a commencé sa carrière en même temps qu'Elvis Presley, en 1954 (année de début du projet, le premier compilateur ayant été déployé chez les clients d'IBM en 1957).

Le code source

Le projet est disponible sous licence GNU GPLv3 ici :
https://github.com/vmagnin/TapTempo-Fortran

Il utilise pour sa construction le Fortran Package Manager fpm (https://github.com/fortran-lang/fpm) développé depuis deux ans par la communauté Fortran-lang, mais vous pouvez aussi le compiler simplement avec la commande :

$ gfortran -o taptempo src/taptempo.f90 app/main.f90

ou si vous êtes pressé, copier/coller le code source suivant dans un unique fichier taptempo.f90 et le compiler avec gfortran -o taptempo taptempo.f90 (gfortran fait partie de la GCC) :

module taptempo
    ! Reals working precision and 64 bits integers:
    use, intrinsic :: iso_fortran_env, only: wp=>real64, int64

    implicit none

    ! Tap Tempo Version:
    character(len=*), parameter :: version = "1.0.0"

    ! Default values of the command options:
    integer :: s = 5                ! Stack size
    integer :: p = 0                ! Precision
    integer :: r = 5                ! Reset time in seconds
    logical :: out_flag = .false.   ! Flag for the ouput file

    private

    public :: manage_command_line, measure_tempo

contains

    subroutine print_version
        print '(A)', "TapTempo Fortran "//version
        print '(A)', "Copyright (C) 2021 Vincent Magnin and the Fortran-lang community"
        print '(A)', "License GPLv3+: GNU GPL version 3 or later "
        print '(A)', "This is free software: you are free to change and redistribute it."
        print '(A)', "There is NO WARRANTY, to the extent permitted by law."
    end subroutine


    subroutine print_options
        print '(A)'
        print '(A)', "Usage: taptempo [options]"
        print '(A)'
        print '(A)', "Options :"
        print '(A)', "  -h, --help            display this help message"
        print '(A)', "  -o, --output          save the results in the taptempo.txt file"
        print '(A)', "  -p, --precision       change the number of decimals for the tempo,"
        print '(A)', "                        the default is 0 decimal places, the max is 5 decimals"
        print '(A)', "  -r, --reset-time      change the time in seconds to reset the calculation,"
        print '(A)', "                        the default is 5 seconds"
        print '(A)', "  -s, --sample-size     change the number of samples needed to calculate the tempo,"
        print '(A)', "                        the default is 5 samples, the minimum is 2"
        print '(A)', "  -v, --version         print the version number"
        print '(A)'
        print '(A)', "Home page: "
    end subroutine


    subroutine manage_command_line
        integer :: i, nb, status
        character(len=100) :: args

        nb = command_argument_count()
        if (nb == 0) return

        i = 0
        do while (i < nb)
            i = i + 1
            call get_command_argument(i, value=args)

            select case(trim(args))
                case("-h", "--help")
                    call print_version()
                    call print_options()
                    stop
                case("-o", "--output")
                    out_flag = .true.
                case("-p", "--precision")
                    i = i + 1
                    call get_command_argument(i, value=args)
                    read(args, *, iostat=status) p
                    if (status /= 0) print '(A)', "Problem with -p: the default value will be used"
                    p = max(0, min(p, 5))   ! 0 <= p <= 5
                case("-r", "--reset-time")
                    i = i + 1
                    call get_command_argument(i, value=args)
                    read(args, *, iostat=status) r
                    if (status /= 0) print '(A)', "Problem with -r: the default value will be used"
                case("-s", "--sample-size")
                    i = i + 1
                    call get_command_argument(i, value=args)
                    read(args, *, iostat=status) s
                    if (status /= 0) print '(A)', "Problem with -s: the default value will be used"
                    s = max(2, s)
                case("-v", "--version")
                    call print_version()
                    stop
                case default
                    print '(2A)', "Unknown option ignored: ", trim(args)
            end select
        end do
    end subroutine manage_command_line


    subroutine measure_tempo
        character(len=1) :: key
        integer(int64) :: count       ! Count of the processor clock
        real(wp) :: rate              ! Number of clock ticks per second
        integer :: i
        integer :: my_file            ! Unit of the output file
        real(wp), dimension(s) :: t   ! Time FIFO stack
        real(wp) :: t0                ! Time origin
        real(wp) :: bpm               ! Beats Per Minute
        integer :: oldest
        character(len=28) :: fmt

        ! Format used for printing the tempo:
        write(fmt, '(A, I1, A)') '("Tempo: ", f10.', p, ', " BPM ")'
        ! Stack initialization:
        t = 0

        if (out_flag) then
            open(newunit=my_file, file="taptempo.txt", status="replace")
            write(my_file, '(A)') "#    t         bpm"
        end if

        print '(A)', "Hit Enter key for each beat (q to quit)."

        ! Infinite loop:
        i = 0
        do
            ! Reading the standard input:
            read '(a1)', key

            if (key == 'q') exit

            call system_clock(count, rate)
            ! Updating the time FIFO stack:
            t(2:s) = t(1:s-1)
            t(1) = count / rate

            i = i + 1

            if (i == 1) then
                print '(A)', "[Hit enter key one more time to start BPM computation...]"
                t0 = t(1)
            else
                ! Verify that the user is actively tapping:
                if (t(1) - t(2) <= r) then
                    ! Oldest time in the stack:
                    oldest = min(i, s)
                    ! Computes and prints the beats per minute:
                    bpm = 60 / ((t(1) - t(oldest)) / (oldest - 1))
                    write(*, fmt, advance="no") bpm
                    if (out_flag) write(my_file, '(F9.3, F12.5)') t(1)-t0, bpm
                else
                    print '(A)', "Time reset"
                    i = 1
                    t(2:s) = 0
                end if
            end if
        end do

        print '(A)', "I don't know why you say goodbye..."
        if (out_flag) close(my_file)

    end subroutine measure_tempo

end module taptempo

program main
    use taptempo, only: manage_command_line, measure_tempo

    implicit none

    call manage_command_line()
    call measure_tempo()
end program main

Commentaires sur le code source

Le programme principal se contente d'appeler la procédure qui gère la ligne de commandes et la procédure qui mesure le tempo. Ces procédures sont placées dans le module taptempo : les modules ont été introduits par la norme Fortran 90 (la norme Fortran 2008 a même introduit les submodules pour les grands codes).

Fortran utilise pour les types de données son système de KIND (un numéro de type de données) : avant Fortran 2008, on aurait par exemple écrit real(8) pour espérer avoir un réel sur 8 octets, malheureusement ce n'était pas normalisé et le nombre entre parenthèses n'était pas forcément le nombre d'octets dans certains compilateurs… Le module intrinsèque iso_fortran_env définit donc désormais des constantes pour les KINDs de chaque grand type de données, par exemple real64 (renommé wp dans notre programme) et int64.

Depuis Fortran 2003, on peut gérer les arguments de la ligne de commandes avec command_argument_count() et get_command_argument(). Les chaînes de caractères Fortran étant de taille fixe (c'est plus rapide !), on utilise la commande trim() qui supprime les espaces excédentaires. La commande read(args, *, iostat=status) p utilise la chaîne args au lieu de l'entrée standard pour écrire la valeur du paramètre dans l'entier p. La variable status reçoit un code d'erreur non nul en cas de problème.

La ligne write(fmt, '(A, I1, A)') '("Tempo: ", f10.', p, ', " BPM ")' permet au contraire d'écrire des données dans la chaîne fmt en respectant le format '(A, I1, A)' (une chaîne, un entier sur un caractère, une chaîne). Pour l'écriture des résultats dans l'éventuel fichier de sortie, on a besoin de réserver une unité non utilisée (newunit=my_file). Traditionnellement, les unités d'entrées/sorties standards occupent les unités 5 et 6 et peuvent être représentées par une étoile, mais on peut désormais aussi utiliser les constantes input_unit et output_unit définies dans le module iso_fortran_env.

Depuis Fortran 90, le langage permet de manipuler facilement des tableaux : t = 0 permet d'initialiser à zéro tous les éléments du tableau. Faire avancer la pile FIFO représentée par ce tableau se fait simplement : t(2:s) = t(1:s-1). Enfin, la commande call system_clock(count, rate) disponible depuis Fortran 90 permet de récupérer le nombre de tics de l'horloge système et son nombre de tics par secondes. A noter que Fortran dispose aussi de la fonction cpu_time(), mais pendant que l'instruction read attend, le processus est idle et la valeur de cette fonction est donc figée. cpu_time() est avant tout conçue pour déterminer le temps de calcul, cheval de bataille du langage.

Ces particularités du langage étant présentées, le reste du code devrait être relativement lisible pour un développeur qui n'est pas habitué au Fortran.

Limitations

  • Il n'y a pas d'internationalisation, il parle la langue de John Backus et d'Elvis Presley. A noter que pour afficher les réels avec une virgule au lieu d'un point décimal, il suffirait d'ajouter dans le format dc, (decimal comma) avant le f10. Seul inconvénient, si p vaut zéro, ça affichera la virgule quand même, ce qui ne passe pas en Français.
  • Si on garde la touche Entrée enfoncée, ça plafonne à 1500 BPM… Probablement une limitation du terminal puisque la version C++ plafonne à la même valeur. Dommage, on aurait pu espérer s'approcher du GBPM.
  • Si le système reste allumé très longtemps, le nombre de tics de l'horloge finira par revenir à zéro. Mais avec des entiers 64 bits on pourra aller jusque 2**63-1 = +9223372036854775807. Avec GFortran sur un PC actuel, l'horloge génère un milliard de tics par seconde. On devrait tenir 9223372036 secondes ~ 106751 jours ~ 292 ans. De quoi nous prémunir du bug des missiles Patriot. Vous pouvez donc même utiliser TapTempo sur un serveur !

Perspectives

  • Vous pouvez utiliser TapTempo pour mesurer votre rythme cardiaque : mettez une main autour de votre gorge et tapez en rythme sur Entrée. Ne serrez pas ! Rappelons la clause 16 de la GNU GPL v3 : _16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM…)
  • On pourrait créer une interface graphique, par exemple avec gtk-fortran, pour remplacer la touche Entrée par un clic de souris sur un bouton. Pour rester minimaliste, le tempo pourrait être affiché comme texte du bouton.

Commentaires : voir le flux Atom ouvrir dans le navigateur

par vmagnin

LinuxFr.org : les journaux

LinuxFr.org : Journaux

La version 2.0 de WhosWho est sortie

 -  15 mai - 

Bonjour Nal,Je viens de publier la version 2.0 de WhosWho, mon logiciel pour faire des trombinoscopes, dont j'avais parlé il y a longtemps dans (...)


décrire une une image avec une iA locale

 -  8 mai - 

Aujourd'hui c'est fourien™, petit tuto sans prétention!Pour décrire des images en utilisant une iA localement j'utilise LLaVA qui fait partie de (...)


antistress adventure in Flatpak land

 -  30 avril - 

Hello nal, ça faisait un bail !Certain (il se reconnaîtra) m'a demandé de le tenir au courant lorsque j'aurai basculé sur un usage de Firefox (...)


Téléphone sous Linux ?

 -  25 avril - 

Aujourd'hui, avoir un téléphone avec un Android libéré, c'est possible, on pense en particulier à Murena.Avoir un téléphone sous GNU/Linux, c'est (...)


Quand votre voiture vous espionne… et vous le fait payer

 -  23 avril - 

Ceci se passe aux États-Unis, pour l’instant, aucune preuve qu’une telle fuite existe en Europe. Mais… si votre assurance augmente brutalement, (...)