rjdj / rjlib

Abstractions and externals for writing RjDj Scenes
http://more.rjdj.me
160 stars 43 forks source link

u_playtable uses hardcoded samplerate #12

Closed danomatika closed 11 years ago

danomatika commented 12 years ago

u_playtable uses a hardcoded sampel rate of 22050 and thus plays samples on my 44100 machine at half speed. It should be using [samplerate] ...

diplojocus commented 12 years ago

Hey Dan,

Thanks for letting us know. I've just pushed a fix.

Cheers, Joe

footils commented 12 years ago

Hi,

oops, seems my long explanation while reopening the issue got lost in cyberspace.

Anyway, here it is again: The usage of a hardcoded 22050 Hz is deliberate and a feature not a bug. You can overwrite the samplerate used for playback with the "sr $1" message to the rightmost inlet. This is the same setting as in s_playtable2, s_playolap, u_samplebank etc.

It's important to realize that the correct samplerate value to use here depends on the samplerate of the soundfile and it's independent of the samplerate that Pd is running in. 22050 was used as that is what the iPling devices run on, so 22050 is (or at least was) the most common samplerate of the soundfiles people used for optimum memory usage and performance on these devices.

I think we can discuss, if a different default would be more modern, but in this case it has to be hardcoded and not derived from Pd's samplerate~. And actually probably a way to more easily set the samplerate for all active objects would be useful.

I have reverted your fix for now, Joe, sorry. :)

danomatika commented 12 years ago

Ah ok. I use [soundfile_info] to get the correct sample rate, forgot it's not vanilla. Too bad soundfiler dosen't provide this ...

Maybe a global receiver/var/settings could be added? I'm looking to integrate my rc-patches with rjlib, so something that easily works on both mobile and desktop worlds is ideal.

footils commented 12 years ago

Yeah, I was thinking of something like a global receiver as well for a long time, but would like to avoid poisoning the global namespace, so it should be only one single receiver.

This could be useful for other things as well, similar to the "pd" receiver of pd for "pd dsp 1", so it should follow the same model with a single receiver/sender and tagged messages.

danomatika commented 12 years ago

Maybe something "rj" preceded? Like "rj sample sr 44100"?

danomatika commented 12 years ago

With "sample" being a subspace within "rj". It would make sense if there was a single receiver for "rj" settings. Or better caps like sssad: "RJ".

diplojocus commented 12 years ago

Hey Frank,

Sorry I didn't see any response so I just went ahead made the change.

Although I feel like maybe we should discuss this more. I understand the initial desire to lock everything to 22050Hz for iPhone constraints, but is it (and will it be) still an issue? I feel with every project we're looking more and more to moving towards 44100Hz as at least the last 3 generations of iPhone would be able to support it.

It makes sense for architectural / open-ended functionality to be able individually set the samplerate for [s_playtable]s but in practice I think this could add another workflow level if it was enforced behaviour. The beauty of some of the current objects is that you can quickly add them as you're patching and they just work. Personally I would find it frustrating if I had to connect a loadbang and sr $1 message everytime I wanted to use the playtable.

