Forums > MaxMSP

has anyone found a way to display a waveform with sfplay yet?

October 2, 2013 | 2:44 pm

i know this has come up before, but i can’t find a satisfying answer at the moment

i’m looking for a way to reliably display my soundfiles while using sfplay~ to play them from disk

as i write here

the groove~/waveform~ combination isn’t working so well for me with long, high-resolution soundfiles; the playback starts stuttering or max 6 actually crashes.

in live performance, i rely heavily on the visual feedback of seeing where i am in a soundfile at the moment, and which transient events are coming up next etc.

i’ve been able to make elapsed/remaining time counters and a progress bar to use with sfplay~, but have had little luck with actually displaying the sounds the past few months

any tips would be highly appreciated, thanks in advance!

October 3, 2013 | 12:19 am

What I do is creating in advance a short buffer (1500ms) for each soundfile. To do that, I read the file (much) faster and record the result in a buffer. It looks quite nice.

Then I use sfplay~‘s position output to control buffer~‘s cursor position.

Here is the patch, which is used in a much bigger patch. It needs 2 arguments (I use 1500 and 1500, in ms, but you may need to tweak that, depending on your hard drive). The message create audiofilepath buffername will fill the buffer with a waveform of the audio file.

Comments are welcome, as I’m not sure it’s really reliable!


– Pasted Max Patch, click to expand. –


October 3, 2013 | 12:34 am

Here is an *old* patch I posted … in 2006 (!) in this thread :

very similar to Patrick’s patch : it creates a buffer~ 50 times smaller than the original sound file.


– Pasted Max Patch, click to expand. –




October 3, 2013 | 11:23 am

hi patrick and mathieu,

thank you very much for the help and the example patches!

patrick, in case you have time to answer a few questions that come up for me when i try your patch:
-where do the two arguments (1500 and 1500) go? i tried putting them in the loadmess objects.
-and the "create audiofilepath buffername" message, where should i send that? i tried sending a message like that into the inlet on the top.
-the [/] and [if] objects are giving me "inlet: wrong message or type" errors

so at the moment, i can’t get it to work, but i must admit there are several objects in the patch that i don’t fully understand. maybe i’ll do better tomorrow morning after some coffee..

October 3, 2013 | 11:31 am


your patch is actually pretty much what i’ve been using the past few years, you’re probably where i got the idea from in the first place! thank you for that.

do you happen to know why, most of the time, only the beginning of the waveform is shown?

i don’t get any error messages, and your patch is very clear, but unfortunately, most of the time, the waveform won’t fully load, and only the first few seconds are shown.
see the attached screenshots.

i’m using 24/96 wav files, mono at the moment, of a few minutes long, on a macbook pro with max 6.

thanks again!

  1. Screen-shot-2013-10-03-at-8.09.28-PM
  2. Screen-shot-2013-10-03-at-8.09.45-PM
October 3, 2013 | 1:04 pm

your sfplay~ stops playing probably because your HD is too slow (playing 24/96 wav at 50x speed requires very fast access)
you can try increasing sfplay~ disk buffer size (2nd arg) (Patrick’s patch uses 26208000 )
or slow down the playback speed.
…or buy a SSD ;-)


October 3, 2013 | 1:45 pm

you were right! i’ve increased the sfplay~ disk buffer size to 40.320.000 (it needs multiples of 20160) and for the moment, the patch is displaying any soundfile i’m throwing at it, including half-hour long 24/96 stereo files..

my next machine will be ssd based, but for now this is great, and if it stops working i’ll know what to tweak.

thanks again for the very helpful and clear example!

October 4, 2013 | 1:04 am

Save the patch I sent before as "waveformAF".
Save the following code as "bufferRuler.js"

// bufferRuler
// Patrick Delges
// Centre Henri Pousseur
// 20130415

mgraphics.relative_coords = 0;
mgraphics.autofill = 0;

var dis_width = mgraphics.size[0]; // size of the jsui
var dis_height = mgraphics.size[1]; //

var bgcolor = [.75, .54, 1.]; // default background color

