I\'m trying to draw a waveform from a raw audio file. I demuxed/decoded an audio file using FFmpeg and I have those informations: samples buffer, the size of the samples buffer,
First, you need to determine where on the screen each sample will end up.
int x = x0 + sample_number * (xn - x0) / number_of_samples;
Now, for all samples with the same x
, determine the min and the max separately for positive and negative values. Draw a vertical line, a dark one from negative max to positive max, then a light one from negative min to positive min over the top of it.
Edit: thinking about this a little more, you probably want to use an average instead of the min for the inner lines.
The second waveform is probably a column approximation of a simple zig zag graph.
Every column is a line from the previous sample amplitude to the current sample amplitude.
So read all the samples into a canvas or texture as a pre-test as dots, then, once you have done that you can do two cases, make bars instead of dots, draw upwards to last sample or upwards to this sample depending on whichever was higher, as long as you draw a line between to two. That makes sure that the waveform is small with low energies between next samples and high with high energies.
You can alias it and measure multiple samples, it just depends what hardware you are running on, if you want to read 1000ds of samples and make a giant 2d array representation of the wave and then alias it downwards into a smaller displayable image or if you want to just run 512 samples only and update fast. with 2d canvas in programs it should be fast to make detailed waveforms with more than 512 samples.
... a different option is same as the grey waveform in the other answer, draw absolute value as lines from +current sample to -current sample.
it helps to average multiple samples i.e. ever 4 samples or get max of every 4 samples to have a less erratic graph, it's a kid of fast aliasing.
ffmpeg
can draw a waveform with the showwavespic filter.
ffmpeg -i input -filter_complex "showwavespic=split_channels=1" output.png
See showwavespic filter documentation for options.
You can also make a video of the live waveform with the showwaves filter.
ffmpeg -i input -filter_complex \
"showwaves=s=600x240:mode=line:split_channels=1,format=yuv420p[v]" \
-map "[v]" -map 0:a -movflags +faststart output.mp4
See showwaves filter documentation for options.
The bottom graphs simply include a longer time span, so if you increased your numSamples you would get a tighter graph. But with white noise you wont see the peaks and troughs that you will find in normal sounds / music.
So if you can increase your sample size, or at least increase your sample period (x-axis) you will start to emulate the bottom charts. Use two of them to get the stereo effect.
There is a nice program audiowaveform from BBC R&D that does what you want, you might consult their sources.
EXPLANATION FOR EVERYBODY I am a developer of a dj app and was searching for similar answers. So i will explain all about the music waveform you may see in any software including audacity.
There are 3 types of waveforms used to display in any music software. Namely Samples, Average and RMS.
1) Samples are the actual music points presented in a graph, could be an array of raw audio data (points you see when you zoom the waveform in audacity).
2) Average: most commonly used, suppose you are displaying 3 minute song on screen, so a single point on screen must display atleast 100ms(approx) of the song which has many raw audio points, so for displaying we calculate the average of all the points in that 100ms duration, and so on for the rest of the track (dark blue big waveform in audacity).
3) RMS: similar to average but here instead of average, root mean square of the particular duration is taken (the small light blue waveform inside the blue one is rms waveform in audacity).
Now how to calculate waveforms.
1) Samples is raw data when you decode a song using any technique you get raw samples/points. Now based on the format of points you convert them to range -1 to 1, example if format is 16-bit you divide all points by 32768(maximum range for 16 bit number) and then draw the points.
2) for average waveform - first add all points converting negative values to positive, then multiply by 2 and then take average.
//samples is the array and nb_samples is the length of array
float sum = 0;
for(int i = 0 ; i < nb_samples ; i++){
if(samples[i] < 0)
sum += -samples[i];
else
sum += samples[i];
}
float average_point = (sum * 2) / nb_samples; //average after multiplying by 2
//now draw this point
3) RMS: its simple take the root mean sqaure - so first square every sample, then take the sum and then calculate the mean and then sqaure root. I will show in programming
//samples is the array and nb_samples is the length of array
float squaredsum = 0;
for(int i = 0 ; i < nb_samples ; i++){
squaredsum += samples[i] * samples[i]; // square and sum
}
float mean = squaredsum / nb_samples; // calculated mean
float rms_point = Math.sqrt(mean); //now calculate square root in last
//now draw this point
Note here the samples is the array of points for calculating the point/pixel for a particular duration of song. example if you want to draw 1 minute of songs data in 60 pixels so the samples array will be the array of all points in 1 second, i.e the amount of audio points to be displayed in 1 pixel.
Hope this will help someone to clarify the concepts about audio waveform.