Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions documentation/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
* Fixed: A mapping slot without explicit sample-trim points read a sample start and end of -1 instead of the whole sample (e.g. a converted Waldorf QPAT then showed a sample start and end of -1 on the device).
* EXS24
* Fixed: Loop type was not applied.
* Fixed: Envelope times were converted from the EXS24 parameter linearly, but the device applies a fourth-power curve, so short times were greatly overstated - and the attack stage additionally skipped even the linear scaling, coming out about 12.7 times too long on top of that. A quick attack (e.g. 7.5 ms) was read as over a second, so plucked and struck instruments faded in too slowly to be heard and appeared silent. Envelope times are now converted with the hardware-calibrated curve seconds = 10 * (parameter / 127)^4, matching Logic to within one percent (thanks to Douglas Carmichael).
* FLAC/OGG
* Fixed: FLAC or OGG samples stored inside a ZIP archive (e.g. discoDSP Bliss or DecentSampler libraries) could fail to decompress.
* Fixed: Stereo (multi-channel) samples stored in a compressed format were truncated to half their length when decompressed while writing to an uncompressed destination.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,12 @@ private static void applyFilterParameters (final EXS24Parameters parameters, fin

private static int formatEnvTime (final double time)
{
// Maximum time for each step are 10 seconds
return time < 0 ? 0 : (int) Math.round (time / 10.0 * 127.0);
// The device maps the 0..127 parameter to a maximum of 10 seconds with a fourth-power
// curve (see EXS24Detector.envelopeTimeToSeconds), so invert it:
// parameter = 127 * (seconds / 10) ^ (1/4).
if (time <= 0)
return 0;
return (int) Math.round (127.0 * Math.pow (Math.min (time, 10.0) / 10.0, 0.25));
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,13 +338,12 @@ private static IEnvelope createEnvelope (final EXS24Parameters parameters, final
final Integer attackCurve = parameters.get (envelopeIndex == 1 ? EXS24Parameters.ENV1_ATK_CURVE : EXS24Parameters.ENV2_ATK_CURVE);

final IEnvelope envelope = new DefaultEnvelope ();
// Maximum time for each step are 10 seconds
envelope.setDelayTime (delay == null ? 0 : delay.doubleValue () / 127.0 * 10.0);
envelope.setAttackTime (attack == null ? 0 : attack.intValue ());
envelope.setHoldTime (hold == null ? 0 : hold.doubleValue () / 127.0 * 10.0);
envelope.setDecayTime (decay == null ? 0 : decay.doubleValue () / 127.0 * 10.0);
envelope.setDelayTime (envelopeTimeToSeconds (delay));
envelope.setAttackTime (envelopeTimeToSeconds (attack));
envelope.setHoldTime (envelopeTimeToSeconds (hold));
envelope.setDecayTime (envelopeTimeToSeconds (decay));
envelope.setSustainLevel (sustain == null ? 1.0 : sustain.doubleValue () / 127.0);
envelope.setReleaseTime (release == null ? 0 : release.doubleValue () / 127.0 * 10.0);
envelope.setReleaseTime (envelopeTimeToSeconds (release));

if (attackCurve != null)
{
Expand All @@ -358,6 +357,27 @@ private static IEnvelope createEnvelope (final EXS24Parameters parameters, final
}


/**
* Convert an EXS24 envelope time parameter to seconds. The parameter ranges from 0 to 127 and
* maps to a maximum of 10 seconds, but the device applies a fourth-power (not linear) curve, so
* low values are far shorter than a linear reading suggests. Calibrated against Logic reference
* instruments (parameter 19 = 5 ms, 27 = 20 ms, 53 = 303 ms, 71 = 977 ms, 94 = 3 s, 127 = 10 s),
* which fit seconds = 10 * (parameter / 127)^4 to within 1 percent. Reading these times linearly
* made e.g. a 7.5 ms attack come out as 1.65 seconds, so the note faded in too slowly to be
* heard.
*
* @param parameter The raw envelope time parameter (0..127), or null when not present
* @return The time in seconds
*/
private static double envelopeTimeToSeconds (final Integer parameter)
{
if (parameter == null)
return 0;
final double normalized = parameter.doubleValue () / 127.0;
return 10.0 * normalized * normalized * normalized * normalized;
}


private static void applyFilterParameters (final IMultisampleSource multisampleSource, final EXS24Parameters parameters)
{
final Integer isFilterEnabled = parameters.get (EXS24Parameters.FILTER1_TOGGLE);
Expand Down