Take [c_urn] for example, I love this object but am constantly adding the [clear, bang( message everytime i use it. While not extremely difficult to do, it does add up when trying to patch 'creatively'. :)

I would suggest that the default is set to the project samplerate and that it could be overridden if necessary with the 'sr $1' message. Other workstations tend to re-sample a file to the project samplerate, I see this as standard.

diplojocus commented 12 years ago

I also agree with you Frank on not poisoning the global name space :D

danomatika commented 12 years ago

"The beauty of some of the current objects is that you can quickly add them as you're patching and they just work. Personally I would find it frustrating if I had to connect a loadbang and sr $1 message everytime I wanted to use the playtable."

This is my feeling exactly.

dizzybanjo commented 12 years ago

My quick contribution would be that :

While RjDj does run at 22050 and its kinda good to that having a default enforces people getting their files in the right samplerate, we are indeed considering 44100 for more modern apps. ( we considered it for http://dimensions.rjdj.me )

However - migrating RjDj up to 44100 would of course be much more complex because of the legacy scenes..

I'd also like to add that in general working in 22050 is the scourge of my life and countless hours of audio tweakery have been destroyed as I downsample :((( :D

danomatika commented 12 years ago

I agree in principle on not adding to the global namespace willy-nilly, but practically speaking, doing so would be the easiest way to deal with this issue IMHO.

diplojocus commented 12 years ago

All those beautiful 11025Hz+ frequencies rolled off :'(

footils commented 12 years ago

Hi,

okay, what about this: We carefully employ a single global sender/receiver reserved for stuff like this and some future things, too. It will be called "RJDJ" and can be used with tagged messages. The first use would be to globally set the samplerate for soundfiles like: [; RJDJ sf-samplerate 44100(. This would allow to change this samplerate for all soundfiles from _main.pd.

The RJDJ receiver maybe could also be used to inform a patch about various environment settings, like the version of the RjDj app, for example, or to get info about hardware capabilities from the app.

If you agree, I'll implement the samplerate settings for the various players and u_samplebanks.

Ciao

Frank

diplojocus commented 12 years ago

Hey Frank,

I feel the simplest solution would be to use whatever samplerate Pd is running at. What are your thoughts on that?

Cheers, Joe

danomatika commented 12 years ago

Frank, that would be the most useful way. Sounds good.

dizzybanjo commented 12 years ago

Im unsure of what the best solution is really, but drawing it from whatever Pd is running it seems logical.

I would add, that the likelihood of the RjDj app moving over to 44100Hz, at least in the near future, is very low.

I think this is mainly due to the difficulty in migrating existing RjDj content over.

Of course rjlib can be used anywhere and not just within RjDj scenes on iOS devices - but I just thought I'd bring this up.

r

footils commented 12 years ago

Hi,

the samplerate Pd is running at is not the samplerate of the soundfile. For example, I often run Pd at 48 kHz when using USB devices, but still my samples are at 44100 Hz. Both are completely independent as far as s_playtable is concerned. It will happily playback samples with correct speed regardless of what rate Pd is running at, provided it is set to the samplerate of the files.

The real problem IMO is not a wrong default (every default is wrong) but that setting the samplerate of the files is only possible one by one, and that's the thing the global receiver is intended to solve.

Ciao

Frank

diplojocus commented 12 years ago

Ok I see your point. If you want to use files that are at a different samplerate to Pd then a global receiver would make sense.

However, if the current default samplerate is set to 22050Hz then it would be necessary to use a global receiver for all samples not at 22050Hz.

What I'm proposing is that if we set the default SR to what Pd is running at then we can assume that our samples (with the same SR) will be correctly played without extra coding.

If we then want to run samples at a different SR to what Pd is running at the methods you're suggesting would be perfect. And actually this is already implemented with the 'sr $1' to individual [s_playtable]s.

Are you already over-riding your [s_playtable]s to 44100Hz when running Pd at 48000Hz? Wouldn't this mean that changing the default SR from 22050Hz to Pd's current setting would not break anything?

footils commented 12 years ago

Actually for me personally the important use case was that I cannot reliably run Pd at 22050 Hz on my laptop (crashes), so I run it at a "normal" CD or DAT samplerate and I am still able to play 22050 Hz samples intended for RjDj scenes.

But the software designer in me says: Soundfile sample rates and Pd's sample rate are different entities. s_playtable is an object that resamples from the soundfile rate as set via "sr $1" to Pd's samplerate (btw: s_fplaytable and readsf are objects that don't resample).

As library authors we can know Pd's sample rate but we are oblivious to the soundfile samplerates (no sndfile_info in vanilla), so we can only guess the latter. Here I prefer a hardcoded guess using the iPlop samplerate as default.

This guess is independent of what samplerate the user is currently running Pd at and that IMO is good! Because if users use soundfiles sampled at a different rate, say 44.1 kHz, they will immediatly notice it - like Dan did - because it's played back too slow. Then they have to fix it: either by resampling their files or by sending an "sr 44100" (or whatever is the soundfile samplerate) message to the playback object. Both these solutions will also fix the playback if the scene is played back on the iPlop.

danomatika commented 12 years ago

Of course, as programmers, we all know the real solution is that soundfiler should return the files' sample rate ...

footils commented 12 years ago

Forgot to mention: The hardcoded 22050 default also will let old scenes play back correctly when the RjDj apps gets modernized to use a different global samplerate like 44100 at least where samples are played back with s_playtable.

diplojocus commented 12 years ago

'This guess is independent of what samplerate the user is currently running Pd at and that IMO is good! Because if users use soundfiles sampled at a different rate, say 44.1 kHz, they will immediatly notice it - like Dan did - because it's played back too slow. '

I actually think the opposite is true. (Correct me if I'm wrong Dan) He had 44100Hz samples in Pd running at 44100Hz and [s_playtable] plays it back at the wrong speed!

It's up to the user to make sure their samples are at the correct rate. Every other DAW I know will up/down sample your files to fit your project, if they don't then they're played back at the wrong speed.

As Rob mentioned earlier, support for 44100 in RjDj is currently unlikely.

danomatika commented 12 years ago

Yes, I'm running at 44100 and 44100 samples play back at 22050.

"As Rob mentioned earlier, support for 44100 in RjDj is currently unlikely."

This is why simply adding a global sample playback rate is preferable. For instance, someone who writes an 8 bit themed scene can run 11025 samples easily and I can set the sample playback rate to 44100 on my desktop. As long as it's documented, it would save the trouble of setting it each time. Fine, default it to 22050 ... but give us the option to save having to type lots of redundant messages by simply adding a [; RJDJ sample sr 44100 < message to our main patch along with the declare.

diplojocus commented 12 years ago

Dan, I agree that there should be a way to change the samplerate easily, however I believe there are two use cases here:

Use case A) A user wants to play back samples of the same samplerate as Pd is running at.

Use case B) A user wants to play back samples of a different samplerate as Pd but keep them at the correct speed.

Having a global send method or changing the SR with a message solves Use case B. However, in the current method a user in Use case A would be required to constantly be changing their SRs for anything other than 22050Hz.

Setting the default [s_playtable] SR to Pd's SR solves Use case A. Adding a message to over-ride [s_playtable]'s default SR solves use case B.

danomatika commented 12 years ago

Ah ok, I see what you mean. I thought you were saying set it to PD sampels rate without adding a user settable default. Yes, that makes the most sense. RJDJ patches will get 22050, desktop people should get 44100, and anyone else can set it if they need too (aka RJ scene creators working with 22050 samples on their laptops ...).

footils commented 12 years ago

s_playtable is resampling the soundfiles to whatever samplerate Pd is running at, just like the pro-DAWs Joe mentioned. That's the whole point of it. Unfortunatly Pd vanilla has no way to know the samplerate of the soundfiles automatically. A user either has to tell Pd the file-samplerate or must use samples that have the rate set to the default samplerate of s_playtable, which currently is 22050.

If the default samplerate of s_playtable would be the result of [samplerate~], it would be a moving target, because users or apps can run Pd at many samplerates. The resampling would be an unnecessary feature and in the end, users who'd like Use case A to be solved, should better be using [tabplay~]: It's faster because it doesn't resample and always plays back samples at Pd's SR, regardless of the file SR. It will also be wrong if you use a different samplerate in Pd. :)

diplojocus commented 12 years ago

Yeah your right, I read the description you posted previously and was going to say under those terms [s_playtable] acts exactly as described, but got distracted :)

The issue with that is that it causes confusion for anyone trying to use the object. I have always been under the impression that [s_playtable] was a heavier version of [s_fplaytable] where the former is using [tabread4~] for interpolation. In actuality it seems that they both have very different use cases, the problem is that this not entirely obvious at first glance - and is the first time I've heard of this in 2 years of using rjlib!

If [s_playtable] is actually designed as a re-sampling tool then it should be worded differently IMHO. Something like [s_resampler]??? And the help patch should clearly state this. But obviously this brings about other implicit issues... :S

danomatika commented 12 years ago

So does it stay 22050 with no way to set it globally?

footils commented 12 years ago

Hi Dan,

sorry, I somehow forgot to finish this. I have now added a receiver to the relevant objects, which I think are these:

u_samplebank.pd, u_samplebank2.pd, s_playtable.pd, s_playolap.pd, s_looper.pd, s_loopsmooth.pd, u_samplebank-help.pd, s_playtable-help.pd, u_samplebank2-help.pd, s_playtable2-help.pd, s_looper-help.pd, s_playolap-help.pd, s_loopsmooth-help.pd

The global receiver is called "RJLIB" and the meta-message to send has to start with the tag "sf-samplerate ". This then will have the same effect as sending an "sr " to the right inlet for these objects. Here's my commit message for reference:

"Added global RJLIB receiver with message sf-samplerate to globally set the samplerate to use for soundfiles. This allows selecting a different samplerate for soundfiles than the default 22050 in soundfile loading and table playback objects like u_samplebank or s_playtable. Note that u_record or s_fplaytable do not support this as they rely on Pd's current system samplerate (they use tabplay~ rsp. tabwrite~). This is the first global receiver apart from the sssad receivers used in the rj library, but it sounds pretty useful to have here. Also note that of course this will only change the default rate for objects already created, so if you later add another of these objects, you need to send your changed default again."

I hope I haven't missed any objects. It would be cool if you could test this and see if it's of any help.

All the best,

Frank

danomatika commented 11 years ago

Hey, I just double checked these and they work great. Thanks! Hopefully, we can eventually move to 44.1 ...