var theDuration = 0; // size of the buffer (ms)
var intervalWidth = dis_width; // interval (in pixel) between increments
var minuteIncrement = 1; // duration (in minutes) between increments

bufferRulerInstantiate = 0;

function loadbang()
if (!bufferRulerInstantiate)
post ("bufferRuler by – Centre Henri Pousseur 2013\n");
bufferRulerInstantiate = 1;


function bang()

function paint()
dis_width = mgraphics.size[0];
dis_height = mgraphics.size[1];

// see
// the size will be updated both in Patching & Presentation mode
// and in all views.

computeIntervals ();

with (mgraphics)
rectangle (0, 0, dis_width, dis_height);

set_line_width (1);

for (x_pos = 0, minute = 0; x_pos = 60000)
minuteWidth = dis_width / (theDuration / 60000);
intervalWidth = minuteWidth;

//post ("->" + minuteIncrement + ", " + minuteWidth + "\n");
while (intervalWidth < 25)
intervalWidth += minuteWidth;
intervalWidth = dis_width;

function labelbgcolor(R, G, B)
bgcolor = [R, G, B];

Then savevand open this patch:


– Pasted Max Patch, click to expand. –


The Javascript UI draws a ruler you can put over the waveform~ ruler.

The difference with Mathieu is that in his solution, the files are always read 50x faster, so if it does work for one file, it will probably work for others.
In my solution, the speed depends on the length of the file, ther idea is to have buffers of constant length (1500 in the example). If it doesn’t work, then the buffer size should be increased.

If the file is too short, then it’s simply imported.

October 5, 2013 | 1:50 pm

hi patrick,

thank you very much for the additional info!

i will dive deeper into your patch the coming days and report back – very interesting to have several different approaches to look into.

October 5, 2013 | 3:30 pm

i would just use a parallel buffer~ with waveform~ as display …

October 5, 2013 | 5:16 pm

Hey Patrick,
your js code returns several compile errors after copy pasting. It might be that the forum formatting breaks some characters… (like the "" for instance, which are the same i guess originally, but interpreted by js as ‘illegal character’. I have another error after :

jsui: bufferRuler.js: Javascript SyntaxError: missing ; after for-loop condition, line 57

). Could you please maybe upload the thing in a zipped format ?…

October 8, 2013 | 12:02 am

Sorry for that vichug. The .js is attached.

(And sorry for the delay, the RSS feeds on c74′s forums only have the 25 last posts, so I didn’t notice this topic continue during the week-end…)

  1. bufferRuler.js
October 8, 2013 | 2:21 am

no worries, thanks a lot !

October 8, 2013 | 2:51 am

erm… this thread is too weird for me to avoid.

a key advantage to sfplay~ is reading directly from disk and saving RAM. if you then use buffer~ alongside sfplay~ just to display its waveform, it is a very lazy/inefficient answer.

instead, if you’re willing to learn, you could use the ‘spool’ message to the ‘filein’ object(which reads from disk same as with sfplay~ allowing you to match proper context of functionality), and parse through the raw bytes of a soundfile.
i understand it’s not the easiest solution, but the information to help you is all easily available on the internet, for example, this makes it ultra-easy to figure out a max patch on your own that would save you ram for aiff files:

there is similar info. available for .wav formats.
you don’t need to know C or C++ for any of this info. to make sense, either, because all you’re needing to pay attention to is how to find which byte where(this addressing and ID of information within ‘chunks’ of an audio file only takes a very basic understanding of how binary information works… this knowledge should actually be essential for anyone working with audio files… there are many creative things you could do reading a soundfile in non-real-time without using RAM to analyze/read, for example, using a set/initializing sound-file which would inform real-time DSP over other signals later on…).
using java javascript within max to do this would make it even easier, too!
once done, i would then simply apply it to a multislider view(and you can even go by the information within the soundfile to set number of sliders, thus giving you the option to set resolution of display according to size of file).
just my 2 cents.

October 8, 2013 | 3:26 am

I agree Roman’s solution may not be optimal (RAM and time wise)

