Skip to content

Commit

Permalink
fix #271723: support for opcodes required for percussion library
Browse files Browse the repository at this point in the history
delay, pan (there is a bug - effects are applied despite on pan mixing
channels), offset, group_volume support
  • Loading branch information
anatoly-os committed May 21, 2018
1 parent 344d332 commit 5c7c5f4
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 11 deletions.
33 changes: 32 additions & 1 deletion zerberus/sfz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ struct SfzRegion {
LoopMode loop_mode;
OffMode off_mode;
std::map<int, double> gain_oncc;
float delay; //seconds
int pan; // [-100, 100]
unsigned long offset; // [0, 4Gb) or [0, 4294967295]
float group_volume; // [-144 to 6] (dB)

void init(const QString&);
bool isEmpty() const { return sample.isEmpty(); }
Expand Down Expand Up @@ -150,6 +154,10 @@ void SfzRegion::init(const QString& _path)
use_cc = false;
off_mode = OffMode::FAST;
gain_oncc.clear();
delay = 0.0f;
pan = 0;
offset = 0;
group_volume = 0.0f;
}

//---------------------------------------------------------
Expand All @@ -164,7 +172,7 @@ void SfzRegion::setZone(Zone* z) const
z->veloLo = lovel;
z->veloHi = hivel;
z->keyBase = pitch_keycenter;
z->offset = 0;
z->offset = offset;
z->volume = pow(10.0, volume / 20.0);
z->ampVeltrack = amp_veltrack;
z->ampegAttack = ampeg_attack * 1000;
Expand Down Expand Up @@ -204,6 +212,9 @@ void SfzRegion::setZone(Zone* z) const
z->loopEnd = loopEnd;
z->loopStart = loopStart;
z->gainOnCC = gain_oncc;
z->delay = delay * 1000; //convert seconds from sfz to ms for computations
z->pan = pan;
z->group_volume = pow(10.0, group_volume / 20.0); //dB -> volume multiplier
}

//---------------------------------------------------------
Expand Down Expand Up @@ -278,6 +289,18 @@ void ZInstrument::addRegion(SfzRegion& r)
addZone(z);
}

//---------------------------------------------------------
// readFloat
//---------------------------------------------------------

static void readFloat(const QString& data, float& val)
{
bool ok;
float d = data.toFloat(&ok);
if (ok)
val = d;
}

//---------------------------------------------------------
// readDouble
//---------------------------------------------------------
Expand Down Expand Up @@ -480,6 +503,14 @@ void SfzRegion::readOp(const QString& b, const QString& data, SfzControl &c)
seq_position = i;
else if (opcode == "transpose")
transpose = i;
else if (opcode == "delay")
readFloat(opcode_data, delay);
else if (opcode == "pan")
pan = i;
else if (opcode == "offset")
offset = opcode_data.toULong();
else if (opcode == "group_volume")
readFloat(opcode_data, group_volume);
else
qDebug("SfzRegion: unknown opcode <%s>", qPrintable(opcode));
}
Expand Down
26 changes: 17 additions & 9 deletions zerberus/voice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ void Voice::start(Channel* c, int key, int v, const Zone* zone, double durSinceN
Sample* s = z->sample;
audioChan = s->channel();
data = s->data() + z->offset * audioChan;
eidx = s->frames() * audioChan;
//avoid processing sample if offset is bigger than sample length
eidx = std::max((s->frames() - long(z->offset) - 1) * audioChan, long(0));
_loopMode = z->loopMode;
_loopStart = z->loopStart;
_loopEnd = z->loopEnd;
Expand All @@ -134,7 +135,7 @@ void Voice::start(Channel* c, int key, int v, const Zone* zone, double durSinceN
// -> afterwards 0.5 (-6dB) is applied to compensate possible coherent
// signals in a stereo output see http://www.sengpielaudio.com/calculator-coherentsources.htm
// -> 0.005 = 0.01 * 0.5
gain = z->volume * (offset + z->ampVeltrack * curve)
gain = (z->volume * z->group_volume) * (offset + z->ampVeltrack * curve)
* .005 * c->gain() * rt_decay_value;

phase.set(0);
Expand Down Expand Up @@ -166,7 +167,7 @@ void Voice::start(Channel* c, int key, int v, const Zone* zone, double durSinceN
float velPercent = _velocity / 127.0;

envelopes[V1Envelopes::DELAY].setTable(Envelope::egLin);
envelopes[V1Envelopes::DELAY].setTime(z->ampegDelay + (z->ampegVel2Delay * velPercent), _zerberus->sampleRate());
envelopes[V1Envelopes::DELAY].setTime(z->ampegDelay + (z->ampegVel2Delay * velPercent) + z->delay, _zerberus->sampleRate());
envelopes[V1Envelopes::DELAY].setConstant(0.0);

envelopes[V1Envelopes::ATTACK].setTable(Envelope::egLin);
Expand Down Expand Up @@ -325,6 +326,8 @@ void Voice::process(int frames, float* p)
last_fres = _fres;
}

const float opcodePanLeftGain = 1.f - std::fmax(0.0f, z->pan / 100.0); //[0, 1]
const float opcodePanRightGain = 1.f + std::fmin(0.0f, z->pan / 100.0); //[0, 1]
if (audioChan == 1) {
while (frames--) {

Expand Down Expand Up @@ -361,9 +364,11 @@ void Voice::process(int frames, float* p)
break;
v *= envelopes[currentEnvelope].val * z->ccGain;

*p++ += v * _channel->panLeftGain();
*p++ += v * _channel->panRightGain();
phase += phaseIncr;
*p++ += v * _channel->panLeftGain() * opcodePanLeftGain;
*p++ += v * _channel->panRightGain() * opcodePanRightGain;
if (V1Envelopes::DELAY != currentEnvelope)
phase += phaseIncr;

_samplesSinceStart++;
}
}
Expand Down Expand Up @@ -422,9 +427,12 @@ void Voice::process(int frames, float* p)
b1 += b1_incr;
}

*p++ += vl;
*p++ += vr;
phase += phaseIncr;
*p++ += vl * opcodePanLeftGain;
*p++ += vr * opcodePanRightGain;

if (V1Envelopes::DELAY != currentEnvelope)
phase += phaseIncr;

_samplesSinceStart++;
}
}
Expand Down
5 changes: 4 additions & 1 deletion zerberus/zone.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ enum class OffMode : char {

struct Zone {
Sample* sample = 0;
int offset = 0;
unsigned long offset = 0; //[0, 4294967295]
int seq = 0;
int seqLen = 0;
int seqPos = 0;
Expand Down Expand Up @@ -76,6 +76,9 @@ struct Zone {
float ampegVel2Sustain = 0.0;
float ampegVel2Release = 0.0;
float rtDecay = 0.0;
float delay = 0.0;
int pan = 0;
float group_volume = 1.0;

Trigger trigger = Trigger::ATTACK;
LoopMode loopMode = LoopMode::NO_LOOP;
Expand Down

0 comments on commit 5c7c5f4

Please sign in to comment.