Skip to content

Commit

Permalink
Moved RIAA based de-emphasis from being pre-applied in RAM to being a…
Browse files Browse the repository at this point in the history
…pplied during playback

 - This fixes most of the clicking sound heard on looping samples
 - Slightly increases the CPU load
 - The TVF (filter) have to be temporarily disabled until improved due to sound artifacts on certain instruments
  • Loading branch information
skjelten committed Nov 14, 2023
1 parent 8476a65 commit 0d3f7b1
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 105 deletions.
211 changes: 114 additions & 97 deletions libemusc/src/partial.cc
Expand Up @@ -55,10 +55,14 @@ Partial::Partial(uint8_t key, int partialId, uint16_t instrumentIndex,
_instPartial(ctrlRom.instrument(instrumentIndex).partials[partialId]),
_index(0),
_direction(1),
_sample(0),
_settings(settings),
_partId(partId),
_keyFreq(440 * exp(log(2) * (key - 69) / 12)),
_expFactor(log(2) / 12000),
_lastPos(0),
_rf1(32000, 15),
_rf2(32000, 15),
_tvp(NULL),
_tvf(NULL),
_tva(NULL)
Expand Down Expand Up @@ -139,12 +143,6 @@ Partial::~Partial()
}


double Partial::_convert_volume(uint8_t volume)
{
return (0.1 * pow(2.0, (double)(volume) / 36.7111) - 0.1);
}


