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();
+1 -1
View File
@@ -120,7 +120,7 @@ void LoadThread::load_effect(QXmlStreamReader& stream, Clip* c) {
// find effect with this name
if (!effect_name.isEmpty()) {
meta = get_meta_from_name(effect_name);
meta = Effect::GetMetaFromName(effect_name);
}
olive::effects_loaded.unlock();
+46 -34
View File
@@ -46,21 +46,25 @@
// Enable verbose audio messages - good for debugging reversed audio
//#define AUDIOWARNINGS
const AVSampleFormat kDestSampleFmt = AV_SAMPLE_FMT_S16;
const AVSampleFormat kDestSampleFmt = AV_SAMPLE_FMT_FLTP;
double bytes_to_seconds(int nb_bytes, int nb_channels, int sample_rate) {
return (double(nb_bytes >> 1) / nb_channels / sample_rate);
double samples_to_seconds(int nb_samples, int nb_channels, int sample_rate) {
return (double(nb_samples) / double(nb_channels) / double(sample_rate));
}
void apply_audio_effects(Clip* clip, double timecode_start, AVFrame* frame, int nb_bytes, QVector<Clip*> nests) {
int samples_to_bytes(int nb_samples, int nb_channels) {
return nb_samples * nb_channels * sizeof(float);
}
void apply_audio_effects(Clip* clip, double timecode_start, AVFrame* frame, int nb_samples, int nb_channels, QVector<Clip*> nests) {
// perform all audio effects
double timecode_end;
timecode_end = timecode_start + bytes_to_seconds(nb_bytes, frame->channels, frame->sample_rate);
timecode_end = timecode_start + samples_to_seconds(nb_samples, frame->channels, frame->sample_rate);
for (int j=0;j<clip->effects.size();j++) {
Effect* e = clip->effects.at(j).get();
if (e->IsEnabled()) {
e->process_audio(timecode_start, timecode_end, frame->data[0], nb_bytes, 2);
e->process_audio(timecode_start, timecode_end, reinterpret_cast<float**>(frame->data), nb_samples, nb_channels, kTransitionNone);
}
}
if (clip->opening_transition != nullptr) {
@@ -71,7 +75,7 @@ void apply_audio_effects(Clip* clip, double timecode_start, AVFrame* frame, int
double adjustment = transition_end - transition_start;
double adjusted_range_start = (timecode_start - transition_start) / adjustment;
double adjusted_range_end = (timecode_end - transition_start) / adjustment;
clip->opening_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, kTransitionOpening);
clip->opening_transition->process_audio(adjusted_range_start, adjusted_range_end, reinterpret_cast<float**>(frame->data), nb_samples, nb_channels, kTransitionOpening);
}
}
}
@@ -84,7 +88,7 @@ void apply_audio_effects(Clip* clip, double timecode_start, AVFrame* frame, int
double adjustment = transition_end - transition_start;
double adjusted_range_start = (timecode_start - transition_start) / adjustment;
double adjusted_range_end = (timecode_end - transition_start) / adjustment;
clip->closing_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, kTransitionClosing);
clip->closing_transition->process_audio(adjusted_range_start, adjusted_range_end, reinterpret_cast<float**>(frame->data), nb_samples, nb_channels, kTransitionClosing);
}
}
}
@@ -95,7 +99,8 @@ void apply_audio_effects(Clip* clip, double timecode_start, AVFrame* frame, int
apply_audio_effects(next_nest,
timecode_start + (double(clip->timeline_in(true)-clip->clip_in(true))/clip->track()->sequence()->frame_rate),
frame,
nb_bytes,
nb_samples,
nb_channels,
nests);
}
}
@@ -157,16 +162,16 @@ void Cacher::CacheAudioWorker() {
while (true) {
AVFrame* frame;
int nb_bytes = INT_MAX;
int nb_samples = INT_MAX;
if (clip->media() == nullptr) {
frame = frame_;
nb_bytes = frame->nb_samples * av_get_bytes_per_sample(static_cast<AVSampleFormat>(frame->format)) * frame->channels;
while ((frame_sample_index_ == -1 || frame_sample_index_ >= nb_bytes) && nb_bytes > 0) {
nb_samples = frame->nb_samples;
while ((frame_sample_index_ == -1 || frame_sample_index_ >= nb_samples) && nb_samples > 0) {
// create "new frame"
memset(frame_->data[0], 0, nb_bytes);
apply_audio_effects(clip, bytes_to_seconds(frame->pts, frame->channels, frame->sample_rate), frame, nb_bytes, nests_);
frame_->pts += nb_bytes;
memset(frame_->data[0], 0, nb_samples);
apply_audio_effects(clip, samples_to_seconds(frame->pts, frame->channels, frame->sample_rate), frame, nb_samples, frame->channels, nests_);
frame_->pts += nb_samples;
frame_sample_index_ = 0;
if (audio_buffer_write == 0) {
audio_buffer_write = get_buffer_offset_from_frame(last_fr, qMax(timeline_in, target_frame));
@@ -184,7 +189,7 @@ void Cacher::CacheAudioWorker() {
// retrieve frame
bool new_frame = false;
while ((frame_sample_index_ == -1 || frame_sample_index_ >= nb_bytes) && nb_bytes > 0) {
while ((frame_sample_index_ == -1 || frame_sample_index_ >= nb_samples) && nb_samples > 0) {
// no more audio left in frame, get a new one
if (!reached_end) {
@@ -338,10 +343,10 @@ void Cacher::CacheAudioWorker() {
if (frame_sample_index_ < 0) {
frame_sample_index_ = 0;
} else {
frame_sample_index_ -= nb_bytes;
frame_sample_index_ -= nb_samples;
}
nb_bytes = frame->nb_samples * av_get_bytes_per_sample(static_cast<AVSampleFormat>(frame->format)) * frame->channels;
nb_samples = frame->nb_samples;
if (audio_just_reset) {
// get precise sample offset for the elected clip_in from this audio frame
@@ -356,7 +361,7 @@ void Cacher::CacheAudioWorker() {
dout << "fsts:" << frame_sts << "tsts:" << target_sts << "nbs:" << nb_samples << "nbb:" << nb_bytes << "rev_targetToSec:" << (reverse_target * timebase);
dout << "fsi-calc:" << frame_sample_index;
#endif
if (reverse_audio) frame_sample_index_ = nb_bytes - frame_sample_index_;
if (reverse_audio) frame_sample_index_ = nb_samples - frame_sample_index_;
audio_just_reset = false;
}
@@ -393,9 +398,19 @@ void Cacher::CacheAudioWorker() {
#endif
// apply any audio effects to the data
if (nb_bytes == INT_MAX) nb_bytes = frame->nb_samples * av_get_bytes_per_sample(static_cast<AVSampleFormat>(frame->format)) * frame->channels;
if (nb_samples == INT_MAX) {
nb_samples = frame->nb_samples;
}
if (new_frame) {
apply_audio_effects(clip, bytes_to_seconds(audio_buffer_write, 2, current_audio_freq()) + audio_ibuffer_timecode + ((double)clip->clip_in(true)/clip->track()->sequence()->frame_rate) - ((double)timeline_in/last_fr), frame, nb_bytes, nests_);
apply_audio_effects(clip,
samples_to_seconds(audio_buffer_write, 2, current_audio_freq())
+ audio_ibuffer_timecode
+ (double(clip->clip_in(true))/clip->track()->sequence()->frame_rate)
- (double(timeline_in)/last_fr),
frame,
nb_samples,
frame->channels,
nests_);
}
}
@@ -408,23 +423,20 @@ void Cacher::CacheAudioWorker() {
audio_write_lock.lock();
int sample_skip = 4*qMax(0, qAbs(playback_speed_)-1);
int sample_byte_size = av_get_bytes_per_sample(static_cast<AVSampleFormat>(frame->format));
while (frame_sample_index_ < nb_bytes
while (frame_sample_index_ < nb_samples
&& audio_buffer_write < audio_ibuffer_read+(audio_ibuffer_size>>1)
&& audio_buffer_write < buffer_timeline_out) {
for (int i=0;i<frame->channels;i++) {
int upper_byte_index = (audio_buffer_write+1)%audio_ibuffer_size;
int lower_byte_index = (audio_buffer_write)%audio_ibuffer_size;
qint16 old_sample = static_cast<qint16>((audio_ibuffer[upper_byte_index] & 0xFF) << 8 | (audio_ibuffer[lower_byte_index] & 0xFF));
qint16 new_sample = static_cast<qint16>((frame->data[0][frame_sample_index_+1] & 0xFF) << 8 | (frame->data[0][frame_sample_index_] & 0xFF));
qint16 mixed_sample = mix_audio_sample(old_sample, new_sample);
int buffer_index = audio_buffer_write%audio_ibuffer_size;
int frame_index = frame_sample_index_ * sizeof(float);
audio_ibuffer[upper_byte_index] = quint8((mixed_sample >> 8) & 0xFF);
audio_ibuffer[lower_byte_index] = quint8(mixed_sample & 0xFF);
audio_buffer_write+=sample_byte_size;
frame_sample_index_+=sample_byte_size;
audio_ibuffer[buffer_index] += static_cast<float>((frame->data[0][frame_index+3] & 0xFF) << 24
| (frame->data[0][frame_index+2] & 0xFF) << 16
| (frame->data[0][frame_index+1] & 0xFF) << 8
| (frame->data[0][frame_index] & 0xFF));
audio_buffer_write++;
frame_sample_index_++;
}
frame_sample_index_ += sample_skip;
@@ -444,7 +456,7 @@ void Cacher::CacheAudioWorker() {
if (audio_thread != nullptr) audio_thread->notifyReceiver();
}
if (frame_sample_index_ >= nb_bytes) {
if (frame_sample_index_ >= nb_samples) {
frame_sample_index_ = -1;
} else {
// assume we have no more data to send