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

    Oct 02 2013 | 9: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 https://cycling74.com/forums/playback-stutters-while-loading-soundfiles-into-buffer 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!

    • Oct 03 2013 | 7: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!
    • Oct 03 2013 | 7:34 am
      Here is an *old* patch I posted ... in 2006 (!) in this thread : https://cycling74.com/forums/displaying-a-waveform-in-a-lcd-bennies/
      very similar to Patrick's patch : it creates a buffer~ 50 times smaller than the original sound file.
    • Oct 03 2013 | 6:23 pm
      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..
    • Oct 03 2013 | 6:31 pm
      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!
    • Oct 03 2013 | 8: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 ;-)
    • Oct 03 2013 | 8: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!
    • Oct 04 2013 | 8: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.init(); 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 pdelges@crfmw.be - Centre Henri Pousseur 2013\n"); bufferRulerInstantiate = 1;
      } */
      function bang() { mgraphics.redraw(); }
      function paint() { dis_width = mgraphics.size[0]; dis_height = mgraphics.size[1];
      // see https://cycling74.com/forums/onresize-when-a-jsui-in-resized-in-presentation-mode // the size will be updated both in Patching & Presentation mode // and in all views.
      computeIntervals ();
      with (mgraphics) { set_source_rgb(bgcolor); rectangle (0, 0, dis_width, dis_height); fill();
      select_font_face("Arial"); set_font_size(10); 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) { minuteIncrement++; intervalWidth += minuteWidth; } mgraphics.redraw(); } else intervalWidth = dis_width; }
      function labelbgcolor(R, G, B) { bgcolor = [R, G, B]; mgraphics.redraw(); }
      Then savevand open this patch:
      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.
    • Oct 05 2013 | 8: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.
    • Oct 05 2013 | 10:30 pm
      i would just use a parallel buffer~ with waveform~ as display ...
    • Oct 06 2013 | 12:16 am
      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 ?...
    • Oct 08 2013 | 7: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...)
    • Oct 08 2013 | 9:21 am
      no worries, thanks a lot !
    • Oct 08 2013 | 9: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: http://www.instructables.com/id/How-to-Read-aiff-Files-using-C/?ALLSTEPS
      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.
    • Oct 08 2013 | 10: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 :-)
    • Oct 08 2013 | 6:18 pm
      "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 :).
    • Oct 08 2013 | 6:32 pm
      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.
    • Oct 08 2013 | 6:44 pm
      "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.
    • Oct 08 2013 | 10:19 pm
    • Apr 19 2015 | 6:35 pm
      Hi karaokaze, your tip and info is very interesting, I've tryed your solution but I can only visualize the first chunks of an aif file (the words FORM AIFF and COMM), but I cannot figure out how to extract the audio data from the file using the obj filein. Please can you help with a normal abstraction? Thanks a lot Italo
    • Apr 20 2015 | 12:59 pm
      @keepsound Hi, 'karaokaze' is another one of my mischievous accounts >8D Original intent here was to stir the ideas, not really a user myself of this technique nor a heavy/light-UI designer myself, but you've called me out! And so i've gone through it and gotten some results for you with as much time as i could spare for it. Many abstractions included in the attachment: symreader = an abstraction to view a 4-byte symbol(such as 'FORM' or 'SSND') starting at a particular byte; longreader = an abstraction to read a 4-byte 'long' number; shortreader = an abstraction to read a 2-byte 'short' number; ssndfinder = an abstraction to find and skip all chunks up until the 'SSND' chunk where the actual raw audio data is found;
      start with the 'FILEINDemo.maxpat' file, should be commented enough, but if you need more detail, it's all there in the weblinks listed near the top(this requires some advanced study, the links are very necessary reading... there are many other things you can do, which i don't explain, like reading the 10-byte extended-precision format of the sample-rate from the 'COMM' chunk, or displaying right vs. left channels, or extending this to .WAV etc... http://sox.sourceforge.net/AudioFormats-11.html ...google for more, everything i did here i learned today on the internet...) apologies in advance if it's not perfect, but everything needed to get started is there at least for AIFF. hope that helps.
    • Apr 20 2015 | 2:54 pm
      Hi Raja! WOW, Many thanks for your additional infos! Will study it! This is my test patch:
    • Apr 21 2015 | 5:56 am
      Hey, my pleasure to learn all this stuff and be able to help while doing so, hope it gets you farther. Forgot to mention, much of the max-patching for abstractions and such could be done more easily in javascript if you know some and use the js object(maybe even mxj/java could open soundfile, store the info. in temporary array and such and manipulate from there...)... a coding or scripting language would make this much easier, maybe you could even use a readymade soundfile reading class in that case(?): https://docs.oracle.com/javase/tutorial/sound/converters.html
      And some extra links i ran into along the way in case they're also helpful: Apple's original revision for compressed additions to the spec for the AIFF file format from 91: http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/AIFF/Docs/AIFF-C.9.26.91.pdf and if ya ever need help with understanding 'extended-precision'(the 80-bit/10-byte format for the sample-rate of the file) this was also interesting reading: http://en.wikipedia.org/wiki/Extended_precision
      also, the way i did '2's complement' to find the negative or positive of the 16-bit wave data info.... it will not be applicable across all bit-depths obviously(12 and 24 bit depth will be particularly hard as you'll need to zero-pad in order to fit within an integral of 8(i.e. within 16 or 32 etc...)...)... but the real way to do it is concisely explained here: http://mathforum.org/library/drmath/view/55924.html (or see wikipedia version too)
      ...and let me know how it goes, also if you find any more docs online about different file-format specifications(like mp3 and wav). i don't have any specific use for any of this but seems a key fundamental to music with computers in general, so i'd be very interested to see more of how folks might use this stuff in a customized way.
    • Apr 21 2015 | 12:08 pm
      Hi Rja_....many many thanks!!! That's abolutely interessant. What I'm searching for in this moment, is a way to extrapolate bitwise a writed audio smpte stream (the 80 bits to convert in h:m:s.f), and as just explained, the way to display a waveform without using the buffer or plot way in MaxMSP. At this moment I'm not able to write a js or mxj patch, or to build a external in C or C++, so I have to learn before how to do it with abstractions...and I'm not so young to learn all that stuff in little time. Grazie mille! Italo
    • Apr 22 2015 | 8:32 am
      'karaokaze' is another one of my mischievous accounts >8D
      : i knew there was something fishy with that Karaokaze guy ! )