ApolloStation

I finally got an organelle (a birthday present from my wife!).
This is my first attempt at a multi-page patch that can generate multiple synchronized parts (kinda a mini workstation/groovebox).
It’s a wavetable synth with sequencer and arpeggiator, preset based drum machine, and multifx (using FX 13):
https://patchstorage.com/apollostation/

I really like the new combo patch syle, and I want to make something that would be easy to swap different synths/sequencers/effect etc.
My subpatches are organized a bit different, they take a page number as a parameter and they will automatically hook up to the knobs for that page. Then the actual stuff you want to route between modules can be hooked up directly.

I also modified the paging code so that after a page change the knobs will start responding either if it passes through the current value, or moves 10%, which I find a bit more intuitive to use.

One issue I found was that reading/writing to the usb drive would often cause buffer underruns and stuttering. I put a block at the output to mute everything before I load, which seems to get rid of the stuttering (the dropout is still noticeable though).

Right now the sequencer has some quirks, and I think I’ll eventually try to write an efficient /robust sequencer external that can things like have multiple tracks, quantization and tempo scaling (after I finish a few other patches).

6 Likes

i can’t wait to try this. : )

congratulations, and nice patch.

I agree the new C&G patch style is a great improvement.

USB read/write - audio glitches , yeah that’s the nature of the beast unless these are pushed off to different thread which is scheduled with low priority.
( as IO is very slow compared to audio rates)
Even then care still has to be taken, as there’s only one core.

That all said I’m sure there must be pure data external that does this , as it’s a common Pd issue ( as it’s single threaded) … eg I think soundfiler (?) does this

an enhanced soundfiler object would be great: loads and saves in separate thread, indicates when it is finished. I don’t think there is Pd object that does this, so it is a bit of a drag especially saving or loading new files while playing. One workaround I’ve done for saving larger sound files in the background is to play the buffer into the writesf~ object. writesf~ does use a separate thread, so there are no interruptions. A similar thing could be done for reading sound files… but obviously not ideal because the sounds load and save at normal playback speed…

Nice patch @WyrdAl btw, thanks for sharing. I like what you have done with the modules, using inlets and outlets instead of the send receives, a bit more fun to patch together. The modularized approach is an ongoing project, you can grab the latest set here, but be aware still pretty developmental:

1 Like

There are ways of working around glitches when loading samples. I have been doing research on this and it is possible by using switch~ in a subpatch.

Switch can make a subpatch work at a higher speed than the rest of the patch. So when you load a sample it is uploaded “faster than realtime”. I still haven tried it though(Scroll all the way to the end):

https://puredata.info/docs/tutorials/TipsAndTrickshttps://puredata.info/docs/tutorials/TipsAndTricks

I really want this to work too as a lot fo the newer stuf I am working on is dependant of loads of random samples that is uploaded all the time so I reallly need this to work too.

id suggest thats not quite what it says … switch allows you to turn bits of the patch off, not run anything faster. (the PD thread is already at RT priority, its not getting any faster :wink: )

but id suggest, perhaps this is better taken to a new topic, as threading/preemption/realtime processing is a pretty big topic, and will swamp the great work @WyrdAl has done on the ApolloStation.

My formulation is not based on what is written in that tis & tricks page it is based on what another user, Baptiste, told me in Facebook group. And I’d say 99.9% of the time he is spot on what he says, he is PD “superuser”. He told me:

"just fill a table with readsf~ in a subpatch reblocked with [switch~ 256 1 2] and time will fly 2 times faster in this subpatch.”

But here is a quote form the link I posted for the tips & trick page:

"fileIO: all objects, that read files from disk, will block audio, until they finished executing. so do load all files beforehand.

When you need to load soundfiles during performance into tables, don’t use [soundfiler]. miller once suggested using [readsf~] in a subpatch with upsampling, so it will load the sample faster than reading it in realtime, but not block dsp during loadtime. it seems, that some people do load only the very first part of each file, that will be used during a performance into a table, and do read the rest from disk."

Which basically says the same thing > use a subpatch with upsampling(which you can do with either switch or block). When you do this the sample will be uploaded a lot faster, because of the upsampling, and therefor the dropout will be less if not 100% removed.

If you wan to see an example on upsampling using block~ check out pd tutorial jo7.overampling. Also check out the helpfile for block~.

So, yeah switch~ as well as block~ can be used for upsampling which is basically what he needs to do.

cool this is what @oweno was suggesting…with the addition, of increasing the sample rate to ‘stream’ the file i/o as a faster rate.

really, this is a bit of hack, unless you really need streaming, as you are forcing an unnecessary timing constraint on the process.
ideally, as previously suggested, you would just read on a separate thread, with a lower priority, which would mean PD would read as fast as possible as the CPU and IO will allow… but never (if using a RT kernel!) cause issues for the RT audio thread.

I’ll be interested to hear how this works for you on Organelle
(PC/Mac’s they have multiple cores and cpu frequency, HDD are much faster than your USB drive - so dynamics might be different)