void Partial::stop(void)
{
// Ignore note off for uninterruptible drums (set by drum set flag)
Expand All @@ -161,8 +159,6 @@ void Partial::stop(void)
// Pitch < 0 => fixed pitch (e.g. for drums)
bool Partial::get_next_sample(float *noteSample)
{
int nextIndex;

// Terminate this partial if its TVA envelope is finished
if (_tva->finished())
return 1;
Expand All @@ -183,96 +179,11 @@ bool Partial::get_next_sample(float *noteSample)
_staticPitchTune *
_tvp->get_pitch();

// Update sample position going in forward direction
if (_direction == 1) {
if (0)
std::cout << "-> FW " << std::dec << "pos=" << (int)_index
<< " PitchAdj=" << pitchAdj
<< " newPos=" << _index + pitchAdj
<< " sLength=" << (int) _ctrlSample->sampleLen
<< " lpMode=" << (int) _ctrlSample->loopMode
<< " lpLength=" << _ctrlSample->loopLen
<< std::endl;

// Update partial sample position based on pitch input
// FIXME: Should drumsets be modified by pitch bend messages?
_index += pitchAdj;

// Check for sample position passing sample boundary
if (_index > _ctrlSample->sampleLen - 1) { // -1 due to lin. interpol.
// Keep track of correct sample index when switching sample direction
float remaining = abs(_ctrlSample->sampleLen - _index);

// loopMode == 0 => Forward only w/loop (jump back "loopLen + 1")
if (_ctrlSample->loopMode == 0) {
_index = _ctrlSample->sampleLen - _ctrlSample->loopLen - 1 + remaining;

// loopMode == 1 => Forward-backward (start moving backwards)
} else if (_ctrlSample->loopMode == 1) {
_index = _ctrlSample->sampleLen - remaining - 1;
_direction = 0;

// loopMode == 2 => Forward-stop (end playback)
} else if (_ctrlSample->loopMode == 2) {
return 1; // Terminate this partial
}
}

// Find next index for linear interpolation and adjust if at end of sample
nextIndex = (int) _index + 1;
if (nextIndex >= _ctrlSample->sampleLen) {
if (_ctrlSample->loopMode == 0)
nextIndex = _ctrlSample->sampleLen - _ctrlSample->loopLen - 1;
else if (_ctrlSample->loopMode == 1)
nextIndex = _ctrlSample->sampleLen - 1;
else if (_ctrlSample->loopMode == 2)
nextIndex = _ctrlSample->sampleLen;
}

// Update sample position going in backward direction
} else { // => _direction == 0
if (0)
std::cout << "<- BW " << std::dec << "pos=" << (int) _index
<< " length=" << (int) _ctrlSample->sampleLen
<< std::endl;

// Update partial sample position based on pitch input
_index -= pitchAdj;

// Check for sample position passing sample boundary
if (_index < _ctrlSample->sampleLen - _ctrlSample->loopLen - 1) {

// Keep track of correct position switching position
float remaining = _ctrlSample->sampleLen - _ctrlSample->loopLen -1-_index;

// Start moving forward
_index = _ctrlSample->sampleLen - _ctrlSample->loopLen - 1 + remaining;
_direction = 1;
}

// Find next index for linear interpolation and adjust if at start of sample
nextIndex = (int) _index - 1;
if (nextIndex < _ctrlSample->sampleLen - _ctrlSample->loopLen - 1)
nextIndex = _ctrlSample->sampleLen - _ctrlSample->loopLen - 1;
}
if (_next_sample_from_rom(pitchAdj))
return 1;

// Temporary samples for LEFT, RIGHT channel
double sample[2] = {0, 0};

// Calculate linear interpolation of PCM sample
/* double fractionNext;
double fractionPrev;
if (_direction) { // Moving forward in sample
fractionNext = _index - ((int) _index);
fractionPrev = 1.0 - fractionNext;
} else { // Moving backwards
fractionPrev = _index - ((int) _index);
fractionNext = 1.0 - fractionPrev;
}
sample[0] = fractionPrev * _pcmSamples->at((int) _index) +
fractionNext * _pcmSamples->at(nextIndex);
*/
sample[0] = _pcmSamples->at((int) _index);
sample[0] = _sample;

// Calculate volume correction from sample definition (7f - 0)
double sampleVol = _convert_volume(_ctrlSample->volume +
Expand All @@ -291,7 +202,8 @@ bool Partial::get_next_sample(float *noteSample)
sample[0] *= sampleVol * partialVol * drumVol;

// Apply TVF
sample[0] = _tvf->apply(sample[0]);
// NOTE: TEMPORARILY DISABLED
// sample[0] = _tvf->apply(sample[0]);

// Apply TVA
sample[0] *= _tva->get_amplification();
Expand All @@ -318,4 +230,109 @@ bool Partial::get_next_sample(float *noteSample)
return 0;
}


bool Partial::_next_sample_from_rom(float pitchAdj)
{
if (_direction == 1) { // Update sample position going in forward direction
if (0)
std::cout << "-> FW " << std::dec << "pos=" << (int) _index
<< " pa=" << pitchAdj
<< " np=" << _index + pitchAdj
<< " sl=" << (int) _ctrlSample->sampleLen
<< " lm=" << (int) _ctrlSample->loopMode
<< " ll=" << _ctrlSample->loopLen
<< " lp=" << _lastPos
<< std::endl;

_index += pitchAdj;

while (roundf(_index) > _lastPos && _lastPos < _ctrlSample->sampleLen - 1) {
_sample = _rf1.apply(_pcmSamples->at(_lastPos++));
_sample = _rf2.apply(_sample);
}

// Check for sample position passing sample boundary
if (_index > _ctrlSample->sampleLen - 1) { // -1 due to lin. interpol.
// Keep track of correct sample index when switching sample direction
float remaining = abs(_ctrlSample->sampleLen - _index);

// loopMode == 0 => Forward only w/loop (jump back "loopLen + 1")
if (_ctrlSample->loopMode == 0) {
_index = _ctrlSample->sampleLen - _ctrlSample->loopLen - 1 + remaining;
_lastPos = _ctrlSample->sampleLen - _ctrlSample->loopLen - 1;

// Filter any remainging samples
while (roundf(_index) > _lastPos) {
_sample = _rf1.apply(_pcmSamples->at(_lastPos++));
_sample = _rf2.apply(_sample);
}

// loopMode == 1 => Forward-backward (start moving backwards)
} else if (_ctrlSample->loopMode == 1) {
_index = _ctrlSample->sampleLen - remaining - 1;
_direction = 0;

// Filter any remainging samples
while (roundf(_index) < _lastPos) {
_sample = _rf1.apply(_pcmSamples->at(_lastPos--));
_sample = _rf2.apply(_sample);
}

// loopMode == 2 => Forward-stop (end playback)
} else if (_ctrlSample->loopMode == 2) {
return 1; // Terminate this partial
}
}

} else { // Update sample position going in backward direction
if (0)
std::cout << "<- BW " << std::dec << "pos=" << (int) _index
<< " sl=" << (int) _ctrlSample->sampleLen
<< " ll=" << _ctrlSample->loopLen
<< " lp=" << _lastPos
<< std::endl;

// Update partial sample position based on pitch input
_index -= pitchAdj;

while (roundf(_index) < _lastPos &&
_lastPos > _ctrlSample->sampleLen - _ctrlSample->loopLen) {
_sample = _rf1.apply(_pcmSamples->at(_lastPos--));
_sample = _rf2.apply(_sample);
}

// Check for sample position passing sample boundary
if (_index < _ctrlSample->sampleLen - _ctrlSample->loopLen - 1) {

// Filter any remainging samples backward
while (_lastPos > _ctrlSample->sampleLen - _ctrlSample->loopLen - 1) {
_sample = _rf1.apply(_pcmSamples->at(_lastPos--));
_sample = _rf2.apply(_sample);
}

// Keep track of correct position switching position
float remaining = _ctrlSample->sampleLen - _ctrlSample->loopLen - _index;

// Start moving forward
_index = _ctrlSample->sampleLen - _ctrlSample->loopLen + remaining;
_direction = 1;

// Filter any remainging samples forward
_lastPos = _ctrlSample->sampleLen - _ctrlSample->loopLen;
while (roundf(_index) < _lastPos) {
_sample = _rf1.apply(_pcmSamples->at(_lastPos++));
_sample = _rf2.apply(_sample);
}
}
}

return 0;
}


double Partial::_convert_volume(uint8_t volume)
{
return (0.1 * pow(2.0, (double)(volume) / 36.7111) - 0.1);
}

}
10 changes: 9 additions & 1 deletion libemusc/src/partial.h
Expand Up @@ -22,6 +22,7 @@


#include "control_rom.h"
#include "riaa_filter.h"
#include "pcm_rom.h"
#include "settings.h"
#include "tva.h"
Expand All @@ -47,12 +48,13 @@ class Partial

std::vector<float> *_pcmSamples;

unsigned int _lastPos; // Last read sample position
float _index; // Sample position in number of samples from start
bool _direction; // Sample read direction: 0 = backward & 1 = foreward

float _expFactor; // log(2) / 12000

float _staticPitchTune;
float _staticPitchTune;

Settings *_settings;
int8_t _partId;
Expand All @@ -64,6 +66,12 @@ class Partial
TVF *_tvf;
TVA *_tva;

RiaaFilter _rf1;
RiaaFilter _rf2;

double _sample;

bool _next_sample_from_rom(float pitchAdj);
double _convert_volume(uint8_t volume);

public:
Expand Down
8 changes: 1 addition & 7 deletions libemusc/src/pcm_rom.cc
Expand Up @@ -21,7 +21,6 @@


#include "pcm_rom.h"
#include "riaa_filter.h"

#include <cmath>
#include <fstream>
Expand Down Expand Up @@ -138,9 +137,6 @@ uint32_t PcmRom::_find_samples_rom_address(uint32_t address)

int PcmRom::_read_samples(std::vector<char> &romData, struct ControlRom::Sample &ctrlSample)
{
RiaaFilter rf1(32000, 15); // Gain 28 seems right, but becomes too much later
RiaaFilter rf2(32000, 15);

uint32_t romAddress = _find_samples_rom_address(ctrlSample.address);

struct Samples s;
Expand All @@ -154,10 +150,8 @@ int PcmRom::_read_samples(std::vector<char> &romData, struct ControlRom::Sample
uint8_t sNibble = (sAddress & 0x10) ? (sByte >> 4 ) : (sByte & 0x0F);
int32_t final = ((data << sNibble) << 14);

// Move to float and apply 2x RIAA deemphasis filters
// Convert to float
float ffinal = (float) final / (1 << 31);
ffinal = rf1.apply(ffinal);
ffinal = rf2.apply(ffinal);

s.samplesF.push_back(ffinal);
}
Expand Down

0 comments on commit 0d3f7b1

Please sign in to comment.