Is there (somewhere) a command-line program for Windows which will create PNG/JPEG visual from MP3/WAV?
EDIT:
This is a good example of how the image should look like.
Sox, "the Swiss Army knife of audio manipulation", can generate accurate PNG spectrograms from sound files. It plays pretty much anything, and binaries are available for Windows. At the most basic level, you'd use something like this:
sox my.wav -n spectrogram
If you want a spectrogram with no axes, titles, legends, and a light background that's 100px high:
sox "Me, London.mp3" -n spectrogram -Y 130 -l -r -o "Me, London.png"
Sox accepts a lot of options if you only want to analyze a single channel for example. If you need your visuals to be even cooler, you could post-process the resulting PNG.
Here is a short overview from the commandline about all available parameters, the manpage has more details:
-x num X-axis size in pixels; default derived or 800
-X num X-axis pixels/second; default derived or 100
-y num Y-axis size in pixels (per channel); slow if not 1 + 2^n
-Y num Y-height total (i.e. not per channel); default 550
-z num Z-axis range in dB; default 120
-Z num Z-axis maximum in dBFS; default 0
-q num Z-axis quantisation (0 - 249); default 249
-w name Window: Hann (default), Hamming, Bartlett, Rectangular, Kaiser
-W num Window adjust parameter (-10 - 10); applies only to Kaiser
-s Slack overlap of windows
-a Suppress axis lines
-r Raw spectrogram; no axes or legends
-l Light background
-m Monochrome
-h High colour
-p num Permute colours (1 - 6); default 1
-A Alternative, inferior, fixed colour-set (for compatibility only)
-t text Title text
-c text Comment text
-o text Output file name; default `spectrogram.png'
-d time Audio duration to fit to X-axis; e.g. 1:00, 48
-S time Start the spectrogram at the given time through the input
A real waveform is possible with ffmpeg, you can download it here.
Install it somewhere and use the following command line as example:
ffmpeg.exe -i "filename.mp3" -lavfi showwavespic=split_channels=1:s=1024x800 waveform.png
or the following to match your example picture color, or other colors:
ffmpeg.exe -i "filename.mp3" -lavfi showwavespic=s=1024x800:colors=0971CE waveform.png
Documentation of FFmpeg showwavespic
I've created a small PHP library that does this: https://github.com/jasny/audio
It works as following. It gets the samples using
sox TRACK.mp3 -t raw 4000 -c 1 -e floating-point -L -
This downsamples the track to 4k and puts everything in 1 channel.
Next I take chunks of samples (per pixel witd) and calculate the min and max. Use them to draw the waveform.
I found this here quite nice (from a web archive, the original one is gone):
http://web.archive.org/web/20140715171716/http://andrewfreiday.com/2011/12/04/optimizing-the-php-mp3-waveform-generator/
its PHP based and uses lame through shell.
update : the site seems dead from time to time, howerver here is the repo : https://github.com/afreiday
An updated, batched version of Wander Nauta which generate histogram for all wav files into folder (BASH/DASH):
for i in *.wav; do ./sox $i -n spectrogram -y 130 -l -r -o ${i%%.wav}.png; done
Related
I'm trying to read a video file and store the frames as a series of images. I'm using VideoReader but for some reason I'm having trouble. I want to store the frames of two videos encoded differently and measure the structural similarity and PSNR between the two on a frame-by-frame basis.
Essentially I've three video files, an original (which reads fine), one compressed with VP9 using ffmpeg, and one compressed with H.624 using ffmpeg. The original video was originally just a set of frames merged into a .avi video using VirtualDub. The compressed videos are also .avi container.
The VP9 video appeared to work fine but when I open the images using imshow() they appear to be just a solid green color. The video opens fine on VLC so I'm not sure what the problem is.
The H.264 video doesn't read at all. When it attempts to enter the "while hasFrame()" loop, it skips over it which leads to believe Matlab thinks the video frames aren't there? Again, this video opens fine in VLC and the three videos look almost identical.
Anyone got any ideas why this is happening? Is it to do with the way Matlab decodes the video or some parameters set by ffmpeg?
Original vs VP9 in Matlab
Console output for ffmpeg - VP9
Console output for ffmpeg - H264
Main file:
test_vid = 'vp9.avi';
images = readVideos(test_vid);
for i=1:length(images)
% Convert from cells to matrices
image1 = cell2mat(images(1,i));
image2 = cell2mat(images(2,i));
% Do stuff with the images here
subplot(1,2,1);
imshow(image1);
subplot(1,2,2);
imshow(image2);
end
ReadVideos():
function images = readVideos(test_video)
% Video directories
test_video_dir = strcat('src/', test_video);
v_original = VideoReader('src/input.avi');
v_test = VideoReader(test_video_dir);
% Read original video
i = 1;
v_original.CurrentTime = 5;
while hasFrame(v_original)
frame = readFrame(v_original);
originalImages{i} = frame;
i = i + 1;
end
% Read test video
i = 1;
v_test.CurrentTime = 5;
while hasFrame(v_test)
frame = readFrame(v_test);
testImages{i} = frame;
i = i + 1;
end
images = cat(1, originalImages, testImages);
end
On a side note, is Matlab the best choice for the task or is there specialised software out there for doing this?
Matlab's Videoreader relies, for the most part, on the decoders provided by the OS. In general, these decoders have limited support for streams with pixel formats other than the most common ones. That appears to be the case here.
Your VP9 output is gbrp i.e. planar (8-bit) RGB. Your H.264 output is YUV but with 4:4:4 chroma sampling. Both of these are non-standard.
To read these files with Videoreader, convert to a standard pixel format:
ffmpeg -i input.avi -pix_fmt yuv420p -c:v libvpx-vp9 vp9.avi
and
ffmpeg -i input.avi -pix_fmt yuv420p -c:v libx264 h264.avi
However, you may encounter issues when carrying out quality metric comparisons since they require both operands to have the same pixel format. Matlab may or may not convert them automatically.
You could just perform the quality check in ffmpeg.
ffmpeg -i input.avi -pix_fmt gbrp -c:v libvpx-vp9 vp9.mkv
and
ffmpeg -i input.avi -pix_fmt gbr24 -c:v libx264rgb h264.mkv
And then
ffmpeg -i input.avi -i vp9.mkv -i h264.mkv -filter_complex "[1][0]psnr=f=vp9-psnr.txt:stats_version=2;[1][0]ssim=f=vp9-ssim.txt;[2][0]psnr=f=h264-psnr.txt:stats_version=2;[2][0]ssim=f=h264-ssim.txt" -f null -
See http://www.ffmpeg.org/ffmpeg-filters.html#psnr and http://www.ffmpeg.org/ffmpeg-filters.html#ssim
I used to have a way to do this, but it's been lost to time... I have one program that outputs an undeliniated ascii data file, and another program that needs the data formatted it's own way. The output contains X,Y data points in the format:
X120207Y041009
X120107Y040071
etc. ...
where each of these ordinates represents a 2.4 data point. The input file needs it as such:
X 12.0207 Y 04.1009
X 12.0107 Y 04.0071
etc. ...
Not all of the lines in the file are data points, but the ones that are start with "X", have the exact same format, and contain nothing else on that line.
All my searching for a similar conversion points toward using sed as a quick, elegant way to do this, but I never learned sed. I think before I actually wrote a c program to do this conversion but that seems like the really hard way to recreate. If anyone could bail me out, I'll owe you a bagel!
You can make use of gawk's FIELDWIDTHS to handle fixed format text:
awk -v FIELDWIDTHS="1 6 1 6" '/^X/{for(x=2;x<=5;x+=2)sub(/../,"&.",$x)}7' file
Let's see an example:
kent$ cat f
X120207Y041009
X120107Y040071
we want to leave it, no matter what it is
kent$ awk -v FIELDWIDTHS="1 6 1 6" '/^X/{for(x=2;x<=5;x+=2)sub(/../,"&.",$x)}7' f
X 12.0207 Y 04.1009
X 12.0107 Y 04.0071
we want to leave it, no matter what it is
I have a large series of netcdf files representing daily snapshots of data. I am hoping to hook these up to a software which is asking me to add to the namelist the maximum and minimum values for a variable in the files. How can I enquire about the maximum and minimum values stored in a variable?
My variable is depth (here is an excerpt from an ncdump for an idea of the size of that variable)
...
dimensions:
z = 40 ;
lat = 224 ;
lon = 198 ;
time = 1 ;
variables:
float depth(z, lat, lon) ;
depth:long_name = "cell centre depth" ;
depth:units = "m" ;
...
I'm still a beginner at handling these files, and have been using NCO operators and/or matlab for netcdf handling to date - is there an easy way to perform this max min enquiry using either of these tools?
Before now I have had netcdfs where the value range was helpfully displayed in the attributes or it has been a sufficiently small amount of data to be displayed easily with a simple ncdump -v look at the values or storing the variable in matlab which auto displays the max min, but now I have too many values to use these quick and dirty methods.
Any help is greatfully received.
All the best,
Bex
One NCO method would be to use the ncrng command, which is simply a "filter" for a longer ncap2 command:
zender#roulee:~/nco/data$ ncrng three_dmn_rec_var in.nc
1.000000 to 80.000000
So, it's a three word command. Documentation on filters is here.
If you have a newer version of MATLAB, try using the ncread function.
% Update with your filename and variable name below.
% This reads in the full variable into MATLAB
variableData = ncread(filename,varname);
% Query max and min values
minValue = min(variableData(:))
maxValue = max(variableData(:))
% you could also write this information back to the file for future reference.
% see https://www.unidata.ucar.edu/software/netcdf/docs/netcdf/Attribute-Conventions.html
ncwriteatt(filename, varname, 'valid_range', [minValue, maxValue]);
% check result
ncdisp(filename, varname);
You could add two additional loops outside, one for looping through all your files and another for looping through all the variables in a file (look at ncinfo) to automate the whole thing.
The CDO method would be
cdo vertmax -fldmax in.nc max.nc
cdo vertmin -fldmin in.nc min.nc
The advantage is that you can calculate min/max just over x-y space (fldmax/fldmin), vertically (vertmax/min) or over time (timmax/min), or a combination of the three.
To dump the values from the netcdf to ascii you can use ncks
ncks -s '%13.9f\n' -C -H -v depth max.nc
To construct a namelist therefore you could for example write
echo min=`ncks -s '%13.9f\n' -C -H -v depth min.nc` >> namelist.txt
echo max=`ncks -s '%13.9f\n' -C -H -v depth max.nc` >> namelist.txt
There are several example data sets in Matlab, for example wind and mri. If you execute the command load wind you will load the data in the data set wind. Some are included in toolboxes and some appear to be included in standard Matlab. These example data sets are valuable as test data when developing algorithms.
Where can one find a list of all such data sets included in Matlab?
You can enter demo in matlab to get a list. The wind table is part of Example — Stream Line Plots of Vector Data, etc.
For the tables on your computer, have a look at:
C:\Program Files\MATLAB\R2007b\toolbox\matlab\demos
The example data is located in .mat files in ../toolbox/matlab/demos.
The following data is available in MATLAB 2014a:
% in matlab run:
> H=what('demos')
> display(H.mat)
You can also use your favorite Linux console:
/usr/local/MATLAB/R2014a/toolbox/matlab/demos$ ls *.mat -1 | sed -e "s/.mat//g"
This is my list for readers who can not try it on their machine while reading this answer:
accidents
airfoil
cape
census
clown
detail
dmbanner
durer
earth
flujet
gatlin
gatlin2
integersignal
logo
mandrill
membrane
mri
patients
penny
quake
seamount
spine
stocks
tetmesh
topo
topography
trimesh2d
trimesh3d
truss
usapolygon
usborder
vibesdat
west0479
wind
xpmndrll
While the command demo in MATLAB 2018b will start a help browser with some demos:
You can find a list of all available dataset and their description in the following link :
https://www.mathworks.com/help/stats/sample-data-sets.html
I have to make a total amount of simulations (e.g. NUM)
with Matlab witch I run with the following line
./run.sh -d num
repeatedly, where num ( NUM = integer*num) indicates the number of new Matlabs.
The same could happen with any other computing program in C or NS, etc.
The problem is that the computer where these processes run only admits a maximum number of Matlabs, e.g. MAX.
I would like to keep track of the number of Matlabs running and when the maximum number is reduced to (MAX-num), because 'num' has already finished, then run the next 'num' simulations of Matlab until the total NUM of simulations is completed.
To know the number of running processes I run the following script
ps axu |grep plopez|grep simulacion|grep MATLAB|awk '{ $2} END{print NR}'
which gives the total Matlabs running in this moment.
How could I make the whole set of simulations just from a single script?
The quick and dirty way would be to divide your set of simulations into NUM subsets, then you can work sequentially on these subsets.
I used the following script to process some images. The folder structure was like this:
CASE
20p
40p
60p
80p
100p
So I entered the CASE folder in the Terminal and ran my script. This called sequentially matlab and ran the script "processImages" to produce some extract data.
The
list=$(ls | grep p)
is really some quick and dirty line of code. However, it worked in my case and might give you the hint to solve the problem.
Have a very nice day.
#!/bin/bash
list=$(ls | grep p)
echo $list
for d in $list
do
echo $d
cd $d
matlab -nodisplay -nosplash -nodesktop -r "processImages; exit"
cd ..
done