yayuj
yayuj

Reputation: 2464

Algorithm to draw waveform from audio

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, the duration of the audio file (in seconds), sample rate (44100, 48000, etc), sample size, sample format (uint8, int16, int32, float, double), and the raw audio data itself.

Digging on the Internet I found this algorithm (more here):

White Noise:

White Noise

The Algorithm

All you need to do is randomize every sample from –amplitude to amplitude. We don’t care about the number of channels in most cases so we just fill every sample with a new random number.

Random rnd = new Random();
short randomValue = 0;

for (int i = 0; i < numSamples; i++)
{
    randomValue = Convert.ToInt16(rnd.Next(-amplitude, amplitude));
    data.shortArray[i] = randomValue;
}

It's really good but I don't want to draw that way, but this way:

audacity

Is there any algorithm or idea of how I can be drawing using the informations that I have?

Upvotes: 23

Views: 23298

Answers (8)

Jorge Banales
Jorge Banales

Reputation: 1

There is an app called DrawNotes in which you can draw a waveform, shareing link for reference

IOS: https://apps.apple.com/mx/app/drawtones/id6683299996

ANDROID: https://play.google.com/store/apps/details?id=com.banales.drawtones

Upvotes: 0

Diljeet
Diljeet

Reputation: 1976

Explanation for Everybody

I am a developer of a dj app and was searching for similar answers. So, I will explain the common techniques to visualize music waveforms you may see in audio software like Audacity.

There are 3 common approaches to visualizing these waveforms: Samples, Average, and RMS (root mean square).

  1. In a Samples approach, the actual music points are presented in a graph. This could be an array of raw audio data like the points you see when you zoom into the waveform in Audacity.

  2. Next, Average is the most commonly used approach. Let's assume you are displaying a 3 minute song on screen. So, a single point on screen must display at least 100ms (approximately) of the song which internally has many more raw audio points. So, for displaying this song, we calculate the average of all points within each 100ms duration or window. Audacity, for example, displays this as the big, dark blue waveform.

  3. Finally, RMS is similar to Average. However, here, we compute the root mean square within each window. Audacity, for example, displays this as the small, light blue waveform inside the larger, dark blue waveform.

Now, let's determine how to calculate these waveforms.

  1. For Samples, first, decode the song to generate raw data and to create raw samples/points. Now, based on the format of points, normalize them into a range between -1 to 1. For example, if the format is 16-bit, divide all the points by 32768 (the maximum range for 16 bit numbers) and then draw the points.

  2. For Average, first, add the absolute value of all points. Then, multiply by 2 and then take the average. Here is an example:

//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
  1. For RMS, first, square every sample. Then, take the sum, calculate the mean, and, finally, compute sqaure root. Here is a programming example:
//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

Please note the samples are the array of points for calculating the point/pixel for a particular duration of a song. For example, if you want to draw 1 minute of a song's data in 60 pixels, the samples array will be the array of all points within 1 second; i.e. the amount of audio points to be displayed in 1 pixel.

I hope this will help clarify the concepts about audio waveforms.

Upvotes: 32

user96265
user96265

Reputation: 558

I think you are referring to a waveform described here.

http://manual.audacityteam.org/man/audacity_waveform.html

I have not read the whole page. But each vertical bar represents a window of waveform samples. The dark blue are the maximum positive and and minimum negative values in that window (I think). And the light blue is the RMS which is root mean squared. http://www.mathwords.com/r/root_mean_square.htm. (basically you square the values within each window, take an average, and then square root.

Hope this helps.

Upvotes: 6

predatflaps
predatflaps

Reputation: 85

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.

Upvotes: 1

llogan
llogan

Reputation: 134303

showwavespic

ffmpeg can draw a waveform with the showwavespic filter.

enter image description here

ffmpeg -i input -filter_complex "showwavespic=split_channels=1" output.png

See showwavespic filter documentation for options.

showwaves

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.

Upvotes: 3

Mark Ransom
Mark Ransom

Reputation: 308530

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.

Upvotes: 9

hcs
hcs

Reputation: 1544

There is a nice program audiowaveform from BBC R&D that does what you want, you might consult their sources.

Upvotes: 2

Grantly
Grantly

Reputation: 2556

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.

Upvotes: 1

Related Questions