This is the way it is done in Pd. You use subpatches to upsample down sample whatever. It is not a hack that is just how PD works. But yeah compared to many other apps it might look like “hack”, but that is because of the blocks, which is pretty unique to PD. It is a bit confusing, to he honest.

I would love to see how you do that. Example?

I have all ready been messing around with oversampling and… It doesnt go well with Organelle, it maxes it out way too fast. Just try the moog filter and crank up the oversampling anf watch your CPU on Organelle get swallowed up. But also depends on what you want. If you want ONE REALLY cool sounding synth you can get that, but if you want 10 drums, all oversampled, dont expect that to works. Maybe on your pimped up Organelle with quad CPU :wink:

its a hack in the sense this could be coded better as an external, and thus use less resources… and as I mentioned above, Im surprised if someone has not already written an external to do it, its not that hard.

as above, you code it in C++ as externals, sorry I don’t need it at the moment, so I’m not going to do it.

yeah, thats expected… and its also partly an issue with not having multiple cores available.

this trick might still be worth trying though, the reason is your not really oversampling anything here.

what its doing is calling ‘read file’ and transfer the data at a increased frequency (the higher sample rate) BUT the thread will be blocked doing the read, due to slow IO… i.e. if you tell it do 512kHz, you wont be doing 512kHz, the thread will be blocked trying to read the USB, so your limited to the rate of the IO, not the sample rate.

now the issue are (and why its a hack)

  • this is not really the intended purpose, so what does readsf do if it cant get the data fast enough as normally this is an ‘error’ i.e. imagine you are streaming at ‘play rate’, if you cant read fast enough, what does readsf give you… Id imagine (without checking the code) either zeros, or an incomplete buffer.
  • thread priority is really important, if the ‘readsf’ thread has the same priority as the audio thread, then its still competing.
    (and i checked the readsf code, bizarrely it doesnt set the thread attributes which means it could well be inheriting the thread priority, exactly what you do NOT want … but it is what you want if your using it for its intended priority (=streaming) )

these highlight an issue… you can get away with many things on a desktop, they have power/resources by the bucket load, unless your writing critical stuff (e.g. VSTs in a DAW that got loads of other VSTs loaded) , you’ll get away with murder.
thats just not the case on small platforms like rPI, Axoloti, Organelle … on these, efficiency is important.

BTW: this is a good idea, for sample playback (assuming no need play it at a faster than playback speed)

basically the idea, is to just give yourself a bit of a ‘head start’ , this is a bit like you will see with say youtube… have some data in hand, that allows for ‘variability’ in IO/network, but then just stream the rest at the rate you need it. also helps with not taking up too much memory.

Have you (or anyone) tried this with writesf~? Originally I wanted to increase write speed so I upsampled the sub patch that was writing, but couldn’t get it to work (I think writesf~ always wanted to write at regular speed if I remember correctly), so had to default to writing at regular speed.

did you increase the block size, I suspect this might be more important than the sample rate, as this translates to x_vecsize in the external. i.e. your saying transfer this much data at a time… and you dont care if it blocks IF this dsp chain is being run in a separate thread. (this is just from a quick look at the writesf code… d_soundfile.c if your interested…)

beware, the readsf code has a nasty comment saying its not strictly thread safe, and if your doing really fast transfers this could bite you. (but I guess on slow usb drive, less likely)

Ahh I thought you ment that it was all ready possible.

For oversampling I am using the j07.Oversampling example, that works fine. I was just pointing out that these object can be used to change the speed of how fast a subpatch updates, which means you can go below the 64 samples in a block for sample precision. And you can also use them, as far as I know, but I have not experimented too much with this yet, to change sample rate etc. Did you check the block~help file? There is some information on some of the things the object can do:

Yeah, true. Might have to pimp it up a notch with an extra core or 2 later on :slight_smile:

Ahh that quote was from the link, just passing on the message.

I am not sure about writesf~ and block~/switch~ have not tried yet. But it would be nice if it did :slight_smile:

But for example adc~& dac~ does not work with the block~/switch~ objects:

sasdasdsad

Maybe the same goes for writesf~

Thanks for the feedback and ideas!
Using sfread/write is a good idea. Reading in at audio rate should be fine for a lot of cases.
Readsf help does says I need to wait ‘a few seconds’ from sending open before playing the file, but I think a small fixed delay should be fairly safe. Also no way to know right buffer size, but that could be worked around. I’ll try that out for my next iteration.

I am loving this patch! …super quick to get drum variations and the synth voices into the FX are quite lush!

Hi, first of all i want to thank you for that wonderful patch! use it a lot to play drums and jam along the beats & arpeggiated sounds :slight_smile: Now i got it set up for ableton link what is a nice addition for my needs. The only thing i can’t figure out is how to get the arpeggiated lines out on a different midi channel (like the arpeggio synth patch does on midi channel 2)… Do you know how to change/add that in the patch?

What a great thread, lots of juicy stuff in here, can’t believe I missed it! :smiley:

hi jani,
I think you can just take the output from the seq_arp/arp object and send it to midi channel 2 with a note_out object. I’ve attached a main.pd with that modification for reference, I haven’t tested that it actually works though.
main.pd (1.6 KB)

Very cool, thanks!!