static gboolean gst_spectra_scope_render (GstBaseAudioVisualizer * bscope, GstBuffer * audio, GstBuffer * video) { GstSpectraScope *scope = GST_SPECTRA_SCOPE (bscope); guint32 *vdata = (guint32 *) GST_BUFFER_DATA (video); gint16 *adata = (gint16 *) g_memdup (GST_BUFFER_DATA (audio), GST_BUFFER_SIZE (audio)); GstFFTS16Complex *fdata = scope->freq_data; guint x, y, off; guint l, h = bscope->height - 1; gfloat fr, fi; guint w = bscope->width; if (bscope->channels > 1) { guint ch = bscope->channels; guint num_samples = GST_BUFFER_SIZE (audio) / (ch * sizeof (gint16)); guint i, c, v, s = 0; /* deinterleave and mixdown adata */ for (i = 0; i < num_samples; i++) { v = 0; for (c = 0; c < ch; c++) { v += adata[s++]; } adata[i] = v / ch; } } /* run fft */ gst_fft_s16_window (scope->fft_ctx, adata, GST_FFT_WINDOW_HAMMING); gst_fft_s16_fft (scope->fft_ctx, adata, fdata); g_free (adata); /* draw lines */ for (x = 0; x < bscope->width; x++) { /* figure out the range so that we don't need to clip, * or even better do a log mapping? */ fr = (gfloat) fdata[1 + x].r / 512.0; fi = (gfloat) fdata[1 + x].i / 512.0; y = (guint) (h * fabs (fr * fr + fi * fi)); if (y > h) y = h; y = h - y; off = (y * w) + x; vdata[off] = 0x00FFFFFF; for (l = y + 1; l <= h; l++) { off += w; add_pixel (&vdata[off], 0x007F7F7F); } } return TRUE; }
static void gst_spectra_scope_finalize (GObject * object) { GstSpectraScope *scope = GST_SPECTRA_SCOPE (object); if (scope->fft_ctx) { gst_fft_s16_free (scope->fft_ctx); scope->fft_ctx = NULL; } if (scope->freq_data) { g_free (scope->freq_data); scope->freq_data = NULL; } G_OBJECT_CLASS (gst_spectra_scope_parent_class)->finalize (object); }
static gboolean gst_spectra_scope_setup (GstBaseAudioVisualizer * bscope) { GstSpectraScope *scope = GST_SPECTRA_SCOPE (bscope); guint num_freq = bscope->width + 1; if (scope->fft_ctx) gst_fft_s16_free (scope->fft_ctx); g_free (scope->freq_data); /* we'd need this amount of samples per render() call */ bscope->req_spf = num_freq * 2 - 2; scope->fft_ctx = gst_fft_s16_new (bscope->req_spf, FALSE); scope->freq_data = g_new (GstFFTS16Complex, num_freq); return TRUE; }
static gboolean gst_spectra_scope_render (GstBaseAudioVisualizer * bscope, GstBuffer * audio, GstBuffer * video) { GstSpectraScope *scope = GST_SPECTRA_SCOPE (bscope); gint16 *mono_adata; GstFFTS16Complex *fdata = scope->freq_data; guint x, y, off; guint l, h = bscope->height - 1; gfloat fr, fi; guint w = bscope->width; GstMapInfo amap, vmap; guint32 *vdata; gint channels; gst_buffer_map (audio, &amap, GST_MAP_READ); gst_buffer_map (video, &vmap, GST_MAP_WRITE); vdata = (guint32 *) vmap.data; channels = GST_AUDIO_INFO_CHANNELS (&bscope->ainfo); mono_adata = (gint16 *) g_memdup (amap.data, amap.size); if (channels > 1) { guint ch = channels; guint num_samples = amap.size / (ch * sizeof (gint16)); guint i, c, v, s = 0; /* deinterleave and mixdown adata */ for (i = 0; i < num_samples; i++) { v = 0; for (c = 0; c < ch; c++) { v += mono_adata[s++]; } mono_adata[i] = v / ch; } } /* run fft */ gst_fft_s16_window (scope->fft_ctx, mono_adata, GST_FFT_WINDOW_HAMMING); gst_fft_s16_fft (scope->fft_ctx, mono_adata, fdata); g_free (mono_adata); /* draw lines */ for (x = 0; x < bscope->width; x++) { /* figure out the range so that we don't need to clip, * or even better do a log mapping? */ fr = (gfloat) fdata[1 + x].r / 512.0; fi = (gfloat) fdata[1 + x].i / 512.0; y = (guint) (h * fabs (fr * fr + fi * fi)); if (y > h) y = h; y = h - y; off = (y * w) + x; vdata[off] = 0x00FFFFFF; for (l = y + 1; l <= h; l++) { off += w; add_pixel (&vdata[off], 0x007F7F7F); } } gst_buffer_unmap (video, &vmap); gst_buffer_unmap (audio, &amap); return TRUE; }
static gboolean gst_spectra_scope_render (GstAudioVisualizer * bscope, GstBuffer * audio, GstVideoFrame * video) { GstSpectraScope *scope = GST_SPECTRA_SCOPE (bscope); gint16 *mono_adata; GstFFTS16Complex *fdata = scope->freq_data; guint x, y, off, l; guint w = GST_VIDEO_INFO_WIDTH (&bscope->vinfo); guint h = GST_VIDEO_INFO_HEIGHT (&bscope->vinfo) - 1; gfloat fr, fi; GstMapInfo amap; guint32 *vdata; gint channels; gst_buffer_map (audio, &amap, GST_MAP_READ); vdata = (guint32 *) GST_VIDEO_FRAME_PLANE_DATA (video, 0); channels = GST_AUDIO_INFO_CHANNELS (&bscope->ainfo); mono_adata = (gint16 *) g_memdup (amap.data, amap.size); if (channels > 1) { guint ch = channels; guint num_samples = amap.size / (ch * sizeof (gint16)); guint i, c, v, s = 0; /* deinterleave and mixdown adata */ for (i = 0; i < num_samples; i++) { v = 0; for (c = 0; c < ch; c++) { v += mono_adata[s++]; } mono_adata[i] = v / ch; } } /* run fft */ gst_fft_s16_window (scope->fft_ctx, mono_adata, GST_FFT_WINDOW_HAMMING); gst_fft_s16_fft (scope->fft_ctx, mono_adata, fdata); g_free (mono_adata); /* draw lines */ for (x = 0; x < w; x++) { /* figure out the range so that we don't need to clip, * or even better do a log mapping? */ fr = (gfloat) fdata[1 + x].r / 512.0; fi = (gfloat) fdata[1 + x].i / 512.0; y = (guint) (h * sqrt (fr * fr + fi * fi)); if (y > h) y = h; y = h - y; off = (y * w) + x; vdata[off] = 0x00FFFFFF; for (l = y; l < h; l++) { off += w; add_pixel (&vdata[off], 0x007F7F7F); } /* ensure bottom line is full bright (especially in move-up mode) */ add_pixel (&vdata[off], 0x007F7F7F); } gst_buffer_unmap (audio, &amap); return TRUE; }