Skip to content

Waldorf Quantum/Iridium: round the sample map positions to the nearest frame - #339

Open
douglas-carmichael wants to merge 1 commit into
git-moss:mainfrom
douglas-carmichael:fix-qpat-position-rounding
Open

Waldorf Quantum/Iridium: round the sample map positions to the nearest frame#339
douglas-carmichael wants to merge 1 commit into
git-moss:mainfrom
douglas-carmichael:fix-qpat-position-rounding

Conversation

@douglas-carmichael

Copy link
Copy Markdown
Contributor

The QPAT sample map stores every position - sample start/end, loop start/end - as a fraction of the sample length with 8 decimal places. Rounding a fraction to 8 decimals can land it marginally below the exact frame boundary:

frame 3977 of 5469  ->  written as 0.72718961
0.72718961 * 5469   =   3976.9999787

The reader multiplies back and truncates ((int) cast), so every such position loses one frame:

loop.setStart ((int) (Double.parseDouble (params[11]) * numSampleFrames));

On a converted card of 165 presets, 759 of 2270 loop positions read one frame low. Reading a preset - the Contents audition included - therefore plays its loops shifted, and a QPAT-to-QPAT conversion walks every affected loop one frame further down per generation.

The device's own files confirm that rounding is the correct interpretation. A preset exported by an Iridium MK2 itself stores the same round-to-nearest fractions - from a real export:

"3:samples/R657 A4 Dream Pad 1/anfourpade_D#3.wav" ... 0.64510852 ...
0.64510852 * 116785 = 75338.9985     (loop start, i.e. frame 75339)
0.99999142 * 116785 = 116783.9980    (loop end)

Both land marginally below their frame, so the device has to round when reading its own exports back - otherwise its own export/import cycles would drift. A truncating reader mis-reads the device's files exactly like ours.

The fix rounds the four positions to the nearest frame. The writer is untouched: it already writes round-to-nearest fractions, which is what the device writes as well.

One observation from the same export, as a question rather than a change: the device writes the sample end as (frames-1)/frames - the last frame index - where we write 1.0 for the full sample (which the device accepts on import). If its end fields are inclusive, reading a device-authored preset trims sample and loop ends by one frame even with rounding. I did not change this since one export is thin evidence for a convention - you may know from the format work whether the device's end positions are inclusive.

Verified by re-reading a full converted card with the fix: the 759 truncation victims move up exactly one frame, all other positions are unchanged, and writing-then-reading a preset now returns every position identically over repeated generations.

…t frame

The sample map of a preset stores every position - sample start and end,
loop start and end - as a fraction of the sample length with 8 decimal
places. Such a fraction can land marginally below the exact frame
boundary: frame 3977 of 5469 is written as 0.72718961, and 0.72718961 *
5469 = 3976.9999787. The reader truncated this product, which loses one
frame for every position whose fraction rounds low - 759 of the 2270
loop positions on a converted card of 165 presets. Each read of such a
preset therefore shifted its loops, and converting a preset to QPAT and
back moved them one frame further down with every generation.

The fraction is now rounded to the nearest frame. This also matches the
device: presets which an Iridium MK2 itself exports store fractions
which land marginally below the frame in exactly the same way (e.g.
0.64510852 * 116785 = 75338.9985 for loop start 75339), so the device
has to round when it reads them back - a truncating reader mis-reads
the device's own files too.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant