converted internal system to float
This commit is contained in:
+3
-9
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user