Chains - a Sunday afternoon math riddle

ok so I’m trying to figure out a thing but my brain is somehow fried. :confused:

I want to do this:

for a set of audio files with varying length, I want to calculate padding between them to create sample chains for the Rytm.
Now, I don’t want the individual slices to all be the same length, but I want them to be the minimum length which would fit into the 120-division start/end parameters.

simple example without padding:

file 1 = 100 samples
file 2 = 200 samples
file 3 = 300 samples

file 1 start = 0
file 1 end = 20

file 2 start = 20
file 2 end = 60

file 3 start = 60
file 3 end = 120

it’s easy as long as the original files already fit into the grid, as with the example above.
but lets change the example to this:

file 1 = 97 samples
file 2 = 199 samples
file 3 = 298 samples

we now have 594 samples in total. each individual slice length doesn’t fit into the 120 grid, so they have to be padded with silence.
again, it would be trivial to pad them all to the same length, such as 298, and then have an even 1/3 division on the start/end parameters, but it’s not what I want to do.

I need to find a formula to pad each individual slice such that each slice is addressable by the 120 resolution. In the above example, intuitively the solution is to pad file 1 by 3 bytes, file 2 by 1 byte, file 3 by 2 bytes. we would then end up with the first example.

another more extreme example:

file 1 = 10 samples
file 2 = 99999 samples

a relatively short vs long slice, with a ratio of 10:99999.

we want the start/end parameters like this:

file 1 sta = 0
file 1 end = 1

file 2 sta = 1
file 2 end = 120

so we need to pad these two files such that the ratio between them is 1:119.

it’s kind of embarrassing but I feel kind of out of my depth on how to do this properly, especially if there are many files. each time I tried to implement a solution, I realized there was some major error. :stuck_out_tongue_winking_eye:

^^must have been a tough saturday night :slight_smile:

Here’s how varichains are implemented in my AR uploader (for Windows) (see
AR Uploader for Windows - Sample Chains and Batch Uploads ):

