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();
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user