But using a short buffer~ (1500ms in my case), it’s not an inefficient solution at all. And you get some UI consistency with buffers.

Using filein is of course an option, but I’m quite happy so far with the way I did it. And I don’t have to worry about all audio file formats sfplay~ supports. Call this laziness if you want.

And As I know how to read RIFF files, I really prefer to learn something else :-)


October 8, 2013 | 11:18 am

"I agree Roman’s solution may not be optimal (RAM and time wise)"

oh shit, i didn’t even see that he had also replied(just the one-liner, completely missed it… i probably would’ve avoided the thread as i know how sensitive he is :D). sorry you made the wrongful and quick-to-jump-to-conclusion assumption that i was referring to his. i was actually referring to everyone’s(hence the words "this thread is too weird" referring to the entire thread…. to be honest, Mathieu’s solution is the only one that borders on being smart and elegant, though still a waste of resources…).
simply put, i was just simply surprised to see so many of the usually-smarter-veterans here do exactly the same thing i was doing when i was a beginner. that’s all. it’s not actually an insult, just a good objective perspective to offer amongst your very obviously subjective experiences(not researching the prob outside of max can force one into very myopic solutions sometimes… and i think that is what i saw quite evidently in this thread).

" I really prefer to learn something else :-)"
this is what Max excels at: letting you get as distracted as you’d like(i used to use it for the same reason). that’s all i was saying. not sure what point you were trying to make(but consider that since you focused on the most moot points of my post, perhaps you are reacting out of some kind of prejudice over something else? i don’t know where the ‘contrariness’ comes from is all i’m saying… since i only spoke the truth: that using buffer~ IS inefficient compared to what you COULD do, and that if one chooses not to learn about the technology they are invested in, there must be a certain amount of laziness involved: in such cases the focus is on the ease of the tech… and furthermore, i never actually said being lazy in Max is bad… if anything, this is what Max excels at helping people do more than anything else and it is quite clever for doing so :).

October 8, 2013 | 11:32 am

Hey Karaokaze, i have to say that here i fully agree wiht Patrick Delges. A 1500 ms buffer is worth ?… maybe 1.5 Mo ? (hah Max has made me too lazy to even calculate this. Or is it because i’m lazy that i use Max ? ;) ) and given our 4Go ram machines it’s not much, nearly nothing, and it is a great way to avoid inconveniences that doing it the "clean" way would lead to, as Patrick explained (using waveform~ conveniences and implementing exotic formats). Also, it is more than likely than one would not need a lot of those buffers at once, hence the little embarassment caused by the memory occupation.
In the case you need a lot (i mean hundreds) of those waveforms displayed at once, then, yes, it would be a good idea to begin doing an external.

October 8, 2013 | 11:44 am

"Max has made me too lazy to even calculate this. Or is it because i’m lazy that i use Max ?"

there ya go :) (it starts with the first part of your sentence, which influences you to sway towards the latter part… so i’d say a little bit of both at this point)

"i have to say that here i fully agree wiht Patrick Delges"

hey no prob, you’re all free to disagree, it doesn’t actually detract from the fact that i am speaking truth, and you are insisting on going with your own max-induced subjectivity.

my contribution to this thread was simply to get you to think about the most efficient(not to mention more professionally applicable) alternative. If you have no desire to ever think or be applicable anywhere outside the box of max, you should totally go with the inefficient and easy stuff. my contribution was just hoping you’d see how developers throughout history and in the actual professional realm of audio have done it(it was never my hope that you’d actually care ;D …i just saw it as my duty to give the proper info. rather than just the info. i would’ve been drawn to for a crutch as a beginner).

Where truth is concerned, a majority voice does not decide. Truth is truth: the techniques using buffer~ are in fact, more inefficient(if it is slight enough for you to not notice, that is another point entirely which has nothing to do with what i’m saying)…. so it is perfectly fine that we all agree to disagree on such a ‘subjective’ level.

October 8, 2013 | 3:19 pm


Viewing 19 posts - 1 through 19 (of 19 total)

Forums > MaxMSP