Commit ff816a14 authored by Richard Boulton's avatar Richard Boulton

I'm too lazy to comment this

Original commit message from CVS:
*** empty log message ***
parent b968efd7
......@@ -165,7 +165,7 @@ GST_PLUGINS_ALL="\
cutter deinterlace flx goom intfloat law level\
median mpeg1enc mpeg1sys mpeg1videoparse mpeg2enc mpeg2sub\
mpegaudio mpegaudioparse mpegstream mpegtypes modplug\
passthrough playondemand rtjpeg silence sine\
monoscope passthrough playondemand rtjpeg silence sine\
smooth spectrum speed stereo stereomono\
synaesthesia udp videoscale volenv volume vumeter wavparse y4m"
......@@ -734,6 +734,7 @@ gst/mpegstream/Makefile
gst/mpegtypes/Makefile
gst/modplug/Makefile
gst/modplug/libmodplug/Makefile
gst/monoscope/Makefile
gst/passthrough/Makefile
gst/playondemand/Makefile
gst/rtjpeg/Makefile
......
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs
plugindir = $(libdir)/gst
plugin_LTLIBRARIES = libgstmonoscope.la
libgstmonoscope_la_SOURCES = gstmonoscope.c monoscope.c convolve.c
noinst_HEADERS = monoscope.h convolve.h
libgstmonoscope_la_CFLAGS = -O2 -ffast-math $(GST_CFLAGS)
libgstmonoscope_la_LIBADD = $(GST_LIBS)
libgstmonoscope_la_LDFLAGS = @GST_PLUGIN_LDFLAGS@
This is a visualization based on on the monoscope output plugin from
alsaplayer.
The monoscope output plugin was written primarily by Ralph Loader.
This implementation is taken from alsaplayer version 0.99.54, at
http://www.alsaplayer.org/
Note: only one instance of this plugin may be created at a time: it has a
lot of static data. This should be fixed (and it shouldn't be hard to do
so, either).
/* Karatsuba convolution
*
* Copyright (C) 1999 Ralph Loader <suckfish@ihug.co.nz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
* $Id$
*
*/
/* The algorithm is based on the following. For the convolution of a pair
* of pairs, (a,b) * (c,d) = (0, a.c, a.d+b.c, b.d), we can reduce the four
* multiplications to three, by the formulae a.d+b.c = (a+b).(c+d) - a.c -
* b.d. A similar relation enables us to compute a 2n by 2n convolution
* using 3 n by n convolutions, and thus a 2^n by 2^n convolution using 3^n
* multiplications (as opposed to the 4^n that the quadratic algorithm
* takes. */
/* For large n, this is slower than the O(n log n) that the FFT method
* takes, but we avoid using complex numbers, and we only have to compute
* one convolution, as opposed to 3 FFTs. We have good locality-of-
* reference as well, which will help on CPUs with tiny caches. */
/* E.g., for a 512 x 512 convolution, the FFT method takes 55 * 512 = 28160
* (real) multiplications, as opposed to 3^9 = 19683 for the Karatsuba
* algorithm. We actually want 257 outputs of a 256 x 512 convolution;
* that doesn't appear to give an easy advantage for the FFT algorithm, but
* for the Karatsuba algorithm, it's easy to use two 256 x 256
* convolutions, taking 2 x 3^8 = 12312 multiplications. [This difference
* is that the FFT method "wraps" the arrays, doing a 2^n x 2^n -> 2^n,
* while the Karatsuba algorithm pads with zeros, doing 2^n x 2^n -> 2.2^n
* - 1]. */
/* There's a big lie above, actually... for a 4x4 convolution, it's quicker
* to do it using 16 multiplications than the more complex Karatsuba
* algorithm... So the recursion bottoms out at 4x4s. This increases the
* number of multiplications by a factor of 16/9, but reduces the overheads
* dramatically. */
/* The convolution algorithm is implemented as a stack machine. We have a
* stack of commands, each in one of the forms "do a 2^n x 2^n
* convolution", or "combine these three length 2^n outputs into one
* 2^{n+1} output." */
#include <stdlib.h>
#include "convolve.h"
typedef union stack_entry_s {
struct {const double * left, * right; double * out;} v;
struct {double * main, * null;} b;
} stack_entry;
#define STACK_SIZE (CONVOLVE_DEPTH * 3)
struct _struct_convolve_state {
double left [CONVOLVE_BIG];
double right [CONVOLVE_SMALL * 3];
double scratch [CONVOLVE_SMALL * 3];
stack_entry stack[STACK_SIZE];
};
/*
* Initialisation routine - sets up tables and space to work in.
* Returns a pointer to internal state, to be used when performing calls.
* On error, returns NULL.
* The pointer should be freed when it is finished with, by convolve_close().
*/
convolve_state *convolve_init(void)
{
return (convolve_state *) malloc (sizeof(convolve_state));
}
/*
* Free the state allocated with convolve_init().
*/
void convolve_close(convolve_state *state)
{
if (state)
free(state);
}
static void convolve_4 (double * out, const double * left, const double * right)
/* This does a 4x4 -> 7 convolution. For what it's worth, the slightly odd
* ordering gives about a 1% speed up on my Pentium II. */
{
double l0, l1, l2, l3, r0, r1, r2, r3;
double a;
l0 = left[0];
r0 = right[0];
a = l0 * r0;
l1 = left[1];
r1 = right[1];
out[0] = a;
a = (l0 * r1) + (l1 * r0);
l2 = left[2];
r2 = right[2];
out[1] = a;
a = (l0 * r2) + (l1 * r1) + (l2 * r0);
l3 = left[3];
r3 = right[3];
out[2] = a;
out[3] = (l0 * r3) + (l1 * r2) + (l2 * r1) + (l3 * r0);
out[4] = (l1 * r3) + (l2 * r2) + (l3 * r1);
out[5] = (l2 * r3) + (l3 * r2);
out[6] = l3 * r3;
}
static void convolve_run (stack_entry * top, unsigned size, double * scratch)
/* Interpret a stack of commands. The stack starts with two entries; the
* convolution to do, and an illegal entry used to mark the stack top. The
* size is the number of entries in each input, and must be a power of 2,
* and at least 8. It is OK to have out equal to left and/or right.
* scratch must have length 3*size. The number of stack entries needed is
* 3n-4 where size=2^n. */
{
do {
const double * left;
const double * right;
double * out;
/* When we get here, the stack top is always a convolve,
* with size > 4. So we will split it. We repeatedly split
* the top entry until we get to size = 4. */
left = top->v.left;
right = top->v.right;
out = top->v.out;
top++;
do {
double * s_left, * s_right;
int i;
/* Halve the size. */
size >>= 1;
/* Allocate the scratch areas. */
s_left = scratch + size * 3;
/* s_right is a length 2*size buffer also used for
* intermediate output. */
s_right = scratch + size * 4;
/* Create the intermediate factors. */
for (i = 0; i < size; i++) {
double l = left[i] + left[i + size];
double r = right[i] + right[i + size];
s_left[i + size] = r;
s_left[i] = l;
}
/* Push the combine entry onto the stack. */
top -= 3;
top[2].b.main = out;
top[2].b.null = NULL;
/* Push the low entry onto the stack. This must be
* the last of the three sub-convolutions, because
* it may overwrite the arguments. */
top[1].v.left = left;
top[1].v.right = right;
top[1].v.out = out;
/* Push the mid entry onto the stack. */
top[0].v.left = s_left;
top[0].v.right = s_right;
top[0].v.out = s_right;
/* Leave the high entry in variables. */
left += size;
right += size;
out += size * 2;
} while (size > 4);
/* When we get here, the stack top is a group of 3
* convolves, with size = 4, followed by some combines. */
convolve_4 (out, left, right);
convolve_4 (top[0].v.out, top[0].v.left, top[0].v.right);
convolve_4 (top[1].v.out, top[1].v.left, top[1].v.right);
top += 2;
/* Now process combines. */
do {
/* b.main is the output buffer, mid is the middle
* part which needs to be adjusted in place, and
* then folded back into the output. We do this in
* a slightly strange way, so as to avoid having
* two loops. */
double * out = top->b.main;
double * mid = scratch + size * 4;
unsigned int i;
top++;
out[size * 2 - 1] = 0;
for (i = 0; i < size-1; i++) {
double lo;
double hi;
lo = mid[0] - (out[0] + out[2 * size]) + out[size];
hi = mid[size] - (out[size] + out[3 * size]) + out[2 * size];
out[size] = lo;
out[2 * size] = hi;
out++;
mid++;
}
size <<= 1;
} while (top->b.null == NULL);
} while (top->b.main != NULL);
}
int convolve_match (const int * lastchoice,
const short * input,
convolve_state * state)
/* lastchoice is a 256 sized array. input is a 512 array. We find the
* contiguous length 256 sub-array of input that best matches lastchoice.
* A measure of how good a sub-array is compared with the lastchoice is
* given by the sum of the products of each pair of entries. We maximise
* that, by taking an appropriate convolution, and then finding the maximum
* entry in the convolutions. state is a (non-NULL) pointer returned by
* convolve_init. */
{
double avg;
double best;
int p = 0;
int i;
double * left = state->left;
double * right = state->right;
double * scratch = state->scratch;
stack_entry * top = state->stack + STACK_SIZE - 1;
#if 1
for (i = 0; i < 512; i++)
left[i] = input[i];
avg = 0;
for (i = 0; i < 256; i++) {
double a = lastchoice[255 - i];
right[i] = a;
avg += a;
}
#endif
/* We adjust the smaller of the two input arrays to have average
* value 0. This makes the eventual result insensitive to both
* constant offsets and positive multipliers of the inputs. */
avg /= 256;
for (i = 0; i < 256; i++)
right[i] -= avg;
/* End-of-stack marker. */
#if 0 /* The following line produces a CRASH, need to figure out why?!! */
top[1].b.null = scratch;
#endif
top[1].b.main = NULL;
/* The low 256x256, of which we want the high 256 outputs. */
top->v.left = left;
top->v.right = right;
top->v.out = right + 256;
convolve_run (top, 256, scratch);
/* The high 256x256, of which we want the low 256 outputs. */
top->v.left = left + 256;
top->v.right = right;
top->v.out = right;
convolve_run (top, 256, scratch);
/* Now find the best position amoungs this. Apart from the first
* and last, the required convolution outputs are formed by adding
* outputs from the two convolutions above. */
best = right[511];
right[767] = 0;
p = -1;
for (i = 0; i < 256; i++) {
double a = right[i] + right[i + 512];
if (a > best) {
best = a;
p = i;
}
}
p++;
#if 0
{
/* This is some debugging code... */
int bad = 0;
best = 0;
for (i = 0; i < 256; i++)
best += ((double) input[i+p]) * ((double) lastchoice[i] - avg);
for (i = 0; i < 257; i++) {
double tot = 0;
unsigned int j;
for (j = 0; j < 256; j++)
tot += ((double) input[i+j]) * ((double) lastchoice[j] - avg);
if (tot > best)
printf ("(%i)", i);
if (tot != left[i + 255])
printf ("!");
}
printf ("%i\n", p);
}
#endif
return p;
}
/* convolve.h: Header for convolutions.
*
* Copyright (C) 1999 Ralph Loader <suckfish@ihug.co.nz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef CONVOLVE_H
#define CONVOLVE_H
#ifdef __cplusplus
extern "C" {
#endif
/* convolve_match takes two blocks, one twice the size of the other. The
* sizes of these are CONVOLVE_BIG and CONVOLVE_SMALL respectively. */
#define CONVOLVE_DEPTH 8
#define CONVOLVE_SMALL (1 << CONVOLVE_DEPTH)
#define CONVOLVE_BIG (CONVOLVE_SMALL * 2)
/* Convolution stuff */
typedef struct _struct_convolve_state convolve_state;
convolve_state *convolve_init (void);
void convolve_close (convolve_state * state);
int convolve_match (const int * lastchoice,
const short int * input,
convolve_state * state);
#ifdef __cplusplus
}
#endif
#endif
This diff is collapsed.
/* monoscope.cpp
* Copyright (C) 2002 Richard Boulton <richard@tartarus.org>
* Copyright (C) 1998-2001 Andy Lo A Foe <andy@alsaplayer.org>
* Original code by Tinic Uro
*
* This code is copied from Alsaplayer.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "monoscope.h"
#include "convolve.h"
#define scope_width 256
#define scope_height 128
static gint16 newEq[CONVOLVE_BIG]; // latest block of 512 samples.
static gint16 copyEq[CONVOLVE_BIG];
static int avgEq[CONVOLVE_SMALL]; // a running average of the last few.
static int avgMax; // running average of max sample.
static guint32 display[(scope_width + 1) * (scope_height + 1)];
static convolve_state *state = NULL;
static guint32 colors[64];
static void colors_init(guint32 * colors)
{
int i;
for (i = 0; i < 32; i++) {
colors[i] = (i*8 << 16) + (255 << 8);
colors[i+31] = (255 << 16) + (((31 - i) * 8) << 8);
}
colors[63] = (40 << 16) + (75 << 8);
}
void monoscope_init (guint32 resx, guint32 resy)
{
state = convolve_init();
colors_init(colors);
}
guint32 * monoscope_update (gint16 data [2][512])
{
/* Note that CONVOLVE_BIG must == data size here, ie 512. */
/* Really, we want samples evenly spread over the available data.
* Just taking a continuous chunk will do for now, though. */
int i;
for (i = 0; i < CONVOLVE_BIG; i++) {
/* Average the two channels. */
newEq[i] = (((int) data[0][i]) + (int) data[1][i]) >> 1;
}
int foo;
int bar;
int h;
guchar bits[ 257 * 129];
guint32 *loc;
int factor;
int val;
int max = 1;
short * thisEq;
memcpy (copyEq, newEq, sizeof (short) * CONVOLVE_BIG);
thisEq = copyEq;
#if 1
val = convolve_match (avgEq, copyEq, state);
thisEq += val;
#endif
memset(display, 0, 256 * 128 * sizeof(guint32));
for (i=0; i < 256; i++) {
foo = thisEq[i] + (avgEq[i] >> 1);
avgEq[i] = foo;
if (foo < 0)
foo = -foo;
if (foo > max)
max = foo;
}
avgMax += max - (avgMax >> 8);
if (avgMax < max)
avgMax = max; /* Avoid overflow */
factor = 0x7fffffff / avgMax;
/* Keep the scaling sensible. */
if (factor > (1 << 18))
factor = 1 << 18;
if (factor < (1 << 8))
factor = 1 << 8;
for (i=0; i < 256; i++) {
foo = avgEq[i] * factor;
foo >>= 18;
if (foo > 63)
foo = 63;
if (foo < -64)
foo = -64;
val = (i + ((foo+64) << 8));
bar = val;
if ((bar > 0) && (bar < (256 * 128))) {
loc = display + bar;
if (foo < 0) {
for (h = 0; h <= (-foo); h++) {
*loc = colors[h];
loc+=256;
}
} else {
for (h = 0; h <= foo; h++) {
*loc = colors[h];
loc-=256;
}
}
}
}
/* Draw grid. */
for (i=16;i < 128; i+=16) {
for (h = 0; h < 256; h+=2) {
display[(i << 8) + h] = colors[63];
if (i == 64)
display[(i << 8) + h + 1] = colors[63];
}
}
for (i = 16; i < 256; i+=16) {
for (h = 0; h < 128; h+=2) {
display[i + (h << 8)] = colors[63];
}
}
return display;
}
void monoscope_close ()
{
}
#ifndef _MONOSCOPE_H
#define _MONOSCOPE_H
#include <glib.h>
void monoscope_init (guint32 resx, guint32 resy);
guint32 * monoscope_update (gint16 data [2][512]);
void monoscope_close ();
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment