-
Notifications
You must be signed in to change notification settings - Fork 0
/
taptempo.f90
130 lines (105 loc) · 4.45 KB
/
taptempo.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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 = "0.9.0"
! Default values of the command options:
integer :: s = 5 ! Stack size
integer :: p = 0 ! Precision
integer :: r = 5 ! Reset time in seconds
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 <http:https://gnu.org/licenses/gpl.html>"
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)', " -p, --precision change the number of decimal 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"
end subroutine
subroutine manage_command_line
integer :: i, nb
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)
if ((trim(args) == "-h").or.(trim(args) == "--help")) then
call print_version()
call print_options()
stop
else if ((trim(args) == "-p").or.(trim(args) == "--precision")) then
i = i + 1
call get_command_argument(i, value=args)
read(args, *) p
p = min(p, 5)
else if ((trim(args) == "-r").or.(trim(args) == "--reset-time")) then
i = i + 1
call get_command_argument(i, value=args)
read(args, *) r
else if ((trim(args) == "-s").or.(trim(args) == "--sample-size")) then
i = i + 1
call get_command_argument(i, value=args)
read(args, *) s
s = max(2, s)
else if ((trim(args) == "-v").or.(trim(args) == "--version")) then
call print_version()
stop
end if
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
real(wp), dimension(s) :: t ! Time FIFO stack
character(len=25) :: fmt
! Format used for printing the tempo:
write(fmt, '(A, I1, A)') '("Tempo: ", f8.', p, ', " BPM")'
! Stack initialization:
t = 0
print '(A)', "Hit Enter key for each beat (q to quit)."
! Infinite loop:
i = 0
do
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...]"
else
! Verify that the user is actively tapping:
if (t(1) - t(2) <= r) then
print fmt, 60 / ((t(1) - t(min(i, s))) / (min(i, s)-1))
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..."
end subroutine measure_tempo
end module taptempo