-
Notifications
You must be signed in to change notification settings - Fork 0
/
taptempo.f90
160 lines (133 loc) · 5.92 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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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 <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)', " -o, --output save the results in the taptempo.txt file"
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"
print '(A)'
print '(A)', "Home page: <https://github.com/vmagnin/TapTempo-Fortran>"
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 reference
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