Manually writing sample values to buffer… faster
Hi all, looking for some suggestions (and apologies for the long description):
I’m trying to manually write audio sample values from a text file back into a wav file – imagine a really long text file full of values from -1/1 . The sample values were extracted from various recordings using a Processing sketch I wrote and saved into text files; those files were then numerically sorted.
The Processing sketch was really fast, using for loops to iterate the array of samples as fast as possible. However, now that I am trying to put the samples back together, I’m running into some problems, mostly in terms of speed.
What I’ve tried:
1. "openraw" in sfplay~
While realtime, this sounds quite different than when I manually write sample values to a buffer. I’m assuming this is because a wav frame holds more than just a sample value. Audacity’s import raw function sounds identical.
2. Write to peek~/buffer~ from jit.textfile
This works great and sounds more like I’m intending. However, since peek~ and buffer~ don’t have a "bang when sample is written" feature, I have to put a 1ms delay before triggering the next sample. This means that a 10 second clip takes a few minutes (44,100 x 10sec = approx 7.35 minutes). For the amount of samples I’d like to work with, this won’t work since it is so far from being real-time.
So: any suggestions for a quicker way to do this?
I’ve spent some time looking through this resource on how wav files work:
… but it’s really confusing. I’m glad to really learn how to manually write wav files if need be, but I suppose I would prefer something a little more familiar using MSP.
What’s the format of the file you saved from P5?
There are chances you have an ASCII text file, so using openraw will create a sound file with the ASCII representation of your floats, which is not what you want.
Can’t you change your P5 sketch to directly write a binary file of floats?
To avoid your 1ms delay, can’t you use an uzi to read/peek~ your file?
It’s a text file… I’m assuming ASCII? In any case, it comes into Max as floats. I know the WAV file is written as hex values, but it seems Max would have tidied that up for users. I do wish the sfplay~ reference had more info about what exactly happens when the raw file comes in.
It’s my understanding that it basically reads it like a WAV file without a header, meaning it assumes some of the samples are the extra data that comes with the sample values in WAV format. Pure conjecture, and I could be wrong.
Uzi causes a stack overflow at the Jitter objects – I’m guessing messages coming in before the previous one is finished.
I would like to know more specifically about how sfplay~ opens raw data. I read in this post: http://cycling74.com/forums/topic.php?id=31434 that the object’s messages of ‘samptype, offset, srate and srchans’ will change how it’s rendered, but is there anything else we should know about importing information. And as an ancillary question, is there anything similar for buffer~ ?
Sound file are binary datas, generally starting with a header (containing informations about bit depth, sample rate, number of channels, and many other things like midi note, markers, regions, loops, etc.).
Those binary datas can be 8 bits integers, 16bits integers, 64 bits floats, etc.
So openraw will first skip the offset number of bytes (this offset could represent a header), then will create a sound with its sample length determined by samptype, will interleave those samples depending on the srcchans, and will use
So if you choose int8, each sample will be create with 8 bits.
Jeff, I’m quite conviced you have an ASCII file, so each character representing your floats will be considered as 8bits of datas:
is ASCII ’0′, ‘.’, ’5′, ’1′
i.e. the numbers
48, 46, 53, 49 (see atoi if you’re not familiar with ASCII)
And those 4 numbers (probably followed by a carriage return, i.e. ASCII 13) will be used with openraw, not 0.51.
try a [deferlow] object after the uzi to slow things down and see if that avoids the stack overflow (just a guess)
Thanks for the more detailed thoughts on the openraw. If it’s helpful for Kenneth, my experiments suggest that sfplay~ assumes the file is stereo and does some unexpected panning with non-audio files. Again, not exactly sure why but can be quite nice.
You may well be correct that the data is read as ASCII as far as spflay~ is concerned. Would the sample values need to be in hex, like they are written in a normal .wav file?
Also, the site I linked to above suggests that "a 16-bit sample can range from -32,768 to +32,767". Would this mean the resulting file should not have values between -1/1?
Thanks, I’ll give that a shot today. That’s one of those objects that I rarely use and just hadn’t thought of.
So adding [deferlow] after the "current index" outlet of the [uzi] and before calling the line from [jit.textfile] seems to work great. It’s still definitely not real-time, but WAY faster than before.
Here’s the basic code, if useful for others. I’ve also uploaded a text file of samples so you don’t have to make your own.
----------begin_max5_patcher---------- 1409.3oc0ZEzbahCF8ryuBUNtiqGPRfM8PmYOrG1K6dYussSGAHmRCH4ADMI sSyu8EIAIXuEgvXnwYlXOxQDd5oO89dee3ueyJmH9CzRGv6.+KX0pueypUpO R9AqZFuxIm7PbFoTMMGVUdDsvYs9OwqDYTg3wCT8+CmTlvYMvIhvt0A7wlYc fHh+bJ61OUPiE5I5syci65127aFrw84qIMQc63Qe4sdaauc64LAijqtYN+dQ JIq8uTCqTVMTTfzqyzKS+lZ5dxawyyUia0jgsfrfVRYBhHky5.Tn6NI1fpqG z9B3ixK5G2bi7k01Rcz6qWNsHVPePcKbD.WizoIZD6qHNM+AgFYwf4jE8NC9 HlmmSkwKmPHI7pnL5aiyRiuCH3efA9ZJ8dPbMNpmdI38uu8RxRYzXdESbzF4 +mlZ18vP0a6BUrUXO7DdN4I2KHOceQpfBJI4GxnkfbBqhjk8XMiAHfnp86oE f8E775QxKArOMi9A1e82+ye7N.oJIkCR30WW8G.XTZh75hn.NCrmW.DeNs7M iklQJ5U+JL.ZjkgWKrLZCPTUvjDil0HrDvgLxifHR7cNlXCEQrUeDEGX7vo6 rRGCHwEF9x91jT35iCga.xLBxPra4uw.m4A6vYaMpms6ZI.xaCnfRRTm+.78 MGXAekjUUm58rNh0vOXSmvBdswO8j9KgVKTkwuu2bfl8Q.65i.uy3grcu1x. FUIDbVuq7gcQ0r5cUwC5AP2dV89FWiSewzy9a02RAXrmqq4k45WdeHSOsqZs qmsgl1yQibKGNlsbzkikNPo28TSN7+jcnRzKasOiSLyOZMBLRETDZNui+XOS fl6yD4zxRxszetamySj.osIi0GSPvM90LRPOLxn8+AmaFo25FhNekiFyIHcl DyUND3+ZS2rGFo.HM3HNyfjFFQGqfLppDL1XD2eQLR4wLR+UP1j+zy3p16Jw RwjhCBFQXf6URXfxY4vcso82gR.i5pcr0nmK+vQRQ9ighvWT0Tv9AsnXax2V wDcpld3Fb3r1WqKn4jB5AZcUuxhTljM8l9vDXzSBF8ZKcSeVRjk0ctIaTL.z cXCIX3UhejujJ1TJJ1H3kOlGwy5mYVaE6.259RUt85ue2UxYHI6HGH6BPuLS 8j9TNQTj9fjiNdjMLFVmE2bEQyZiAP+BpBtwWuWfEUAim4hf6SpHNiRJljwT qpdI7JQqHgD+DvC.Gt8ovc9CGSCcmy0843Ls1nP8+jAJh2lGTFB0Myo4GTFD ckHF9aOAb2zK4TldKqFvVblnUvamIaVvWcEz2mHgpUd0+necRpEMsDr4or1i ZAz+JQtPZ77oghWVaeaO7z8FyChLF3DLmzykzedF4Q6Zdn8GsZxlFhLJ3r8J oyPGHw2AbMI5XSGU0moBMZHEdsjBV+DhOJrQo6bIxY41sCzdlahBBuTIsT2c kVxIeiWTKAUwsGwhk7ph31Ue6CPB7xhHgVJRYpmlZmIIKesyj9bZRBk0s4O4 oIG3oLQCH54AsZKlj2M3.PR9EnYAgjrh0AoI4WGkwfo5fHoTMVY+0G+7fIh0 SfwOGqxFetf7mTBYX9ye2hBJ0yEYPTgvibWUuShgJGbH2vmGMQ3FNCfcpmTk gZdCgoQtqp4OXfxHi9LhZvDwp7Q9LH+EtnzWfMwemf6YGStVfIYKv6HQO6pu gVDlAOdRCGlorAJqEUp65oB5TilHX8s4bJbYCzvg1totfZGV47Xg4IjMZriL MuGTqgg5JngltflUdRFKXmZdda7d.WVuamb65AS3kmmFRQaggjMIijckbLhr M1efa8zhsuLZwP6BxfHaCz7VNLYiqG3xJR3YClPmkHqGVWFUmQKQwnizgq2N M71h5B1smlRndvOt4+P0+11. -----------end_max5_patcher-----------
You don’t need a counter, uzi does this already.
The following patch works without a deferlow. BTW, the first datas in your attachment are below -1. I tried only with the first 44100 lines.
I just had a look in Processing: it doesn’t seem to be trivial to write floats as binary datas in a file.
----------begin_max5_patcher---------- 1254.3oc2Y87jaZCF8r8eEJ9XGGOHILfygLSOzC8R6kN8RSlNBP1q5BBOfH6 tIS1+1q9At16FiPXyhsalIlUBP7ziuu22ShuMcxr3hGoUy.e.7WfIS91zISz co5XRS6IyxIOljQpzW1LN8gh3+Y1byoDzGE5tKKpETPEUr6LaIhj6X7M+cIM QXd.X7Bu4.TTj5PvRcC3BOvmatEVpdnjC+6Qnciy5BtfSxo5S8mzxTBmr6b7 5bFOiJzHCtuSIV10K5fgoh8U8v.QxGsoayUJdZK0.wYylK+O3ypy98oSU+L+ 7HlskLt.jVvouyB0.gF5HZk5PXnUtANPbiWKbyvM4E.FfYcZ6olovP8ALZwx 1m1vnKTHg78mJpPc3zBLpyiok1XgHCKXNrroQKrP3QYgetjQxNWNvqSNHlv2 LnYGBfmEhwWmT.MLBBYkWBFDdAdB7xIwGIE44Tt3GHjzh53L56SxXI2CDEeh C9Bi9.HQhG4kWA93G2cKYLNMonlKN784QHQjIGyGoOXDXPqZgE8GDVzqEVb. 4oGJYp5Mj7sYzJPNgWSxxdRxX.BHtd8ZZIXcYQtrk5V.qYYzOw+se+O9kO.H 0orBohr79jc.3TZp59hofBNXcQIPbGq5c8klwFILSnZ.xJKitUXY7BfntjqH FCqQ3ofsYjm.wjj6sUp2SSDglDX+.qotd2JzAZAPo.phV1TXsbN5foenUgqn akIObAnjRR0oRfh0M4dfuPxpkNHOorkF9w2VxRv0F+DWKDE7te4C8LV57186 Qi8WdBEm9gpPCdY45ux.99POOqd2Lw0XsY0vU1Bxw87kH5nyebOKNqok46Od 5N3ZwZOkd+yM0d9U91Zqq8ooHrNlXkc8vk8US.OHdYVmUPNQBJmVUQ1POdUZ arhwgmuIUw3+GFzBszayInAgVFX+twcW0DazEsa3MX4Ewv6fK0TJqpzw1Fzv JlXErUglf9Fi3c8EiT0IizrtHy5E8gVID30V8yV2mD5VpzcoxAg0hqPydinM MDXUH0GeQRQFVITkmqNqqzX4vt.pO5+A5mp+vxZcMqtcoNFw9pNvCiwx95IY P7izoEzlBpv.Grf5eYcf1VbeRFkT1cUAmrNr51OvOkj7L.BPcyHnHimJq0IQ dCBkLfkEjtOkis0udfY5AcXWRQ3KxtjZbP+VrOo+zy.uEN7t22jTDoyFZibt L9nqXa3xGvfJRnWls7ele6leZVSdy9s2hZAZ4subgxE0yNvGXScBD1Z.SvfP HnSKf4sHcRsEltuxcuCpktBaU2I7h337bRsZggL6g9K3HcRlCUjahoruPMr+ 0lBsFk5DmW88v0SU8xRdAKVUTWlrab2sWdf8S1TZkfwIBlzo19KB+hq4NVZJ keXkzbV51BowvFLzxqTWgj5yn2Ijz62jzawXAJky6NA0qP9nfIXWXBNpXxG6 R7TP+vDT5hR8Q1wZEebz+03bAK5M.rm6KU4SC0Uve30GjhFUH8pGmMMhQFTc kO5OxhotnuiF2PbjKZDJC+in9t9w0Il7FWdxYL0CdB6sRKeFp2tILdeqyEst TMxebIvPWCzFQL4jQhwUfOvk.sfkiKlbQ3Z0nBoUt3VXbilzeewAGT3k9JUA ej1oUihgt04BWWB9CFYGqNsbidVgzHqB806vqgM0Md0h2l98o+KP48REy -----------end_max5_patcher-----------
Ah, you’re about the counter! Nice tidying up!
I’ve found that jit.textfile seems to work a little better with VERY large files (hundreds of MB or more, which is what I’m dealing with). Might take some more experimentation to see if it really makes any difference.
As for binary data… yeah. I’m poking around FileOutputStream but it is quite confusing. Supposedly the Ess library can write to file from a float array, but I’m not having any luck there. If I can get the Max solution to be close to or less than real-time, then that option should work great.