How can I apply a conversion function to the indices of a datafile to generate the xticlabels
at each interval?
Here I'd like to use my user-defined secs_to_beats_bars
function (which returns a string formatted with sprintf
), see below.
Note, I am seeking to avoid the following:
Lets say I have a datafile, indexed in seconds (decimal):
# Seconds, Pitch, Duration, Velocity
0.16129032258064513, 31, 0.7157258064516129, 71
0.8870967741935483, 31, 0.3578629032258066, 75
1.2499999999999998, 31, 0.3427419354838712, 78
1.6129032258064513, 42, 0.4637096774193551, 75
2.0967741935483866, 37, 0.7056451612903228, 76
2.82258064516129, 33, 0.3427419354838712, 77
3.1854838709677415, 31, 0.3427419354838712, 78
3.548387096774193, 31, 0.46370967741935554, 74
4.032258064516128, 31, 1.0735887096774201, 71
5.120967741935483, 33, 0.34778225806451696, 62
5.483870967741934, 31, 0.32258064516129087, 50
5.806451612903225, 35, 0.48387096774193544, 87
5.96774193548387, 43, 0.3528225806451618, 63
6.330645161290321, 31, 0.7106854838709676, 58
I have a custom function to convert the seconds to a musically relevant time system (like beats and bars):
# tempo is in beats per minute, beats and bars are indexed from one.
# eg: bar 1 beat 1 = "1:1"
secs_to_beats(secs, tempo) = int(secs * tempo / 60);
secs_to_beats_bars(secs, tempo, beatsperbar) = sprintf('%.0f:%.0f', int(secs_to_beats(secs, tempo) / beatsperbar) + 1, secs_to_beats(secs, tempo) % beatsperbar + 1);
Which I use to set the xtics
at a regular intervals at each beat, and mxtics
to further subdivide the grid to semiquavers:
beats_to_secs(beat, tempo) = 1.0/(tempo * 1.0/60.0) * beat;
bpm = 80;
beatinterval = beats_to_secs(1, bpm);
set xtics beatinterval; set mxtics 4; set grid x mx ls 100, ls 101;
and finally plot this using boxxyerror
to create rectangles for each row using the seconds, pitch and duration columns:
set yrange[0:127];
plot 'midi.dat' u (($1+$3)/2):(($2+0.95)/2):1:($3+$1):($2):($2+0.95) w boxxy fs solid 0.50 border lc 'black';
As you can see, the xticlabels
are in seconds, I am seeking to convert these to the beats/bars using the secs_to_beats_bars
function above.
I guess the following example does what you are asking for:
Furthermore:
boxxyerror
(x):(y):(+/-dx):(+/-dy)
, check help boxxyerror
.With your added factors 1.0
in your script, I assume that you are aware about gnuplot's integer division (e.g. 1/2 = 0
).
Script:
### change x-axis scale
reset session
$Data <<EOD
# Seconds, Pitch, Duration, Velocity
0.16129032258064513, 31, 0.7157258064516129, 71
0.8870967741935483, 31, 0.3578629032258066, 75
1.2499999999999998, 31, 0.3427419354838712, 78
1.6129032258064513, 42, 0.4637096774193551, 75
2.0967741935483866, 37, 0.7056451612903228, 76
2.82258064516129, 33, 0.3427419354838712, 77
3.1854838709677415, 31, 0.3427419354838712, 78
3.548387096774193, 31, 0.46370967741935554, 74
4.032258064516128, 31, 1.0735887096774201, 71
5.120967741935483, 33, 0.34778225806451696, 62
5.483870967741934, 31, 0.32258064516129087, 50
5.806451612903225, 35, 0.48387096774193544, 87
5.96774193548387, 43, 0.3528225806451618, 63
6.330645161290321, 31, 0.7106854838709676, 58
EOD
BPM = 80 # beats per minute
BPB = 4 # beats per bar
OFF = 0.000 # offset in seconds
SecToBar(s) = s*BPM/60./BPB
BoxCenter(colS,colD) = SecToBar(column(colS) + column(colD)*0.5 + OFF) + 1
BoxWidth(colD) = SecToBar(column(colD))*0.5
set datafile separator comma
set style line 1 lw 1.5 lc "red"
set style line 2 lw 1.0 lc "grey"
set style fill solid 0.50 transparent border lc 'black'
set key noautotitle
set xlabel "bars"
set xtics 1
set mxtics BPB
set grid x,mx ls 1, ls 2
set ylabel "pitch"
set yrange[25:50]
plot $Data u (BoxCenter(1,3)):2:(BoxWidth(3)):(0.45) w boxxy lc 'blue'
### end of script
Result: