FFMPEG, how to create custom waveform - audio

I have done research trying to create a waveform with FFMPEG and am currently able to create a white png with the wave being transparent. The goal is to generate the wave like the smooth wave below and have the grey be transparent.
Here is my current FFMPEG waveform generator and output.
ffmpeg -i ./_test.mp3 -filter_complex \
"[0:a]aformat=channel_layouts=mono,compand=gain=-6, \
showwavespic=s=450x46:colors=white,negate[a]; \
color=white:450x46[c]; \
[c][a]alphamerge" -vframes 1 _test.png

You won't be able to do this in FFmpeg, one because the waveform isn't drawn with a line, but filled polygons, and two because FFmpeg seems to have trouble dealing with millisecond duration audio.
It would probably be possible to do this using more advanced math/plotting software like R, Octave or matplotlib, but my first thought was to use three smaller more specialized command line utilities:
SoX to trim, resample and save an audio file to a parseable .dat format
(grep/sed to clean up the .dat file)
Gnuplot to draw a plot based on that .dat file and save as .png
Imagemagick to modify the .png so that the plotted line is transparent
In the end my example script ended up like this
# create example file
sox -n -r 32k -b 16 pnoise.wav synth 10 pinknoise norm -0.1
# trim/convert
sox --norm=-1 pnoise.wav test.dat remix 1 trim 5 0.002 rate 200k
grep -v "^;" test.dat |\
sed -e "s/^[[:space:]]*//" -e "s/[[:space:]]*$//" > test.txt
# draw plot
gnuplot
set term png size 600,200 background "#BBBBBB"
set output "test.png"
unset key
unset border
unset xtics
unset ytics
set margins 0, 0, 0, 0
set yrange [-1:1]
plot "test.txt" with lines lt rgb "#FF0000" lw 3
exit
# replace red opaque with fully transparent
mogrify -channel rgba -matte -fill "#FF000000" -opaque "#FF0000" test.png

Related

Use gnuplot command without prompt

To use the Gnuplot (On linux Ubuntu 16.04) command directly by specifying arguments without using the its prompt, I enter this for example :
gnuplot -e "filename='DataFile.txt'" SettingsFile
Where SettingsFile looks like this :
plot filename with lines
set title "Total Packets consumption"
set xlabel "Time"
set ylabel "Packets"
set datafile separator ","
pause -1
And the DataFile.txt looks like this :
Packets, Time(in seconds) :
13392,120
24607,240
23867,360
21764,480
20727,600
20004,720
19719,840
19758,960
19728,1080
20168,1200
19737,1320
19729,1440
20135,1560
20006,1680
21301,1800
19923,1920
20002,2040
19761,2160
20918,2280
22756,2400
22820,2520
23370,2640
22987,2760
22956,2880
24427,3000
23527,3120
24009,3240
23832,3360
23464,3480
23652,3600
11212,3654
First question :
Is there a way to set into that SettingsFile a png OutputFile ? So I can enter it as an argument to the Gnuplot command just as I did with the DataFile. (I want to use it this way, because I want to invoke it from an external code)
I want to achieve something like this :
gnuplot -e "filename='DataFile.txt'" SettingsFile OutputFile.png
Second question :
The screen output that I get from Gnuplot shows the xtics differently than expected :
Notice also that the axis titles are not shown !
Now if I try to resize the window I get this :
The graph gets bizarrely flipped, with the titles set and the tics being updated as desired.
How should I fix these two problems, first mentioning an output file in the SettingsFile, and second the xtics not being showed properly and third this strange behavior in the screen output ?
Several commands can be added to gnuplot -e through semicolons, for example:
gnuplot -p -e 'filename="data.txt"; fileout="image.png"' SettingsFile
Your SettingsFile should already have a line configuring the terminal type:
set terminal png
set output fileout
set title "Total Packets consumption"
set xlabel "Time"
set ylabel "Packets"
set datafile separator ","
plot filename using 2:1 with lines
If you want more control over your code, try with this script (gnuplot 5.0+):
filename=(ARGC>0 ? ARG1 : 'DataFile.txt' ) # By default filename=DataFile.txt
# If called with one argument (ARGC=1)
# then `filename=ARG1`
if(ARGC>1){
# if called with two arguments (ARGC=2), then configure a png output
set terminal png
set output ARG2
}
set title "Total Packets consumption"
set xlabel "Time"
set ylabel "Packets"
set datafile separator ","
# the plot command ALWAYS at the end of the script after the settings
plot filename using 2:1 with lines
If you want to plot 'DataFile.txt' (by default) interactively:
gnuplot -p SettingsFile
If you want to plot another file, e.g. AnotherData.txt:
gnuplot -p -c SettingsFile AnotherData.txt
If you want to plot another file and save it as PNG:
gnuplot -p -c SettingsFile AnotherData.txt Output.png
The -p argument lets plot windows survive after main gnuplot program exits. Thw -c argument load script using gnuplot's "call" mechanism and pass it the remainder of the command line as arguments. See How to pass command line argument to gnuplot?
Notice that your script plots the datafile first, and THEN configure the labels, title and datafile separator. That is why you see weird tics.

plot multiple datasets with gnuplot script from stdin

I am trying to plot some data with gnuplot. I want to use a static script.gp file and feed it from stdin with my data. I also have multiple datasets that I need to pass to the script.
script.gp:
set term jpeg
set encoding utf8
plot '<cat' index 0 with lines, plot '' index 1 with lines
data:
1 2
2 2
0 0
7 4
command:
cat data | gnuplot script.gp
This doesn't work, since I'm guessing it tries to reread from stdin. Is there a way I can do this, or do I have to use temporary files to store my data?
The solution I 've found so far has plenty of drawbacks, however it kind of does the job:
Use 'gnuplot -e' and cat the script file into the command:
cat data | gnuplot -e "$(cat script.gp)"
change script.gp using ; at the end of every line, remove all comments and change the plot command using '-' instead of '<cat' and removing index:
set term jpeg;
set encoding utf8;
plot '-' with lines, '-' with lines
change the data format, seperating each dataset with a line with e:
1 2
2 2
e
0 0
7 4
I would suggest to use the special file '<' which allows you to call the php script and you can have your gnuplot file plot.gp:
set term jpeg;
set encoding utf8;
set output file_out
my_cmd1=sprintf('< my_script %s', my_file1)
my_cmd2=sprintf('< my_script %s', my_file2)
plot my_cmd1 with lines, my_cmd2 with lines
and you call in a shell with:
gnuplot -e 'my_file1="input1.txt"; my_file2="input2.txt"; file_out="my_out.jpg"' plot.gp

Plot all files in a directory simultanously with gnuplot?

I want to do something similar to this question: gnuplot : plotting data from multiple input files in a single graph.
I want to plot simultaneously all the files in a directory, without having to explicitly write their names. The column numbers are the same for all the files. What can I do?
Doing plot for [file in *] file u 3:2 doesn't work.
Also, I don't want each file to have a different legend. All points from all files should be treated the same, as if they all came from a single file.
As an alternative to Jonatan's answer, I would go with
FILES = system("ls -1 *.dat")
plot for [data in FILES] data u 1:2 w p pt 1 lt rgb 'black' notitle
or
plot '<(cat *.dat)' u 3:2 title 'your data'
The first option gives you more flexibility if you want to label each curve. For example, if you have several files with names data_1.dat, data_2.dat, etc., which will be labeled as 1, 2, etc., then:
FILES = system("ls -1 data_*.dat")
LABEL = system("ls -1 data_*.dat | sed -e 's/data_//' -e 's/.dat//'")
plot for [i=1:words(FILES)] word(FILES,i) u 3:2 title word(LABEL,i) noenhanced
You could try something like:
a=system('a=`tempfile`;cat *.dat > $a;echo "$a"')
plot a u 3:2
This uses the command line tempfile command to create a safe, unique, and disposable temporary file. It mashes all of the data files into this file. It then echoes the file's name so gnuplot can retrieve it. Gnuplot then plots things.
Worried about header lines? Try this:
a=system('a=`tempfile`;cat *.dat | grep "^\s*[0-9]" > $a;echo "$a"')
The regular expression ^\s*[0-9] will match all lines which begin with any amount of whitespace followed by a number.
I like to be able too choose the files to plot with wildcards, so if you like that you can do as follows, though there are many ways. Create the following script.
script.sh:
gnuplot -p << eof
set term wxt size 1200,900 title 'plots'
set logs
set xlabel 'energy'
plot for [ file in "$#" ] file w l
eof
do chmod u+x script.sh
Run like ./script.sh dir/* *.dat
If you need it often make an alias for it and put it in some reasonable place:)
Cheers /J
Try the following command:
gnuplot -e 'plot for [file in system("find . -depth 1 -type f -print")] file u 3:2'
Note: Add -p to keep the plot window.

plot is not generated (gnuplot from command line)

In sample.dat I have:
set terminal pngcairo transparent enhanced font "arial,10" fontscale 1.0 size 500, 350
set output 'simple.2.png'
plot [-pi/2:pi] cos(x),-(sin(x) > sin(x+1) ? sin(x) : sin(x+1))
From ubuntu/terminal I execute:
gnuplot -e "filename='sample.dat'"
but the simple.2.png file is not created. How do I export a plot to e.g png using gnuplot from command line?
I have no idea where you got that from!
To execute a gnuplot script (here called simple.gp), simply call
gnuplot simple.gp
You should keep the extension .dat for data files.

Font in Gnuplot Postscript Terminal

I would like gnuplot to use the same font in the postscript-terminal as it does in the wxt-terminal. The Gnuplot help says that wxt uses "Sans" by default. Now, if i set the terminal to
gnuplot> set term post enhanced color "Sans" 12
Terminal type set to 'postscript'
Options are 'landscape enhanced defaultplex \
leveldefault color colortext \
dashed dashlength 1.0 linewidth 1.0 butt noclip \
palfuncparam 2000,0.003 \
"Sans" 12 '
then the font looks very different to the one in wxt.
I am using Ubuntu 10.04 lucid.
Which font would you suggest me to use? Any ideas welcome.
I've also tried "cm-super" to get latex-fonts (computer modern) in gnuplot. Actually it worked, but the text overlapped boxes and margins very often!
Greets,
mefiX
Since the considered plots are part of a LaTeX document, I decided to use the computer modern fonts described earlier.
gnuplot> set term post enhanced color fontfile "/usr/share/texmf/fonts/type1/public/cm-super/sfss1200.pfb" "SFSS1200"
Terminal type set to 'postscript'
Font file '/usr/share/texmf/fonts/type1/public/cm-super/sfss1200.pfb' contains the font 'SFSS1200'. Location:
/usr/share/texmf/fonts/type1/public/cm-super/sfss1200.pfb
Options are 'landscape enhanced defaultplex \
leveldefault color colortext \
dashed dashlength 1.0 linewidth 1.0 butt noclip \
palfuncparam 2000,0.003 \
"SFSS1200" 14 fontfile "/usr/share/texmf/fonts/type1/public/cm-super/sfss1200.pfb" '
As already mentioned, you can install these under ubuntu by calling
# apt-get install cm-super
on the root command line.
Note that the characters in SFSS1200 describe font encoding (Latin1, ...), style (Sans-Serif, ...) and desired resolution in dpi.

Resources