buffer play record buffer

Roman Thilenius's icon

buffer~ play~ record~ buffer~ ... you have seen that before when you have ever
built an audio editing program.

whenever i need more than 4 channels, i run into the sync trap with record~, because
it only takes int to start recording but no signal.

and its own sync signal is not of much help either, even in situations, where the
play speed is 1. and the buffer lenght is known.

i know that there are third party objects for copying buffers, but i really dont want
to use them.

in an old project i was using a 100 samples pregap with a spike of exactly 3.0 for
everything (the buffer from which is played and the buffer where is recorded to) but
that was getting really complicated and i am sure there is an easier method.

does any of you have found a workable solution for synchronising [record~] ?

goodparleyandorfing's icon

Hi. There is an external posted in this thread that does sample accurate recording.. https://cycling74.com/forums/sample-accurate-record-and-playback

Tim Lloyd's icon

Complete synchronisation of record~ is simply not possible above 4 channels.

It seems like you're already fine with recording into RAM with record~, so you could do it sample-accurately with hr.count~ and hr.poke~. I'm not entirely sure what length of glitch-free recording this will give you at a given sample rate (before you run into round-off errors), but it should be enough for most things.

If I remember correctly, it was Eric Lyon's el.sarec~ that was posted in that thread, but it was an OSX-only beta at the time, and it doesn't seem to be on his website.

To save you the trouble of wading through my messy patches in that thread, there isn't anything there that can't be accomplished with +=~/count~, poke~ and sig~............all my messing with Eric Lyon's objects was because I didn't know what I was doing, and just needed the sig~ object.

heh....beginners eh? :P

Roman Thilenius's icon

"not possible" is not an option. :)

i remembered an old trick of mine for things like that ... using poly~ ... a lot of
effort for such a basic task but it could work.

when all involved play~ and record~ objects are in a poly patcher, they can be forced
to sync upon incoming messages by turning the audio on:

1. user presses start button
2. poly is turned off
3. message is sent to line~ & play~ as well as to record~
4. poly is turned on again.

all audio objects will start at the same sample, all new buffers are in sync with each other
and with the original buffers.

will post a patch tomorrow if i have the time to do some testing.

-110

Roth's icon

To save you the trouble of wading through my messy patches in that thread, there isn't anything there that can't be accomplished with +=~/count~, poke~ and sig~.

That was my first thought, although at SR=44100, I think there would be issues recording for more than about 6 minutes as if I remember correctly 32bit floats can only represent every integer up to 2^24. For under 6 minutes though, I would certainly use a [count~] into as many [poke~]s as you need.

Another thought, if you have overdrive and audio interrupt on, as long as you aren't processing more scheduler events than the poll throttle, if you used one toggle to start all of your [record~]s, wouldn't it they start in sync as the int message in the [record~] wouldn't be called until the beginning of the next signal vector? I'm not an expert in scheduler settings, so take that with a grain of salt, but it seems to make sense to me while thinking about it.

Tim Lloyd's icon

The round-off error issue is why I suggested using Joshua Kit Clayton's hi-res objects. They use two 32-bit float signals combined to form a double with 48-bit precision.

So they can represent and pass between themselves accurate integers up to 2^48, which is round about 200 years at 44.1kHz. Should be enough time even for Roman ;)

2^48 = 2.8^14 seconds = 4.7^12 minutes.......etc.......

I would definitely go with the hi-res approach and have guaranteed sample-accuracy rather than using a dsp-reset "hack" within poly~. It seems more robust to me.

Roman Thilenius's icon

aha, so you are still undecided if it is possible or not possible, nice to hear that.

i dont need no more than 6 minutes .. and i dont see how double precision will
help to syncronize multiple record~ objects.

otoh my version here is really tricky and i havent found out yet what code
would make a good abstraction for general use.
so i will look into your poke~ approach now (poke only takes numbers, no??) just
to make sure i dont miss anything due to my ignorance.

-110

Roth's icon

aha, so you are still undecided if it is possible or not possible, nice to hear that.

