gstmoodbar: Formatting

This commit is contained in:
Jonas Kvinge 2021-10-30 00:48:21 +02:00
parent e75c955a68
commit 377e6fad25
4 changed files with 167 additions and 192 deletions

View File

@ -33,24 +33,25 @@
#include "gstfastspectrum.h" #include "gstfastspectrum.h"
GST_DEBUG_CATEGORY_STATIC (gst_fastspectrum_debug); GST_DEBUG_CATEGORY_STATIC(gst_fastspectrum_debug);
#define GST_CAT_DEFAULT gst_fastspectrum_debug #define GST_CAT_DEFAULT gst_fastspectrum_debug
/* elementfactory information */ // elementfactory information
#if G_BYTE_ORDER == G_LITTLE_ENDIAN #if G_BYTE_ORDER == G_LITTLE_ENDIAN
# define FORMATS "{ S16LE, S24LE, S32LE, F32LE, F64LE }" # define FORMATS "{ S16LE, S24LE, S32LE, F32LE, F64LE }"
#else #else
# define FORMATS "{ S16BE, S24BE, S32BE, F32BE, F64BE }" # define FORMATS "{ S16BE, S24BE, S32BE, F32BE, F64BE }"
#endif #endif
#define ALLOWED_CAPS \ #define ALLOWED_CAPS \
GST_AUDIO_CAPS_MAKE (FORMATS) ", " \ GST_AUDIO_CAPS_MAKE(FORMATS) \
", " \
"layout = (string) interleaved, " \ "layout = (string) interleaved, " \
"channels = 1" "channels = 1"
/* Spectrum properties */ // Spectrum properties
#define DEFAULT_INTERVAL (GST_SECOND / 10) #define DEFAULT_INTERVAL (GST_SECOND / 10)
#define DEFAULT_BANDS 128 #define DEFAULT_BANDS 128
enum { enum {
PROP_0, PROP_0,
@ -59,92 +60,89 @@ enum {
}; };
#define gst_fastspectrum_parent_class parent_class #define gst_fastspectrum_parent_class parent_class
G_DEFINE_TYPE (GstFastSpectrum, gst_fastspectrum, GST_TYPE_AUDIO_FILTER) G_DEFINE_TYPE(GstFastSpectrum, gst_fastspectrum, GST_TYPE_AUDIO_FILTER)
static void gst_fastspectrum_finalize (GObject * object); static void gst_fastspectrum_finalize(GObject *object);
static void gst_fastspectrum_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_fastspectrum_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void gst_fastspectrum_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void gst_fastspectrum_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static gboolean gst_fastspectrum_start (GstBaseTransform * trans); static gboolean gst_fastspectrum_start(GstBaseTransform *trans);
static gboolean gst_fastspectrum_stop (GstBaseTransform * trans); static gboolean gst_fastspectrum_stop(GstBaseTransform *trans);
static GstFlowReturn gst_fastspectrum_transform_ip (GstBaseTransform *trans, GstBuffer *buffer); static GstFlowReturn gst_fastspectrum_transform_ip(GstBaseTransform *trans, GstBuffer *buffer);
static gboolean gst_fastspectrum_setup (GstAudioFilter * base, const GstAudioInfo * info); static gboolean gst_fastspectrum_setup(GstAudioFilter *base, const GstAudioInfo *info);
static void gst_fastspectrum_class_init (GstFastSpectrumClass * klass) { static void gst_fastspectrum_class_init(GstFastSpectrumClass *klass) {
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS (klass); GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS(klass);
GstAudioFilterClass *filter_class = GST_AUDIO_FILTER_CLASS (klass); GstAudioFilterClass *filter_class = GST_AUDIO_FILTER_CLASS(klass);
GstCaps *caps = nullptr; GstCaps *caps = nullptr;
gobject_class->set_property = gst_fastspectrum_set_property; gobject_class->set_property = gst_fastspectrum_set_property;
gobject_class->get_property = gst_fastspectrum_get_property; gobject_class->get_property = gst_fastspectrum_get_property;
gobject_class->finalize = gst_fastspectrum_finalize; gobject_class->finalize = gst_fastspectrum_finalize;
trans_class->start = GST_DEBUG_FUNCPTR (gst_fastspectrum_start); trans_class->start = GST_DEBUG_FUNCPTR(gst_fastspectrum_start);
trans_class->stop = GST_DEBUG_FUNCPTR (gst_fastspectrum_stop); trans_class->stop = GST_DEBUG_FUNCPTR(gst_fastspectrum_stop);
trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_fastspectrum_transform_ip); trans_class->transform_ip = GST_DEBUG_FUNCPTR(gst_fastspectrum_transform_ip);
trans_class->passthrough_on_same_caps = TRUE; trans_class->passthrough_on_same_caps = TRUE;
filter_class->setup = GST_DEBUG_FUNCPTR (gst_fastspectrum_setup); filter_class->setup = GST_DEBUG_FUNCPTR(gst_fastspectrum_setup);
g_object_class_install_property (gobject_class, PROP_INTERVAL, g_object_class_install_property(gobject_class, PROP_INTERVAL, g_param_spec_uint64("interval", "Interval", "Interval of time between message posts (in nanoseconds)", 1, G_MAXUINT64, DEFAULT_INTERVAL, GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_param_spec_uint64 ("interval", "Interval", "Interval of time between message posts (in nanoseconds)", 1, G_MAXUINT64, DEFAULT_INTERVAL, GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (gobject_class, PROP_BANDS, g_param_spec_uint ("bands", "Bands", "Number of frequency bands", 0, G_MAXUINT, DEFAULT_BANDS, GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); g_object_class_install_property(gobject_class, PROP_BANDS, g_param_spec_uint("bands", "Bands", "Number of frequency bands", 0, G_MAXUINT, DEFAULT_BANDS, GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
GST_DEBUG_CATEGORY_INIT (gst_fastspectrum_debug, "spectrum", 0, GST_DEBUG_CATEGORY_INIT(gst_fastspectrum_debug, "spectrum", 0, "audio spectrum analyser element");
"audio spectrum analyser element");
gst_element_class_set_static_metadata (element_class, "Spectrum analyzer", gst_element_class_set_static_metadata(element_class, "Spectrum analyzer",
"Filter/Analyzer/Audio", "Filter/Analyzer/Audio",
"Run an FFT on the audio signal, output spectrum data", "Run an FFT on the audio signal, output spectrum data",
"Erik Walthinsen <omega@cse.ogi.edu>, " "Erik Walthinsen <omega@cse.ogi.edu>, "
"Stefan Kost <ensonic@users.sf.net>, " "Stefan Kost <ensonic@users.sf.net>, "
"Sebastian Dröge <sebastian.droege@collabora.co.uk>"); "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
caps = gst_caps_from_string (ALLOWED_CAPS); caps = gst_caps_from_string(ALLOWED_CAPS);
gst_audio_filter_class_add_pad_templates (filter_class, caps); gst_audio_filter_class_add_pad_templates(filter_class, caps);
gst_caps_unref (caps); gst_caps_unref(caps);
klass->fftw_lock = new QMutex; klass->fftw_lock = new QMutex;
} }
static void gst_fastspectrum_init (GstFastSpectrum * spectrum) { static void gst_fastspectrum_init(GstFastSpectrum *spectrum) {
spectrum->interval = DEFAULT_INTERVAL; spectrum->interval = DEFAULT_INTERVAL;
spectrum->bands = DEFAULT_BANDS; spectrum->bands = DEFAULT_BANDS;
spectrum->channel_data_initialized = false; spectrum->channel_data_initialized = false;
g_mutex_init (&spectrum->lock); g_mutex_init(&spectrum->lock);
} }
static void gst_fastspectrum_alloc_channel_data (GstFastSpectrum * spectrum) { static void gst_fastspectrum_alloc_channel_data(GstFastSpectrum *spectrum) {
guint bands = spectrum->bands; guint bands = spectrum->bands;
guint nfft = 2 * bands - 2; guint nfft = 2 * bands - 2;
spectrum->input_ring_buffer = new double[nfft]; spectrum->input_ring_buffer = new double[nfft];
spectrum->fft_input = reinterpret_cast<double*>( fftw_malloc(sizeof(double) * nfft)); spectrum->fft_input = reinterpret_cast<double*>(fftw_malloc(sizeof(double) * nfft));
spectrum->fft_output =reinterpret_cast<fftw_complex*>( fftw_malloc(sizeof(fftw_complex) * (nfft/2+1))); spectrum->fft_output = reinterpret_cast<fftw_complex*>(fftw_malloc(sizeof(fftw_complex) * (nfft / 2 + 1)));
spectrum->spect_magnitude = new double[bands]{}; spectrum->spect_magnitude = new double[bands] {};
GstFastSpectrumClass* klass = reinterpret_cast<GstFastSpectrumClass*>(G_OBJECT_GET_CLASS(spectrum)); GstFastSpectrumClass *klass = reinterpret_cast<GstFastSpectrumClass*>(G_OBJECT_GET_CLASS(spectrum));
{ {
QMutexLocker l(klass->fftw_lock); QMutexLocker l(klass->fftw_lock);
spectrum->plan = fftw_plan_dft_r2c_1d(nfft, spectrum->fft_input, spectrum->fft_output, FFTW_ESTIMATE); spectrum->plan = fftw_plan_dft_r2c_1d(static_cast<int>(nfft), spectrum->fft_input, spectrum->fft_output, FFTW_ESTIMATE);
} }
spectrum->channel_data_initialized = true; spectrum->channel_data_initialized = true;
} }
static void gst_fastspectrum_free_channel_data (GstFastSpectrum * spectrum) { static void gst_fastspectrum_free_channel_data(GstFastSpectrum *spectrum) {
GstFastSpectrumClass* klass = reinterpret_cast<GstFastSpectrumClass*>(G_OBJECT_GET_CLASS(spectrum)); GstFastSpectrumClass *klass = reinterpret_cast<GstFastSpectrumClass*>(G_OBJECT_GET_CLASS(spectrum));
if (spectrum->channel_data_initialized) { if (spectrum->channel_data_initialized) {
{ {
QMutexLocker l(klass->fftw_lock); QMutexLocker l(klass->fftw_lock);
@ -160,7 +158,7 @@ static void gst_fastspectrum_free_channel_data (GstFastSpectrum * spectrum) {
} }
static void gst_fastspectrum_flush (GstFastSpectrum * spectrum) { static void gst_fastspectrum_flush(GstFastSpectrum *spectrum) {
spectrum->num_frames = 0; spectrum->num_frames = 0;
spectrum->num_fft = 0; spectrum->num_fft = 0;
@ -169,147 +167,145 @@ static void gst_fastspectrum_flush (GstFastSpectrum * spectrum) {
} }
static void gst_fastspectrum_reset_state (GstFastSpectrum * spectrum) { static void gst_fastspectrum_reset_state(GstFastSpectrum *spectrum) {
GST_DEBUG_OBJECT (spectrum, "resetting state"); GST_DEBUG_OBJECT(spectrum, "resetting state");
gst_fastspectrum_free_channel_data (spectrum); gst_fastspectrum_free_channel_data(spectrum);
gst_fastspectrum_flush (spectrum); gst_fastspectrum_flush(spectrum);
} }
static void gst_fastspectrum_finalize (GObject * object) { static void gst_fastspectrum_finalize(GObject *object) {
GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(object); GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(object);
gst_fastspectrum_reset_state (spectrum); gst_fastspectrum_reset_state(spectrum);
g_mutex_clear (&spectrum->lock); g_mutex_clear(&spectrum->lock);
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS(parent_class)->finalize(object);
} }
static void gst_fastspectrum_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { static void gst_fastspectrum_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) {
GstFastSpectrum *filter = reinterpret_cast<GstFastSpectrum*>(object); GstFastSpectrum *filter = reinterpret_cast<GstFastSpectrum*>(object);
switch (prop_id) { switch (prop_id) {
case PROP_INTERVAL:{ case PROP_INTERVAL: {
guint64 interval = g_value_get_uint64 (value); guint64 interval = g_value_get_uint64(value);
g_mutex_lock (&filter->lock); g_mutex_lock(&filter->lock);
if (filter->interval != interval) { if (filter->interval != interval) {
filter->interval = interval; filter->interval = interval;
gst_fastspectrum_reset_state (filter); gst_fastspectrum_reset_state(filter);
} }
g_mutex_unlock (&filter->lock); g_mutex_unlock(&filter->lock);
break; break;
} }
case PROP_BANDS:{ case PROP_BANDS: {
guint bands = g_value_get_uint (value); guint bands = g_value_get_uint(value);
g_mutex_lock (&filter->lock); g_mutex_lock(&filter->lock);
if (filter->bands != bands) { if (filter->bands != bands) {
filter->bands = bands; filter->bands = bands;
gst_fastspectrum_reset_state (filter); gst_fastspectrum_reset_state(filter);
} }
g_mutex_unlock (&filter->lock); g_mutex_unlock(&filter->lock);
break; break;
} }
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break; break;
} }
} }
static void gst_fastspectrum_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { static void gst_fastspectrum_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
GstFastSpectrum *filter = reinterpret_cast<GstFastSpectrum*>(object); GstFastSpectrum *filter = reinterpret_cast<GstFastSpectrum*>(object);
switch (prop_id) { switch (prop_id) {
case PROP_INTERVAL: case PROP_INTERVAL:
g_value_set_uint64 (value, filter->interval); g_value_set_uint64(value, filter->interval);
break; break;
case PROP_BANDS: case PROP_BANDS:
g_value_set_uint (value, filter->bands); g_value_set_uint(value, filter->bands);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break; break;
} }
} }
static gboolean gst_fastspectrum_start (GstBaseTransform * trans) { static gboolean gst_fastspectrum_start(GstBaseTransform *trans) {
GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(trans); GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(trans);
gst_fastspectrum_reset_state (spectrum); gst_fastspectrum_reset_state(spectrum);
return TRUE; return TRUE;
} }
static gboolean gst_fastspectrum_stop (GstBaseTransform * trans) { static gboolean gst_fastspectrum_stop(GstBaseTransform *trans) {
GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(trans); GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(trans);
gst_fastspectrum_reset_state (spectrum); gst_fastspectrum_reset_state(spectrum);
return TRUE; return TRUE;
} }
/* mixing data readers */ // Mixing data readers
static void input_data_mixed_float(const guint8* _in, double* out, guint len, double max_value, guint op, guint nfft) { static void input_data_mixed_float(const guint8 *_in, double *out, guint len, double max_value, guint op, guint nfft) {
Q_UNUSED(max_value); Q_UNUSED(max_value);
guint j = 0, ip = 0;
const gfloat *in = reinterpret_cast<const gfloat*>(_in); const gfloat *in = reinterpret_cast<const gfloat*>(_in);
guint ip = 0;
for (j = 0; j < len; j++) { for (guint j = 0; j < len; j++) {
out[op] = in[ip++]; out[op] = in[ip++];
op = (op + 1) % nfft; op = (op + 1) % nfft;
} }
} }
static void input_data_mixed_double (const guint8 * _in, double* out, guint len, double max_value, guint op, guint nfft) { static void input_data_mixed_double(const guint8 *_in, double *out, guint len, double max_value, guint op, guint nfft) {
Q_UNUSED(max_value); Q_UNUSED(max_value);
guint j = 0, ip = 0;
const gdouble *in = reinterpret_cast<const gdouble*>(_in); const gdouble *in = reinterpret_cast<const gdouble*>(_in);
guint ip = 0;
for (j = 0; j < len; j++) { for (guint j = 0; j < len; j++) {
out[op] = in[ip++]; out[op] = in[ip++];
op = (op + 1) % nfft; op = (op + 1) % nfft;
} }
} }
static void input_data_mixed_int32_max (const guint8 * _in, double* out, guint len, double max_value, guint op, guint nfft) { static void input_data_mixed_int32_max(const guint8 *_in, double *out, guint len, double max_value, guint op, guint nfft) {
guint j = 0, ip = 0;
const gint32 *in = reinterpret_cast<const gint32*>(_in); const gint32 *in = reinterpret_cast<const gint32*>(_in);
guint ip = 0;
for (j = 0; j < len; j++) { for (guint j = 0; j < len; j++) {
out[op] = in[ip++] / max_value; out[op] = in[ip++] / max_value;
op = (op + 1) % nfft; op = (op + 1) % nfft;
} }
} }
static void input_data_mixed_int24_max (const guint8 * _in, double* out, guint len, double max_value, guint op, guint nfft) { static void input_data_mixed_int24_max(const guint8 *_in, double *out, guint len, double max_value, guint op, guint nfft) {
guint j = 0; for (guint j = 0; j < len; j++) {
for (j = 0; j < len; j++) {
#if G_BYTE_ORDER == G_BIG_ENDIAN #if G_BYTE_ORDER == G_BIG_ENDIAN
gint32 value = GST_READ_UINT24_BE (_in); guint32 value = GST_READ_UINT24_BE(_in);
#else #else
gint32 value = GST_READ_UINT24_LE (_in); guint32 value = GST_READ_UINT24_LE(_in);
#endif #endif
if (value & 0x00800000) { if (value & 0x00800000) {
value |= 0xff000000; value |= 0xff000000;
@ -322,25 +318,25 @@ static void input_data_mixed_int24_max (const guint8 * _in, double* out, guint l
} }
static void input_data_mixed_int16_max (const guint8 * _in, double * out, guint len, double max_value, guint op, guint nfft) { static void input_data_mixed_int16_max(const guint8 *_in, double *out, guint len, double max_value, guint op, guint nfft) {
guint j = 0, ip = 0;
const gint16 *in = reinterpret_cast<const gint16*>(_in); const gint16 *in = reinterpret_cast<const gint16*>(_in);
guint ip = 0;
for (j = 0; j < len; j++) { for (guint j = 0; j < len; j++) {
out[op] = in[ip++] / max_value; out[op] = in[ip++] / max_value;
op = (op + 1) % nfft; op = (op + 1) % nfft;
} }
} }
static gboolean gst_fastspectrum_setup (GstAudioFilter * base, const GstAudioInfo * info) { static gboolean gst_fastspectrum_setup(GstAudioFilter *base, const GstAudioInfo *info) {
GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(base); GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(base);
GstFastSpectrumInputData input_data = nullptr; GstFastSpectrumInputData input_data = nullptr;
g_mutex_lock (&spectrum->lock); g_mutex_lock(&spectrum->lock);
switch (GST_AUDIO_INFO_FORMAT (info)) { switch (GST_AUDIO_INFO_FORMAT(info)) {
case GST_AUDIO_FORMAT_S16: case GST_AUDIO_FORMAT_S16:
input_data = input_data_mixed_int16_max; input_data = input_data_mixed_int16_max;
break; break;
@ -357,35 +353,33 @@ static gboolean gst_fastspectrum_setup (GstAudioFilter * base, const GstAudioInf
input_data = input_data_mixed_double; input_data = input_data_mixed_double;
break; break;
default: default:
g_assert_not_reached (); g_assert_not_reached();
break; break;
} }
spectrum->input_data = input_data; spectrum->input_data = input_data;
gst_fastspectrum_reset_state (spectrum); gst_fastspectrum_reset_state(spectrum);
g_mutex_unlock (&spectrum->lock); g_mutex_unlock(&spectrum->lock);
return TRUE; return TRUE;
} }
static void gst_fastspectrum_run_fft (GstFastSpectrum * spectrum, guint input_pos) { static void gst_fastspectrum_run_fft(GstFastSpectrum *spectrum, guint input_pos) {
guint i = 0;
guint bands = spectrum->bands; guint bands = spectrum->bands;
guint nfft = 2 * bands - 2; guint nfft = 2 * bands - 2;
for (i = 0; i < nfft; i++) { for (guint i = 0; i < nfft; i++) {
spectrum->fft_input[i] = spectrum->input_ring_buffer[(input_pos + i) % nfft]; spectrum->fft_input[i] = spectrum->input_ring_buffer[(input_pos + i) % nfft];
} }
// Should be safe to execute the same plan multiple times in parallel. // Should be safe to execute the same plan multiple times in parallel.
fftw_execute(spectrum->plan); fftw_execute(spectrum->plan);
gdouble val = 0.0; // Calculate magnitude in db
/* Calculate magnitude in db */ for (guint i = 0; i < bands; i++) {
for (i = 0; i < bands; i++) { gdouble val = spectrum->fft_output[i][0] * spectrum->fft_output[i][0];
val = spectrum->fft_output[i][0] * spectrum->fft_output[i][0];
val += spectrum->fft_output[i][1] * spectrum->fft_output[i][1]; val += spectrum->fft_output[i][1] * spectrum->fft_output[i][1];
val /= nfft * nfft; val /= nfft * nfft;
spectrum->spect_magnitude[i] += val; spectrum->spect_magnitude[i] += val;
@ -393,79 +387,68 @@ static void gst_fastspectrum_run_fft (GstFastSpectrum * spectrum, guint input_po
} }
static GstFlowReturn gst_fastspectrum_transform_ip (GstBaseTransform *trans, GstBuffer *buffer) { static GstFlowReturn gst_fastspectrum_transform_ip(GstBaseTransform *trans, GstBuffer *buffer) {
GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(trans); GstFastSpectrum *spectrum = reinterpret_cast<GstFastSpectrum*>(trans);
guint rate = GST_AUDIO_FILTER_RATE (spectrum); guint rate = GST_AUDIO_FILTER_RATE(spectrum);
guint bps = GST_AUDIO_FILTER_BPS (spectrum); guint bps = GST_AUDIO_FILTER_BPS(spectrum);
guint bpf = GST_AUDIO_FILTER_BPF (spectrum); guint bpf = GST_AUDIO_FILTER_BPF(spectrum);
double max_value = (1UL << ((bps << 3) - 1)) - 1; double max_value = static_cast<double>((1UL << ((bps << 3) - 1)) - 1);
guint bands = spectrum->bands; guint bands = spectrum->bands;
guint nfft = 2 * bands - 2; guint nfft = 2 * bands - 2;
guint input_pos = 0; guint input_pos = 0;
GstMapInfo map; GstMapInfo map;
const guint8 *data = nullptr; const guint8 *data = nullptr;
gsize size = 0; gsize size = 0;
guint fft_todo = 0, msg_todo = 0, block_size = 0;
gboolean have_full_interval = false;
GstFastSpectrumInputData input_data = nullptr; GstFastSpectrumInputData input_data = nullptr;
g_mutex_lock (&spectrum->lock); g_mutex_lock(&spectrum->lock);
gst_buffer_map (buffer, &map, GST_MAP_READ); gst_buffer_map(buffer, &map, GST_MAP_READ);
data = map.data; data = map.data;
size = map.size; size = map.size;
GST_LOG_OBJECT (spectrum, "input size: %" G_GSIZE_FORMAT " bytes", size); GST_LOG_OBJECT(spectrum, "input size: %" G_GSIZE_FORMAT " bytes", size);
if (GST_BUFFER_IS_DISCONT (buffer)) { if (GST_BUFFER_IS_DISCONT(buffer)) {
GST_DEBUG_OBJECT (spectrum, "Discontinuity detected -- flushing"); GST_DEBUG_OBJECT(spectrum, "Discontinuity detected -- flushing");
gst_fastspectrum_flush (spectrum); gst_fastspectrum_flush(spectrum);
} }
/* If we don't have a FFT context yet (or it was reset due to parameter // If we don't have a FFT context yet (or it was reset due to parameter changes) get one and allocate memory for everything
* changes) get one and allocate memory for everything
*/
if (!spectrum->channel_data_initialized) { if (!spectrum->channel_data_initialized) {
GST_DEBUG_OBJECT (spectrum, "allocating for bands %u", bands); GST_DEBUG_OBJECT(spectrum, "allocating for bands %u", bands);
gst_fastspectrum_alloc_channel_data (spectrum); gst_fastspectrum_alloc_channel_data(spectrum);
/* number of sample frames we process before posting a message // Number of sample frames we process before posting a message interval is in ns
* interval is in ns */ spectrum->frames_per_interval = gst_util_uint64_scale(spectrum->interval, rate, GST_SECOND);
spectrum->frames_per_interval = gst_util_uint64_scale (spectrum->interval, rate, GST_SECOND);
spectrum->frames_todo = spectrum->frames_per_interval; spectrum->frames_todo = spectrum->frames_per_interval;
/* rounding error for frames_per_interval in ns, // Rounding error for frames_per_interval in ns, aggregated it in accumulated_error
* aggregated it in accumulated_error */
spectrum->error_per_interval = (spectrum->interval * rate) % GST_SECOND; spectrum->error_per_interval = (spectrum->interval * rate) % GST_SECOND;
if (spectrum->frames_per_interval == 0) { if (spectrum->frames_per_interval == 0) {
spectrum->frames_per_interval = 1; spectrum->frames_per_interval = 1;
} }
GST_INFO_OBJECT (spectrum, "interval %" GST_TIME_FORMAT ", fpi %" GST_INFO_OBJECT(spectrum, "interval %" GST_TIME_FORMAT ", fpi %" G_GUINT64_FORMAT ", error %" GST_TIME_FORMAT, GST_TIME_ARGS(spectrum->interval), spectrum->frames_per_interval, GST_TIME_ARGS(spectrum->error_per_interval));
G_GUINT64_FORMAT ", error %" GST_TIME_FORMAT,
GST_TIME_ARGS (spectrum->interval), spectrum->frames_per_interval,
GST_TIME_ARGS (spectrum->error_per_interval));
spectrum->input_pos = 0; spectrum->input_pos = 0;
gst_fastspectrum_flush (spectrum); gst_fastspectrum_flush(spectrum);
} }
if (spectrum->num_frames == 0) { if (spectrum->num_frames == 0) {
spectrum->message_ts = GST_BUFFER_TIMESTAMP (buffer); spectrum->message_ts = GST_BUFFER_TIMESTAMP(buffer);
} }
input_pos = spectrum->input_pos; input_pos = spectrum->input_pos;
input_data = spectrum->input_data; input_data = spectrum->input_data;
while (size >= bpf) { while (size >= bpf) {
/* run input_data for a chunk of data */ // Run input_data for a chunk of data
fft_todo = nfft - (spectrum->num_frames % nfft); guint fft_todo = nfft - (spectrum->num_frames % nfft);
msg_todo = spectrum->frames_todo - spectrum->num_frames; guint msg_todo = spectrum->frames_todo - spectrum->num_frames;
GST_LOG_OBJECT (spectrum, GST_LOG_OBJECT(spectrum, "message frames todo: %u, fft frames todo: %u, input frames %" G_GSIZE_FORMAT, msg_todo, fft_todo, (size / bpf));
"message frames todo: %u, fft frames todo: %u, input frames %" guint block_size = msg_todo;
G_GSIZE_FORMAT, msg_todo, fft_todo, (size / bpf));
block_size = msg_todo;
if (block_size > (size / bpf)) { if (block_size > (size / bpf)) {
block_size = (size / bpf); block_size = (size / bpf);
} }
@ -473,7 +456,7 @@ static GstFlowReturn gst_fastspectrum_transform_ip (GstBaseTransform *trans, Gst
block_size = fft_todo; block_size = fft_todo;
} }
/* Move the current frames into our ringbuffers */ // Move the current frames into our ringbuffers
input_data(data, spectrum->input_ring_buffer, block_size, max_value, input_pos, nfft); input_data(data, spectrum->input_ring_buffer, block_size, max_value, input_pos, nfft);
data += block_size * bpf; data += block_size * bpf;
@ -481,25 +464,19 @@ static GstFlowReturn gst_fastspectrum_transform_ip (GstBaseTransform *trans, Gst
input_pos = (input_pos + block_size) % nfft; input_pos = (input_pos + block_size) % nfft;
spectrum->num_frames += block_size; spectrum->num_frames += block_size;
have_full_interval = (spectrum->num_frames == spectrum->frames_todo); gboolean have_full_interval = (spectrum->num_frames == spectrum->frames_todo);
GST_LOG_OBJECT (spectrum, GST_LOG_OBJECT(spectrum, "size: %" G_GSIZE_FORMAT ", do-fft = %d, do-message = %d", size, (spectrum->num_frames % nfft == 0), have_full_interval);
"size: %" G_GSIZE_FORMAT ", do-fft = %d, do-message = %d", size,
(spectrum->num_frames % nfft == 0), have_full_interval);
/* If we have enough frames for an FFT or we have all frames required for // If we have enough frames for an FFT or we have all frames required for the interval and we haven't run a FFT, then run an FFT
* the interval and we haven't run a FFT, then run an FFT */
if ((spectrum->num_frames % nfft == 0) || (have_full_interval && !spectrum->num_fft)) { if ((spectrum->num_frames % nfft == 0) || (have_full_interval && !spectrum->num_fft)) {
gst_fastspectrum_run_fft (spectrum, input_pos); gst_fastspectrum_run_fft(spectrum, input_pos);
spectrum->num_fft++; spectrum->num_fft++;
} }
/* Do we have the FFTs for one interval? */ // Do we have the FFTs for one interval?
if (have_full_interval) { if (have_full_interval) {
GST_DEBUG_OBJECT (spectrum, "nfft: %u frames: %" G_GUINT64_FORMAT GST_DEBUG_OBJECT(spectrum, "nfft: %u frames: %" G_GUINT64_FORMAT " fpi: %" G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft, spectrum->num_frames, spectrum->frames_per_interval, GST_TIME_ARGS(spectrum->accumulated_error));
" fpi: %" G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft,
spectrum->num_frames, spectrum->frames_per_interval,
GST_TIME_ARGS (spectrum->accumulated_error));
spectrum->frames_todo = spectrum->frames_per_interval; spectrum->frames_todo = spectrum->frames_per_interval;
if (spectrum->accumulated_error >= GST_SECOND) { if (spectrum->accumulated_error >= GST_SECOND) {
@ -511,17 +488,17 @@ static GstFlowReturn gst_fastspectrum_transform_ip (GstBaseTransform *trans, Gst
if (spectrum->output_callback) { if (spectrum->output_callback) {
// Calculate average // Calculate average
for (guint i = 0; i < spectrum->bands; i++) { for (guint i = 0; i < spectrum->bands; i++) {
spectrum->spect_magnitude[i] /= spectrum->num_fft; spectrum->spect_magnitude[i] /= static_cast<double>(spectrum->num_fft);
} }
spectrum->output_callback(spectrum->spect_magnitude, spectrum->bands); spectrum->output_callback(spectrum->spect_magnitude, static_cast<int>(spectrum->bands));
// Reset spectrum accumulators // Reset spectrum accumulators
memset(spectrum->spect_magnitude, 0, spectrum->bands * sizeof(double)); memset(spectrum->spect_magnitude, 0, spectrum->bands * sizeof(double));
} }
if (GST_CLOCK_TIME_IS_VALID (spectrum->message_ts)) { if (GST_CLOCK_TIME_IS_VALID(spectrum->message_ts)) {
spectrum->message_ts += gst_util_uint64_scale (spectrum->num_frames, GST_SECOND, rate); spectrum->message_ts += gst_util_uint64_scale(spectrum->num_frames, GST_SECOND, rate);
} }
spectrum->num_frames = 0; spectrum->num_frames = 0;
@ -531,10 +508,10 @@ static GstFlowReturn gst_fastspectrum_transform_ip (GstBaseTransform *trans, Gst
spectrum->input_pos = input_pos; spectrum->input_pos = input_pos;
gst_buffer_unmap (buffer, &map); gst_buffer_unmap(buffer, &map);
g_mutex_unlock (&spectrum->lock); g_mutex_unlock(&spectrum->lock);
g_assert (size == 0); g_assert(size == 0);
return GST_FLOW_OK; return GST_FLOW_OK;

View File

@ -38,38 +38,37 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define GST_TYPE_FASTSPECTRUM (gst_fastspectrum_get_type()) #define GST_TYPE_FASTSPECTRUM (gst_fastspectrum_get_type())
#define GST_FASTSPECTRUM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FASTSPECTRUM,GstFastSpectrum)) #define GST_FASTSPECTRUM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_FASTSPECTRUM, GstFastSpectrum))
#define GST_IS_FASTSPECTRUM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FASTSPECTRUM)) #define GST_IS_FASTSPECTRUM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_FASTSPECTRUM))
#define GST_FASTSPECTRUM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_FASTSPECTRUM,GstFastSpectrumClass)) #define GST_FASTSPECTRUM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_FASTSPECTRUM, GstFastSpectrumClass))
#define GST_IS_FASTSPECTRUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_FASTSPECTRUM)) #define GST_IS_FASTSPECTRUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_FASTSPECTRUM))
class QMutex; class QMutex;
typedef void (*GstFastSpectrumInputData)(const guint8* in, double* out, guint len, double max_value, guint op, guint nfft); typedef void (*GstFastSpectrumInputData)(const guint8 *in, double *out, guint len, double max_value, guint op, guint nfft);
typedef std::function<void(double* magnitudes, int size)> OutputCallback; typedef std::function<void(double *magnitudes, int size)> OutputCallback;
struct GstFastSpectrum { struct GstFastSpectrum {
GstAudioFilter parent; GstAudioFilter parent;
/* properties */ // Properties
guint64 interval; /* how many nanoseconds between emits */ guint64 interval; // How many nanoseconds between emits
guint64 frames_per_interval; /* how many frames per interval */ guint64 frames_per_interval; // How many frames per interval
guint64 frames_todo; guint64 frames_todo;
guint bands; /* number of spectrum bands */ guint bands; // Number of spectrum bands
gboolean multi_channel; /* send separate channel results */ gboolean multi_channel; // Send separate channel results
guint64 num_frames; /* frame count (1 sample per channel) guint64 num_frames; // Frame count (1 sample per channel) since last emit
* since last emit */ guint64 num_fft; // Number of FFTs since last emit
guint64 num_fft; /* number of FFTs since last emit */ GstClockTime message_ts; // Starttime for next message
GstClockTime message_ts; /* starttime for next message */
/* <private> */ // <private>
bool channel_data_initialized; bool channel_data_initialized;
double* input_ring_buffer; double *input_ring_buffer;
double* fft_input; double *fft_input;
fftw_complex* fft_output; fftw_complex *fft_output;
double* spect_magnitude; double *spect_magnitude;
fftw_plan plan; fftw_plan plan;
guint input_pos; guint input_pos;
@ -87,11 +86,11 @@ struct GstFastSpectrumClass {
GstAudioFilterClass parent_class; GstAudioFilterClass parent_class;
// Static lock for creating & destroying FFTW plans. // Static lock for creating & destroying FFTW plans.
QMutex* fftw_lock; QMutex *fftw_lock;
}; };
GType gst_fastspectrum_get_type (void); GType gst_fastspectrum_get_type(void);
G_END_DECLS G_END_DECLS
#endif // GST_MOODBAR_FASTSPECTRUM_H #endif // GST_MOODBAR_FASTSPECTRUM_H

View File

@ -30,7 +30,6 @@ static gboolean gst_moodbar_plugin_init(GstPlugin *plugin) {
} }
return TRUE; return TRUE;
} }
} // namespace } // namespace

View File

@ -19,7 +19,7 @@
#define GST_MOODBAR_PLUGIN_H #define GST_MOODBAR_PLUGIN_H
extern "C" { extern "C" {
int gstfastspectrum_register_static(); int gstfastspectrum_register_static();
} }
#endif // GST_MOODBAR_PLUGIN_H #endif // GST_MOODBAR_PLUGIN_H