converted internal system to float

This commit is contained in:
itsmattkc
2019-04-07 13:37:28 +10:00
parent a2d7025776
commit 644d096f3c
31 changed files with 365 additions and 257 deletions
+3 -9
View File
@@ -678,7 +678,7 @@ void Effect::load_from_string(const QByteArray &s) {
for (int i=0;i<attributes.size();i++) {
const QXmlStreamAttribute& attr = attributes.at(i);
if (attr.name() == "name") {
if (get_meta_from_name(attr.value().toString()) == meta) {
if (Effect::GetMetaFromName(attr.value().toString()) == meta) {
// pass off to standard loading function
load(stream);
} else {
@@ -959,7 +959,7 @@ GLuint Effect::process_superimpose(QOpenGLContext* ctx, double timecode) {
return texture;
}
void Effect::process_audio(double, double, quint8*, int, int) {}
void Effect::process_audio(double, double, float **, int, int, int) {}
void Effect::gizmo_draw(double, GLTextureCoords &) {}
@@ -1140,7 +1140,7 @@ void Effect::delete_texture() {
}
}
const EffectMeta* get_meta_from_name(const QString& input) {
const EffectMeta* Effect::GetMetaFromName(const QString& input) {
int split_index = input.indexOf('/');
QString category;
if (split_index > -1) {
@@ -1157,9 +1157,3 @@ const EffectMeta* get_meta_from_name(const QString& input) {
}
return nullptr;
}
qint16 mix_audio_sample(qint16 a, qint16 b) {
qint32 mixed_sample = static_cast<qint32>(a) + static_cast<qint32>(b);
mixed_sample = qMax(qMin(mixed_sample, static_cast<qint32>(INT16_MAX)), static_cast<qint32>(INT16_MIN));
return static_cast<qint16>(mixed_sample);
}
+11 -5
View File
@@ -126,10 +126,6 @@ struct GLTextureCoords {
float opacity;
};
const EffectMeta* get_meta_from_name(const QString& input);
qint16 mix_audio_sample(qint16 a, qint16 b);
class Effect : public QObject {
Q_OBJECT
public:
@@ -189,7 +185,7 @@ public:
virtual void process_shader(double timecode, GLTextureCoords&, int iteration);
virtual void process_coords(double timecode, GLTextureCoords& coords, int data);
virtual GLuint process_superimpose(QOpenGLContext *ctx, double timecode);
virtual void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
virtual void process_audio(double timecode_start, double timecode_end, float **samples, int nb_samples, int nb_channels, int type);
virtual void gizmo_draw(double timecode, GLTextureCoords& coords);
void gizmo_move(EffectGizmo* sender, int x_movement, int y_movement, double timecode, bool done);
@@ -205,8 +201,18 @@ public:
return distribution(generator);
}
template <typename T>
T randomFloat()
{
static std::random_device device;
static std::mt19937 generator(device());
static std::uniform_int_distribution<> distribution(-1.0, 1.0);
return distribution(generator);
}
static EffectPtr Create(Clip *c, const EffectMeta *em);
static const EffectMeta* GetInternalMeta(int internal_id, int type);
static const EffectMeta* GetMetaFromName(const QString& input);
public slots:
void FieldChanged();
void SetEnabled(bool b);
+19 -20
View File
@@ -35,30 +35,29 @@ AudioNoiseEffect::AudioNoiseEffect(Clip* c, const EffectMeta *em) : Effect(c, em
mix_val->SetValueAt(0, true);
}
void AudioNoiseEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int) {
double interval = (timecode_end - timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=4) {
void AudioNoiseEffect::process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) {
double interval = (timecode_end - timecode_start)/nb_samples;
for (int i=0;i<nb_samples;i+=4) {
double timecode = timecode_start+(interval*i);
qint16 left_noise_sample = this->randomNumber<qint16>();
qint16 right_noise_sample = this->randomNumber<qint16>();
// set noise volume
double vol = log_volume( amount_val->GetDoubleAt(timecode)*0.01 );
left_noise_sample *= vol;
right_noise_sample *= vol;
float vol = log_volume( amount_val->GetDoubleAt(timecode)*0.01 );
// mix with source audio
if (mix_val->GetBoolAt(timecode)) {
qint16 left_sample = static_cast<qint16> (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
qint16 right_sample = static_cast<qint16> (((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF));
left_noise_sample = mix_audio_sample(left_noise_sample, left_sample);
right_noise_sample = mix_audio_sample(right_noise_sample, right_sample);
for (int j=0;j<channel_count;j++) {
// Generate noise sample
float noise_sample = this->randomFloat<float>() * vol;
// mix with source audio
if (mix_val->GetBoolAt(timecode)) {
samples[j][i] += noise_sample;
} else {
samples[j][i] = noise_sample;
}
}
samples[i+3] = static_cast<quint8> (right_noise_sample >> 8);
samples[i+2] = static_cast<quint8> (right_noise_sample);
samples[i+1] = static_cast<quint8> (left_noise_sample >> 8);
samples[i] = static_cast<quint8> (left_noise_sample);
}
}
+6 -1
View File
@@ -27,7 +27,12 @@ class AudioNoiseEffect : public Effect {
Q_OBJECT
public:
AudioNoiseEffect(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) override;
DoubleField* amount_val;
BoolField* mix_val;
+1 -1
View File
@@ -26,7 +26,7 @@
class CornerPinEffect : public Effect {
Q_OBJECT
public:
CornerPinEffect(Clip* c, const EffectMeta* em);
CornerPinEffect(Clip* c, const EffectMeta* em);
void process_coords(double timecode, GLTextureCoords& coords, int data);
void process_shader(double timecode, GLTextureCoords& coords, int iterations);
void gizmo_draw(double timecode, GLTextureCoords& coords);
+2 -2
View File
@@ -25,8 +25,8 @@
class CrossDissolveTransition : public Transition {
public:
CrossDissolveTransition(Clip *c, Clip *s, const EffectMeta* em);
void process_coords(double timecode, GLTextureCoords &, int data);
CrossDissolveTransition(Clip *c, Clip *s, const EffectMeta* em);
void process_coords(double timecode, GLTextureCoords &, int data);
};
#endif // CROSSDISSOLVETRANSITION_H
+2 -2
View File
@@ -25,8 +25,8 @@
class CubeTransition : public Transition {
public:
CubeTransition(Clip* c, Clip* s, const EffectMeta* em);
void process_coords(double timecode, GLTextureCoords &, int data);
CubeTransition(Clip* c, Clip* s, const EffectMeta* em);
void process_coords(double timecode, GLTextureCoords &, int data);
};
#endif // CUBETRANSITION_H
+19 -24
View File
@@ -24,32 +24,27 @@
ExponentialFadeTransition::ExponentialFadeTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) {}
void ExponentialFadeTransition::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int type) {
double interval = (timecode_end-timecode_start)/nb_bytes;
void ExponentialFadeTransition::process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) {
double interval = (timecode_end-timecode_start)/nb_samples;
for (int i=0;i<nb_bytes;i+=2) {
qint16 samp = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
for (int i=0;i<nb_samples;i++) {
/*switch (type) {
case TRAN_TYPE_OPEN:
case TRAN_TYPE_OPENWLINK:
samp *= qSqrt(timecode_start + (interval * i));
break;
case TRAN_TYPE_CLOSE:
case TRAN_TYPE_CLOSEWLINK:
samp *= qSqrt(1 - (timecode_start + (interval * i)));
break;
}*/
switch (type) {
case kTransitionOpening:
samp *= qPow(timecode_start + (interval * i), 2);
break;
case kTransitionClosing:
samp *= qPow(1 - (timecode_start + (interval * i)), 2);
break;
double multi = timecode_start + (interval * i);
for (int j=0;j<channel_count;j++) {
switch (type) {
case kTransitionOpening:
samples[j][i] *= qPow(multi, 2);
break;
case kTransitionClosing:
samples[j][i] *= qPow(1.0 - multi, 2);
break;
}
}
samples[i+1] = (quint8) (samp >> 8);
samples[i] = (quint8) samp;
}
}
+7 -2
View File
@@ -25,8 +25,13 @@
class ExponentialFadeTransition : public Transition {
public:
ExponentialFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
ExponentialFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) override;
};
#endif // LINEARFADETRANSITION_H
+8 -3
View File
@@ -30,9 +30,14 @@ FillLeftRightEffect::FillLeftRightEffect(Clip* c, const EffectMeta *em) : Effect
fill_type->AddItem(tr("Fill Right with Left"), FILL_TYPE_RIGHT);
}
void FillLeftRightEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) {
double interval = (timecode_end-timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=4) {
void FillLeftRightEffect::process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) {
double interval = (timecode_end-timecode_start)/nb_samples;
for (int i=0;i<nb_samples;i+=4) {
if (fill_type->GetValueAt(timecode_start+(interval*i)) == FILL_TYPE_LEFT) {
samples[i+1] = samples[i+3];
samples[i] = samples[i+2];
+6 -1
View File
@@ -27,7 +27,12 @@ class FillLeftRightEffect : public Effect {
Q_OBJECT
public:
FillLeftRightEffect(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) override;
private:
ComboField* fill_type;
};
+20 -14
View File
@@ -22,22 +22,28 @@
LinearFadeTransition::LinearFadeTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) {}
void LinearFadeTransition::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int type) {
double interval = (timecode_end-timecode_start)/nb_bytes;
void LinearFadeTransition::process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) {
double interval = (timecode_end-timecode_start)/nb_samples;
for (int i=0;i<nb_bytes;i+=2) {
qint16 samp = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
for (int i=0;i<nb_samples;i++) {
switch (type) {
case kTransitionOpening:
samp *= timecode_start + (interval * i);
break;
case kTransitionClosing:
samp *= 1 - (timecode_start + (interval * i));
break;
float multi = timecode_start + (interval * i);
for (int j=0;j<channel_count;j++) {
switch (type) {
case kTransitionOpening:
samples[j][i] *= multi;
break;
case kTransitionClosing:
samples[j][i] *= 1.0f - multi;
break;
}
}
samples[i+1] = (quint8) (samp >> 8);
samples[i] = (quint8) samp;
}
}
+7 -2
View File
@@ -25,8 +25,13 @@
class LinearFadeTransition : public Transition {
public:
LinearFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
LinearFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) override;
};
#endif // LINEARFADETRANSITION_H
+19 -14
View File
@@ -24,22 +24,27 @@
LogarithmicFadeTransition::LogarithmicFadeTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) {}
void LogarithmicFadeTransition::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int type) {
double interval = (timecode_end-timecode_start)/nb_bytes;
void LogarithmicFadeTransition::process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) {
double interval = (timecode_end-timecode_start)/nb_samples;
for (int i=0;i<nb_bytes;i+=2) {
qint16 samp = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
for (int i=0;i<nb_samples;i++) {
switch (type) {
case kTransitionOpening:
samp *= qSqrt(timecode_start + (interval * i));
break;
case kTransitionClosing:
samp *= qSqrt(1 - (timecode_start + (interval * i)));
break;
float multi = timecode_start + (interval * i);
for (int j=0;j<channel_count;j++) {
switch (type) {
case kTransitionOpening:
samples[j][i] *= qSqrt(multi);
break;
case kTransitionClosing:
samples[j][i] *= qSqrt(1.0f - multi);
break;
}
}
samples[i+1] = (quint8) (samp >> 8);
samples[i] = (quint8) samp;
}
}
+7 -2
View File
@@ -25,8 +25,13 @@
class LogarithmicFadeTransition : public Transition {
public:
LogarithmicFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
LogarithmicFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) override;
};
#endif // LOGARITHMICFADETRANSITION_H
+17 -13
View File
@@ -36,26 +36,30 @@ PanEffect::PanEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
pan_val->SetMaximum(100);
}
void PanEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) {
double interval = (timecode_end - timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=4) {
void PanEffect::process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) {
// This has no effect on mono sources
if (channel_count < 2) {
return;
}
double interval = (timecode_end - timecode_start)/nb_samples;
for (int i=0;i<nb_samples;i++) {
double pan_field_val = pan_val->GetDoubleAt(timecode_start+(interval*i));
double pval = log_volume(qAbs(pan_field_val)*0.01);
qint16 left_sample = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
qint16 right_sample = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF));
if (pan_field_val < 0) {
// affect right channel
right_sample *= (1.0-pval);
samples[1][i] *= (1.0-pval);
} else {
// affect left channel
left_sample *= (1.0-pval);
samples[0][i] *= (1.0-pval);
}
samples[i+3] = quint8(right_sample >> 8);
samples[i+2] = quint8(right_sample);
samples[i+1] = quint8(left_sample >> 8);
samples[i] = quint8(left_sample);
}
}
+6 -1
View File
@@ -27,7 +27,12 @@ class PanEffect : public Effect {
Q_OBJECT
public:
PanEffect(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) override;
DoubleField* pan_val;
};
+1 -1
View File
@@ -27,7 +27,7 @@ class RichTextEffect : public Effect {
Q_OBJECT
public:
RichTextEffect(Clip* c, const EffectMeta *em);
void redraw(double timecode);
virtual void redraw(double timecode) override;
protected:
virtual bool AlwaysUpdate() override;
private:
+2 -2
View File
@@ -28,8 +28,8 @@
class ShakeEffect : public Effect {
Q_OBJECT
public:
ShakeEffect(Clip* c, const EffectMeta* em);
void process_coords(double timecode, GLTextureCoords& coords, int data);
ShakeEffect(Clip* c, const EffectMeta* em);
virtual void process_coords(double timecode, GLTextureCoords& coords, int data) override;
DoubleField* intensity_val;
DoubleField* rotation_val;
+1 -1
View File
@@ -35,7 +35,7 @@ public:
};
SolidEffect(Clip* c, const EffectMeta *em);
virtual void redraw(double timecode);
virtual void redraw(double timecode) override;
void SetType(SolidType type);
private slots:
+1 -1
View File
@@ -30,7 +30,7 @@ class TextEffect : public Effect {
Q_OBJECT
public:
TextEffect(Clip* c, const EffectMeta *em);
void redraw(double timecode);
virtual void redraw(double timecode) override;
private slots:
void outline_enable(bool);
void shadow_enable(bool);
+1 -1
View File
@@ -30,7 +30,7 @@ class TimecodeEffect : public Effect {
Q_OBJECT
public:
TimecodeEffect(Clip* c, const EffectMeta *em);
void redraw(double timecode);
virtual void redraw(double timecode) override;
DoubleField* scale_val;
ColorField* color_val;
ColorField* color_bg_val;
+26 -18
View File
@@ -49,29 +49,37 @@ ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_
mix_val->SetValueAt(0, true);
}
void ToneEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int) {
double interval = (timecode_end - timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=4) {
void ToneEffect::process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) {
double interval = (timecode_end - timecode_start)/nb_samples;
for (int i=0;i<nb_samples;i++) {
double timecode = timecode_start+(interval*i);
float tone_sample = qSin((2*M_PI*sinX*freq_val->GetDoubleAt(timecode))
/parent_clip->track()->sequence()->audio_frequency)
*log_volume(amount_val->GetDoubleAt(timecode)*0.01);
qint16 left_tone_sample = qint16(qRound(qSin((2*M_PI*sinX*freq_val->GetDoubleAt(timecode))
/parent_clip->track()->sequence()->audio_frequency)
*log_volume(amount_val->GetDoubleAt(timecode)*0.01)*INT16_MAX));
qint16 right_tone_sample = left_tone_sample;
for (int j=0;j<channel_count;j++) {
if (mix_val->GetBoolAt(timecode)) {
// mix with source audio
samples[j][i] += tone_sample;
} else {
// replace source audio
samples[j][i] = tone_sample;
}
// mix with source audio
if (mix_val->GetBoolAt(timecode)) {
qint16 left_sample = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
qint16 right_sample = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF));
left_tone_sample = mix_audio_sample(left_tone_sample, left_sample);
right_tone_sample = mix_audio_sample(right_tone_sample, right_sample);
}
samples[i+3] = quint8(right_tone_sample >> 8);
samples[i+2] = quint8(right_tone_sample);
samples[i+1] = quint8(left_tone_sample >> 8);
samples[i] = quint8(left_tone_sample);
sinX++;
}
}
+6 -1
View File
@@ -27,7 +27,12 @@ class ToneEffect : public Effect {
Q_OBJECT
public:
ToneEffect(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) override;
ComboField* type_val;
DoubleField* freq_val;
+3 -3
View File
@@ -27,10 +27,10 @@ class TransformEffect : public Effect {
Q_OBJECT
public:
TransformEffect(Clip* c, const EffectMeta* em);
void refresh();
void process_coords(double timecode, GLTextureCoords& coords, int data);
virtual void refresh() override;
virtual void process_coords(double timecode, GLTextureCoords& coords, int data) override;
void gizmo_draw(double timecode, GLTextureCoords& coords);
virtual void gizmo_draw(double timecode, GLTextureCoords& coords) override;
public slots:
void toggle_uniform_scale(bool enabled);
private:
+12 -22
View File
@@ -37,32 +37,22 @@ VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
volume_val->SetDisplayType(LabelSlider::Decibel);
}
void VolumeEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) {
double interval = (timecode_end-timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=4) {
void VolumeEffect::process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) {
double interval = (timecode_end-timecode_start)/nb_samples;
for (int i=0;i<nb_samples;i++) {
double vol_val = volume_val->GetDoubleAt(timecode_start+(interval*i));
qint32 right_samp = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF));
qint32 left_samp = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
for (int j=0;j<channel_count;j++) {
left_samp *= vol_val;
right_samp *= vol_val;
samples[j][i] *= vol_val;
if (left_samp > INT16_MAX) {
left_samp = INT16_MAX;
} else if (left_samp < INT16_MIN) {
left_samp = INT16_MIN;
}
if (right_samp > INT16_MAX) {
right_samp = INT16_MAX;
} else if (right_samp < INT16_MIN) {
right_samp = INT16_MIN;
}
samples[i+3] = (quint8) (right_samp >> 8);
samples[i+2] = (quint8) right_samp;
samples[i+1] = (quint8) (left_samp >> 8);
samples[i] = (quint8) left_samp;
}
}
+6 -1
View File
@@ -27,7 +27,12 @@ class VolumeEffect : public Effect {
Q_OBJECT
public:
VolumeEffect(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) override;
DoubleField* volume_val;
};
+73 -49
View File
@@ -46,7 +46,6 @@ class NSWindow;
#endif
#define BLOCK_SIZE 512
#define CHANNEL_COUNT 2
struct VSTRect {
int16_t top;
@@ -212,15 +211,6 @@ bool VSTHost::canPluginDo(char *canDoString) {
return (dispatcher(plugin, effCanDo, 0, 0, static_cast<void*>(canDoString), 0.0f) > 0);
}
void VSTHost::processAudio(long numFrames) {
// Always reset the output array before processing.
for (int i=0;i<CHANNEL_COUNT;i++) {
memset(outputs[i], 0, BLOCK_SIZE*sizeof(float));
}
plugin->processReplacing(plugin, inputs, outputs, numFrames);
}
void VSTHost::CreateDialogIfNull()
{
if (dialog == nullptr) {
@@ -240,17 +230,12 @@ void VSTHost::send_data_cache_to_plugin()
VSTHost::VSTHost(Clip* c, const EffectMeta *em) :
Effect(c, em),
plugin(nullptr),
dialog(nullptr)
dialog(nullptr),
input_cache(BLOCK_SIZE),
output_cache(BLOCK_SIZE)
{
plugin = nullptr;
inputs = new float* [CHANNEL_COUNT];
outputs = new float* [CHANNEL_COUNT];
for(int channel = 0; channel < CHANNEL_COUNT; channel++) {
inputs[channel] = new float[BLOCK_SIZE];
outputs[channel] = new float[BLOCK_SIZE];
}
EffectRow* file_row = new EffectRow(this, tr("Plugin"), true, false);
file_field = new FileField(file_row, "filename");
connect(file_field, SIGNAL(Changed()), this, SLOT(change_plugin()), Qt::QueuedConnection);
@@ -264,47 +249,35 @@ VSTHost::VSTHost(Clip* c, const EffectMeta *em) :
}
VSTHost::~VSTHost() {
for(int channel = 0; channel < CHANNEL_COUNT; channel++) {
delete [] inputs[channel];
delete [] outputs[channel];
}
delete [] outputs;
delete [] inputs;
freePlugin();
}
void VSTHost::process_audio(double, double, quint8* samples, int nb_bytes, int) {
void VSTHost::process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) {
if (plugin != nullptr) {
int interval = BLOCK_SIZE*4;
for (int i=0;i<nb_bytes;i+=interval) {
int process_size = qMin(interval, nb_bytes - i);
int lim = i + process_size;
// convert to float
for (int j=i;j<lim;j+=4) {
qint16 left_sample = qint16(((samples[j+1] & 0xFF) << 8) | (samples[j] & 0xFF));
qint16 right_sample = qint16(((samples[j+3] & 0xFF) << 8) | (samples[j+2] & 0xFF));
// Make copy of audio
input_cache.Create(channel_count);
output_cache.Create(channel_count);
int index = (j-i)>>2;
inputs[0][index] = float(left_sample) / float(INT16_MAX);
inputs[1][index] = float(right_sample) / float(INT16_MAX);
for (int i=0;i<nb_samples;i+=BLOCK_SIZE) {
int sample_size = qMin(BLOCK_SIZE, nb_samples - i);
// Copy samples to input cache
for (int j=0;j<channel_count;j++) {
memcpy(input_cache.data()[j], &samples[j][i], nb_samples * sizeof(float));
}
// send to VST
processAudio(process_size>>2);
plugin->processReplacing(plugin, input_cache.data(), output_cache.data(), sample_size);
// convert back to int16
for (int j=i;j<lim;j+=4) {
int index = (j-i)>>2;
qint16 left_sample = qint16(qRound(outputs[0][index] * INT16_MAX));
qint16 right_sample = qint16(qRound(outputs[1][index] * INT16_MAX));
samples[j+3] = quint8(right_sample >> 8);
samples[j+2] = quint8(right_sample);
samples[j+1] = quint8(left_sample >> 8);
samples[j] = quint8(left_sample);
// Copy output cache back to samples
for (int j=0;j<channel_count;j++) {
memcpy(&samples[j][i], output_cache.data()[j], nb_samples * sizeof(float));
}
}
}
@@ -379,3 +352,54 @@ void VSTHost::change_plugin() {
}
show_interface_btn->SetEnabled(plugin != nullptr);
}
SampleCache::SampleCache(int block_size) :
block_size_(block_size),
channel_count_(0),
array_(nullptr)
{
}
SampleCache::~SampleCache()
{
destroy();
}
void SampleCache::Create(int channels)
{
if (channel_count_ != channels) {
if (channel_count_ > 0) {
destroy();
}
channel_count_ = channels;
array_ = new float* [channel_count_];
for (int i=0;i<channel_count_;i++) {
array_[i] = new float[block_size_];
}
}
}
void SampleCache::SetZero()
{
for (int i=0;i<channel_count_;i++) {
memset(array_[i], 0, block_size_ * sizeof(float));
}
}
float **SampleCache::data()
{
return array_;
}
void SampleCache::destroy()
{
for (int i=0;i<channel_count_;i++) {
delete [] array_[i];
}
delete [] array_;
array_ = nullptr;
}
+26 -6
View File
@@ -30,15 +30,36 @@
// Plugin's dispatcher function
typedef intptr_t (*dispatcherFuncPtr)(AEffect *effect, int32_t opCode, int32_t index, int32_t value, void *ptr, float opt);
class SampleCache {
public:
SampleCache(int block_size);
~SampleCache();
void Create(int channels);
void SetZero();
float** data();
private:
int channel_count_;
int block_size_;
float** array_;
void destroy();
};
class VSTHost : public Effect {
Q_OBJECT
public:
VSTHost(Clip* c, const EffectMeta* em);
~VSTHost();
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
int nb_samples,
int channel_count,
int type) override;
void custom_load(QXmlStreamReader& stream);
void save(QXmlStreamWriter& stream);
virtual void custom_load(QXmlStreamReader& stream) override;
virtual void save(QXmlStreamWriter& stream) override;
private slots:
void show_interface(bool show);
void uncheck_show_button();
@@ -57,12 +78,11 @@ private:
void resumePlugin();
void suspendPlugin();
bool canPluginDo(char *canDoString);
void processAudio(long numFrames);
void CreateDialogIfNull();
float** inputs;
float** outputs;
QDialog* dialog;
QByteArray data_cache;
SampleCache input_cache;
SampleCache output_cache;
void send_data_cache_to_plugin();