Maybe I'm not sure what you are referring to. Using a single [record~] to record more than 4 channels in sync is not possible as Tim Lloyd said. I'm not confident in it since I'm nota scheduler expert, but based on other things I've been told and some things I have discovered while developing my own externals, it seems like using one [toggle] to start multiple [record~]s with "Overdrive" and "Scheduler in Audio Interrupt" is worth trying. I've got too many other projects going on this week to make a throughou test myself, but as long as you aren't doing more scheduler events than the poll throttle each signal vector, I have a hunch it might work.

so i will look into your poke~ approach now (poke only takes numbers, no??) just
to make sure i dont miss anything due to my ignorance.

[poke~] can definitely be trusted to do what you want and can take a floats or signals. So connect a [count~] to the middle inlet of all the [poke~]s you want and they will be recording in sync.

i dont need no more than 6 minutes .. and i dont see how double precision will
help to syncronize multiple record~ objects.

It won't help you at all with using multiple [record~] objects. What it does help with is the fact that signals in MSP are 32bit floats, and after you get passed 2^24, 32bit floats are not able to express every interger (can't explain it well myself, but it has to do with the way base10 numbers are expressed in binary and how floating point numbers are stored)—what this means is that after about 6 minutes (at SR=44100), using [count~] and [poke~] will no longer be writing to the [buffer~] sequentially, but will be skipping samples (you can run into the same problem playing back long [buffer~]s with [index~]). By outputting 48bit values from [hr.count~] into [hr.poke~], you don't have this problem because as Tim says, it would take recording for years before you would run into a precision problem (and that would take a lot of RAM to have a [buffer~] that big!).

Tj Shredder's icon
Max Patch
Copy patch and select New From Clipboard in Max.

This should do it sample accurate:

Tim Lloyd's icon

That's a cool patch from Stefan. But isn't the floating point recording index signal for poke~ potentially going to cause errors? The reference file of poke~ says that a float in the middle inlet is converted to an integer, which is good; but is it doing this (like + 0.5 then truncate) in such a way as to remove continuity errors before the value 16777621? It probably is, but I remember a while ago running into recording errors with poke~ and at the time attributed it to a non-int sample index ( and that seemed to fix it). I very well may have been wrong about that, some tests of long recordings might clear up any question for me.

Also, in that patch if you turn the toggle off, the sample index sent to poke~ will flip to 0, erasing the first sample of the buffer, so it becomes non-sample-accurate there. Poke~ needs a sample index of -1 to stop this happening.

It's a cool idea but I don't see any big advantage over just using count~; The scaled sync outlet of record~ is still going to be limited in accuracy to 6 mins at 44.1k,

Max Patch
Copy patch and select New From Clipboard in Max.

Here's how I would change it, disregard the float to int conversion if you think it's unnecessary:

Tim Lloyd's icon
Max Patch
Copy patch and select New From Clipboard in Max.

This still looks to me like the cleanest and easiest way of doing this; abstraction-ise the poke~ sub-patches (maybe with included argument-named buffers) and you have the easiest possible way of doing this imho.

Roman Thilenius's icon

"Using a single [record~] to record more than 4 channels in sync is not possible as Tim Lloyd said."

my question was about using more than one record~.

" I'm not confident in it since I'm nota scheduler expert, but based on other things I've been
told and some things I have discovered while developing my own externals, it seems like
using one [toggle] to start multiple [record~]s with "Overdrive" and "Scheduler in Audio
Interrupt" is worth trying."

i have even tried using a metro objecct to start sfrecord~ or record~ instances in snyc
some years ago but had problems with it.

the max sheduler gives me 1 ms, but i never sample accuracy.

"I've got too many other projects going on this week to make a throughou test
myself, but as long as you aren't doing more scheduler events than the poll throttle
each signal vector, I have a hunch it might work."

i have to try it out again once more, too.

it sound quite logical that certain audio objects _do start at the next vector after receiving
a message.

but i still wonder how to make sure that two instancs of an object are in sync: what if the
"start" message comes right at the beginning of the next audio vector?
it could still happen that one obejcts starts now andthe other one vector later.

but i could be wrong, and my bad experience with it might have other reasons.

but if it would be that easy we would not have discussed the phasor/cycle phase
issue during the last decade me thinks ;)

"[poke~] can definitely be trusted to do what you want and can take a floats
or signals. So connect a [count~] to the middle inlet of all the [poke~]s you
want and they will be recording in sync.