if(b_varichain)
{
// Varichain

if(120 != ((120 / chain.numElements) * chain.numElements))
{
trace “[…] varichain length would result in non-integer sample start/end step.”;
trace “[…] adding silence to compensate”;

  int newChainSz = chain.numElements;

  while((120 != ((120 / newChainSz) * newChainSz)) && (newChainSz <= 120))
  {
     newChainSz++;
  }

  if(120 != ((120 / newChainSz) * newChainSz))
  {
     trace "[---] unable to determine usable varichain size :(";
     exit(5);
  }

  loop(newChainSz - chain.numElements)
  {
     ChainEntry enVariPad <= new ChainEntry;
     enVariPad.init();
     chain.add(#(deref enVariPad));
  }

}

int chainStep = 120 / chain.numElements;
trace "[…] varichain size is “+chain.numElements+”, sample start/end step is "+chainStep;

maxSmpSz = ChainUtils.GetMaxSampleSize();
int varStepSmpSz = maxSmpSz / chainStep;
trace "[…] varichain step sample size is "+varStepSmpSz;

ChainUtils.AlignEntrySizesTo(varStepSmpSz); // Align to multiple of "varStepSmpSz’
}

EDIT: for clarification, the “loop” statement evaluates the loop count expr only once (unlike a “for” or “while” loop) /EDIT

btw, did the MD5 sample checksum thing work out ? (didn’t get a reply from you after that)

Hi!

haven’t investigated the MD5 things further - waiting for feedback from HQ :slight_smile:

not sure if I understand your code entirely.
but it looks like you’re creating “empty” entries if the number of elements in your chain don’t fit into the 120-division nicely? does this mean that some chains come with extra silence at the end?

I think what I’m trying to do is slightly different…
I don’t need even divisions between the individual slices, main goal is to keep the amount of padding to a minimum. so each slice should have just enough padding to fit into any 120-division relative to the entire chain, such that the full 120 range is used.
and it needs to work with any number of chain elements from 1 - 120.

not sure why I’m having so much trouble with it, this shouldn’t be so problematic but my mind fails to grok it… :zonked:

Void, I don’t understand why you need to fit >120 samples into a 120-based division…
That would mean that if I chose start = 5 / end = 6 on the Rytm, I would have more than one slice on my trig : what’s the point ?
Did I overlooked something ?

sorry - in the first post’s examples, “samples” mean individual sample points within an audio file.
e.g. in a 48kHz file which is 1 second long, there are 48000 samples.

1 Like

that’s what the code does – it keeps the amount of padding to a minimum while remaining compatible to the 0…120 sample start / end range of the AR (and OT).

extra silence is added when the number of slices does not fit that range, i.e. 11 slices will be padded to 12 b/c (120/11) is not an integer.

since we’re talking about varichains, the extra pad slices usually consume very little memory (unlike extra slices in fixed-size sample chains).

^ ok :slight_smile:

so what I’m trying to do, is actually use 11 slices in that case.
it should be possible to add padding to the individual slices such that:

slice 1: 0-11 -> length 11
slice 2: 11-21 -> length 10
etc... the sum of all slices lengths needs to be 120 of course.

well, here’s an example that uses 11 (vari-)chain elements:

original file sizes:
1: 34004
2: 11800
3: 38356
4: 35744
5: 4834
6: 13106
7: 14846
8: 15282
9: 34004
10: 43146
11: 5704

250826 bytes

varichain sizes:
1: 34480
2: 12930
3: 38790
4: 38790
5: 8620
6: 17240
7: 17240
8: 17240
9: 34480
10: 47410
11: 8620
12: 4310 (padding)

280150 bytes

[…] varichain length would result in non-integer sample start/end step.
[…] adding silence to compensate
[…] varichain size is 12, sample start/end step is 10
[…] varichain step sample size is 2155 frames

like I said: minimum overhead :slight_smile:

(these are the first 11 samples of the classic ST-01 sample disk, btw)

p.s.: A musician-friendly UI version of this tool is going to be released soon.

hmm… yea seems the padding at the end is not that bad… :slight_smile:

wondering how you get to

varichain step sample size is 2155 frames

?

if chainStep is 10, what does

ChainUtils.GetMaxSampleSize();

do?

My brain 'urts…


1 Like

Interesting challenge, to get a true minimum might need an iterative optimisation routine, but I think there’s likely little benefit in chasing that tbh
.
adding a separate pad at the end is a neat notion, it reminds me of the similar thing I did for the OT and raises an arguably more pragmatic point … it could become a pita to manage the proper usage of a chain of varying lengths, so even if it’s saving the precious ram resources, it’s offsetting the nuisance to a user who now needs to keep tweaking start and end by ear to suit
.
I have it on good authority that a ‘start and end’ LFO destination is in the pipeline, in that instance having common length samples is advantageous too !
.
fwiw - for my Max chain compiler for OT (where RAM needn’t be used admittedly) my approach was to make all hits the same length and make the few longer (cymbal) hits integer multiples of the default short length and locate the longer samples at the end of the chain - the OT can have more accurate unequal chain lengths too, but I liked just using a drag and drop auto approach for a consistent layout scheme

the one thing I want to do with this is to create kits where there is one sample chain per kit. Just drag/drop samples onto SDS Drop’s pads, everything else is automatic.

It would have an option to export the chain/kit, so you could easily create & share sample-based kits with other people.

^ I think it’s a good thing and an interesting puzzle, I presumed the automation using app, in case I wasn’t clear it was just about the administration of using any irregular chains once they’re in the m/c … that then requires a little planning from a user
.
ahhh , penny just dropped … I see what you’re offering, do once use many times (less manual shuffling about) :+1:
I tend to want to use chains in a way to substitute similar or compatible alternatives, so maybe a chain of tones with increasing harmonic content that can be played with velocity etc - so i’d tend to think in terms of advantages when there’s linear progress through a chain
.
sorry for derail - but neat that you’re saving slots and trying to reduce sample RAM too, good thinking, may well be worth an optimisation routine !

the entire samplechain concept is nothing but a nuisance (invented in the early 90ies to work around the limited number of sample slots in a back-then popular home computer software)

With the AR, the main advantage - beside the obvious advantage of saving sample slots - is that samples upload faster. Uploading many small samples is very(!) slow for some reason, putting all the small samples in one big sample chain accelerates the upload by factor 40 (!).
(to be precise: the transfers itself are relatively fast but the +drive writes seem to be rather slow. it’s worse when the AR has to create many small files)

I’m currently trying out a workflow where I create project/song-specific samples using all kinds of synths (mainly percussive sounds), then transfer them to the AR to sequence/process them.
Since the samples (and the selection of samples) will change while working on the track, it is convenient to just put them in a samplechain.
Saves me from having to manually delete or replace all the slices, e.g. after batch processing the sounds with a PC.
Just an experiment, though :slight_smile:

that’s neat! then we can finally do wavetable synthesis w/o resorting to software / MIDI LFOs.

I’m not surprised :slight_smile: My tool does the same thing, except that the samples are simply uploaded to whatever directory the user has selected (on the AR). Assigning them to the AR tracks is up the user then (just take a few seconds, anyway).
Does your tool upload them to the +drive or are the samples gone when the AR is turned off ?

Feel free to use the varichain algorithm I posted earlier (that goes for everyone who wants to implement this) !

it’s all in the code, i.e. “int varStepSmpSz = maxSmpSz / chainStep;”
ChainUtils.GetMaxSampleSize() simply returns the size of the largest sample in the chain (number of sample frames).

edit: ah didn’t realise the file sizes did include 40 byte headers…
getting the same result as you now. thanks!

the one thing I want to do with this is to create kits where there is one sample chain per kit. Just drag/drop samples onto SDS Drop’s pads, everything else is automatic.

It would have an option to export the chain/kit, so you could easily create & share sample-based kits with other people.
[/quote]

I encourage you to do this, as I’d like to support anyway I can. :+1: :+1: :+1: I was looking at doing something originally with SoX. But have been making most of my chains manually… I’d love for a sample-chain utility that works well on OS X + the ability to save time on making kits would be well over the top.

I love this conversation, gentlemen.
:+1:

You guys deserve a good beer :stuck_out_tongue_winking_eye:
Just saying…

It may also be worth looking at Abhoth’s OctaChainer, which I believe calculates the minimum padding needed for chains:

http://www.elektronauts.com/t/octachainer-v1-0-uploaded-a-tool-for-sample-chains/10334/83896

ok finally got it. :slight_smile:
thanks Scott for the hint towards an iterative approach!
pretty much just stupidly adding padding frame-by-frame to the element which is closest to a clean integer ratio until everything fits into the grid…

not sure how to test it for correctness, but it does its thing and fits on a napkin:

with bsp’s 11 example input files (i’m interpreting them as frame counts, not raw file size but this doesn’t matter), it would create a chain which looks like this:

done after 11375 iterations:
slice  0 total frames:    34960, padding  956, STA   0, END  16
slice  1 total frames:    13110, padding 1310, STA  16, END  22
slice  2 total frames:    39330, padding  974, STA  22, END  40
slice  3 total frames:    37145, padding 1401, STA  40, END  57
slice  4 total frames:     6555, padding 1721, STA  57, END  60
slice  5 total frames:    13110, padding    4, STA  60, END  66
slice  6 total frames:    15295, padding  449, STA  66, END  73
slice  7 total frames:    15295, padding   13, STA  73, END  80
slice  8 total frames:    34960, padding  956, STA  80, END  96
slice  9 total frames:    45885, padding 2739, STA  96, END 117
slice 10 total frames:     6555, padding  851, STA 117, END 120
total padding added: 11374 frames (4.53 %)

edit: just measured the time - for this example it’s 2.5 ms on my old macbook air. probably can be optimized but it’s fast enough.