in this case i had no further questions, either i missed that when trying the
day before yesterday, or it i not yet supported im max 4 ... (i mainly develop
on mac os classic! :D )

"By outputting 48bit values from [hr.count~] into [hr.poke~], you don't have this
problem"

i am aware of the problem and theory behind it .. well, if i get it to work
using poke~ (will try later) i might even use the hr. ... the hr. objects _do
belong to the very selection i am willing to use where unavoidable.

hmmm ... do i have hr.count and hr.poke for OS 9? ... until now i´ve only
used *~ and biquad~ ...

-110

stefan: jpg or attachement would be cool. :/

Tim Lloyd's icon

The hi-res objects don't seem to be available for OS9 unfortunately. I'm attaching a pic of Stephan's patch, and of the last one I posted. Unless poke~ doesn't exist in Max4.x, I really don't see the point of using record~ for what you seem to need.

edit ------ in the samp_index cub-patch of my patch, the sig~ has a value of -1, it's hard to see in the screenshot.

683.Screen_shot_2010-06-12_at_19.08.54.png
png
Roman Thilenius's icon

so ... i dont know what i did wrong when i tried it ... but suddenly it works fine to
control poke with counter. maybe sometimes it just requires someone telling you
to do it.

and if really needed, both are available as hr. in classic, too.

hr.poke~ has doubleprecision only at the index inlet. ^^

the main reason why i was using play~ and record~ is that wide parts of my patch
are using milliseconds and not samples (and conversion is always a little risk).

another issue with count and poke is a playspeed other than 1.0 from the
source buffer ... it is okay to implement backwards, punch in/out, and loop
this way, but it is difficult to play the source 30% faster (without interpolation, get me?)

so now i have two working version, one with poke~ and then the one with my poly
on off magic ... and i cant decide which way to go.

-110
p.s. thanks for the jpg. :)

Roth's icon

the main reason why i was using play~ and record~ is that wide parts of my patch
are using milliseconds and not samples (and conversion is always a little risk).

Ah, I see. I often have reservations about that conversion risk as well. Been thinking about that a bunch recently regarding an external I'm working on and am trying to decide if I want to implement a ms mode, or just only have a samples mode. If you are okay with the precision of specifying times in ms, I would think that adding one samples-to-ms conversion may still be within acceptabe precision, going ms-to-samples though may not have the precision you want—guess you'd have to try out the risk and see if it works for you.

another issue with count and poke is a playspeed other than 1.0 from the
source buffer ... it is okay to implement backwards, punch in/out, and loop
this way, but it is difficult to play the source 30% faster (without interpolation, get me?)

That does bring up an issue indeed. Just to clarify because I'm a little confused by your wording: you want to play back the source faster without interploation? I assume that is not the case since you said you were using [play~]. If playing the source faster without interpolation is what you are after, you could use the same [count~] that is driving your [poke~] objects to drive an [index~] and just scale the output of [count~] appropriately before it goes into [index~]. If you want interpolation of the source driven by a [count~], that would be less simple. I suppose you could convert the output of [count~] to ms and use it to drive a [play~] (i've done things like that before in phase-vocoders, but I can see why you wouldn't want to for this application. Another thing you could do is use the [count~] to drive two or more [index~] and implement the interpolation (linear, cubic, whatever you want) in MSP, but that seems a little crazy and more suited to an external. I think someone posted a link to a version of [index~] that does interpolation, that may be helpful for this.
https://cycling74.com/forums/the-equivalent-of-tabread4

so now i have two working version, one with poke~ and then the one with my poly
on off magic ... and i cant decide which way to go.

So what is the function of this patch? If it is just a studio/sound design tool, the poly on off magic while not elegant does what you want so would probably be fine. If it is a live performance type thing, that would seem to justify the work in getting the [count~]->[poke~] (or something similar) working the way you want.

Roman Thilenius's icon

you are right: one can scale the output of count~ ... to _float .. in order to
drive wave~or play~ in parallel to poke~.

i am coming closer. :)

the function of the patch? .. currently i want maximum flexibilty ... think of creating
an abstraction for later use.
which is what i always try, even in a specific situation, where a specific solution
or workaround would be enough for the actual job.
 -110